Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • danc/MicroCART
  • snawerdt/MicroCART_17-18
  • bbartels/MicroCART_17-18
  • jonahu/MicroCART
4 results
Show changes
Showing
with 0 additions and 4772 deletions
html
latex
man
# Changes made by:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
include(DoxygenTargets)
#-----------------------------------------------------------------------------
# Create documentation
add_doxygen(Doxyfile
INSTALL_DESTINATION
share/doc/vrpn-${BRIEF_VERSION}/source-docs
NO_PDF
INSTALL_COMPONENT
doc) # For some reason, LaTeX bails with a nesting-too-deep error
# 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.
# For config item PROJECT_NAME, default is My Project
PROJECT_NAME = vrpn
# 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.
# For config item PROJECT_BRIEF, default is
PROJECT_BRIEF = "Virtual Reality Peripheral Network"
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
# For config item FULL_PATH_NAMES, default is 1
FULL_PATH_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.)
# For config item JAVADOC_AUTOBRIEF, default is 0
JAVADOC_AUTOBRIEF = YES
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
# interpret the first line (until the first dot) of a Qt-style
# comment as the brief description. If set to NO, the comments
# will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.)
# For config item QT_AUTOBRIEF, default is 0
QT_AUTOBRIEF = YES
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
# comments) as a brief description. This used to be the default behaviour.
# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
# For config item MULTILINE_CPP_IS_BRIEF, default is 0
MULTILINE_CPP_IS_BRIEF = 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 makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
# For config item BUILTIN_STL_SUPPORT, default is 0
BUILTIN_STL_SUPPORT = YES
# 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
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically
# be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
# For config item TYPEDEF_HIDES_STRUCT, default is 0
TYPEDEF_HIDES_STRUCT = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
# For config item EXTRACT_ALL, default is 0
EXTRACT_ALL = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
# For config item EXTRACT_LOCAL_CLASSES, default is 1
EXTRACT_LOCAL_CLASSES = NO
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
# For config item INPUT, default is
INPUT = ..
# If the value of the INPUT tag contains directories, you can use the
# 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++ *.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
# For config item FILE_PATTERNS, default is
FILE_PATTERNS = *.h \
*.C
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
# For config item SOURCE_BROWSER, default is 0
SOURCE_BROWSER = YES
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
# functions referencing it will be listed.
# For config item REFERENCED_BY_RELATION, default is 0
REFERENCED_BY_RELATION = YES
# If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities
# called/used by that function will be listed.
# For config item REFERENCES_RELATION, default is 0
REFERENCES_RELATION = YES
# 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
# containing a tree-like index structure (just like the one that
# 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.
# For config item GENERATE_TREEVIEW, default is 0
GENERATE_TREEVIEW = YES
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
# For config item PAPER_TYPE, default is a4
PAPER_TYPE = letter
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
# For config item GENERATE_MAN, default is 0
GENERATE_MAN = YES
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
# For config item PREDEFINED, default is
PREDEFINED = VRPN_USE_PHANTOM_SERVER \
VRPN_USE_DIRECTINPUT \
VRPN_USE_DIRECTSHOW \
VRPN_INCLUDE_INTERSENSE \
VRPN_USE_NATIONAL_INSTRUMENTS \
VRPN_USE_NATIONAL_INSTRUMENTS_MX \
VRPN_USE_USDIGITAL \
VRPN_USE_MICROSCRIBE \
VRPN_INCLUDE_PHASESPACE \
VRPN_USE_GPM_MOUSE \
VRPN_USE_MOTIONNODE \
VRPN_USE_WIIUSE \
VRPN_USE_FREESPACE \
VRPN_USE_TRIVISIOCOLIBRI \
VRPN_USE_HID \
VRPN_USE_LIBUSB_1_0
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
# For config item HAVE_DOT, default is 0
HAVE_DOT = YES
# If the CALL_GRAPH and HAVE_DOT options are set to YES then
# doxygen will generate a call dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
# For config item CALL_GRAPH, default is 0
CALL_GRAPH = YES
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
# For config item CALLER_GRAPH, default is 0
CALLER_GRAPH = NO
android_widgets/example_app/.classpath
android_widgets/example_app/default.properties
android_widgets/example_app/proguard.cfg
android_widgets/example_app/res/drawable-hdpi/icon.png
android_widgets/example_app/res/drawable-mdpi/icon.png
android_widgets/example_app/res/drawable-ldpi/icon.png
android_widgets/example_app/res/layout/main.xml
android_widgets/example_app/res/values/vrpn.xml
android_widgets/example_app/res/values/strings.xml
android_widgets/example_app/res/values/arrays.xml
android_widgets/example_app/src/test/app1/MainActivity.java
android_widgets/example_app/.project
android_widgets/example_app/AndroidManifest.xml
android_widgets/README.txt
android_widgets/vrpn_library/.classpath
android_widgets/vrpn_library/doc/allclasses-noframe.html
android_widgets/vrpn_library/doc/deprecated-list.html
android_widgets/vrpn_library/doc/allclasses-frame.html
android_widgets/vrpn_library/doc/help-doc.html
android_widgets/vrpn_library/doc/index.html
android_widgets/vrpn_library/doc/package-list
android_widgets/vrpn_library/doc/constant-values.html
android_widgets/vrpn_library/doc/stylesheet.css
android_widgets/vrpn_library/doc/index-files/index-1.html
android_widgets/vrpn_library/doc/index-files/index-4.html
android_widgets/vrpn_library/doc/index-files/index-3.html
android_widgets/vrpn_library/doc/index-files/index-2.html
android_widgets/vrpn_library/doc/index-files/index-5.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/package-frame.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnToggleButton.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/package-use.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnSpinner.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnToggleButton.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnSpinner.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnClient.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnApplication.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnSeekBar.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnPressButton.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnRadioButton.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/class-use/VrpnSurface.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnClient.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnApplication.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnSeekBar.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/package-summary.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/package-tree.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnPressButton.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnRadioButton.html
android_widgets/vrpn_library/doc/eu/ensam/ii/vrpn/VrpnSurface.html
android_widgets/vrpn_library/doc/overview-tree.html
android_widgets/vrpn_library/doc/resources/inherit.gif
android_widgets/vrpn_library/default.properties
android_widgets/vrpn_library/proguard.cfg
android_widgets/vrpn_library/res/drawable-hdpi/ic_menu_manage.png
android_widgets/vrpn_library/res/drawable-hdpi/ic_menu_rotate_right.png
android_widgets/vrpn_library/res/drawable-hdpi/ic_menu_rotate_left.png
android_widgets/vrpn_library/res/drawable-hdpi/ic_menu_preferences.png
android_widgets/vrpn_library/res/drawable-hdpi/ic_lock_silent_mode_vibrate.png
android_widgets/vrpn_library/res/drawable-hdpi/icon.png
android_widgets/vrpn_library/res/drawable-hdpi/ic_menu_refresh.png
android_widgets/vrpn_library/res/drawable-mdpi/ic_menu_rotate_right.png
android_widgets/vrpn_library/res/drawable-mdpi/ic_menu_rotate_left.png
android_widgets/vrpn_library/res/drawable-mdpi/ic_lock_silent_mode_vibrate.png
android_widgets/vrpn_library/res/drawable-mdpi/icon.png
android_widgets/vrpn_library/res/drawable-ldpi/icon.png
android_widgets/vrpn_library/res/layout/vrpn_seekbar.xml
android_widgets/vrpn_library/res/layout/tab_debug_sensors.xml
android_widgets/vrpn_library/res/values/strings.xml
android_widgets/vrpn_library/res/values/attrs.xml
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnSpinner.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnSeekBar.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/Quat.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnClient.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/package-info.html
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/Vec3f.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnPressButton.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/package-info.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnRadioButton.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnSurface.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnToggleButton.java
android_widgets/vrpn_library/src/eu/ensam/ii/vrpn/VrpnApplication.java
android_widgets/vrpn_library/.project
android_widgets/vrpn_library/AndroidManifest.xml
cmake/FindJsonCpp.cmake
gpsnmealib/typedCoord.h
gpsnmealib/utmCoord.h
gpsnmealib/gpsnmealib.vcproj
gpsnmealib/typedCoord.C
gpsnmealib/nmeaParser.h
gpsnmealib/latLonCoord.C
gpsnmealib/utmCoord.C
gpsnmealib/nmeaParser.C
gpsnmealib/.cvsignore
gpsnmealib/latLonCoord.h
server_src/vrpn.cfg
util/cleanupBeforeCommit.sh
vrpn_android/index_files/vrpn48.png
vrpn_android/cpp_doc.htm
vrpn_android/manuals/functionalspec.pdf
vrpn_android/manuals/designdoc.pdf
vrpn_android/manuals/manual.pdf
vrpn_android/comp523android/.classpath
vrpn_android/comp523android/default.properties
vrpn_android/comp523android/res/drawable-hdpi/icon.png
vrpn_android/comp523android/res/menu/controller_menu.xml
vrpn_android/comp523android/res/drawable-mdpi/icon.png
vrpn_android/comp523android/res/drawable/vrpn48.png
vrpn_android/comp523android/res/drawable/gradient.xml
vrpn_android/comp523android/res/drawable-ldpi/icon.png
vrpn_android/comp523android/res/layout/main.xml
vrpn_android/comp523android/res/values/strings.xml
vrpn_android/comp523android/jniInfo.txt
vrpn_android/comp523android/todo.txt
vrpn_android/comp523android/debugging.txt
vrpn_android/comp523android/src/edu/unc/cs/vrpn/VrpnSeekBarChangeListener.java
vrpn_android/comp523android/src/edu/unc/cs/vrpn/Main.java
vrpn_android/comp523android/src/edu/unc/cs/vrpn/JniBuilder.java
vrpn_android/comp523android/src/edu/unc/cs/vrpn/AccelerometerListener.java
vrpn_android/comp523android/src/edu/unc/cs/vrpn/ButtonListener.java
vrpn_android/comp523android/src/jni/JniLayer.java
vrpn_android/comp523android/.project
vrpn_android/comp523android/AndroidManifest.xml
vrpn_android/README.txt
vrpn_android/index.htm
vrpn_Qt_GUI_server/vrpn_Qt.h
vrpn_Qt_GUI_server/vrpn_Qt.C
vrpn_Qt_GUI_server/vrpn_Qt_AppExample/CMakeLists.txt
vrpn_Qt_GUI_server/vrpn_Qt_AppExample/vrpn_Qt_AppExample.cpp
vrpn_Qt_GUI_server/vrpn_Qt_AppExample/MainWindow.cpp
vrpn_Qt_GUI_server/vrpn_Qt_AppExample/MainWindow.h
vrpn_Qt_GUI_server/vrpn_Qt_AppExample/vrpn_Qt_AppExample.bat
vrpn_Qt_GUI_server/vrpn_Qt_AppExample/MainWindow.ui
vrpn_Qt_GUI_server/README.txt
vrpn_Qt_GUI_server/cmake/FindVRPN.cmake
vrpn_Qt_GUI_server/cmake/Findquatlib.cmake
vrpn_Qt_GUI_server/CMakeLists.txt
#!/bin/sh
function SourceFile()
{
cat <<EOS
<File
RelativePath="${1}"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
EOS
}
function HeaderFile()
{
cat <<EOS
<File
RelativePath="${1}"
>
</File>
EOS
}
function CleanFileList()
{
sort -f | grep --invert-match "Android" | grep --invert-match "Atmel"
}
function GenerateFilesSection()
{
cat << EOS
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
EOS
for src in $(ls vrpn_*.C vrpn_*.cpp | CleanFileList)
do
SourceFile $src
done
cat <<EOS
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
EOS
for header in $(ls vrpn_*.h | CleanFileList)
do
HeaderFile $header
done
cat <<EOS
</Filter>
</Files>
EOS
}
function GenerateVrpnVCPROJ()
{
cat <<'EOS'
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="vrpn"
ProjectGUID="{7EE1DB03-16A5-4465-9164-061BE0C88B8C}"
RootNamespace="vrpn"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory=".\pc_win32/Release"
IntermediateDirectory=".\pc_win32/Release"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="&quot;$(SYSTEMDRIVE)\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include&quot;;../dtrack;quat;../isense;../Dtrack;../libfreespace/include;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C Dev\include&quot;;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\Include&quot;;&quot;$(SYSTEMDRIVE)\sdk\cpp&quot;;&quot;$(SYSTEMDRIVE)\Program Files\boost\boost_1_34_1&quot;;./submodules/hidapi/hidapi;&quot;$(SYSTEMDRIVE)\Program Files\libusb-1.0\libusb&quot;"
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS,VRPNDLL_NOEXPORTS"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=".\pc_win32/Release/vrpn.pch"
AssemblerListingLocation=".\pc_win32/Release/"
ObjectFile=".\pc_win32/Release/"
ProgramDataBaseFileName=".\pc_win32/Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\pc_win32/Release\vrpn.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\pc_win32/Release/vrpn.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\pc_win32/Debug"
IntermediateDirectory=".\pc_win32/Debug"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SYSTEMDRIVE)\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include&quot;;../dtrack;quat;../isense;../Dtrack;../libfreespace/include;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C Dev\include&quot;;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\Include&quot;;&quot;$(SYSTEMDRIVE)\sdk\cpp&quot;;&quot;$(SYSTEMDRIVE)\Program Files\boost\boost_1_34_1&quot;;./submodules/hidapi/hidapi;&quot;$(SYSTEMDRIVE)\Program Files\libusb-1.0\libusb&quot;"
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS,VRPNDLL_NOEXPORTS"
RuntimeLibrary="3"
PrecompiledHeaderFile=".\pc_win32/Debug/vrpn.pch"
AssemblerListingLocation=".\pc_win32/Debug/"
ObjectFile=".\pc_win32/Debug/"
ProgramDataBaseFileName=".\pc_win32/Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\pc_win32/Debug\vrpn.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\pc_win32/Debug/vrpn.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
EOS
GenerateFilesSection
cat <<EOS
<Globals>
</Globals>
</VisualStudioProject>
EOS
}
function GenerateVrpnDLLVCPROJ()
{
cat <<'EOS'
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="vrpndll"
ProjectGUID="{5F38B32E-B5AE-4316-B15E-9E21D033B1BE}"
RootNamespace="vrpndll"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\pc_win32/DLL/Debug"
IntermediateDirectory=".\pc_win32/DLL/Debug"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\pc_win32/DLL/Debug/vrpndll.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SYSTEMDRIVE)\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include&quot;;quat;../isense;../Dtrack;../libfreespace/include;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C Dev\include&quot;;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\Include&quot;;&quot;$(SYSTEMDRIVE)\sdk\cpp&quot;;&quot;$(SYSTEMDRIVE)\Program Files\boost\boost_1_34_1&quot;;./submodules/hidapi/hidapi;&quot;$(SYSTEMDRIVE)\Program Files\libusb-1.0\libusb&quot;"
PreprocessorDefinitions="VRPNDLL_EXPORTS,_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
PrecompiledHeaderFile=".\pc_win32/DLL/Debug/vrpndll.pch"
AssemblerListingLocation=".\pc_win32/DLL/Debug/"
ObjectFile=".\pc_win32/DLL/Debug/"
ProgramDataBaseFileName=".\pc_win32/DLL/Debug/"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
IgnoreImportLibrary="true"
OutputFile=".\pc_win32/DLL/Debug/vrpndll.dll"
LinkIncremental="2"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="$(SYSTEMDRIVE)\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib,$(SYSTEMDRIVE)\sdk\cpp,$(SYSTEMDRIVE)\Program Files\boost\boost_1_34_1\lib"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\pc_win32/DLL/Debug/vrpndll.pdb"
ImportLibrary=".\pc_win32\DLL\Debug\vrpndll.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\pc_win32/DLL/Debug/vrpndll.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\pc_win32/DLL/Release"
IntermediateDirectory=".\pc_win32/DLL/Release"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\pc_win32/DLL/Release/vrpndll.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="&quot;$(SYSTEMDRIVE)\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include&quot;;quat;../isense;../Dtrack;../libfreespace/include;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\DAQmx ANSI C Dev\include&quot;;&quot;$(SYSTEMDRIVE)\Program Files\National Instruments\NI-DAQ\Include&quot;;&quot;$(SYSTEMDRIVE)\sdk\cpp&quot;;&quot;$(SYSTEMDRIVE)\Program Files\boost\boost_1_34_1&quot;;./submodules/hidapi/hidapi;&quot;$(SYSTEMDRIVE)\Program Files\libusb-1.0\libusb&quot;"
PreprocessorDefinitions="VRPNDLL_EXPORTS,_CRT_SECURE_NO_WARNINGS"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=".\pc_win32/DLL/Release/vrpndll.pch"
AssemblerListingLocation=".\pc_win32/DLL/Release/"
ObjectFile=".\pc_win32/DLL/Release/"
ProgramDataBaseFileName=".\pc_win32/DLL/Release/"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
IgnoreImportLibrary="true"
OutputFile=".\pc_win32/DLL/Release/vrpndll.dll"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="$(SYSTEMDRIVE)\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib,$(SYSTEMDRIVE)\sdk\cpp,$(SYSTEMDRIVE)\Program Files\boost\boost_1_34_1\lib"
ProgramDatabaseFile=".\pc_win32/DLL/Release/vrpndll.pdb"
ImportLibrary=".\pc_win32\DLL\Release\vrpndll.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\pc_win32/DLL/Release/vrpndll.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
EOS
GenerateFilesSection
cat <<EOS
<Globals>
</Globals>
</VisualStudioProject>
EOS
}
GenerateVrpnVCPROJ > vrpn.vcproj
dos2unix --u2d vrpn.vcproj
GenerateVrpnDLLVCPROJ > vrpndll.vcproj
dos2unix --u2d vrpndll.vcproj
# | sed 's|^\(.*\)$|<File RelativePath="\1"></File>|'
Debug
*.ncb
*.suo
if(WIN32)
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
endif()
set(GPSNMEALIB_PUBLIC_HEADERS
nmeaParser.h
utmCoord.h
latLonCoord.h)
set(GPSNMEALIB_SOURCES
latLonCoord.C
nmeaParser.C
typedCoord.h
typedCoord.C
utmCoord.C)
add_library(gpsnmea ${GPSNMEALIB_PUBLIC_HEADERS} ${GPSNMEALIB_SOURCES})
set_property(TARGET
gpsnmea
PROPERTY
PUBLIC_HEADER
${GPSNMEALIB_PUBLIC_HEADERS})
set_property(TARGET gpsnmea PROPERTY FOLDER "Library")
if(VRPN_INSTALL)
install(TARGETS
gpsnmea
ARCHIVE
DESTINATION
lib
COMPONENT
serversdk
PUBLIC_HEADER
DESTINATION
include
COMPONENT
serversdk)
endif()
\ No newline at end of file
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="gpsnmealib"
ProjectGUID="{D60E311B-657F-444E-9A0E-5218B37D5551}"
RootNamespace="gpsnmealib"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\latLonCoord.C"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\nmeaParser.C"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\typedCoord.C"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\utmCoord.C"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\latLonCoord.h"
>
</File>
<File
RelativePath=".\nmeaParser.h"
>
</File>
<File
RelativePath=".\typedCoord.h"
>
</File>
<File
RelativePath=".\utmCoord.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
// LatLonCoord.cpp: Implementation of the CLatLonCoord class.
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#include "gpsnmealib/typedCoord.h" // for TypedCoord
#include "latLonCoord.h"
#ifdef sgi
#include <assert.h>
#include <math.h>
#include <stdio.h>
#else
#include <cassert> // for assert
#include <cmath> // for fabs
#include <cstdio> // for sprintf
#endif
// Format strings for the degree-to-string conversion functions.
// Note that east/west (EW) has a different set of format strings as north/
// south (NS), as integer degrees in east/west can have up to three digits
// instead of two.
static const char formatD_NS[] = "%c %02d.%05d*";
static const char formatDM_NS[] = "%c %02d*%02d.%03d'";
static const char formatDMS_NS[] = "%c %02d*%02d'%02d.%01d\x22";
static const char formatD_EW[] = "%c %03d.%05d*";
static const char formatDM_EW[] = "%c %03d*%02d.%03d'";
static const char formatDMS_EW[] = "%c %03d*%02d'%02d.%01d\x22";
/////////////////////////////////////////////////////////////////////////////
// LatLonCoord construction/destruction
LatLonCoord::LatLonCoord (): TypedCoord ()
{
// Set the default output coordinate format to decimal degrees.
m_latLonFormat = FORMAT_D;
}
LatLonCoord::LatLonCoord (double lat, double lon)
{
m_lat = lat;
m_lon = lon;
// Set the default output coordinate format to decimal degrees.
m_latLonFormat = FORMAT_D;
}
LatLonCoord::LatLonCoord (const LatLonCoord& other)
{
copyLatLonCoord (other);
}
LatLonCoord::LatLonCoord (const TypedCoord& other)
{
m_latLonFormat = FORMAT_D;
copyOtherCoord (other);
}
/////////////////////////////////////////////////////////////////////////////
// LatLonCoord operators
LatLonCoord& LatLonCoord::operator= (const LatLonCoord& other)
{
copyLatLonCoord (other);
return *this;
}
LatLonCoord& LatLonCoord::operator= (const TypedCoord& other)
{
copyOtherCoord (other);
return *this;
}
/////////////////////////////////////////////////////////////////////////////
// LatLonCoord members
void LatLonCoord::copyLatLonCoord (const LatLonCoord& other)
// Purpose:
// This function copies the lat/lon coordinate of the specified object and
// assigns that coordinate to this object.
{
m_lat = other.m_lat;
m_lon = other.m_lon;
}
void LatLonCoord::copyOtherCoord (const TypedCoord& other)
// Purpose:
// This function copies the coordinate of the specified object, converts
// the coordinate to the coordinate type of this object, then assigns the
// converted coordinate to this object.
{
// Convert the right hand side coordinate to lat/lon; then store these
// lat/lon values in this coordinate.
other.getLatLonCoord (m_lat, m_lon);
}
const std::string& LatLonCoord::createCoordString(std::string& coordString) const
// Purpose:
// This function creates a formatted coordinate string containing this
// object's coordinate value.
// Parameters:
// std::string& coordString:
// Upon exit, this parameter will contain the generated coordinate
// string
// Returns:
// A reference to the generated coordinate string.
// Notes:
// The string can be in one of three different formats (degrees, degrees and
// decimal minutes, or degrees, minutes, and decimal seconds.) Set the
// format by calling the SetCurrentLatLonFormat() member function.
{
std::string latString;
std::string lonString;
// Create the formatted lat/lon strings; the format is specified by the
// m_currentLatLonFormat member variable
degreeToString (latString, m_lat, HEMISPHERE_NS);
degreeToString (lonString, m_lon, HEMISPHERE_EW);
coordString = latString + ", " + lonString;
return coordString;
}
void LatLonCoord::createDisplayStrings (std::string& topLeftString,
std::string& topRightString, std::string& bottomLeftString,
std::string& bottomRightString) const
// Purpose:
// This function creates four strings that can be used for display; these
// strings contain coordinate data. The four strings are for the top left,
// top right, bottom left, and bottom right text of a display; each string
// is specified as follows:
// - top left: North/south hemisphere character
// - top right: Latitude
// - bottom left: East/west hemisphere character
// - bottom right: Longitude
// Notes:
// It is up to the calling function to write these strings to the display.
{
std::string coordString;
createCoordString (coordString);
#if 0
// Extract the elements of the coordinate string.
switch (getLatLonFormat ()) {
case FORMAT_D:
topLeftString = coordString.Mid (LAT_D_HPPEMISPHERE_POS,
LAT_D_HPPEMISPHERE_LEN);
topRightString = coordString.Mid (LAT_D_DEGREE_POS,
LAT_D_DEGREE_LEN);
bottomLeftString = coordString.Mid (LON_D_HPPEMISPHERE_POS,
LON_D_HPPEMISPHERE_LEN);
bottomRightString = coordString.Mid (LON_D_DEGREE_POS,
LON_D_DEGREE_LEN);
break;
case FORMAT_DM:
topLeftString = coordString.Mid (LAT_DM_HPPEMISPHERE_POS,
LAT_DM_HPPEMISPHERE_LEN);
topRightString = coordString.Mid (LAT_DM_DEGREE_POS,
LAT_DM_DEGREE_LEN);
bottomLeftString = coordString.Mid (LON_DM_HPPEMISPHERE_POS,
LON_DM_HPPEMISPHERE_LEN);
bottomRightString = coordString.Mid (LON_DM_DEGREE_POS,
LON_DM_DEGREE_LEN);
break;
case FORMAT_DMS:
topLeftString = coordString.Mid (LAT_DMS_HPPEMISPHERE_POS,
LAT_DMS_HPPEMISPHERE_LEN);
topRightString = coordString.Mid (LAT_DMS_DEGREE_POS,
LAT_DMS_DEGREE_LEN);
bottomLeftString = coordString.Mid (LON_DMS_HPPEMISPHERE_POS,
LON_DMS_HPPEMISPHERE_LEN);
bottomRightString = coordString.Mid (LON_DMS_DEGREE_POS,
LON_DMS_DEGREE_LEN);
break;
default:
ASSERT (FALSE);
}
#endif
}
void LatLonCoord::createXYCoordStrings (std::string& xString, std::string& yString)
const
// Purpose:
// This function generates two strings: a string containing the longitude
// (stored in the parameter xString), and a string containing the latitude
// (stored in the parameter yString.)
// Notes:
// The string can be in one of three different formats (degrees, degrees and
// decimal minutes, or degrees, minutes, and decimal seconds); Set the
// format by calling the SetCurrentLatLonFormat() member function.
{
degreeToString (xString, m_lon, HEMISPHERE_EW);
degreeToString (yString, m_lat, HEMISPHERE_NS);
}
const std::string& LatLonCoord::degreeToD (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const
// Purpose:
// This function converts a value specified in decimal degrees to a string
// formatted as H DDD.DDDDD*.
// Pre:
// -180.0 <= degree <= 180.0
// Parameters:
// std::string& output:
// Upon exit, this parameter contains the converted string.
// double degree:
// The degree value to convert.
// HEMISPHERE_DIRECTION direction:
// The direction of the hemisphere, either north/south or east/west.
// This value determines the hemisphere character in the converted
// string.
// Returns:
// The converted string.
{
char hemisphereChar = getHemisphereChar (degree, direction);
double positiveDegrees = fabs (degree);
// A "unit" is measured in 1/100000ths of a degree; this is the smallest
// possible unit when coordinates are expressed as DDD.DDDDD.
// (Calculating the degree and the 1/100000th degree parts as integers
// avoid rounding errors in the final result.)
int units = (int)((positiveDegrees * 100000.0) + 0.5);
int intDegrees = units / 100000;
int int100ThousandthDegrees = units % 100000;
const char* pFormatString;
char tempString[1000];
if (direction == HEMISPHERE_NS) {
pFormatString = formatD_NS;
} else {
pFormatString = formatD_EW;
}
sprintf(tempString, pFormatString, hemisphereChar, intDegrees,
int100ThousandthDegrees);
output = tempString;
return output;
}
const std::string& LatLonCoord::degreeToDM (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const
// Purpose:
// Same as DegreeToD, except the string is formatted as H DDD*MM.MMM'.
// Pre:
// -180.0 <= degree <= 180.0
{
char hemisphereChar = getHemisphereChar (degree, direction);
double positiveDegrees = fabs (degree);
// A "unit" is measured in 1/1000ths of a minute (or 1/60000 of a degree);
// this is the smallest possible unit when coordinates are expressed as
// DDD MM.MMM. (Calculating the degree, minute, and the 1/1000th minute
// parts as integers avoid rounding errors in the final result.)
int units = (int)((positiveDegrees * 60000.0) + 0.5);
int intDegrees = units / 60000;
int intDegreesInUnits = intDegrees * 60000;
int intMinutes = (units - intDegreesInUnits) / 1000;
int intThousandthMinutes = (units - intDegreesInUnits) % 1000;
const char* pFormatString;
char tempString[1000];
if (direction == HEMISPHERE_NS) {
pFormatString = formatDM_NS;
} else {
pFormatString = formatDM_EW;
}
sprintf(tempString, pFormatString, hemisphereChar,
intDegrees, intMinutes, intThousandthMinutes);
output = tempString;
return output;
}
const std::string& LatLonCoord::degreeToDMS (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const
// Purpose:
// Same as DegreeToD, except the string is formatted as H DDD*MM'SS.S".
// Pre:
// -180.0 <= degree <= 180.0
{
char hemisphereChar = getHemisphereChar (degree, direction);
double positiveDegrees = fabs (degree);
// A "unit" is measured in 1/10ths of a second (or 1/36000 of a degree);
// this is the smallest possible unit when coordinates are expressed as
// DDD MM SS.S. (Calculating the degree, minute, second, and the 1/10th
// second parts as integers will avoid rounding errors in the final
// result.)
int units = (int)((positiveDegrees * 36000.0) + 0.5);
int intDegrees = units / 36000;
int intDegreesInUnits = intDegrees * 36000;
int intMinutes = (units - intDegreesInUnits) / 600;
int intMinutesInUnits = intMinutes * 600;
int intSeconds = (units - intDegreesInUnits - intMinutesInUnits) / 10;
int intTenthSeconds = (units - intDegreesInUnits - intMinutesInUnits) % 10;
const char* pFormatString;
char tempString[1000];
if (direction == HEMISPHERE_NS) {
pFormatString = formatDMS_NS;
} else {
pFormatString = formatDMS_EW;
}
sprintf(tempString, pFormatString, hemisphereChar,
intDegrees, intMinutes, intSeconds, intTenthSeconds);
output = tempString;
return output;
}
const std::string& LatLonCoord::degreeToString (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const
// Purpose:
// This function converts a value specified in decimal degrees to a formatted
// string.
// Pre:
// -180.0 <= degree <= 180.0
// Parameters:
// std::string& output:
// Upon exit, this parameter contains the converted string.
// double degree:
// The degree value to convert.
// HEMISPHERE_DIRECTION direction:
// The direction of the hemisphere, either north/south or east/west.
// This value determines the hemisphere character in the converted
// string.
// Returns:
// The converted string.
// Notes:
// If formatType is FORMAT_D, the returned string format is H DDD.DDDDD*.
// If formatType is FORMAT_DM, the returned string format is H DDD*MM.MMM'.
// If formatType is FORMAT_DMS, the returned string format is H DDD*MM'SS.S".
{
switch (m_latLonFormat) {
case FORMAT_DMS:
return degreeToDMS (output, degree, direction);
break;
case FORMAT_DM:
return degreeToDM (output, degree, direction);
break;
case FORMAT_D:
return degreeToD (output, degree, direction);
break;
default:
assert(false);
return output; // needed to stop compiler warning.
}
}
void LatLonCoord::getXYCoord (double& x, double& y) const
// Purpose:
// This function returns the (x, y) coordinate stored within this object.
// In this class, the x coordinate is the longitude and the y coordinate is
// the latitude.
{
x = m_lon;
y = m_lat;
}
char LatLonCoord::getHemisphereChar (double degree,
HEMISPHERE_DIRECTION direction) const
// Purpose:
// This function determine the appropriate hemisphere character ('N', 'S',
// 'E', 'W') given the degree value and the hemisphere direction (north/south
// or east/west).
// Returns:
// 'N' if direction is HEMISPHERE_NS and degree is positive.
// 'S' if direction is HEMISPHERE_NS and degree is negative.
// 'E' if direction is HEMISPHERE_EW and degree is positive.
// 'W' if direction is HEMISPHERE_EW and degree is negative.
{
if (direction == HEMISPHERE_NS) {
if (degree >= 0.0) {
return 'N';
} else {
return 'S';
}
} else {
if (degree >= 0.0) {
return 'E';
} else {
return 'W';
}
}
}
// LatLonCoord.h: Definition of the CLatLonCoord class.
//
// The CLatLonCoord class, derived from the CTypedCoord class, represents a
// lat/lon coordinate. Since this class contains an internal lat/lon
// coordinate from CTypedCoord, no conversion functions are necessary.
//
// The formatted coordinate string generated by the CreateCoordString() member
// function can be in one of the three following formats:
// - Degrees (H DD.DDDDD*, H DDD.DDDDD*); this is the default.
// - Degrees, and decimal minutes (H DD*MM.MMM'. H DDD* MM.MMM')
// - Degrees, minutes, and decimal seconds (H DD*MM'SS.S", H DDD*MM'SS.S")
//
// The coordinate string format is set by calling the SetCurrentLatLonFormat()
// member function.
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#ifndef __LAT_LON_CPPOORD_HPP
#define __LAT_LON_CPPOORD_HPP
#include <string> // for string
#include "typedCoord.h" // for COORD_TYPE, etc
enum HEMISPHERE_DIRECTION
{
HEMISPHERE_NS = 0,
HEMISPHERE_EW = 1
};
enum COORD_LATLON_FORMAT
{
FORMAT_D = 0,
FORMAT_DM = 1,
FORMAT_DMS = 2
};
// These constants are used by the CreateDisplayStrings() and the
// CreateXYCoordStrings() functions to parse the string generated by the
// CreateCoordString() function. Modify these constants when you modify the
// code that generates the string. These constants do not affect the code
// that generate these strings, but you may write parsing functions that
// require the positions of the individual elements in the strings.
const int LAT_D_HPPEMISPHERE_POS = 0;
const int LAT_D_HPPEMISPHERE_LEN = 1;
const int LON_D_HPPEMISPHERE_POS = 13;
const int LON_D_HPPEMISPHERE_LEN = 1;
const int LAT_D_DEGREE_POS = 2;
const int LAT_D_DEGREE_LEN = 9;
const int LON_D_DEGREE_POS = 15;
const int LON_D_DEGREE_LEN = 10;
const int LAT_DM_HPPEMISPHERE_POS = 0;
const int LAT_DM_HPPEMISPHERE_LEN = 1;
const int LON_DM_HPPEMISPHERE_POS = 14;
const int LON_DM_HPPEMISPHERE_LEN = 1;
const int LAT_DM_DEGREE_POS = 2;
const int LAT_DM_DEGREE_LEN = 10;
const int LON_DM_DEGREE_POS = 16;
const int LON_DM_DEGREE_LEN = 11;
const int LAT_DMS_HPPEMISPHERE_POS = 0;
const int LAT_DMS_HPPEMISPHERE_LEN = 1;
const int LON_DMS_HPPEMISPHERE_POS = 15;
const int LON_DMS_HPPEMISPHERE_LEN = 1;
const int LAT_DMS_DEGREE_POS = 2;
const int LAT_DMS_DEGREE_LEN = 11;
const int LON_DMS_DEGREE_POS = 17;
const int LON_DMS_DEGREE_LEN = 12;
const char DEGREE_CHAR = '*';
class LatLonCoord: public TypedCoord
{
public:
LatLonCoord ();
LatLonCoord (double lat, double lon);
LatLonCoord (const TypedCoord& other);
LatLonCoord (const LatLonCoord& other);
LatLonCoord& operator= (const LatLonCoord& other);
LatLonCoord& operator= (const TypedCoord& other);
void copyLatLonCoord (const LatLonCoord& other);
void copyOtherCoord (const TypedCoord& other);
virtual const std::string& createCoordString (std::string& coordString) const;
virtual void createDisplayStrings (std::string& topLeftString,
std::string& topRightString, std::string& bottomLeftString,
std::string& bottomRightString) const;
virtual void createXYCoordStrings (std::string& xString, std::string& yString)
const;
virtual COORD_TYPE getCoordType () const {return COORD_LATLON;}
COORD_LATLON_FORMAT getLatLonFormat () const
{return m_latLonFormat;}
virtual void getXYCoord (double& x, double& y) const;
void setLatLonFormat (COORD_LATLON_FORMAT latLonFormat)
{m_latLonFormat = latLonFormat;}
protected:
// Conversion functions for each of the three lat/lon formats.
const std::string& degreeToD (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const;
const std::string& degreeToDM (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const;
const std::string& degreeToDMS (std::string& output, double degree,
HEMISPHERE_DIRECTION direction) const;
const std::string& degreeToString (std::string& output, double degree,
HEMISPHERE_DIRECTION formatType) const;
char getHemisphereChar (double degree, HEMISPHERE_DIRECTION direction)
const;
// Current lat/lon format in one of three format types.
COORD_LATLON_FORMAT m_latLonFormat;
};
#endif
// NmeaParser.cpp: Implementation of the NMEA-0183 2.0 parser class.
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#ifdef sgi
#include <stdlib.h>
#include <string.h>
#else
#include <cstdlib> // for atof, atoi, atol
#endif
#include "nmeaParser.h"
// This constant define the length of the date string in a sentence.
const int DATE_LEN = 6;
/////////////////////////////////////////////////////////////////////////////
// NMEAData construction/destruction
NMEAData::NMEAData ()
{
// The constructor for the NMEAData object clears all data and resets the
// times of last acquisition to 0.
reset ();
// No coordinate has ever been valid since this object was created.
hasCoordEverBeenValid = false;
}
/////////////////////////////////////////////////////////////////////////////
// NMEAData methods
void NMEAData::reset()
// Purpose:
// This function resets all the data in this object to its defaults.
{
// Reset the data.
lat = 0.0;
lon = 0.0;
altitude = 0.0;
speed = 0.0;
UTCYear = 94;
UTCMonth = 6;
UTCDay = 1;
UTCHour = 0;
UTCMinute = 0;
UTCSecond = 0;
track = 0.0;
magVariation = 0.0;
hdop = 1.0;
eStd = 1.0;
nStd = 1.0;
numSats = 0;
// All data stored by this object is currently invalid.
isValidLat = false;
isValidLon = false;
isValidAltitude = false;
isValidSpeed = false;
isValidDate = false;
isValidTime = false;
isValidTrack = false;
isValidMagVariation = false;
isValidHdop = false;
isValidNStd = false;
isValidEStd = false;
isValidZStd = false;
isValidHStd = false;
isValidSatData = false;
isValidRangeResidualData = false;
isValidFixQuality = false;
// Last fix was invalid.
lastFixQuality = FIX_AUTONOMOUS;
// Still waiting for the frame to start...
waitingForStart = true;
// Clear what messages have been seen
seenZDA = false;
seenGGA = false;
seenGLL = false;
seenRMC = false;
seenGSV = false;
seenGST = false;
seenVTG = false;
seenRRE = false;
}
/////////////////////////////////////////////////////////////////////////////
// NMEAParser construction/destruction
NMEAParser::NMEAParser () //sj: log4cpp::Category& l) : logger(l)
{
m_data = new NMEAData();
// by default, we'll look for "RMC" message to signify a new sequence of messages
strcpy(startSentence, "RMC");
// Defaults for the GSV sentence parser.
m_lastSentenceNumber = 1;
m_numSentences = 1;
m_numSatsExpected = 0;
m_numSatsLeft = 0;
m_satArrayPos = 0;
}
NMEAParser::NMEAParser (NMEAData* data)//sj: log4cpp::Category& l, NMEAData* data) : logger(l)
{
m_data = data;
// Defaults for the GSV sentence parser.
m_lastSentenceNumber = 1;
m_numSentences = 1;
m_numSatsExpected = 0;
m_numSatsLeft = 0;
m_satArrayPos = 0;
}
NMEAParser::~NMEAParser ()
{
delete m_data;
m_data = 0;
}
void NMEAParser::parseZDA(const char* sentence)
{
m_data->seenZDA=true;
char field[255];
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Skip past the '$xxZDA'
if ((isMore = getNextField (field, sentence, currentPos)) == false)
{
return;
}
// UTC time.
isMore = getNextField (field, sentence, currentPos);
parseAndValidateTime (field);
}
void NMEAParser::parseGGA (const char* sentence)
// Purpose:
// This function parses a GGA sentence; all data will be stored in the
// NMEAData object within this class. This function will correctly parse
// a partial GGA sentence.
// Pre:
// The string to parse must be a valid GGA sentence.
{
m_data->seenGGA=true;
char field[255];
char hemisphereField[32];
char hemisphereChar;
char unitField[32];
char unitChar;
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Skip past the '$xxGGA'
if ((isMore = getNextField (field, sentence, currentPos)) == false)
{
return;
}
// UTC time.
isMore = getNextField (field, sentence, currentPos);
parseAndValidateTime (field);
if (isMore == false) return;
// Latitude.
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (hemisphereField, sentence, currentPos);
if (strlen (hemisphereField) != 0) {
hemisphereChar = hemisphereField[0];
} else {
hemisphereChar = ' ';
}
parseAndValidateLat (field, hemisphereChar);
if (isMore == false) return;
// Longitude.
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (hemisphereField, sentence, currentPos);
if (strlen (hemisphereField) != 0) {
hemisphereChar = hemisphereField[0];
} else {
hemisphereChar = ' ';
}
parseAndValidateLon (field, hemisphereChar);
if (isMore == false) return;
// Quality of GPS fix.
isMore = getNextField (field, sentence, currentPos);
parseAndValidateFixQuality (field);
if (isMore == false) return;
// Skip number of sats tracked for now.
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Horizontal dilution of precision (HDOP).
isMore = getNextField (field, sentence, currentPos);
parseAndValidateHdop (field);
if (isMore == false) return;
// Altitude.
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (unitField, sentence, currentPos);
if (strlen (unitField) != 0) {
unitChar = unitField[0];
} else {
unitChar = ' ';
}
parseAndValidateAltitude (field, unitChar);
if (isMore == false) return;
// Everything else (geoid height and DGPS info) is ignored for now.
return;
}
void NMEAParser::parseGLL (const char* sentence)
// Purpose:
// This function parses a GLL sentence; all data will be stored in the
// NMEAData object within this class. This function will correctly parse
// a partial GLL sentence.
// Pre:
// The string to parse must be a valid GLL sentence.
{
m_data->seenGLL=true;
char field[255];
char hemisphereField[32];
char hemisphereChar;
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Count commas in this sentence to see if it's valid.
if (countChars (sentence, ',', SENTENCE_GLL_COMMAS) < 0) return;
// Skip past the '$xxGLL'
if ((isMore = getNextField (field, sentence, currentPos)) == false) {
return;
}
// Latitude
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (hemisphereField, sentence, currentPos);
if (strlen (hemisphereField) != 0) {
hemisphereChar = hemisphereField[0];
} else {
hemisphereChar = ' ';
}
parseAndValidateLat (field, hemisphereChar);
if (isMore == false) return;
// Longitude
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (hemisphereField, sentence, currentPos);
if (strlen (hemisphereField) != 0) {
hemisphereChar = hemisphereField[0];
} else {
hemisphereChar = ' ';
}
parseAndValidateLon (field, hemisphereChar);
if (isMore == false) return;
// UTC time
isMore = getNextField (field, sentence, currentPos);
parseAndValidateTime (field);
if (isMore == false) return;
}
void NMEAParser::parseGSV (const char* sentence)
// Purpose:
// This function parses a GSV sentence; all data will be stored in the
// NMEAData object within this class. This function will correctly parse
// a partial GSV sentence.
// Pre:
// The string to parse must be a valid GSV sentence.
// Notes:
// All GSV sentences from a single packet (a collection of NMEA sentences
// sent from the GPS) must be processed before satellite information in the
// NMEAData object is updated. There is data for only four satellites
// in each GSV sentence, so multiple sentences must be processed. For
// example, if your GPS was tracking eight satellites, two GSV sentences is
// sent from your GPS in each packet; both sentences must be parsed before
// the NMEAData object is updated with the satellite information.
{
m_data->seenGSV=true;
char field[255];
uint_ numSats;
int numSentences;
int sentenceNumber;
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Count commas in this sentence to see if it's valid.
if (countChars (sentence, ',', SENTENCE_GSV_COMMAS) < 0) return;
// Skip past the '$xxGSV'
if ((isMore = getNextField (field, sentence, currentPos)) == false) {
return;
}
// Determine the number of sentences that will make up the satellite data.
isMore = getNextField (field, sentence, currentPos);
numSentences = atoi (field);
if (isMore == false) return;
// Which sentence is this?.
isMore = getNextField (field, sentence, currentPos);
sentenceNumber = atoi (field);
if (isMore == false) return;
// How many satellites are in total?
isMore = getNextField (field, sentence, currentPos);
numSats = atoi (field);
if (isMore == false) return;
// Is this the first sentence? If so, reset the satellite information.
if (sentenceNumber == 1) {
m_lastSentenceNumber = 1;
m_numSentences = numSentences;
m_numSatsExpected = numSats;
m_numSatsLeft = numSats;
m_satArrayPos = 0;
} else {
// Make sure the satellite strings are being sent in order. If not,
// then you're screwed.
if (sentenceNumber != m_lastSentenceNumber + 1) return;
// BUGFIX:
// Added by Clarke Brunt 20001112
m_lastSentenceNumber = sentenceNumber;
}
// parse the satellite string. There are four satellite info fields per
// sentence.
int i;
for (i = 0; i < 4; i++) {
getNextField (field, sentence, currentPos);
if (strlen (field) != 0) {
m_tempSatData[m_satArrayPos].prn = atoi (field);
getNextField (field, sentence, currentPos);
if (strlen (field) != 0) {
m_tempSatData[m_satArrayPos].elevation = atoi (field);
}
getNextField (field, sentence, currentPos);
if (strlen (field) != 0) {
m_tempSatData[m_satArrayPos].azimuth = atoi (field);
}
getNextField (field, sentence, currentPos);
if (strlen (field) != 0) {
m_tempSatData[m_satArrayPos].strength = atoi (field);
}
--m_numSatsLeft;
++m_satArrayPos;
} else {
// Jump past the next three fields.
for (int j = 0; j < 3; j++)
getNextField (field, sentence, currentPos);
}
}
// If all the satellite information has been received, then update the
// NMEAData object with the new satellite data.
if (m_numSatsLeft == 0) {
for (i = 0; i < m_numSatsExpected; i++) {
m_data->satData[i] = m_tempSatData[i];
}
m_data->numSats = m_numSatsExpected;
m_data->isValidSatData = true;
}
}
void NMEAParser::parseRRE (const char* sentence)
{
m_data->seenRRE=true;
bool isMore;
char field[255];
uint_ currentPos = 0;
// Skip past the '$xxRMC'
if ((isMore = getNextField (field, sentence, currentPos)) == false)
{
return;
}
isMore = getNextField (field, sentence, currentPos);
// I assume the RRE numSats is the same as the RRE numSats!
m_data->numSats = atoi(field);
// Skip the intermediate stuff
for (uint_ i = 0; i < m_data->numSats; i++)
{
isMore = getNextField (field, sentence, currentPos);
if (isMore == false)
{
//sj: logger.error("only read %d out of %d entries", m_data->numSats, i);
return;
}
m_data->rrData[i].prn = atoi(field);
isMore = getNextField (field, sentence, currentPos);
if (isMore == false)
{
//sj: logger.error("only read %d out of %d entries", m_data->numSats, i);
return;
}
m_data->rrData[i].residual = atof(field);
}
m_data->isValidRangeResidualData = true;
// Now read the horizontal
isMore = getNextField (field, sentence, currentPos);
if (isMore == false)
{
// sj: logger.error("no fields left to read hStd");
return;
}
m_data->hStd = atof(field);
m_data->isValidHStd = true;
// Now read the vertical
isMore = getNextField (field, sentence, currentPos);
m_data->zStd = atof(field);
m_data->isValidZStd = true;
//sj: logger.debug("isValidRangeResidualData=%d",
//sj: m_data->isValidRangeResidualData);
//sj: logger.debug("isValidHStd=%d", m_data->isValidHStd);
//sj: logger.debug("isValidZStd=%d", m_data->isValidZStd);
}
void NMEAParser::parseRMC (const char* sentence)
// Purpose:
// This function parses an RMC sentence; all data will be stored in the
// NMEAData object within this class. This function will correctly parse
// a partial RMC sentence.
// Pre:
// The string to parse must be a valid RMC sentence.
{
m_data->seenRMC=true;
char field[255];
char hemisphereField[32];
char hemisphereChar;
char directionField[32];
char directionChar;
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Count commas in this sentence to see if it's valid.
if (countChars (sentence, ',', SENTENCE_RMC_COMMAS) < 0) return;
// Skip past the '$xxRMC'
if ((isMore = getNextField (field, sentence, currentPos)) == false) {
return;
}
// UTC time
isMore = getNextField (field, sentence, currentPos);
parseAndValidateTime (field);
if (isMore == false) return;
// Skip past the navigation warning indicator for now.
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Latitude
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (hemisphereField, sentence, currentPos);
if (strlen (hemisphereField) != 0) {
hemisphereChar = hemisphereField[0];
} else {
hemisphereChar = ' ';
}
parseAndValidateLat (field, hemisphereChar);
if (isMore == false) return;
// Longitude
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (hemisphereField, sentence, currentPos);
if (strlen (hemisphereField) != 0) {
hemisphereChar = hemisphereField[0];
} else {
hemisphereChar = ' ';
}
parseAndValidateLon (field, hemisphereChar);
if (isMore == false) return;
// Current speed, in knots.
isMore = getNextField (field, sentence, currentPos);
parseAndValidateSpeed (field);
if (isMore == false) return;
// Current track, in degrees.
isMore = getNextField (field, sentence, currentPos);
parseAndValidateTrack (field);
if (isMore == false) return;
// Current date
isMore = getNextField (field, sentence, currentPos);
parseAndValidateDate (field);
if (isMore == false) return;
// Magnetic variation (degrees from true north)
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
isMore = getNextField (directionField, sentence, currentPos);
if (strlen (directionField) != 0) {
directionChar = directionField[0];
} else {
directionChar = ' ';
}
parseAndValidateMagVariation (field, directionChar);
if (isMore == false) return;
}
void NMEAParser::parseGST (const char* sentence)
{
m_data->seenGST=true;
char field[255];
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Count commas in this sentence to see if it's valid.
if (countChars (sentence, ',', SENTENCE_GST_COMMAS) < 0) return;
// Skip past '$GPGST'
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Get the UTC time
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
parseAndValidateTime(field);
// This field is the RMS value of the standard deviations to the range inputs
// to the navigation process
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Skip unimplemented fields
currentPos += 3;
// Standard deviation of latitude
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Parse the north standard deviation
parseAndValidateNStd(field);
// Standard deviation of longitude
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
parseAndValidateEStd(field);
// Standard deviation of altitude
isMore = getNextField (field, sentence, currentPos);
parseAndValidateZStd(field);
}
void NMEAParser::parseVTG (const char* sentence)
{
m_data->seenVTG=true;
char field[255];
char reference[256];
uint_ currentPos = 0;
bool isMore = true; // More strings to parse?
// Count commas in this sentence to see if it's valid.
if (countChars (sentence, ',', SENTENCE_VTG_COMMAS) < 0) return;
// Skip past '$GPVTG'
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Get the COG wrt to true north
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Get the reference
isMore = getNextField (reference, sentence, currentPos);
if (isMore == false) return;
// Reference should be a 'T' to denote true north
if (reference[0] != 'T')
{
// sj: logger.warn("parseVTG: the reference should be T but it's ",
// sj: reference);
return;
}
// Get the track
parseAndValidateTrack(field);
// Get the COG wrt to magnetic north
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Get the reference
isMore = getNextField (reference, sentence, currentPos);
if (isMore == false) return;
// Reference should be a 'M' to denote wrt magnetic north
if (reference[0] != 'M')
{
// sj: logger.warn("parseVTG: the reference should be M but it's ",
// sj: reference);
return;
}
// Speed, should be in miles per hour
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Get the reference
isMore = getNextField (reference, sentence, currentPos);
if (isMore == false) return;
// Reference should be a 'N' to denote knots per hour
if (reference[0] != 'N')
{
// sj: logger.warn("parseVTG: the reference should be N but it's ",
// sj: reference);
return;
}
// Speed, should be in kilometres per hour
isMore = getNextField (field, sentence, currentPos);
if (isMore == false) return;
// Get the reference
isMore = getNextField (reference, sentence, currentPos);
// Reference should be a 'K' to denote kilometers per hour
if (reference[0] != 'K')
{
// sj: logger.warn("parseVTG: the reference should be K but it's ",
// sj: reference);
return;
}
parseAndValidateSpeed(field);
}
SENTENCE_STATUS NMEAParser::parseSentence (const char* sentence)
// Purpose:
// This function parses a given NMEA sentence. All valid information will be
// stored within the NMEAData object in this class; call the GetData()
// member function to retrieve the data.
// Parameters:
// const char* sentence:
// The sentence to parse.
// Returns:
// SENTENCE_VALID if the sentence passed is a valid NMEA sentence.
// SENTENCE_INVALID if the sentence passed is not a valid NMEA sentence, or
// the sentence type is unsupported (see NMEAParser.h for a list of
// supported sentences.)
// SENTENCE_BAD_CHECKSUM if the sentence has an invalid checksum.
{
#if 0 // sj
if (logger.isDebugEnabled())
{
logger.debug("parsing sentence %s", sentence);
}
#endif
if (isCorrectChecksum (sentence) == false)
{
// sj: logger.debug("SENTENCE_BAD_CHECKSUM");
return SENTENCE_BAD_CHECKSUM;
}
if (isKnownSentenceType (sentence) == false)
{
// sj: logger.debug("SENTENCE_UNKNOWN");
return SENTENCE_UNKNOWN;
}
return parseValidSentence(sentence);
}
SENTENCE_STATUS NMEAParser::parseValidSentence (const char* sentence)
{
#if 0 // sj
if (logger.isDebugEnabled())
{
logger.debug("NMEAParser: parsing %s", sentence);
}
#endif
// Start the parsing 3 spaces past start to get past the initial
// '$xx', where xx is the device type sending the sentences (GP =
// GPS, etc.)
uint_ currentPos = 3;
char sentenceType[4];
if (getNextField (sentenceType, sentence, currentPos) == false)
{
return SENTENCE_INVALID;
}
if (strcmp (sentenceType, startSentence) == 0)
{
// this message is the first in the sequence
m_data->waitingForStart = false;
}
// If we are waiting for the start message to appear, don't bother
// processing any other message type
if (m_data->waitingForStart == true)
{
return SENTENCE_VALID;
}
// Parse the sentence. Make sure the sentence has the correct
// number of commas in it, otherwise the sentence is invalid.
if (strcmp (sentenceType, "GGA") == 0)
{
if (countChars (sentence, ',', SENTENCE_GGA_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseGGA (sentence);
}
else if (strcmp (sentenceType, "GLL") == 0)
{
if (countChars (sentence, ',', SENTENCE_GLL_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseGLL (sentence);
}
else if (strcmp (sentenceType, "RMC") == 0)
{
if (countChars (sentence, ',', SENTENCE_RMC_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseRMC (sentence);
}
else if (strcmp (sentenceType, "GSV") == 0)
{
if (countChars (sentence, ',', SENTENCE_GSV_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseGSV (sentence);
}
else if (strcmp (sentenceType, "RRE") == 0)
{
// if (countChars (sentence, ',', SENTENCE_RRE_COMMAS) < 0)
//{
// return SENTENCE_INVALID;
//}
parseRRE (sentence);
}
else if (strcmp (sentenceType, "VTG") == 0)
{
if (countChars (sentence, ',', SENTENCE_VTG_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseVTG (sentence);
}
else if (strcmp (sentenceType, "GST") == 0)
{
if (countChars (sentence, ',', SENTENCE_GST_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseGST (sentence);
}
else if (strcmp (sentenceType, "ZDA") == 0)
{
if (countChars (sentence, ',', SENTENCE_ZDA_COMMAS) < 0)
{
return SENTENCE_INVALID;
}
parseZDA (sentence);
}
else
{
return SENTENCE_INVALID;
}
return SENTENCE_VALID;
}
/////////////////////////////////////////////////////////////////////////////
// Member functions for individual element parsing of sentences.
bool NMEAParser::parseDate (int& year, int& month, int& day,
const char* dateString) const
// Purpose:
// This function parses a date string from an NMEA sentence in DDMMYY format
// and returns the year, month, and day values.
// Parameters:
// int& year, int& month, int& year:
// Upon exit, these variables will contain the year, month, and day
// values specified in dateString, respectively.
// const char* dateString:
// The NMEA date string to parse.
// Returns:
// true if the date string is in a valid format, false if not.
// Notes:
// - NMEA sentences are *not* "Year 2000-compliant"{tm}; the software must
// correctly determine the year's century.
// - If this function returns false, then the variables year, month, and day
// are unaffected.
{
// Date must be six characters.
if (strlen (dateString) < unsigned (DATE_LEN))
{
return false;
}
long tempDate = atol (dateString);
int tempYear, tempMonth, tempDay;
tempYear = tempDate - ((tempDate / 100) * 100);
tempMonth = (tempDate - ((tempDate / 10000) * 10000)) / 100;
tempDay = tempDate / 10000;
// Check to see if the date is valid. (This function will accept
// Feb 31 as a valid date; no check is made for how many days are in
// each month of our whacked calendar.)
if ((tempYear >= 0 && tempYear <= 99)
&& (tempMonth >= 1 && tempMonth <= 12)
&& (tempDay >= 1 && tempDay <= 31))
{
year = tempYear;
month = tempMonth;
day = tempDay;
return true;
}
return false;
}
bool NMEAParser::parseDegrees (double& degrees, const char* degString) const
// Purpose:
// This function converts a lat/lon string returned from an NMEA string into
// a numeric representation of that string, in degrees. (A lat/lon string
// must be in the format DDMM.M(...) where D = degrees and M = minutes.)
// Pre:
// The string degString must contain a number in the format DDMM.M(...).
// Parameters:
// double& degrees:
// Upon exit, degrees will contain the numeric representation of the
// string passed to this function, in decimal degrees.
// const char* degString:
// Contains the string to convert.
// Returns:
// - true if the conversion was successful. If false is returned, either
// degString was not in one of those required formats, or the string data
// itself is invalid. (For example, the string 23809.666 would not be
// valid, as the 238th degree does not exist.)
// - If this function returns false, then the parameter 'degrees' is
// unaffected.
{
if (strlen (degString) == 0)
{
return false;
}
double tempPosition = atof (degString);
double tempDegrees = (double)((int)(tempPosition / 100.0));
double tempMinutes = (tempPosition - (tempDegrees * 100.0));
tempPosition = tempDegrees + (tempMinutes / 60.0);
if (tempPosition >= 0.0 && tempPosition <= 180.0)
{
degrees = tempPosition;
return true;
}
return false;
}
bool NMEAParser::parseTime (int& hour, int& minute, int& second,
const char* timeString) const
// Purpose:
// This function parses a time string from an NMEA sentence in HHMMSS.S(...)
// format and returns the hour, minute, and second values.
// Parameters:
// int& hour, int& minute, int& second:
// Upon exit, these variables will contain the hour, minute, and second
// values specified in timeString, respectively.
// const char* timeString:
// The NMEA time string to parse.
// Returns:
// true if the time string is in a valid format, false if not.
// Notes:
// - Decimal second values are truncated.
// - If this function returns false, then the variables hour, minute, and
// second are unaffected.
{
if (strlen (timeString) == 0)
{
return false;
}
long tempTime = atol (timeString);
int tempHour = tempTime / 10000;
int tempMinute = (tempTime - ((tempTime / 10000) * 10000)) / 100;
int tempSecond = tempTime - ((tempTime / 100) * 100);
// Check to see if the time is valid.
if ((tempHour >= 0 && tempHour <= 23)
&& (tempMinute >= 0 && tempMinute <= 59)
&& (tempSecond >= 0 && tempSecond <= 61))
{ // leap seconds
hour = tempHour;
minute = tempMinute;
second = tempSecond;
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
// parse And Validate member functions for NMEAParser.
//
// Each of these member functions parse a specified field from a sentence and
// updates the appropriate member variables in the NMEAData object. If the
// data parsed is valid, the validation member variable associated the parsed
// value is set to true, otherwise it is set to false.
void NMEAParser::parseAndValidateAltitude (const char* field, const char unit)
// Purpose:
// This function parses the altitude field of a sentence.
// Parameters:
// const char* field:
// The altitude field of the sentence to parse.
// const char unit:
// The unit of altitude. Valid values are 'f' (feet) and 'm' (meters).
// Notes:
// The resulting altitude data is specified in feet.
{
// Initially assume data is invalid.
m_data->isValidAltitude = false;
if (strlen (field) != 0) {
if (unit == 'f' || unit == 'F') {
// Altitude is in feet.
m_data->altitude = atof (field) * FEET_TO_METERS;
m_data->isValidAltitude = true;
} else if (unit == 'm' || unit == 'M') {
// Altitude is in meters. Convert to feet.
m_data->altitude = atof (field);
m_data->isValidAltitude = true;
}
}
// sj: logger.debug("isValidAltitude=%d; altitude=%f",
// sj: m_data->isValidAltitude, m_data->altitude);
}
void NMEAParser::parseAndValidateDate (const char* field)
// Purpose:
// This function parses the date field of a sentence, in the format DDMMYY.
{
// Initially assume data is invalid.
m_data->isValidDate = false;
if (strlen (field) != 0) {
int year, month, day;
if (parseDate (year, month, day, field) == true) {
m_data->UTCYear = year;
m_data->UTCMonth = month;
m_data->UTCDay = day;
m_data->isValidDate = true;
}
}
// sj: logger.debug("isValidDate=%d; year=%d; month=%d; day=%d",
// sj: m_data->isValidDate, m_data->UTCYear, m_data->UTCMonth,
// sj: m_data->UTCDay);
}
void NMEAParser::parseAndValidateFixQuality (const char* field)
// Purpose:
// This function parses the GPS fix quality field of a sentence.
{
if (strlen (field) != 0) {
m_data->isValidFixQuality = true;
int fixQuality = atoi (field);
if (fixQuality == 0) m_data->lastFixQuality = FIX_AUTONOMOUS;
else if (fixQuality == 1) m_data->lastFixQuality = FIX_RTCM;
else if (fixQuality == 2) m_data->lastFixQuality = FIX_CPD_FLOAT;
else if (fixQuality == 3) m_data->lastFixQuality = FIX_CPD_FIXED;
else if (fixQuality == 9) m_data->lastFixQuality = FIX_ALMANAC;
else
{
// sj: logger.notice("unknown fix quality %d", fixQuality);
m_data->lastFixQuality = FIX_AUTONOMOUS;
}
}
// sj: logger.debug("lastFixQuality=%d", m_data->lastFixQuality);
}
void NMEAParser::parseAndValidateHdop (const char* field)
// Purpose:
// This function parses the HDOP (horizontal dilution of precision) field of
// a sentence.
{
if (strlen (field) != 0) {
m_data->hdop = atof (field);
m_data->isValidHdop = true;
} else {
m_data->isValidHdop = false;
}
// sj: logger.debug("isValidHdop=%d; hdop=%f", m_data->isValidHdop, m_data->hdop);
}
void NMEAParser::parseAndValidateNStd (const char* field)
// Purpose:
// This function parses the NSTD (1 standard deviation of position estimate in northern
// direction)
{
if (strlen (field) != 0) {
m_data->nStd = atof (field);
m_data->isValidNStd = true;
} else {
m_data->isValidNStd = false;
}
// sj: logger.debug("isValidNStd=%d; nStd=%f", m_data->isValidNStd, m_data->nStd);
}
void NMEAParser::parseAndValidateEStd (const char* field)
// Purpose:
// This function parses the ESTD (1 standard deviation of position estimate in eastern
// direction)
{
if (strlen (field) != 0) {
m_data->eStd = atof (field);
m_data->isValidEStd = true;
} else {
m_data->isValidEStd = false;
}
}
void NMEAParser::parseAndValidateZStd (const char* field)
// Purpose:
// This function parses the ZSTD (1 standard deviation of position estimate in altitude)
{
if (strlen (field) != 0) {
m_data->zStd = atof (field);
m_data->isValidZStd = true;
} else {
m_data->isValidZStd = false;
}
// sj: logger.debug("isValidEStd=%d; eStd=%f", m_data->isValidEStd, m_data->eStd);
}
void NMEAParser::parseAndValidateLat (const char* field, const char hem)
// Purpose:
// This function parses the latitude field of a sentence in the format
// DDMM.M(...).
// Parameters:
// const char* field:
// The latitude field of the sentence to parse.
// const char hem:
// The hemisphere that contains the location. Valid values are 'N' and
// 'S'.
// Notes:
// - If the latitude is in the southern hemisphere, the latitude member
// variable will be negative. (e.g., 4000.000 S will be stored as -40.0.)
// - If the latitude field does not exist within a sentence, the fix
// quality variable, m_data->lastFixQuality, is set to FIX_AUTONOMOUS.
{
// Initially assume data is invalid.
m_data->isValidLat = false;
if (strlen (field) != 0) {
// GPS lat/lon data has been received.
// Set the fix quality to "GPS navigation." This is because some
// GPS's may not send GGA sentences; therefore the last fix quality
// would never get set.
if (m_data->lastFixQuality == FIX_AUTONOMOUS) {
m_data->lastFixQuality = FIX_RTCM;
}
m_data->hasCoordEverBeenValid = true;
double degree;
if (parseDegrees (degree, field) == true) {
if (hem == 'N') {
// Northern hemisphere.
m_data->lat = degree;
m_data->isValidLat = true;
} else if (hem == 'S') {
// Southern hemisphere, so make latitude negative.
m_data->lat = -degree;
m_data->isValidLat = true;
}
}
} else {
m_data->lastFixQuality = FIX_AUTONOMOUS;
}
// sj: logger.debug("isValidLat=%d; lat=%f", m_data->isValidLat, m_data->lat);
}
void NMEAParser::parseAndValidateLon (const char* field, const char hem)
// Purpose:
// Same as parseAndValidateLat(), but the longitude is in the format
// DDDMM.M(...).
// Notes:
// - The valid values for the hem parameter are 'E' and 'W'.
// - If the longitude is in the western hemisphere, the longitude member
// variable will be negative. (e.g., 4000.000 W will be stored as -40.0.)
// - If the latitude field does not exist within a sentence, the last fix
// quality variable, m_data->lastFixQuality, is set to FIX_AUTONOMOUS.
{
// Initially assume data is invalid.
m_data->isValidLon = false;
if (strlen (field) != 0) {
// GPS lat/lon data has been received.
// Set the fix quality to "GPS navigation." This is because some
// GPS's may not send GGA sentences; therefore the last fix quality
// would never get set.
if (m_data->lastFixQuality == FIX_AUTONOMOUS) {
m_data->lastFixQuality = FIX_RTCM;
m_data->hasCoordEverBeenValid = true;
}
double degree;
if (parseDegrees (degree, field) == true) {
if (hem == 'E') {
// Eastern hemisphere.
m_data->lon = degree;
m_data->isValidLon = true;
} else if (hem == 'W') {
// Western hemisphere, so make longitude negative.
m_data->lon = -degree;
m_data->isValidLon = true;
}
}
} else {
m_data->lastFixQuality = FIX_AUTONOMOUS;
}
// sj: logger.debug("isValidLon=%d; lon=%f", m_data->isValidLon, m_data->lon);
}
void NMEAParser::parseAndValidateMagVariation (const char* field,
const char direction)
// Purpose:
// This function parses the magnetic variation field of a sentence, in
// relation to true north.
// Parameters:
// const char* field:
// The magnetic variation field of the sentence to parse, in degrees.
// const char direction:
// The direction of the field in relation to true north. Valid values
// are 'E' and 'W'.
// Notes:
// If the magnetic variation points west of true north, the magnetic
// variation variable will be negative. (e.g., 020.3 W will be stored as
// -20.3.)
{
// Initially assume data is invalid.
m_data->isValidMagVariation = false;
if (strlen (field) != 0) {
double degree = atof (field);
if (degree >= 0.0 && degree <= 360.0) {
if (direction == 'E') {
m_data->magVariation = degree;
m_data->isValidMagVariation = true;
} else if (direction == 'W') {
m_data->magVariation = -degree;
m_data->isValidMagVariation = true;
}
}
}
// sj: logger.debug("isValidMagVariation=%d; magVariation=%f",
// sj: m_data->isValidMagVariation, m_data->magVariation);
}
void NMEAParser::parseAndValidateSpeed (const char* field)
// Purpose:
// This function parses the speed field of a sentence.
{
if (strlen (field) != 0) {
m_data->speed = atof (field);
m_data->isValidSpeed = true;
} else {
m_data->isValidSpeed = false;
}
// sj: logger.debug("isValidSpeed=%d; speed=%f",
// sj: m_data->isValidSpeed, m_data->speed);
}
void NMEAParser::parseAndValidateTime (const char* field)
// Purpose:
// This function parses the date field of a sentence, in the format
// HHMMSS.S(...), except the decimal second values are truncated.
{
// Initially assume data is invalid.
m_data->isValidTime = false;
if (strlen (field) != 0) {
int hour, minute, second;
if (parseTime (hour, minute, second, field) == true) {
m_data->UTCHour = hour;
m_data->UTCMinute = minute;
m_data->UTCSecond = second;
m_data->isValidTime = true;
}
}
// sj: logger.debug("isValidTime=%d; hour=%d; minute=%d; second=%d",
// sj: m_data->isValidTime, m_data->UTCHour, m_data->UTCMinute,
// sj: m_data->UTCSecond);
}
void NMEAParser::parseAndValidateTrack (const char* field)
// Purpose:
// This function parses the track field of a sentence.
{
// Initially assume data is invalid.
m_data->isValidTrack = false;
if (strlen (field) != 0) {
double track = atof (field);
if (track >= 0.0 && track <= 360.0) {
m_data->track = track;
m_data->isValidTrack = true;
}
}
// sj: logger.debug("isValidTrack=%d; track=%f", m_data->isValidTrack, m_data->track);
}
/////////////////////////////////////////////////////////////////////////////
// Miscellaneous member functions
bool NMEAParser::getNextField (char* data, const char* sentence,
uint_& currentPos) const
// Purpose:
// This function retrieves the next field in the NMEA sentence. A field is
// defined as the text between two delimiters (in this case of NMEA
// sentences, a delimiter is a comma character.)
// Pre:
// The specified sentence is valid. (Before calling this function, call the
// member functions IsCorrectChecksum() and ValidSentenceType(), passing the
// sentence to those functions.)
// Parameters:
// char* data:
// Upon exit, this string will contain the contents of the next field
// in the sentence.
// const char* sentence:
// The NMEA sentence to parse.
// uint_& currentPos:
// Determines the initial position within the NMEA sentence in which to
// parse. This function will grab all of the characters from
// currentPos all the way to the character before the comma delimiter.
// Upon exit, currentPosition will point to the next field in the string.
// Note that the comma is not included in the field data.
// Returns:
// true if there are more fields to parse, false if not.
// Notes:
// To grab all of the fields, you can iteratively call GetNextData()
// using the same variable that is passed as currentPosition, until
// GetNextData() returns false.
{
int srcPos = currentPos;
int dstPos = 0;
char currentChar = sentence[srcPos];
// The delimiter character is the comma.
while ((currentChar != '\0' ) && (currentChar != ',')
&& (currentChar != '\x0d') && (currentChar != '*')) {
data[dstPos++] = currentChar;
currentChar = sentence[++srcPos];
}
data[dstPos] = '\0';
if (currentChar == ',') {
// Next data field to parse will be past the comma.
currentPos = srcPos + 1;
return true;
} else {
// No more characters in the string to parse; this function has
// arrived at the end of the string.
return false;
}
}
bool NMEAParser::isCorrectChecksum (const char* sentence) const
// Purpose:
// This function calculates the sentence's checksum and compares it with the
// checksum in the sentence.
// Pre:
// The NMEA sentence is valid (ValidSentenceStructure() must be called with
// this sentence before calling this function; that function must return
// true.)
// Returns:
// true if the checksum is valid or there is no checksum in the sentence.
// (It is not necessary to have a device append a checksum to a sentence.)
// Otherwise this function returns false.
// Notes:
// The checksum in the sentence occurs after the * character.
{
// Check all characters between the initial '$' and the last "*" in the
// sentence and XOR them together.
int charPos = 1; // start past the initial '$'.
char currentChar = sentence[charPos];
uint8_ checksum = 0;
while (currentChar != '*' && currentChar != '\0') {
checksum ^= (uint8_)currentChar;
currentChar = sentence[++charPos];
}
// If no checksum exists (this function has reached the end of the string
// without finding one), the sentence is good.
if (sentence[charPos + 1] == '\0') return true;
// Convert last two hex characters (the checksum) in the sentence with
// the checksum this function has generated.
char firstDigit = sentence[charPos + 1];
char lastDigit = sentence[charPos + 2];
if ( (firstDigit <= '9' ? firstDigit - '0': (firstDigit - 'A') + 10) * 16
+ (lastDigit <= '9' ? lastDigit - '0': (lastDigit - 'A') + 10)
== checksum) {
return true;
} else {
return false;
}
return true;
}
bool NMEAParser::isValidSentenceType (const char* sentence) const
{
if (strlen (sentence) < 6)
{
return false;
}
if (sentence[0] != '$')
{
return false;
}
return isKnownSentenceType(sentence);
}
bool NMEAParser::isKnownSentenceType (const char* sentence) const
// Purpose:
// This function determines whether this is a valid NMEA sentence that this
// class can support.
// Notes:
// See the header file for a list of sentences supported by this class.
{
// Get the three letters after the '$xx'; this is the type of
// sentence. (Note the xx is the type of device which is sending
// the string. For example, GP = GPS, etc.)
char sentenceType[4];
memcpy (sentenceType, &(sentence[3]), 3);
sentenceType[3] = '\0';
return ((strcmp (sentenceType, "ZDA") == 0)
|| (strcmp (sentenceType, "GGA") == 0)
|| (strcmp (sentenceType, "GLL") == 0)
|| (strcmp (sentenceType, "RMC") == 0)
|| (strcmp (sentenceType, "GSV") == 0)
|| (strcmp (sentenceType, "GST") == 0)
|| (strcmp (sentenceType, "VTG") == 0)
|| (strcmp (sentenceType, "RRE") == 0));
}
int NMEAParser::countChars (const char* string, char charToCount, uint_ charCount) const
// Purpose:
// This function counts the number of specified occurrences of the
// specified characters and compares to the number of characters that is
// expected.
// Parameters:
// const char* string:
// The string to check.
// char charToCount:
// The character to count.
// uint_ charCount:
// The number of the characters specified by charToCount that is expected
// to be contained within that string.
// Returns:
// 0 if the number of specified characters in the sentence matches charCount.
// 1 if the number of specified characters in the sentence is less than
// charCount.
// -1 if the number of specified characters in the sentence is greater than
// charCount.
{
size_t stringSize = strlen (string);
size_t currentCharCount = 0;
const char* currentChar = string;
for (size_t i = 0; i < stringSize; i++) {
if (*currentChar++ == charToCount) ++currentCharCount;
}
if (currentCharCount > charCount) {
return 1;
} else if (currentCharCount < charCount) {
return -1;
} else {
return 0;
}
}
/*
* This class was adapted from the GPSThing CNmeaParser class.
* Originally written by Jason Bevins
*/
#ifndef __NMEAPARSER_HPP
#define __NMEAPARSER_HPP
#if 1
typedef unsigned char uint8_;
typedef unsigned short uint16_;
typedef unsigned int uint32_;
typedef unsigned int uint_;
#else
// Get standard types (uint8_, etc.)
#include <cc++/config.h>
#endif
#include <string.h>
// sj: #include <log4cpp/Category.hh>
struct SatData
{
SatData ()
{
prn = 0;
elevation = 0;
azimuth = 0;
strength = 0;
}
SatData (uint8_ prn_, uint16_ elevation_, uint16_ azimuth_,
uint16_ strength_)
{
prn = prn_;
elevation = elevation_;
azimuth = azimuth_;
strength = strength_;
}
uint16_ prn; // Satellite's ID.
uint16_ elevation; // Elevation of satellite, in degrees.
uint16_ azimuth; // Azimuth of satellite, in degrees.
uint16_ strength; // Signal strength of satellite.
};
struct RangeResidualData
{
RangeResidualData()
{
prn = 0;
residual = 0;
}
RangeResidualData(uint8_ prn_, double residual_)
{
prn = prn_;
residual = residual_;
}
uint8_ prn;
double residual;
};
const double METERS_TO_FEET = 3.280839895013;
const double FEET_TO_METERS = 1 / METERS_TO_FEET;
const double KM_TO_NM = 1.853;
const double NM_TO_KM = 1 / KM_TO_NM;
const double KM_TO_MI = FEET_TO_METERS * 5.28;
const double MI_TO_KM = 1 / KM_TO_MI;
// GPS coordinate fix quality.
enum GPS_FIX_QUALITY
{
FIX_AUTONOMOUS = 0,
FIX_RTCM = 1,
FIX_CPD_FLOAT = 2,
FIX_CPD_FIXED = 3,
FIX_ALMANAC = 9
};
// Sentence parsing status.
enum SENTENCE_STATUS
{
SENTENCE_VALID=0, // Sentence parsed is valid.
SENTENCE_INVALID, // Sentence parsed has invalid data.
SENTENCE_BAD_CHECKSUM, // Sentence parsed has a bad checksum.
SENTENCE_UNKNOWN // Sentence is of unknown type
};
// Number of commas in each sentence. In order for a sentence to be valid,
// it must have a specified number of commas.
enum SENTENCE_COMMA_SIZES
{
SENTENCE_ZDA_COMMAS = 6,
SENTENCE_GGA_COMMAS = 14,
SENTENCE_GLL_COMMAS = 6,
SENTENCE_RMC_COMMAS = 11,
SENTENCE_GSV_COMMAS = 19,
SENTENCE_VTG_COMMAS = 7,
SENTENCE_GST_COMMAS = 8,
SENTENCE_RRE_COMMAS = 4
};
// Maximum size of an NMEA sentence (plus the NULL character.)
const int MAX_SENTENCE_SIZE = 1024;
// No GPS I'm aware of can track more than 12 satellites.
const uint8_ MAX_SATS = 12;
// Data class stored with the parser. To extract the data parsed from the
// parser, pass an object of this class to the parser.
// NOTE! NMEA sentences are not "Year 2000-compliant"{tm}
struct NMEAData
{
NMEAData ();
virtual ~NMEAData()
{
}
virtual void reset ();
// Data retrieved from the NMEA sentences.
double lat; // Latitude, in degrees (positive=N, negative=S)
double lon; // Longitude, in degrees (positive=E, negative=W)
double altitude; // Altitude, in feet
double speed; // Speed, in knots
double track; // Current track, in degrees.
double magVariation; // Magnetic variation, in degrees.
double hdop; // Horizontal dilution of precision.
double nStd; // North standard deviation.
double eStd; // East standard deviation.
double zStd; // Altitude standard deviation.
double hStd; // Horizonal standard deviation.
uint_ numSats; // Number of satellites in the sky.
int UTCYear; // GPS Date (UTC), year part
int UTCMonth; // GPS Date (UTC), month part
int UTCDay; // GPS Date (UTC), day part
int UTCHour; // GPS Time (UTC), hour part.
int UTCMinute; // GPS Time (UTC), minute part
int UTCSecond; // GPS Time (UTC), second part
SatData satData[MAX_SATS];
RangeResidualData rrData[MAX_SATS];
// Quality of last fix:
// 0 = invalid, 1 = GPS fix, 2 = DGPS fix.
GPS_FIX_QUALITY lastFixQuality;
// Validity of data parsed.
bool isValidLat; // Latitude
bool isValidLon; // Longitude
bool isValidAltitude; // Altitude
bool isValidSpeed; // Speed
bool isValidDate; // Date
bool isValidTime; // Time
bool isValidTrack; // Track
bool isValidMagVariation; // Magnetic variation
bool isValidHdop; // Horizontal dilution of precision
bool isValidNStd;
bool isValidEStd;
bool isValidZStd;
bool isValidSatData; // Satellite data
bool isValidRangeResidualData; // Satellite data
bool isValidHStd;
bool isValidFixQuality;
// Has a valid coordinate ever been sent over the serial port?
bool hasCoordEverBeenValid;
// Flag indicates if we are waiting for the frame to start
bool waitingForStart;
// Whether we have seen a particular message since the data was
// reset
bool seenZDA;
bool seenGGA;
bool seenGLL;
bool seenRMC;
bool seenGSV;
bool seenGST;
bool seenVTG;
bool seenRRE;
};
class NMEAParser
{
public:
NMEAParser (/* sj: log4cpp::Category& l*/);
virtual ~NMEAParser ();
SENTENCE_STATUS parseSentence (const char* sentence);
void setStartSentence(char *sentence)
{
strcpy(startSentence, sentence);
}
void getData (NMEAData& data) const
{
data = *m_data;
}
NMEAData& getData()
{
return *m_data;
}
void reset ()
{
m_data->reset ();
}
bool isValidSentenceType (const char* sentence) const;
bool isCorrectChecksum (const char* sentence) const;
protected:
NMEAParser (/* sj: log4cpp::Category& l,*/ NMEAData* data);
bool parseDegrees (double& degrees, const char* degString) const;
bool parseDate (int& year, int& month, int& day,
const char* dateString) const;
bool parseTime (int& hour, int& minute, int& second,
const char* timeString) const;
void parseAndValidateAltitude (const char* field, const char unit);
void parseAndValidateDate (const char* field);
void parseAndValidateFixQuality (const char* field);
void parseAndValidateLat (const char* field, const char hem);
void parseAndValidateLon (const char* field, const char hem);
void parseAndValidateHdop (const char* field);
void parseAndValidateSpeed (const char* field);
void parseAndValidateNStd (const char* field);
void parseAndValidateEStd (const char* field);
void parseAndValidateZStd (const char* field);
void parseAndValidateMagVariation(const char* field,
const char direction);
void parseAndValidateTime (const char* field);
void parseAndValidateTrack (const char* field);
bool getNextField(char* data, const char* sentence,
uint_& currentPosition) const;
int countChars(const char* sentence, char charToCount,
uint_ charCount) const;
virtual bool isKnownSentenceType (const char* sentence) const;
virtual SENTENCE_STATUS parseValidSentence (const char* sentence);
NMEAData* m_data;
// the sentence that marks the beginning of the set of packets
char startSentence[16];
// Needed for parsing the GSV sentence.
int m_lastSentenceNumber;// Which sentence number was the last one?
int m_numSentences; // Number of sentences to process.
int m_numSatsExpected; // Number of satellites expected to parse.
int m_numSatsLeft; // Number of satellites left to parse.
int m_satArrayPos; // Array position of the next sat entry.
SatData m_tempSatData[MAX_SATS];
// The logging category
// sj: log4cpp::Category& logger;
private:
void parseZDA(const char* sentence);
void parseGGA (const char* sentence);
void parseGLL (const char* sentence);
void parseRMC (const char* sentence);
void parseGSV (const char* sentence);
void parseGST (const char* sentence);
void parseVTG (const char* sentence);
void parseRRE (const char* sentence);
};
#endif
// TypedCoord.C: Implementation of the CTypedCoord abstract base class.
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#include "gpsnmealib/nmeaParser.h" // for GPS_FIX_QUALITY
#include "typedCoord.h"
#ifdef sgi
#include <math.h>
#else
#include <cmath> // for sqrt, atan2, cos, sin, fabs
#endif
// Mmmmm, pi...
static const double PI = 3.141592653589793;
// Radians to degrees conversion constants.
static const double RAD_TO_DEG = 180.0 / PI;
static const double DEG_TO_RAD = PI / 180.0;
static double mod (double num, double divisor)
// Purpose:
// This function determines the remainder of num / divisor.
{
if (num >= 0) {
return num - divisor * (int)(num / divisor);
} else {
return num + divisor * (int)((-num / divisor) + 1);
}
}
/////////////////////////////////////////////////////////////////////////////
// TypedCoord operators
TypedCoord& TypedCoord::operator= (const TypedCoord& other)
{
double lat, lon;
other.getLatLonCoord (lat, lon);
setLatLonCoord (lat, lon);
return *this;
}
/////////////////////////////////////////////////////////////////////////////
// TypedCoord members
void TypedCoord::calculateDistAndBearing (const TypedCoord& coord,
double& dist, double& bearingStartToEnd, double& bearingEndToStart) const
// Purpose:
// This function calculates the distance between this coordinate and the
// specified coordinate on the Earth and determines the bearing to the
// coordinates in the forward and the reverse direction.
// Parameters:
// TypedCoord& coord:
// The specified coordinate.
// double& dist:
// Upon exit, this parameter contains the distance between the two
// coordinates, in meters.
// double& bearingStartToEnd:
// Upon exit, this parameter contains the bearing from this coordinate
// to the specified coordinate, in degrees.
// double& bearingEndToStart:
// Upon exit, this parameter contains the bearing from the specified
// coordinate to this coordinate, in degrees.
{
double startLat, startLon;
double endLat, endLon;
getLatLonCoord (startLat, startLon);
coord.getLatLonCoord (endLat, endLon);
distAndBearingWGS84 (startLat, startLon, endLat, endLon, dist,
bearingStartToEnd, bearingEndToStart);
}
void TypedCoord::distAndBearing (double a, double f, double startLat,
double startLon, double endLat, double endLon, double& dist,
double& bearingStartToEnd, double& bearingEndToStart) const
// Purpose:
// This function calculates the distance between two coordinates on the Earth
// and determines the bearing to the coordinates in the forward and the
// reverse direction.
// Pre:
// startLat and endLat does not equal 90 or -90 degrees.
// Parameters:
// double a:
// Ellipsoid semi-major axis, in meters. (For WGS84 datum, use 6378137.0)
// double f:
// Ellipsoid flattening. (For WGS84 datum, use 1 / 298.257223563)
// double startLat:
// The starting latitude.
// double startLon:
// The starting longitude.
// double endLat:
// The ending latitude.
// double startLon:
// The ending longitude.
// double& dist:
// Upon exit, this parameter contains the distance between the two
// coordinates, in meters.
// double& bearingStartToEnd:
// Upon exit, this parameter contains the bearing from the starting
// coordinate to the ending coordinate, in degrees.
// double& bearingEndToStart:
// Upon exit, this parameter contains the bearing from the ending
// coordinate to the starting coordinate, in degrees.
{
double c;
double c1;
double c2;
double c2a;
double sinX, cosX;
double cy, cz;
double d, e;
double r, s;
double s1, sa, sy;
double tan1, tan2;
double x, y;
double t, t1, t2, t3, t4, t5;
double coordStartLatRad = startLat * DEG_TO_RAD;
double coordStartLonRad = startLon * DEG_TO_RAD;
double coordEndLatRad = endLat * DEG_TO_RAD;
double coordEndLonRad = endLon * DEG_TO_RAD;
r = 1.0 - f;
tan1 = (r * sin (coordStartLatRad)) / cos (coordStartLatRad);
tan2 = (r * sin (coordEndLatRad)) / cos (coordEndLatRad);
c1 = 1.0 / sqrt ((tan1 * tan1) + 1.0);
s1 = c1 * tan1;
c2 = 1.0 / sqrt ((tan2 * tan2) + 1.0);
s = c1 * c2;
bearingEndToStart = s * tan2;
bearingStartToEnd = bearingEndToStart * tan1;
x = coordEndLonRad - coordStartLonRad;
int exitLoop = 0;
int loopCount = 0;
while (exitLoop == 0 && loopCount < 6)
{
sinX = sin (x);
cosX = cos (x);
tan1 = c2 * sinX;
tan2 = bearingEndToStart - (s1 * c2 * cosX);
sy = sqrt ((tan1 * tan1) + (tan2 * tan2));
cy = (s * cosX) + bearingStartToEnd;
y = atan2 (sy, cy);
sa = (s * sinX) / sy;
c2a = ((-sa) * sa) + 1.0;
cz = bearingStartToEnd * 2.0;
if (c2a > 0.0) {
cz = ((-cz) / c2a) + cy;
}
e = (cz * cz * 2.0) - 1.0;
c = (((((-3.0 * c2a) + 4.0 ) * f) + 4.0) * c2a * f) / 16.0;
d = x;
t = ((((e * cy * c) + cz) * sy * c) + y) * sa;
x = ((1.0 - c) * t * f) + coordEndLonRad - coordStartLonRad;
// Make sure this function does not go into an infinite loop...
if (fabs (d - x) > 0.00000000005) {
exitLoop = 0;
} else {
exitLoop = 1;
}
++loopCount;
}
bearingStartToEnd = atan2 (tan1, tan2);
bearingEndToStart = atan2 (c1 * sinX, ((bearingEndToStart * cosX)
- (s1 * c2))) + PI;
t = sqrt ((((1.0 / r / r) - 1) * c2a) + 1.0) + 1.0;
x = (t - 2.0) / t;
t = 1.0 - x;
c = (((x * x) / 4.0) + 1.0) / t;
d = ((0.375 * (x * x)) - 1.0) * x;
x *= cy;
s = (1.0 - e) - e;
t1 = (sy * sy * 4.0) - 3.0;
t2 = ((s * cz * d) / 6.0) - x;
t3 = t1 * t2;
t4 = ((t3 * d) / 4.0) + cz;
t5 = (t4 * sy * d ) + y;
dist = t5 * c * a * r;
bearingStartToEnd *= RAD_TO_DEG;
bearingEndToStart *= RAD_TO_DEG;
// Make sure the bearings are between 0 and 360, inclusive.
bearingStartToEnd = mod (bearingStartToEnd, 360.0);
bearingEndToStart = mod (bearingEndToStart, 360.0);
}
void TypedCoord::distAndBearingWGS84 (double startLat, double startLon,
double endLat, double endLon, double& dist, double& bearingStartToEnd,
double& bearingEndToStart) const
// Purpose:
// This function calculates the distance between two coordinates on the Earth
// and determines the bearing to the coordinates in the forward and the
// reverse direction.
// Pre:
// startLat and endLat does not equal 90 or -90 degrees.
// Parameters:
// See TypedCoord::DistAndBearing().
{
distAndBearing (6378137.0, 1 / 298.257223563, startLat, startLon, endLat,
endLon, dist, bearingStartToEnd, bearingEndToStart);
}
void TypedCoord::getLatLonCoord (double& lat, double& lon) const
// Purpose:
// This function returns the latitude and longitude contained within this
// object.
{
lat = m_lat;
lon = m_lon;
}
void TypedCoord::setFixQuality (GPS_FIX_QUALITY fixQuality)
// Purpose:
// This function sets the fix quality of the coordinate. Use this function
// to store the quality of the fix from a GPS with the coordinate.
{
m_fixQuality = fixQuality;
}
// TypedCoord.h: Definition of the CTypedCoord abstract base class.
//
// The CTypedCoord class is an abstract base class whose derived classes
// represents a WGS84 coordinate with a specific type. For example, a UTM
// coordinate class can be derived from the CTypedCoord class. These classes
// store a coordinate in the class' coordinate type.
//
// Since a GPS uses lat/lon format for its coordinates, and distance/bearing
// formulas require lat/lon coordinates, CTypedCoord contains a latitude and
// a longitude member variable; member functions exist for converting between
// the lat/lon coordinate and the class' coordinate type.
//
// Conversion of coordinates from lat/lon to another format can be very
// computationally intensive, especially on machines without FPUs. Because
// of this, it is encouraged that derived classes use lazy evaluation when
// returning coordinates, so the conversions take place only when necessary.
// Because of the lazy evaluation, derived classes should not access the
// coordinate member variables directly; use the GetLatLonCoord() and the
// SetLatLonCoord() member functions to access and/or modify these variables.
//
// Since this is an abstract base class, you *must* override the following
// member functions in your derived classes:
// - GetCoordType(): Override this member function to return the type of this
// object. Each derived class from CTypedCoord has a unique type ID that
// specified the type of this object. Add a value to the enumerated type
// COORD_TYPE when deriving a new class, and return this value from this
// function. The COORD_TYPE enumerated type is found elsewhere in this
// project.
// - CreateCoordString(): Override this member function to create a formatted
// coordinate std::string using the coordinate within the class.
// - CreateXYCoordStrings(): Override this member function to create two
// formatted std::strings containing the x and y coordinate values;
// - GetXYCoord(): Override this member function to return the (x, y)
// coordinate values. This function is useful when the other data (e.g.,
// zones, etc.) are not needed.
// - CreateDisplayStrings: Override this function to create four std::strings that
// can be used for display purposes. The four std::strings contain coordinate
// data; these std::strings are displayed at the top left, top right, bottom
// left, and bottom right of a display. For example:
// A lat/lon coordinate class may create std::strings as follows:
// - top left: North/south hemisphere character
// - top right: Latitude
// - bottom left: East/west hemisphere character
// - bottom right: Longitude
// This would create a display as follows:
// N 48*25'33.3"
// W 123*20'09.8"
// A UTM coordinate class may create std::strings as follows:
// - top left: UTM zone (e.g., "10U")
// - top right: UTM easting
// - bottom left A std::string describing the coordinate type ("UTM")
// - bottom right: UTM northing
// This would create a display as follows:
// 10U 475139
// UTM 5363695
// It is up to the calling function to write the std::strings to a display.
//
// Member functions that can (and should) be overridden include:
// - SetLatLonCoord(): Override this member function to set the current lat/
// lon coordinate within this class and convert the lat/lon coordinate to
// the appropriate coordinate type so it can be stored within this class.
// - GetLatLonCoord(): Override this member function so that the lat/lon
// coordinate can be returned by converting the class' coordinate from the
// class' coordinate type.
// - operator=(): Override this operator to implement assignment operations.
// Two operator=() functions should be created as follows:
// - An operator=() function that takes a parameter of type CTypedCoord&.
// Use the GetLatLonCoord() function to convert the right hand side
// coordinate from its current type to a pair of lat/lon values, then
// call this class' SetLatLonCoord() function to convert the lat/lon pair
// to a coordinate of this class' type.
// - An operator=() function that takes a parameter of a reference to an
// object as the same type as the object. Simply copy all member
// variables from the right hand side object to this object.
//
// Using coordinate objects derived from this base class, it is simple to
// perform such operations as:
// - Finding the distance between two coordinate objects with different
// coordinate types.
// - Assigning the coordinates of an object of one coordinate type to another
// object with a different coordinate type.
//
// [TO DO: Allow for other map datums. For now, these coordinates are using
// the WGS84 datum.]
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#ifndef __TYPED_COORD_HPP
#define __TYPED_COORD_HPP
#include <string>
// Because of the way I hacked up the GPSThing code
// Needed for GPS_FIX_QUALITY
#include "nmeaParser.h"
enum COORD_TYPE
{
COORD_LATLON = 0,
COORD_UTM = 1
};
class TypedCoord
{
public:
TypedCoord () {m_lat = 0; m_lon = 0;}
virtual ~TypedCoord () {}
TypedCoord& operator= (const TypedCoord& other);
void calculateDistAndBearing (const TypedCoord& coord, double& dist,
double& dirStartToEnd, double& bearingEndToStart) const;
virtual const std::string& createCoordString (std::string& coordString) const
= 0;
virtual void createDisplayStrings (std::string& topLeftString,
std::string& topRightString, std::string& bottomLeftString,
std::string& bottomRightString) const = 0;
virtual void createXYCoordStrings (std::string& xString,
std::string& yString) const = 0;
virtual COORD_TYPE getCoordType () const = 0;
GPS_FIX_QUALITY getFixQuality () const
{return m_fixQuality;}
virtual void getLatLonCoord (double& lat, double& lon) const;
virtual void getXYCoord (double& x, double& y) const = 0;
void setFixQuality (GPS_FIX_QUALITY fixQuality);
virtual void setLatLonCoord (double lat, double lon)
{m_lat = lat; m_lon = lon;}
protected:
void distAndBearing (double a, double f, double startLat,
double startLon, double endLat, double endLon,
double& dist,
double& bearingStartToEnd,
double& bearingEndToStart) const;
void distAndBearingWGS84 (double startLat, double startLon,
double endLat, double endLon, double& dist,
double& bearingStartToEnd,
double& bearingEndToStart) const;
// Current lat/lon coordinate.
double m_lat;
double m_lon;
// Fix quality for the coordinate that originated from a GPS.
GPS_FIX_QUALITY m_fixQuality;
};
#endif // __TYPED_COORD_HPP
// UtmCoord.C: Implementaion of the CUtmCoord class.
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#include "gpsnmealib/typedCoord.h" // for TypedCoord
#include "utmCoord.h"
#ifdef sgi
#include <assert.h>
#include <math.h>
#else
#include <cassert> // for assert
#include <cmath> // for sin, cos, sqrt, M_PI
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// Radians to degrees conversion constants.
static const double RAD_TO_DEG = 180.0 / M_PI;
static const double DEG_TO_RAD = M_PI / 180.0;
// Some constants used by these functions.
static const double fe = 500000.0;
static const double ok = 0.9996;
// An array containing each vertical UTM zone.
static char cArray[] = "CDEFGHJKLMNPQRSTUVWX";
/////////////////////////////////////////////////////////////////////////////
// Miscellaneous functions for these UTM conversion formulas.
static double calculateESquared (double a, double b)
{
return ((a * a) - (b * b)) / (a * a);
}
static double calculateE2Squared (double a, double b)
{
return ((a * a) - (b * b)) / (b * b);
}
static double denom (double es, double sphi)
{
double sinSphi = sin (sphi);
return sqrt (1.0 - es * (sinSphi * sinSphi));
}
static double sphsr (double a, double es, double sphi)
{
double dn = denom (es, sphi);
return a * (1.0 - es) / (dn * dn * dn);
}
static double sphsn (double a, double es, double sphi)
{
double sinSphi = sin (sphi);
return a / sqrt (1.0 - es * (sinSphi * sinSphi));
}
static double sphtmd (double ap, double bp, double cp, double dp, double ep,
double sphi)
{
return (ap * sphi) - (bp * sin (2.0 * sphi)) + (cp * sin (4.0 * sphi))
- (dp * sin (6.0 * sphi)) + (ep * sin (8.0 * sphi));
}
/////////////////////////////////////////////////////////////////////////////
// UTMCoord construction/destruction
UTMCoord::UTMCoord ()
{
m_requireLatLonConvert = false;
m_requireUTMConvert = false;
setLatLonCoord (0.0, 0.0);
}
UTMCoord::UTMCoord (int utmXZone, char utmYZone, double easting,
double northing)
{
m_requireLatLonConvert = false;
m_requireUTMConvert = false;
setUTMCoord (utmXZone, utmYZone, easting, northing);
}
UTMCoord::UTMCoord (const UTMCoord& other)
{
copyUTMCoord (other);
}
UTMCoord::UTMCoord (const TypedCoord& other)
{
copyOtherCoord (other);
}
/////////////////////////////////////////////////////////////////////////////
// UTMCoord operators
UTMCoord& UTMCoord::operator= (const UTMCoord& other)
{
copyUTMCoord (other);
return *this;
}
UTMCoord& UTMCoord::operator= (const TypedCoord& other)
{
copyOtherCoord (other);
return *this;
}
/////////////////////////////////////////////////////////////////////////////
// UTMCoord members
void UTMCoord::copyUTMCoord (const UTMCoord& other)
// Purpose:
// This function copies the UTM coordinate of the specified object and
// assigns that coordinate to this object.
// Notes:
// This function copies every member function from that object, including
// its lat/lon value and its lazy evaluation flags.
{
m_lat = other.m_lat;
m_lon = other.m_lon;
m_utmXZone = other.m_utmXZone;
m_utmYZone = other.m_utmYZone;
m_easting = other.m_easting;
m_northing = other.m_northing;
m_requireLatLonConvert = other.m_requireLatLonConvert;
m_requireUTMConvert = other.m_requireUTMConvert;
}
void UTMCoord::copyOtherCoord (const TypedCoord& other)
// Purpose:
// This function copies the coordinate of the specified object, converts
// the coordinate to the coordinate type of this object, then assigns the
// converted coordinate to this object.
{
// Convert the right hand side coordinate to lat/lon; then convert this
// lat/lon coordinate to UTM.
double lat, lon;
other.getLatLonCoord (lat, lon);
setLatLonCoord (lat, lon);
}
const std::string& UTMCoord::createCoordString (std::string& coordString) const
// Purpose:
// This function creates a formatted coordinate string containing this
// object's coordinate.
// Parameters:
// CString& coordString:
// Upon exit, this parameter will contain the coordinate string.
// Returns:
// The coordinate string.
// Notes:
// If the coordinate is outside of the UTM grid boundary (>= 84 N or <= 80 S)
// the string will contain the resource string specified by the constant
// IDS_OUTSIDE_UTM_BOUNDARY.
{
double easting;
double northing;
int utmXZone;
char utmYZone;
getUTMCoord (utmXZone, utmYZone, easting, northing);
#if 0
if (utmYZone != '*') {
coordString.Format ("%02d%c %06d %07d", utmXZone, utmYZone,
(int)easting, (int)northing);
} else {
// UTM vertical zone is out of range.
coordString.LoadString (IDS_OUTSIDE_UTM_BOUNDARY);
}
#endif
return coordString;
}
void UTMCoord::createDisplayStrings (std::string& topLeftString,
std::string& topRightString, std::string& bottomLeftString,
std::string& bottomRightString) const
// Purpose:
// This function creates four strings that can be used for display; these
// strings contain coordinate data. The four strings are for the top left,
// top right, bottom left, and bottom right text of a display; each string
// is specified as follows:
// - top left: UTM zone
// - top right: Easting
// - bottom left: "UTM"
// - bottom right: Northing
// Notes:
// It is up to the calling function to write these strings to the display.
{
#if 0
bottomLeftString.LoadString (IDS_UTM);
if (IsOutsideUTMGrid () == false) {
// Extract the elements of the coordinate string.
CString coordString;
CreateCoordString (coordString);
topLeftString = coordString.Mid (UTM_ZONE_POS, UTM_ZONE_LEN);
topRightString = coordString.Mid (UTM_EASTING_POS, UTM_EASTING_LEN);
bottomRightString = coordString.Mid (UTM_NORTHING_POS,
UTM_NORTHING_LEN);
} else {
// The coordinate is outside of the UTM grid boundary, so the
// coordiante strings are empty.
topLeftString = "";
topRightString = "";
bottomRightString = "";
}
#endif
}
void UTMCoord::createXYCoordStrings (std::string& xString, std::string& yString)
const
// Purpose:
// This function generates two strings: a string containing the easting
// coordinate (stored in the parameter xString), and a string containing the
// northing coordinate (stored in the parameter yString.)
{
double easting;
double northing;
int utmXZone;
char utmYZone;
getUTMCoord (utmXZone, utmYZone, easting, northing);
#if 0
xString.Format ("%06d", (int)easting);
yString.Format ("%07d", (int)northing);
#endif
}
void UTMCoord::getLatLonCoord (double& lat, double& lon) const
// Purpose:
// This function converts the object's UTM coordinate to a lat/lon coordinate
// and returns the latitude and longitude.
{
if (m_requireLatLonConvert == true) {
// The conversion between UTM and lat/lon has not occurred yet, so do
// the conversion now. A non-const pointer to this object must be
// created so that this function can convert the UTM coordinate stored
// within this object to a lat/lon coordinate if the conversion is
// necessary. This lat/lon coordinate is then copied to the m_lat
// and m_lon members of this object, requiring the object to be
// non-const.
UTMCoord* myThis = const_cast<UTMCoord*>(this);
// Convert to lat/lon.
utmToLatLonWGS84 (myThis->m_utmXZone, myThis->m_utmYZone,
myThis->m_easting, myThis->m_northing, myThis->m_lat,
myThis->m_lon);
// Do not make this conversion again (unless the coordinates have been
// changed and another conversion is required.)
myThis->m_requireLatLonConvert = false;
}
lat = m_lat;
lon = m_lon;
}
void UTMCoord::getUTMCoord (int& utmXZone, char& utmYZone, double& easting,
double& northing) const
// Purpose:
// This function returns the current UTM coordinate.
{
if (m_requireUTMConvert == true) {
// The conversion between lat/lon and UTM has not occurred yet, so do
// the conversion now. A non-const pointer to this object must be
// created so that this function can convert the lat/lon coordinate
// stored within this object to a UTM coordinate if the conversion
// is necessary. This UTM coordinate is then copied to the m_utmXZone
// m_utmYZone, m_easting, and m_northing members of this object,
// requiring the object to be non-const.
UTMCoord* myThis = const_cast<UTMCoord*>(this);
// Convert to UTM.
latLonToUTMWGS84 (myThis->m_utmXZone, myThis->m_utmYZone,
myThis->m_easting, myThis->m_northing, myThis->m_lat,
myThis->m_lon);
// Do not make this conversion again (unless the coordinates have been
// changed and another conversion is required.)
myThis->m_requireUTMConvert = false;
}
easting = m_easting;
northing = m_northing;
utmXZone = m_utmXZone;
utmYZone = m_utmYZone;
}
void UTMCoord::getUTMZone (int& utmXZone, char& utmYZone) const
// Purpose:
// This function returns the current UTM zone.
// Parameters:
// int& utmXZone:
// Upon exit, this parameter contains the UTM horizontal zone. This
// zone will be between 1 and 60, inclusive.
// char& utmYZone:
// Upon exit, this parameter contains the UTM vertical zone. This
// zone will be one of: CDEFGHJKLMNPQRSTUVWX.
{
double easting;
double northing;
getUTMCoord (utmXZone, utmYZone, easting, northing);
}
void UTMCoord::getXYCoord (double& x, double& y) const
// Purpose:
// This function returns the coordinate's (x, y) coordinate. For this class,
// the x coordinate is the easting, and the y coordinate is the northing.
{
int utmXZone;
char utmYZone;
getUTMCoord (utmXZone, utmYZone, x, y);
}
bool UTMCoord::isOutsideUTMGrid () const
// Purpose:
// This function determines whether the current coordinate is outside of the
// UTM grid boundary (i.e., >= 84 N or <= 80 s)
{
// If a UTM coordinate has been converted to a lat/lon coordinate by lazy
// evaluation, simply determine whether the coordinate is north of 84, or
// south of 80.
if (m_requireLatLonConvert == false) {
if (m_lat >= 84.0 || m_lat <= -80.0) {
return true;
} else {
return false;
}
} else if (m_requireUTMConvert == false) {
if (m_utmYZone == '*') {
return true;
} else {
return false;
}
} else {
// This should not happen
assert(false);
return false;
}
}
void UTMCoord::latLonToUTM (double a, double f, int& utmXZone, char& utmYZone,
double& easting, double& northing, double lat, double lon) const
// Purpose:
// This function converts the specified lat/lon coordinate to a UTM
// coordinate.
// Parameters:
// double a:
// Ellipsoid semi-major axis, in meters. (For WGS84 datum, use 6378137.0)
// double f:
// Ellipsoid flattening. (For WGS84 datum, use 1 / 298.257223563)
// int& utmXZone:
// Upon exit, this parameter will contain the hotizontal zone number of
// the UTM coordinate. The returned value for this parameter is a number
// within the range 1 to 60, inclusive.
// char& utmYZone:
// Upon exit, this parameter will contain the zone letter of the UTM
// coordinate. The returned value for this parameter will be one of:
// CDEFGHJKLMNPQRSTUVWX.
// double& easting:
// Upon exit, this parameter will contain the UTM easting, in meters.
// double& northing:
// Upon exit, this parameter will contain the UTM northing, in meters.
// double lat, double lon:
// The lat/lon coordinate to convert.
// Notes:
// - The code in this function is a C conversion of some of the source code
// from the Mapping Datum Transformation Software (MADTRAN) program,
// written in PowerBasic. To get the source code for MADTRAN, go to:
//
// http://164.214.2.59/publications/guides/MADTRAN/index.html
//
// and download MADTRAN.ZIP
// - If the UTM zone is out of range, the y-zone character is set to the
// asterisk character ('*').
{
double recf;
double b;
double eSquared;
double e2Squared;
double tn;
double ap;
double bp;
double cp;
double dp;
double ep;
double olam;
double dlam;
double s;
double c;
double t;
double eta;
double sn;
double tmd;
double t1, t2, t3, t6, t7;
double nfn;
if (lon <= 0.0) {
utmXZone = 30 + (int)(lon / 6.0);
} else {
utmXZone = 31 + (int)(lon / 6.0);
}
if (lat < 84.0 && lat >= 72.0) {
// Special case: zone X is 12 degrees from north to south, not 8.
utmYZone = cArray[19];
} else {
utmYZone = cArray[(int)((lat + 80.0) / 8.0)];
}
if (lat >= 84.0 || lat < -80.0) {
// Invalid coordinate; the vertical zone is set to the invalid
// character.
utmYZone = '*';
}
double latRad = lat * DEG_TO_RAD;
double lonRad = lon * DEG_TO_RAD;
recf = 1.0 / f;
b = a * (recf - 1.0) / recf;
eSquared = calculateESquared (a, b);
e2Squared = calculateE2Squared (a, b);
tn = (a - b) / (a + b);
ap = a * (1.0 - tn + 5.0 * ((tn * tn) - (tn * tn * tn)) / 4.0 + 81.0 *
((tn * tn * tn * tn) - (tn * tn * tn * tn * tn)) / 64.0);
bp = 3.0 * a * (tn - (tn * tn) + 7.0 * ((tn * tn * tn)
- (tn * tn * tn * tn)) / 8.0 + 55.0 * (tn * tn * tn * tn * tn) / 64.0)
/ 2.0;
cp = 15.0 * a * ((tn * tn) - (tn * tn * tn) + 3.0 * ((tn * tn * tn * tn)
- (tn * tn * tn * tn * tn)) / 4.0) / 16.0;
dp = 35.0 * a * ((tn * tn * tn) - (tn * tn * tn * tn) + 11.0
* (tn * tn * tn * tn * tn) / 16.0) / 48.0;
ep = 315.0 * a * ((tn * tn * tn * tn) - (tn * tn * tn * tn * tn)) / 512.0;
olam = (utmXZone * 6 - 183) * DEG_TO_RAD;
dlam = lonRad - olam;
s = sin (latRad);
c = cos (latRad);
t = s / c;
eta = e2Squared * (c * c);
sn = sphsn (a, eSquared, latRad);
tmd = sphtmd (ap, bp, cp, dp, ep, latRad);
t1 = tmd * ok;
t2 = sn * s * c * ok / 2.0;
t3 = sn * s * (c * c * c) * ok * (5.0 - (t * t) + 9.0 * eta + 4.0
* (eta * eta)) / 24.0;
if (latRad < 0.0) nfn = 10000000.0; else nfn = 0;
northing = nfn + t1 + (dlam * dlam) * t2 + (dlam * dlam * dlam
* dlam) * t3 + (dlam * dlam * dlam * dlam * dlam * dlam) + 0.5;
t6 = sn * c * ok;
t7 = sn * (c * c * c) * (1.0 - (t * t) + eta) / 6.0;
easting = fe + dlam * t6 + (dlam * dlam * dlam) * t7 + 0.5;
if (northing >= 9999999.0) northing = 9999999.0;
}
void UTMCoord::latLonToUTMWGS84 (int& utmXZone, char& utmYZone,
double& easting, double& northing, double lat, double lon) const
// Purpose:
// This function converts the specified lat/lon coordinate to a UTM
// coordinate in the WGS84 datum. (See the comment block for the
// LatLonToUTM() member function.)
{
latLonToUTM (6378137.0, 1 / 298.257223563, utmXZone, utmYZone,
easting, northing, lat, lon);
}
void UTMCoord::setLatLonCoord (double lat, double lon)
// Purpose:
// This function sets the UTM coordinate given a latitude and a longitude.
{
m_lat = lat;
m_lon = lon;
// No conversion between UTM and lat/lon is necessary, since this function
// has set a new lat/lon coordinate.
m_requireLatLonConvert = false;
// Do not perform the conversion between lat/lon and UTM now; wait until
// the user requests the UTM coordinate.
m_requireUTMConvert = true;
}
void UTMCoord::setUTMCoord (int utmXZone, char utmYZone, double easting,
double northing)
{
m_easting = easting;
m_northing = northing;
m_utmXZone = utmXZone;
m_utmYZone = utmYZone;
// Do not perform the conversion between UTM and lat/lon now; wait until
// the user requests the lat/lon coordinate.
m_requireLatLonConvert = true;
// No conversion between lat/lon and UTM is necessary, since this function
// has set a new UTM coordinate.
m_requireUTMConvert = false;
}
void UTMCoord::utmToLatLon (double a, double f, int utmXZone, char utmYZone,
double easting, double northing, double& lat, double& lon) const
// Purpose:
// This function converts the specified UTM coordinate to a lat/lon
// coordinate.
// Pre:
// - utmXZone must be between 1 and 60, inclusive.
// - utmYZone must be one of: CDEFGHJKLMNPQRSTUVWX
// Parameters:
// double a:
// Ellipsoid semi-major axis, in meters. (For WGS84 datum, use 6378137.0)
// double f:
// Ellipsoid flattening. (For WGS84 datum, use 1 / 298.257223563)
// int utmXZone:
// The horizontal zone number of the UTM coordinate.
// char utmYZone:
// The vertical zone letter of the UTM coordinate.
// double easting, double northing:
// The UTM coordinate to convert.
// double& lat:
// Upon exit, lat contains the latitude.
// double& lon:
// Upon exit, lon contains the longitude.
// Notes:
// The code in this function is a C conversion of some of the source code
// from the Mapping Datum Transformation Software (MADTRAN) program, written
// in PowerBasic. To get the source code for MADTRAN, go to:
//
// http://164.214.2.59/publications/guides/MADTRAN/index.html
//
// and download MADTRAN.ZIP
{
double recf;
double b;
double eSquared;
double e2Squared;
double tn;
double ap;
double bp;
double cp;
double dp;
double ep;
double nfn;
double tmd;
double sr;
double sn;
double ftphi;
double s;
double c;
double t;
double eta;
double de;
double dlam;
double olam;
recf = 1.0 / f;
b = a * (recf - 1) / recf;
eSquared = calculateESquared (a, b);
e2Squared = calculateE2Squared (a, b);
tn = (a - b) / (a + b);
ap = a * (1.0 - tn + 5.0 * ((tn * tn) - (tn * tn * tn)) / 4.0 + 81.0 *
((tn * tn * tn * tn) - (tn * tn * tn * tn * tn)) / 64.0);
bp = 3.0 * a * (tn - (tn * tn) + 7.0 * ((tn * tn * tn)
- (tn * tn * tn * tn)) / 8.0 + 55.0 * (tn * tn * tn * tn * tn) / 64.0)
/ 2.0;
cp = 15.0 * a * ((tn * tn) - (tn * tn * tn) + 3.0 * ((tn * tn * tn * tn)
- (tn * tn * tn * tn * tn)) / 4.0) / 16.0;
dp = 35.0 * a * ((tn * tn * tn) - (tn * tn * tn * tn) + 11.0
* (tn * tn * tn * tn * tn) / 16.0) / 48.0;
ep = 315.0 * a * ((tn * tn * tn * tn) - (tn * tn * tn * tn * tn)) / 512.0;
if ((utmYZone <= 'M' && utmYZone >= 'C')
|| (utmYZone <= 'm' && utmYZone >= 'c')) {
nfn = 10000000.0;
} else {
nfn = 0;
}
tmd = (northing - nfn) / ok;
sr = sphsr (a, eSquared, 0.0);
ftphi = tmd / sr;
double t10, t11, t14, t15;
for (int i = 0; i < 5; i++) {
t10 = sphtmd (ap, bp, cp, dp, ep, ftphi);
sr = sphsr (a, eSquared, ftphi);
ftphi = ftphi + (tmd - t10) / sr;
}
sr = sphsr (a, eSquared, ftphi);
sn = sphsn (a, eSquared, ftphi);
s = sin (ftphi);
c = cos (ftphi);
t = s / c;
eta = e2Squared * (c * c);
de = easting - fe;
t10 = t / (2.0 * sr * sn * (ok * ok));
t11 = t * (5.0 + 3.0 * (t * t) + eta - 4.0 * (eta * eta) - 9.0 * (t * t)
* eta) / (24.0 * sr * (sn * sn * sn) * (ok * ok * ok * ok));
lat = ftphi - (de * de) * t10 + (de * de * de * de) * t11;
t14 = 1.0 / (sn * c * ok);
t15 = (1.0 + 2.0 * (t * t) + eta) / (6 * (sn * sn * sn) * c
* (ok * ok * ok));
dlam = de * t14 - (de * de * de) * t15;
olam = (utmXZone * 6 - 183.0) * DEG_TO_RAD;
lon = olam + dlam;
lon *= RAD_TO_DEG;
lat *= RAD_TO_DEG;
}
void UTMCoord::utmToLatLonWGS84 (int utmXZone, char utmYZone, double easting,
double northing, double& lat, double& lon) const
// Purpose:
// This function converts the specified UTM coordinate to a lat/lon
// coordinate in the WGS84 datum. (See the comment block for the
// UTMToLatLon() member function.
{
utmToLatLon (6378137.0, 1 / 298.257223563, utmXZone, utmYZone,
easting, northing, lat, lon);
}
// UtmCoord.h: Definition of the CUtmCoord class.
//
// This class represents a coordinate on the UTM grid.
//
// Like all other typed coordinate classes, this class contains an internal
// lat/lon coordinate. This lat/lon coordinate is created by converting the
// lat/lon coordinate from a UTM coordinate. Since either lat/lon or UTM can
// be set and read, a conversion may be necessary from one type to another.
// This conversion is quite slow on machines without FPUs, so these conver-
// sions are done internally only when the converted coordinates are required
// by code using a UTM object (this is known as 'lazy evaluation.') In order
// to implement this lazy evaluation code, this class uses member functions
// to access the coordinates (since those member functions modify the lazy
// evaluation flags), rather than manipulating the coordinates directly.
//
// If the lat/lon coordinate contained within an object of this class is
// outside of the UTM grid boundary (>= 84 N or <= 80 S), the vertical UTM
// zone character is set to an asterisk ('*'). You can check the vertical
// UTM zone contained within this class to determine if the coordinate is
// outside of the UTM grid boundary.
//
// Written by Jason Bevins in 1998. File is in the public domain.
//
#ifndef __UTM_COORD_HPP
#define __UTM_COORD_HPP
#include <string> // for string
#include "typedCoord.h" // for COORD_TYPE, etc
// These constants are used by the CreateDisplayStrings() and the
// CreateXYCoordStrings() functions to parse the string generated by the
// CreateCoordString() function. Modify these constants when you modify the
// code that generates the string. These constants do not affect the code
// that generate these strings, but you may write parsing functions that
// require the positions of the individual elements in the strings.
const int UTM_ZONE_POS = 0;
const int UTM_ZONE_LEN = 3;
const int UTM_EASTING_POS = 4;
const int UTM_EASTING_LEN = 6;
const int UTM_NORTHING_POS = 11;
const int UTM_NORTHING_LEN = 7;
class UTMCoord: public TypedCoord
{
public:
UTMCoord ();
UTMCoord (int utmXZone, char utmYZone, double easting,
double northing);
UTMCoord (const TypedCoord& other);
UTMCoord (const UTMCoord& other);
void copyUTMCoord (const UTMCoord& other);
void copyOtherCoord (const TypedCoord& other);
UTMCoord& operator= (const UTMCoord& other);
UTMCoord& operator= (const TypedCoord& other);
virtual const std::string& createCoordString (std::string& coordString) const;
virtual void createDisplayStrings (std::string& topLeftString,
std::string& topRightString, std::string& bottomLeftString,
std::string& bottomRightString) const;
virtual void createXYCoordStrings (std::string& xString, std::string& yString)
const;
virtual COORD_TYPE getCoordType () const {return COORD_UTM;}
virtual void getLatLonCoord (double& lat, double& lon) const;
virtual void getUTMCoord (int& utmXZone, char& utmYZone,
double& easting, double& northing) const;
void getUTMZone (int& utmXZone, char& utmYZone) const;
virtual void getXYCoord (double& x, double& y) const;
bool isOutsideUTMGrid () const;
virtual void setLatLonCoord (double lat, double lon);
virtual void setUTMCoord (int utmXZone, char utmYZone, double easting,
double northing);
protected:
// Lazy evaluation flags.
mutable bool m_requireLatLonConvert;
mutable bool m_requireUTMConvert;
// UTM conversion functions.
void latLonToUTM (double a, double f, int& utmXZone, char& utmYZone,
double& easting, double& northing, double lat, double lon) const;
void latLonToUTMWGS84 (int& utmXZone, char& utmYZone, double& easting,
double& northing, double lat, double lon) const;
void utmToLatLon (double a, double f, int utmXZone, char utmYZone,
double easting, double northing, double& lat, double& lon) const;
void utmToLatLonWGS84 (int utmXZone, char utmYZone, double easting,
double northing, double& lat, double& lon) const;
// UTM values.
mutable int m_utmXZone;
mutable char m_utmYZone;
mutable double m_easting;
mutable double m_northing;
};
#endif // _UTM_COORD_HPP
if(NOT VRPN_BUILD_SERVER_LIBRARY OR NOT VRPN_USE_HID)
message(FATAL_ERROR
"Cannot compile HID gui without the full (server) library and HID support. Enable it and try again.")
endif()
set(VRPN_SERVER_LIBRARY vrpnserver)
if(NOT WIN32)
set(VRPN_ATMEL_LIBRARY vrpn_atmel)
endif()
set(SOURCES
HIDDevice.cpp
Inspector.cpp
main.cpp
MainWindow.cpp
QuickChart.cpp)
set(HEADERS)
set(MOCS
HIDDevice.h
Inspector.h
MainWindow.h
QuickChart.h)
set(UIS
mainwindow.ui
plot.ui)
find_package(Qt4 4.7)
if(QT_FOUND)
include(${QT_USE_FILE})
qt4_wrap_ui(GENERATED_SOURCES ${UIS})
qt4_wrap_cpp(GENERATED_SOURCES ${MOCS})
source_group("Generated Sources - Do Not Edit"
FILES
${GENERATED_SOURCES})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Build and link the app!
add_executable(vrpn_hid_gui
MACOSX_BUNDLE
${SOURCES}
${GENERATED_SOURCES}
${HEADERS}
${UIS}
${MOCS}
${RESOURCES})
target_link_libraries(vrpn_hid_gui ${QT_LIBRARIES} vrpnserver)
endif()
/**
@file
@brief Implementation
@date 2011
@author
Ryan Pavlik
<rpavlik@iastate.edu> and <abiryan@ryand.net>
http://academic.cleardefinition.com/
Iowa State University Virtual Reality Applications Center
Human-Computer Interaction Graduate Program
*/
// Copyright Iowa State University 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Internal Includes
#include "HIDDevice.h"
#include "vrpn_HumanInterface.h"
// Library/third-party includes
#include <QDateTime>
// Standard includes
// - none
class HIDDevice::VRPNDevice : public vrpn_HidInterface {
HIDDevice * _container;
public:
VRPNDevice(vrpn_HidAcceptor * acceptor, HIDDevice * container)
: vrpn_HidInterface(acceptor)
, _container(container)
{}
protected:
void on_data_received(size_t bytes, vrpn_uint8 *buffer) {
_container->send_data_signal(bytes, reinterpret_cast<char *>(buffer));
}
};
HIDDevice::HIDDevice(vrpn_HidAcceptor * acceptor, QObject * parent)
: QObject(parent)
, _connected(false)
, _device(new VRPNDevice(acceptor, this))
, _startingTimestamp(-1) {}
HIDDevice::~HIDDevice() {
delete _device;
_device = NULL;
}
void HIDDevice::do_update() {
bool wasConnected = _connected;
_connected = _device->connected();
if (_connected && !wasConnected) {
emit message("Connected to device!");
} else if (!_connected && wasConnected) {
emit message("Lost connection to device!");
}
_device->update();
}
void HIDDevice::send_data_signal(size_t bytes, const char * buffer) {
qint64 current = QDateTime::currentMSecsSinceEpoch();
if (_startingTimestamp < 0) {
_startingTimestamp = current;
}
emit inputReport(QByteArray(buffer, bytes), current - _startingTimestamp);
}
void HIDDevice::send_message_signal(QString const& msg) {
emit message(msg);
}
/** @file
@brief Header
@date 2011
@author
Ryan Pavlik
<rpavlik@iastate.edu> and <abiryan@ryand.net>
http://academic.cleardefinition.com/
Iowa State University Virtual Reality Applications Center
Human-Computer Interaction Graduate Program
*/
// Copyright Iowa State University 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
// Internal Includes
#include "vrpn_Shared.h"
// Library/third-party includes
#include <QObject>
#include <QByteArray>
#include <QString>
// Standard includes
// - none
class vrpn_HidAcceptor;
/// Qt wrapper for a debugging HidInterface.
class HIDDevice: public QObject {
Q_OBJECT
public:
explicit HIDDevice(vrpn_HidAcceptor * acceptor, QObject * parent = NULL);
~HIDDevice();
signals:
void inputReport(QByteArray buffer, qint64 timestamp);
void message(QString const& msg);
public slots:
void do_update();
protected:
bool _connected;
class VRPNDevice;
friend class HIDDevice::VRPNDevice;
void send_data_signal(size_t bytes, const char * buffer);
void send_message_signal(QString const& msg);
VRPNDevice * _device;
qint64 _startingTimestamp;
};
/**
@file
@brief Implementation
@date 2011
@author
Ryan Pavlik
<rpavlik@iastate.edu> and <abiryan@ryand.net>
http://academic.cleardefinition.com/
Iowa State University Virtual Reality Applications Center
Human-Computer Interaction Graduate Program
*/
// Copyright Iowa State University 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Internal Includes
#include "Inspector.h"
#include "vrpn_Shared.h"
// Library/third-party includes
// - none
// Standard includes
#include <stdexcept>
#include <iostream>
//#include <stdint.h>
template<typename T>
T getFromByteArray(QByteArray const& input) {
union {
char bytes[sizeof(T)];
T value;
};
for (int i = 0; i < sizeof(T); ++i) {
bytes[i] = input.at(i);
}
return value;
}
Inspector::Inspector(std::size_t first_index, std::size_t length, bool signedVal, bool bigEndian, QObject * parent)
: QObject(parent)
, _first(first_index)
, _length(length)
, _signed(signedVal)
, _bigEndian(bigEndian) {
switch (_length) {
case 1:
case 2:
case 4:
break;
default:
throw std::logic_error("Can't get an integer with that many bytes!");
}
}
void Inspector::updatedData(QByteArray buf, qint64 timestamp) {
QByteArray myPortion;
myPortion.reserve(_length);
if (!_bigEndian) {
myPortion = buf.mid(_first, _length);
} else {
unsigned i;
for (i = 0; i < _length; ++i) {
myPortion.prepend(buf.at(_first + i));
}
}
switch (_length) {
case 1:
_sendNewValue(timestamp, _signed ?
myPortion.at(0)
: getFromByteArray<vrpn_uint8>(myPortion));
break;
case 2:
_sendNewValue(timestamp, _signed ?
getFromByteArray<vrpn_int16>(myPortion) :
getFromByteArray<vrpn_uint16>(myPortion));
break;
case 4:
_sendNewValue(timestamp, _signed ?
getFromByteArray<vrpn_int32>(myPortion) :
getFromByteArray<vrpn_uint32>(myPortion));
break;
}
}
void Inspector::_sendNewValue(qint64 timestamp, float val) {
emit newValue(val);
emit newValue(float(timestamp) / 1000.0f, val);
}