pud: include nmealib v1.0.0
authorFerry Huberts <ferry.huberts@pelagic.nl>
Fri, 13 Jul 2012 16:14:22 +0000 (18:14 +0200)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Sun, 15 Jul 2012 20:58:35 +0000 (22:58 +0200)
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
35 files changed:
lib/pud/nmealib/LICENSE [moved from lib/pud/nmealib/LICENSE.TXT with 100% similarity]
lib/pud/nmealib/Makefile
lib/pud/nmealib/Makefile.inc
lib/pud/nmealib/README [moved from lib/pud/nmealib/README.TXT with 85% similarity]
lib/pud/nmealib/doc/nmea.doxygen
lib/pud/nmealib/include/nmea/context.h
lib/pud/nmealib/include/nmea/conversions.h [moved from lib/pud/nmealib/include/nmea/time.h with 51% similarity]
lib/pud/nmealib/include/nmea/generate.h
lib/pud/nmealib/include/nmea/generator.h
lib/pud/nmealib/include/nmea/gmath.h
lib/pud/nmealib/include/nmea/info.h
lib/pud/nmealib/include/nmea/nmea.h [deleted file]
lib/pud/nmealib/include/nmea/parse.h
lib/pud/nmealib/include/nmea/parser.h
lib/pud/nmealib/include/nmea/sentence.h
lib/pud/nmealib/include/nmea/tok.h
lib/pud/nmealib/include/nmea/units.h [deleted file]
lib/pud/nmealib/include/nmea/util.h [deleted file]
lib/pud/nmealib/samples/generate/main.c
lib/pud/nmealib/samples/generator/main.c
lib/pud/nmealib/samples/math/main.c
lib/pud/nmealib/samples/parse/main.c
lib/pud/nmealib/samples/parse_file/main.c
lib/pud/nmealib/src/context.c
lib/pud/nmealib/src/conversions.c [new file with mode: 0644]
lib/pud/nmealib/src/generate.c
lib/pud/nmealib/src/generator.c
lib/pud/nmealib/src/gmath.c
lib/pud/nmealib/src/info.c
lib/pud/nmealib/src/parse.c
lib/pud/nmealib/src/parser.c
lib/pud/nmealib/src/sentence.c
lib/pud/nmealib/src/time.c [deleted file]
lib/pud/nmealib/src/tok.c
lib/pud/nmealib/src/util.c [deleted file]

index 0567676..58e2b9e 100644 (file)
@@ -19,7 +19,7 @@ INCLUDEDIR ?= $(DESTDIR)/usr/include
 LIBDIR ?= $(USRDIR)/lib
 
 
-MODULES = context generate generator gmath info parse parser sentence time tok util
+MODULES = context conversions generate generator gmath info parse parser sentence tok
 OBJ = $(MODULES:%=build/%.o)
 
 LIBRARIES = -lm
@@ -60,30 +60,30 @@ all-before:
 clean:
        @$(MAKE) -C doc clean
        @$(MAKE) -C samples clean
-       rm -fr build lib
+       @rm -frv build lib
 
 doc:
-       $(MAKE) -C doc all
+       @$(MAKE) -C doc all
 
 doc-clean:
        @$(MAKE) -C doc clean
 
 install: all
        @mkdir -v -p "$(LIBDIR)"
-       cp "lib/$(LIBNAME)" "$(LIBDIR)/$(LIBNAME).$(VERSION)"
-       $(STRIP) "$(LIBDIR)/$(LIBNAME).$(VERSION)"
-       /sbin/ldconfig -n "$(LIBDIR)"
+       @cp -v "lib/$(LIBNAME)" "$(LIBDIR)/$(LIBNAME).$(VERSION)"
+       @$(STRIP) "$(LIBDIR)/$(LIBNAME).$(VERSION)"
+       @ldconfig -n "$(LIBDIR)"
 
 install-headers: all
        @mkdir -v -p "$(INCLUDEDIR)"
        @rm -fr "$(INCLUDEDIR)/nmea"
-       cp -r include/nmea "$(INCLUDEDIR)"
+       @cp -rv include/nmea "$(INCLUDEDIR)"
 
 uninstall:
-       rm -f "$(LIBDIR)/$(LIBNAME)" "$(LIBDIR)/$(LIBNAME).$(VERSION)"
-       /sbin/ldconfig -n "$(LIBDIR)"
+       @rm -fv "$(LIBDIR)/$(LIBNAME)" "$(LIBDIR)/$(LIBNAME).$(VERSION)"
+       @ldconfig -n "$(LIBDIR)"
        @rmdir -v -p --ignore-fail-on-non-empty "$(LIBDIR)"
 
 uninstall-headers:
-       rm -fr "$(INCLUDEDIR)/nmea"
+       @rm -frv "$(INCLUDEDIR)/nmea"
        @rmdir -v -p --ignore-fail-on-non-empty "$(INCLUDEDIR)"
index f33826e..3037fa8 100644 (file)
@@ -22,7 +22,7 @@ endif
 
 # we expect the version to be like 'v0.5.3-27-g0c2727a' and then strip the 'v',
 # and the '-27-g0c2727a' parts
-VERSION=0.6.10
+VERSION=1.0.0
 
 # protect against no version number
 ifeq ($(strip $(VERSION)),)
similarity index 85%
rename from lib/pud/nmealib/README.TXT
rename to lib/pud/nmealib/README
index f24bc87..13f50b1 100644 (file)
@@ -20,11 +20,11 @@ Introduction
 
 Features
 
-- Analysis NMEA sentences and granting GPS data in C structures
-- Generate NMEA sentences
+- Parsing of NMEA sentences into C structures
+- Generate NMEA sentences from C structures
 - Supported sentences: GPGGA, GPGSA, GPGSV, GPRMC, GPVTG
 - Multilevel architecture of algorithms
-- Additional functions of geographical mathematics and work with navigation data
+- Additional functions of geographical mathematics
 
 Supported (tested) platforms
 
index 5ae8c60..9954954 100644 (file)
@@ -1,14 +1,14 @@
-# Doxyfile 1.7.1
+# Doxyfile 1.8.1.1
 
 # This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
+# doxygen (www.doxygen.org) for a project.
 #
-# All text after a hash (#) is considered a comment and will be ignored
+# All text after a hash (#) is considered a comment and will be ignored.
 # The format is:
 #       TAG = value [value, ...]
 # For lists items can also be appended using:
 #       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
+# Values that contain spaces should be placed between quotes (" ").
 
 #---------------------------------------------------------------------------
 # Project related configuration options
@@ -22,8 +22,9 @@
 
 DOXYFILE_ENCODING      = UTF-8
 
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
 
 PROJECT_NAME           = "NMEAlib"
 
@@ -33,6 +34,19 @@ PROJECT_NAME           = "NMEAlib"
 
 PROJECT_NUMBER         =
 
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
 # base path where the generated documentation will be put.
 # If a relative path is entered, it will be relative to the location
@@ -57,7 +71,7 @@ CREATE_SUBDIRS         = NO
 # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
 # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
 # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
 # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
 
 OUTPUT_LANGUAGE        = English
@@ -126,7 +140,7 @@ STRIP_FROM_PATH        =
 STRIP_FROM_INC_PATH    =
 
 # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
+# (but less readable) file names. This can be useful if your file system
 # doesn't support long names like on DOS, Mac, or CD-ROM.
 
 SHORT_NAMES            = NO
@@ -181,6 +195,13 @@ TAB_SIZE               = 2
 
 ALIASES                =
 
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
 # sources only. Doxygen will then generate output that is more tailored for C.
 # For instance, some of the names that are used will be different. The list
@@ -219,11 +240,20 @@ OPTIMIZE_OUTPUT_VHDL   = NO
 
 EXTENSION_MAPPING      =
 
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
 # to include (a tag file for) the STL sources as input, then you should
 # set this tag to YES in order to let doxygen match functions declarations and
 # definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
+# func(std::string) {}). This also makes the inheritance and collaboration
 # diagrams that involve STL classes more complete and accurate.
 
 BUILTIN_STL_SUPPORT    = NO
@@ -241,7 +271,7 @@ SIP_SUPPORT            = NO
 
 # For Microsoft's IDL there are propget and propput attributes to indicate getter
 # and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen to replace the get and set methods by a property in the
+# will make doxygen replace the get and set methods by a property in the
 # documentation. This will only work if the methods are indeed getting or
 # setting a simple type. If this is not the case, or you want to show the
 # methods anyway, you should set this option to NO.
@@ -263,6 +293,22 @@ DISTRIBUTE_GROUP_DOC   = NO
 
 SUBGROUPING            = YES
 
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
 # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
 # is documented as struct, union, or enum with the name of the typedef. So
 # typedef struct TypeS {} TypeT, will appear in the documentation as a struct
@@ -279,16 +325,27 @@ TYPEDEF_HIDES_STRUCT   = NO
 # For small to medium size projects (<1000 input files) the default value is
 # probably good enough. For larger projects a too small cache size can cause
 # doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
+# causing a significant performance penalty.
 # If the system has enough physical memory increasing the cache will improve the
 # performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
+# a logarithmic scale so increasing the size by one will roughly double the
 # memory usage. The cache size is given by this formula:
 # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
+# corresponding to a cache size of 2^16 = 65536 symbols.
 
 SYMBOL_CACHE_SIZE      = 0
 
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
@@ -305,6 +362,10 @@ EXTRACT_ALL            = YES
 
 EXTRACT_PRIVATE        = YES
 
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
 # If the EXTRACT_STATIC tag is set to YES all static members of a file
 # will be included in the documentation.
 
@@ -327,7 +388,7 @@ EXTRACT_LOCAL_METHODS  = YES
 # extracted and appear in the documentation as a namespace called
 # 'anonymous_namespace{file}', where file will be replaced with the base
 # name of the file that contains the anonymous namespace. By default
-# anonymous namespace are hidden.
+# anonymous namespaces are hidden.
 
 EXTRACT_ANON_NSPACES   = YES
 
@@ -438,6 +499,15 @@ SORT_GROUP_NAMES       = NO
 
 SORT_BY_SCOPE_NAME     = NO
 
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
 # The GENERATE_TODOLIST tag can be used to enable (YES) or
 # disable (NO) the todo list. This list is created by putting \todo
 # commands in the documentation.
@@ -468,10 +538,10 @@ GENERATE_DEPRECATEDLIST= YES
 ENABLED_SECTIONS       =
 
 # The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
+# the initial value of a variable or macro consists of for it to appear in
 # the documentation. If the initializer consists of more lines than specified
 # here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
+# The appearance of the initializer of individual variables and macros in the
 # documentation can be controlled using \showinitializer or \hideinitializer
 # command in the documentation regardless of this setting.
 
@@ -483,12 +553,6 @@ MAX_INITIALIZER_LINES  = 30
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
 # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
 # This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
@@ -514,13 +578,23 @@ FILE_VERSION_FILTER    =
 
 # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
 # by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
+# output files in an output format independent way. To create the layout file
 # that represents doxygen's defaults, run doxygen with the -l option.
 # You can optionally specify a file name after the option, if omitted
 # DoxygenLayout.xml will be used as the name of the layout file.
 
 LAYOUT_FILE            =
 
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES         =
+
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
@@ -549,7 +623,7 @@ WARN_IF_UNDOCUMENTED   = YES
 
 WARN_IF_DOC_ERROR      = YES
 
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
 # functions that are documented, but have no documentation for their parameters
 # or return value. If set to NO (the default) doxygen will only warn about
 # wrong or incomplete parameter documentation, but not about the absence of
@@ -581,7 +655,8 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = ../src ../include/nmea
+INPUT                  = ../src \
+                         ../include/nmea
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -595,10 +670,12 @@ INPUT_ENCODING         = UTF-8
 # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
 # and *.h) to filter out the source-files in the directories. If left
 # blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
 
-FILE_PATTERNS          = *.c *.h
+FILE_PATTERNS          = *.c \
+                         *.h
 
 # The RECURSIVE tag can be used to turn specify whether or not subdirectories
 # should be searched for input files as well. Possible values are YES and NO.
@@ -606,14 +683,16 @@ FILE_PATTERNS          = *.c *.h
 
 RECURSIVE              = YES
 
-# The EXCLUDE tag can be used to specify files and/or directories that should
+# The EXCLUDE tag can be used to specify files and/or directories that should be
 # excluded from the INPUT source files. This way you can easily exclude a
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
 
 EXCLUDE                =
 
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
 # from the input.
 
 EXCLUDE_SYMLINKS       = NO
@@ -677,8 +756,8 @@ INPUT_FILTER           =
 # filter if there is a match.
 # The filters are a list of the form:
 # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
 
 FILTER_PATTERNS        =
 
@@ -688,6 +767,14 @@ FILTER_PATTERNS        =
 
 FILTER_SOURCE_FILES    = NO
 
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
 #---------------------------------------------------------------------------
 # configuration options related to source browsing
 #---------------------------------------------------------------------------
@@ -706,7 +793,7 @@ INLINE_SOURCES         = NO
 
 # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
 # doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
 
 STRIP_CODE_COMMENTS    = NO
 
@@ -790,7 +877,14 @@ HTML_FILE_EXTENSION    = .html
 
 # The HTML_HEADER tag can be used to specify a personal HTML header for
 # each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
 
 HTML_HEADER            =
 
@@ -800,22 +894,26 @@ HTML_HEADER            =
 
 HTML_FOOTER            =
 
-# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
-# documentation will contain the timesstamp.
-
-HTML_TIMESTAMP         = NO
-
 # The HTML_STYLESHEET tag can be used to specify a user-defined cascading
 # style sheet that is used by each HTML page. It can be used to
 # fine-tune the look of the HTML output. If the tag is left blank doxygen
 # will generate a default style sheet. Note that doxygen will try to copy
 # the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
+# style sheet in the HTML output directory as well, or it will be erased!
 
 HTML_STYLESHEET        =
 
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
+# Doxygen will adjust the colors in the style sheet and background images
 # according to this color. Hue is specified as an angle on a colorwheel,
 # see http://en.wikipedia.org/wiki/Hue for more information.
 # For instance the value 0 represents red, 60 is yellow, 120 is green,
@@ -845,20 +943,23 @@ HTML_COLORSTYLE_GAMMA  = 80
 
 HTML_TIMESTAMP         = YES
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+# page has loaded.
 
 HTML_DYNAMIC_SECTIONS  = NO
 
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
 # If the GENERATE_DOCSET tag is set to YES, additional index files
 # will be generated that can be used as input for Apple's Xcode 3
 # integrated development environment, introduced with OSX 10.5 (Leopard).
@@ -1010,17 +1111,14 @@ GENERATE_ECLIPSEHELP   = NO
 
 ECLIPSE_DOC_ID         = org.doxygen.Project
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
 
 DISABLE_INDEX          = NO
 
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE   = 4
-
 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
 # structure should be generated to display hierarchical information.
 # If the tag value is set to YES, a side panel will be generated
@@ -1028,13 +1126,17 @@ ENUM_VALUES_PER_LINE   = 4
 # is generated for HTML Help). For this to work a browser that supports
 # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
 # Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
 
 GENERATE_TREEVIEW      = YES
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
 
-USE_INLINE_TREES       = NO
+ENUM_VALUES_PER_LINE   = 4
 
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
@@ -1063,6 +1165,32 @@ FORMULA_FONTSIZE       = 10
 
 FORMULA_TRANSPARENT    = YES
 
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
 # When the SEARCHENGINE tag is enabled doxygen will generate a search box
 # for the HTML output. The underlying search engine uses javascript
 # and DHTML and should work on any modern browser. Note that when using
@@ -1078,7 +1206,7 @@ SEARCHENGINE           = YES
 # using Javascript. Doxygen will generate the search PHP script and index
 # file to put on the web server. The advantage of the server
 # based approach is that it scales better to large projects and allows
-# full text search. The disadvances is that it is more difficult to setup
+# full text search. The disadvantages are that it is more difficult to setup
 # and does not have live searching capabilities.
 
 SERVER_BASED_SEARCH    = NO
@@ -1119,7 +1247,7 @@ MAKEINDEX_CMD_NAME     = makeindex
 COMPACT_LATEX          = NO
 
 # The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
+# by the printer. Possible values are: a4, letter, legal and
 # executive. If left blank a4wide will be used.
 
 PAPER_TYPE             = a4wide
@@ -1136,6 +1264,13 @@ EXTRA_PACKAGES         =
 
 LATEX_HEADER           =
 
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
 # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
 # is prepared for conversion to pdf (using ps2pdf). The pdf file will
 # contain links (just like the HTML output) instead of page references
@@ -1169,6 +1304,12 @@ LATEX_HIDE_INDICES     = NO
 
 LATEX_SOURCE_CODE      = NO
 
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
 #---------------------------------------------------------------------------
 # configuration options related to the RTF output
 #---------------------------------------------------------------------------
@@ -1200,7 +1341,7 @@ COMPACT_RTF            = NO
 
 RTF_HYPERLINKS         = YES
 
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# Load style sheet definitions from file. Syntax is similar to doxygen's
 # config file, i.e. a series of assignments. You only have to provide
 # replacements, missing definitions are set to their default value.
 
@@ -1345,7 +1486,7 @@ MACRO_EXPANSION        = YES
 EXPAND_ONLY_PREDEF     = YES
 
 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
 
 SEARCH_INCLUDES        = YES
 
@@ -1370,21 +1511,20 @@ INCLUDE_FILE_PATTERNS  =
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             =
-PREDEFINED            += "__attribute__(x)="
+PREDEFINED             = "__attribute__(x)="
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
 # The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
 
 EXPAND_AS_DEFINED      =
 
 # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
 
 SKIP_FUNCTION_MACROS   = YES
 
@@ -1392,22 +1532,18 @@ SKIP_FUNCTION_MACROS   = YES
 # Configuration::additions related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
 #
 # TAGFILES = file1 file2 ...
 # Adding location for the tag files is done as follows:
 #
 # TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
 
 TAGFILES               =
 
@@ -1440,9 +1576,8 @@ PERL_PATH              = /usr/bin/perl
 # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
 # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
 # or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
 
 CLASS_DIAGRAMS         = YES
 
@@ -1476,14 +1611,12 @@ HAVE_DOT               = YES
 
 DOT_NUM_THREADS        = 0
 
-# By default doxygen will write a font called FreeSans.ttf to the output
-# directory and reference it in all dot files that doxygen generates. This
-# font does not include all possible unicode characters however, so when you need
-# these (or just want a differently looking font) you can specify the font name
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
 
 DOT_FONTNAME           = FreeSans.ttf
 
@@ -1492,17 +1625,16 @@ DOT_FONTNAME           = FreeSans.ttf
 
 DOT_FONTSIZE           = 10
 
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
 
 DOT_FONTPATH           =
 
 # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
 # will generate a graph for each documented class showing the direct and
 # indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
+# CLASS_DIAGRAMS tag to NO.
 
 CLASS_GRAPH            = YES
 
@@ -1524,6 +1656,15 @@ GROUP_GRAPHS           = YES
 
 UML_LOOK               = YES
 
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
 # If set to YES, the inheritance and collaboration graphs will show the
 # relations between templates and their instances.
 
@@ -1560,11 +1701,11 @@ CALL_GRAPH             = YES
 CALLER_GRAPH           = YES
 
 # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
+# will generate a graphical hierarchy of all classes instead of a textual one.
 
 GRAPHICAL_HIERARCHY    = YES
 
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
 # then doxygen will show the dependencies a directory has on other directories
 # in a graphical way. The dependency relations are determined by the #include
 # relations between the files in the directories.
@@ -1572,11 +1713,22 @@ GRAPHICAL_HIERARCHY    = YES
 DIRECTORY_GRAPH        = YES
 
 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
 
 DOT_IMAGE_FORMAT       = png
 
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
 # The tag DOT_PATH can be used to specify the path where the dot tool can be
 # found. If left blank, it is assumed the dot tool can be found in the path.
 
@@ -1588,6 +1740,12 @@ DOT_PATH               =
 
 DOTFILE_DIRS           =
 
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
 # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
 # nodes that will be shown in the graph. If the number of nodes in a graph
 # becomes larger than this value, doxygen will truncate the graph, which is
index 1fb30ed..078a46f 100644 (file)
 #ifndef __NMEA_CONTEXT_H__
 #define __NMEA_CONTEXT_H__
 
-#define NMEA_DEF_PARSEBUFF  (1024)
-#define NMEA_MIN_PARSEBUFF  (256)
+/** the default size for the temporary buffers */
+#define NMEA_DEF_PARSEBUFF  1024
+
+/** the minimum size for the temporary buffers */
+#define NMEA_MIN_PARSEBUFF  256
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
+/**
+ * Function type definition for tracing
+ *
+ * @param str the string to trace
+ * @param str_size the length of the string
+ */
 typedef void (*nmeaTraceFunc)(const char *str, int str_size);
-typedef void (*nmeaErrorFunc)(const char *str, int str_size);
 
-typedef struct _nmeaPROPERTY {
-       nmeaTraceFunc trace_func;
-       nmeaErrorFunc error_func;
-       int parse_buff_size;
-
-} nmeaPROPERTY;
+/**
+ * Function type definition for error logging
+ *
+ * @param str the string to log
+ * @param str_size the length of the string
+ */
+typedef void (*nmeaErrorFunc)(const char *str, int str_size);
 
-nmeaPROPERTY * nmea_property(void);
+void nmea_context_set_trace_func(nmeaTraceFunc func);
+void nmea_context_set_error_func(nmeaErrorFunc func);
+void nmea_context_set_buffer_size(int buff_size);
+int nmea_context_get_buffer_size(void);
 
 void nmea_trace(const char *str, ...) __attribute__ ((format(printf, 1, 2)));
 void nmea_trace_buff(const char *buff, int buff_size);
similarity index 51%
rename from lib/pud/nmealib/include/nmea/time.h
rename to lib/pud/nmealib/include/nmea/conversions.h
index 9e6666d..0d33a7e 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*! \file */
+#ifndef __NMEA_CONVERSIONS_H__
+#define __NMEA_CONVERSIONS_H__
 
-#ifndef __NMEA_TIME_H__
-#define __NMEA_TIME_H__
+#include <nmea/sentence.h>
+#include <nmea/info.h>
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-/**
- * Date and time data
- * @see nmea_time_now
- */
-typedef struct _nmeaTIME {
-       int year; /**< Years since 1900 */
-       int mon;  /**< Months since January - [0,11] */
-       int day;  /**< Day of the month - [1,31] */
-       int hour; /**< Hours since midnight - [0,23] */
-       int min;  /**< Minutes after the hour - [0,59] */
-       int sec;  /**< Seconds after the minute - [0,59] */
-       int hsec; /**< Hundredth part of second - [0,99] */
-
-} nmeaTIME;
-
-/**
- * \brief Get time now to nmeaTIME structure
- */
-void nmea_time_now(nmeaTIME *t);
+int nmea_gsv_npack(int sat_count);
+
+void nmea_GPGGA2info(const nmeaGPGGA *pack, nmeaINFO *info);
+void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack);
+
+void nmea_GPGSA2info(const nmeaGPGSA *pack, nmeaINFO *info);
+void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack);
+
+void nmea_GPGSV2info(const nmeaGPGSV *pack, nmeaINFO *info);
+void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx);
+
+void nmea_GPRMC2info(const nmeaGPRMC *pack, nmeaINFO *info);
+void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack);
+
+void nmea_GPVTG2info(const nmeaGPVTG *pack, nmeaINFO *info);
+void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack);
 
 #ifdef  __cplusplus
 }
 #endif
 
-#endif /* __NMEA_TIME_H__ */
+#endif /* __NMEA_CONVERSIONS_H__ */
index 34eab4e..80c20dc 100644 (file)
 #ifndef __NMEA_GENERATE_H__
 #define __NMEA_GENERATE_H__
 
-#include <nmea/info.h>
 #include <nmea/sentence.h>
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-int nmea_generate(char *buff, int buff_sz, const nmeaINFO *info,
-               int generate_mask);
+int nmea_gen_GPGGA(char *s, const int len, const nmeaGPGGA *pack);
+int nmea_gen_GPGSA(char *s, const int len, const nmeaGPGSA *pack);
+int nmea_gen_GPGSV(char *s, const int len, const nmeaGPGSV *pack);
+int nmea_gen_GPRMC(char *s, const int len, const nmeaGPRMC *pack);
+int nmea_gen_GPVTG(char *s, const int len, const nmeaGPVTG *pack);
 
-int nmea_gen_GPGGA(char *buff, int buff_sz, nmeaGPGGA *pack);
-int nmea_gen_GPGSA(char *buff, int buff_sz, nmeaGPGSA *pack);
-int nmea_gen_GPGSV(char *buff, int buff_sz, nmeaGPGSV *pack);
-int nmea_gen_GPRMC(char *buff, int buff_sz, nmeaGPRMC *pack);
-int nmea_gen_GPVTG(char *buff, int buff_sz, nmeaGPVTG *pack);
-
-void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack);
-void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack);
-void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack);
-void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack);
-
-int nmea_gsv_npack(int sat_count);
-void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx);
+int nmea_generate(char *s, const int len, const nmeaINFO *info, const int generate_mask);
 
 #ifdef  __cplusplus
 }
index 6d7c049..60ec3f3 100644 (file)
 extern "C" {
 #endif
 
-/*
- * high level
- */
-
+/* forward declaration */
 struct _nmeaGENERATOR;
 
-enum nmeaGENTYPE
-{
-    NMEA_GEN_NOISE = 0,
-    NMEA_GEN_STATIC,
-    NMEA_GEN_ROTATE,
-
-    NMEA_GEN_SAT_STATIC,
-    NMEA_GEN_SAT_ROTATE,
-    NMEA_GEN_POS_RANDMOVE,
-
-    NMEA_GEN_LAST
+/**
+ * Generator type enum
+ */
+enum nmeaGENTYPE {
+       NMEA_GEN_NOISE = 0,
+       NMEA_GEN_STATIC,
+       NMEA_GEN_ROTATE,
+       NMEA_GEN_SAT_STATIC,
+       NMEA_GEN_SAT_ROTATE,
+       NMEA_GEN_POS_RANDMOVE,
+       NMEA_GEN_LAST
 };
 
-struct _nmeaGENERATOR * nmea_create_generator(int type, nmeaINFO *info);
-void    nmea_destroy_generator(struct _nmeaGENERATOR *gen);
-
-int     nmea_generate_from(
-        char *buff, int buff_sz,    /* buffer */
-        nmeaINFO *info,             /* source info */
-        struct _nmeaGENERATOR *gen, /* generator */
-        int generate_mask           /* mask of sentence`s (e.g. GPGGA | GPGSA) */
-        );
+struct _nmeaGENERATOR * nmea_create_generator(const int type, nmeaINFO *info);
+int nmea_generate_from(char *buff, int buff_sz, nmeaINFO *info, struct _nmeaGENERATOR *gen, int generate_mask);
 
-/*
- * low level
+/**
+ * Generator initialiser function definition.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
  */
-
 typedef int (*nmeaNMEA_GEN_INIT)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+
+/**
+ * Generator loop function definition.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
 typedef int (*nmeaNMEA_GEN_LOOP)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+
+/**
+ * Generator reset function definition.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
 typedef int (*nmeaNMEA_GEN_RESET)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
-typedef int (*nmeaNMEA_GEN_DESTROY)(struct _nmeaGENERATOR *gen);
 
-typedef struct _nmeaGENERATOR
-{
-    void                *gen_data;
-    nmeaNMEA_GEN_INIT    init_call;
-    nmeaNMEA_GEN_LOOP    loop_call;
-    nmeaNMEA_GEN_RESET   reset_call;
-    nmeaNMEA_GEN_DESTROY destroy_call;
-    struct _nmeaGENERATOR *next;
+/**
+ * Generator destroy function definition.
+ *
+ * @param gen a pointer to the generator
+ * @return 1 (true) on success, 0 (false) otherwise
+ */typedef int (*nmeaNMEA_GEN_DESTROY)(struct _nmeaGENERATOR *gen);
 
+/**
+ * Generator structure
+ */
+typedef struct _nmeaGENERATOR {
+       void *gen_data;                    /**< generator data */
+       nmeaNMEA_GEN_INIT init_call;       /**< initialiser function */
+       nmeaNMEA_GEN_LOOP loop_call;       /**< loop function */
+       nmeaNMEA_GEN_RESET reset_call;     /**< reset function */
+       nmeaNMEA_GEN_DESTROY destroy_call; /**< destroy function */
+       struct _nmeaGENERATOR *next;       /**< the next generator */
 } nmeaGENERATOR;
 
-int     nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info);
-int     nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info);
-int     nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info);
-void    nmea_gen_destroy(nmeaGENERATOR *gen);
-void    nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen);
+int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info);
+int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info);
+int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info);
+void nmea_gen_destroy(nmeaGENERATOR *gen);
+void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen);
 
 #ifdef  __cplusplus
 }
index 5bd37d9..771a19d 100644 (file)
 
 #include <nmea/info.h>
 
+#define NMEA_TUD_YARDS              (1.0936133)                     /**< Yards, meter * NMEA_TUD_YARDS = yard */
+#define NMEA_TUD_KNOTS              (1.852)                         /**< Knots, kilometer / NMEA_TUD_KNOTS = knot */
+#define NMEA_TUD_MILES              (1.609344)                      /**< Miles, kilometer / NMEA_TUD_MILES = mile */
+#define NMEA_TUS_MS                 (3.6)                           /**< Meters per seconds, (k/h) / NMEA_TUS_MS= (m/s) */
 #define NMEA_PI                     (3.141592653589793)             /**< PI value */
 #define NMEA_PI180                  (NMEA_PI / 180)                 /**< PI division by 180 */
 #define NMEA_EARTHRADIUS_KM         (6378)                          /**< Earth's mean radius in km */
@@ -40,26 +44,26 @@ extern "C" {
  * degree VS radian
  */
 
-double nmea_degree2radian(double val);
-double nmea_radian2degree(double val);
+double nmea_degree2radian(const double val);
+double nmea_radian2degree(const double val);
 
 /*
  * NDEG (NMEA degree)
  */
 
-double nmea_ndeg2degree(double val);
-double nmea_degree2ndeg(double val);
+double nmea_ndeg2degree(const double val);
+double nmea_degree2ndeg(const double val);
 
-double nmea_ndeg2radian(double val);
-double nmea_radian2ndeg(double val);
+double nmea_ndeg2radian(const double val);
+double nmea_radian2ndeg(const double val);
 
 /*
  * DOP
  */
 
-double nmea_calc_pdop(double hdop, double vdop);
-double nmea_dop2meters(double dop);
-double nmea_meters2dop(double meters);
+double nmea_calc_pdop(const double hdop, const double vdop);
+double nmea_dop2meters(const double dop);
+double nmea_meters2dop(const double meters);
 
 /*
  * positions work
@@ -68,32 +72,15 @@ double nmea_meters2dop(double meters);
 void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos);
 void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info);
 
-double  nmea_distance(
-        const nmeaPOS *from_pos,
-        const nmeaPOS *to_pos
-        );
-
-double  nmea_distance_ellipsoid(
-        const nmeaPOS *from_pos,
-        const nmeaPOS *to_pos,
-        double *from_azimuth,
-        double *to_azimuth
-        );
-
-int     nmea_move_horz(
-        const nmeaPOS *start_pos,
-        nmeaPOS *end_pos,
-        double azimuth,
-        double distance
-        );
-
-int     nmea_move_horz_ellipsoid(
-        const nmeaPOS *start_pos,
-        nmeaPOS *end_pos,
-        double azimuth,
-        double distance,
-        double *end_azimuth
-        );
+double nmea_distance(const nmeaPOS *from_pos, const nmeaPOS *to_pos);
+
+double nmea_distance_ellipsoid(const nmeaPOS *from_pos, const nmeaPOS *to_pos, double *from_azimuth,
+               double *to_azimuth);
+
+int nmea_move_horz(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance);
+
+int nmea_move_horz_ellipsoid(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance,
+               double *end_azimuth);
 
 #ifdef  __cplusplus
 }
index ce74e80..88a6014 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*! \file */
-
 #ifndef __NMEA_INFO_H__
 #define __NMEA_INFO_H__
 
-#include <nmea/time.h>
+#include <stdint.h>
 #include <stdbool.h>
 
+/**
+ * @file
+ * The table below describes which fields are present in the sentences that are
+ * supported by the library.
+ <pre>
+ field/sentence       GPGGA   GPGSA   GPGSV   GPRMC   GPVTG
+ present:               x       x       x       x       x
+ smask:                 x       x       x       x       x
+ utc (date):                                    x
+ utc (time):            x                       x
+ sig:                   x                       x1
+ fix:                           x               x1
+ PDOP:                          x
+ HDOP:                  x       x
+ VDOP:                          x
+ lat:                   x                       x
+ lon:                   x                       x
+ elv:                   x
+ speed:                                         x       x
+ track:                                         x       x
+ mtrack:                                                x
+ magvar:                                        x
+ satinfo (inuse count): x       x1
+ satinfo (inuse):               x
+ satinfo (inview):                      x
+
+ x1 = not present in the sentence but the library sets it up.
+ </pre>
+ */
+
 #define NMEA_SIG_BAD   (0)
 #define NMEA_SIG_LOW   (1)
 #define NMEA_SIG_MID   (2)
 #define NMEA_SIG_HIGH  (3)
+#define NMEA_SIG_RTKIN (4)
+#define NMEA_SIG_FLRTK (5)
+#define NMEA_SIG_ESTIM (6)
+#define NMEA_SIG_MAN   (7)
+#define NMEA_SIG_SIM   (8)
 
 #define NMEA_FIX_BAD   (1)
 #define NMEA_FIX_2D    (2)
 #define NMEA_SATINPACK (4)
 #define NMEA_NSATPACKS (NMEA_MAXSAT / NMEA_SATINPACK)
 
-#define NMEA_DEF_LAT   (5001.2621)
-#define NMEA_DEF_LON   (3613.0595)
+#define NMEA_DEF_LAT   (0.0)
+#define NMEA_DEF_LON   (0.0)
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
 /**
+ * Date and time data
+ * @see nmea_time_now
+ */
+typedef struct _nmeaTIME {
+       int year;                                               /**< Years since 1900 */
+       int mon;                                                /**< Months since January - [0,11] */
+       int day;                                                /**< Day of the month - [1,31] */
+       int hour;                                               /**< Hours since midnight - [0,23] */
+       int min;                                                /**< Minutes after the hour - [0,59] */
+       int sec;                                                /**< Seconds after the minute - [0,59] */
+       int hsec;                                               /**< Hundredth part of second - [0,99] */
+} nmeaTIME;
+
+/**
  * Position data in fractional degrees or radians
  */
 typedef struct _nmeaPOS {
-       double lat; /**< Latitude */
-       double lon; /**< Longitude */
-
+       double lat;                                             /**< Latitude */
+       double lon;                                             /**< Longitude */
 } nmeaPOS;
 
 /**
@@ -61,12 +107,10 @@ typedef struct _nmeaPOS {
  * @see nmeaGPGSV
  */
 typedef struct _nmeaSATELLITE {
-       int id;      /**< Satellite PRN number */
-       int in_use;  /**< Used in position fix */
-       int elv;     /**< Elevation in degrees, 90 maximum */
-       int azimuth; /**< Azimuth, degrees from true north, 000 to 359 */
-       int sig;     /**< Signal, 00-99 dB */
-
+       int id;                                                 /**< Satellite PRN number */
+       int elv;                                                /**< Elevation in degrees, 90 maximum */
+       int azimuth;                                    /**< Azimuth, degrees from true north, 000 to 359 */
+       int sig;                                                /**< Signal, 00-99 dB */
 } nmeaSATELLITE;
 
 /**
@@ -75,10 +119,10 @@ typedef struct _nmeaSATELLITE {
  * @see nmeaGPGSV
  */
 typedef struct _nmeaSATINFO {
-       int inuse;  /**< Number of satellites in use (not those in view) */
-       int inview; /**< Total number of satellites in view */
-       nmeaSATELLITE sat[NMEA_MAXSAT]; /**< Satellites information */
-
+       int inuse;                                              /**< Number of satellites in use (not those in view) */
+       int in_use[NMEA_MAXSAT];                /**< IDs of satellites in use (not those in view) */
+       int inview;                                             /**< Total number of satellites in view */
+       nmeaSATELLITE sat[NMEA_MAXSAT]; /**< Satellites information (in view) */
 } nmeaSATINFO;
 
 /**
@@ -88,38 +132,76 @@ typedef struct _nmeaSATINFO {
  * @see nmea_GPGGA2info,  nmea_...2info
  */
 typedef struct _nmeaINFO {
-       int smask;    /**< Mask specifying from which sentences data has been obtained */
-
-       nmeaTIME utc; /**< UTC of position */
-
-       int sig; /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
-       int fix; /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
-
-       double PDOP;        /**< Position Dilution Of Precision */
-       double HDOP;        /**< Horizontal Dilution Of Precision */
-       double VDOP;        /**< Vertical Dilution Of Precision */
-
-       double lat;         /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
-       double lon;         /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
-       double elv;         /**< Antenna altitude above/below mean sea level (geoid) in meters */
-       double speed;       /**< Speed over the ground in kilometers/hour */
-       double direction;   /**< Track angle in degrees True */
-       double declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
-
-       nmeaSATINFO satinfo; /**< Satellites information */
+       uint32_t present;                               /**< Mask specifying which fields are present */
+
+       int smask;                                              /**< Mask specifying from which sentences data has been obtained */
+
+       nmeaTIME utc;                                   /**< UTC of position */
+
+       int sig;                                                /**< GPS quality indicator: 0 = Invalid
+                                                                   1 = Fix;
+                                                                                                           2 = Differential
+                                                                                                           3 = Sensitive
+                                                                                                           4 = Real Time Kinematic
+                                                                                                           5 = Float RTK,
+                                                                                                           6 = estimated (dead reckoning) (v2.3)
+                                                                                                           7 = Manual input mode
+                                                                                                           8 = Simulation mode) */
+
+       int fix;                                                /**< Operating mode, used for navigation: 1 = Fix not available
+                                                                                 2 = 2D
+                                                                                 3 = 3D) */
+
+       double PDOP;                                    /**< Position Dilution Of Precision */
+       double HDOP;                                    /**< Horizontal Dilution Of Precision */
+       double VDOP;                                    /**< Vertical Dilution Of Precision */
+
+       double lat;                                             /**< Latitude in NDEG:  +/-[degree][min].[sec/60] */
+       double lon;                                             /**< Longitude in NDEG: +/-[degree][min].[sec/60] */
+       double elv;                                             /**< Antenna altitude above/below mean sea level (geoid) in meters */
+       double speed;                                   /**< Speed over the ground in kph */
+       double track;                                   /**< Track angle in degrees True */
+       double mtrack;                                  /**< Magnetic Track angle in degrees True */
+       double magvar;                                  /**< Magnetic variation degrees */
+
+       nmeaSATINFO satinfo;                    /**< Satellites information */
 } nmeaINFO;
 
 /**
- * Enumeration for the fields names of a nmeaINFO structure
+ * Enumeration for the fields names of a nmeaINFO structure.
+ * The values are used in the 'present' mask.
  */
 typedef enum _nmeaINFO_FIELD {
-       SMASK, UTC, SIG, FIX, PDOP, HDOP, VDOP, LAT, LON, ELV, SPEED, DIRECTION,
-       DECLINATION, SATINFO
+       SMASK                   = (1 << 0),  /* 0x00001 */
+       UTCDATE                 = (1 << 1),  /* 0x00002 */
+       UTCTIME                 = (1 << 2),  /* 0x00004 */
+       SIG                             = (1 << 3),  /* 0x00008 */
+       FIX                             = (1 << 4),  /* 0x00010 */
+       PDOP                    = (1 << 5),  /* 0x00020 */
+       HDOP                    = (1 << 6),  /* 0x00040 */
+       VDOP                    = (1 << 7),  /* 0x00080 */
+       LAT                             = (1 << 8),  /* 0x00100 */
+       LON                             = (1 << 9),  /* 0x00200 */
+       ELV                             = (1 << 10), /* 0x00400 */
+       SPEED                   = (1 << 11), /* 0x00800 */
+       TRACK                   = (1 << 12), /* 0x01000 */
+       MTRACK                  = (1 << 13), /* 0x02000 */
+       MAGVAR                  = (1 << 14), /* 0x04000 */
+       SATINUSECOUNT   = (1 << 15), /* 0x08000 */
+       SATINUSE                = (1 << 16), /* 0x10000 */
+       SATINVIEW               = (1 << 17), /* 0x20000 */
+       _nmeaINFO_FIELD_LAST = SATINVIEW
 } nmeaINFO_FIELD;
 
+#define NMEA_INFO_PRESENT_MASK ((_nmeaINFO_FIELD_LAST << 1) - 1)
+
+void nmea_time_now(nmeaTIME *utc, uint32_t * present);
 void nmea_zero_INFO(nmeaINFO *info);
 
-bool nmea_INFO_has_field(int smask, nmeaINFO_FIELD fieldName);
+bool nmea_INFO_is_present_smask(int smask, nmeaINFO_FIELD fieldName);
+bool nmea_INFO_is_present(uint32_t present, nmeaINFO_FIELD fieldName);
+void nmea_INFO_set_present(uint32_t * present, nmeaINFO_FIELD fieldName);
+void nmea_INFO_unset_present(uint32_t * present, nmeaINFO_FIELD fieldName);
 
 void nmea_INFO_sanitise(nmeaINFO *nmeaInfo);
 
diff --git a/lib/pud/nmealib/include/nmea/nmea.h b/lib/pud/nmealib/include/nmea/nmea.h
deleted file mode 100644 (file)
index 0069c72..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * Copyright (c) 2008 Timur Sinitsyn
- * Copyright (c) 2011 Ferry Huberts
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_H__
-#define __NMEA_H__
-
-#include <nmea/context.h>
-#include <nmea/generate.h>
-#include <nmea/generator.h>
-#include <nmea/gmath.h>
-#include <nmea/info.h>
-#include <nmea/parse.h>
-#include <nmea/parser.h>
-#include <nmea/sentence.h>
-#include <nmea/time.h>
-#include <nmea/tok.h>
-#include <nmea/units.h>
-
-#endif /* __NMEA_H__ */
index adfe406..30a5a0d 100644 (file)
 #ifndef __NMEA_PARSE_H__
 #define __NMEA_PARSE_H__
 
-#include <nmea/info.h>
 #include <nmea/sentence.h>
 
+#include <stdbool.h>
+#include <stddef.h>
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-int nmea_pack_type(const char *buff, int buff_sz);
-int nmea_find_tail(const char *buff, int buff_sz, int *res_crc);
+bool nmea_parse_sentence_has_invalid_chars(const char * str, const size_t strlen, const char * strName, char * report,
+               const size_t reportSize);
 
-int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack);
-int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack);
-int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack);
-int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack);
-int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack);
+int nmea_parse_get_sentence_type(const char *s, const int len);
+int nmea_parse_get_sentence_length(const char *s, const int len, int *checksum);
 
-void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info);
-void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info);
-void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info);
-void nmea_GPRMC2info(nmeaGPRMC *pack, nmeaINFO *info);
-void nmea_GPVTG2info(nmeaGPVTG *pack, nmeaINFO *info);
+int nmea_parse_GPGGA(const char *s, const int len, nmeaGPGGA *pack);
+int nmea_parse_GPGSA(const char *s, const int len, nmeaGPGSA *pack);
+int nmea_parse_GPGSV(const char *s, const int len, nmeaGPGSV *pack);
+int nmea_parse_GPRMC(const char *s, const int len, nmeaGPRMC *pack);
+int nmea_parse_GPVTG(const char *s, const int len, nmeaGPVTG *pack);
 
 #ifdef  __cplusplus
 }
index 94d71c8..ce427bf 100644 (file)
 extern "C" {
 #endif
 
-/*
- * high level
+/**
+ * Description of a parser node / packet
  */
+typedef struct _nmeaParserNODE {
+       int packType;                                           /**< the type of the packet (see nmeaPACKTYPE) */
+       void *pack;                         /**< the packet (a pointer to a malloced sentence sctucture) */
+       struct _nmeaParserNODE *next_node;  /**< pointer to the next node / packet */
+} nmeaParserNODE;
 
-typedef struct _nmeaPARSER
-{
-    void *top_node;
-    void *end_node;
-    unsigned char *buffer;
-    int buff_size;
-    int buff_use;
-
+/**
+ * The parser data.
+ */
+typedef struct _nmeaPARSER {
+       nmeaParserNODE *top_node; /**< the first node / packet */
+       nmeaParserNODE *end_node; /**< the last node / packet */
+       char *buffer;             /**< the buffer containing the string to parse */
+       int buff_size;            /**< the size of the buffer */
+       int buff_use;             /**< the number of bytes in the buffer */
 } nmeaPARSER;
 
-int     nmea_parser_init(nmeaPARSER *parser);
-void    nmea_parser_destroy(nmeaPARSER *parser);
-
-int     nmea_parse(
-        nmeaPARSER *parser,
-        const char *buff, int buff_sz,
-        nmeaINFO *info
-        );
-
-/*
- * low level
- */
+int nmea_parser_init(nmeaPARSER *parser);
+void nmea_parser_destroy(nmeaPARSER *parser);
+int nmea_parse(nmeaPARSER *parser, const char *buff, const int buff_sz, nmeaINFO *info);
 
-int     nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz);
-int     nmea_parser_top(nmeaPARSER *parser);
-int     nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr);
-int     nmea_parser_peek(nmeaPARSER *parser, void **pack_ptr);
-int     nmea_parser_drop(nmeaPARSER *parser);
-int     nmea_parser_buff_clear(nmeaPARSER *parser);
-int     nmea_parser_queue_clear(nmeaPARSER *parser);
+int nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz);
+int nmea_parser_top(const nmeaPARSER *parser);
+int nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr);
+int nmea_parser_peek(const nmeaPARSER *parser, void **pack_ptr);
+int nmea_parser_drop(nmeaPARSER *parser);
+void nmea_parser_buff_clear(nmeaPARSER *parser);
+void nmea_parser_queue_clear(nmeaPARSER *parser);
 
 #ifdef  __cplusplus
 }
index 8f36272..88f8703 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*! \file */
+/**
+ * Extended descriptions of sentences are taken from
+ *   http://www.gpsinformation.org/dale/nmea.htm
+ */
 
 #ifndef __NMEA_SENTENCE_H__
 #define __NMEA_SENTENCE_H__
 
 #include <nmea/info.h>
-#include <nmea/time.h>
+
+#include <stdint.h>
 
 #ifdef  __cplusplus
 extern "C" {
@@ -33,97 +37,246 @@ extern "C" {
 /**
  * NMEA packets type which parsed and generated by library
  */
-enum nmeaPACKTYPE
-{
-    GPNON   = 0x0000,   /**< Unknown packet type. */
-    GPGGA   = 0x0001,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
-    GPGSA   = 0x0002,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
-    GPGSV   = 0x0004,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
-    GPRMC   = 0x0008,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
-    GPVTG   = 0x0010    /**< VTG - Actual track made good and speed over ground. */
+enum nmeaPACKTYPE {
+       GPNON = 0,                      /**< Unknown packet type. */
+       GPGGA = (1 << 0),       /**< GGA - Essential fix data which provide 3D location and accuracy data. */
+       GPGSA = (1 << 1),       /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
+       GPGSV = (1 << 2),       /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
+       GPRMC = (1 << 3),       /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
+       GPVTG = (1 << 4)        /**< VTG - Actual track made good and speed over ground. */
 };
 
 /**
  * GGA packet information structure (Global Positioning System Fix Data)
+ *
+ * <pre>
+ * GGA - essential fix data which provide 3D location and accuracy data.
+ *
+ * $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
+ *
+ * Where:
+ *      GGA          Global Positioning System Fix Data
+ *      123519       Fix taken at 12:35:19 UTC
+ *      4807.038,N   Latitude 48 deg 07.038' N
+ *      01131.000,E  Longitude 11 deg 31.000' E
+ *      1            Signal quality: 0 = invalid
+ *                                   1 = GPS fix (SPS)
+ *                                   2 = DGPS fix
+ *                                   3 = PPS fix
+ *                                              4 = Real Time Kinematic
+ *                                              5 = Float RTK
+ *                                   6 = estimated (dead reckoning) (2.3 feature)
+ *                                              7 = Manual input mode
+ *                                              8 = Simulation mode
+ *      08           Number of satellites being tracked
+ *      0.9          Horizontal dilution of position
+ *      545.4,M      Altitude, Meters, above mean sea level
+ *      46.9,M       Height of geoid (mean sea level) above WGS84
+ *                       ellipsoid
+ *      (empty field) time in seconds since last DGPS update
+ *      (empty field) DGPS station ID number
+ *      *47          the checksum data, always begins with *
+ *
+ * If the height of geoid is missing then the altitude should be suspect. Some
+ * non-standard implementations report altitude with respect to the ellipsoid
+ * rather than geoid altitude. Some units do not report negative altitudes at
+ * all. This is the only sentence that reports altitude.
+ * </pre>
  */
-typedef struct _nmeaGPGGA
-{
-    nmeaTIME utc;       /**< UTC of position (just time) */
-       double  lat;        /**< Latitude in NDEG - [degree][min].[sec/60] */
-    char    ns;         /**< [N]orth or [S]outh */
-       double  lon;        /**< Longitude in NDEG - [degree][min].[sec/60] */
-    char    ew;         /**< [E]ast or [W]est */
-    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
-       int     satinuse;   /**< Number of satellites in use (not those in view) */
-    double  HDOP;       /**< Horizontal dilution of precision */
-    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) */
-    char    elv_units;  /**< [M]eters (Antenna height unit) */
-    double  diff;       /**< Geoidal separation (Diff. between WGS-84 earth ellipsoid and mean sea level. '-' = geoid is below WGS-84 ellipsoid) */
-    char    diff_units; /**< [M]eters (Units of geoidal separation) */
-    double  dgps_age;   /**< Time in seconds since last DGPS update */
-    int     dgps_sid;   /**< DGPS station ID number */
-
+typedef struct _nmeaGPGGA {
+       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
+       nmeaTIME utc;                           /**< UTC of position (just time) */
+       double lat;                                     /**< Latitude in NDEG - [degree][min].[sec/60] */
+       char ns;                                        /**< [N]orth or [S]outh */
+       double lon;                                     /**< Longitude in NDEG - [degree][min].[sec/60] */
+       char ew;                                        /**< [E]ast or [W]est */
+       int sig;                                        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
+       int satinuse;                           /**< Number of satellites in use (not those in view) */
+       double HDOP;                            /**< Horizontal dilution of precision */
+       double elv;                                     /**< Antenna altitude above/below mean sea level (geoid) */
+       char elv_units;                         /**< [M]eters (Antenna height unit) */
+       double diff;                            /**< Geoidal separation (Diff. between WGS-84 earth ellipsoid and mean sea level. '-' = geoid is below WGS-84 ellipsoid) */
+       char diff_units;                        /**< [M]eters (Units of geoidal separation) */
+       double dgps_age;                        /**< Time in seconds since last DGPS update */
+       int dgps_sid;                           /**< DGPS station ID number */
 } nmeaGPGGA;
 
 /**
  * GSA packet information structure (Satellite status)
+ *
+ * <pre>
+ * GSA - GPS DOP and active satellites.
+ *
+ * This sentence provides details on the nature of the fix. It includes the
+ * numbers of the satellites being used in the current solution and the DOP.
+ *
+ * DOP (dilution of precision) is an indication of the effect of satellite
+ * geometry on the accuracy of the fix. It is a unitless number where smaller
+ * is better. For 3D fixes using 4 satellites a 1.0 would be considered to be
+ * a perfect number, however for overdetermined solutions it is possible to see
+ * numbers below 1.0.
+ *
+ * There are differences in the way the PRN's are presented which can effect the
+ * ability of some programs to display this data. For example, in the example
+ * shown below there are 5 satellites in the solution and the null fields are
+ * scattered indicating that the almanac would show satellites in the null
+ * positions that are not being used as part of this solution. Other receivers
+ * might output all of the satellites used at the beginning of the sentence with
+ * the null field all stacked up at the end. This difference accounts for some
+ * satellite display programs not always being able to display the satellites
+ * being tracked. Some units may show all satellites that have ephemeris data
+ * without regard to their use as part of the solution but this is non-standard.
+ *
+ * $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
+ *
+ * Where:
+ *      GSA      Satellite status
+ *      A        Auto selection of 2D or 3D fix (M = manual)
+ *      3        3D fix - values include: 1 = no fix
+ *                                        2 = 2D fix
+ *                                        3 = 3D fix
+ *      04,05... PRNs of satellites used for fix (space for 12)
+ *      2.5      PDOP (dilution of precision)
+ *      1.3      Horizontal dilution of precision (HDOP)
+ *      2.1      Vertical dilution of precision (VDOP)
+ *      *39      the checksum data, always begins with *
+ * </pre>
  */
-typedef struct _nmeaGPGSA
-{
-    char    fix_mode;   /**< Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D) */
-    int     fix_type;   /**< Type, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
-    int     sat_prn[NMEA_MAXSAT]; /**< PRNs of satellites used in position fix (null for unused fields) */
-    double  PDOP;       /**< Dilution of precision */
-    double  HDOP;       /**< Horizontal dilution of precision */
-    double  VDOP;       /**< Vertical dilution of precision */
-
+typedef struct _nmeaGPGSA {
+       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
+       char fix_mode;                          /**< Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D) */
+       int fix_type;                           /**< Type, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
+       int sat_prn[NMEA_MAXSAT];       /**< PRNs of satellites used in position fix (0 for unused fields) */
+       double PDOP;                            /**< Dilution of precision */
+       double HDOP;                            /**< Horizontal dilution of precision */
+       double VDOP;                            /**< Vertical dilution of precision */
 } nmeaGPGSA;
 
 /**
  * GSV packet information structure (Satellites in view)
+ *
+ * <pre>
+ * GSV - Satellites in View
+ *
+ * Shows data about the satellites that the unit might be able to find based on
+ * its viewing mask and almanac data. It also shows current ability to track
+ * this data. Note that one GSV sentence only can provide data for up to 4
+ * satellites and thus there may need to be 3 sentences for the full
+ * information. It is reasonable for the GSV sentence to contain more satellites
+ * than GGA might indicate since GSV may include satellites that are not used as
+ * part of the solution. It is not a requirement that the GSV sentences all
+ * appear in sequence. To avoid overloading the data bandwidth some receivers
+ * may place the various sentences in totally different samples since each
+ * sentence identifies which one it is.
+ *
+ * The field called SNR (Signal to Noise Ratio) in the NMEA standard is often
+ * referred to as signal strength. SNR is an indirect but more useful value than
+ * raw signal strength. It can range from 0 to 99 and has units of dB according
+ * to the NMEA standard, but the various manufacturers send different ranges of
+ * numbers with different starting numbers so the values themselves cannot
+ * necessarily be used to evaluate different units. The range of working values
+ * in a given gps will usually show a difference of about 25 to 35 between the
+ * lowest and highest values, however 0 is a special case and may be shown on
+ * satellites that are in view but not being tracked.
+ *
+ * $GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
+ *
+ * Where:
+ *      GSV          Satellites in view
+ *      2            Number of sentences for full data
+ *      1            sentence 1 of 2
+ *      08           Number of satellites in view
+ *
+ *      01           Satellite PRN number
+ *      40           Elevation, degrees
+ *      083          Azimuth, degrees
+ *      46           SNR - higher is better
+ *           for up to 4 satellites per sentence
+ *
+ *      *75          the checksum data, always begins with *
+ * </pre>
  */
-typedef struct _nmeaGPGSV
-{
-    int     pack_count; /**< Total number of messages of this type in this cycle */
-    int     pack_index; /**< Message number */
-    int     sat_count;  /**< Total number of satellites in view */
-    nmeaSATELLITE sat_data[NMEA_SATINPACK];
-
+typedef struct _nmeaGPGSV {
+       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
+       int pack_count;                         /**< Total number of messages of this type in this cycle */
+       int pack_index;                         /**< Message number */
+       int sat_count;                          /**< Total number of satellites in view */
+       nmeaSATELLITE sat_data[NMEA_SATINPACK];
 } nmeaGPGSV;
 
 /**
- * RMC packet information structure (Recommended Minimum sentence C)
+ * RMC -packet information structure (Recommended Minimum sentence C)
+ *
+ * <pre>
+ * RMC - Recommended Minimum sentence C
+ *
+ * NMEA has its own version of essential gps pvt (position, velocity,
+ * time) data. It is called RMC, the Recommended Minimum, which will look
+ * similar to:
+ *
+ * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
+ * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W,A*6A (v2.3)
+ *
+ * Where:
+ *      RMC          Recommended Minimum sentence C
+ *      123519       Fix taken at 12:35:19 UTC
+ *      A            Status A=active or V=Void.
+ *      4807.038,N   Latitude 48 deg 07.038' N
+ *      01131.000,E  Longitude 11 deg 31.000' E
+ *      022.4        Speed over the ground in knots
+ *      084.4        Track angle in degrees True
+ *      230394       Date - 23rd of March 1994
+ *      003.1,W      Magnetic Variation
+ *      A            Mode A=autonomous, D=differential, E=Estimated,
+ *                        N=not valid, S=Simulator (NMEA v2.3)
+ *      *6A          The checksum data, always begins with *
+ * </pre>
  */
-typedef struct _nmeaGPRMC
-{
-    nmeaTIME utc;       /**< UTC of position */
-    char    status;     /**< Status (A = active or V = void) */
-       double  lat;        /**< Latitude in NDEG - [degree][min].[sec/60] */
-    char    ns;         /**< [N]orth or [S]outh */
-       double  lon;        /**< Longitude in NDEG - [degree][min].[sec/60] */
-    char    ew;         /**< [E]ast or [W]est */
-    double  speed;      /**< Speed over the ground in knots */
-    double  direction;  /**< Track angle in degrees True */
-    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
-    char    declin_ew;  /**< [E]ast or [W]est */
-    char    mode;       /**< Mode indicator of fix type (A = autonomous, D = differential, E = estimated, N = not valid, S = simulator) */
-
+typedef struct _nmeaGPRMC {
+       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
+       nmeaTIME utc;                           /**< UTC of position */
+       char status;                            /**< Status (A = active or V = void) */
+       double lat;                                     /**< Latitude in NDEG - [degree][min].[sec/60] */
+       char ns;                                        /**< [N]orth or [S]outh */
+       double lon;                                     /**< Longitude in NDEG - [degree][min].[sec/60] */
+       char ew;                                        /**< [E]ast or [W]est */
+       double speed;                           /**< Speed over the ground in knots */
+       double track;                           /**< Track angle in degrees True */
+       double magvar;                          /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
+       char magvar_ew;                         /**< [E]ast or [W]est */
+       char mode;                                      /**< Mode indicator of fix type (A=autonomous, D=differential, E=Estimated, N=not valid, S=Simulator) */
 } nmeaGPRMC;
 
 /**
  * VTG packet information structure (Track made good and ground speed)
+ *
+ * <pre>
+ * VTG - Velocity made good.
+ *
+ * The gps receiver may use the LC prefix instead of GP if it is emulating
+ * Loran output.
+ *
+ * $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48
+ *
+ * where:
+ *      VTG          Track made good and ground speed
+ *      054.7,T      True track made good (degrees)
+ *      034.4,M      Magnetic track made good
+ *      005.5,N      Ground speed, knots
+ *      010.2,K      Ground speed, Kilometers per hour
+ *      *48          Checksum
+ * </pre>
  */
-typedef struct _nmeaGPVTG
-{
-    double  dir;        /**< True track made good (degrees) */
-    char    dir_t;      /**< Fixed text 'T' indicates that track made good is relative to true north */
-    double  dec;        /**< Magnetic track made good */
-    char    dec_m;      /**< Fixed text 'M' */
-    double  spn;        /**< Ground speed, knots */
-    char    spn_n;      /**< Fixed text 'N' indicates that speed over ground is in knots */
-    double  spk;        /**< Ground speed, kilometers per hour */
-    char    spk_k;      /**< Fixed text 'K' indicates that speed over ground is in kilometers/hour */
-
+typedef struct _nmeaGPVTG {
+       uint32_t present;                       /**< Mask specifying which fields are present, same as in nmeaINFO */
+       double track;                           /**< True track made good (degrees) */
+       char track_t;                           /**< Fixed text 'T' indicates that track made good is relative to true north */
+       double mtrack;                          /**< Magnetic track made good */
+       char mtrack_m;                          /**< Fixed text 'M' */
+       double spn;                                     /**< Ground speed, knots */
+       char spn_n;                                     /**< Fixed text 'N' indicates that speed over ground is in knots */
+       double spk;                                     /**< Ground speed, kilometers per hour */
+       char spk_k;                                     /**< Fixed text 'K' indicates that speed over ground is in kilometers/hour */
 } nmeaGPVTG;
 
 void nmea_zero_GPGGA(nmeaGPGGA *pack);
index 7ca6c4e..3ee3c12 100644 (file)
 extern "C" {
 #endif
 
-int nmea_calc_crc(const char *buff, int buff_sz);
-int nmea_atoi(const char *str, int str_sz, int radix);
-double nmea_atof(const char *str, int str_sz);
-int nmea_printf(char *buff, int buff_sz, const char *format, ...) __attribute__ ((format(printf, 3, 4)));
-int nmea_scanf(const char *buff, int buff_sz, const char *format, ...);
+int nmea_calc_crc(const char *s, const int len);
+int nmea_atoi(const char *s, const int len, const int radix);
+double nmea_atof(const char *s, const int len);
+int nmea_printf(char *s, int len, const char *format, ...) __attribute__ ((format(printf, 3, 4)));
+int nmea_scanf(const char *s, int len, const char *format, ...);
 
 #ifdef  __cplusplus
 }
diff --git a/lib/pud/nmealib/include/nmea/units.h b/lib/pud/nmealib/include/nmea/units.h
deleted file mode 100644 (file)
index ebc717a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * Copyright (c) 2008 Timur Sinitsyn
- * Copyright (c) 2011 Ferry Huberts
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_UNITS_H__
-#define __NMEA_UNITS_H__
-
-/*
- * Distance units
- */
-
-#define NMEA_TUD_YARDS (1.0936) /**< Yards, meter * NMEA_TUD_YARDS = yard */
-#define NMEA_TUD_KNOTS (1.852)  /**< Knots, kilometer / NMEA_TUD_KNOTS = knot */
-#define NMEA_TUD_MILES (1.609)  /**< Miles, kilometer / NMEA_TUD_MILES = mile */
-
-/*
- * Speed units
- */
-
-#define NMEA_TUS_MS    (3.6)    /**< Meters per seconds, (k/h) / NMEA_TUS_MS= (m/s) */
-
-#endif /* __NMEA_UNITS_H__ */
diff --git a/lib/pud/nmealib/include/nmea/util.h b/lib/pud/nmealib/include/nmea/util.h
deleted file mode 100644 (file)
index f3b0f6d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * Copyright (c) 2011 Ferry Huberts
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __NMEA_UTIL_H__
-#define __NMEA_UTIL_H__
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-bool nmea_string_has_invalid_chars(const char * str, const char * strName,
-               char * report, size_t reportSize);
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* __NMEA_UTIL_H__ */
index e8bb187..3b93a21 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/nmea.h>
+#include <nmea/info.h>
+
+#include <nmea/gmath.h>
+#include <nmea/generate.h>
 
 #include <stdio.h>
 #include <unistd.h>
 
 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
-    nmeaINFO info;
-    char buff[2048];
-    int gen_sz;
-    int it;
+       nmeaINFO info;
+       char buff[2048];
+       int gen_sz;
+       int it;
+
+       nmea_zero_INFO(&info);
 
-    nmea_zero_INFO(&info);
+       info.sig = 3;
+       info.fix = 3;
+       info.lat = 5000.0;
+       info.lon = 3600.0;
+       info.speed = 2.14 * NMEA_TUS_MS;
+       info.elv = 10.86;
+       info.track = 45;
+       info.mtrack = 55;
+       info.magvar = 55;
+       info.HDOP = 2.3;
+       info.VDOP = 1.2;
+       info.PDOP = 2.594224354;
 
-    info.sig = 3;
-    info.fix = 3;
-    info.lat = 5000.0;
-    info.lon = 3600.0;
-    info.speed = 2.14 * NMEA_TUS_MS;
-    info.elv = 10.86;
+       nmea_INFO_set_present(&info.present, SIG);
+       nmea_INFO_set_present(&info.present, FIX);
+       nmea_INFO_set_present(&info.present, LAT);
+       nmea_INFO_set_present(&info.present, LON);
+       nmea_INFO_set_present(&info.present, SPEED);
+       nmea_INFO_set_present(&info.present, ELV);
+       nmea_INFO_set_present(&info.present, TRACK);
+       nmea_INFO_set_present(&info.present, MTRACK);
+       nmea_INFO_set_present(&info.present, MAGVAR);
+       nmea_INFO_set_present(&info.present, HDOP);
+       nmea_INFO_set_present(&info.present, VDOP);
+       nmea_INFO_set_present(&info.present, PDOP);
 
-    info.satinfo.inuse = 1;
-    info.satinfo.inview = 1;
+       info.satinfo.inuse = NMEA_MAXSAT;
+       nmea_INFO_set_present(&info.present, SATINUSECOUNT);
+       for (it = 0; it < NMEA_MAXSAT; it++) {
+               info.satinfo.in_use[it] = it + 1;
+       }
+       nmea_INFO_set_present(&info.present, SATINUSE);
 
-    /*
-    info.satinfo.sat[0].id = 1;
-    info.satinfo.sat[0].in_use = 1;
-    info.satinfo.sat[0].elv = 50;
-    info.satinfo.sat[0].azimuth = 0;
-    info.satinfo.sat[0].sig = 99;
-    */
+       info.satinfo.inview = NMEA_MAXSAT;
+       for (it = 0; it < NMEA_MAXSAT; it++) {
+               info.satinfo.sat[it].id = it + 1;
+               info.satinfo.sat[it].elv = (it * 10);
+               info.satinfo.sat[it].azimuth = it + 1;
+               info.satinfo.sat[it].sig = 99 - it;
+       }
+       nmea_INFO_set_present(&info.present, SATINVIEW);
 
-    for(it = 0; it < 10; ++it)
-    {
-        gen_sz = nmea_generate(
-            &buff[0], 2048, &info,
-            GPGGA | GPGSA | GPGSV | GPRMC | GPVTG
-            );
+       for (it = 0; it < 10; it++) {
+               gen_sz = nmea_generate(&buff[0], 2048, &info, GPGGA | GPGSA | GPGSV | GPRMC | GPVTG);
 
-        buff[gen_sz] = 0;
-        printf("%s\n", &buff[0]);
+               buff[gen_sz] = 0;
+               printf("%s\n", &buff[0]);
 
-        usleep(500000);
+               usleep(500000);
 
-        info.speed += .1;
-    }
+               info.speed += .1;
+       }
 
-    return 0;
+       return 0;
 }
index b48c53d..957489a 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/nmea.h>
+#include <nmea/generator.h>
+#include <nmea/sentence.h>
 
 #include <stdio.h>
 #include <unistd.h>
 
 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
-    nmeaGENERATOR *gen;
-    nmeaINFO info;
-    char buff[2048];
-    int gen_sz;
-    int it;
+       nmeaGENERATOR *gen;
+       nmeaINFO info;
+       char buff[2048];
+       int gen_sz;
+       int it;
 
-    nmea_zero_INFO(&info);
+       nmea_zero_INFO(&info);
 
-    if(0 == (gen = nmea_create_generator(NMEA_GEN_ROTATE, &info)))
-        return -1;
+       nmea_INFO_set_present(&info.present, PDOP);
+       nmea_INFO_set_present(&info.present, HDOP);
+       nmea_INFO_set_present(&info.present, VDOP);
+       nmea_INFO_set_present(&info.present, ELV);
 
-    for(it = 0; it < 10000; ++it)
-    {
-        gen_sz = nmea_generate_from(
-            &buff[0], 2048, &info, gen,
-            GPGGA | GPGSA | GPGSV | GPRMC | GPVTG
-            );
+       if (0 == (gen = nmea_create_generator(NMEA_GEN_ROTATE, &info)))
+               return -1;
 
-        buff[gen_sz] = 0;
-        printf("%s\n", &buff[0]);
+       for (it = 0; it < 10000; it++) {
+               gen_sz = nmea_generate_from(&buff[0], 2048, &info, gen, GPGGA | GPGSA | GPGSV | GPRMC | GPVTG);
 
-        usleep(500000);        
-    }
+               buff[gen_sz] = 0;
+               printf("%s\n", &buff[0]);
 
-    nmea_gen_destroy(gen);
+               usleep(500000);
+       }
 
-    return 0;
+       nmea_gen_destroy(gen);
+
+       return 0;
 }
index 7b81769..cda96dd 100644 (file)
@@ -18,7 +18,9 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
  */\r
 \r
-#include <nmea/nmea.h>\r
+#include <nmea/info.h>\r
+#include <nmea/parser.h>\r
+#include <nmea/gmath.h>\r
 \r
 #include <stdio.h>\r
 #include <string.h>\r
 #define NUM_POINTS 4\r
 \r
 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {\r
-    const char *buff[] = {\r
-        "$GPRMC,213916.199,A,4221.0377,N,07102.9778,W,0.00,,010207,,,A*6A\r\n",\r
-        "$GPRMC,213917.199,A,4221.0510,N,07102.9549,W,0.23,175.43,010207,,,A*77\r\n",\r
-        "$GPRMC,213925.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*68\r\n",\r
-        "$GPRMC,111609.14,A,5001.27,N,3613.06,E,11.2,0.0,261206,0.0,E*50\r\n"\r
-    };\r
+       const char *buff[] = { "$GPRMC,213916.199,A,4221.0377,N,07102.9778,W,0.00,,010207,,,A*6A\r\n",\r
+                       "$GPRMC,213917.199,A,4221.0510,N,07102.9549,W,0.23,175.43,010207,,,A*77\r\n",\r
+                       "$GPRMC,213925.000,A,4221.1129,N,07102.9146,W,0.00,,010207,,,A*68\r\n",\r
+                       "$GPRMC,111609.14,A,5001.27,N,3613.06,E,11.2,0.0,261206,0.0,E*50\r\n" };\r
 \r
-    nmeaPOS pos[NUM_POINTS], pos_moved[NUM_POINTS][2];\r
-    double dist[NUM_POINTS][2]; \r
-    double azimuth[NUM_POINTS][2], azimuth_moved[NUM_POINTS];\r
-    int result[2];\r
-    int it = 0;\r
+       nmeaPOS pos[NUM_POINTS], pos_moved[NUM_POINTS][2];\r
+       double dist[NUM_POINTS][2];\r
+       double azimuth[NUM_POINTS][2], azimuth_moved[NUM_POINTS];\r
+       int result[2];\r
+       int it = 0;\r
 \r
-    nmeaPARSER parser;\r
-    nmea_parser_init(&parser);\r
+       nmeaPARSER parser;\r
+       nmea_parser_init(&parser);\r
 \r
-    for(it = 0; it < NUM_POINTS; ++it)\r
-    {\r
-        nmeaINFO info;\r
-        nmea_zero_INFO(&info);\r
-        (void)nmea_parse(&parser, buff[it], (int)strlen(buff[it]), &info);\r
-        nmea_info2pos(&info, &pos[it]);\r
-    }\r
+       for (it = 0; it < NUM_POINTS; it++) {\r
+               nmeaINFO info;\r
+               nmea_zero_INFO(&info);\r
+               (void) nmea_parse(&parser, buff[it], (int) strlen(buff[it]), &info);\r
+               nmea_info2pos(&info, &pos[it]);\r
+       }\r
 \r
-    nmea_parser_destroy(&parser);\r
+       nmea_parser_destroy(&parser);\r
 \r
-    for(it = 0; it < NUM_POINTS; ++it)\r
-    {\r
-        dist[it][0] = nmea_distance(&pos[0], &pos[it]);\r
-        dist[it][1] = nmea_distance_ellipsoid(\r
-            &pos[0], &pos[it], &azimuth[it][0], &azimuth[it][1]\r
-            );\r
-    }\r
+       for (it = 0; it < NUM_POINTS; it++) {\r
+               dist[it][0] = nmea_distance(&pos[0], &pos[it]);\r
+               dist[it][1] = nmea_distance_ellipsoid(&pos[0], &pos[it], &azimuth[it][0], &azimuth[it][1]);\r
+       }\r
 \r
-    for(it = 0; it < NUM_POINTS; ++it)\r
-    {\r
-        result[0] = nmea_move_horz(&pos[0], &pos_moved[it][0], azimuth[it][0], dist[it][0]);\r
-        result[1] = nmea_move_horz_ellipsoid(\r
-            &pos[0], &pos_moved[it][1], azimuth[it][0], dist[it][0], &azimuth_moved[it]\r
-            );\r
+       for (it = 0; it < NUM_POINTS; it++) {\r
+               result[0] = nmea_move_horz(&pos[0], &pos_moved[it][0], azimuth[it][0], dist[it][0]);\r
+               result[1] = nmea_move_horz_ellipsoid(&pos[0], &pos_moved[it][1], azimuth[it][0], dist[it][0],\r
+                               &azimuth_moved[it]);\r
 \r
-    }\r
+       }\r
 \r
-    /* Output of results */\r
-    printf("Coordinate points:\n");\r
-    for(it = 0; it < NUM_POINTS; ++it)\r
-    {\r
-        printf(\r
-            "P%d in radians: lat:%9.6lf lon:%9.6lf  \tin degree: lat:%+010.6lf° lon:%+011.6lf°\n",\r
-            it, pos[it].lat, pos[it].lon, nmea_radian2degree(pos[it].lat), nmea_radian2degree(pos[it].lon)\r
-            );\r
-    }\r
+       /* Output of results */\r
+       printf("Coordinate points:\n");\r
+       for (it = 0; it < NUM_POINTS; it++) {\r
+               printf("P%d in radians: lat:%9.6lf lon:%9.6lf  \tin degree: lat:%+010.6lf° lon:%+011.6lf°\n", it, pos[it].lat,\r
+                               pos[it].lon, nmea_radian2degree(pos[it].lat), nmea_radian2degree(pos[it].lon));\r
+       }\r
 \r
-    printf("\nCalculation results:\n");\r
-    for(it = 0; it < NUM_POINTS; ++it)\r
-    {\r
-        printf("\n");\r
-        printf("Distance P0 to P%d\ton spheroid:  %14.3lf m\n", it, dist[it][0]);\r
-        printf("Distance P0 to P%d\ton ellipsoid: %14.3lf m\n", it, dist[it][1]);\r
-        printf("Azimuth  P0 to P%d\tat start: %8.3lf°\tat end: %8.3lf°\n", it, nmea_radian2degree(azimuth[it][0]), nmea_radian2degree(azimuth[it][1]));\r
-        printf("Move     P0 to P%d\t         \tAzimuth at end: %8.3lf°\n", it, nmea_radian2degree(azimuth_moved[it]));\r
-        printf("Move     P0 to P%d\ton spheroid:  %3s lat:%+010.6lf° lon:%+011.6lf°\n", it, result[0] == 1 ? "OK" : "nOK", nmea_radian2degree(pos_moved[it][0].lat), nmea_radian2degree(pos_moved[it][0].lon));\r
-        printf("Move     P0 to P%d\ton ellipsoid: %3s lat:%+010.6lf° lon:%+011.6lf°\n", it, result[0] == 1 ? "OK" : "nOK", nmea_radian2degree(pos_moved[it][1].lat), nmea_radian2degree(pos_moved[it][1].lon));\r
-        printf("Move     P0 to P%d\toriginal:         lat:%+010.6lf° lon:%+011.6lf°\n", it, nmea_radian2degree(pos[it].lat), nmea_radian2degree(pos[it].lon));\r
-    }\r
+       printf("\nCalculation results:\n");\r
+       for (it = 0; it < NUM_POINTS; it++) {\r
+               printf("\n");\r
+               printf("Distance P0 to P%d\ton spheroid:  %14.3lf m\n", it, dist[it][0]);\r
+               printf("Distance P0 to P%d\ton ellipsoid: %14.3lf m\n", it, dist[it][1]);\r
+               printf("Azimuth  P0 to P%d\tat start: %8.3lf°\tat end: %8.3lf°\n", it, nmea_radian2degree(azimuth[it][0]),\r
+                               nmea_radian2degree(azimuth[it][1]));\r
+               printf("Move     P0 to P%d\t         \tAzimuth at end: %8.3lf°\n", it, nmea_radian2degree(azimuth_moved[it]));\r
+               printf("Move     P0 to P%d\ton spheroid:  %3s lat:%+010.6lf° lon:%+011.6lf°\n", it,\r
+                               result[0] == 1 ? "OK" : "nOK", nmea_radian2degree(pos_moved[it][0].lat),\r
+                               nmea_radian2degree(pos_moved[it][0].lon));\r
+               printf("Move     P0 to P%d\ton ellipsoid: %3s lat:%+010.6lf° lon:%+011.6lf°\n", it,\r
+                               result[0] == 1 ? "OK" : "nOK", nmea_radian2degree(pos_moved[it][1].lat),\r
+                               nmea_radian2degree(pos_moved[it][1].lon));\r
+               printf("Move     P0 to P%d\toriginal:         lat:%+010.6lf° lon:%+011.6lf°\n", it,\r
+                               nmea_radian2degree(pos[it].lat), nmea_radian2degree(pos[it].lon));\r
+       }\r
 \r
-    return 0;\r
+       return 0;\r
 }\r
index a29a6c2..f950415 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/nmea.h>
+#include <nmea/info.h>
+#include <nmea/parser.h>
+#include <nmea/gmath.h>
 
 #include <stdio.h>
 #include <string.h>
 
 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
-    const char *buff[] = {
-        "$GPRMC,173843,A,3349.896,N,11808.521,W,000.0,360.0,230108,013.4,E*69\r\n",
-        "$GPGGA,111609.14,5001.27,N,3613.06,E,3,08,0.0,10.2,M,0.0,M,0.0,0000*70\r\n",
-        "$GPGSV,2,1,08,01,05,005,80,02,05,050,80,03,05,095,80,04,05,140,80*7f\r\n",
-        "$GPGSV,2,2,08,05,05,185,80,06,05,230,80,07,05,275,80,08,05,320,80*71\r\n",
-        "$GPGSA,A,3,01,02,03,04,05,06,07,08,00,00,00,00,0.0,0.0,0.0*3a\r\n",
-        "$GPRMC,111609.14,A,5001.27,N,3613.06,E,11.2,0.0,261206,0.0,E*50\r\n",
-        "$GPVTG,217.5,T,208.8,M,000.00,N,000.01,K*4C\r\n"
-    };
-
-    int it;
-    nmeaINFO info;
-    nmeaPARSER parser;
-    nmeaPOS dpos;
-
-    nmea_zero_INFO(&info);
-    nmea_parser_init(&parser);
-
-    for(it = 0; it < 6; ++it)
-    {
-        nmea_parse(&parser, buff[it], (int)strlen(buff[it]), &info);
-
-        nmea_info2pos(&info, &dpos);
-        printf("%03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d\n", it, dpos.lat,
-               dpos.lon, info.sig, info.fix);
-    }
-
-    nmea_parser_destroy(&parser);
-
-    return 0;
+       const char *buff[] = { "$GPRMC,173843,A,3349.896,N,11808.521,W,000.0,360.0,230108,013.4,E*69\r\n",
+                       "$GPGGA,111609.14,5001.27,N,3613.06,E,3,08,0.0,10.2,M,0.0,M,0.0,0000*70\r\n",
+                       "$GPGSV,2,1,08,01,05,005,80,02,05,050,80,03,05,095,80,04,05,140,80*7f\r\n",
+                       "$GPGSV,2,2,08,05,05,185,80,06,05,230,80,07,05,275,80,08,05,320,80*71\r\n",
+                       "$GPGSA,A,3,01,02,03,04,05,06,07,08,00,00,00,00,0.0,0.0,0.0*3a\r\n",
+                       "$GPRMC,111609.14,A,5001.27,N,3613.06,E,11.2,0.0,261206,0.0,E*50\r\n",
+                       "$GPVTG,217.5,T,208.8,M,000.00,N,000.01,K*4C\r\n" };
+
+       int it;
+       nmeaINFO info;
+       nmeaPARSER parser;
+       nmeaPOS dpos;
+
+       nmea_zero_INFO(&info);
+       nmea_parser_init(&parser);
+
+       for (it = 0; it < 6; it++) {
+               nmea_parse(&parser, buff[it], (int) strlen(buff[it]), &info);
+
+               nmea_info2pos(&info, &dpos);
+               printf("%03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d\n", it, dpos.lat, dpos.lon, info.sig, info.fix);
+       }
+
+       nmea_parser_destroy(&parser);
+
+       return 0;
 }
index cc47180..3836657 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <nmea/nmea.h>
+#include <nmea/info.h>
+#include <nmea/context.h>
+#include <nmea/parser.h>
+#include <nmea/gmath.h>
 
 #include <stdio.h>
-#include <string.h>
 #include <unistd.h>
+#include <libgen.h>
+#include <string.h>
 
+static const char * traceStr = "Trace: ";
+static const char * errorStr = "Error: ";
+static const char * eol = "\n";
 
-static void trace(const char *str, int str_size)
-{
-    printf("Trace: ");
-    write(1, str, str_size);
-    printf("\n");
+static void trace(const char *str, int str_size) {
+       write(1, traceStr, strlen(traceStr));
+       write(1, str, str_size);
+       write(1, eol, strlen(eol));
 }
-static void error(const char *str, int str_size)
-{
-    printf("Error: ");
-    write(1, str, str_size);
-    printf("\n");
+static void error(const char *str, int str_size) {
+       write(1, errorStr, strlen(errorStr));
+       write(1, str, str_size);
+       write(1, eol, strlen(eol));
 }
 
 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
-    static const char * filename = "../../samples/parse_file/gpslog.txt";
-    nmeaINFO info;
-    nmeaPARSER parser;
-    FILE *file;
-    char buff[2048];
-    int size, it = 0;
-    nmeaPOS dpos;
-
-    file = fopen(filename, "rb");
-
-    if(!file) {
-        printf("Could not open file %s\n", filename);
-        return -1;
-    }
-
-    nmea_property()->trace_func = &trace;
-    nmea_property()->error_func = &error;
-
-    nmea_zero_INFO(&info);
-    nmea_parser_init(&parser);
-
-    /*
-    while(1)
-    {
-    */
-
-    while(!feof(file))
-    {
-        size = (int)fread(&buff[0], 1, 100, file);
-
-        nmea_parse(&parser, &buff[0], size, &info);
-
-        nmea_info2pos(&info, &dpos);
-
-        printf(
-            "%03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d\n",
-            it++, dpos.lat, dpos.lon, info.sig, info.fix
-            );
-    }
-
-    fseek(file, 0, SEEK_SET);
-
-    /*
-    }
-    */
-
-    nmea_parser_destroy(&parser);
-    fclose(file);
-
-    return 0;
+       char fn[2048];
+       const char * filename = &fn[0];
+       const char * deffile;
+       const char * dn;
+       nmeaINFO info;
+       nmeaPARSER parser;
+       FILE *file;
+       char buff[2048];
+       int size, it = 0;
+       nmeaPOS dpos;
+
+       if (argc <= 1) {
+               dn = dirname(argv[0]);
+               deffile="/../../samples/parse_file/gpslog.txt";
+       } else {
+               dn="";
+               deffile = argv[1];
+       }
+       snprintf(&fn[0], sizeof(fn),"%s%s", dn, deffile);
+       printf("Using file %s\n", filename);
+
+       file = fopen(filename, "rb");
+
+       if (!file) {
+               printf("Could not open file %s\n", filename);
+               return -1;
+       }
+
+       nmea_context_set_trace_func(&trace);
+       nmea_context_set_error_func(&error);
+
+       nmea_zero_INFO(&info);
+       nmea_parser_init(&parser);
+
+       while (!feof(file)) {
+               size = (int) fread(&buff[0], 1, 100, file);
+
+               nmea_parse(&parser, &buff[0], size, &info);
+               nmea_info2pos(&info, &dpos);
+
+               printf("*** %03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d\n", it++, dpos.lat, dpos.lon, info.sig, info.fix);
+       }
+
+       fseek(file, 0, SEEK_SET);
+
+       /*
+        }
+        */
+
+       nmea_parser_destroy(&parser);
+       fclose(file);
+
+       return 0;
 }
index 99edf00..b583de5 100644 (file)
 #include <stdarg.h>
 #include <stdio.h>
 
-nmeaPROPERTY * nmea_property(void) {
-    static nmeaPROPERTY prop = {
-        0, 0, NMEA_DEF_PARSEBUFF
-        };
+/**
+ * The structure with nmealib context.
+ */
+typedef struct _nmeaPROPERTY {
+       nmeaTraceFunc trace_func; /**< the tracing function, defaults to NULL (disabled) */
+       nmeaErrorFunc error_func; /**< the error function, defaults to NULL (disabled) */
+       int parse_buff_size; /**< the size to use for temporary buffers, minimum is NMEA_MIN_PARSEBUFF */
+} nmeaPROPERTY;
+
+/** the nmealib context */
+static nmeaPROPERTY property = { .trace_func = NULL, .error_func = NULL, .parse_buff_size = NMEA_DEF_PARSEBUFF };
 
-    return &prop;
+/**
+ * Set the trace function
+ *
+ * @param func the trace function
+ */
+void nmea_context_set_trace_func(nmeaTraceFunc func) {
+       property.trace_func = func;
+}
+
+/**
+ * Set the error function
+ *
+ * @param func the error function
+ */
+void nmea_context_set_error_func(nmeaErrorFunc func) {
+       property.error_func = func;
 }
 
-void nmea_trace(const char *str, ...)
-{
-    int size;
-    va_list arg_list;
-    char buff[NMEA_DEF_PARSEBUFF];
-    nmeaTraceFunc func = nmea_property()->trace_func;
-
-    if(func)
-    {
-        va_start(arg_list, str);
-        size = vsnprintf(&buff[0], NMEA_DEF_PARSEBUFF - 1, str, arg_list);
-        va_end(arg_list);
-
-        if(size > 0)
-            (*func)(&buff[0], size);
-    }
+/**
+ * Set the buffer size for temporary buffers.
+ * If the size is less than NMEA_MIN_PARSEBUFF, then the size that is
+ * configured will be NMEA_MIN_PARSEBUFF.
+ *
+ * @param buff_size the buffer size for temporary buffers
+ */
+void nmea_context_set_buffer_size(int buff_size) {
+       if (buff_size < NMEA_MIN_PARSEBUFF)
+               property.parse_buff_size = NMEA_MIN_PARSEBUFF;
+       else
+               property.parse_buff_size = buff_size;
 }
 
-void nmea_trace_buff(const char *buff, int buff_size)
-{
-    nmeaTraceFunc func = nmea_property()->trace_func;
-    if(func && buff_size)
-        (*func)(buff, buff_size);
+/**
+ * @return the buffer size for temporary buffers
+ */
+int nmea_context_get_buffer_size(void) {
+       return property.parse_buff_size;
 }
 
-void nmea_error(const char *str, ...)
-{
-    int size;
-    va_list arg_list;
-    char buff[NMEA_DEF_PARSEBUFF];
-    nmeaErrorFunc func = nmea_property()->error_func;
-
-    if(func)
-    {
-        va_start(arg_list, str);
-        size = vsnprintf(&buff[0], NMEA_DEF_PARSEBUFF - 1, str, arg_list);
-        va_end(arg_list);
-
-        if(size > 0)
-            (*func)(&buff[0], size);
-    }
+/**
+ * Trace a formatted string
+ *
+ * @param str a formatted string
+ */
+void nmea_trace(const char *str, ...) {
+       nmeaTraceFunc func = property.trace_func;
+
+       if (func) {
+               int size;
+               va_list arg_list;
+               char buff[property.parse_buff_size];
+
+               va_start(arg_list, str);
+               size = vsnprintf(&buff[0], property.parse_buff_size - 1, str, arg_list);
+               va_end(arg_list);
+
+               if (size > 0)
+                       (*func)(&buff[0], size);
+       }
+}
+
+/**
+ * Trace a buffer
+ *
+ * @param buff a pointer to the buffer
+ * @param buff_size the size of the buffer
+ */
+void nmea_trace_buff(const char *buff, int buff_size) {
+       nmeaTraceFunc func = property.trace_func;
+       if (func && buff_size)
+               (*func)(buff, buff_size);
+}
+
+/**
+ * Log a formatted error string
+ *
+ * @param str a formatted error string
+ */
+void nmea_error(const char *str, ...) {
+       nmeaErrorFunc func = property.error_func;
+
+       if (func) {
+               int size;
+               va_list arg_list;
+               char buff[property.parse_buff_size];
+
+               va_start(arg_list, str);
+               size = vsnprintf(&buff[0], property.parse_buff_size - 1, str, arg_list);
+               va_end(arg_list);
+
+               if (size > 0)
+                       (*func)(&buff[0], size);
+       }
 }
diff --git a/lib/pud/nmealib/src/conversions.c b/lib/pud/nmealib/src/conversions.c
new file mode 100644 (file)
index 0000000..94cc962
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * This file is part of nmealib.
+ *
+ * Copyright (c) 2008 Timur Sinitsyn
+ * Copyright (c) 2011 Ferry Huberts
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nmea/conversions.h>
+
+#include <nmea/gmath.h>
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+/**
+ * Determine the number of GSV sentences needed for a number of sats
+ *
+ * @param sats the number of sats
+ * @return the number of GSV sentences needed
+ */
+int nmea_gsv_npack(int sats) {
+       int pack_count = sats / NMEA_SATINPACK;
+
+       if ((sats % NMEA_SATINPACK) > 0)
+               pack_count++;
+
+       if (!pack_count)
+               pack_count++;
+
+       return pack_count;
+}
+
+/**
+ * Fill nmeaINFO structure from GGA packet structure
+ *
+ * @param pack a pointer to the packet structure
+ * @param info a pointer to the nmeaINFO structure
+ */
+void nmea_GPGGA2info(const nmeaGPGGA *pack, nmeaINFO *info) {
+       assert(pack);
+       assert(info);
+
+       info->present |= pack->present;
+       nmea_INFO_set_present(&info->present, SMASK);
+       info->smask |= GPGGA;
+       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
+               info->utc.hour = pack->utc.hour;
+               info->utc.min = pack->utc.min;
+               info->utc.sec = pack->utc.sec;
+               info->utc.hsec = pack->utc.hsec;
+       }
+       if (nmea_INFO_is_present(pack->present, LAT)) {
+               info->lat = ((pack->ns == 'N') ? pack->lat : -pack->lat);
+       }
+       if (nmea_INFO_is_present(pack->present, LON)) {
+               info->lon = ((pack->ew == 'E') ? pack->lon : -pack->lon);
+       }
+       if (nmea_INFO_is_present(pack->present, SIG)) {
+               info->sig = pack->sig;
+       }
+       if (nmea_INFO_is_present(pack->present, SATINUSECOUNT)) {
+               info->satinfo.inuse = pack->satinuse;
+       }
+       if (nmea_INFO_is_present(pack->present, HDOP)) {
+               info->HDOP = pack->HDOP;
+       }
+       if (nmea_INFO_is_present(pack->present, ELV)) {
+               info->elv = pack->elv;
+       }
+       /* ignore diff and diff_units */
+       /* ignore dgps_age and dgps_sid */
+}
+
+/**
+ * Convert an nmeaINFO structure into an nmeaGPGGA structure
+ *
+ * @param info a pointer to the nmeaINFO structure
+ * @param pack a pointer to the nmeaGPGGA structure
+ */
+void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack) {
+       assert(pack);
+       assert(info);
+
+       nmea_zero_GPGGA(pack);
+
+       pack->present = info->present;
+       nmea_INFO_unset_present(&pack->present, SMASK);
+       if (nmea_INFO_is_present(info->present, UTCTIME)) {
+               pack->utc.hour = info->utc.hour;
+               pack->utc.min = info->utc.min;
+               pack->utc.sec = info->utc.sec;
+               pack->utc.hsec = info->utc.hsec;
+       }
+       if (nmea_INFO_is_present(info->present, LAT)) {
+               pack->lat = fabs(info->lat);
+               pack->ns = ((info->lat > 0) ? 'N' : 'S');
+       }
+       if (nmea_INFO_is_present(info->present, LON)) {
+               pack->lon = fabs(info->lon);
+               pack->ew = ((info->lon > 0) ? 'E' : 'W');
+       }
+       if (nmea_INFO_is_present(info->present, SIG)) {
+               pack->sig = info->sig;
+       }
+       if (nmea_INFO_is_present(info->present, SATINUSECOUNT)) {
+               pack->satinuse = info->satinfo.inuse;
+       }
+       if (nmea_INFO_is_present(info->present, HDOP)) {
+               pack->HDOP = info->HDOP;
+       }
+       if (nmea_INFO_is_present(info->present, ELV)) {
+               pack->elv = info->elv;
+               pack->elv_units = 'M';
+       }
+       /* defaults for (ignored) diff and diff_units */
+       pack->diff = 0;
+       pack->diff_units = 'M';
+       /* defaults for (ignored) dgps_age and dgps_sid */
+       pack->dgps_age = 0;
+       pack->dgps_sid = 0;
+}
+
+/**
+ * Fill nmeaINFO structure from GSA packet structure
+ *
+ * @param pack a pointer to the packet structure
+ * @param info a pointer to the nmeaINFO structure
+ */
+void nmea_GPGSA2info(const nmeaGPGSA *pack, nmeaINFO *info) {
+       int i = 0;
+
+       assert(pack);
+       assert(info);
+
+       info->present |= pack->present;
+       nmea_INFO_set_present(&info->present, SMASK);
+       info->smask |= GPGSA;
+       if (nmea_INFO_is_present(pack->present, FIX)) {
+               /* fix_mode is ignored */
+               info->fix = pack->fix_type;
+       }
+       if (nmea_INFO_is_present(pack->present, SATINUSE)) {
+               assert(sizeof(info->satinfo.in_use) == sizeof(info->satinfo.in_use));
+               info->satinfo.inuse = 0;
+               for (i = 0; i < NMEA_MAXSAT; i++) {
+                       info->satinfo.in_use[i] = pack->sat_prn[i];
+                       if (pack->sat_prn[i]) {
+                               info->satinfo.inuse++;
+                       }
+               }
+               nmea_INFO_set_present(&info->present, SATINUSECOUNT);
+       }
+       if (nmea_INFO_is_present(pack->present, PDOP)) {
+               info->PDOP = pack->PDOP;
+       }
+       if (nmea_INFO_is_present(pack->present, HDOP)) {
+               info->HDOP = pack->HDOP;
+       }
+       if (nmea_INFO_is_present(pack->present, VDOP)) {
+               info->VDOP = pack->VDOP;
+       }
+}
+
+/**
+ * Convert an nmeaINFO structure into an nmeaGPGSA structure
+ *
+ * @param info a pointer to the nmeaINFO structure
+ * @param pack a pointer to the nmeaGPGSA structure
+ */
+void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack) {
+       assert(pack);
+       assert(info);
+
+       nmea_zero_GPGSA(pack);
+
+       pack->present = info->present;
+       nmea_INFO_unset_present(&pack->present, SMASK);
+       if (nmea_INFO_is_present(info->present, FIX)) {
+               pack->fix_mode = 'A';
+               pack->fix_type = info->fix;
+       }
+       if (nmea_INFO_is_present(info->present, SATINUSE)) {
+               memcpy(pack->sat_prn, info->satinfo.in_use, sizeof(pack->sat_prn));
+       }
+       if (nmea_INFO_is_present(info->present, PDOP)) {
+               pack->PDOP = info->PDOP;
+       }
+       if (nmea_INFO_is_present(info->present, HDOP)) {
+               pack->HDOP = info->HDOP;
+       }
+       if (nmea_INFO_is_present(info->present, VDOP)) {
+               pack->VDOP = info->VDOP;
+       }
+}
+
+/**
+ * Fill nmeaINFO structure from GSV packet structure
+ *
+ * @param pack a pointer to the packet structure
+ * @param info a pointer to the nmeaINFO structure
+ */
+void nmea_GPGSV2info(const nmeaGPGSV *pack, nmeaINFO *info) {
+       int pack_index;
+
+       assert(pack);
+       assert(info);
+
+       pack_index = pack->pack_index;
+       if (pack_index < 1)
+               pack_index = 1;
+
+       if (pack_index > pack->pack_count)
+               pack_index = pack->pack_count;
+
+       if ((pack_index * NMEA_SATINPACK) > NMEA_MAXSAT)
+               pack_index = NMEA_NSATPACKS;
+
+       info->present |= pack->present;
+       nmea_INFO_set_present(&info->present, SMASK);
+       info->smask |= GPGSV;
+       if (nmea_INFO_is_present(pack->present, SATINVIEW)) {
+               int sat_index;
+
+               /* index of 1st sat in pack */
+               int sat_offset = (pack_index - 1) * NMEA_SATINPACK;
+               /* the number of sats in this sentence */
+               int sat_count = ((sat_offset + NMEA_SATINPACK) > pack->sat_count) ? (pack->sat_count - sat_offset) : NMEA_SATINPACK;
+
+               for (sat_index = 0; sat_index < sat_count; sat_index++) {
+                       info->satinfo.sat[sat_offset + sat_index].id = pack->sat_data[sat_index].id;
+                       info->satinfo.sat[sat_offset + sat_index].elv = pack->sat_data[sat_index].elv;
+                       info->satinfo.sat[sat_offset + sat_index].azimuth = pack->sat_data[sat_index].azimuth;
+                       info->satinfo.sat[sat_offset + sat_index].sig = pack->sat_data[sat_index].sig;
+               }
+
+               info->satinfo.inview = pack->sat_count;
+       }
+}
+
+/**
+ * Convert an nmeaINFO structure into an nmeaGPGSV structure
+ *
+ * @param info a pointer to the nmeaINFO structure
+ * @param pack a pointer to the nmeaGPGSV structure
+ * @param pack_idx pack index (zero based)
+ */
+void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx) {
+       int sit;
+       int pit;
+
+       assert(pack);
+       assert(info);
+
+       nmea_zero_GPGSV(pack);
+
+       pack->present = info->present;
+       nmea_INFO_unset_present(&pack->present, SMASK);
+       if (nmea_INFO_is_present(info->present, SATINVIEW)) {
+               pack->sat_count = (info->satinfo.inview < NMEA_MAXSAT) ? info->satinfo.inview : NMEA_MAXSAT;
+               pack->pack_count = nmea_gsv_npack(pack->sat_count);
+
+               if (pack_idx >= pack->pack_count)
+                       pack->pack_index = (pack_idx % pack->pack_count) + 1;
+               else
+                       pack->pack_index = pack_idx + 1;
+
+               for (pit = 0, sit = ((pack->pack_index - 1) * NMEA_SATINPACK); pit < NMEA_SATINPACK; pit++, sit++)
+                       pack->sat_data[pit] = info->satinfo.sat[sit];
+       }
+}
+
+/**
+ * Fill nmeaINFO structure from RMC packet structure
+ *
+ * @param pack a pointer to the packet structure
+ * @param info a pointer to the nmeaINFO structure
+ */
+void nmea_GPRMC2info(const nmeaGPRMC *pack, nmeaINFO *info) {
+       assert(pack);
+       assert(info);
+
+       info->present |= pack->present;
+       nmea_INFO_set_present(&info->present, SMASK);
+       info->smask |= GPRMC;
+       if (nmea_INFO_is_present(pack->present, UTCDATE)) {
+               info->utc.year = pack->utc.year;
+               info->utc.mon = pack->utc.mon;
+               info->utc.day = pack->utc.day;
+       }
+       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
+               info->utc.hour = pack->utc.hour;
+               info->utc.min = pack->utc.min;
+               info->utc.sec = pack->utc.sec;
+               info->utc.hsec = pack->utc.hsec;
+       }
+       nmea_INFO_set_present(&info->present, SIG);
+       nmea_INFO_set_present(&info->present, FIX);
+       if (pack->status == 'A') {
+               if (info->sig == NMEA_SIG_BAD) {
+                       info->sig = NMEA_SIG_MID;
+               }
+               if (info->fix == NMEA_FIX_BAD) {
+                       info->fix = NMEA_FIX_2D;
+               }
+       } else {
+               info->sig = NMEA_SIG_BAD;
+               info->fix = NMEA_FIX_BAD;
+       }
+       if (nmea_INFO_is_present(pack->present, LAT)) {
+               info->lat = ((pack->ns == 'N') ? pack->lat : -pack->lat);
+       }
+       if (nmea_INFO_is_present(pack->present, LON)) {
+               info->lon = ((pack->ew == 'E') ? pack->lon : -pack->lon);
+       }
+       if (nmea_INFO_is_present(pack->present, SPEED)) {
+               info->speed = pack->speed * NMEA_TUD_KNOTS;
+       }
+       if (nmea_INFO_is_present(pack->present, TRACK)) {
+               info->track = pack->track;
+       }
+       if (nmea_INFO_is_present(pack->present, MAGVAR)) {
+               info->magvar = ((pack->magvar_ew == 'E') ? pack->magvar : -pack->magvar);
+       }
+       /* mode is ignored */
+}
+
+/**
+ * Convert an nmeaINFO structure into an nmeaGPRMC structure
+ *
+ * @param info a pointer to the nmeaINFO structure
+ * @param pack a pointer to the nmeaGPRMC structure
+ */
+void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack) {
+       assert(pack);
+       assert(info);
+
+       nmea_zero_GPRMC(pack);
+
+       pack->present = info->present;
+       nmea_INFO_unset_present(&pack->present, SMASK);
+       if (nmea_INFO_is_present(info->present, UTCDATE)) {
+               pack->utc.year = info->utc.year;
+               pack->utc.mon = info->utc.mon;
+               pack->utc.day = info->utc.day;
+       }
+       if (nmea_INFO_is_present(info->present, UTCTIME)) {
+               pack->utc.hour = info->utc.hour;
+               pack->utc.min = info->utc.min;
+               pack->utc.sec = info->utc.sec;
+               pack->utc.hsec = info->utc.hsec;
+       }
+       if (nmea_INFO_is_present(info->present, SIG)) {
+               pack->status = ((info->sig != NMEA_SIG_BAD) ? 'A' : 'V');
+       } else {
+               pack->status = 'V';
+       }
+       if (nmea_INFO_is_present(info->present, LAT)) {
+               pack->lat = fabs(info->lat);
+               pack->ns = ((info->lat > 0) ? 'N' : 'S');
+       }
+       if (nmea_INFO_is_present(info->present, LON)) {
+               pack->lon = fabs(info->lon);
+               pack->ew = ((info->lon > 0) ? 'E' : 'W');
+       }
+       if (nmea_INFO_is_present(info->present, SPEED)) {
+               pack->speed = info->speed / NMEA_TUD_KNOTS;
+       }
+       if (nmea_INFO_is_present(info->present, TRACK)) {
+               pack->track = info->track;
+       }
+       if (nmea_INFO_is_present(info->present, MAGVAR)) {
+               pack->magvar = fabs(info->magvar);
+               pack->magvar_ew = ((info->magvar > 0) ? 'E' : 'W');
+       }
+       if (nmea_INFO_is_present(info->present, SIG)) {
+               pack->mode = ((info->sig != NMEA_SIG_BAD) ? 'A' : 'N');
+       } else {
+               pack->mode = 'N';
+       }
+}
+
+/**
+ * Fill nmeaINFO structure from VTG packet structure
+ *
+ * @param pack a pointer to the packet structure
+ * @param info a pointer to the nmeaINFO structure
+ */
+void nmea_GPVTG2info(const nmeaGPVTG *pack, nmeaINFO *info) {
+       assert(pack);
+       assert(info);
+
+       info->present |= pack->present;
+       nmea_INFO_set_present(&info->present, SMASK);
+       info->smask |= GPVTG;
+       if (nmea_INFO_is_present(pack->present, SPEED)) {
+               info->speed = pack->spk;
+       }
+       if (nmea_INFO_is_present(pack->present, TRACK)) {
+               info->track = pack->track;
+       }
+       if (nmea_INFO_is_present(pack->present, MTRACK)) {
+               info->mtrack = pack->mtrack;
+       }
+}
+
+/**
+ * Convert an nmeaINFO structure into an nmeaGPVTG structure
+ *
+ * @param info a pointer to the nmeaINFO structure
+ * @param pack a pointer to the nmeaGPRMC structure
+ */
+void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack) {
+       assert(pack);
+       assert(info);
+
+       nmea_zero_GPVTG(pack); /* also sets up units */
+
+       pack->present = info->present;
+       nmea_INFO_unset_present(&pack->present, SMASK);
+       if (nmea_INFO_is_present(info->present, TRACK)) {
+               pack->track = info->track;
+       }
+       if (nmea_INFO_is_present(info->present, MTRACK)) {
+               pack->mtrack = info->mtrack;
+       }
+       if (nmea_INFO_is_present(info->present, SPEED)) {
+               pack->spn = info->speed / NMEA_TUD_KNOTS;
+               pack->spk = info->speed;
+       }
+}
index b8441c2..f1789b6 100644 (file)
 
 #include <nmea/generate.h>
 
-#include <math.h>
-
 #include <nmea/tok.h>
-#include <nmea/units.h>
-
-int nmea_gen_GPGGA(char *buff, int buff_sz, nmeaGPGGA *pack)
-{
-    return nmea_printf(buff, buff_sz,
-        "$GPGGA,%02d%02d%02d.%02d,%09.4f,%C,%010.4f,%C,%1d,%02d,%03.1f,%03.1f,%C,%03.1f,%C,%03.1f,%04d",
-        pack->utc.hour, pack->utc.min, pack->utc.sec, pack->utc.hsec,
-        pack->lat, pack->ns, pack->lon, pack->ew,
-        pack->sig, pack->satinuse, pack->HDOP, pack->elv, pack->elv_units,
-        pack->diff, pack->diff_units, pack->dgps_age, pack->dgps_sid);
-}
+#include <nmea/conversions.h>
 
-int nmea_gen_GPGSA(char *buff, int buff_sz, nmeaGPGSA *pack)
-{
-    return nmea_printf(buff, buff_sz,
-        "$GPGSA,%C,%1d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%02d,%03.1f,%03.1f,%03.1f",
-        pack->fix_mode, pack->fix_type,
-        pack->sat_prn[0], pack->sat_prn[1], pack->sat_prn[2], pack->sat_prn[3], pack->sat_prn[4], pack->sat_prn[5],
-        pack->sat_prn[6], pack->sat_prn[7], pack->sat_prn[8], pack->sat_prn[9], pack->sat_prn[10], pack->sat_prn[11],
-        pack->PDOP, pack->HDOP, pack->VDOP);
-}
-
-int nmea_gen_GPGSV(char *buff, int buff_sz, nmeaGPGSV *pack)
-{
-    return nmea_printf(buff, buff_sz,
-        "$GPGSV,%1d,%1d,%02d,"
-        "%02d,%02d,%03d,%02d,"
-        "%02d,%02d,%03d,%02d,"
-        "%02d,%02d,%03d,%02d,"
-        "%02d,%02d,%03d,%02d",
-        pack->pack_count, pack->pack_index + 1, pack->sat_count,
-        pack->sat_data[0].id, pack->sat_data[0].elv, pack->sat_data[0].azimuth, pack->sat_data[0].sig,
-        pack->sat_data[1].id, pack->sat_data[1].elv, pack->sat_data[1].azimuth, pack->sat_data[1].sig,
-        pack->sat_data[2].id, pack->sat_data[2].elv, pack->sat_data[2].azimuth, pack->sat_data[2].sig,
-        pack->sat_data[3].id, pack->sat_data[3].elv, pack->sat_data[3].azimuth, pack->sat_data[3].sig);
-}
-
-int nmea_gen_GPRMC(char *buff, int buff_sz, nmeaGPRMC *pack)
-{
-    return nmea_printf(buff, buff_sz,
-        "$GPRMC,%02d%02d%02d.%02d,%C,%09.4f,%C,%010.4f,%C,%03.1f,%03.1f,%02d%02d%02d,%03.1f,%C,%C",
-        pack->utc.hour, pack->utc.min, pack->utc.sec, pack->utc.hsec,
-        pack->status, pack->lat, pack->ns, pack->lon, pack->ew,
-        pack->speed, pack->direction,
-        pack->utc.day, pack->utc.mon + 1, pack->utc.year - 100,
-        pack->declination, pack->declin_ew, pack->mode);
-}
-
-int nmea_gen_GPVTG(char *buff, int buff_sz, nmeaGPVTG *pack)
-{
-    return nmea_printf(buff, buff_sz,
-        "$GPVTG,%.1f,%C,%.1f,%C,%.1f,%C,%.1f,%C",
-        pack->dir, pack->dir_t,
-        pack->dec, pack->dec_m,
-        pack->spn, pack->spn_n,
-        pack->spk, pack->spk_k);
-}
+#include <stdio.h>
+#include <stdbool.h>
 
-void nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack)
-{
-    nmea_zero_GPGGA(pack);
-
-    pack->utc = info->utc;
-    pack->lat = fabs(info->lat);
-    pack->ns = ((info->lat > 0)?'N':'S');
-    pack->lon = fabs(info->lon);
-    pack->ew = ((info->lon > 0)?'E':'W');
-    pack->sig = info->sig;
-    pack->satinuse = info->satinfo.inuse;
-    pack->HDOP = info->HDOP;
-    pack->elv = info->elv;
-}
-
-void nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack)
-{
-    int it;
-
-    nmea_zero_GPGSA(pack);
-
-    pack->fix_type = info->fix;
-    pack->PDOP = info->PDOP;
-    pack->HDOP = info->HDOP;
-    pack->VDOP = info->VDOP;
-
-    for(it = 0; it < NMEA_MAXSAT; ++it)
-    {
-        pack->sat_prn[it] =
-            ((info->satinfo.sat[it].in_use)?info->satinfo.sat[it].id:0);
-    }
+/**
+ * Generate a GPGGA sentence from an nmeaGPGGA structure
+ *
+ * @param s a pointer to the buffer to generate the string in
+ * @param len the size of the buffer
+ * @param pack the structure
+ * @return the length of the generated sentence
+ */
+int nmea_gen_GPGGA(char *s, const int len, const nmeaGPGGA *pack) {
+       char sTime[16];
+       char sLat[16];
+       char sNs[2];
+       char sLon[16];
+       char sEw[2];
+       char sSig[4];
+       char sSatInUse[4];
+       char sHdop[16];
+       char sElv[16];
+       char sElvUnit[2];
+
+       sTime[0] = 0;
+       sLat[0] = 0;
+       sNs[0] = sNs[1] = 0;
+       sLon[0] = 0;
+       sEw[0] = sEw[1] = 0;
+       sSig[0] = 0;
+       sSatInUse[0] = 0;
+       sHdop[0] = 0;
+       sElv[0] = 0;
+       sElvUnit[0] = sElvUnit[1] = 0;
+
+       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
+               snprintf(&sTime[0], sizeof(sTime), "%02d%02d%02d.%02d", pack->utc.hour, pack->utc.min, pack->utc.sec,
+                               pack->utc.hsec);
+       }
+       if (nmea_INFO_is_present(pack->present, LAT)) {
+               snprintf(&sLat[0], sizeof(sLat), "%09.4f", pack->lat);
+               sNs[0] = pack->ns;
+       }
+       if (nmea_INFO_is_present(pack->present, LON)) {
+               snprintf(&sLon[0], sizeof(sLon), "%010.4f", pack->lon);
+               sEw[0] = pack->ew;
+       }
+       if (nmea_INFO_is_present(pack->present, SIG)) {
+               snprintf(&sSig[0], sizeof(sSig), "%1d", pack->sig);
+       }
+       if (nmea_INFO_is_present(pack->present, SATINUSECOUNT)) {
+               snprintf(&sSatInUse[0], sizeof(sSatInUse), "%02d", pack->satinuse);
+       }
+       if (nmea_INFO_is_present(pack->present, HDOP)) {
+               snprintf(&sHdop[0], sizeof(sHdop), "%03.1f", pack->HDOP);
+       }
+       if (nmea_INFO_is_present(pack->present, ELV)) {
+               snprintf(&sElv[0], sizeof(sElv), "%03.1f", pack->elv);
+               sElvUnit[0] = pack->elv_units;
+       }
+
+       return nmea_printf(s, len, "$GPGGA,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,,,,", &sTime[0], &sLat[0], &sNs[0],
+                       &sLon[0], &sEw[0], &sSig[0], &sSatInUse[0], &sHdop[0], &sElv[0], &sElvUnit[0]);
 }
 
-int nmea_gsv_npack(int sat_count)
-{
-    int pack_count = lrint(ceil(((double)sat_count) / (double)NMEA_SATINPACK));
-
-    if(0 == pack_count)
-        pack_count = 1;
-
-    return pack_count;
+/**
+ * Generate a GPGSA sentence from an nmeaGPGSA structure
+ *
+ * @param s a pointer to the buffer to generate the string in
+ * @param len the size of the buffer
+ * @param pack the structure
+ * @return the length of the generated sentence
+ */
+int nmea_gen_GPGSA(char *s, const int len, const nmeaGPGSA *pack) {
+       int i;
+       char sFixMode[2];
+       char sFixType[2];
+       char sSatPrn[64];
+       char sPdop[16];
+       char sHdop[16];
+       char sVdop[16];
+
+       char * psSatPrn = &sSatPrn[0];
+       int ssSatPrn = sizeof(sSatPrn);
+
+       bool satinuse = nmea_INFO_is_present(pack->present, SATINUSE);
+
+       sFixMode[0] = sFixMode[1] = 0;
+       sFixType[0] = sFixType[1] = 0;
+       sSatPrn[0] = 0;
+       sPdop[0] = 0;
+       sHdop[0] = 0;
+       sVdop[0] = 0;
+
+       if (nmea_INFO_is_present(pack->present, FIX)) {
+               sFixMode[0] = pack->fix_mode;
+               snprintf(&sFixType[0], sizeof(sFixType), "%1d", pack->fix_type);
+       }
+
+       for (i = 0; i < NMEA_MAXSAT; i++) {
+               if (satinuse && pack->sat_prn[i]) {
+                       int cnt = snprintf(psSatPrn, ssSatPrn, "%d", pack->sat_prn[i]);
+                       if (cnt >= ssSatPrn) {
+                               ssSatPrn = 0;
+                               psSatPrn = &sSatPrn[sizeof(sSatPrn) - 1];
+                               *psSatPrn = '\0';
+                               break;
+                       } else {
+                               ssSatPrn -= cnt;
+                               psSatPrn += cnt;
+                       }
+               }
+               if (i < (NMEA_MAXSAT - 1)) {
+                       *psSatPrn = ',';
+                       psSatPrn++;
+                       ssSatPrn--;
+                       *psSatPrn = '\0';
+               }
+       }
+
+       if (nmea_INFO_is_present(pack->present, PDOP)) {
+               snprintf(&sPdop[0], sizeof(sPdop), "%03.1f", pack->PDOP);
+       }
+       if (nmea_INFO_is_present(pack->present, HDOP)) {
+               snprintf(&sHdop[0], sizeof(sHdop), "%03.1f", pack->HDOP);
+       }
+       if (nmea_INFO_is_present(pack->present, VDOP)) {
+               snprintf(&sVdop[0], sizeof(sVdop), "%03.1f", pack->VDOP);
+       }
+
+       return nmea_printf(s, len, "$GPGSA,%s,%s,%s,%s,%s,%s", &sFixMode[0], &sFixType[0], &sSatPrn[0], &sPdop[0],
+                       &sHdop[0], &sVdop[0]);
 }
 
-void nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx)
-{
-    int sit, pit;
-
-    nmea_zero_GPGSV(pack);
-
-    pack->sat_count = (info->satinfo.inview <= NMEA_MAXSAT)?info->satinfo.inview:NMEA_MAXSAT;
-    pack->pack_count = nmea_gsv_npack(pack->sat_count);
-
-    if(pack->pack_count == 0)
-        pack->pack_count = 1;
-
-    if(pack_idx >= pack->pack_count)
-        pack->pack_index = pack_idx % pack->pack_count;
-    else
-        pack->pack_index = pack_idx;
-
-    for(pit = 0, sit = pack->pack_index * NMEA_SATINPACK; pit < NMEA_SATINPACK; ++pit, ++sit)
-        pack->sat_data[pit] = info->satinfo.sat[sit];
+/**
+ * Generate a GPGSV sentence from an nmeaGPGSV structure
+ *
+ * @param s a pointer to the buffer to generate the string in
+ * @param len the size of the buffer
+ * @param pack the structure
+ * @return the length of the generated sentence
+ */
+int nmea_gen_GPGSV(char *s, const int len, const nmeaGPGSV *pack) {
+       char sCount[2];
+       char sIndex[2];
+       char sSatCount[4];
+       char sSatInfo[64];
+       char * psSatInfo = &sSatInfo[0];
+       int ssSatInfo = sizeof(sSatInfo);
+       bool satinview = nmea_INFO_is_present(pack->present, SATINVIEW);
+       int i;
+
+       sCount[0] = 0;
+       sIndex[0] = 0;
+       sSatCount[0] = 0;
+       sSatInfo[0] = 0;
+
+       if (satinview) {
+               snprintf(&sCount[0], sizeof(sCount), "%1d", pack->pack_count);
+               snprintf(&sIndex[0], sizeof(sIndex), "%1d", pack->pack_index);
+               snprintf(&sSatCount[0], sizeof(sSatCount), "%02d", pack->sat_count);
+       }
+       for (i = 0; i < NMEA_SATINPACK; i++) {
+               int cnt = 0;
+               if (satinview && pack->sat_data[i].id) {
+                       cnt = snprintf(psSatInfo, ssSatInfo, "%02d,%02d,%03d,%02d", pack->sat_data[i].id, pack->sat_data[i].elv,
+                                       pack->sat_data[i].azimuth, pack->sat_data[i].sig);
+               } else {
+                       cnt = snprintf(psSatInfo, ssSatInfo, ",,,");
+               }
+               if (cnt >= ssSatInfo) {
+                       ssSatInfo = 0;
+                       psSatInfo = &sSatInfo[sizeof(sSatInfo) - 1];
+                       *psSatInfo = '\0';
+                       break;
+               } else {
+                       ssSatInfo -= cnt;
+                       psSatInfo += cnt;
+               }
+               if (i < (NMEA_SATINPACK - 1)) {
+                       *psSatInfo = ',';
+                       psSatInfo++;
+                       ssSatInfo--;
+                       *psSatInfo = '\0';
+               }
+       }
+
+       return nmea_printf(s, len, "$GPGSV,%s,%s,%s,%s", &sCount[0], &sIndex[0], &sSatCount[0], &sSatInfo[0]);
 }
 
-void nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack)
-{
-    nmea_zero_GPRMC(pack);
-
-    pack->utc = info->utc;
-    pack->status = ((info->sig > 0)?'A':'V');
-    pack->lat = fabs(info->lat);
-    pack->ns = ((info->lat > 0)?'N':'S');
-    pack->lon = fabs(info->lon);
-    pack->ew = ((info->lon > 0)?'E':'W');
-    pack->speed = info->speed / NMEA_TUD_KNOTS;
-    pack->direction = info->direction;
-    pack->declination = info->declination;
-    pack->declin_ew = 'E';
-    pack->mode = ((info->sig > 0)?'A':'N');
+/**
+ * Generate a GPRMC sentence from an nmeaGPRMC structure
+ *
+ * @param s a pointer to the buffer to generate the string in
+ * @param len the size of the buffer
+ * @param pack the structure
+ * @return the length of the generated sentence
+ */
+int nmea_gen_GPRMC(char *s, const int len, const nmeaGPRMC *pack) {
+       char sTime[16];
+       char sDate[16];
+       char sLat[16];
+       char sNs[2];
+       char sLon[16];
+       char sEw[2];
+       char sSpeed[16];
+       char sTrack[16];
+       char sMagvar[16];
+       char sMagvar_ew[2];
+
+       sTime[0] = 0;
+       sDate[0] = 0;
+       sLat[0] = 0;
+       sNs[0] = sNs[1] = 0;
+       sLon[0] = 0;
+       sEw[0] = sEw[1] = 0;
+       sSpeed[0] = 0;
+       sTrack[0] = 0;
+       sMagvar[0] = 0;
+       sMagvar_ew[0] = sMagvar_ew[1] = 0;
+
+       if (nmea_INFO_is_present(pack->present, UTCDATE)) {
+               snprintf(&sDate[0], sizeof(sDate), "%02d%02d%02d", pack->utc.day, pack->utc.mon + 1, pack->utc.year - 100);
+       }
+       if (nmea_INFO_is_present(pack->present, UTCTIME)) {
+               snprintf(&sTime[0], sizeof(sTime), "%02d%02d%02d.%02d", pack->utc.hour, pack->utc.min, pack->utc.sec,
+                               pack->utc.hsec);
+       }
+       if (nmea_INFO_is_present(pack->present, LAT)) {
+               snprintf(&sLat[0], sizeof(sLat), "%09.4f", pack->lat);
+               sNs[0] = pack->ns;
+       }
+       if (nmea_INFO_is_present(pack->present, LON)) {
+               snprintf(&sLon[0], sizeof(sLon), "%010.4f", pack->lon);
+               sEw[0] = pack->ew;
+       }
+       if (nmea_INFO_is_present(pack->present, SPEED)) {
+               snprintf(&sSpeed[0], sizeof(sSpeed), "%03.1f", pack->speed);
+       }
+       if (nmea_INFO_is_present(pack->present, TRACK)) {
+               snprintf(&sTrack[0], sizeof(sTrack), "%03.1f", pack->track);
+       }
+       if (nmea_INFO_is_present(pack->present, MAGVAR)) {
+               snprintf(&sMagvar[0], sizeof(sMagvar), "%03.1f", pack->magvar);
+               sMagvar_ew[0] = pack->magvar_ew;
+       }
+
+       return nmea_printf(s, len, "$GPRMC,%s,%C,%s,%s,%s,%s,%s,%s,%s,%s,%s,%C", &sTime[0], pack->status, &sLat[0], &sNs[0],
+                       &sLon[0], &sEw[0], &sSpeed[0], &sTrack[0], &sDate[0], &sMagvar[0], &sMagvar_ew[0], pack->mode);
 }
 
-void nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack)
-{
-    nmea_zero_GPVTG(pack);
-
-    pack->dir = info->direction;
-    pack->dec = info->declination;
-    pack->spn = info->speed / NMEA_TUD_KNOTS;
-    pack->spk = info->speed;
+/**
+ * Generate a GPVTG sentence from an nmeaGPVTG structure
+ *
+ * @param s a pointer to the buffer to generate the string in
+ * @param len the size of the buffer
+ * @param pack the structure
+ * @return the length of the generated sentence
+ */
+int nmea_gen_GPVTG(char *s, const int len, const nmeaGPVTG *pack) {
+       char sTrackT[16];
+       char sTrackM[16];
+       char sSpeedN[16];
+       char sSpeedK[16];
+       char sUnitT[2];
+       char sUnitM[2];
+       char sUnitN[2];
+       char sUnitK[2];
+
+       sTrackT[0] = 0;
+       sTrackM[0] = 0;
+       sSpeedN[0] = 0;
+       sSpeedK[0] = 0;
+       sUnitT[0] = sUnitT[1] = 0;
+       sUnitM[0] = sUnitM[1] = 0;
+       sUnitN[0] = sUnitN[1] = 0;
+       sUnitK[0] = sUnitK[1] = 0;
+
+       if (nmea_INFO_is_present(pack->present, TRACK)) {
+               snprintf(&sTrackT[0], sizeof(sTrackT), "%03.1f", pack->track);
+               sUnitT[0] = 'T';
+       }
+       if (nmea_INFO_is_present(pack->present, MTRACK)) {
+               snprintf(&sTrackM[0], sizeof(sTrackM), "%03.1f", pack->mtrack);
+               sUnitM[0] = 'M';
+       }
+       if (nmea_INFO_is_present(pack->present, SPEED)) {
+               snprintf(&sSpeedN[0], sizeof(sSpeedN), "%03.1f", pack->spn);
+               sUnitN[0] = 'N';
+               snprintf(&sSpeedK[0], sizeof(sSpeedK), "%03.1f", pack->spk);
+               sUnitK[0] = 'K';
+       }
+
+       return nmea_printf(s, len, "$GPVTG,%s,%s,%s,%s,%s,%s,%s,%s", &sTrackT[0], &sUnitT[0], &sTrackM[0],
+                       &sUnitM[0], &sSpeedN[0], &sUnitN[0], &sSpeedK[0], &sUnitK[0]);
 }
 
-int nmea_generate(
-    char *buff, int buff_sz,
-    const nmeaINFO *info,
-    int generate_mask
-    )
-{
-    int gen_count = 0, gsv_it, gsv_count;
-    int pack_mask = generate_mask;
-
-    nmeaGPGGA gga;
-    nmeaGPGSA gsa;
-    nmeaGPGSV gsv;
-    nmeaGPRMC rmc;
-    nmeaGPVTG vtg;
-
-    if(!buff)
-        return 0;
-
-    while(pack_mask)
-    {
-        if(pack_mask & GPGGA)
-        {
-            nmea_info2GPGGA(info, &gga);
-            gen_count += nmea_gen_GPGGA(buff + gen_count, buff_sz - gen_count, &gga);
-            pack_mask &= ~GPGGA;
-        }
-        else if(pack_mask & GPGSA)
-        {
-            nmea_info2GPGSA(info, &gsa);
-            gen_count += nmea_gen_GPGSA(buff + gen_count, buff_sz - gen_count, &gsa);
-            pack_mask &= ~GPGSA;
-        }
-        else if(pack_mask & GPGSV)
-        {
-            gsv_count = nmea_gsv_npack(info->satinfo.inview);
-            for(gsv_it = 0; gsv_it < gsv_count && buff_sz - gen_count > 0; ++gsv_it)
-            {
-                nmea_info2GPGSV(info, &gsv, gsv_it);
-                gen_count += nmea_gen_GPGSV(buff + gen_count, buff_sz - gen_count, &gsv);
-            }
-            pack_mask &= ~GPGSV;
-        }
-        else if(pack_mask & GPRMC)
-        {
-            nmea_info2GPRMC(info, &rmc);
-            gen_count += nmea_gen_GPRMC(buff + gen_count, buff_sz - gen_count, &rmc);
-            pack_mask &= ~GPRMC;
-        }
-        else if(pack_mask & GPVTG)
-        {
-            nmea_info2GPVTG(info, &vtg);
-            gen_count += nmea_gen_GPVTG(buff + gen_count, buff_sz - gen_count, &vtg);
-            pack_mask &= ~GPVTG;
-        }
-        else
-            break;
-
-        if(buff_sz - gen_count <= 0)
-            break;
-    }
-
-    return gen_count;
+/**
+ * Generate a number of sentences from an nmeaINFO structure.
+ *
+ * @param s a pointer to the buffer in which to generate the sentences
+ * @param len the size of the buffer
+ * @param info the structure
+ * @param generate_mask the mask of which sentences to generate
+ * @return the total length of the generated sentences
+ */
+int nmea_generate(char *s, const int len, const nmeaINFO *info, const int generate_mask) {
+       int gen_count = 0;
+       int pack_mask = generate_mask;
+
+       if (!s || !len || !info || !generate_mask)
+               return 0;
+
+       while (pack_mask) {
+               if (pack_mask & GPGGA) {
+                       nmeaGPGGA gga;
+
+                       nmea_info2GPGGA(info, &gga);
+                       gen_count += nmea_gen_GPGGA(s + gen_count, len - gen_count, &gga);
+                       pack_mask &= ~GPGGA;
+               } else if (pack_mask & GPGSA) {
+                       nmeaGPGSA gsa;
+
+                       nmea_info2GPGSA(info, &gsa);
+                       gen_count += nmea_gen_GPGSA(s + gen_count, len - gen_count, &gsa);
+                       pack_mask &= ~GPGSA;
+               } else if (pack_mask & GPGSV) {
+                       nmeaGPGSV gsv;
+                       int gsv_it;
+                       int gsv_count = nmea_gsv_npack(info->satinfo.inview);
+
+                       for (gsv_it = 0; gsv_it < gsv_count && len - gen_count > 0; gsv_it++) {
+                               nmea_info2GPGSV(info, &gsv, gsv_it);
+                               gen_count += nmea_gen_GPGSV(s + gen_count, len - gen_count, &gsv);
+                       }
+                       pack_mask &= ~GPGSV;
+               } else if (pack_mask & GPRMC) {
+                       nmeaGPRMC rmc;
+
+                       nmea_info2GPRMC(info, &rmc);
+                       gen_count += nmea_gen_GPRMC(s + gen_count, len - gen_count, &rmc);
+                       pack_mask &= ~GPRMC;
+               } else if (pack_mask & GPVTG) {
+                       nmeaGPVTG vtg;
+
+                       nmea_info2GPVTG(info, &vtg);
+                       gen_count += nmea_gen_GPVTG(s + gen_count, len - gen_count, &vtg);
+                       pack_mask &= ~GPVTG;
+               } else {
+                       /* no more known sentences to process */
+                       break;
+               }
+
+               if (len - gen_count <= 0)
+                       break;
+       }
+
+       return gen_count;
 }
index 47d5999..bc590e5 100644 (file)
 
 #include <nmea/generator.h>
 
-#include <stdlib.h>
-#include <string.h>
-
 #include <nmea/context.h>
-#include <nmea/generate.h>
 #include <nmea/gmath.h>
+#include <nmea/generate.h>
+
+#include <stdlib.h>
+#include <string.h>
 #include <math.h>
 
-static double nmea_random(double min, double max)
-{
-    static double rand_max = RAND_MAX;
-    double rand_val = rand();
-    double bounds = max - min;
-    return min + (rand_val * bounds) / rand_max;
+/**
+ * Generate a random number in the range [min, max]
+ *
+ * @param min the minimum
+ * @param max the maximum
+ * @return a random number
+ */
+static double nmea_random(const double min, const double max) {
+       static double rand_max = RAND_MAX;
+       double rand_val = rand();
+       double bounds = max - min;
+       return min + (rand_val * bounds) / rand_max;
 }
 
-/*
- * low level
+/**
+ * Initialise the generator
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * (present and smask are preserved, other fields are reset before generation starts)
+ * @return 1 (true) on success, 0 (false) otherwise
  */
-
-int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info)
-{
-    int RetVal = 1; int smask = info->smask;
-    nmeaGENERATOR *igen = gen;
-
-    nmea_zero_INFO(info);
-    info->smask = smask;
-
-    info->lat = NMEA_DEF_LAT;
-    info->lon = NMEA_DEF_LON;
-
-    while(RetVal && igen)
-    {
-        if(igen->init_call)
-            RetVal = (*igen->init_call)(igen, info);
-        igen = igen->next;
-    }
-
-    return RetVal;
+int nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info) {
+       int retval = 1;
+       int present = info->present;
+       int smask = info->smask;
+       nmeaGENERATOR *igen = gen;
+
+       nmea_zero_INFO(info);
+       info->present = present;
+       info->smask = smask;
+       nmea_INFO_set_present(&info->present, SMASK);
+
+       info->lat = NMEA_DEF_LAT;
+       info->lon = NMEA_DEF_LON;
+       nmea_INFO_set_present(&info->present, LAT);
+       nmea_INFO_set_present(&info->present, LON);
+
+       while (retval && igen) {
+               if (igen->init_call)
+                       retval = (*igen->init_call)(igen, info);
+               igen = igen->next;
+       }
+
+       return retval;
 }
 
-int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info)
-{
-    int RetVal = 1;
+/**
+ * Loop the generator.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+int nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info) {
+       int retVal = 1;
 
-    if(gen->loop_call)
-        RetVal = (*gen->loop_call)(gen, info);
+       if (gen->loop_call)
+               retVal = (*gen->loop_call)(gen, info);
 
-    if(RetVal && gen->next)
-        RetVal = nmea_gen_loop(gen->next, info);
+       if (retVal && gen->next)
+               retVal = nmea_gen_loop(gen->next, info);
 
-    return RetVal;
+       return retVal;
 }
 
-int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info)
-{
-    int RetVal = 1;
+/**
+ * Reset the generator.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+int nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info) {
+       int RetVal = 1;
 
-    if(gen->reset_call)
-        RetVal = (*gen->reset_call)(gen, info);
+       if (gen->reset_call)
+               RetVal = (*gen->reset_call)(gen, info);
 
-    return RetVal;
+       return RetVal;
 }
 
-void nmea_gen_destroy(nmeaGENERATOR *gen)
-{
-    if(gen->next)
-    {
-        nmea_gen_destroy(gen->next);
-        gen->next = 0;
-    }
+/**
+ * Destroy the generator.
+ *
+ * @param gen a pointer to the generator
+ */
+void nmea_gen_destroy(nmeaGENERATOR *gen) {
+       if (gen->next) {
+               nmea_gen_destroy(gen->next);
+               gen->next = 0;
+       }
 
-    if(gen->destroy_call)
-        (*gen->destroy_call)(gen);
+       if (gen->destroy_call)
+               (*gen->destroy_call)(gen);
 
-    free(gen);
+       free(gen);
 }
 
-void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen)
-{
-    if(to->next)
-        nmea_gen_add(to->next, gen);
-    else
-        to->next = gen;
+/**
+ * Add a generator to the existing ones.
+ *
+ * @param to the generators to add to
+ * @param gen the generator to add
+ */
+void nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen) {
+       nmeaGENERATOR * next = to;
+       while (next->next)
+               next = to->next;
+
+       next->next = gen;
 }
 
-int nmea_generate_from(
-    char *buff, int buff_sz,
-    nmeaINFO *info,
-    nmeaGENERATOR *gen,
-    int generate_mask
-    )
-{
-    int retval;
+/**
+ * Run a new generation loop on the generator
+ *
+ * @param s a pointer to the string buffer in which to generate
+ * @param len the size of the buffer
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @param gen a pointer to the generator
+ * @param generate_mask the smask of sentences to generate
+ * @return the total length of the generated sentences
+ */
+int nmea_generate_from(char *s, int len, nmeaINFO *info, nmeaGENERATOR *gen, int generate_mask) {
+       int retval;
 
-    if(0 != (retval = nmea_gen_loop(gen, info)))
-        retval = nmea_generate(buff, buff_sz, info, generate_mask);
+       if ((retval = nmea_gen_loop(gen, info)))
+               retval = nmea_generate(s, len, info, generate_mask);
 
-    return retval;
+       return retval;
 }
 
 /*
  * NOISE generator
  */
 
-static int nmea_igen_noise_init(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info __attribute__ ((unused)))
-{
-    return 1;
-}
-
-static int nmea_igen_noise_loop(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{
-    int it;
-    int in_use;
-
-    info->sig = lrint(nmea_random(1, 3));
-    info->PDOP = nmea_random(0, 9);
-    info->HDOP = nmea_random(0, 9);
-    info->VDOP = nmea_random(0, 9);
-    info->fix = lrint(nmea_random(2, 3));
-    info->lat = nmea_random(0, 100);
-    info->lon = nmea_random(0, 100);
-    info->speed = nmea_random(0, 100);
-    info->direction = nmea_random(0, 360);
-    info->declination = nmea_random(0, 360);
-    info->elv = lrint(nmea_random(-100, 100));
-
-    info->satinfo.inuse = 0;
-    info->satinfo.inview = 0;
-
-    for(it = 0; it < 12; ++it)
-    {
-        info->satinfo.sat[it].id = it;
-        info->satinfo.sat[it].in_use = in_use = lrint(nmea_random(0, 3));
-        info->satinfo.sat[it].elv = lrint(nmea_random(0, 90));
-        info->satinfo.sat[it].azimuth = lrint(nmea_random(0, 359));
-        info->satinfo.sat[it].sig = (int)(in_use?nmea_random(40, 99):nmea_random(0, 40));
-
-        if(in_use)
-            info->satinfo.inuse++;
-        if(info->satinfo.sat[it].sig > 0)
-            info->satinfo.inview++;
-    }
-
-    return 1;
-}
-
-static int nmea_igen_noise_reset(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info __attribute__ ((unused)))
-{
-    return 1;
+/**
+ * NOISE Generator loop function.
+ * Does not touch smask and utc in info.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_noise_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       int it;
+       int in_use;
+
+       info->sig = lrint(nmea_random(1, 3));
+       info->fix = lrint(nmea_random(2, 3));
+       info->PDOP = nmea_random(0, 9);
+       info->HDOP = nmea_random(0, 9);
+       info->VDOP = nmea_random(0, 9);
+       info->lat = nmea_random(0, 100);
+       info->lon = nmea_random(0, 100);
+       info->elv = lrint(nmea_random(-100, 100));
+       info->speed = nmea_random(0, 100);
+       info->track = nmea_random(0, 360);
+       info->mtrack = nmea_random(0, 360);
+       info->magvar = nmea_random(0, 360);
+
+       nmea_INFO_set_present(&info->present, SIG);
+       nmea_INFO_set_present(&info->present, FIX);
+       nmea_INFO_set_present(&info->present, PDOP);
+       nmea_INFO_set_present(&info->present, HDOP);
+       nmea_INFO_set_present(&info->present, VDOP);
+       nmea_INFO_set_present(&info->present, LAT);
+       nmea_INFO_set_present(&info->present, LON);
+       nmea_INFO_set_present(&info->present, ELV);
+       nmea_INFO_set_present(&info->present, SPEED);
+       nmea_INFO_set_present(&info->present, TRACK);
+       nmea_INFO_set_present(&info->present, MTRACK);
+       nmea_INFO_set_present(&info->present, MAGVAR);
+
+       info->satinfo.inuse = 0;
+       info->satinfo.inview = 0;
+
+       for (it = 0; it < NMEA_MAXSAT; it++) {
+               in_use = lrint(nmea_random(0, 3));
+               info->satinfo.in_use[it] = in_use ? it : 0;
+               info->satinfo.sat[it].id = it;
+               info->satinfo.sat[it].elv = lrint(nmea_random(0, 90));
+               info->satinfo.sat[it].azimuth = lrint(nmea_random(0, 359));
+               info->satinfo.sat[it].sig = (int) (in_use ? nmea_random(40, 99) : nmea_random(0, 40));
+
+               if (in_use)
+                       info->satinfo.inuse++;
+               if (info->satinfo.sat[it].sig > 0)
+                       info->satinfo.inview++;
+       }
+
+       nmea_INFO_set_present(&info->present, SATINUSECOUNT);
+       nmea_INFO_set_present(&info->present, SATINUSE);
+       nmea_INFO_set_present(&info->present, SATINVIEW);
+
+       return 1;
 }
 
 /*
  * STATIC generator
  */
 
-static int nmea_igen_static_loop(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{
-    nmea_time_now(&info->utc);
-    return 1;
-};
-
-static int nmea_igen_static_reset(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{
-    info->satinfo.inuse = 4;
-    info->satinfo.inview = 4;
-
-    info->satinfo.sat[0].id = 1;
-    info->satinfo.sat[0].in_use = 1;
-    info->satinfo.sat[0].elv = 50;
-    info->satinfo.sat[0].azimuth = 0;
-    info->satinfo.sat[0].sig = 99;
-
-    info->satinfo.sat[1].id = 2;
-    info->satinfo.sat[1].in_use = 1;
-    info->satinfo.sat[1].elv = 50;
-    info->satinfo.sat[1].azimuth = 90;
-    info->satinfo.sat[1].sig = 99;
-
-    info->satinfo.sat[2].id = 3;
-    info->satinfo.sat[2].in_use = 1;
-    info->satinfo.sat[2].elv = 50;
-    info->satinfo.sat[2].azimuth = 180;
-    info->satinfo.sat[2].sig = 99;
-
-    info->satinfo.sat[3].id = 4;
-    info->satinfo.sat[3].in_use = 1;
-    info->satinfo.sat[3].elv = 50;
-    info->satinfo.sat[3].azimuth = 270;
-    info->satinfo.sat[3].sig = 99;
-
-    return 1;
+/**
+ * STATIC Generator loop function.
+ * Only touches utc in info.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_static_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       nmea_time_now(&info->utc, &info->present);
+       return 1;
 }
 
-static int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info)
-{
-    info->sig = 3;
-    info->fix = 3;
-
-    nmea_igen_static_reset(gen, info);
-
-    return 1;
+/**
+ * STATIC Generator reset function.
+ * Resets only the satinfo to 4 sats in use and in view.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_static_reset(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       info->satinfo.inuse = 4;
+       info->satinfo.inview = 4;
+
+       info->satinfo.in_use[0] = 1;
+       info->satinfo.sat[0].id = 1;
+       info->satinfo.sat[0].elv = 50;
+       info->satinfo.sat[0].azimuth = 0;
+       info->satinfo.sat[0].sig = 99;
+
+       info->satinfo.in_use[1] = 2;
+       info->satinfo.sat[1].id = 2;
+       info->satinfo.sat[1].elv = 50;
+       info->satinfo.sat[1].azimuth = 90;
+       info->satinfo.sat[1].sig = 99;
+
+       info->satinfo.in_use[2] = 3;
+       info->satinfo.sat[2].id = 3;
+       info->satinfo.sat[2].elv = 50;
+       info->satinfo.sat[2].azimuth = 180;
+       info->satinfo.sat[2].sig = 99;
+
+       info->satinfo.in_use[3] = 4;
+       info->satinfo.sat[3].id = 4;
+       info->satinfo.sat[3].elv = 50;
+       info->satinfo.sat[3].azimuth = 270;
+       info->satinfo.sat[3].sig = 99;
+
+       nmea_INFO_set_present(&info->present, SATINUSECOUNT);
+       nmea_INFO_set_present(&info->present, SATINUSE);
+       nmea_INFO_set_present(&info->present, SATINVIEW);
+
+       return 1;
 }
 
-/*
- * SAT_ROTATE generator
+/**
+ * STATIC Generator initialiser function.
+ * Only touches sig, fix and satinfo in info.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
  */
+static int nmea_igen_static_init(nmeaGENERATOR *gen, nmeaINFO *info) {
+       info->sig = 3;
+       info->fix = 3;
 
-static int nmea_igen_rotate_loop(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{
-    int it;
-    int count = info->satinfo.inview;
-    double deg = 360 / (count?count:1);
-    double srt = (count?(info->satinfo.sat[0].azimuth):0) + 5;
-
-    nmea_time_now(&info->utc);
-
-    for(it = 0; it < count; ++it)
-    {
-        info->satinfo.sat[it].azimuth =
-            (int)((srt >= 360)?srt - 360:srt);
-        srt += deg;
-    }
-
-    return 1;
-};
-
-static int nmea_igen_rotate_reset(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{
-    int it;
-    double deg = 360 / 8;
-    double srt = 0;
-
-    info->satinfo.inuse = 8;
-    info->satinfo.inview = 8;
-
-    for(it = 0; it < info->satinfo.inview; ++it)
-    {
-        info->satinfo.sat[it].id = it + 1;
-        info->satinfo.sat[it].in_use = 1;
-        info->satinfo.sat[it].elv = 5;
-        info->satinfo.sat[it].azimuth = (int)srt;
-        info->satinfo.sat[it].sig = 80;
-        srt += deg;
-    }
-
-    return 1;
-}
-
-static int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info)
-{
-    info->sig = 3;
-    info->fix = 3;
+       nmea_INFO_set_present(&info->present, SIG);
+       nmea_INFO_set_present(&info->present, FIX);
 
-    nmea_igen_rotate_reset(gen, info);
+       nmea_igen_static_reset(gen, info);
 
-    return 1;
+       return 1;
 }
 
 /*
- * POS_RANDMOVE generator
+ * SAT_ROTATE generator
  */
 
-static int nmea_igen_pos_rmove_init(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{    
-    info->sig = 3;
-    info->fix = 3;
-    info->direction = info->declination = 0;
-    info->speed = 20;
-    return 1;
-}
+/**
+ * SAT_ROTATE Generator loop function.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_rotate_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       int it;
+       int count = info->satinfo.inview;
+       double deg = 360 / (count ? count : 1);
+       double srt = (count ? (info->satinfo.sat[0].azimuth) : 0) + 5;
 
-static int nmea_igen_pos_rmove_loop(nmeaGENERATOR *gen __attribute__ ((unused)),
-               nmeaINFO *info)
-{
-    nmeaPOS crd;
+       nmea_time_now(&info->utc, &info->present);
 
-    info->direction += nmea_random(-10, 10);
-    info->speed += nmea_random(-2, 3);
+       for (it = 0; it < count; it++) {
+               info->satinfo.sat[it].azimuth = (int) ((srt >= 360) ? srt - 360 : srt);
+               srt += deg;
+       }
 
-    if(info->direction < 0)
-        info->direction = 359 + info->direction;
-    if(info->direction > 359)
-        info->direction -= 359;
+       nmea_INFO_set_present(&info->present, SATINVIEW);
 
-    if(info->speed > 40)
-        info->speed = 40;
-    if(info->speed < 1)
-        info->speed = 1;
+       return 1;
+}
 
-    nmea_info2pos(info, &crd);
-    nmea_move_horz(&crd, &crd, info->direction, info->speed / 3600);
-    nmea_pos2info(&crd, info);
+/**
+ * SAT_ROTATE Generator reset function.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_rotate_reset(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       int it;
+       double deg = 360 / 8;
+       double srt = 0;
+
+       info->satinfo.inuse = 8;
+       info->satinfo.inview = 8;
+
+       for (it = 0; it < info->satinfo.inview; it++) {
+               info->satinfo.in_use[it] = it + 1;
+               info->satinfo.sat[it].id = it + 1;
+               info->satinfo.sat[it].elv = 5;
+               info->satinfo.sat[it].azimuth = (int) srt;
+               info->satinfo.sat[it].sig = 80;
+               srt += deg;
+       }
+
+       nmea_INFO_set_present(&info->present, SATINUSECOUNT);
+       nmea_INFO_set_present(&info->present, SATINUSE);
+       nmea_INFO_set_present(&info->present, SATINVIEW);
+
+       return 1;
+}
 
-    info->declination = info->direction;
+/**
+ * SAT_ROTATE Generator initialiser function.
+ * Only touches sig, fix and satinfo in info.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_rotate_init(nmeaGENERATOR *gen, nmeaINFO *info) {
+       info->sig = 3;
+       info->fix = 3;
 
-    return 1;
-};
+       nmea_INFO_set_present(&info->present, SIG);
+       nmea_INFO_set_present(&info->present, FIX);
 
-static int nmea_igen_pos_rmove_destroy(nmeaGENERATOR *gen __attribute__ ((unused)))
-{
-    return 1;
-};
+       nmea_igen_rotate_reset(gen, info);
+
+       return 1;
+}
 
 /*
- * generator create
+ * POS_RANDMOVE generator
  */
 
-static nmeaGENERATOR * __nmea_create_generator(int type, nmeaINFO *info)
-{
-    nmeaGENERATOR *gen = 0;
-
-    switch(type)
-    {
-    case NMEA_GEN_NOISE:
-        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
-            nmea_error("Insufficient memory!");
-        else
-        {
-            memset(gen, 0, sizeof(nmeaGENERATOR));
-            gen->init_call = &nmea_igen_noise_init;
-            gen->loop_call = &nmea_igen_noise_loop;
-            gen->reset_call = &nmea_igen_noise_reset;
-        }
-        break;
-    case NMEA_GEN_STATIC:
-    case NMEA_GEN_SAT_STATIC:
-        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
-            nmea_error("Insufficient memory!");
-        else
-        {
-            memset(gen, 0, sizeof(nmeaGENERATOR));
-            gen->init_call = &nmea_igen_static_init;
-            gen->loop_call = &nmea_igen_static_loop;
-            gen->reset_call = &nmea_igen_static_reset;
-        }
-        break;
-    case NMEA_GEN_SAT_ROTATE:
-        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
-            nmea_error("Insufficient memory!");
-        else
-        {
-            memset(gen, 0, sizeof(nmeaGENERATOR));
-            gen->init_call = &nmea_igen_rotate_init;
-            gen->loop_call = &nmea_igen_rotate_loop;
-            gen->reset_call = &nmea_igen_rotate_reset;
-        }
-        break;
-    case NMEA_GEN_POS_RANDMOVE:
-        if(0 == (gen = malloc(sizeof(nmeaGENERATOR))))
-            nmea_error("Insufficient memory!");
-        else
-        {
-            memset(gen, 0, sizeof(nmeaGENERATOR));
-            gen->init_call = &nmea_igen_pos_rmove_init;
-            gen->loop_call = &nmea_igen_pos_rmove_loop;
-            gen->destroy_call = &nmea_igen_pos_rmove_destroy;
-        }
-        break;
-    default:
-    /* case NMEA_GEN_ROTATE: */
-        gen = __nmea_create_generator(NMEA_GEN_SAT_ROTATE, info);
-        nmea_gen_add(gen, __nmea_create_generator(NMEA_GEN_POS_RANDMOVE, info));
-        break;
-    };
-
-    return gen;
+/**
+ * POS_RANDMOVE Generator initialiser function.
+ * Only touches sig, fix, track, mtrack, magvar and speed in info.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_pos_rmove_init(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       info->sig = 3;
+       info->fix = 3;
+       info->speed = 20;
+       info->track = 0;
+       info->mtrack = 0;
+       info->magvar = 0;
+
+       nmea_INFO_set_present(&info->present, SIG);
+       nmea_INFO_set_present(&info->present, FIX);
+       nmea_INFO_set_present(&info->present, SPEED);
+       nmea_INFO_set_present(&info->present, TRACK);
+       nmea_INFO_set_present(&info->present, MTRACK);
+       nmea_INFO_set_present(&info->present, MAGVAR);
+
+       return 1;
 }
 
-nmeaGENERATOR * nmea_create_generator(int type, nmeaINFO *info)
-{
-    nmeaGENERATOR *gen = __nmea_create_generator(type, info);
-
-    if(gen)
-        nmea_gen_init(gen, info);
+/**
+ * POS_RANDMOVE Generator loop function.
+ *
+ * @param gen a pointer to the generator
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return 1 (true) on success, 0 (false) otherwise
+ */
+static int nmea_igen_pos_rmove_loop(nmeaGENERATOR *gen __attribute__ ((unused)), nmeaINFO *info) {
+       nmeaPOS crd;
+
+       info->track += nmea_random(-10, 10);
+       info->mtrack += nmea_random(-10, 10);
+       info->speed += nmea_random(-2, 3);
+
+       if (info->track < 0) {
+               info->track = 359 + info->track;
+       }
+       if (info->track > 359) {
+               info->track -= 359;
+       }
+       if (info->mtrack < 0) {
+               info->mtrack = 359 + info->mtrack;
+       }
+       if (info->mtrack > 359) {
+               info->mtrack -= 359;
+       }
+
+       if (info->speed > 40)
+               info->speed = 40;
+       if (info->speed < 1)
+               info->speed = 1;
+
+       nmea_info2pos(info, &crd);
+       nmea_move_horz(&crd, &crd, info->track, info->speed / 3600);
+       nmea_pos2info(&crd, info);
+
+       info->magvar = info->track;
+
+       nmea_INFO_set_present(&info->present, LAT);
+       nmea_INFO_set_present(&info->present, LON);
+       nmea_INFO_set_present(&info->present, SPEED);
+       nmea_INFO_set_present(&info->present, TRACK);
+       nmea_INFO_set_present(&info->present, MTRACK);
+       nmea_INFO_set_present(&info->present, MAGVAR);
+
+       return 1;
+}
 
-    return gen;
+/**
+ * Create the generator.
+ *
+ * @param type the type of the generator to create (see nmeaGENTYPE)
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return the generator
+ */
+static nmeaGENERATOR * __nmea_create_generator(const int type, nmeaINFO *info) {
+       nmeaGENERATOR *gen = 0;
+
+       switch (type) {
+       case NMEA_GEN_NOISE:
+               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
+                       nmea_error("__nmea_create_generator: insufficient memory!");
+               else {
+                       memset(gen, 0, sizeof(nmeaGENERATOR));
+                       gen->loop_call = &nmea_igen_noise_loop;
+               }
+               break;
+       case NMEA_GEN_STATIC:
+       case NMEA_GEN_SAT_STATIC:
+               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
+                       nmea_error("__nmea_create_generator: insufficient memory!");
+               else {
+                       memset(gen, 0, sizeof(nmeaGENERATOR));
+                       gen->init_call = &nmea_igen_static_init;
+                       gen->loop_call = &nmea_igen_static_loop;
+                       gen->reset_call = &nmea_igen_static_reset;
+               }
+               break;
+       case NMEA_GEN_SAT_ROTATE:
+               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
+                       nmea_error("__nmea_create_generator: insufficient memory!");
+               else {
+                       memset(gen, 0, sizeof(nmeaGENERATOR));
+                       gen->init_call = &nmea_igen_rotate_init;
+                       gen->loop_call = &nmea_igen_rotate_loop;
+                       gen->reset_call = &nmea_igen_rotate_reset;
+               }
+               break;
+       case NMEA_GEN_POS_RANDMOVE:
+               if (!(gen = malloc(sizeof(nmeaGENERATOR))))
+                       nmea_error("__nmea_create_generator: insufficient memory!");
+               else {
+                       memset(gen, 0, sizeof(nmeaGENERATOR));
+                       gen->init_call = &nmea_igen_pos_rmove_init;
+                       gen->loop_call = &nmea_igen_pos_rmove_loop;
+               }
+               break;
+       default:
+               /* case NMEA_GEN_ROTATE: */
+               gen = __nmea_create_generator(NMEA_GEN_SAT_ROTATE, info);
+               nmea_gen_add(gen, __nmea_create_generator(NMEA_GEN_POS_RANDMOVE, info));
+               break;
+       };
+
+       return gen;
 }
 
-void nmea_destroy_generator(nmeaGENERATOR *gen)
-{
-    nmea_gen_destroy(gen);
+/**
+ * Create the generator and initialise it.
+ *
+ * @param type the type of the generator to create (see nmeaGENTYPE)
+ * @param info a pointer to an nmeaINFO structure to use during generation
+ * @return the generator
+ */
+nmeaGENERATOR * nmea_create_generator(const int type, nmeaINFO *info) {
+       nmeaGENERATOR *gen = __nmea_create_generator(type, info);
+
+       if (gen)
+               nmea_gen_init(gen, info);
+
+       return gen;
 }
index b38dd52..8bda75e 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*! \file gmath.h */
-
 #include <nmea/gmath.h>
 
 #include <math.h>
 #include <assert.h>
 
 /**
- * \brief Convert degree to radian
+ * Convert degrees to radians
+ *
+ * @param val degrees
+ * @return radians
  */
-double nmea_degree2radian(double val)
-{ return (val * NMEA_PI180); }
+double nmea_degree2radian(const double val) {
+       return (val * NMEA_PI180);
+}
 
 /**
- * \brief Convert radian to degree
+ * Convert radians to degrees
+ *
+ * @param val radians
+ * @return degrees
  */
-double nmea_radian2degree(double val)
-{ return (val / NMEA_PI180); }
+double nmea_radian2degree(const double val) {
+       return (val / NMEA_PI180);
+}
 
 /**
- * \brief Convert NDEG (NMEA degree) to fractional degree
+ * Convert NDEG (NMEA degrees) to decimal (fractional) degrees
+ *
+ * @param val NDEG (NMEA degrees)
+ * @return decimal (fractional) degrees
  */
-double nmea_ndeg2degree(double val)
-{
-    double deg;
-    double fra_part = modf(val / 100.0, &deg);
-    return (deg + ((fra_part * 100.0) / 60.0));
+double nmea_ndeg2degree(const double val) {
+       double deg;
+       double fra_part = modf(val / 100.0, &deg);
+       return (deg + ((fra_part * 100.0) / 60.0));
 }
 
 /**
- * \brief Convert fractional degree to NDEG (NMEA degree)
+ * Convert decimal (fractional) degrees to NDEG (NMEA degrees)
+ *
+ * @param val decimal (fractional) degrees
+ * @return NDEG (NMEA degrees)
  */
-double nmea_degree2ndeg(double val)
-{
-    double deg;
-    double fra_part = modf(val, &deg);
-    return ((deg * 100.0) + (fra_part * 60.0));
+double nmea_degree2ndeg(const double val) {
+       double deg;
+       double fra_part = modf(val, &deg);
+       return ((deg * 100.0) + (fra_part * 60.0));
 }
 
 /**
- * \brief Convert NDEG (NMEA degree) to radian
+ * Convert NDEG (NMEA degrees) to radians
+ *
+ * @param val NDEG (NMEA degrees)
+ * @return radians
  */
-double nmea_ndeg2radian(double val)
-{ return nmea_degree2radian(nmea_ndeg2degree(val)); }
+double nmea_ndeg2radian(const double val) {
+       return nmea_degree2radian(nmea_ndeg2degree(val));
+}
 
 /**
- * \brief Convert radian to NDEG (NMEA degree)
+ * Convert radians to NDEG (NMEA degrees)
+ *
+ * @param val radians
+ * @return NDEG (NMEA degrees)
  */
-double nmea_radian2ndeg(double val)
-{ return nmea_degree2ndeg(nmea_radian2degree(val)); }
+double nmea_radian2ndeg(const double val) {
+       return nmea_degree2ndeg(nmea_radian2degree(val));
+}
 
 /**
- * \brief Calculate PDOP (Position Dilution Of Precision) factor
+ * Calculate PDOP (Position Dilution Of Precision) factor from HDOP and VDOP
+ *
+ * @param hdop HDOP
+ * @param vdop VDOP
+ * @return PDOP
  */
-double nmea_calc_pdop(double hdop, double vdop)
-{
-    return sqrt(pow(hdop, 2) + pow(vdop, 2));
+double nmea_calc_pdop(const double hdop, const double vdop) {
+       return sqrt(pow(hdop, 2) + pow(vdop, 2));
 }
 
-double nmea_dop2meters(double dop)
-{ return (dop * NMEA_DOP_FACTOR); }
+/**
+ * Convert DOP to meters, using the NMEA_DOP_FACTOR factor
+ *
+ * @param dop the DOP
+ * @return the DOP in meters
+ */
+double nmea_dop2meters(const double dop) {
+       return (dop * NMEA_DOP_FACTOR);
+}
 
-double nmea_meters2dop(double meters)
-{ return (meters / NMEA_DOP_FACTOR); }
+/**
+ * Convert DOP in meters to plain DOP, using the NMEA_DOP_FACTOR factor
+ *
+ * @param meters the DOP in meters
+ * @return the plain DOP
+ */
+double nmea_meters2dop(const double meters) {
+       return (meters / NMEA_DOP_FACTOR);
+}
 
 /**
- * \brief Calculate distance between two points
- * \return Distance in meters
+ * Calculate distance between two points
+ *
+ * @param from_pos a pointer to the from position (in radians)
+ * @param to_pos a pointer to the to position (in radians)
+ * @return distance in meters
  */
-double nmea_distance(
-        const nmeaPOS *from_pos,    /**< From position in radians */
-        const nmeaPOS *to_pos       /**< To position in radians */
-        )
-{
-    double dist = ((double)NMEA_EARTHRADIUS_M) * acos(
-        sin(to_pos->lat) * sin(from_pos->lat) +
-        cos(to_pos->lat) * cos(from_pos->lat) * cos(to_pos->lon - from_pos->lon)
-        );
-    return dist;
+double nmea_distance(const nmeaPOS *from_pos, const nmeaPOS *to_pos) {
+       return ((double) NMEA_EARTHRADIUS_M)
+                       * acos(
+                                       sin(to_pos->lat) * sin(from_pos->lat)
+                                                       + cos(to_pos->lat) * cos(from_pos->lat) * cos(to_pos->lon - from_pos->lon));
 }
 
 /**
- * \brief Calculate distance between two points
+ * Calculate the distance between two points.
  * This function uses an algorithm for an oblate spheroid earth model.
  * The algorithm is described here: 
  * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
- * \return Distance in meters
+ *
+ * @param from_pos a pointer to the from position (in radians)
+ * @param to_pos a pointer to the to position (in radians)
+ * @param from_azimuth a pointer to the azimuth at "from" position (in radians) (output)
+ * @param to_azimuth a pointer to the azimuth at "to" position (in radians) (output)
+ * @return distance in meters
  */
-double nmea_distance_ellipsoid(
-        const nmeaPOS *from_pos,    /**< From position in radians */
-        const nmeaPOS *to_pos,      /**< To position in radians */
-        double *from_azimuth,       /**< (O) azimuth at "from" position in radians */
-        double *to_azimuth          /**< (O) azimuth at "to" position in radians */
-        )
-{
-    /* All variables */
-    double f, a, b, sqr_a, sqr_b;
-    double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
-    double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda, delta_lambda;
-    int remaining_steps; 
-    double sqr_u, A, B, delta_sigma, lambda_prev;
-
-    /* Check input */
-    assert(from_pos != 0);
-    assert(to_pos != 0);
-
-    if ((from_pos->lat == to_pos->lat) && (from_pos->lon == to_pos->lon))
-    { /* Identical points */
-        if ( from_azimuth != 0 )
-            *from_azimuth = 0;
-        if ( to_azimuth != 0 )
-            *to_azimuth = 0;
-        return 0;    
-    } /* Identical points */
-
-    /* Earth geometry */
-    f = NMEA_EARTH_FLATTENING;
-    a = NMEA_EARTH_SEMIMAJORAXIS_M;
-    b = (1 - f) * a;
-    sqr_a = a * a;
-    sqr_b = b * b;
-
-    /* Calculation */
-    L = to_pos->lon - from_pos->lon;
-    phi1 = from_pos->lat;
-    phi2 = to_pos->lat;
-    U1 = atan((1 - f) * tan(phi1));
-    U2 = atan((1 - f) * tan(phi2));
-    sin_U1 = sin(U1);
-    sin_U2 = sin(U2);
-    cos_U1 = cos(U1);
-    cos_U2 = cos(U2);
-
-    /* Initialize iteration */
-    sigma = 0;
-    sin_sigma = sin(sigma);
-    cos_sigma = cos(sigma);
-    cos_2_sigmam = 0;
-    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-    sqr_cos_alpha = 0;
-    lambda = L;
-    sin_lambda = sin(lambda);                            
-    cos_lambda = cos(lambda);  
-    lambda_prev = (double)2.0 * (double)NMEA_PI;
-    delta_lambda = lambda_prev - lambda;
-    if ( delta_lambda < 0 ) delta_lambda = -delta_lambda;
-    remaining_steps = 20; 
-
-    while ((delta_lambda > 1e-12) && (remaining_steps > 0)) 
-    { /* Iterate */
-        /* Variables */
-        double tmp1, tmp2, sin_alpha, cos_alpha, C;
-
-        /* Calculation */
-        tmp1 = cos_U2 * sin_lambda;
-        tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;  
-        sin_sigma = sqrt(tmp1 * tmp1 + tmp2 * tmp2);                
-        cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;   
-        sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;  
-        cos_alpha = cos(asin(sin_alpha));                 
-        sqr_cos_alpha = cos_alpha * cos_alpha;                     
-        cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
-        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam; 
-        C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
-        lambda_prev = lambda; 
-        sigma = asin(sin_sigma); 
-        lambda = L + 
-            (1 - C) * f * sin_alpha
-            * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));                                                
-        delta_lambda = lambda_prev - lambda; 
-        if ( delta_lambda < 0 ) delta_lambda = -delta_lambda; 
-        sin_lambda = sin(lambda);
-        cos_lambda = cos(lambda);
-        remaining_steps--; 
-    }  /* Iterate */
-
-    /* More calculation  */
-    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
-    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
-    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
-    delta_sigma = B * sin_sigma * ( 
-        cos_2_sigmam + B / 4 * ( 
-        cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) -
-        B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
-        ));
-
-    /* Calculate result */
-    if ( from_azimuth != 0 )
-    {
-        double tan_alpha_1 = cos_U2 * sin_lambda / (cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
-        *from_azimuth = atan(tan_alpha_1);
-    }
-    if ( to_azimuth != 0 )
-    {
-        double tan_alpha_2 = cos_U1 * sin_lambda / (-sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
-        *to_azimuth = atan(tan_alpha_2);
-    }
-
-    return b * A * (sigma - delta_sigma);
+double nmea_distance_ellipsoid(const nmeaPOS *from_pos, const nmeaPOS *to_pos, double *from_azimuth, double *to_azimuth) {
+       /* All variables */
+       double f, a, b, sqr_a, sqr_b;
+       double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
+       double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda,
+                       delta_lambda;
+       int remaining_steps;
+       double sqr_u, A, B, delta_sigma, lambda_prev;
+
+       /* Check input */
+       assert(from_pos != 0);
+       assert(to_pos != 0);
+
+       if ((from_pos->lat == to_pos->lat) && (from_pos->lon == to_pos->lon)) { /* Identical points */
+               if (from_azimuth != 0)
+                       *from_azimuth = 0;
+               if (to_azimuth != 0)
+                       *to_azimuth = 0;
+               return 0;
+       } /* Identical points */
+
+       /* Earth geometry */
+       f = NMEA_EARTH_FLATTENING;
+       a = NMEA_EARTH_SEMIMAJORAXIS_M;
+       b = (1 - f) * a;
+       sqr_a = a * a;
+       sqr_b = b * b;
+
+       /* Calculation */
+       L = to_pos->lon - from_pos->lon;
+       phi1 = from_pos->lat;
+       phi2 = to_pos->lat;
+       U1 = atan((1 - f) * tan(phi1));
+       U2 = atan((1 - f) * tan(phi2));
+       sin_U1 = sin(U1);
+       sin_U2 = sin(U2);
+       cos_U1 = cos(U1);
+       cos_U2 = cos(U2);
+
+       /* Initialize iteration */
+       sigma = 0;
+       sin_sigma = sin(sigma);
+       cos_sigma = cos(sigma);
+       cos_2_sigmam = 0;
+       sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+       sqr_cos_alpha = 0;
+       lambda = L;
+       sin_lambda = sin(lambda);
+       cos_lambda = cos(lambda);
+       lambda_prev = (double) 2.0 * (double) NMEA_PI;
+       delta_lambda = lambda_prev - lambda;
+       if (delta_lambda < 0)
+               delta_lambda = -delta_lambda;
+       remaining_steps = 20;
+
+       while ((delta_lambda > 1e-12) && (remaining_steps > 0)) { /* Iterate */
+               /* Variables */
+               double tmp1, tmp2, sin_alpha, cos_alpha, C;
+
+               /* Calculation */
+               tmp1 = cos_U2 * sin_lambda;
+               tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;
+               sin_sigma = sqrt(tmp1 * tmp1 + tmp2 * tmp2);
+               cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;
+               sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;
+               cos_alpha = cos(asin(sin_alpha));
+               sqr_cos_alpha = cos_alpha * cos_alpha;
+               cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
+               sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+               C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+               lambda_prev = lambda;
+               sigma = asin(sin_sigma);
+               lambda = L
+                               + (1 - C) * f * sin_alpha
+                                               * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));
+               delta_lambda = lambda_prev - lambda;
+               if (delta_lambda < 0)
+                       delta_lambda = -delta_lambda;
+               sin_lambda = sin(lambda);
+               cos_lambda = cos(lambda);
+               remaining_steps--;
+       } /* Iterate */
+
+       /* More calculation  */
+       sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b;
+       A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+       B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+       delta_sigma = B * sin_sigma
+                       * (cos_2_sigmam
+                                       + B / 4
+                                                       * (cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)
+                                                                       - B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma)
+                                                                                       * (-3 + 4 * sqr_cos_2_sigmam)));
+
+       /* Calculate result */
+       if (from_azimuth != 0) {
+               double tan_alpha_1 = cos_U2 * sin_lambda / (cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
+               *from_azimuth = atan(tan_alpha_1);
+       }
+       if (to_azimuth != 0) {
+               double tan_alpha_2 = cos_U1 * sin_lambda / (-sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
+               *to_azimuth = atan(tan_alpha_2);
+       }
+
+       return b * A * (sigma - delta_sigma);
 }
 
 /**
- * \brief Horizontal move of point position
+ * Perform a horizontal move.
+ *
+ * @param start_pos a pointer to the start position (in radians)
+ * @param end_pos a pointer to the end position (in radians) (output)
+ * @param azimuth azimuth (in degrees, [0, 359])
+ * @param distance the distance (in km)
+ * @return 1 (true) on success, 0 (false) on failure
  */
-int nmea_move_horz(
-    const nmeaPOS *start_pos,   /**< Start position in radians */
-    nmeaPOS *end_pos,           /**< Result position in radians */
-    double azimuth,             /**< Azimuth (degree) [0, 359] */
-    double distance             /**< Distance (km) */
-    )
-{
-    nmeaPOS p1 = *start_pos;
-    int RetVal = 1;
-
-    distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
-    azimuth = nmea_degree2radian(azimuth);
-
-    end_pos->lat = asin(
-        sin(p1.lat) * cos(distance) + cos(p1.lat) * sin(distance) * cos(azimuth));
-    end_pos->lon = p1.lon + atan2(
-        sin(azimuth) * sin(distance) * cos(p1.lat), cos(distance) - sin(p1.lat) * sin(end_pos->lat));
-
-    if(isnan(end_pos->lat) || isnan(end_pos->lon))
-    {
-        end_pos->lat = 0; end_pos->lon = 0;
-        RetVal = 0;
-    }
-
-    return RetVal;
+int nmea_move_horz(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance) {
+       nmeaPOS p1 = *start_pos;
+       int RetVal = 1;
+
+       distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
+       azimuth = nmea_degree2radian(azimuth);
+
+       end_pos->lat = asin(sin(p1.lat) * cos(distance) + cos(p1.lat) * sin(distance) * cos(azimuth));
+       end_pos->lon = p1.lon
+                       + atan2(sin(azimuth) * sin(distance) * cos(p1.lat), cos(distance) - sin(p1.lat) * sin(end_pos->lat));
+
+       if (isnan(end_pos->lat) || isnan(end_pos->lon)) {
+               end_pos->lat = 0;
+               end_pos->lon = 0;
+               RetVal = 0;
+       }
+
+       return RetVal;
 }
 
 /**
- * \brief Horizontal move of point position
+ * Perform a horizontal move.
  * This function uses an algorithm for an oblate spheroid earth model.
  * The algorithm is described here: 
  * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ *
+ * @param start_pos a pointer to the start position (in radians)
+ * @param end_pos a pointer to the end position (in radians) (output)
+ * @param azimuth azimuth (in radians)
+ * @param distance the distance (in km)
+ * @param end_azimuth azimuth at end position (in radians) (output)
+ * @return 1 (true) on success, 0 (false) on failure
  */
-int nmea_move_horz_ellipsoid(
-    const nmeaPOS *start_pos,   /**< Start position in radians */
-    nmeaPOS *end_pos,           /**< (O) Result position in radians */
-    double azimuth,             /**< Azimuth in radians */
-    double distance,            /**< Distance (km) */
-    double *end_azimuth         /**< (O) Azimuth at end position in radians */
-    )
-{
-    /* Variables */
-    double f, a, b, sqr_a, sqr_b;
-    double phi1, tan_U1, sin_U1, cos_U1, s, alpha1, sin_alpha1, cos_alpha1;
-    double sigma1, sin_alpha, sqr_cos_alpha, sqr_u, A, B;
-    double sigma_initial, sigma, sigma_prev, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, delta_sigma;
-    int remaining_steps;
-    double tmp1, phi2, lambda, C, L;
-    
-    /* Check input */
-    assert(start_pos != 0);
-    assert(end_pos != 0);
-    
-    if (fabs(distance) < 1e-12)
-    { /* No move */
-        *end_pos = *start_pos;
-        if ( end_azimuth != 0 ) *end_azimuth = azimuth;
-        return ! (isnan(end_pos->lat) || isnan(end_pos->lon));
-    } /* No move */
-
-    /* Earth geometry */
-    f = NMEA_EARTH_FLATTENING;
-    a = NMEA_EARTH_SEMIMAJORAXIS_M;
-    b = (1 - f) * a;
-    sqr_a = a * a;
-    sqr_b = b * b;
-    
-    /* Calculation */
-    phi1 = start_pos->lat;
-    tan_U1 = (1 - f) * tan(phi1);
-    cos_U1 = 1 / sqrt(1 + tan_U1 * tan_U1);
-    sin_U1 = tan_U1 * cos_U1;
-    s = distance;
-    alpha1 = azimuth;
-    sin_alpha1 = sin(alpha1);
-    cos_alpha1 = cos(alpha1);
-    sigma1 = atan2(tan_U1, cos_alpha1);
-    sin_alpha = cos_U1 * sin_alpha1;
-    sqr_cos_alpha = 1 - sin_alpha * sin_alpha;
-    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
-    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
-    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
-    
-    /* Initialize iteration */
-    sigma_initial = s / (b * A);
-    sigma = sigma_initial;
-    sin_sigma = sin(sigma);
-    cos_sigma = cos(sigma);
-    cos_2_sigmam = cos(2 * sigma1 + sigma);
-    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-    delta_sigma = 0;
-    sigma_prev = 2 * NMEA_PI;
-    remaining_steps = 20;
-
-    while ((fabs(sigma - sigma_prev) > 1e-12) && (remaining_steps > 0))
-    { /* Iterate */
-        cos_2_sigmam = cos(2 * sigma1 + sigma);
-        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
-        sin_sigma = sin(sigma);
-        cos_sigma = cos(sigma);
-        delta_sigma = B * sin_sigma * ( 
-             cos_2_sigmam + B / 4 * ( 
-             cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) - 
-             B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
-             ));
-        sigma_prev = sigma;
-        sigma = sigma_initial + delta_sigma;
-        remaining_steps --;
-    } /* Iterate */
-    
-    /* Calculate result */
-    tmp1 = (sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_alpha1);
-    phi2 = atan2(
-            sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_alpha1,
-            (1 - f) * sqrt(sin_alpha * sin_alpha + tmp1 * tmp1)
-            );
-    lambda = atan2(
-            sin_sigma * sin_alpha1,
-            cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_alpha1
-            );
-    C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
-    L = lambda -
-        (1 - C) * f * sin_alpha * (
-        sigma + C * sin_sigma *
-        (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam))
-        );
-    
-    /* Result */
-    end_pos->lon = start_pos->lon + L;
-    end_pos->lat = phi2;
-    if ( end_azimuth != 0 )
-    {
-        *end_azimuth = atan2(
-            sin_alpha, -sin_U1 * sin_sigma + cos_U1 * cos_sigma * cos_alpha1
-            );
-    }
-    return ! (isnan(end_pos->lat) || isnan(end_pos->lon));
+int nmea_move_horz_ellipsoid(const nmeaPOS *start_pos, nmeaPOS *end_pos, double azimuth, double distance,
+               double *end_azimuth) {
+       /* Variables */
+       double f, a, b, sqr_a, sqr_b;
+       double phi1, tan_U1, sin_U1, cos_U1, s, alpha1, sin_alpha1, cos_alpha1;
+       double sigma1, sin_alpha, sqr_cos_alpha, sqr_u, A, B;
+       double sigma_initial, sigma, sigma_prev, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, delta_sigma;
+       int remaining_steps;
+       double tmp1, phi2, lambda, C, L;
+
+       /* Check input */
+       assert(start_pos != 0);
+       assert(end_pos != 0);
+
+       if (fabs(distance) < 1e-12) { /* No move */
+               *end_pos = *start_pos;
+               if (end_azimuth != 0)
+                       *end_azimuth = azimuth;
+               return !(isnan(end_pos->lat) || isnan(end_pos->lon));
+       } /* No move */
+
+       /* Earth geometry */
+       f = NMEA_EARTH_FLATTENING;
+       a = NMEA_EARTH_SEMIMAJORAXIS_M;
+       b = (1 - f) * a;
+       sqr_a = a * a;
+       sqr_b = b * b;
+
+       /* Calculation */
+       phi1 = start_pos->lat;
+       tan_U1 = (1 - f) * tan(phi1);
+       cos_U1 = 1 / sqrt(1 + tan_U1 * tan_U1);
+       sin_U1 = tan_U1 * cos_U1;
+       s = distance;
+       alpha1 = azimuth;
+       sin_alpha1 = sin(alpha1);
+       cos_alpha1 = cos(alpha1);
+       sigma1 = atan2(tan_U1, cos_alpha1);
+       sin_alpha = cos_U1 * sin_alpha1;
+       sqr_cos_alpha = 1 - sin_alpha * sin_alpha;
+       sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b;
+       A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+       B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+
+       /* Initialize iteration */
+       sigma_initial = s / (b * A);
+       sigma = sigma_initial;
+       sin_sigma = sin(sigma);
+       cos_sigma = cos(sigma);
+       cos_2_sigmam = cos(2 * sigma1 + sigma);
+       sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+       delta_sigma = 0;
+       sigma_prev = 2 * NMEA_PI;
+       remaining_steps = 20;
+
+       while ((fabs(sigma - sigma_prev) > 1e-12) && (remaining_steps > 0)) { /* Iterate */
+               cos_2_sigmam = cos(2 * sigma1 + sigma);
+               sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+               sin_sigma = sin(sigma);
+               cos_sigma = cos(sigma);
+               delta_sigma = B * sin_sigma
+                               * (cos_2_sigmam
+                                               + B / 4
+                                                               * (cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)
+                                                                               - B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma)
+                                                                                               * (-3 + 4 * sqr_cos_2_sigmam)));
+               sigma_prev = sigma;
+               sigma = sigma_initial + delta_sigma;
+               remaining_steps--;
+       } /* Iterate */
+
+       /* Calculate result */
+       tmp1 = (sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_alpha1);
+       phi2 = atan2(sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_alpha1,
+                       (1 - f) * sqrt(sin_alpha * sin_alpha + tmp1 * tmp1));
+       lambda = atan2(sin_sigma * sin_alpha1, cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_alpha1);
+       C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+       L = lambda
+                       - (1 - C) * f * sin_alpha
+                                       * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));
+
+       /* Result */
+       end_pos->lon = start_pos->lon + L;
+       end_pos->lat = phi2;
+       if (end_azimuth != 0) {
+               *end_azimuth = atan2(sin_alpha, -sin_U1 * sin_sigma + cos_U1 * cos_sigma * cos_alpha1);
+       }
+       return !(isnan(end_pos->lat) || isnan(end_pos->lon));
 }
 
 /**
- * \brief Convert position from INFO to radians position
+ * Convert a position from INFO to radians position
+ *
+ * @param info a pointer to the INFO position
+ * @param pos a pointer to the radians position (output)
  */
-void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos)
-{
-    pos->lat = nmea_ndeg2radian(info->lat);
-    pos->lon = nmea_ndeg2radian(info->lon);
+void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos) {
+       if (nmea_INFO_is_present(info->present, LAT))
+               pos->lat = nmea_ndeg2radian(info->lat);
+       else
+               pos->lat = NMEA_DEF_LAT;
+
+       if (nmea_INFO_is_present(info->present, LON))
+               pos->lon = nmea_ndeg2radian(info->lon);
+       else
+               pos->lat = NMEA_DEF_LON;
 }
 
 /**
- * \brief Convert radians position to INFOs position
+ * Convert a radians position to a position from INFO
+ *
+ * @param pos a pointer to the radians position
+ * @param info a pointer to the INFO position (output)
  */
-void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info)
-{
-    info->lat = nmea_radian2ndeg(pos->lat);
-    info->lon = nmea_radian2ndeg(pos->lon);
+void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info) {
+       info->lat = nmea_radian2ndeg(pos->lat);
+       info->lon = nmea_radian2ndeg(pos->lon);
+       nmea_INFO_set_present(&info->present, LAT);
+       nmea_INFO_set_present(&info->present, LON);
 }
index 7cd20d4..e3ec4ab 100644 (file)
 
 #include <nmea/sentence.h>
 #include <nmea/gmath.h>
-#include <nmea/time.h>
 
+#include <stdbool.h>
 #include <string.h>
 #include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include <assert.h>
 
-void nmea_zero_INFO(nmeaINFO *info)
-{
+/**
+ * Reset the time to now
+ *
+ * @param utc a pointer to the time structure
+ * @param present a pointer to a present field. when non-NULL then the UTCDATE
+ * and UTCTIME flags are set in it.
+ */
+void nmea_time_now(nmeaTIME *utc, uint32_t * present) {
+       struct timeval tp;
+       struct tm tt;
+
+       assert(utc);
+
+       gettimeofday(&tp, NULL );
+       gmtime_r(&tp.tv_sec, &tt);
+
+       utc->year = tt.tm_year;
+       utc->mon = tt.tm_mon;
+       utc->day = tt.tm_mday;
+       utc->hour = tt.tm_hour;
+       utc->min = tt.tm_min;
+       utc->sec = tt.tm_sec;
+       utc->hsec = (tp.tv_usec / 10000);
+       if (present) {
+               *present |= (UTCDATE | UTCTIME);
+       }
+}
+
+/**
+ * Clear an info structure.
+ * Resets the time to now, sets up the signal as BAD, the FIX as BAD, and
+ * signals presence of these fields.
+ * Resets all other fields to 0.
+ *
+ * @param info a pointer to the structure
+ */
+void nmea_zero_INFO(nmeaINFO *info) {
        if (!info) {
                return;
        }
 
-    memset(info, 0, sizeof(nmeaINFO));
-    nmea_time_now(&info->utc);
-    info->sig = NMEA_SIG_BAD;
-    info->fix = NMEA_FIX_BAD;
+       memset(info, 0, sizeof(nmeaINFO));
+       nmea_time_now(&info->utc, &info->present);
+
+       info->sig = NMEA_SIG_BAD;
+       nmea_INFO_set_present(&info->present, SIG);
+
+       info->fix = NMEA_FIX_BAD;
+       nmea_INFO_set_present(&info->present, FIX);
 }
 
 /**
- * Determine whether a given nmeaINFO structure has a certain field.
- *
- * nmeaINFO dependencies:
- <pre>
- field/sentence GPGGA   GPGSA   GPGSV   GPRMC   GPVTG
- smask:         x       x       x       x       x
- utc:           x                       x
- sig:           x                       x
- fix:                   x               x
- PDOP:                  x
- HDOP:          x       x
- VDOP:                  x
- lat:           x                       x
- lon:           x                       x
- elv:           x
- speed:                                 x       x
- direction:                             x       x
- declination:                                   x
- satinfo:               x       x
- </pre>
+ * Determine if a nmeaINFO structure has a certain field (from the smask).
+ * Note: this is not the complete truth as fields may be absent in certain
+ * sentences and are presented as 'present' by this function.
  *
- * @param smask
- * the smask of a nmeaINFO structure
- * @param fieldName
- * the field name
- *
- * @return
- * - true when the nmeaINFO structure has the field
- * - false otherwise
+ * @deprecated use nmea_INFO_is_present instead
+ * @param smask the smask field
+ * @param fieldName use a name from nmeaINFO_FIELD
+ * @return a boolean, true when the structure has the requested field
  */
-bool nmea_INFO_has_field(int smask, nmeaINFO_FIELD fieldName) {
+bool nmea_INFO_is_present_smask(int smask, nmeaINFO_FIELD fieldName) {
        switch (fieldName) {
-               case SMASK:
-                       return true;
+       case SMASK:
+               return true;
+
+       case ELV:
+               return ((smask & GPGGA) != 0);
 
-               case UTC:
-               case SIG:
-               case LAT:
-               case LON:
-                       return ((smask & (GPGGA | GPRMC)) != 0);
+       case PDOP:
+       case VDOP:
+       case SATINUSE:
+               return ((smask & GPGSA) != 0);
 
-               case FIX:
-                       return ((smask & (GPGSA | GPRMC)) != 0);
+       case SATINVIEW:
+               return ((smask & GPGSV) != 0);
 
-               case PDOP:
-               case VDOP:
-                       return ((smask & GPGSA) != 0);
+       case UTCDATE:
+       case MAGVAR:
+               return ((smask & GPRMC) != 0);
 
-               case HDOP:
-                       return ((smask & (GPGGA | GPGSA)) != 0);
+       case MTRACK:
+               return ((smask & GPVTG) != 0);
 
-               case ELV:
-                       return ((smask & GPGGA) != 0);
+       case SATINUSECOUNT:
+       case HDOP:
+               return ((smask & (GPGGA | GPGSA)) != 0);
 
-               case SPEED:
-               case DIRECTION:
-                       return ((smask & (GPRMC | GPVTG)) != 0);
+       case UTCTIME:
+       case SIG:
+       case LAT:
+       case LON:
+               return ((smask & (GPGGA | GPRMC)) != 0);
 
-               case DECLINATION:
-                       return ((smask & GPVTG) != 0);
+       case FIX:
+               return ((smask & (GPGSA | GPRMC)) != 0);
 
-               case SATINFO:
-                       return ((smask & (GPGSA | GPGSV)) != 0);
+       case SPEED:
+       case TRACK:
+               return ((smask & (GPRMC | GPVTG)) != 0);
 
-               default:
-                       return false;
+       default:
+               return false;
        }
 }
 
 /**
+ * Determine if a nmeaINFO structure has a certain field
+ *
+ * @param present the presence field
+ * @param fieldName use a name from nmeaINFO_FIELD
+ * @return a boolean, true when the structure has the requested field
+ */
+bool nmea_INFO_is_present(uint32_t present, nmeaINFO_FIELD fieldName) {
+       return ((present & fieldName) != 0);
+}
+
+/**
+ * Flag a nmeaINFO structure to contain a certain field
+ *
+ * @param present a pointer to the presence field
+ * @param fieldName use a name from nmeaINFO_FIELD
+ */
+void nmea_INFO_set_present(uint32_t * present, nmeaINFO_FIELD fieldName) {
+       assert(present);
+       *present |= fieldName;
+}
+
+/**
+ * Flag a nmeaINFO structure to NOT contain a certain field
+ *
+ * @param present a pointer to the presence field
+ * @param fieldName use a name from nmeaINFO_FIELD
+ */
+void nmea_INFO_unset_present(uint32_t * present, nmeaINFO_FIELD fieldName) {
+       assert(present);
+       *present &= ~fieldName;
+}
+
+/**
  * Sanitise the NMEA info, make sure that:
+ * - sig is in the range [0, 8],
+ * - fix is in the range [1, 3],
+ * - DOPs are positive,
  * - latitude is in the range [-9000, 9000],
  * - longitude is in the range [-18000, 18000],
- * - DOPs are positive,
  * - speed is positive,
- * - direction is in the range [0, 360>.
+ * - track is in the range [0, 360>.
+ * - mtrack is in the range [0, 360>.
+ * - magvar is in the range [0, 360>.
+ * - satinfo:
+ *   - inuse and in_use are consistent (w.r.t. count)
+ *   - inview and sat are consistent (w.r.t. count/id)
+ *   - in_use and sat are consistent (w.r.t. count/id)
+ *   - elv is in the range [0, 90]
+ *   - azimuth is in the range [0, 359]
+ *   - sig is in the range [0, 99]
  *
  * Time is set to the current time when not present.
- *
- * When a field is not present then it is reset to its default (NMEA_SIG_BAD,
- * NMEA_FIX_BAD, 0).
- *
- * Satinfo is not touched.
+ * Fields are reset to their defaults (0) when not signaled as being present.
  *
  * @param nmeaInfo
  * the NMEA info structure to sanitise
@@ -131,71 +198,118 @@ void nmea_INFO_sanitise(nmeaINFO *nmeaInfo) {
        double lat = 0;
        double lon = 0;
        double speed = 0;
-       double direction = 0;
+       double track = 0;
+       double mtrack = 0;
+       double magvar = 0;
        bool latAdjusted = false;
        bool lonAdjusted = false;
        bool speedAdjusted = false;
-       bool directionAdjusted = false;
+       bool trackAdjusted = false;
+       bool mtrackAdjusted = false;
+       bool magvarAdjusted = false;
+       nmeaTIME utc;
+       int inuseIndex;
+       int inviewIndex;
 
        if (!nmeaInfo) {
                return;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, UTC)) {
-               nmea_time_now(&nmeaInfo->utc);
+       nmeaInfo->present = nmeaInfo->present & NMEA_INFO_PRESENT_MASK;
+
+       if (!nmea_INFO_is_present(nmeaInfo->present, SMASK)) {
+               nmeaInfo->smask = 0;
+       }
+
+       if (!nmea_INFO_is_present(nmeaInfo->present, UTCDATE) || !nmea_INFO_is_present(nmeaInfo->present, UTCTIME)) {
+               nmea_time_now(&utc, NULL);
+       }
+
+       if (!nmea_INFO_is_present(nmeaInfo->present, UTCDATE)) {
+               nmeaInfo->utc.year = utc.year;
+               nmeaInfo->utc.mon = utc.mon;
+               nmeaInfo->utc.day = utc.day;
+       }
+
+       if (!nmea_INFO_is_present(nmeaInfo->present, UTCTIME)) {
+               nmeaInfo->utc.hour = utc.hour;
+               nmeaInfo->utc.min = utc.min;
+               nmeaInfo->utc.sec = utc.sec;
+               nmeaInfo->utc.hsec = utc.hsec;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, SIG)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, SIG)) {
                nmeaInfo->sig = NMEA_SIG_BAD;
+       } else {
+               if ((nmeaInfo->sig < NMEA_SIG_BAD) || (nmeaInfo->sig > NMEA_SIG_SIM)) {
+                       nmeaInfo->sig = NMEA_SIG_BAD;
+               }
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, FIX)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, FIX)) {
                nmeaInfo->fix = NMEA_FIX_BAD;
+       } else {
+               if ((nmeaInfo->fix < NMEA_FIX_BAD) || (nmeaInfo->fix > NMEA_FIX_3D)) {
+                       nmeaInfo->fix = NMEA_FIX_BAD;
+               }
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, PDOP)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, PDOP)) {
                nmeaInfo->PDOP = 0;
        } else {
                nmeaInfo->PDOP = fabs(nmeaInfo->PDOP);
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, HDOP)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, HDOP)) {
                nmeaInfo->HDOP = 0;
        } else {
                nmeaInfo->HDOP = fabs(nmeaInfo->HDOP);
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, VDOP)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, VDOP)) {
                nmeaInfo->VDOP = 0;
        } else {
                nmeaInfo->VDOP = fabs(nmeaInfo->VDOP);
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, LAT)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, LAT)) {
                nmeaInfo->lat = 0;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, LON)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, LON)) {
                nmeaInfo->lon = 0;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, ELV)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, ELV)) {
                nmeaInfo->elv = 0;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, SPEED)) {
+       if (!nmea_INFO_is_present(nmeaInfo->present, SPEED)) {
                nmeaInfo->speed = 0;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, DIRECTION)) {
-               nmeaInfo->direction = 0;
+       if (!nmea_INFO_is_present(nmeaInfo->present, TRACK)) {
+               nmeaInfo->track = 0;
        }
 
-       if (!nmea_INFO_has_field(nmeaInfo->smask, DECLINATION)) {
-               nmeaInfo->declination = 0;
+       if (!nmea_INFO_is_present(nmeaInfo->present, MTRACK)) {
+               nmeaInfo->mtrack = 0;
        }
 
-       /* satinfo is not used */
+       if (!nmea_INFO_is_present(nmeaInfo->present, MAGVAR)) {
+               nmeaInfo->magvar = 0;
+       }
+
+       if (!nmea_INFO_is_present(nmeaInfo->present, SATINUSECOUNT)) {
+               nmeaInfo->satinfo.inuse = 0;
+       }
+       if (!nmea_INFO_is_present(nmeaInfo->present, SATINUSE)) {
+               memset(&nmeaInfo->satinfo.in_use, 0, sizeof(nmeaInfo->satinfo.in_use));
+       }
+       if (!nmea_INFO_is_present(nmeaInfo->present, SATINVIEW)) {
+               nmeaInfo->satinfo.inview = 0;
+               memset(&nmeaInfo->satinfo.sat, 0, sizeof(nmeaInfo->satinfo.sat));
+       }
 
        /*
         * lat
@@ -263,13 +377,16 @@ void nmea_INFO_sanitise(nmeaINFO *nmeaInfo) {
         */
 
        speed = nmeaInfo->speed;
-       direction = nmeaInfo->direction;
+       track = nmeaInfo->track;
+       mtrack = nmeaInfo->mtrack;
 
        if (speed < 0.0) {
                speed = -speed;
-               direction += 180.0;
+               track += 180.0;
+               mtrack += 180.0;
                speedAdjusted = true;
-               directionAdjusted = true;
+               trackAdjusted = true;
+               mtrackAdjusted = true;
        }
 
        /* speed is now in [0, max> */
@@ -279,23 +396,146 @@ void nmea_INFO_sanitise(nmeaINFO *nmeaInfo) {
        }
 
        /*
-        * direction
+        * track
         */
 
-       /* force direction in [0, 360> */
-       while (direction < 0.0) {
-               direction += 360.0;
-               directionAdjusted = true;
+       /* force track in [0, 360> */
+       while (track < 0.0) {
+               track += 360.0;
+               trackAdjusted = true;
        }
-       while (direction >= 360.0) {
-               direction -= 360.0;
-               directionAdjusted = true;
+       while (track >= 360.0) {
+               track -= 360.0;
+               trackAdjusted = true;
        }
 
-       /* direction is now in [0, 360> */
+       /* track is now in [0, 360> */
+
+       if (trackAdjusted) {
+               nmeaInfo->track = track;
+       }
+
+       /*
+        * mtrack
+        */
+
+       /* force mtrack in [0, 360> */
+       while (mtrack < 0.0) {
+               mtrack += 360.0;
+               mtrackAdjusted = true;
+       }
+       while (mtrack >= 360.0) {
+               mtrack -= 360.0;
+               mtrackAdjusted = true;
+       }
+
+       /* mtrack is now in [0, 360> */
+
+       if (mtrackAdjusted) {
+               nmeaInfo->mtrack = mtrack;
+       }
+
+       /*
+        * magvar
+        */
+
+       magvar = nmeaInfo->magvar;
+
+       /* force magvar in [0, 360> */
+       while (magvar < 0.0) {
+               magvar += 360.0;
+               magvarAdjusted = true;
+       }
+       while (magvar >= 360.0) {
+               magvar -= 360.0;
+               magvarAdjusted = true;
+       }
+
+       /* magvar is now in [0, 360> */
+
+       if (magvarAdjusted) {
+               nmeaInfo->magvar = magvar;
+       }
+
+       /*
+        * satinfo
+        */
 
-       if (directionAdjusted) {
-               nmeaInfo->direction = direction;
+       nmeaInfo->satinfo.inuse = 0;
+       for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
+               if (nmeaInfo->satinfo.in_use[inuseIndex])
+                       nmeaInfo->satinfo.inuse++;
+       }
+
+       nmeaInfo->satinfo.inview = 0;
+       for (inviewIndex = 0; inviewIndex < NMEA_MAXSAT; inviewIndex++) {
+               if (nmeaInfo->satinfo.sat[inviewIndex].id) {
+                       nmeaInfo->satinfo.inview++;
+
+                       /* force elv in [-180, 180] */
+                       while (nmeaInfo->satinfo.sat[inviewIndex].elv < -180) {
+                               nmeaInfo->satinfo.sat[inviewIndex].elv += 360;
+                       }
+                       while (nmeaInfo->satinfo.sat[inviewIndex].elv > 180) {
+                               nmeaInfo->satinfo.sat[inviewIndex].elv -= 360;
+                       }
+
+                       /* elv is now in [-180, 180] */
+
+                       /* force elv from <90, 180] in [90, 0] */
+                       if (nmeaInfo->satinfo.sat[inviewIndex].elv > 90) {
+                               nmeaInfo->satinfo.sat[inviewIndex].elv = 180 - nmeaInfo->satinfo.sat[inviewIndex].elv;
+                       }
+
+                       /* force elv from [-180, -90> in [0, -90] */
+                       if (nmeaInfo->satinfo.sat[inviewIndex].elv < -90) {
+                               nmeaInfo->satinfo.sat[inviewIndex].elv = -180 - nmeaInfo->satinfo.sat[inviewIndex].elv;
+                       }
+
+                       /* elv is now in [-90, 90] */
+
+                       if (nmeaInfo->satinfo.sat[inviewIndex].elv < 0) {
+                               nmeaInfo->satinfo.sat[inviewIndex].elv = -nmeaInfo->satinfo.sat[inviewIndex].elv;
+                       }
+
+                       /* elv is now in [0, 90] */
+
+                       /* force azimuth in [0, 360> */
+                       while (nmeaInfo->satinfo.sat[inviewIndex].azimuth < 0) {
+                               nmeaInfo->satinfo.sat[inviewIndex].azimuth += 360;
+                       }
+                       while (nmeaInfo->satinfo.sat[inviewIndex].azimuth >= 360) {
+                               nmeaInfo->satinfo.sat[inviewIndex].azimuth -= 360;
+                       }
+                       /* azimuth is now in [0, 360> */
+
+                       /* force sig in [0, 99] */
+                       if (nmeaInfo->satinfo.sat[inviewIndex].sig < 0)
+                               nmeaInfo->satinfo.sat[inviewIndex].sig = 0;
+                       if (nmeaInfo->satinfo.sat[inviewIndex].sig > 99)
+                               nmeaInfo->satinfo.sat[inviewIndex].sig = 99;
+               }
+       }
+
+       /* make sure the in_use IDs map to sat IDs */
+       for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
+               int inuseID = nmeaInfo->satinfo.in_use[inuseIndex];
+               if (inuseID) {
+                       bool found = false;
+                       for (inviewIndex = 0; inviewIndex < NMEA_MAXSAT; inviewIndex++) {
+                               int inviewID = nmeaInfo->satinfo.sat[inviewIndex].id;
+                               if (inuseID == inviewID) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               /* clear the id, did not find it */
+                               nmeaInfo->satinfo.in_use[inuseIndex] = 0;
+                               if (nmeaInfo->satinfo.inuse)
+                                       nmeaInfo->satinfo.inuse--;
+                       }
+               }
        }
 }
 
@@ -318,30 +558,31 @@ void nmea_INFO_unit_conversion(nmeaINFO * nmeaInfo) {
        /* sig (already in correct format) */
        /* fix (already in correct format) */
 
-       if (nmea_INFO_has_field(nmeaInfo->smask, PDOP)) {
+       if (nmea_INFO_is_present(nmeaInfo->present, PDOP)) {
                nmeaInfo->PDOP = nmea_dop2meters(nmeaInfo->PDOP);
        }
 
-       if (nmea_INFO_has_field(nmeaInfo->smask, HDOP)) {
+       if (nmea_INFO_is_present(nmeaInfo->present, HDOP)) {
                nmeaInfo->HDOP = nmea_dop2meters(nmeaInfo->HDOP);
        }
 
-       if (nmea_INFO_has_field(nmeaInfo->smask, VDOP)) {
+       if (nmea_INFO_is_present(nmeaInfo->present, VDOP)) {
                nmeaInfo->VDOP = nmea_dop2meters(nmeaInfo->VDOP);
        }
 
-       if (nmea_INFO_has_field(nmeaInfo->smask, LAT)) {
+       if (nmea_INFO_is_present(nmeaInfo->present, LAT)) {
                nmeaInfo->lat = nmea_ndeg2degree(nmeaInfo->lat);
        }
 
-       if (nmea_INFO_has_field(nmeaInfo->smask, LON)) {
+       if (nmea_INFO_is_present(nmeaInfo->present, LON)) {
                nmeaInfo->lon = nmea_ndeg2degree(nmeaInfo->lon);
        }
 
        /* elv (already in correct format) */
        /* speed (already in correct format) */
-       /* direction (already in correct format) */
-       /* declination (already in correct format) */
+       /* track (already in correct format) */
+       /* mtrack (already in correct format) */
+       /* magvar (already in correct format) */
 
-       /* satinfo (not used) */
+       /* satinfo (already in correct format) */
 }
index b2adf7e..5e35d58 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/**
- * \file parse.h
- * \brief Functions of a low level for analysis of
- * packages of NMEA stream.
- *
- * \code
- * ...
- * ptype = nmea_pack_type(
- *     (const char *)parser->buffer + nparsed + 1,
- *     parser->buff_use - nparsed - 1);
- * 
- * if(0 == (node = malloc(sizeof(nmeaParserNODE))))
- *     goto mem_fail;
- * 
- * node->pack = 0;
- * 
- * switch(ptype)
- * {
- * case GPGGA:
- *     if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
- *         goto mem_fail;
- *     node->packType = GPGGA;
- *     if(!nmea_parse_GPGGA(
- *         (const char *)parser->buffer + nparsed,
- *         sen_sz, (nmeaGPGGA *)node->pack))
- *     {
- *         free(node);
- *         node = 0;
- *     }
- *     break;
- * case GPGSA:
- *     if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
- *         goto mem_fail;
- *     node->packType = GPGSA;
- *     if(!nmea_parse_GPGSA(
- *         (const char *)parser->buffer + nparsed,
- *         sen_sz, (nmeaGPGSA *)node->pack))
- *     {
- *         free(node);
- *         node = 0;
- *     }
- *     break;
- * ...
- * \endcode
- */
-
 #include <nmea/parse.h>
 
+#include <nmea/gmath.h>
+#include <nmea/tok.h>
+#include <nmea/context.h>
+
 #include <string.h>
 #include <assert.h>
+#include <math.h>
+#include <ctype.h>
+#include <stdio.h>
 
-#include <nmea/context.h>
-#include <nmea/tok.h>
-#include <nmea/units.h>
-
-#define NMEA_TIMEPARSE_BUF  (256)
-
-static int _nmea_parse_time(const char *buff, int buff_sz, nmeaTIME *res)
-{
-    int success = 0;
-
-    switch(buff_sz)
-    {
-    case sizeof("hhmmss") - 1:
-        success = (3 == nmea_scanf(buff, buff_sz,
-            "%2d%2d%2d", &(res->hour), &(res->min), &(res->sec)
-            ));
-        break;
-    case sizeof("hhmmss.s") - 1:
-    case sizeof("hhmmss.ss") - 1:
-    case sizeof("hhmmss.sss") - 1:
-        success = (4 == nmea_scanf(buff, buff_sz,
-            "%2d%2d%2d.%d", &(res->hour), &(res->min), &(res->sec), &(res->hsec)
-            ));
-        break;
-    default:
-        nmea_error("Parse of time error (format error)!");
-        success = 0;
-        break;
-    }
-
-    return (success?0:-1);        
-}
+/** the size of the buffer to put time string (that is to be parsed) into */
+#define NMEA_TIMEPARSE_BUF  256
 
 /**
- * \brief Define packet type by header (nmeaPACKTYPE).
- * @param buff a constant character pointer of packet buffer.
- * @param buff_sz buffer size.
- * @return The defined packet type
- * @see nmeaPACKTYPE
+ * Parse nmeaTIME (time only, no date) from a string.
+ * The format that is used (hhmmss, hhmmss.s, hhmmss.ss or hhmmss.sss) is
+ * determined by the length of the string.
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param t a pointer to the nmeaTIME structure in which to store the parsed time
+ * @return true on success, false otherwise
  */
-int nmea_pack_type(const char *buff, int buff_sz)
-{
-    static const char *pheads[] = {
-        "GPGGA",
-        "GPGSA",
-        "GPGSV",
-        "GPRMC",
-        "GPVTG",
-    };
-
-    assert(buff);
-
-    if(buff_sz < 5)
-        return GPNON;
-    else if(0 == memcmp(buff, pheads[0], 5))
-        return GPGGA;
-    else if(0 == memcmp(buff, pheads[1], 5))
-        return GPGSA;
-    else if(0 == memcmp(buff, pheads[2], 5))
-        return GPGSV;
-    else if(0 == memcmp(buff, pheads[3], 5))
-        return GPRMC;
-    else if(0 == memcmp(buff, pheads[4], 5))
-        return GPVTG;
-
-    return GPNON;
+static bool _nmea_parse_time(const char *s, const int len, nmeaTIME *t) {
+       assert(s);
+       assert(t);
+
+       if (len == (sizeof("hhmmss") - 1)) {
+               return (3 == nmea_scanf(s, len, "%2d%2d%2d", &t->hour, &t->min, &t->sec));
+       }
+
+       if (len == (sizeof("hhmmss.s") - 1)) {
+               if (4 == nmea_scanf(s, len, "%2d%2d%2d.%d", &t->hour, &t->min, &t->sec, &t->hsec)) {
+                       t->hsec *= 10;
+                       return true;
+               }
+               return false;
+       }
+
+       if (len == (sizeof("hhmmss.ss") - 1)) {
+               return (4 == nmea_scanf(s, len, "%2d%2d%2d.%d", &t->hour, &t->min, &t->sec, &t->hsec));
+       }
+
+       if (len == (sizeof("hhmmss.sss") - 1)) {
+               if ((4 == nmea_scanf(s, len, "%2d%2d%2d.%d", &t->hour, &t->min, &t->sec, &t->hsec))) {
+                       t->hsec = (t->hsec + 9) / 10;
+                       return true;
+               }
+               return false;
+       }
+
+       nmea_error("Parse error: invalid time format in %s", s);
+       return false;
 }
 
 /**
- * \brief Find tail of packet ("\r\n") in buffer and check control sum (CRC).
- * @param buff a constant character pointer of packets buffer.
- * @param buff_sz buffer size.
- * @param res_crc a integer pointer for return CRC of packet (must be defined).
- * @return Number of bytes to packet tail.
+ * Validate the time fields in an nmeaTIME structure.
+ * Expects:
+ * <pre>
+ *   0 <= hour <   24
+ *   0 <= min  <   60
+ *   0 <= sec  <=  60
+ *   0 <= hsec <  100
+ * </pre>
+ *
+ * @param t a pointer to the structure
+ * @return true when valid, false otherwise
  */
-int nmea_find_tail(const char *buff, int buff_sz, int *res_crc)
-{
-    static const int tail_sz = 3 /* *[CRC] */ + 2 /* \r\n */;
-
-    const char *end_buff = buff + buff_sz;
-    int nread = 0;
-    int crc = 0;
-
-    assert(buff && res_crc);
-
-    *res_crc = -1;
-
-    for(;buff < end_buff; ++buff, ++nread)
-    {
-        if(('$' == *buff) && nread)
-        {
-            buff = 0;
-            break;
-        }
-        else if('*' == *buff)
-        {
-            if(buff + tail_sz <= end_buff && '\r' == buff[3] && '\n' == buff[4])
-            {
-                *res_crc = nmea_atoi(buff + 1, 2, 16);
-                nread = buff_sz - (int)(end_buff - (buff + tail_sz));
-                if(*res_crc != crc)
-                {
-                    *res_crc = -1;
-                    buff = 0;
-                }
-            }
-
-            break;
-        }
-        else if(nread)
-            crc ^= (int)*buff;
-    }
-
-    if(*res_crc < 0 && buff)
-        nread = 0;
-
-    return nread;
+static bool validateTime(const nmeaTIME * t) {
+       if (!t) {
+               return false;
+       }
+
+       if (!((t->hour >= 0) && (t->hour < 24) && (t->min >= 0) && (t->min < 60) && (t->sec >= 0) && (t->sec <= 60)
+                       && (t->hsec >= 0) && (t->hsec < 100))) {
+               nmea_error("Parse error: invalid time (%d:%d:%d.%d)", t->hour, t->min, t->sec, t->hsec);
+               return false;
+       }
+
+       return true;
 }
 
 /**
- * \brief Parse GGA packet from buffer.
- * @param buff a constant character pointer of packet buffer.
- * @param buff_sz buffer size.
- * @param pack a pointer of packet which will filled by function.
- * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ * Validate the date fields in an nmeaTIME structure.
+ * Expects:
+ * <pre>
+ *   year  [90, 189]
+ *   month [ 0,  11]
+ *   day   [ 1,  31]
+ * </pre>
+ *
+ * @param t a pointer to the structure
+ * @return true when valid, false otherwise
  */
-int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack)
-{
-    char time_buff[NMEA_TIMEPARSE_BUF];
-
-    assert(buff && pack);
-
-    memset(pack, 0, sizeof(nmeaGPGGA));
-
-    nmea_trace_buff(buff, buff_sz);
-
-    if(14 != nmea_scanf(buff, buff_sz,
-        "$GPGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*",
-        &(time_buff[0]),
-        &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
-        &(pack->sig), &(pack->satinuse), &(pack->HDOP), &(pack->elv), &(pack->elv_units),
-        &(pack->diff), &(pack->diff_units), &(pack->dgps_age), &(pack->dgps_sid)))
-    {
-        nmea_error("GPGGA parse error!");
-        return 0;
-    }
-
-    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
-    {
-        nmea_error("GPGGA time parse error!");
-        return 0;
-    }
-
-    return 1;
+static bool validateDate(const nmeaTIME * t) {
+       if (!t) {
+               return false;
+       }
+
+       if (!((t->year >= 90) && (t->year <= 189) && (t->mon >= 0) && (t->mon <= 11) && (t->day >= 1) && (t->day <= 31))) {
+               nmea_error("Parse error: invalid date (%d-%d-%d - D-M-Y)", t->day, t->mon, t->year);
+               return false;
+       }
+
+       return true;
 }
 
 /**
- * \brief Parse GSA packet from buffer.
- * @param buff a constant character pointer of packet buffer.
- * @param buff_sz buffer size.
- * @param pack a pointer of packet which will filled by function.
- * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ * Validate north/south or east/west and uppercase it.
+ * Expects:
+ * <pre>
+ *   c in { n, N, s, S } (for north/south)
+ *   c in { e, E, w, W } (for east/west)
+ * </pre>
+ *
+ * @param c a pointer to the character. The character will be converted to uppercase.
+ * @param ns true: evaluate north/south, false: evaluate east/west
+ * @return true when valid, false otherwise
  */
-int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack)
-{
-    assert(buff && pack);
-
-    memset(pack, 0, sizeof(nmeaGPGSA));
-
-    nmea_trace_buff(buff, buff_sz);
-
-    if(17 != nmea_scanf(buff, buff_sz,
-        "$GPGSA,%C,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%f*",
-        &(pack->fix_mode), &(pack->fix_type),
-        &(pack->sat_prn[0]), &(pack->sat_prn[1]), &(pack->sat_prn[2]), &(pack->sat_prn[3]), &(pack->sat_prn[4]), &(pack->sat_prn[5]),
-        &(pack->sat_prn[6]), &(pack->sat_prn[7]), &(pack->sat_prn[8]), &(pack->sat_prn[9]), &(pack->sat_prn[10]), &(pack->sat_prn[11]),
-        &(pack->PDOP), &(pack->HDOP), &(pack->VDOP)))
-    {
-        nmea_error("GPGSA parse error!");
-        return 0;
-    }
-
-    return 1;
+static bool validateNSEW(char * c, const bool ns) {
+       if (!c) {
+               return false;
+       }
+
+       *c = toupper(*c);
+
+       if (ns) {
+               if (!((*c == 'N') || (*c == 'S'))) {
+                       nmea_error("Parse error: invalid north/south (%c)", *c);
+                       return false;
+               }
+       } else {
+               if (!((*c == 'E') || (*c == 'W'))) {
+                       nmea_error("Parse error: invalid east/west (%c)", *c);
+                       return false;
+               }
+       }
+
+       return true;
 }
 
 /**
- * \brief Parse GSV packet from buffer.
- * @param buff a constant character pointer of packet buffer.
- * @param buff_sz buffer size.
- * @param pack a pointer of packet which will filled by function.
- * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ * Validate mode and uppercase it.
+ * Expects:
+ * <pre>
+ *   c in { a, A, d, D, e, E, n, N, s, S }
+ * </pre>
+ *
+ * @param c a pointer to the character. The character will be converted to uppercase.
+ * @return true when valid, false otherwise
  */
-int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack)
-{
-    int nsen, nsat;
-
-    assert(buff && pack);
-
-    memset(pack, 0, sizeof(nmeaGPGSV));
-
-    nmea_trace_buff(buff, buff_sz);
-
-    nsen = nmea_scanf(buff, buff_sz,
-        "$GPGSV,%d,%d,%d,"
-        "%d,%d,%d,%d,"
-        "%d,%d,%d,%d,"
-        "%d,%d,%d,%d,"
-        "%d,%d,%d,%d*",
-        &(pack->pack_count), &(pack->pack_index), &(pack->sat_count),
-        &(pack->sat_data[0].id), &(pack->sat_data[0].elv), &(pack->sat_data[0].azimuth), &(pack->sat_data[0].sig),
-        &(pack->sat_data[1].id), &(pack->sat_data[1].elv), &(pack->sat_data[1].azimuth), &(pack->sat_data[1].sig),
-        &(pack->sat_data[2].id), &(pack->sat_data[2].elv), &(pack->sat_data[2].azimuth), &(pack->sat_data[2].sig),
-        &(pack->sat_data[3].id), &(pack->sat_data[3].elv), &(pack->sat_data[3].azimuth), &(pack->sat_data[3].sig));
-
-    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
-    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
-    nsat = nsat * 4 + 3 /* first three sentence`s */;
-
-    if(nsen < nsat || nsen > (NMEA_SATINPACK * 4 + 3))
-    {
-        nmea_error("GPGSV parse error!");
-        return 0;
-    }
-
-    return 1;
+static bool validateMode(char * c) {
+       if (!c) {
+               return false;
+       }
+
+       *c = toupper(*c);
+
+       if (!((*c == 'A') || (*c == 'D') || (*c == 'E') || (*c == 'N') || (*c == 'S'))) {
+               nmea_error("Parse error: invalid mode (%c)", *c);
+               return false;
+       }
+
+       return true;
 }
 
 /**
- * \brief Parse RMC packet from buffer.
- * @param buff a constant character pointer of packet buffer.
- * @param buff_sz buffer size.
- * @param pack a pointer of packet which will filled by function.
- * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ * Determine whether the given string contains characters that are not allowed
+ * for fields in an NMEA string.
+ *
+ * @param str
+ * The string to check
+ * @param strlen
+ * The length of the string to check
+ * @param strName
+ * The name of the string to report when invalid characters are encountered
+ * @param report
+ * A pointer to a buffer in which to place the report string when an invalid
+ * nmea character is detected
+ * @param reportSize
+ * The size of the report buffer
+ *
+ * @return
+ * - true when the string has invalid characters
+ * - false otherwise
  */
-int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack)
-{
-    int nsen;
-    char time_buff[NMEA_TIMEPARSE_BUF];
-
-    assert(buff && pack);
-
-    memset(pack, 0, sizeof(nmeaGPRMC));
-
-    nmea_trace_buff(buff, buff_sz);
-
-    nsen = nmea_scanf(buff, buff_sz,
-        "$GPRMC,%s,%C,%f,%C,%f,%C,%f,%f,%2d%2d%2d,%f,%C,%C*",
-        &(time_buff[0]),
-        &(pack->status), &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
-        &(pack->speed), &(pack->direction),
-        &(pack->utc.day), &(pack->utc.mon), &(pack->utc.year),
-        &(pack->declination), &(pack->declin_ew), &(pack->mode));
-
-    if(nsen != 13 && nsen != 14)
-    {
-        nmea_error("GPRMC parse error!");
-        return 0;
-    }
-
-    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
-    {
-        nmea_error("GPRMC time parse error!");
-        return 0;
-    }
-
-    if(pack->utc.year < 90)
-        pack->utc.year += 100;
-    pack->utc.mon -= 1;
-
-    return 1;
+bool nmea_parse_sentence_has_invalid_chars(const char * str, const size_t strlen, const char * strName, char * report,
+               const size_t reportSize) {
+       static const char invalidChars[] = { '$', '*', ',', '!', '\\', '^', '~' };
+       static const char * invalidCharsNames[] = { "sentence delimiter ($)", "checksum field delimiter (*)", "comma (,)",
+                       "exclamation mark (!)", "backslash (\\)", "power (^)", "tilde (~)" };
+
+       size_t i;
+       size_t j;
+
+       if (!str || !strlen) {
+               return false;
+       }
+
+       for (i = 0; i < strlen; i++) {
+               char c = str[i];
+
+               if (!((c >= 32) && (c <= 126))) {
+                       if (report && reportSize) {
+                               snprintf(report, reportSize, "Configured %s (%s),"
+                                               " character %lu, can not contain non-printable"
+                                               " characters (codes outside the range [32, 126])", strName, str, (unsigned long) i + 1);
+                       }
+                       return true;
+               }
+
+               for (j = 0; j < sizeof(invalidChars); j++) {
+                       if (c == invalidChars[j]) {
+                               if (report && reportSize) {
+                                       snprintf(report, reportSize, "Configured %s (%s),"
+                                                       " character %lu, can not contain %s characters", strName, str, (unsigned long) i + 1,
+                                                       invalidCharsNames[j]);
+                               }
+                               return true;
+                       }
+               }
+       }
+
+       return false;
 }
 
 /**
- * \brief Parse VTG packet from buffer.
- * @param buff a constant character pointer of packet buffer.
- * @param buff_sz buffer size.
- * @param pack a pointer of packet which will filled by function.
- * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ * Determine sentence type (see nmeaPACKTYPE) by the header of a string.
+ * The header is the start of an NMEA sentence, right after the $.
+ *
+ * @param s the string. must be the NMEA string, right after the initial $
+ * @param len the length of the string
+ * @return The packet type (or GPNON when it could not be determined)
  */
-int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack)
-{
-    assert(buff && pack);
-
-    memset(pack, 0, sizeof(nmeaGPVTG));
-
-    nmea_trace_buff(buff, buff_sz);
-
-    if(8 != nmea_scanf(buff, buff_sz,
-        "$GPVTG,%f,%C,%f,%C,%f,%C,%f,%C*",
-        &(pack->dir), &(pack->dir_t),
-        &(pack->dec), &(pack->dec_m),
-        &(pack->spn), &(pack->spn_n),
-        &(pack->spk), &(pack->spk_k)))
-    {
-        nmea_error("GPVTG parse error!");
-        return 0;
-    }
-
-    if( pack->dir_t != 'T' ||
-        pack->dec_m != 'M' ||
-        pack->spn_n != 'N' ||
-        pack->spk_k != 'K')
-    {
-        nmea_error("GPVTG parse error (format error)!");
-        return 0;
-    }
-
-    return 1;
+int nmea_parse_get_sentence_type(const char *s, const int len) {
+       static const char *pheads[] = { "GPGGA", "GPGSA", "GPGSV", "GPRMC", "GPVTG" };
+       static const int types[] = { GPGGA, GPGSA, GPGSV, GPRMC, GPVTG };
+       unsigned int i;
+
+       assert(s);
+
+       if (len < 5)
+               return GPNON;
+
+       for (i = 0; i < (sizeof(types) / sizeof(int)); i++) {
+               if (!memcmp(s, pheads[i], 5)) {
+                       return types[i];
+               }
+       }
+
+       return GPNON;
 }
 
 /**
- * \brief Fill nmeaINFO structure by GGA packet data.
- * @param pack a pointer of packet structure.
- * @param info a pointer of summary information structure.
+ * Find the tail ("\r\n") of a sentence in a string and check the checksum of the sentence.
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param checksum a pointer to the location where the checksum (as specified
+ * in the sentence) should be stored (will be -1 if the checksum did not match
+ * the calculated checksum or a new sentence was found in s after the start of s)
+ * @return Number of bytes from the start of the string until the tail or 0
+ * when no sentence was found
  */
-void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info)
-{
-    assert(pack && info);
-
-    info->utc.hour = pack->utc.hour;
-    info->utc.min = pack->utc.min;
-    info->utc.sec = pack->utc.sec;
-    info->utc.hsec = pack->utc.hsec;
-    info->sig = pack->sig;
-    info->HDOP = pack->HDOP;
-    info->elv = pack->elv;
-    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
-    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
-    info->smask |= GPGGA;
+int nmea_parse_get_sentence_length(const char *s, const int len, int *checksum) {
+       static const int tail_sz = 1 + 2 + 2 /* *xx\r\n */;
+
+       const char * s_end = s + len;
+       int nread = 0;
+       int cksum = 0;
+
+       assert(s);
+       assert(checksum);
+
+       *checksum = -1;
+
+       for (; s < s_end; s++, nread++) {
+               if ((*s == '$') && nread) {
+                       /* found a new sentence start marker _after_ the first character of s */
+                       s = NULL; /* do not reset nread when exiting */
+                       break;
+               }
+               if ('*' == *s) {
+                       /* found a sentence checksum marker */
+                       if (((s + tail_sz) <= s_end) && ('\r' == s[3]) && ('\n' == s[4])) {
+                               *checksum = nmea_atoi(s + 1, 2, 16);
+                               nread = len - (int) (s_end - (s + tail_sz));
+                               if (*checksum != cksum) {
+                                       *checksum = -1;
+                                       s = NULL; /* do not reset nread when exiting */
+                               }
+                       }
+                       break;
+               }
+               if (nread) {
+                       cksum ^= (int) *s;
+               }
+       }
+
+       if (s && (*checksum < 0))
+               nread = 0;
+
+       return nread;
 }
 
 /**
- * \brief Fill nmeaINFO structure by GSA packet data.
- * @param pack a pointer of packet structure.
- * @param info a pointer of summary information structure.
+ * Parse a GPGGA sentence from a string
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param pack a pointer to the result structure
+ * @return 1 (true) - if parsed successfully or 0 (false) otherwise.
  */
-void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info)
-{
-    int i, j, nuse = 0;
-
-    assert(pack && info);
-
-    info->fix = pack->fix_type;
-    info->PDOP = pack->PDOP;
-    info->HDOP = pack->HDOP;
-    info->VDOP = pack->VDOP;
-
-    for(i = 0; i < NMEA_MAXSAT; ++i)
-    {
-        for(j = 0; j < info->satinfo.inview; ++j)
-        {
-            if(pack->sat_prn[i] && pack->sat_prn[i] == info->satinfo.sat[j].id)
-            {
-                info->satinfo.sat[j].in_use = 1;
-                nuse++;
-            }
-        }
-    }
-
-    info->satinfo.inuse = nuse;
-    info->smask |= GPGSA;
+int nmea_parse_GPGGA(const char *s, const int len, nmeaGPGGA *pack) {
+       int token_count;
+       char time_buff[NMEA_TIMEPARSE_BUF];
+       size_t time_buff_len = 0;
+
+       assert(s);
+       assert(pack);
+
+       nmea_trace_buff(s, len);
+
+       /*
+        * Clear before parsing, to be able to detect absent fields
+        */
+       time_buff[0] = '\0';
+       pack->present = 0;
+       pack->utc.hour = -1;
+       pack->utc.min = -1;
+       pack->utc.sec = -1;
+       pack->utc.hsec = -1;
+       pack->lat = NAN;
+       pack->ns = 0;
+       pack->lon = NAN;
+       pack->ew = 0;
+       pack->sig = -1;
+       pack->satinuse = -1;
+       pack->HDOP = NAN;
+       pack->elv = NAN;
+       pack->elv_units = 0;
+       pack->diff = 0;                 /* ignored */
+       pack->diff_units = 0;   /* ignored */
+       pack->dgps_age = 0;             /* ignored */
+       pack->dgps_sid = 0;             /* ignored */
+
+       /* parse */
+       token_count = nmea_scanf(s, len, "$GPGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*", &time_buff[0], &pack->lat,
+                       &pack->ns, &pack->lon, &pack->ew, &pack->sig, &pack->satinuse, &pack->HDOP, &pack->elv, &pack->elv_units,
+                       &pack->diff, &pack->diff_units, &pack->dgps_age, &pack->dgps_sid);
+
+       /* see that we have enough tokens */
+       if (token_count != 14) {
+               nmea_error("GPGGA parse error: need 14 tokens, got %d in %s", token_count, s);
+               return 0;
+       }
+
+       /* determine which fields are present and validate them */
+
+       time_buff_len = strlen(&time_buff[0]);
+       if (time_buff_len > (NMEA_TIMEPARSE_BUF - 1))
+               time_buff_len = NMEA_TIMEPARSE_BUF - 1;
+       if (time_buff_len) {
+               if (!_nmea_parse_time(&time_buff[0], time_buff_len, &pack->utc)) {
+                       return 0;
+               }
+
+               if (!validateTime(&pack->utc)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, UTCTIME);
+       }
+       if (!isnan(pack->lat) && (pack->ns)) {
+               if (!validateNSEW(&pack->ns, true)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, LAT);
+       }
+       if (!isnan(pack->lon) && (pack->ew)) {
+               if (!validateNSEW(&pack->ew, false)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, LON);
+       }
+       if (pack->sig != -1) {
+               if (!((pack->sig >= 0) && (pack->sig <= 8))) {
+                       nmea_error("GPGGA parse error: invalid signal %d, expected [0, 8]", pack->sig);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, SIG);
+       }
+       if (pack->satinuse != -1) {
+               nmea_INFO_set_present(&pack->present, SATINUSECOUNT);
+       }
+       if (!isnan(pack->HDOP)) {
+               nmea_INFO_set_present(&pack->present, HDOP);
+       }
+       if (!isnan(pack->elv) && (pack->elv_units)) {
+               if (pack->elv_units != 'M') {
+                       nmea_error("GPGGA parse error: invalid elevation unit (%c)", pack->elv_units);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, ELV);
+       }
+       /* ignore diff and diff_units */
+       /* ignore dgps_age and dgps_sid */
+
+       return 1;
 }
 
 /**
- * \brief Fill nmeaINFO structure by GSV packet data.
- * @param pack a pointer of packet structure.
- * @param info a pointer of summary information structure.
+ * Parse a GPGSA sentence from a string
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param pack a pointer to the result structure
+ * @return 1 (true) - if parsed successfully or 0 (false) otherwise.
  */
-void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info)
-{
-    int isat, isi, nsat;
-
-    assert(pack && info);
-
-    if(pack->pack_index > pack->pack_count ||
-        pack->pack_index * NMEA_SATINPACK > NMEA_MAXSAT)
-        return;
-
-    if(pack->pack_index < 1)
-        pack->pack_index = 1;
-
-    info->satinfo.inview = pack->sat_count;
-
-    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
-    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
-
-    for(isat = 0; isat < nsat; ++isat)
-    {
-        isi = (pack->pack_index - 1) * NMEA_SATINPACK + isat;
-        info->satinfo.sat[isi].id = pack->sat_data[isat].id;
-        info->satinfo.sat[isi].elv = pack->sat_data[isat].elv;
-        info->satinfo.sat[isi].azimuth = pack->sat_data[isat].azimuth;
-        info->satinfo.sat[isi].sig = pack->sat_data[isat].sig;
-    }
+int nmea_parse_GPGSA(const char *s, const int len, nmeaGPGSA *pack) {
+       int token_count;
+       int i;
+
+       assert(s);
+       assert(pack);
+
+       nmea_trace_buff(s, len);
+
+       /*
+        * Clear before parsing, to be able to detect absent fields
+        */
+       pack->present = 0;
+       pack->fix_mode = 0;
+       pack->fix_type = -1;
+       for (i = 0; i < NMEA_MAXSAT; i++) {
+               pack->sat_prn[i] = 0;
+       }
+       pack->PDOP = NAN;
+       pack->HDOP = NAN;
+       pack->VDOP = NAN;
+
+       /* parse */
+       token_count = nmea_scanf(s, len, "$GPGSA,%C,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%f*", &pack->fix_mode,
+                       &pack->fix_type, &pack->sat_prn[0], &pack->sat_prn[1], &pack->sat_prn[2], &pack->sat_prn[3],
+                       &pack->sat_prn[4], &pack->sat_prn[5], &pack->sat_prn[6], &pack->sat_prn[7], &pack->sat_prn[8],
+                       &pack->sat_prn[9], &pack->sat_prn[10], &pack->sat_prn[11], &pack->PDOP, &pack->HDOP, &pack->VDOP);
+
+       /* see that we have enough tokens */
+       if (token_count != 17) {
+               nmea_error("GPGSA parse error: need 17 tokens, got %d in %s", token_count, s);
+               return 0;
+       }
+
+       /* determine which fields are present and validate them */
+
+       pack->fix_mode = toupper(pack->fix_mode);
+       if (!((pack->fix_mode == 'A') || (pack->fix_mode == 'M'))) {
+               nmea_error("GPGSA parse error: invalid fix mode (%c)", pack->fix_mode);
+               return 0;
+       }
+       if (pack->fix_type != -1) {
+               if (!((pack->fix_type >= 1) && (pack->fix_type <= 3))) {
+                       nmea_error("GPGSA parse error: invalid fix type %d, expected [1, 3]", pack->fix_type);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, FIX);
+       }
+       for (i = 0; i < NMEA_MAXSAT; i++) {
+               if (pack->sat_prn[i] != 0) {
+                       nmea_INFO_set_present(&pack->present, SATINUSE);
+                       break;
+               }
+       }
+       if (!isnan(pack->PDOP)) {
+               nmea_INFO_set_present(&pack->present, PDOP);
+       }
+       if (!isnan(pack->HDOP)) {
+               nmea_INFO_set_present(&pack->present, HDOP);
+       }
+       if (!isnan(pack->VDOP)) {
+               nmea_INFO_set_present(&pack->present, VDOP);
+       }
+
+       return 1;
+}
 
-    info->smask |= GPGSV;
+/**
+ * Parse a GPGSV sentence from a string
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param pack a pointer to the result structure
+ * @return 1 (true) - if parsed successfully or 0 (false) otherwise.
+ */
+int nmea_parse_GPGSV(const char *s, const int len, nmeaGPGSV *pack) {
+       int token_count;
+       int token_count_expected;
+       int sat_count;
+       int sat_counted = 0;
+
+       assert(s);
+       assert(pack);
+
+       nmea_trace_buff(s, len);
+
+       /*
+        * Clear before parsing, to be able to detect absent fields
+        */
+       memset(pack, 0, sizeof(nmeaGPGSV));
+
+       /* parse */
+       token_count = nmea_scanf(s, len, "$GPGSV,%d,%d,%d,"
+                       "%d,%d,%d,%d,"
+                       "%d,%d,%d,%d,"
+                       "%d,%d,%d,%d,"
+                       "%d,%d,%d,%d*", &pack->pack_count, &pack->pack_index, &pack->sat_count, &pack->sat_data[0].id,
+                       &pack->sat_data[0].elv, &pack->sat_data[0].azimuth, &pack->sat_data[0].sig, &pack->sat_data[1].id,
+                       &pack->sat_data[1].elv, &pack->sat_data[1].azimuth, &pack->sat_data[1].sig, &pack->sat_data[2].id,
+                       &pack->sat_data[2].elv, &pack->sat_data[2].azimuth, &pack->sat_data[2].sig, &pack->sat_data[3].id,
+                       &pack->sat_data[3].elv, &pack->sat_data[3].azimuth, &pack->sat_data[3].sig);
+
+       /* return if we have no sentences or sats */
+       if ((pack->pack_count < 1) || (pack->pack_count > NMEA_NSATPACKS) || (pack->pack_index < 1)
+                       || (pack->pack_index > pack->pack_count) || (pack->sat_count < 0) || (pack->sat_count > NMEA_MAXSAT)) {
+               nmea_error("GPGSV parse error: inconsistent pack (count/index/satcount = %d/%d/%d)", pack->pack_count,
+                               pack->pack_index, pack->sat_count);
+               return 0;
+       }
+
+       /* validate all sat settings and count the number of sats in the sentence */
+       for (sat_count = 0; sat_count < NMEA_SATINPACK; sat_count++) {
+               if (pack->sat_data[sat_count].id != 0) {
+                       if ((pack->sat_data[sat_count].id < 0)) {
+                               nmea_error("GPGSV parse error: invalid sat %d id (%d)", sat_count + 1, pack->sat_data[sat_count].id);
+                               return 0;
+                       }
+                       if ((pack->sat_data[sat_count].elv < 0) || (pack->sat_data[sat_count].elv > 90)) {
+                               nmea_error("GPGSV parse error: invalid sat %d elevation (%d)", sat_count + 1, pack->sat_data[sat_count].elv);
+                               return 0;
+                       }
+                       if ((pack->sat_data[sat_count].azimuth < 0) || (pack->sat_data[sat_count].azimuth >= 360)) {
+                               nmea_error("GPGSV parse error: invalid sat %d azimuth (%d)", sat_count + 1, pack->sat_data[sat_count].azimuth);
+                               return 0;
+                       }
+                       if ((pack->sat_data[sat_count].sig < 0) || (pack->sat_data[sat_count].sig > 99)) {
+                               nmea_error("GPGSV parse error: invalid sat %d signal (%d)", sat_count + 1, pack->sat_data[sat_count].sig);
+                               return 0;
+                       }
+                       sat_counted++;
+               }
+       }
+
+       /* see that we have enough tokens */
+       token_count_expected = (sat_counted * 4) + 3;
+       if ((token_count < token_count_expected) || (token_count > (NMEA_SATINPACK * 4 + 3))) {
+               nmea_error("GPGSV parse error: need %d tokens, got %d", token_count_expected, token_count);
+               return 0;
+       }
+
+       /* determine which fields are present and validate them */
+
+       if (pack->sat_count > 0) {
+               nmea_INFO_set_present(&pack->present, SATINVIEW);
+       }
+
+       return 1;
 }
 
 /**
- * \brief Fill nmeaINFO structure by RMC packet data.
- * @param pack a pointer of packet structure.
- * @param info a pointer of summary information structure.
+ * Parse a GPRMC sentence from a string
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param pack a pointer to the result structure
+ * @return 1 (true) - if parsed successfully or 0 (false) otherwise.
  */
-void nmea_GPRMC2info(nmeaGPRMC *pack, nmeaINFO *info)
-{
-    assert(pack && info);
-
-    if('A' == pack->status)
-    {
-        if(NMEA_SIG_BAD == info->sig)
-            info->sig = NMEA_SIG_MID;
-        if(NMEA_FIX_BAD == info->fix)
-            info->fix = NMEA_FIX_2D;
-    }
-    else if('V' == pack->status)
-    {
-        info->sig = NMEA_SIG_BAD;
-        info->fix = NMEA_FIX_BAD;
-    }
-
-    info->utc = pack->utc;
-    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
-    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
-    info->speed = pack->speed * NMEA_TUD_KNOTS;
-    info->direction = pack->direction;
-    info->smask |= GPRMC;
+int nmea_parse_GPRMC(const char *s, const int len, nmeaGPRMC *pack) {
+       int token_count;
+       char time_buff[NMEA_TIMEPARSE_BUF];
+       size_t time_buff_len = 0;
+
+       assert(s);
+       assert(pack);
+
+       nmea_trace_buff(s, len);
+
+       /*
+        * Clear before parsing, to be able to detect absent fields
+        */
+       time_buff[0] = '\0';
+       pack->present = 0;
+       pack->utc.year = -1;
+       pack->utc.mon = -1;
+       pack->utc.day = -1;
+       pack->utc.hour = -1;
+       pack->utc.min = -1;
+       pack->utc.sec = -1;
+       pack->utc.hsec = -1;
+       pack->status = 0;
+       pack->lat = NAN;
+       pack->ns = 0;
+       pack->lon = NAN;
+       pack->ew = 0;
+       pack->speed = NAN;
+       pack->track = NAN;
+       pack->magvar = NAN;
+       pack->magvar_ew = 0;
+       pack->mode = 0;
+
+       /* parse */
+       token_count = nmea_scanf(s, len, "$GPRMC,%s,%C,%f,%C,%f,%C,%f,%f,%2d%2d%2d,%f,%C,%C*", &time_buff[0], &pack->status,
+                       &pack->lat, &pack->ns, &pack->lon, &pack->ew, &pack->speed, &pack->track, &pack->utc.day, &pack->utc.mon,
+                       &pack->utc.year, &pack->magvar, &pack->magvar_ew, &pack->mode);
+
+       /* see that we have enough tokens */
+       if ((token_count != 13) && (token_count != 14)) {
+               nmea_error("GPRMC parse error: need 13 or 14 tokens, got %d in %s", token_count, s);
+               return 0;
+       }
+
+       /* determine which fields are present and validate them */
+
+       if ((pack->utc.year != -1) && (pack->utc.mon != -1) && (pack->utc.day != -1)) {
+               if (pack->utc.year < 90) {
+                       pack->utc.year += 100;
+               }
+               pack->utc.mon -= 1;
+
+               if (!validateDate(&pack->utc)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, UTCDATE);
+       }
+
+       time_buff_len = strlen(&time_buff[0]);
+       if (time_buff_len) {
+               if (!_nmea_parse_time(&time_buff[0], time_buff_len, &pack->utc)) {
+                       return 0;
+               }
+
+               if (!validateTime(&pack->utc)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, UTCTIME);
+       }
+
+       if (!pack->status) {
+               pack->status = 'V';
+       } else {
+               pack->status = toupper(pack->status);
+               if (!((pack->status == 'A') || (pack->status == 'V'))) {
+                       nmea_error("GPRMC parse error: invalid status (%c)", pack->status);
+                       return 0;
+               }
+       }
+       if (!isnan(pack->lat) && (pack->ns)) {
+               if (!validateNSEW(&pack->ns, true)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, LAT);
+       }
+       if (!isnan(pack->lon) && (pack->ew)) {
+               if (!validateNSEW(&pack->ew, false)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, LON);
+       }
+       if (!isnan(pack->speed)) {
+               nmea_INFO_set_present(&pack->present, SPEED);
+       }
+       if (!isnan(pack->track)) {
+               nmea_INFO_set_present(&pack->present, TRACK);
+       }
+       if (!isnan(pack->magvar) && (pack->magvar_ew)) {
+               if (!validateNSEW(&pack->magvar_ew, false)) {
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, MAGVAR);
+       }
+       if (token_count == 13) {
+               pack->mode = 'A';
+       } else {
+               if (!pack->mode) {
+                       pack->mode = 'N';
+               } else {
+                       if (!validateMode(&pack->mode)) {
+                               return 0;
+                       }
+               }
+       }
+
+       return 1;
 }
 
 /**
- * \brief Fill nmeaINFO structure by VTG packet data.
- * @param pack a pointer of packet structure.
- * @param info a pointer of summary information structure.
+ * Parse a GPVTG sentence from a string
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param pack a pointer to the result structure
+ * @return 1 (true) - if parsed successfully or 0 (false) otherwise.
  */
-void nmea_GPVTG2info(nmeaGPVTG *pack, nmeaINFO *info)
-{
-    assert(pack && info);
-
-    info->direction = pack->dir;
-    info->declination = pack->dec;
-    info->speed = pack->spk;
-    info->smask |= GPVTG;
+int nmea_parse_GPVTG(const char *s, const int len, nmeaGPVTG *pack) {
+       int token_count;
+
+       assert(s);
+       assert(pack);
+
+       nmea_trace_buff(s, len);
+
+       /*
+        * Clear before parsing, to be able to detect absent fields
+        */
+       pack->present = 0;
+       pack->track = NAN;
+       pack->track_t = 0;
+       pack->mtrack = NAN;
+       pack->mtrack_m = 0;
+       pack->spn = NAN;
+       pack->spn_n = 0;
+       pack->spk = NAN;
+       pack->spk_k = 0;
+
+       /* parse */
+       token_count = nmea_scanf(s, len, "$GPVTG,%f,%C,%f,%C,%f,%C,%f,%C*", &pack->track, &pack->track_t, &pack->mtrack,
+                       &pack->mtrack_m, &pack->spn, &pack->spn_n, &pack->spk, &pack->spk_k);
+
+       /* see that we have enough tokens */
+       if (token_count != 8) {
+               nmea_error("GPVTG parse error: need 8 tokens, got %d in %s", token_count, s);
+               return 0;
+       }
+
+       /* determine which fields are present and validate them */
+
+       if (!isnan(pack->track) && (pack->track_t)) {
+               pack->track_t = toupper(pack->track_t);
+               if (pack->track_t != 'T') {
+                       nmea_error("GPVTG parse error: invalid track unit, got %C, expected T", pack->track_t);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, TRACK);
+       }
+       if (!isnan(pack->mtrack) && (pack->mtrack_m)) {
+               pack->mtrack_m = toupper(pack->mtrack_m);
+               if (pack->mtrack_m != 'M') {
+                       nmea_error("GPVTG parse error: invalid mtrack unit, got %C, expected M", pack->mtrack_m);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, MTRACK);
+       }
+       if (!isnan(pack->spn) && (pack->spn_n)) {
+               pack->spn_n = toupper(pack->spn_n);
+               if (pack->spn_n != 'N') {
+                       nmea_error("GPVTG parse error: invalid knots speed unit, got %C, expected N", pack->spn_n);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, SPEED);
+
+               if (isnan(pack->spk)) {
+                       pack->spk = pack->spn * NMEA_TUD_KNOTS;
+                       pack->spk_k = 'K';
+               }
+       }
+       if (!isnan(pack->spk) && (pack->spk_k)) {
+               pack->spk_k = toupper(pack->spk_k);
+               if (pack->spk_k != 'K') {
+                       nmea_error("GPVTG parse error: invalid kph speed unit, got %C, expected K", pack->spk_k);
+                       return 0;
+               }
+
+               nmea_INFO_set_present(&pack->present, SPEED);
+
+               if (isnan(pack->spn)) {
+                       pack->spn = pack->spk / NMEA_TUD_KNOTS;
+                       pack->spn_n = 'N';
+               }
+       }
+
+       return 1;
 }
index 5770dae..6e82aeb 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/**
- * \file parser.h
- */
-
 #include <nmea/parser.h>
 
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <assert.h>
-
 #include <nmea/context.h>
 #include <nmea/parse.h>
 #include <nmea/sentence.h>
+#include <nmea/conversions.h>
 
-typedef struct _nmeaParserNODE
-{
-    int packType;
-    void *pack;
-    struct _nmeaParserNODE *next_node;
-
-} nmeaParserNODE;
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
 
 /*
  * high level
  */
 
 /**
- * \brief Initialization of parser object
+ * Initialise the parser.
+ * Allocates a buffer.
+ *
+ * @param parser a pointer to the parser
  * @return true (1) - success or false (0) - fail
  */
-int nmea_parser_init(nmeaPARSER *parser)
-{
-    int resv = 0;
-    int buff_size = nmea_property()->parse_buff_size;
-
-    assert(parser);
+int nmea_parser_init(nmeaPARSER *parser) {
+       int resv = 0;
+       int buff_size = nmea_context_get_buffer_size();
 
-    if(buff_size < NMEA_MIN_PARSEBUFF)
-        buff_size = NMEA_MIN_PARSEBUFF;
+       assert(parser);
 
-    memset(parser, 0, sizeof(nmeaPARSER));
+       memset(parser, 0, sizeof(nmeaPARSER));
 
-    if(0 == (parser->buffer = malloc(buff_size)))
-        nmea_error("Insufficient memory!");
-    else
-    {
-        parser->buff_size = buff_size;
-        resv = 1;
-    }    
+       if (!(parser->buffer = malloc(buff_size)))
+               nmea_error("nmea_parser_init: insufficient memory");
+       else {
+               parser->buff_size = buff_size;
+               resv = 1;
+       }
 
-    return resv;
+       return resv;
 }
 
 /**
- * \brief Destroy parser object
+ * Destroy the parser.
+ * Frees a buffer.
+ *
+ * @param parser a pointer to the parser
  */
-void nmea_parser_destroy(nmeaPARSER *parser)
-{
-    assert(parser);
-    if (parser->buffer) {
-       free(parser->buffer);
-       parser->buffer = NULL;
-    }
-    nmea_parser_queue_clear(parser);
-    memset(parser, 0, sizeof(nmeaPARSER));
+void nmea_parser_destroy(nmeaPARSER *parser) {
+       assert(parser);
+
+       if (parser->buffer) {
+               free(parser->buffer);
+               parser->buffer = NULL;
+       }
+       nmea_parser_queue_clear(parser);
+       memset(parser, 0, sizeof(nmeaPARSER));
 }
 
 /**
- * \brief Analysis of buffer and put results to information structure
- * @return Number of packets wos parsed
+ * Parse a string and store the results in the nmeaINFO structure
+ *
+ * @param parser a pointer to the parser
+ * @param s the string
+ * @param len the length of the string
+ * @param info a pointer to the nmeaINFO structure
+ * @return the number of packets that were parsed
  */
-int nmea_parse(    
-    nmeaPARSER *parser,
-    const char *buff, int buff_sz,
-    nmeaINFO *info
-    )
-{
-    int ptype, nread = 0;
-    void *pack = 0;
-
-    assert(parser && parser->buffer);
-
-    nmea_parser_push(parser, buff, buff_sz);
-
-    while(GPNON != (ptype = nmea_parser_pop(parser, &pack)))
-    {
-        nread++;
-
-        switch(ptype)
-        {
-        case GPGGA:
-            nmea_GPGGA2info((nmeaGPGGA *)pack, info);
-            break;
-        case GPGSA:
-            nmea_GPGSA2info((nmeaGPGSA *)pack, info);
-            break;
-        case GPGSV:
-            nmea_GPGSV2info((nmeaGPGSV *)pack, info);
-            break;
-        case GPRMC:
-            nmea_GPRMC2info((nmeaGPRMC *)pack, info);
-            break;
-        case GPVTG:
-            nmea_GPVTG2info((nmeaGPVTG *)pack, info);
-            break;
-        default:
-            break;
-        };
-
-        free(pack);
-    }
-
-    return nread;
+int nmea_parse(nmeaPARSER *parser, const char *s, const int len, nmeaINFO *info) {
+       int packetType;
+       int packetsParsed = 0;
+       void *packet = 0;
+
+       assert(parser);
+
+       nmea_parser_push(parser, s, len);
+
+       while (GPNON != (packetType = nmea_parser_pop(parser, &packet))) {
+               packetsParsed++;
+
+               switch (packetType) {
+               case GPGGA:
+                       nmea_GPGGA2info((nmeaGPGGA *) packet, info);
+                       break;
+               case GPGSA:
+                       nmea_GPGSA2info((nmeaGPGSA *) packet, info);
+                       break;
+               case GPGSV:
+                       nmea_GPGSV2info((nmeaGPGSV *) packet, info);
+                       break;
+               case GPRMC:
+                       nmea_GPRMC2info((nmeaGPRMC *) packet, info);
+                       break;
+               case GPVTG:
+                       nmea_GPVTG2info((nmeaGPVTG *) packet, info);
+                       break;
+               default:
+                       break;
+               };
+
+               free(packet);
+       }
+
+       return packetsParsed;
 }
 
 /*
  * low level
  */
 
-static int nmea_parser_real_push(nmeaPARSER *parser, const char *buff, int buff_sz)
-{
-    int nparsed = 0, crc, sen_sz, ptype;
-    nmeaParserNODE *node = 0;
-
-    assert(parser && parser->buffer);
-
-    /* clear unuse buffer (for debug) */
-    /*
-    memset(
-        parser->buffer + parser->buff_use, 0,
-        parser->buff_size - parser->buff_use
-        );
-        */
-
-    /* add */
-    if(parser->buff_use + buff_sz >= parser->buff_size)
-        nmea_parser_buff_clear(parser);
-
-    memcpy(parser->buffer + parser->buff_use, buff, buff_sz);
-    parser->buff_use += buff_sz;
-
-    /* parse */
-    for(;;node = 0)
-    {
-        sen_sz = nmea_find_tail(
-            (const char *)parser->buffer + nparsed,
-            (int)parser->buff_use - nparsed, &crc);
-
-        if(!sen_sz)
-        {
-            if(nparsed)
-                memcpy(
-                parser->buffer,
-                parser->buffer + nparsed,
-                parser->buff_use -= nparsed);
-            break;
-        }
-        else if(crc >= 0)
-        {
-            ptype = nmea_pack_type(
-                (const char *)parser->buffer + nparsed + 1,
-                parser->buff_use - nparsed - 1);
-
-            if(0 == (node = malloc(sizeof(nmeaParserNODE))))
-                goto mem_fail;
-
-            node->pack = 0;
-
-            switch(ptype)
-            {
-            case GPGGA:
-                if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
-                    goto mem_fail;
-                node->packType = GPGGA;
-                if(!nmea_parse_GPGGA(
-                    (const char *)parser->buffer + nparsed,
-                    sen_sz, (nmeaGPGGA *)node->pack))
-                {
-                    free(node->pack);
-                    free(node);
-                    node = 0;
-                }
-                break;
-            case GPGSA:
-                if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
-                    goto mem_fail;
-                node->packType = GPGSA;
-                if(!nmea_parse_GPGSA(
-                    (const char *)parser->buffer + nparsed,
-                    sen_sz, (nmeaGPGSA *)node->pack))
-                {
-                    free(node->pack);
-                    free(node);
-                    node = 0;
-                }
-                break;
-            case GPGSV:
-                if(0 == (node->pack = malloc(sizeof(nmeaGPGSV))))
-                    goto mem_fail;
-                node->packType = GPGSV;
-                if(!nmea_parse_GPGSV(
-                    (const char *)parser->buffer + nparsed,
-                    sen_sz, (nmeaGPGSV *)node->pack))
-                {
-                    free(node->pack);
-                    free(node);
-                    node = 0;
-                }
-                break;
-            case GPRMC:
-                if(0 == (node->pack = malloc(sizeof(nmeaGPRMC))))
-                    goto mem_fail;
-                node->packType = GPRMC;
-                if(!nmea_parse_GPRMC(
-                    (const char *)parser->buffer + nparsed,
-                    sen_sz, (nmeaGPRMC *)node->pack))
-                {
-                    free(node->pack);
-                    free(node);
-                    node = 0;
-                }
-                break;
-            case GPVTG:
-                if(0 == (node->pack = malloc(sizeof(nmeaGPVTG))))
-                    goto mem_fail;
-                node->packType = GPVTG;
-                if(!nmea_parse_GPVTG(
-                    (const char *)parser->buffer + nparsed,
-                    sen_sz, (nmeaGPVTG *)node->pack))
-                {
-                    free(node->pack);
-                    free(node);
-                    node = 0;
-                }
-                break;
-            default:
-                free(node);
-                node = 0;
-                break;
-            };
-
-            if(node)
-            {
-                if(parser->end_node)
-                    ((nmeaParserNODE *)parser->end_node)->next_node = node;
-                parser->end_node = node;
-                if(!parser->top_node)
-                    parser->top_node = node;
-                node->next_node = 0;
-            }
-        }
-
-        nparsed += sen_sz;
-    }
-
-    return nparsed;
-
-mem_fail:
-    if(node)
-        free(node);
-
-    nmea_error("Insufficient memory!");
-
-    return -1;
+/**
+ * Do the actual parsing of a string and store the results in the parser.
+ * This function is used to parse (broken up parts) of a complete string.
+ *
+ * @param parser a pointer to the parser
+ * @param s the string
+ * @param len the length of the string
+ * @return the number of bytes that were parsed, -1 on error
+ */
+static int nmea_parser_real_push(nmeaPARSER *parser, const char *s, int len) {
+       int charsParsed = 0;
+       int crc;
+       int sentenceLength;
+       int sentenceType;
+       nmeaParserNODE *node = NULL;
+
+       assert(parser);
+       assert(parser->buffer);
+
+       if (!s || !len)
+               return 0;
+
+       /* clear the buffer if the string is too large */
+       if ((parser->buff_use + len) >= parser->buff_size)
+               nmea_parser_buff_clear(parser);
+
+       /* check that the string will fit in the buffer */
+       if ((parser->buff_use + len) >= parser->buff_size) {
+               nmea_error("nmea_parser_real_push: string too long to fit in parser buffer");
+               return 0;
+       }
+
+       /* put the string in the buffer */
+       memcpy(parser->buffer + parser->buff_use, s, len);
+       parser->buff_use += len;
+
+       /* parse */
+       for (;; node = NULL) {
+               sentenceLength = nmea_parse_get_sentence_length(parser->buffer + charsParsed, parser->buff_use - charsParsed,
+                               &crc);
+
+               if (!sentenceLength) {
+                       if (charsParsed)
+                               memmove(parser->buffer, parser->buffer + charsParsed, parser->buff_use -= charsParsed);
+                       break;
+               } else if (crc >= 0) {
+                       sentenceType = nmea_parse_get_sentence_type(parser->buffer + charsParsed + 1,
+                                       parser->buff_use - charsParsed - 1);
+
+                       if (!(node = malloc(sizeof(nmeaParserNODE))))
+                               goto mem_fail;
+
+                       node->pack = NULL;
+
+                       switch (sentenceType) {
+                       case GPGGA:
+                               if (!(node->pack = malloc(sizeof(nmeaGPGGA))))
+                                       goto mem_fail;
+                               node->packType = GPGGA;
+                               if (!nmea_parse_GPGGA(parser->buffer + charsParsed, sentenceLength, (nmeaGPGGA *) node->pack)) {
+                                       free(node->pack);
+                                       free(node);
+                                       node = NULL;
+                               }
+                               break;
+                       case GPGSA:
+                               if (!(node->pack = malloc(sizeof(nmeaGPGSA))))
+                                       goto mem_fail;
+                               node->packType = GPGSA;
+                               if (!nmea_parse_GPGSA(parser->buffer + charsParsed, sentenceLength, (nmeaGPGSA *) node->pack)) {
+                                       free(node->pack);
+                                       free(node);
+                                       node = NULL;
+                               }
+                               break;
+                       case GPGSV:
+                               if (!(node->pack = malloc(sizeof(nmeaGPGSV))))
+                                       goto mem_fail;
+                               node->packType = GPGSV;
+                               if (!nmea_parse_GPGSV(parser->buffer + charsParsed, sentenceLength, (nmeaGPGSV *) node->pack)) {
+                                       free(node->pack);
+                                       free(node);
+                                       node = NULL;
+                               }
+                               break;
+                       case GPRMC:
+                               if (!(node->pack = malloc(sizeof(nmeaGPRMC))))
+                                       goto mem_fail;
+                               node->packType = GPRMC;
+                               if (!nmea_parse_GPRMC(parser->buffer + charsParsed, sentenceLength, (nmeaGPRMC *) node->pack)) {
+                                       free(node->pack);
+                                       free(node);
+                                       node = NULL;
+                               }
+                               break;
+                       case GPVTG:
+                               if (!(node->pack = malloc(sizeof(nmeaGPVTG))))
+                                       goto mem_fail;
+                               node->packType = GPVTG;
+                               if (!nmea_parse_GPVTG(parser->buffer + charsParsed, sentenceLength, (nmeaGPVTG *) node->pack)) {
+                                       free(node->pack);
+                                       free(node);
+                                       node = NULL;
+                               }
+                               break;
+                       default:
+                               free(node);
+                               node = NULL;
+                               break;
+                       };
+
+                       if (node) {
+                               if (parser->end_node)
+                                       parser->end_node->next_node = node;
+                               parser->end_node = node;
+                               if (!parser->top_node)
+                                       parser->top_node = node;
+                               node->next_node = NULL;
+                       }
+               }
+
+               charsParsed += sentenceLength;
+       }
+
+       return charsParsed;
+
+       mem_fail: if (node)
+               free(node);
+       nmea_error("Insufficient memory!");
+
+       return -1;
 }
 
 /**
- * \brief Analysis of buffer and keep results into parser
- * @return Number of bytes wos parsed from buffer
+ * Parse a string and store the results in the parser
+ *
+ * @param parser a pointer to the parser
+ * @param s the string
+ * @param len the length of the string
+ * @return the number of bytes that were parsed
  */
-int nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz)
-{
-    int nparse, nparsed = 0;
+int nmea_parser_push(nmeaPARSER *parser, const char *s, int len) {
+       int charsParsed = 0;
+
+       assert(parser);
 
-    do
-    {
-        if(buff_sz > parser->buff_size)
-            nparse = parser->buff_size;
-        else
-            nparse = buff_sz;
+       if (!s || !len)
+               return 0;
 
-        nparsed += nmea_parser_real_push(
-            parser, buff, nparse);
+       do {
+               int charsToParse;
 
-        buff_sz -= nparse;
+               if (len > parser->buff_size)
+                       charsToParse = parser->buff_size;
+               else
+                       charsToParse = len;
 
-    } while(buff_sz);
+               charsParsed += nmea_parser_real_push(parser, s, charsToParse);
+               len -= charsToParse;
+       } while (len);
 
-    return nparsed;
+       return charsParsed;
 }
 
 /**
- * \brief Get type of top packet keeped into parser
- * @return Type of packet
- * @see nmeaPACKTYPE
+ * Get the type of top packet
+ *
+ * @param parser a pointer to the parser
+ * @return the type of the top packet (see nmeaPACKTYPE)
  */
-int nmea_parser_top(nmeaPARSER *parser)
-{
-    int retval = GPNON;
-    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+int nmea_parser_top(const nmeaPARSER *parser) {
+       int retval = GPNON;
+       nmeaParserNODE *node;
 
-    assert(parser && parser->buffer);
+       assert(parser);
 
-    if(node)
-        retval = node->packType;
+       node = parser->top_node;
+       if (node)
+               retval = node->packType;
 
-    return retval;
+       return retval;
 }
 
 /**
- * \brief Withdraw top packet from parser
- * @return Received packet type
- * @see nmeaPACKTYPE
+ * Remove the top packet from the parser
+ *
+ * @param parser a pointer to the parser
+ * @param pack_ptr a pointer to the location where to store a pointer to the packet
+ * @return the type of the top packet (see nmeaPACKTYPE)
  */
-int nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr)
-{
-    int retval = GPNON;
-    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
-
-    assert(parser && parser->buffer);
-
-    if(node)
-    {
-        *pack_ptr = node->pack;
-        retval = node->packType;
-        parser->top_node = node->next_node;
-        if(!parser->top_node)
-            parser->end_node = 0;
-        free(node);
-    }
-
-    return retval;
+int nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr) {
+       int retval = GPNON;
+       nmeaParserNODE *node;
+
+       assert(parser);
+
+       node = parser->top_node;
+       if (node) {
+               retval = node->packType;
+               if (pack_ptr)
+                       *pack_ptr = node->pack;
+               parser->top_node = node->next_node;
+               if (!parser->top_node)
+                       parser->end_node = 0;
+               free(node);
+       }
+
+       return retval;
 }
 
 /**
- * \brief Get top packet from parser without withdraw
- * @return Received packet type
- * @see nmeaPACKTYPE
+ * Get the top packet from the parser without removing it
+ *
+ * @param parser a pointer to the parser
+ * @param pack_ptr a pointer to the location where to store a pointer to the packet
+ * @return the type of the top packet (see nmeaPACKTYPE)
  */
-int nmea_parser_peek(nmeaPARSER *parser, void **pack_ptr)
-{
-    int retval = GPNON;
-    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+int nmea_parser_peek(const nmeaPARSER *parser, void **pack_ptr) {
+       int retval = GPNON;
+       nmeaParserNODE *node;
 
-    assert(parser && parser->buffer);
+       assert(parser);
 
-    if(node)
-    {
-        *pack_ptr = node->pack;
-        retval = node->packType;
-    }
+       node = parser->top_node;
+       if (node) {
+               retval = node->packType;
+               if (pack_ptr)
+                       *pack_ptr = node->pack;
+       }
 
-    return retval;
+       return retval;
 }
 
 /**
- * \brief Delete top packet from parser
- * @return Deleted packet type
- * @see nmeaPACKTYPE
+ * Remove the top packet from the parser
+ *
+ * @param parser a pointer to the parser
+ * @return the type of the removed packet (see nmeaPACKTYPE)
  */
-int nmea_parser_drop(nmeaPARSER *parser)
-{
-    int retval = GPNON;
-    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
-
-    assert(parser && parser->buffer);
-
-    if(node)
-    {
-        if(node->pack)
-            free(node->pack);
-        retval = node->packType;
-        parser->top_node = node->next_node;
-        if(!parser->top_node)
-            parser->end_node = 0;
-        free(node);
-    }
-
-    return retval;
+int nmea_parser_drop(nmeaPARSER *parser) {
+       int retval = GPNON;
+       nmeaParserNODE *node;
+
+       assert(parser);
+
+       node = parser->top_node;
+       if (node) {
+               retval = node->packType;
+               if (node->pack)
+                       free(node->pack);
+               parser->top_node = node->next_node;
+               if (!parser->top_node)
+                       parser->end_node = NULL;
+               free(node);
+       }
+
+       return retval;
 }
 
 /**
- * \brief Clear cache of parser
- * @return true (1) - success
+ * Clear the cache of the parser
+ *
+ * @param parser a pointer to the parser
  */
-int nmea_parser_buff_clear(nmeaPARSER *parser)
-{
-    assert(parser && parser->buffer);
-    parser->buff_use = 0;
-    return 1;
+void nmea_parser_buff_clear(nmeaPARSER *parser) {
+       assert(parser);
+       parser->buff_use = 0;
 }
 
 /**
- * \brief Clear packets queue into parser
- * @return true (1) - success
+ * Clear the packets queue in the parser
+ *
+ * @param parser a pointer to the parser
  */
-int nmea_parser_queue_clear(nmeaPARSER *parser)
-{
-    assert(parser);
-    while(parser->top_node)
-        nmea_parser_drop(parser);
-    return 1;
+void nmea_parser_queue_clear(nmeaPARSER *parser) {
+       assert(parser);
+       while (parser->top_node)
+               nmea_parser_drop(parser);
 }
index cf98c72..cbc4d4d 100644 (file)
 
 #include <string.h>
 
-void nmea_zero_GPGGA(nmeaGPGGA *pack)
-{
-    memset(pack, 0, sizeof(nmeaGPGGA));
-    nmea_time_now(&pack->utc);
-    pack->ns = 'N';
-    pack->ew = 'E';
-    pack->elv_units = 'M';
-    pack->diff_units = 'M';
+void nmea_zero_GPGGA(nmeaGPGGA *pack) {
+       memset(pack, 0, sizeof(nmeaGPGGA));
+       nmea_time_now(&pack->utc, &pack->present);
+       pack->ns = 'N';
+       pack->ew = 'E';
+       pack->elv_units = 'M';
+       pack->diff_units = 'M';
 }
 
-void nmea_zero_GPGSA(nmeaGPGSA *pack)
-{
-    memset(pack, 0, sizeof(nmeaGPGSA));
-    pack->fix_mode = 'A';
-    pack->fix_type = NMEA_FIX_BAD;
+void nmea_zero_GPGSA(nmeaGPGSA *pack) {
+       memset(pack, 0, sizeof(nmeaGPGSA));
+       pack->fix_mode = 'A';
+       pack->fix_type = NMEA_FIX_BAD;
 }
 
-void nmea_zero_GPGSV(nmeaGPGSV *pack)
-{
-    memset(pack, 0, sizeof(nmeaGPGSV));
+void nmea_zero_GPGSV(nmeaGPGSV *pack) {
+       memset(pack, 0, sizeof(nmeaGPGSV));
 }
 
-void nmea_zero_GPRMC(nmeaGPRMC *pack)
-{
-    memset(pack, 0, sizeof(nmeaGPRMC));
-    nmea_time_now(&pack->utc);
-    pack->status = 'V';
-    pack->ns = 'N';
-    pack->ew = 'E';
-    pack->declin_ew = 'E';
+void nmea_zero_GPRMC(nmeaGPRMC *pack) {
+       memset(pack, 0, sizeof(nmeaGPRMC));
+       nmea_time_now(&pack->utc, &pack->present);
+       pack->status = 'V';
+       pack->ns = 'N';
+       pack->ew = 'E';
+       pack->magvar_ew = 'E';
+       pack->mode = 'N';
 }
 
-void nmea_zero_GPVTG(nmeaGPVTG *pack)
-{
-    memset(pack, 0, sizeof(nmeaGPVTG));
-    pack->dir_t = 'T';
-    pack->dec_m = 'M';
-    pack->spn_n = 'N';
-    pack->spk_k = 'K';
+void nmea_zero_GPVTG(nmeaGPVTG *pack) {
+       memset(pack, 0, sizeof(nmeaGPVTG));
+       pack->track_t = 'T';
+       pack->mtrack_m = 'M';
+       pack->spn_n = 'N';
+       pack->spk_k = 'K';
 }
diff --git a/lib/pud/nmealib/src/time.c b/lib/pud/nmealib/src/time.c
deleted file mode 100644 (file)
index 18d6be8..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * This file is part of nmealib.
- *
- * Copyright (c) 2008 Timur Sinitsyn
- * Copyright (c) 2011 Ferry Huberts
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <nmea/time.h>
-
-#include <stddef.h>
-#include <time.h>
-#include <sys/time.h>
-
-void nmea_time_now(nmeaTIME *stm) {
-       struct timeval tp;
-       struct tm tt;
-
-       gettimeofday(&tp, NULL);
-       gmtime_r(&tp.tv_sec, &tt);
-
-       stm->year = tt.tm_year;
-       stm->mon = tt.tm_mon;
-       stm->day = tt.tm_mday;
-       stm->hour = tt.tm_hour;
-       stm->min = tt.tm_min;
-       stm->sec = tt.tm_sec;
-       stm->hsec = (tp.tv_usec / 10000);
-}
index 7a39250..bfc6867 100644 (file)
@@ -18,8 +18,6 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*! \file tok.h */
-
 #include <nmea/tok.h>
 
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 
-#define NMEA_TOKS_COMPARE   (1)
-#define NMEA_TOKS_PERCENT   (2)
-#define NMEA_TOKS_WIDTH     (3)
-#define NMEA_TOKS_TYPE      (4)
+#define NMEA_TOKS_COMPARE   1
+#define NMEA_TOKS_PERCENT   2
+#define NMEA_TOKS_WIDTH     3
+#define NMEA_TOKS_TYPE      4
 
-#define NMEA_CONVSTR_BUF    (256)
+/** number conversion buffer size */
+#define NMEA_CONVSTR_BUF    64
 
 /**
- * \brief Calculate control sum of binary buffer
+ * Calculate crc control sum of a string
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @return the crc
  */
-int nmea_calc_crc(const char *buff, int buff_sz)
-{
-    int chsum = 0,
-        it;
+int nmea_calc_crc(const char *s, const int len) {
+       int chksum = 0;
+       int it;
 
-    for(it = 0; it < buff_sz; ++it)
-        chsum ^= (int)buff[it];
+       for (it = 0; it < len; it++)
+               chksum ^= (int) s[it];
 
-    return chsum;
+       return chksum;
 }
 
 /**
- * \brief Convert string to number
+ * Convert string to an integer
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param radix the radix of the numbers in the string
+ * @return the converted number, or 0 on failure
  */
-int nmea_atoi(const char *str, int str_sz, int radix)
-{
-    char *tmp_ptr;
-    char buff[NMEA_CONVSTR_BUF];
-    int res = 0;
-
-    if(str_sz < NMEA_CONVSTR_BUF)
-    {
-        memcpy(&buff[0], str, str_sz);
-        buff[str_sz] = '\0';
-        res = strtol(&buff[0], &tmp_ptr, radix);
-    }
-
-    return res;
+int nmea_atoi(const char *s, int len, int radix) {
+       char *tmp_ptr;
+       char buff[NMEA_CONVSTR_BUF];
+       long res = 0;
+
+       if (len < NMEA_CONVSTR_BUF) {
+               memcpy(&buff[0], s, len);
+               buff[len] = '\0';
+               res = strtol(&buff[0], &tmp_ptr, radix);
+       }
+
+       return (int) res;
 }
 
 /**
- * \brief Convert string to fraction number
+ * Convert string to a floating point number
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @return the converted number, or 0 on failure
  */
-double nmea_atof(const char *str, int str_sz)
-{
-    char *tmp_ptr;
-    char buff[NMEA_CONVSTR_BUF];
-    double res = 0;
-
-    if(str_sz < NMEA_CONVSTR_BUF)
-    {
-        memcpy(&buff[0], str, str_sz);
-        buff[str_sz] = '\0';
-        res = strtod(&buff[0], &tmp_ptr);
-    }
-
-    return res;
+double nmea_atof(const char *s, const int len) {
+       char *tmp_ptr;
+       char buff[NMEA_CONVSTR_BUF];
+       double res = 0;
+
+       if (len < NMEA_CONVSTR_BUF) {
+               memcpy(&buff[0], s, len);
+               buff[len] = '\0';
+               res = strtod(&buff[0], &tmp_ptr);
+       }
+
+       return res;
 }
 
 /**
- * \brief Formating string (like standart printf) with CRC tail (*CRC)
+ * Formating string (like standart printf) with CRC tail (*CRC)
+ *
+ * @param s the string buffer to printf into
+ * @param len the size of the string buffer
+ * @param format the string format to use
+ * @return the number of printed characters
  */
-int nmea_printf(char *buff, int buff_sz, const char *format, ...)
-{
-    int retval, add = 0;
-    va_list arg_ptr;
+int nmea_printf(char *s, int len, const char *format, ...) {
+       int retval;
+       int add = 0;
+       va_list arg_ptr;
 
-    if(buff_sz <= 0)
-        return 0;
+       if (len <= 0)
+               return 0;
 
-    va_start(arg_ptr, format);
+       va_start(arg_ptr, format);
 
-    retval = vsnprintf(buff, buff_sz, format, arg_ptr);
+       retval = vsnprintf(s, len, format, arg_ptr);
 
-    if(retval > 0)
-    {
-        add = snprintf(
-            buff + retval, buff_sz - retval, "*%02x\r\n",
-            nmea_calc_crc(buff + 1, retval - 1));
-    }
+       if (retval > 0) {
+               add = snprintf(s + retval, len - retval, "*%02x\r\n", nmea_calc_crc(s + 1, retval - 1));
+       }
 
-    retval += add;
+       retval += add;
 
-    if(retval < 0 || retval > buff_sz)
-    {
-        memset(buff, ' ', buff_sz);
-        retval = buff_sz;
-    }
+       if (retval < 0 || retval > len) {
+               memset(s, ' ', len);
+               retval = len;
+       }
 
-    va_end(arg_ptr);
+       va_end(arg_ptr);
 
-    return retval;
+       return retval;
 }
 
 /**
- * \brief Analyse string (specificate for NMEA sentences)
+ * Analyse a string (specific for NMEA sentences)
+ *
+ * @param s the string
+ * @param len the length of the string
+ * @param format the string format to use
+ * @return the number of scanned characters
  */
-int nmea_scanf(const char *buff, int buff_sz, const char *format, ...)
-{
-    const char *beg_tok;
-    const char *end_buf = buff + buff_sz;
-
-    va_list arg_ptr;
-    int tok_type = NMEA_TOKS_COMPARE;
-    int width = 0;
-    const char *beg_fmt = 0;
-    int snum = 0, unum = 0;
-
-    int tok_count = 0;
-    void *parg_target;
-
-    va_start(arg_ptr, format);
-    
-    for(; *format && buff < end_buf; ++format)
-    {
-        switch(tok_type)
-        {
-        case NMEA_TOKS_COMPARE:
-            if('%' == *format)
-                tok_type = NMEA_TOKS_PERCENT;
-            else if(*buff++ != *format)
-                goto fail;
-            break;
-        case NMEA_TOKS_PERCENT:
-            width = 0;
-            beg_fmt = format;
-            tok_type = NMEA_TOKS_WIDTH;
-            /* no break */
-        case NMEA_TOKS_WIDTH:
-            if(isdigit(*format))
-                break;
-            {
-                tok_type = NMEA_TOKS_TYPE;
-                if(format > beg_fmt)
-                    width = nmea_atoi(beg_fmt, (int)(format - beg_fmt), 10);
-            }
-            /* no break */
-        case NMEA_TOKS_TYPE:
-            beg_tok = buff;
-
-            if(!width && ('c' == *format || 'C' == *format) && *buff != format[1])
-                width = 1;
-
-            if(width)
-            {
-                if(buff + width <= end_buf)
-                    buff += width;
-                else
-                    goto fail;
-            }
-            else
-            {
-                if(!format[1] || (0 == (buff = (char *)memchr(buff, format[1], end_buf - buff))))
-                    buff = end_buf;
-            }
-
-            if(buff > end_buf)
-                goto fail;
-
-            tok_type = NMEA_TOKS_COMPARE;
-            tok_count++;
-
-            parg_target = 0; width = (int)(buff - beg_tok);
-
-            switch(*format)
-            {
-            case 'c':
-            case 'C':
-                parg_target = (void *)va_arg(arg_ptr, char *);
-                if(width && 0 != (parg_target))
-                    *((char *)parg_target) = *beg_tok;
-                break;
-            case 's':
-            case 'S':
-                parg_target = (void *)va_arg(arg_ptr, char *);
-                if(width && 0 != (parg_target))
-                {
-                    memcpy(parg_target, beg_tok, width);
-                    ((char *)parg_target)[width] = '\0';
-                }
-                break;
-            case 'f':
-            case 'g':
-            case 'G':
-            case 'e':
-            case 'E':
-                parg_target = (void *)va_arg(arg_ptr, double *);
-                if(width && 0 != (parg_target))
-                    *((double *)parg_target) = nmea_atof(beg_tok, width);
-                break;
-            default:
-                break;
-            };
-
-            if(parg_target)
-                break;
-            if(0 == (parg_target = (void *)va_arg(arg_ptr, int *)))
-                break;
-            if(!width)
-                break;
-
-            switch(*format)
-            {
-            case 'd':
-            case 'i':
-                snum = nmea_atoi(beg_tok, width, 10);
-                memcpy(parg_target, &snum, sizeof(int));
-                break;
-            case 'u':
-                unum = nmea_atoi(beg_tok, width, 10);
-                memcpy(parg_target, &unum, sizeof(unsigned int));
-                break;
-            case 'x':
-            case 'X':
-                unum = nmea_atoi(beg_tok, width, 16);
-                memcpy(parg_target, &unum, sizeof(unsigned int));
-                break;
-            case 'o':
-                unum = nmea_atoi(beg_tok, width, 8);
-                memcpy(parg_target, &unum, sizeof(unsign