diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..24687ac
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+novatel_oem7/bin/liboem7decoder.a filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3986aec
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+.bash_history
+.bloom_logs
+.catkin_workspace
+.ros
+.viminfo
+build
+devel
+install
+doc
+src/CMakeLists.txt
+*.pyc
+*.deb
+*.ddeb
+debian
+obj-*
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..09ed338
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+MIT
+
+Copyright (c) 2020 NovAtel Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e769544
--- /dev/null
+++ b/README.md
@@ -0,0 +1,638 @@
+# NovAtel OEM7 Driver
+[**ROS**](www.ros.org) Driver for [**NovAtel**](www.novatel.com) OEM7 GNSS Receivers.
+
+
+
+
BETA Driver
+This driver is considered pre-release at this time. This is provided as-is. Please refer to the bundled license.
+
+
+
+
+## Getting Started
+
+### Prerequisites
+* ROS Kinetic or Melodic, including gps-common and tf ROS packages.
+* Obtain OEM7 receiver.
+
+
+### Installation
+#### Option A: Install binary package
+```
+sudo apt-get install ros-${ROS_DISTRO}-novatel-oem7-driver
+```
+
+#### Option B: Build from source (docker)
+These instructions assume that you are using Ubuntu 18.04.
+
+1. Install Docker, add the user you intend on using to the 'docker' group.
+1. From the base directory of the repository, run `./docker/run-melodic-build.sh` (this may take >10mins)
+1. From within your docker container (where the prompt from above should land), run `./build.sh -f`
+
+#### Option C: Build from source (local environment)
+Here are approximate instructions for building this driver with your local ROS development environment. Please note this is for reference. The Docker approach is recommended.
+
+1. Install ROS with developer support to your environment
+1. Install ROS dependencies gps-common, tf
+ Ex: `sudo apt install ros-melodic-gps-common ros-melodic-tf`
+1. Run `source /opt/ros/melodic/setup.bash`
+1. Set `ROS_DISTRO` environment variable (Ex: `ROS_DISTRO=melodic`)
+1. Run `bash envsetup.sh`
+1. Run build: `./build.sh -f`
+
+
+## Basic Operation with OEM7 receiver
+
+### Operation using TCP/IP
+
+Use default TCP/IP port '3001'. Refer to the OEM7 receiver [manual](https://docs.novatel.com/OEM7/Content/Home.htm) for more details on ICOM ports.
+
+```shell
+roslaunch novatel_oem7_driver oem7_net.launch oem7_ip_addr:=10.128.224.56
+```
+
+
+### Operation using UDP/IP
+
+By default (factory reset), OEM7 receivers do not support UDP connections. An ICOM port must be configured for UDP and **the configuration saved.**
+
+Using a terminal program, connect to OEM7 COM port as described in OEM7 manual and enter :
+```
+ICOMCONFIG ICOM2 UDP ":3002"
+SAVECONFIG
+```
+Then
+```shell
+roslaunch novatel_oem7_driver oem7_net.launch oem7_if:=Oem7ReceiverUdp `oem7_ip_addr:=10.128.224.56 oem7_port:=3002
+```
+Refer to "ICOMCONFIG" command in OEM7 receiver manual.
+
+
+### Operation Using Serial Port (TTY)
+
+
+```shell
+roslaunch novatel_oem7_driver oem7_tty.launch oem7_tty_name:=/dev/ttyUSB0
+```
+
+To (optionally) set a specific baud rate, e.g. 115200, set **oem7_tty_baud**:=115200
+Ensure that the baud rate of receiver port matches; the driver does ***not*** automatically configure receiver baud rate.
+Setting the baud rate is required for physical RS232 ports.
+
+In order to use USB ports, install OEM7 USB [drivers](https://docs.novatel.com/OEM7/Content/Operation/USB_Communications.htm).
+Setting the baud rate is not required for USB serial ports.
+
+
+
+### ROS Parameter namespace layout
+
+The driver uses standard ROS relative parameter addressing, with some parameters private to the nodelets.
+
+The default namespace is outlined below. The namespace structure can be changed in the .launch and .xml files.
+
+
+**/novatel/oem7**
+Overall driver namespace; global driver paramerers.
+
+**/novatel/oem7/receivers**
+OEM7 Receiver instances
+
+**/novatel/oem7/receivers/main**
+OEM7 Receiver instance: interface (TCP/IP, TTY) parameters, initialization commands, published topics, etc.
+
+
+
+
+
+
+## Customization
+
+### Configuring your own initialization commands
+
+The **/novatel/oem7/receivers/main/receiver_init_commands** parameter holds the list of commands to be executed on driver startup.
+There are no semantics checking of any kind; it is the user's responsibility to ensure correctness.
+By default, this list is populated from ***$(find novatel_oem7_driver)/config/std_init_commands.yaml***
+
+
+This list can be overriden using standard ROS parameter mechanisms.
+
+
+
+Notes:
+
+1. In order to be processed by the driver, logs must be in OEM7 "binary' format, e.g. "BESTPOS**B**"
+
+
+
+### Configuring topic parameters:
+
+Topic name and reference frame are configured by adding the following parameter under /novatel/oem7/receivers/main
+
+```
+$message_name{topic: $topic_name, frame_id:$id, queue_size: "$size"}
+```
+
+INSCONFIG
+```
+INSCONFIG: {topic: /gps/insconfig, frame_id: gps, queue_size: "10"}
+```
+The default configuration is populated from "$(find novatel_oem7_driver)/config/std_msg_topics.yaml"
+
+
+
+### Other Configuration Files
+
+The .launch files includes other configuration files:
+
+
+$(find novatel_oem7_driver)/config/**std_oem7_raw_msgs.yaml**
+The list of OEM7 messages to logged as blobs for postprocessing. Refer to novatel_oem7_msg/Oem7RawMsg.msg
+
+
+
+$(find novatel_oem7_driver)/config/**std_driver_config.xml**
+$(find novatel_oem7_driver)/config/**std_msg_handlers.yaml**
+Various driver plugins to be loaded; there is no need to modify these unless you are developing your own plugins or optimizing the driver.
+
+
+
+$(find novatel_oem7_driver)/config/**oem7_msgs.yaml**
+A map of OEM7 message names / IDs.
+Messages not in this list will be ignored by the driver. Typically, this does not need modification, unless you are optimizing the driver.
+
+
+
+### ROS Message Generation
+
+ROS messages are derived ("synthesized") from multiple OEM7 messages.
+Consult documentation in $(find novatel_oem7_driver)/config/std_init_commands.yaml
+
+
+
+### Runtime Receiver Reconfiguration
+
+The driver implements ROS Service "**/novatel_oem7_driver/receivers/main/Oem7Cmd**" which sends OEM7 Abbreviated ASCII commands from Linux terminal using "rosservice" tool:
+```
+rosservice call /novatel/oem7/receivers/main/Oem7Cmd "$oem7_abbreviated_ascii_command"
+```
+OEM7 response is printed out verbatim.
+
+Example:
+```
+rosservice call /novatel/oem7/receivers/main/Oem7Cmd "LOG BESTPOSB ONTIME 0.1"
+rsp: "OK"
+```
+
+
+
+All standard OEM7 abbreviated ascii commands are supported. The commands are executed "as-is"; the syntax is not modified.
+
+
+
+
+### Error Detection and Recovery
+
+There is no internal recovery mechanism; whenever the driver goes into an error state, message publishing stops. The user is responsible for detection of this condition.
+Recovery is achieved by reloading the driver (Message and Config nodelets).
+
+
+
+
+
+### Built-in Self-Test (BIST)
+
+Standard driver installation supports BIST, which can be used to evaluate if the driver is operating normally.
+BIST is lauched by using rostest instead of roslaunch, by specifying "oem7_bist:=true" parameter with your standard .launch file.
+
+For example, to run BIST with an oem7_net.launch file:
+
+```
+**rostest** --text novatel_oem7_driver oem7_net.launch oem7_ip_addr:=10.128.224.56 **oem7_bist:=true**
+
+BIST outputs topic statistics, similar to the "rostopic hz" command:
+
+
+... topic: '/gps/gps', exp interval= 0.02. samples= 2945:
+
+mean, max, stdev
+
+Bag Recording interval: 0.0200001721311, 0.127890110016, 0.00589703421274
+
+Message publish interval: 0.0200002559501, 0.119542121887, 0.00569331898041
+
+Bag Rec - Message Pub Delta: 0.000302689346676, 0.0227742195129, 0.000916649615432
+
+
+
+topic: '/novatel/oem7/inspva', exp interval= 0.02. samples= 2918:
+
+mean, max, stdev
+
+Bag Recording interval: 0.0199991217369, 0.0854535102844, 0.0049107521279
+
+Message publish interval: 0.0199991563922, 0.0838820934296, 0.00478976290435
+
+Bag Rec - Message Pub Delta: 0.000299763973647, 0.0198292732239, 0.000763679984502
+
+
+
+topic: '/novatel/oem7/time', exp interval= 1.0. samples= 57:
+
+mean, max, stdev
+
+Bag Recording interval: 0.999989598989, 1.0087621212, 0.0045717348049
+
+Message publish interval: 0.999993549926, 1.00874257088, 0.00458939860791
+
+Bag Rec - Message Pub Delta: 0.000231772138361, 0.000780344009399, 0.000111371446655
+
+
+
+topic: '/gps/fix', exp interval= 0.02. samples= 2886:
+
+mean, max, stdev
+
+Bag Recording interval: 0.0200002543021, 0.078773021698, 0.00453926745601
+
+Message publish interval: 0.0200003352901, 0.0766448974609, 0.00433987262471
+
+Bag Rec - Message Pub Delta: 0.000307747992227, 0.0275449752808, 0.00098472728123
+
+
+
+topic: '/novatel/oem7/bestpos', exp interval= 0.1. samples= 573:
+
+mean, max, stdev
+
+Bag Recording interval: 0.100003437979, 0.144937515259, 0.0112068678576
+
+Message publish interval: 0.100003776017, 0.144729137421, 0.0111951734664
+
+Bag Rec - Message Pub Delta: 0.000227286137419, 0.00631713867188, 0.000422261912593
+
+
+
+topic: '/gps/imu', exp interval= 0.01. samples= 5922:
+
+mean, max, stdev
+
+Bag Recording interval: 0.00999986636157, 0.127390623093, 0.00506395854586
+
+Message publish interval: 0.0099998703077, 0.118784427643, 0.00485288752033
+
+Bag Rec - Message Pub Delta: 0.000257168738917, 0.0433497428894, 0.00116386292041
+
+
+
+topic: '/novatel/oem7/inspvax', exp interval= 1.0. samples= 59:
+
+mean, max, stdev
+
+Bag Recording interval: 0.999823825113, 1.02793908119, 0.00850038277189
+
+Message publish interval: 0.999849241355, 1.02734613419, 0.00816920128965
+
+Bag Rec - Message Pub Delta: 0.000262191740133, 0.00299835205078, 0.000491497024532
+
+
+
+topic: '/novatel/oem7/bestvel', exp interval= 0.1. samples= 587:
+
+mean, max, stdev
+
+Bag Recording interval: 0.0998391059478, 0.159289360046, 0.0127196007736
+
+Message publish interval: 0.0998426366585, 0.151807785034, 0.012558915178
+
+Bag Rec - Message Pub Delta: 0.000218554290434, 0.00764131546021, 0.000507693107715
+
+
+
+topic: '/novatel/oem7/corrimu', exp interval= 0.01. samples= 5746:
+
+mean, max, stdev
+
+Bag Recording interval: 0.00999978424882, 0.0556886196136, 0.00387268651204
+
+Message publish interval: 0.00999978275482, 0.040646314621, 0.00370057604793
+
+Bag Rec - Message Pub Delta: 0.000260806108575, 0.0385403633118, 0.000954403421047
+
+
+
+topic: '/novatel/oem7/bestutm', exp interval= 1.0. samples= 58:
+
+mean, max, stdev
+
+Bag Recording interval: 0.999384821507, 1.0226817131, 0.00724017624648
+
+Message publish interval: 0.999406969338, 1.02262759209, 0.00715263035281
+
+Bag Rec - Message Pub Delta: 0.000181029582846, 0.00139737129211, 0.000200204160647
+
+
+
+topic: '/novatel/oem7/insstdev', exp interval= 1.0. samples= 57:
+
+mean, max, stdev
+
+Bag Recording interval: 1.00011486241, 1.01120710373, 0.00461768586745
+
+Message publish interval: 1.00011816195, 1.01120328903, 0.00446202626225
+
+Bag Rec - Message Pub Delta: 0.000224979300248, 0.00264716148376, 0.000435574278454
+
+
+
+ok
+
+
+
+----------------------------------------------------------------------
+
+Ran 2 tests in 106.496s
+
+
+
+OK
+
+-------------------------------------------------------------
+
+SUMMARY:
+
+* RESULT: SUCCESS
+
+* TESTS: 2
+
+* ERRORS: 0 []
+
+* FAILURES: 0 []
+```
+
+
+### Sample Driver Output
+
+```
+SUMMARY
+========
+
+PARAMETERS
+* /novatel/oem7/oem7_msgs/BDSEPHEMERIS: 1696
+* /novatel/oem7/oem7_msgs/BESTPOS: 42
+* /novatel/oem7/oem7_msgs/BESTUTM: 726
+* /novatel/oem7/oem7_msgs/BESTVEL: 99
+* /novatel/oem7/oem7_msgs/CORRIMUS: 2264
+* /novatel/oem7/oem7_msgs/GALFNAVEPHEMERIS: 1310
+* /novatel/oem7/oem7_msgs/GALINAVEPHEMERIS: 1309
+* /novatel/oem7/oem7_msgs/GLOEPHEMERIS: 723
+* /novatel/oem7/oem7_msgs/HEADING2: 1335
+* /novatel/oem7/oem7_msgs/IMURATECORRIMUS: 1362
+* /novatel/oem7/oem7_msgs/INSCONFIG: 1945
+* /novatel/oem7/oem7_msgs/INSPVAS: 508
+* /novatel/oem7/oem7_msgs/INSPVAX: 1465
+* /novatel/oem7/oem7_msgs/INSSTDEV: 2051
+* /novatel/oem7/oem7_msgs/INSUPDATESTATUS: 1825
+* /novatel/oem7/oem7_msgs/PSRDOP2: 1163
+* /novatel/oem7/oem7_msgs/RANGE: 43
+* /novatel/oem7/oem7_msgs/RAWEPHEM: 41
+* /novatel/oem7/oem7_msgs/RAWIMUSX: 1462
+* /novatel/oem7/oem7_msgs/RXSTATUS: 93
+* /novatel/oem7/oem7_msgs/TIME: 101
+* /novatel/oem7/receivers/main/BESTPOS/frame_id: gps
+* /novatel/oem7/receivers/main/BESTPOS/topic: /novatel/oem7/bes...
+* /novatel/oem7/receivers/main/BESTUTM/frame_id: gps
+* /novatel/oem7/receivers/main/BESTUTM/topic: /novatel/oem7/bes...
+* /novatel/oem7/receivers/main/BESTVEL/frame_id: gps
+* /novatel/oem7/receivers/main/BESTVEL/topic: /novatel/oem7/bes...
+* /novatel/oem7/receivers/main/CORRIMU/frame_id: gps
+* /novatel/oem7/receivers/main/CORRIMU/topic: /novatel/oem7/cor...
+* /novatel/oem7/receivers/main/GPSFix/frame_id: gps
+* /novatel/oem7/receivers/main/GPSFix/topic: /gps/gps
+* /novatel/oem7/receivers/main/HEADING2/frame_id: gps
+* /novatel/oem7/receivers/main/HEADING2/topic: /novatel/oem7/hea...
+* /novatel/oem7/receivers/main/IMU/frame_id: gps
+* /novatel/oem7/receivers/main/IMU/topic: /gps/imu
+* /novatel/oem7/receivers/main/INSCONFIG/frame_id: gps
+* /novatel/oem7/receivers/main/INSCONFIG/queue_size: 10
+* /novatel/oem7/receivers/main/INSCONFIG/topic: /novatel/oem7/ins...
+* /novatel/oem7/receivers/main/INSPVA/frame_id: gps
+* /novatel/oem7/receivers/main/INSPVA/topic: /novatel/oem7/inspva
+* /novatel/oem7/receivers/main/INSPVAX/frame_id: gps
+* /novatel/oem7/receivers/main/INSPVAX/queue_size: 10
+* /novatel/oem7/receivers/main/INSPVAX/topic: /novatel/oem7/ins...
+* /novatel/oem7/receivers/main/INSSTDEV/frame_id: gps
+* /novatel/oem7/receivers/main/INSSTDEV/queue_size: 10
+* /novatel/oem7/receivers/main/INSSTDEV/topic: /novatel/oem7/ins...
+* /novatel/oem7/receivers/main/NavSatFix/frame_id: gps
+* /novatel/oem7/receivers/main/NavSatFix/topic: /gps/fix
+* /novatel/oem7/receivers/main/Oem7RawMsg/frame_id: gps
+* /novatel/oem7/receivers/main/Oem7RawMsg/queue_size: 200
+* /novatel/oem7/receivers/main/Oem7RawMsg/topic: /novatel/oem7/oem...
+* /novatel/oem7/receivers/main/RXSTATUS/frame_id: gps
+* /novatel/oem7/receivers/main/RXSTATUS/queue_size: 10
+* /novatel/oem7/receivers/main/RXSTATUS/topic: /novatel/oem7/rxs...
+* /novatel/oem7/receivers/main/TIME/frame_id: gps
+* /novatel/oem7/receivers/main/TIME/topic: /novatel/oem7/time
+* /novatel/oem7/receivers/main/oem7_if: Oem7ReceiverTcp
+* /novatel/oem7/receivers/main/oem7_ip_addr: 10.128.224.50
+* /novatel/oem7/receivers/main/oem7_msg_decoder: Oem7MessageDecoder
+* /novatel/oem7/receivers/main/oem7_msg_handlers: ['BESTPOSHandler'...
+* /novatel/oem7/receivers/main/oem7_port: 3001
+* /novatel/oem7/receivers/main/oem7_raw_msgs: ['BESTPOS', 'BEST...
+* /novatel/oem7/receivers/main/receiver_init_commands: ['UNLOGALL THISPO...
+* /novatel/oem7/supported_imus/0/name: Unknown
+* /novatel/oem7/supported_imus/0/rate: 0
+* /novatel/oem7/supported_imus/1/name: Honeywell HG1700 AG1
+* /novatel/oem7/supported_imus/1/rate: 100
+* /novatel/oem7/supported_imus/11/name: Honeywell HG1700 ...
+* /novatel/oem7/supported_imus/11/rate: 100
+* /novatel/oem7/supported_imus/12/name: Honeywell HG1700 ...
+* /novatel/oem7/supported_imus/12/rate: 100
+* /novatel/oem7/supported_imus/13/name: iMAR ilMU-FSAS
+* /novatel/oem7/supported_imus/13/rate: 200
+* /novatel/oem7/supported_imus/16/name: KVH CPT IMU
+* /novatel/oem7/supported_imus/16/rate: 200
+* /novatel/oem7/supported_imus/19/name: Northrop Grumman ...
+* /novatel/oem7/supported_imus/19/rate: 200
+* /novatel/oem7/supported_imus/20/name: Honeywell HG1930 ...
+* /novatel/oem7/supported_imus/20/rate: 100
+* /novatel/oem7/supported_imus/26/name: Northrop Grumman ...
+* /novatel/oem7/supported_imus/26/rate: 100
+* /novatel/oem7/supported_imus/27/name: Honeywell HG1900 ...
+* /novatel/oem7/supported_imus/27/rate: 100
+* /novatel/oem7/supported_imus/28/name: Honeywell HG1930 ...
+* /novatel/oem7/supported_imus/28/rate: 100
+* /novatel/oem7/supported_imus/31/name: Analog Devices AD...
+* /novatel/oem7/supported_imus/31/rate: 200
+* /novatel/oem7/supported_imus/32/name: Sensonor STIM300
+* /novatel/oem7/supported_imus/32/rate: 125
+* /novatel/oem7/supported_imus/33/name: KVH1750 IMU
+* /novatel/oem7/supported_imus/33/rate: 200
+* /novatel/oem7/supported_imus/4/name: Honeywell HG1700 ...
+* /novatel/oem7/supported_imus/4/rate: 100
+* /novatel/oem7/supported_imus/41/name: Epson G320N
+* /novatel/oem7/supported_imus/41/rate: 125
+* /novatel/oem7/supported_imus/45/name: KVH 1725 IMU?
+* /novatel/oem7/supported_imus/45/rate: 200
+* /novatel/oem7/supported_imus/5/name: Honeywell HG1700 ...
+* /novatel/oem7/supported_imus/5/rate: 100
+* /novatel/oem7/supported_imus/52/name: Litef microIMU
+* /novatel/oem7/supported_imus/52/rate: 200
+* /novatel/oem7/supported_imus/56/name: Sensonor STIM300,...
+* /novatel/oem7/supported_imus/56/rate: 125
+* /novatel/oem7/supported_imus/58/name: Honeywell HG4930 ...
+* /novatel/oem7/supported_imus/58/rate: 200
+* /novatel/oem7/supported_imus/61/name: Epson G370N
+* /novatel/oem7/supported_imus/61/rate: 200
+* /novatel/oem7/supported_imus/62/name: Epson G320N - 200Hz
+* /novatel/oem7/supported_imus/62/rate: 200
+* /novatel/oem7/supported_imus/8/name: Northrop Grumman ...
+* /novatel/oem7/supported_imus/8/rate: 200
+* /rosdistro: melodic
+* /rosversion: 1.14.3
+
+NODES
+/novatel/oem7/
+driver (nodelet/nodelet)
+/novatel/oem7/receivers/
+main (nodelet/nodelet)
+/novatel/oem7/receivers/main/
+config (nodelet/nodelet)
+
+auto-starting new master
+process[master]: started with pid [95]
+ROS_MASTER_URI=[http://localhost:11311](http://localhost:11311/)
+
+setting /run_id to 3c58ff7a-5825-11ea-af66-0242ac110002
+process[rosout-1]: started with pid [106]
+started core service [/rosout]
+process[novatel/oem7/driver-2]: started with pid [113]
+[ INFO] [1582672757.580037186]: Initializing nodelet with 1 worker threads.
+process[novatel/oem7/receivers/main-3]: started with pid [114]
+[ INFO] [1582672758.427979153]: Loading nodelet /novatel/oem7/receivers/main of type novatel_oem7_driver/Oem7MessageNodelet to manager /novatel/oem7/driver with the following remappings:
+[ INFO] [1582672758.482685569]: /novatel/oem7/receivers/main: Oem7MessageNodelet v.0.1.5; Feb 25 2020 23:10:59
+[ INFO] [1582672758.491468200]: Oem7MessageDecoderLib version: 0.1.0
+[ INFO] [1582672758.501851170]: topic [/novatel/oem7/bestpos]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.506864595]: topic [/novatel/oem7/bestvel]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.520382178]: topic [/novatel/oem7/bestutm]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.522930675]: topic [/novatel/oem7/inspva]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.525848469]: topic [/gps/gps]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.531813975]: topic [/gps/fix]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.539888495]: topic [/gps/imu]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.546775428]: topic [/novatel/oem7/corrimu]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.561730288]: topic [/novatel/oem7/insstdev]: frame_id: 'gps'; q size: 10
+[ INFO] [1582672758.566235059]: topic [/novatel/oem7/inspvax]: frame_id: 'gps'; q size: 10
+[ INFO] [1582672758.568718145]: topic [/novatel/oem7/insconfig]: frame_id: 'gps'; q size: 10
+[ INFO] [1582672758.575187796]: topic [/novatel/oem7/heading2]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.586377975]: topic [/novatel/oem7/rxstatus]: frame_id: 'gps'; q size: 10
+[ INFO] [1582672758.597258756]: topic [/novatel/oem7/time]: frame_id: 'gps'; q size: 100
+[ INFO] [1582672758.608667707]: Oem7 Raw message 'BESTPOS' will be published.
+[ INFO] [1582672758.608896692]: Oem7 Raw message 'BESTVEL' will be published.
+[ INFO] [1582672758.609316891]: Oem7 Raw message 'INSPVAX' will be published.
+[ INFO] [1582672758.609700340]: Oem7 Raw message 'INSUPDATESTATUS' will be published.
+[ INFO] [1582672758.610101790]: Oem7 Raw message 'RAWIMUSX' will be published.
+[ INFO] [1582672758.610435285]: Oem7 Raw message 'RAWEPHEM' will be published.
+[ INFO] [1582672758.610800972]: Oem7 Raw message 'GLOEPHEMERIS' will be published.
+[ INFO] [1582672758.611205708]: Oem7 Raw message 'BDSEPHEMERIS' will be published.
+[ INFO] [1582672758.611586715]: Oem7 Raw message 'GALFNAVEPHEMERIS' will be published.
+[ INFO] [1582672758.611931563]: Oem7 Raw message 'GALINAVEPHEMERIS' will be published.
+[ INFO] [1582672758.612324055]: Oem7 Raw message 'RANGE' will be published.
+[ INFO] [1582672758.612752046]: Oem7 Raw message 'HEADING2' will be published.
+[ INFO] [1582672758.613338666]: Oem7 Raw message 'TIME' will be published.
+[ INFO] [1582672758.619745586]: Oem7 Raw message 'RXSTATUS' will be published.
+[ INFO] [1582672758.620168469]: Oem7 Raw message 'INSCONFIG' will be published.
+[ INFO] [1582672758.625131610]: topic [/novatel/oem7/oem7raw]: frame_id: 'gps'; q size: 200
+[ INFO] [1582672758.645420418]: Oem7Net TCP['10.128.224.50' : 3001]
+[ INFO] [1582672758.648501360]: Oem7Net socket open: '1; OS error= 0
+process[novatel/oem7/receivers/main/config-4]: started with pid [123]
+[ INFO] [1582672759.522221729]: Loading nodelet /novatel/oem7/receivers/main/config of type novatel_oem7_driver/Oem7ConfigNodelet to manager /novatel/oem7/driver with the following remappings:
+[ INFO] [1582672759.532702445]: /novatel/oem7/receivers/main/config: Oem7ConfigNodelet v.0.1.5; Feb 25 2020 23:10:59
+[ INFO] [1582672759.549198962]: AACmd 'UNLOGALL THISPORT' : 'OK'
+[ INFO] [1582672759.555651969]: AACmd 'LOG INSCONFIGB ONCE' : 'OK'
+[ INFO] [1582672759.557937765]: IMU: 'Epson G320N', rate= 125
+[ INFO] [1582672759.563950339]: AACmd 'LOG INSCONFIGB ONTIME 300' : 'OK'
+[ INFO] [1582672759.570031172]: AACmd 'LOG RXSTATUSB ONCHANGED' : 'OK'
+[ INFO] [1582672759.692688310]: AACmd 'LOG BESTPOSB ONTIME 0.1' : 'OK'
+[ INFO] [1582672759.699932134]: AACmd 'LOG BESTVELB ONTIME 0.1' : 'OK'
+[ INFO] [1582672759.708925767]: AACmd 'LOG BESTUTMB ONTIME 1' : 'OK'
+[ INFO] [1582672759.717126078]: AACmd 'LOG HEADING2B ONNEW' : 'OK'
+[ INFO] [1582672759.968983558]: AACmd 'LOG PSRDOP2B ONCHANGED' : 'OK'
+[ INFO] [1582672759.979083113]: AACmd 'LOG INSPVASB ONTIME 0.02' : 'OK'
+[ INFO] [1582672759.989194363]: AACmd 'LOG INSPVAXB ONTIME 1' : 'OK'
+[ INFO] [1582672760.110518011]: AACmd 'LOG CORRIMUSB ONTIME 0.01' : 'OK'
+[ INFO] [1582672760.117430487]: AACmd 'LOG INSSTDEVB ONTIME 1' : 'OK'
+[ INFO] [1582672760.127582549]: AACmd 'LOG TIMEB ONTIME 1' : 'OK'
+[ INFO] [1582672760.250652075]: AACmd 'LOG RAWIMUSXB ONNEW' : 'OK'
+[ INFO] [1582672760.259886196]: AACmd 'LOG INSUPDATESTATUSB ONNEW' : 'OK'
+[ INFO] [1582672760.268288028]: AACmd 'LOG RAWEPHEMB ONNEW' : 'OK'
+[ INFO] [1582672760.441192318]: AACmd 'LOG GLOEPHEMERISB ONNEW' : 'OK'
+[ INFO] [1582672760.452404856]: AACmd 'LOG BDSEPHEMERISB ONNEW' : 'OK'
+[ INFO] [1582672760.463694659]: AACmd 'LOG GALFNAVEPHEMERISB ONNEW' : 'OK'
+[ INFO] [1582672760.476838316]: AACmd 'LOG GALINAVEPHEMERISB ONNEW' : 'OK'
+[ INFO] [1582672760.485394230]: AACmd 'LOG RANGEB ONTIME 1' : 'OK'
+[ INFO] [1582672760.486592625]: Oem7 configuration completed.
+[ INFO] [1582672793.168160450]: Log Statistics:
+[ INFO] [1582672793.170725228]: Logs: 10000; discarded: 37
+[ INFO] [1582672793.171424835]: Log[RAWEPHEM](41):10
+[ INFO] [1582672793.171991321]: Log[BESTPOS](42):335
+[ INFO] [1582672793.172548012]: Log[RANGE](43):33
+[ INFO] [1582672793.173131571]: Log[RXSTATUS](93):1
+[ INFO] [1582672793.173925225]: Log[BESTVEL](99):335
+[ INFO] [1582672793.174466830]: Log[TIME](101):33
+[ INFO] [1582672793.175082019]: Log[INSPVAS](508):1660
+[ INFO] [1582672793.177104558]: Log[GLOEPHEMERIS](723):8
+[ INFO] [1582672793.177702006]: Log[BESTUTM](726):34
+[ INFO] [1582672793.178415540]: Log[PSRDOP2](1163):2
+[ INFO] [1582672793.182107115]: Log[HEADING2](1335):34
+[ INFO] [1582672793.182548463]: Log[RAWIMUSX](1462):4130
+[ INFO] [1582672793.183634882]: Log[INSPVAX](1465):33
+[ INFO] [1582672793.187078494]: Log[INSCONFIG](1945):2
+[ INFO] [1582672793.191874451]: Log[INSSTDEV](2051):33
+[ INFO] [1582672793.192099653]: Log[CORRIMUS](2264):3317
+```
+
+#### Output Interpretation:
+
+
+```
+[ INFO] [1582672759.692688310]: AACmd 'LOG BESTPOSB ONTIME 0.1' : 'OK'
+```
+Initialization command sent, "OK" response received.
+
+
+
+
+```
+[ INFO] [1582672759.557937765]: IMU: 'Epson G320N', rate= 12
+```
+Detected IMU and assumed data rate.
+
+
+
+
+```
+Logs: 10000; discarded: 37
+```
+10000 logs received and processed; 37 logs or message fragments discarded.
+Discarded fragments during receiver configuration are normal. However, continuously increasing number of discarded fragments during stable operation indicates misconfiguration.
+Received OEM7 Message statistics are output periodically.
+
+
+
+```
+Log[BESTPOS](42):335
+```
+335 BESTPOS logs (ID=42) received.
+
+
+
+## Authors
+
+* [**NovAtel**](https://www.novatel.com), part of [**Hexagon**](https://hexagon.com)
+
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
+
+
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..de1b2fc
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+print_usage()
+{
+ echo "Build novatel_oem7_driver"
+ echo "Usage: "
+ echo " $0 -h"
+ echo " $0 [-c] [-d | -r] [-p] [-t]"
+ echo
+ echo "Where:"
+ echo " -h: Print this help message and exit."
+ echo " -c: Clean all intermediate files."
+ echo " -d: Build debug binaries"
+ echo " -r: Build release binaries; can't be combined with -d"
+ echo " -t: Run tests using local binaries."
+ echo " -p: Build .deb package(s)"
+ echo " -f: Full build, equivalent to '$0 -crtp'"
+ echo
+ echo "Examples"
+ echo " '$0' Build local binaries; used for local development."
+ echo " '$0 -f' Full build: Used for production artifacts."
+ echo " '$0 -r' Release build, no tests or .deb packages"
+ echo " '$0 -cd' Clean Debug build, no packages."
+}
+
+
+
+build_deb_pkg()
+{
+ ./create-$ROS_DISTRO-package.sh
+}
+
+
+INSTALL=
+CLEAN=
+DEBUG_FLAG=
+ROSDOC=
+BUILD_DEB_PKG=
+RUN_TESTS=
+
+
+while getopts "hcdrpft" OPT; do
+ case $OPT in
+ h )
+ print_usage
+ exit 0
+ ;;
+
+ c )
+ CLEAN=clean
+ ;;
+
+ d )
+ INSTALL=install
+ DEBUG_FLAG=-DCMAKE_BUILD_TYPE=Debug
+ ;;
+
+ r )
+ INSTALL=install
+ DEBUG_FLAG=
+ ;;
+
+ p )
+ INSTALL=install
+ BUILD_DEB_PKG=build_deb_pkg
+ ;;
+
+ t )
+ RUN_TESTS=run_tests
+ ;;
+
+ f )
+ CLEAN=clean
+ INSTALL=install
+ BUILD_DEB_PKG=build_deb_pkg
+ RUN_TESTS=run_tests
+ ;;
+
+ * )
+ print_usage
+ exit 1
+ ;;
+ esac
+done
+
+
+
+if [[ $CLEAN ]];
+then
+ # Remove all intermediate and temporary files.
+ catkin_make clean
+ rm -rf .ros devel build doc install
+ rm -rf *.deb src/*.ddeb
+ rm -rf src/novatel_oem7_driver/debian src/novatel_oem7_driver/obj-*
+ rm -rf src/novatel_oem7_msgs/debian src/novatel_oem7_msgs/obj-*
+fi
+
+
+
+set -e
+
+. ./envsetup.sh
+
+# Build local artifacts
+catkin_make $DEBUG_FLAG $CLEAN $INSTALL $RUN_TESTS
+
+if [[ $INSTALL ]];
+then
+ rosdoc_lite src/novatel_oem7_driver -o doc
+ $BUILD_DEB_PKG
+fi
diff --git a/create-binary-package.sh b/create-binary-package.sh
new file mode 100755
index 0000000..45a5237
--- /dev/null
+++ b/create-binary-package.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+UBUNTU_TGT_DISTRO=$1
+ROS_TGT_DISTRO=$2
+
+rosdep init
+rosdep update
+
+rm *.deb
+rm src/*.deb
+./create-deb.sh $UBUNTU_TGT_DISTRO $ROS_TGT_DISTRO src/novatel_oem7_msgs
+./create-deb.sh $UBUNTU_TGT_DISTRO $ROS_TGT_DISTRO src/novatel_oem7_driver
+mv src/*.deb .
+
+
+
diff --git a/create-deb.sh b/create-deb.sh
new file mode 100755
index 0000000..45ba0d2
--- /dev/null
+++ b/create-deb.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+CALLED_FROM=$PWD
+cd $3
+
+rm -rf debian obj-*
+bloom-generate rosdebian --os-name ubuntu --os-version $1 --ros-distro $2
+
+
+fakeroot -- debian/rules binary
+
+cd $CALLED_FROM
+
+
+
+
diff --git a/create-kinetic-package.sh b/create-kinetic-package.sh
new file mode 100755
index 0000000..059e3ba
--- /dev/null
+++ b/create-kinetic-package.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+./create-binary-package.sh xenial kinetic
+
diff --git a/create-melodic-package.sh b/create-melodic-package.sh
new file mode 100755
index 0000000..cdf4bdb
--- /dev/null
+++ b/create-melodic-package.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+./create-binary-package.sh bionic melodic
+
diff --git a/create_eclipse_project.sh b/create_eclipse_project.sh
new file mode 100755
index 0000000..39b8ef6
--- /dev/null
+++ b/create_eclipse_project.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+catkin_make --force-cmake -G"Eclipse CDT4 - Unix Makefiles"
+awk -f $(rospack find mk)/eclipse.awk build/.project > build/.project_with_env && mv build/.project_with_env build/.project
+
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..e5b1357
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,5 @@
+from ros:kinetic
+
+
+
+
diff --git a/docker/Dockerfile.kinetic.build b/docker/Dockerfile.kinetic.build
new file mode 100644
index 0000000..a592d5a
--- /dev/null
+++ b/docker/Dockerfile.kinetic.build
@@ -0,0 +1,42 @@
+from ros:kinetic
+
+# Needed to deal with a recent key revocation, presumably melodic dockerfile will be updated eventually, and this can be remvoed.
+#sudo apt-key del 421C365BD9FF1F717815A3895523BAEEB01FA116
+#sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
+
+#sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
+#sudo apt-get update && sudo apt-get install -y sudo ros-kinetic-desktop ros-kinetic-catkin build-essential gdb
+
+#sudo apt-get install dh-make
+#rosdep init
+#rosdep update
+#sudo chown -R $( whoami) ~/.ros
+
+
+SHELL ["/bin/bash", "-c"]
+
+RUN apt-get update && apt-get install -y ros-kinetic-tf ros-kinetic-gps-umd ros-kinetic-rosdoc-lite dh-make python-bloom
+
+# Replace dash with bash
+#RUN rm /bin/sh && ln -s /bin/bash /bin/sh
+
+#----------------------------------
+# TODO - Not sure about this, since we want to run as your host user id. Might need to remove this build user.
+# User management
+RUN groupadd -g 1000 build
+RUN useradd -u 1000 -g 1000 -G sudo,build -ms /bin/bash build
+
+USER build
+#----------------------------------
+
+
+RUN rosdep init
+RUN rosdep update
+
+
+# bindmount source directory
+# Make /home/build the working directory. This will be mapped to a host directory on your machine.
+#WORKDIR /home/build
+
+# If no command is provided when the container is started, this will be run, giving you a shell inside the container as the 'build' user.
+CMD "/bin/bash"
diff --git a/docker/Dockerfile.kinetic.test b/docker/Dockerfile.kinetic.test
new file mode 100644
index 0000000..dee04dc
--- /dev/null
+++ b/docker/Dockerfile.kinetic.test
@@ -0,0 +1,24 @@
+from ros:kinetic
+
+# Needed to deal with a recent key revocation, presumably melodic dockerfile will be updated eventually, and this can be remvoed.
+#sudo apt-key del 421C365BD9FF1F717815A3895523BAEEB01FA116
+#sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
+
+#sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
+#sudo apt-get update && sudo apt-get install -y sudo ros-kinetic-desktop ros-kinetic-catkin build-essential gdb
+
+
+SHELL ["/bin/bash", "-c"]
+
+RUN apt-get update && apt-get install -y ros-kinetic-tf ros-kinetic-gps-umd vim sudo
+RUN apt install
+
+#----------------------------------
+# Create 'test:test' user/password in sudo group.
+RUN useradd -m test && echo "test:test" | chpasswd && adduser test sudo
+USER test
+#----------------------------------
+
+
+# If no command is provided when the container is started, this will be run, giving you a shell inside the container as the 'test' user.
+CMD "/bin/bash"
diff --git a/docker/Dockerfile.melodic.build b/docker/Dockerfile.melodic.build
new file mode 100644
index 0000000..79fdba5
--- /dev/null
+++ b/docker/Dockerfile.melodic.build
@@ -0,0 +1,38 @@
+from ros:melodic
+
+# Needed to deal with a recent key revocation, presumably melodic dockerfile will be updated eventually, and this can be remvoed.
+#sudo apt-key del 421C365BD9FF1F717815A3895523BAEEB01FA116
+#sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
+
+#sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
+#sudo apt-get update && sudo apt-get install -y sudo ros-kinetic-desktop ros-kinetic-catkin build-essential gdb
+
+#sudo apt-get install dh-make
+#rosdep init
+#rosdep update
+#sudo chown -R $( whoami) ~/.ros
+
+
+SHELL ["/bin/bash", "-c"]
+
+RUN apt-get update && apt-get install -y ros-melodic-rosdoc-lite ros-melodic-tf ros-melodic-gps-umd dh-make python-bloom vim
+
+# Replace dash with bash
+#RUN rm /bin/sh && ln -s /bin/bash /bin/sh
+
+#----------------------------------
+# TODO - Not sure about this, since we want to run as your host user id. Might need to remove this build user.
+# User management
+RUN groupadd -g 1000 build
+RUN useradd -u 1000 -g 1000 -G sudo,build,dialout -ms /bin/bash build
+USER build
+#----------------------------------
+
+
+
+# bindmount source directory
+# Make /home/build the working directory. This will be mapped to a host directory on your machine.
+#WORKDIR /home/build
+
+# If no command is provided when the container is started, this will be run, giving you a shell inside the container as the 'build' user.
+CMD "/bin/bash"
diff --git a/docker/Dockerfile.melodic.test b/docker/Dockerfile.melodic.test
new file mode 100644
index 0000000..a754d56
--- /dev/null
+++ b/docker/Dockerfile.melodic.test
@@ -0,0 +1,22 @@
+from ros:melodic
+
+# Needed to deal with a recent key revocation, presumably melodic dockerfile will be updated eventually, and this can be remvoed.
+#sudo apt-key del 421C365BD9FF1F717815A3895523BAEEB01FA116
+#sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
+
+#sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
+
+
+SHELL ["/bin/bash", "-c"]
+
+RUN apt-get update && apt-get install -y ros-melodic-tf ros-melodic-gps-umd vim sudo
+
+#----------------------------------
+# Create 'test:test' user/password in sudo group.
+RUN useradd -m test && echo "test:test" | chpasswd && adduser test sudo
+USER test
+#----------------------------------
+
+
+# If no command is provided when the container is started, this will be run, giving you a shell inside the container as the 'test' user.
+CMD "/bin/bash"
diff --git a/docker/run-distro-build.sh b/docker/run-distro-build.sh
new file mode 100755
index 0000000..f8ea4d2
--- /dev/null
+++ b/docker/run-distro-build.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+DISTRO=$1
+NAME=ros-$DISTRO-build
+docker build -t $NAME - < docker/Dockerfile.$DISTRO.build
+
+BLDDIR=/home/build
+docker run -ti --mount type=bind,source="$(pwd)",target=$BLDDIR -w $BLDDIR -u `id -u`:`id -g` --group-add sudo --rm $NAME:latest
+
diff --git a/docker/run-kinetic-build.sh b/docker/run-kinetic-build.sh
new file mode 100755
index 0000000..e2e5212
--- /dev/null
+++ b/docker/run-kinetic-build.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+NAME=ros-kinetic-build
+docker build -t $NAME - < docker/Dockerfile.kinetic.build
+
+BLDDIR=/home/build
+docker run -ti --mount type=bind,source="$(pwd)",target=$BLDDIR -w $BLDDIR -u `id -u`:`id -g` --group-add sudo --rm $NAME:latest
+
diff --git a/docker/run-kinetic-test.sh b/docker/run-kinetic-test.sh
new file mode 100755
index 0000000..473b339
--- /dev/null
+++ b/docker/run-kinetic-test.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+NAME=ros-kinetic-test
+docker build -t $NAME - < docker/Dockerfile.kinetic.test
+
+CONT_TESTDIR=/home/test
+HOST_TESTDIR=$(pwd)/docker-test
+docker run -ti --mount type=bind,source=$HOST_TESTDIR,target=$CONT_TESTDIR -w $CONT_TESTDIR -u `id -u`:`id -g` --group-add sudo --rm $NAME:latest
+
diff --git a/docker/run-melodic-build.sh b/docker/run-melodic-build.sh
new file mode 100755
index 0000000..71bd561
--- /dev/null
+++ b/docker/run-melodic-build.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./docker/run-distro-build.sh melodic
+
+
diff --git a/docker/run-melodic-test.sh b/docker/run-melodic-test.sh
new file mode 100755
index 0000000..1e92379
--- /dev/null
+++ b/docker/run-melodic-test.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+NAME=ros-melodic-test
+docker build -t $NAME - < docker/Dockerfile.melodic.test
+
+CONT_TESTDIR=/home/test
+HOST_TESTDIR=$(pwd)/docker-test
+docker run -ti --mount type=bind,source=$HOST_TESTDIR,target=$CONT_TESTDIR -w $CONT_TESTDIR -u `id -u`:`id -g` --group-add sudo --rm $NAME:latest
+
diff --git a/docker/run-test.sh b/docker/run-test.sh
new file mode 100755
index 0000000..3b158b8
--- /dev/null
+++ b/docker/run-test.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+docker build -t novatel_oem7_driver .
+docker run -ti --mount type=bind,source="$(pwd)",target=/test --rm novatel_oem7_driver:latest
diff --git a/envsetup.sh b/envsetup.sh
new file mode 100644
index 0000000..6c18640
--- /dev/null
+++ b/envsetup.sh
@@ -0,0 +1,12 @@
+
+source /opt/ros/$ROS_DISTRO/setup.bash
+
+# If no catkin environment is setup, create it
+if [ ! -d ./devel ]; then
+ echo "catkin environment does not exist; creating it. This runs the local build once as well."
+ catkin_make
+fi
+
+source ./devel/setup.bash
+
+
diff --git a/novatel_oem7/bin/liboem7decoder.a b/novatel_oem7/bin/liboem7decoder.a
new file mode 100644
index 0000000..8cdfa55
--- /dev/null
+++ b/novatel_oem7/bin/liboem7decoder.a
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:460c465ff8ab73e44bf9ab2ba79d040ecc1bb9d61bb44a7e2ed7fc12b61e9c6e
+size 111757832
diff --git a/novatel_oem7/include/oem7_message_decoder_lib.hpp b/novatel_oem7/include/oem7_message_decoder_lib.hpp
new file mode 100644
index 0000000..bfdc3c2
--- /dev/null
+++ b/novatel_oem7/include/oem7_message_decoder_lib.hpp
@@ -0,0 +1,66 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_MESSAGE_DECODER__
+#define __OEM7_MESSAGE_DECODER__
+
+#include
+
+#include
+#include
+
+
+
+namespace novatel_oem7
+{
+ typedef short version_element_t;
+
+ class Oem7MessageDecoderLibIf
+ {
+
+ public:
+ virtual ~Oem7MessageDecoderLibIf(){}
+ virtual bool readMessage(boost::shared_ptr&) = 0;
+
+ };
+
+ class Oem7MessageDecoderLibUserIf
+ {
+ public:
+ virtual ~Oem7MessageDecoderLibUserIf(){}
+ virtual bool read( boost::asio::mutable_buffer, size_t&) = 0;
+ };
+
+
+ boost::shared_ptr
+ GetOem7MessageDecoder(Oem7MessageDecoderLibUserIf*);
+
+ void
+ GetOem7MessageDecoderLibVersion(version_element_t& major, version_element_t& minor, version_element_t& build);
+}
+
+
+
+
+#endif
diff --git a/novatel_oem7/include/oem7_raw_message_if.hpp b/novatel_oem7/include/oem7_raw_message_if.hpp
new file mode 100644
index 0000000..5f4a8ba
--- /dev/null
+++ b/novatel_oem7/include/oem7_raw_message_if.hpp
@@ -0,0 +1,67 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_RAW_MESSAGE_IF_
+#define __OEM7_RAW_MESSAGE_IF_
+
+#include
+#include
+
+#include
+
+namespace novatel_oem7
+{
+ class Oem7RawMessageIf
+ {
+ public:
+
+ typedef boost::shared_ptr ConstPtr;
+
+ enum Oem7MessageType
+ {
+ OEM7MSGTYPE_LOG,
+ OEM7MSGTYPE_RSP,
+ OOEM7MSGTYPE_CMD,
+ OEM7MSGTYPE_UNKNOWN = 1000
+ };
+
+ enum Oem7MessageFormat
+ {
+ OEM7MSGFMT_BINARY,
+ OEM7MSGFMT_ASCII,
+ OEM7MSGFMT_ABASCII,
+ OEM7MSGFMT_UNKNOWN = 1000
+ };
+
+ virtual ~Oem7RawMessageIf(){}
+
+ virtual Oem7MessageType getMessageType() const = 0;
+ virtual Oem7MessageFormat getMessageFormat() const = 0;
+ virtual int getMessageId() const = 0;
+ virtual const uint8_t* getMessageData(size_t offset) const = 0;
+ virtual size_t getMessageDataLength() const = 0;
+ };
+}
+
+#endif
diff --git a/src/novatel_oem7_driver/CMakeLists.txt b/src/novatel_oem7_driver/CMakeLists.txt
new file mode 100644
index 0000000..0fb5cb3
--- /dev/null
+++ b/src/novatel_oem7_driver/CMakeLists.txt
@@ -0,0 +1,157 @@
+cmake_minimum_required(VERSION 2.8.3)
+project(novatel_oem7_driver)
+
+## Compile as C++11, supported in ROS Kinetic and newer
+add_compile_options(-std=c++11)
+
+# Without this line, .deb package build fails due to lpthread linking errors.
+set(novatel_oem7_msgs_DIR ${CMAKE_CURRENT_LIST_DIR}/../../install/share/novatel_oem7_msgs/cmake)
+
+
+set(BUILD_DEPS
+ nodelet
+ roscpp
+ std_msgs
+ nav_msgs
+ gps_common
+ sensor_msgs
+ tf
+ message_generation
+ novatel_oem7_msgs
+)
+
+
+find_package(catkin REQUIRED COMPONENTS ${BUILD_DEPS})
+find_package(Boost REQUIRED COMPONENTS system thread)
+find_package(novatel_oem7_msgs REQUIRED)
+
+
+###################################
+## catkin specific configuration ##
+###################################
+## The catkin_package macro generates cmake config files for your package
+## Declare things to be passed to dependent projects
+## INCLUDE_DIRS: uncomment this if your package contains header files
+## LIBRARIES: libraries you create in this project that dependent projects also need
+## CATKIN_DEPENDS: catkin_packages dependent projects also need
+## DEPENDS: system dependencies of this project that dependent projects also need
+catkin_package(
+ INCLUDE_DIRS include
+ LIBRARIES ${PROJET_NAME}
+ CATKIN_DEPENDS nodelet roscpp
+)
+
+# Make package available as a macro to C++
+add_definitions("-D${PROJECT_NAME}_VERSION=\"${${PROJECT_NAME}_VERSION}\"")
+
+###########
+## Build ##
+###########
+
+include_directories(include
+ ${catkin_INCLUDE_DIRS}
+ ${Boost_INCLUDE_DIRS}
+ ${novatel_oem7_msgs_INCLUDE_DIRS}
+ "../../novatel_oem7/include"
+ src
+)
+
+
+
+## All components are plugins
+add_library(${PROJECT_NAME}
+ src/oem7_log_nodelet.cpp
+ src/oem7_message_nodelet.cpp
+ src/oem7_config_nodelet.cpp
+ src/oem7_receiver_net.cpp
+ src/oem7_receiver_port.cpp
+ src/oem7_receiver_file.cpp
+ src/oem7_message_decoder.cpp
+ src/oem7_message_util.cpp
+ src/oem7_ros_messages.cpp
+ src/message_handler.cpp
+ src/bestpos_handler.cpp
+ src/ins_handler.cpp
+ src/align_handler.cpp
+ src/time_handler.cpp
+ src/receiverstatus_handler.cpp
+)
+
+
+add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
+
+
+FIND_LIBRARY(OEM7_DECODER_LIB liboem7decoder.a "../../novatel_oem7/bin")
+message(STATUS "Linking to Oem7 Decoder at: '${OEM7_DECODER_LIB}'")
+
+target_link_libraries(${PROJECT_NAME}
+ ${catkin_LIBRARIES}
+ ${Boost_LIBRARIES}
+ ${OEM7_DECODER_LIB}
+)
+
+
+#############
+## Install ##
+#############
+
+# all install targets should use catkin DESTINATION variables
+# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
+
+
+## Mark executables and/or libraries for installation
+install(TARGETS ${PROJECT_NAME}
+ ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+ RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+)
+
+## Export plugin header files.
+install(DIRECTORY include/${PROJECT_NAME}/
+ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
+ FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
+)
+
+## Mark other files for installation (e.g. launch and bag files, etc.)
+install(
+ FILES novatel_oem7_driver_nodelets.xml novatel_oem7_driver_plugins.xml
+ DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
+ )
+
+install(
+ DIRECTORY
+ launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
+ )
+
+install(
+ DIRECTORY
+ config DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
+ )
+
+
+#############
+## Testing ##
+#############
+
+# Built-in Self Test (BIST)
+catkin_install_python(PROGRAMS test/oem7_bist.py test/oem7_message_test.py
+ DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
+# Instaleld into SHARED vs BINARY. BINARY does not allow BIST to be run using
+# rostest novatel_oem7_driver your_launch_file.lauch" syntax.
+
+
+find_package(rostest REQUIRED)
+add_rostest(test/align.test)
+add_rostest(test/bestpos.test)
+add_rostest(test/ins1.test)
+add_rostest(test/ins2.test)
+add_rostest(test/rxstatus.test)
+add_rostest(test/time.test)
+
+
+
+#message("includes:")
+#get_property(incdirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
+#foreach(dir ${incdirs})
+# message(STATUS "incdir= '${dir}'")
+#endforeach()
diff --git a/src/novatel_oem7_driver/config/oem7_msgs.yaml b/src/novatel_oem7_driver/config/oem7_msgs.yaml
new file mode 100644
index 0000000..e8fb6ea
--- /dev/null
+++ b/src/novatel_oem7_driver/config/oem7_msgs.yaml
@@ -0,0 +1,26 @@
+# Oem7 messages; message names and IDs are as they appear in Oem7 manual.
+# Correctness of message ID is critical for correct operation.
+oem7_msgs:
+ # Standard messages - Do not remove.
+ BESTPOS: 42
+ BESTVEL: 99
+ BESTUTM: 726
+ INSPVAS: 508
+ INSPVAX: 1465
+ INSSTDEV: 2051
+ CORRIMUS: 2264
+ IMURATECORRIMUS: 1362
+ RANGE: 43
+ RAWIMUSX: 1462
+ RAWEPHEM: 41
+ GLOEPHEMERIS: 723
+ BDSEPHEMERIS: 1696
+ GALINAVEPHEMERIS: 1309
+ GALFNAVEPHEMERIS: 1310
+ HEADING2: 1335
+ TIME: 101
+ RXSTATUS: 93
+ INSUPDATESTATUS: 1825
+ INSCONFIG: 1945
+ PSRDOP2: 1163
+ # More messages may be added in order to process Oem7 'raw' messages.
diff --git a/src/novatel_oem7_driver/config/oem7_supported_imus.yaml b/src/novatel_oem7_driver/config/oem7_supported_imus.yaml
new file mode 100644
index 0000000..96d63d7
--- /dev/null
+++ b/src/novatel_oem7_driver/config/oem7_supported_imus.yaml
@@ -0,0 +1,25 @@
+supported_imus:
+ "0" : { name: "Unknown", rate: "0" }
+ "1" : { name: "Honeywell HG1700 AG1", rate: "100" }
+ "4" : { name: "Honeywell HG1700 AG17", rate: "100" }
+ "5" : { name: "Honeywell HG1700 CA29", rate: "100" }
+ "8" : { name: "Northrop Grumman LN-200/LN-200C", rate: "200" }
+ "11" : { name: "Honeywell HG1700 AG58", rate: "100" }
+ "12" : { name: "Honeywell HG1700 AG62", rate: "100" }
+ "13" : { name: "iMAR ilMU-FSAS", rate: "200" }
+ "16" : { name: "KVH CPT IMU", rate: "200" }
+ "19" : { name: "Northrop Grumman Litef LCI-1", rate: "200" }
+ "20" : { name: "Honeywell HG1930 AA99", rate: "100" }
+ "26" : { name: "Northrop Grumman Litef ISA-100C", rate: "100" }
+ "27" : { name: "Honeywell HG1900 CA50", rate: "100" }
+ "28" : { name: "Honeywell HG1930 CA50", rate: "100" }
+ "31" : { name: "Analog Devices ADIS16488", rate: "200" }
+ "32" : { name: "Sensonor STIM300", rate: "125" }
+ "33" : { name: "KVH1750 IMU", rate: "200" }
+ "41" : { name: "Epson G320N", rate: "125" }
+ "45" : { name: "KVH 1725 IMU?", rate: "200" }
+ "52" : { name: "Litef microIMU" , rate: "200" }
+ "56" : { name: "Sensonor STIM300, Direct Connection", rate: "125" }
+ "58" : { name: "Honeywell HG4930 AN01", rate: "200" }
+ "61" : { name: "Epson G370N", rate: "200" }
+ "62" : { name: "Epson G320N - 200Hz", rate: "200" }
\ No newline at end of file
diff --git a/src/novatel_oem7_driver/config/std_driver_config.xml b/src/novatel_oem7_driver/config/std_driver_config.xml
new file mode 100644
index 0000000..70d9914
--- /dev/null
+++ b/src/novatel_oem7_driver/config/std_driver_config.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/config/std_init_commands.yaml b/src/novatel_oem7_driver/config/std_init_commands.yaml
new file mode 100644
index 0000000..838cb88
--- /dev/null
+++ b/src/novatel_oem7_driver/config/std_init_commands.yaml
@@ -0,0 +1,90 @@
+# Oem7 Receiver initialization and configuration Commands, sent to Oem7 as-is.
+# Refer to Oem7 Receiver documentation.
+#
+#
+# Lines marked as "Do Not Remove" are needed to ensure correct operation.
+# Some ROS messages are composed from a combination of Oem7 messages.
+# It is critical to log individiual Oem7 message to ensure correct generation and field population.
+#
+# Message generation/composition as as follows:
+#
+# ---------------------------------------------------------------------------------------------------
+# 'GPSFix':
+# BESTPOSB
+# BESTVELB
+# INSPVASB (on IMU-enabled units only, not needed on non-IMU units)
+# PSDROP2B (on IMU-enabled units only, not needed on non-IMU units)
+#
+# Output rate: the highest rate of:
+# BESTPOSB, BESTVELB, INSPVASB.
+# Typically, INSPVASB is logged at the highest rate and thus generates GPSFix
+#
+# -----------------------------------------------------------------------------------------------------
+# NavSatFix: published at the same rate as GPSFix; data derived from:
+# BESTPOSB
+#
+# It is recommended to use GPSFix instead of NavSatFix.
+#
+# -----------------------------------------------------------------------------------------------------
+# 'Imu':
+# INSPVASB
+# INSSTDEVB
+# CORRIMUSB or IMURATECORRIMUSB
+#
+# Output rate: the highest rate of:
+# CORRIMUSB or IMURATECORRIMUSB
+
+# Commented out Oem7 commands are for example purposes
+receiver_init_commands:
+#-----------------------------------------------------------------------------------------------------
+# Reset logging
+
+- "UNLOGALL THISPORT"
+#- "FRESET"
+#- "!PAUSE 10"
+#- "SETINSPROFILE LAND"
+#- "SETINSTRANSLATION ANT 1
+#- ... etc.
+
+
+#-------------------------------------------------------------------------------------------------------
+# Standard Logging Requests
+
+#----------------------------
+# Status & Config
+- "LOG INSCONFIGB ONCE" # Log once to obtain initial configuration. Do not remove, needed for IMU messages.
+- "LOG INSCONFIGB ONTIME 300" # Periodic update.
+- "LOG RXSTATUSB ONCHANGED"
+
+# GNSS and INS Solutions
+
+# Do not remove these messages --------------------------------------------------------------------------
+- "LOG BESTPOSB ONTIME 0.1"
+- "LOG BESTVELB ONTIME 0.1"
+- "LOG BESTUTMB ONTIME 1"
+- "LOG HEADING2B ONNEW"
+- "LOG PSRDOP2B ONCHANGED"
+- "LOG INSPVASB ONTIME 0.02"
+- "LOG INSPVAXB ONTIME 1"
+- "LOG CORRIMUSB ONTIME 0.01"
+- "LOG INSSTDEVB ONTIME 1"
+#----------------------------------------------------------------------------------------------------------
+
+- "LOG TIMEB ONTIME 1" # Can be used as a 'heartbeat' message.
+
+# Post-Processing Messages; not directly used to generate ROS messages.
+- "LOG RAWIMUSXB ONNEW"
+- "LOG INSUPDATESTATUSB ONNEW"
+- "LOG RAWEPHEMB ONNEW"
+- "LOG GLOEPHEMERISB ONNEW"
+- "LOG BDSEPHEMERISB ONNEW"
+- "LOG GALFNAVEPHEMERISB ONNEW"
+- "LOG GALINAVEPHEMERISB ONNEW"
+- "LOG RANGEB ONTIME 1"
+
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/config/std_msg_handlers.yaml b/src/novatel_oem7_driver/config/std_msg_handlers.yaml
new file mode 100644
index 0000000..fe3e24a
--- /dev/null
+++ b/src/novatel_oem7_driver/config/std_msg_handlers.yaml
@@ -0,0 +1,7 @@
+oem7_msg_handlers:
+- "BESTPOSHandler"
+- "INSHandler"
+- "ALIGNHandler"
+- "RXSTATUSHandler"
+- "TimeHandler"
+
\ No newline at end of file
diff --git a/src/novatel_oem7_driver/config/std_msg_topics.yaml b/src/novatel_oem7_driver/config/std_msg_topics.yaml
new file mode 100644
index 0000000..eaee01c
--- /dev/null
+++ b/src/novatel_oem7_driver/config/std_msg_topics.yaml
@@ -0,0 +1,20 @@
+# ROS-standard
+IMU: {topic: /gps/imu, frame_id: gps}
+GPSFix: {topic: /gps/gps, frame_id: gps}
+NavSatFix: {topic: /gps/fix, frame_id: gps}
+
+# Oem7-specific
+Oem7RawMsg: {topic: /novatel/oem7/oem7raw, frame_id: gps, queue_size: "200"}
+BESTPOS: {topic: /novatel/oem7/bestpos, frame_id: gps}
+BESTUTM: {topic: /novatel/oem7/bestutm, frame_id: gps}
+BESTVEL: {topic: /novatel/oem7/bestvel, frame_id: gps}
+CORRIMU: {topic: /novatel/oem7/corrimu, frame_id: gps}
+HEADING2: {topic: /novatel/oem7/heading2, frame_id: gps}
+INSPVA: {topic: /novatel/oem7/inspva, frame_id: gps}
+INSPVAX: {topic: /novatel/oem7/inspvax, frame_id: gps, queue_size: "10"}
+INSSTDEV: {topic: /novatel/oem7/insstdev, frame_id: gps, queue_size: "10"}
+INSCONFIG: {topic: /novatel/oem7/insconfig, frame_id: gps, queue_size: "10"}
+RXSTATUS: {topic: /novatel/oem7/rxstatus, frame_id: gps, queue_size: "10"}
+TIME: {topic: /novatel/oem7/time, frame_id: gps}
+
+
diff --git a/src/novatel_oem7_driver/config/std_oem7_raw_msgs.yaml b/src/novatel_oem7_driver/config/std_oem7_raw_msgs.yaml
new file mode 100644
index 0000000..3969445
--- /dev/null
+++ b/src/novatel_oem7_driver/config/std_oem7_raw_msgs.yaml
@@ -0,0 +1,17 @@
+oem7_raw_msgs:
+- BESTPOS
+- BESTVEL
+- INSPVAX
+- INSUPDATESTATUS
+- RAWIMUSX
+- RAWEPHEM
+- GLOEPHEMERIS
+- BDSEPHEMERIS
+- GALFNAVEPHEMERIS
+- GALINAVEPHEMERIS
+- RANGE
+- HEADING2
+- TIME
+- RXSTATUS
+- INSCONFIG
+
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_decoder_if.hpp b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_decoder_if.hpp
new file mode 100644
index 0000000..b635508
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_decoder_if.hpp
@@ -0,0 +1,85 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_MESSAGE_PARSER_IF_HPP__
+#define __OEM7_MESSAGE_PARSER_IF_HPP__
+
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "novatel_oem7_msgs/Oem7RawMsg.h"
+
+namespace novatel_oem7_driver
+{
+ /**
+ * Interface implemented by Oem7RawMessageParserIf users, in order to receiver message callbacks.
+ */
+ class Oem7MessageDecoderUserIf
+ {
+ public:
+ virtual ~Oem7MessageDecoderUserIf(){};
+
+ /**
+ * Called when new message is available.
+ */
+ virtual void onNewMessage(boost::shared_ptr) = 0;
+ };
+
+
+ /**
+ * Interface for accessing Oem7 message decoder.
+ * The user is responsible for initializing it, and calling service from its preferred context.
+ * Any callbacks on Oem7RawMessageParserUserIf are made from the service context.
+ */
+ class Oem7MessageDecoderIf
+ {
+ public:
+ virtual ~Oem7MessageDecoderIf(){}
+
+ /**
+ * Initializes the parser.
+ * @return true on success
+ */
+ virtual bool initialize(
+ ros::NodeHandle& nh, /**< [in] handle of the owner node. Parser uses it to access ROS environment. */
+ Oem7ReceiverIf* recvr, /**< [in] Receiver interface used for data input */
+ Oem7MessageDecoderUserIf* user /**< [in] Interface to receiver message callbacks */
+ ) = 0;
+
+ /**
+ * Message decoder service loop; blocks as long as input is available.
+ * Returns when no more input is available; or when ros::ok() returns false.
+ */
+ virtual void service() = 0;
+ };
+}
+
+
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_handler_if.hpp b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_handler_if.hpp
new file mode 100644
index 0000000..d3225e9
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_handler_if.hpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_MESSAGE_HANDLER_IF_HPP__
+#define __OEM7_MESSAGE_HANDLER_IF_HPP__
+
+
+#include
+
+#include
+
+#include "oem7_raw_message_if.hpp"
+using novatel_oem7::Oem7RawMessageIf;
+
+namespace novatel_oem7_driver
+{
+ /**
+ * Interface implemented by modules handling Oem7RawMessageIf messages
+ */
+ class Oem7MessageHandlerIf
+ {
+ public:
+ virtual ~Oem7MessageHandlerIf(){};
+
+ /**
+ * Initializes the handler
+ */
+ virtual void initialize(ros::NodeHandle&) = 0;
+
+ /**
+ * @return a vector of Oem7 message IDs to be handled by this Handler.
+ */
+ virtual const std::vector& getMessageIds() = 0;
+
+ /**
+ * Handle a message
+ */
+ virtual void handleMsg(Oem7RawMessageIf::ConstPtr msg) = 0;
+ };
+}
+
+
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_ids.h b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_ids.h
new file mode 100644
index 0000000..d90d31f
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_ids.h
@@ -0,0 +1,50 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_MESSAGE_IDS_HPP__
+#define __OEM7_MESSAGE_IDS_HPP__
+
+/*! \file
+ * Oem7 Message ID definitions.
+ * Refer to Oem7 manual.
+ */
+
+namespace novatel_oem7_driver
+{
+ const int BESTPOS_OEM7_MSGID = 42;
+ const int BESTUTM_OEM7_MSGID = 726;
+ const int BESTVEL_OEM7_MSGID = 99;
+ const int CORRIMUS_OEM7_MSGID = 2264;
+ const int HEADING2_OEM7_MSGID = 1335;
+ const int IMURATECORRIMU_OEM7_MSGID = 1362;
+ const int INSCONFIG_OEM7_MSGID = 1945;
+ const int INSPVAS_OEM7_MSGID = 508;
+ const int INSPVAX_OEM7_MSGID = 1465;
+ const int INSSTDEV_OEM7_MSGID = 2051;
+ const int PSRDOP2_OEM7_MSGID = 1163;
+ const int RXSTATUS_OEM7_MSGID = 93;
+ const int TIME_OEM7_MSGID = 101;
+}
+
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_util.hpp b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_util.hpp
new file mode 100644
index 0000000..5bbbccf
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_message_util.hpp
@@ -0,0 +1,77 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_MESSAGE_UTIL_HPP__
+#define __OEM7_MESSAGE_UTIL_HPP__
+
+#include "novatel_oem7_msgs/Oem7Header.h"
+#include "novatel_oem7_msgs/Oem7RawMsg.h"
+
+#include "oem7_raw_message_if.hpp"
+using novatel_oem7::Oem7RawMessageIf;
+
+#include "oem7_messages.h"
+
+#include
+
+namespace novatel_oem7_driver
+{
+
+ void initializeOem7MessageUtil(ros::NodeHandle& nh);
+ int getOem7MessageId(const std::string& msg_name);
+ const std::string& getOem7MessageName(int msg_id);
+
+ /**
+ * Populates Oem7 Binary message header from raw message
+ *
+ */
+ void getOem7Header(
+ const Oem7RawMessageIf::ConstPtr& raw_msg, ///< [in] Raw binary message
+ novatel_oem7_msgs::Oem7Header::Type& hdr ///< [out] Oem7 Message Header
+ );
+
+ /**
+ * Populates Oem7 Binary message header from 'short' raw message
+ *
+ */
+ void getOem7ShortHeader(
+ const Oem7RawMessageIf::ConstPtr& raw_msg, ///< [in] Raw binary message
+ novatel_oem7_msgs::Oem7Header::Type& hdr ///< [out] Oem7 Message Header
+ );
+
+ size_t Get_INSCONFIG_NumTranslations(const INSCONFIG_FixedMem* insconfig);
+
+ const INSCONFIG_TranslationMem* Get_INSCONFIG_Translation(const INSCONFIG_FixedMem* insconfig, size_t idx);
+
+ size_t Get_INSCONFIG_NumRotations(const INSCONFIG_FixedMem* insconfig);
+
+ const INSCONFIG_RotationMem* Get_INSCONFIG_Rotation(const INSCONFIG_FixedMem* insconfig, size_t idx);
+
+
+ size_t Get_PSRDOP2_NumSystems(const PSRDOP2_FixedMem* psrdop2);
+ const PSRDOP2_SystemMem* Get_PSRDOP2_System(const PSRDOP2_FixedMem* psrdop2, size_t idx);
+}
+
+
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_messages.h b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_messages.h
new file mode 100644
index 0000000..5cd3068
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_messages.h
@@ -0,0 +1,417 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/*! \file
+ * Binary format definitions for Oem7 messages.
+ * In the future, this file will be autogenerated.
+ * All Oem7 messages are 4-byte aligned, allowing simple casting into structs.
+ * Consult Oem7 manual for details.
+ */
+
+#ifndef __OEM7_MESSAGES_H_
+#define __OEM7_MESSAGES_H_
+
+#include
+
+
+#define ASSERT_MSG "Consult Oem7 manual"
+
+namespace novatel_oem7_driver
+{
+ typedef uint32_t oem7_enum_t;
+ typedef uint32_t oem7_bool_t;
+ typedef uint8_t oem7_hex_t;
+ typedef char oem7_char_t;
+
+ static_assert(sizeof(oem7_char_t) == 1, ASSERT_MSG);
+ static_assert(sizeof(double) == 8, ASSERT_MSG);
+ static_assert(sizeof(float) == 4, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ Oem7MessageCommonHeaderMem
+ {
+ char sync1;
+ char sync2;
+ char sync3;
+
+ uint8_t message_length;
+ uint16_t message_id;
+ };
+
+ struct __attribute__((packed))
+ Oem7MessageHeaderMem
+ {
+ char sync1;
+ char sync2;
+ char sync3;
+
+ uint8_t header_length;
+ uint16_t message_id;
+ char message_type;
+ uint8_t port_address;
+ uint16_t message_length;
+ uint16_t sequence;
+ uint8_t idle_time;
+ uint8_t time_status;
+ uint16_t gps_week;
+ int32_t gps_milliseconds;
+ uint32_t recevier_status;
+ uint16_t reserved;
+ uint16_t recevier_version;
+ };
+
+ struct __attribute__((packed))
+ Oem7MessgeShortHeaderMem
+ {
+ char sync1;
+ char sync2;
+ char sync3;
+
+ uint8_t message_length;
+ uint16_t message_id;
+ uint16_t gps_week;
+ int32_t gps_milliseconds;
+ };
+
+
+ struct __attribute__((packed))
+ BESTPOSMem
+ {
+ oem7_enum_t sol_stat;
+ oem7_enum_t pos_type;
+ double lat;
+ double lon;
+ double hgt;
+ float undulation;
+ oem7_enum_t datum_id;
+ float lat_stdev;
+ float lon_stdev;
+ float hgt_stdev;
+ oem7_char_t stn_id[4];
+ float diff_age;
+ float sol_age;
+ uint8_t num_svs;
+ uint8_t num_sol_svs;
+ uint8_t num_sol_l1_svs;
+ uint8_t num_sol_multi_svs;
+ oem7_hex_t reserved;
+ oem7_hex_t ext_sol_stat;
+ uint8_t galileo_beidou_sig_mask;
+ uint8_t gps_glonass_sig_mask;
+ };
+ static_assert(sizeof(BESTPOSMem) == 72, ASSERT_MSG);
+
+
+ struct __attribute__((packed))
+ BESTVELMem
+ {
+ uint32_t sol_stat;
+ uint32_t vel_type;
+ float latency;
+ float diff_age;
+ double hor_speed;
+ double track_gnd;
+ double ver_speed;
+ float reserved;
+ };
+ static_assert(sizeof(BESTVELMem) == 44, ASSERT_MSG);
+
+
+ struct __attribute__((packed))
+ INSPVASmem
+ {
+ uint32_t gnss_week;
+ double seconds;
+ double latitude;
+ double longitude;
+ double height;
+ double north_velocity;
+ double east_velocity;
+ double up_velocity;
+ double roll;
+ double pitch;
+ double azimuth;
+ oem7_enum_t status;
+ };
+ static_assert(sizeof(INSPVASmem) == 88, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ CORRIMUSMem
+ {
+ uint32_t imu_data_count;
+ double pitch_rate;
+ double roll_rate;
+ double yaw_rate;
+ double lateral_acc;
+ double longitudinal_acc;
+ double vertical_acc;
+ uint32_t reserved1;
+ uint32_t reserved2;
+ };
+ static_assert(sizeof(CORRIMUSMem) == 60, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ IMURATECORRIMUSMem
+ {
+ uint32_t week;
+ double seconds;
+ double pitch_rate;
+ double roll_rate;
+ double yaw_rate;
+ double lateral_acc;
+ double longitudinal_acc;
+ double vertical_acc;
+ };
+ static_assert(sizeof(IMURATECORRIMUSMem) == 60, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ INSSTDEVMem
+ {
+ float latitude_stdev;
+ float longitude_stdev;
+ float height_stdev;
+ float north_velocity_stdev;
+ float east_velocity_stdev;
+ float up_velocity_stdev;
+ float roll_stdev;
+ float pitch_stdev;
+ float azimuth_stdev;
+ uint32_t ext_sol_status;
+ uint16_t time_since_last_update;
+ uint16_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+ };
+ static_assert(sizeof(INSSTDEVMem) == 52, ASSERT_MSG);
+
+
+ struct __attribute__((packed))
+ INSCONFIG_FixedMem
+ {
+ oem7_enum_t imu_type;
+ uint8_t mapping;
+ uint8_t initial_alignment_velocity;
+ uint16_t heave_window;
+ oem7_enum_t profile;
+ oem7_hex_t enabled_updates[4];
+ oem7_enum_t alignment_mode;
+ oem7_enum_t relative_ins_output_frame;
+ oem7_bool_t relative_ins_output_direction;
+ oem7_hex_t ins_receiver_status[4];
+ uint8_t ins_seed_enabled;
+ uint8_t ins_seed_validation;
+ uint16_t reserved_1;
+ uint32_t reserved_2;
+ uint32_t reserved_3;
+ uint32_t reserved_4;
+ uint32_t reserved_5;
+ uint32_t reserved_6;
+ uint32_t reserved_7;
+ };
+ static_assert(sizeof(INSCONFIG_FixedMem) == 60, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ INSCONFIG_TranslationMem
+ {
+ uint32_t translation;
+ uint32_t frame;
+ float x_offset;
+ float y_offset;
+ float z_offset;
+ float x_uncertainty;
+ float y_uncertainty;
+ float z_uncertainty;
+ uint32_t translation_source;
+ };
+
+
+ struct __attribute__((packed))
+ INSCONFIG_RotationMem
+ {
+ uint32_t rotation;
+ uint32_t frame;
+ float x_rotation;
+ float y_rotation;
+ float z_rotation;
+ float x_rotation_stdev;
+ float y_rotation_stdev;
+ float z_rotation_stdev;
+ uint32_t rotation_source;
+ };
+
+
+ struct __attribute__((packed))
+ INSPVAXMem
+ {
+ oem7_enum_t ins_status;
+ oem7_enum_t pos_type;
+ double latitude;
+ double longitude;
+ double height;
+ float undulation;
+ double north_velocity;
+ double east_velocity;
+ double up_velocity;
+ double roll;
+ double pitch;
+ double azimuth;
+ float latitude_stdev;
+ float longitude_stdev;
+ float height_stdev;
+ float north_velocity_stdev;
+ float east_velocity_stdev;
+ float up_velocity_stdev;
+ float roll_stdev;
+ float pitch_stdev;
+ float azimuth_stdev;
+ uint32_t extended_status;
+ uint16_t time_since_update;
+ };
+ static_assert(sizeof(INSPVAXMem) == 126, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ HEADING2Mem
+ {
+ oem7_enum_t sol_status;
+ oem7_enum_t pos_type;
+ float length;
+ float heading;
+ float pitch;
+ float reserved;
+ float heading_stdev;
+ float pitch_stdev;
+ oem7_char_t rover_stn_id[4];
+ oem7_char_t master_stn_id[4];
+ uint8_t num_sv_tracked;
+ uint8_t num_sv_in_sol;
+ uint8_t num_sv_obs;
+ uint8_t num_sv_multi;
+ uint8_t sol_source;
+ uint8_t ext_sol_status;
+ uint8_t galileo_beidou_sig_mask;
+ uint8_t gps_glonass_sig_mask;
+ };
+ static_assert(sizeof(HEADING2Mem) == 48, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ BESTUTMMem
+ {
+ oem7_enum_t sol_stat;
+ oem7_enum_t pos_type;
+ uint32_t lon_zone_number;
+ uint32_t lat_zone_letter;
+ double northing;
+ double easting;
+ double height;
+ float undulation;
+ uint32_t datum_id;
+ float northing_stddev;
+ float easting_stddev;
+ float height_stddev;
+ char stn_id[4];
+ float diff_age;
+ float sol_age;
+ uint8_t num_svs;
+ uint8_t num_sol_svs;
+ uint8_t num_sol_ggl1_svs;
+ uint8_t num_sol_multi_svs;
+ uint8_t reserved;
+ uint8_t ext_sol_stat;
+ uint8_t galileo_beidou_sig_mask;
+ uint8_t gps_glonass_sig_mask;
+ };
+ static_assert(sizeof(BESTUTMMem) == 80, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ RXSTATUSMem
+ {
+ uint32_t error;
+ uint32_t num_status_codes;
+ uint32_t rxstat;
+ uint32_t rxstat_pri_mask;
+ uint32_t rxstat_set_mask;
+ uint32_t rxstat_clr_mask;
+ uint32_t aux1_stat;
+ uint32_t aux1_stat_pri;
+ uint32_t aux1_stat_set;
+ uint32_t aux1_stat_clr;
+ uint32_t aux2_stat;
+ uint32_t aux2_stat_pri;
+ uint32_t aux2_stat_set;
+ uint32_t aux2_stat_clr;
+ uint32_t aux3_stat;
+ uint32_t aux3_stat_pri;
+ uint32_t aux3_stat_set;
+ uint32_t aux3_stat_clr;
+ uint32_t aux4_stat;
+ uint32_t aux4_stat_pri;
+ uint32_t aux4_stat_set;
+ uint32_t aux4_stat_clr;
+ };
+ static_assert(sizeof(RXSTATUSMem) == 88, ASSERT_MSG);
+
+
+ struct __attribute__((packed))
+ TIMEMem
+ {
+ uint32_t clock_status;
+ double offset;
+ double offset_std;
+ double utc_offset;
+ uint32_t utc_year;
+ uint8_t utc_month;
+ uint8_t utc_day;
+ uint8_t utc_hour;
+ uint8_t utc_min;
+ uint32_t utc_msec;
+ uint32_t utc_status;
+ };
+ static_assert(sizeof(TIMEMem) == 44, ASSERT_MSG);
+
+
+ struct __attribute__((packed))
+ PSRDOP2_FixedMem
+ {
+ float gdop;
+ float pdop;
+ float hdop;
+ float vdop;
+ };
+ static_assert(sizeof(PSRDOP2_FixedMem) == 16, ASSERT_MSG);
+
+ struct __attribute__((packed))
+ PSRDOP2_SystemMem
+ {
+ uint32_t system;
+ float tdop;
+ };
+
+
+ const std::size_t OEM7_BINARY_MSG_HDR_LEN = sizeof(Oem7MessageHeaderMem);
+ const std::size_t OEM7_BINARY_MSG_SHORT_HDR_LEN = sizeof(Oem7MessgeShortHeaderMem);
+
+
+
+}
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_receiver_if.hpp b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_receiver_if.hpp
new file mode 100644
index 0000000..17f63cd
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_receiver_if.hpp
@@ -0,0 +1,50 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_RECEIVER_INTERFACE_HPP__
+#define __OEM7_RECEIVER_INTERFACE_HPP__
+
+
+#include
+#include
+#include
+
+
+
+
+namespace novatel_oem7_driver
+{
+ class Oem7ReceiverIf
+ {
+ public:
+ virtual ~Oem7ReceiverIf(){};
+ virtual bool initialize(ros::NodeHandle&) = 0;
+
+ virtual bool read( boost::asio::mutable_buffer, size_t&) = 0;
+ virtual bool write(boost::asio::const_buffer ) = 0;
+ };
+}
+
+
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_ros_messages.hpp b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_ros_messages.hpp
new file mode 100644
index 0000000..7f2ff9a
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/oem7_ros_messages.hpp
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __OEM7_ROS_MESSAGES_HPP__
+#define __OEM7_ROS_MESSAGES_HPP__
+
+#include
+
+#include "oem7_raw_message_if.hpp"
+using novatel_oem7::Oem7RawMessageIf;
+
+#include "novatel_oem7_driver/ros_messages.hpp"
+#include "novatel_oem7_driver/oem7_message_ids.h"
+
+namespace novatel_oem7_driver
+{
+
+ template
+ void
+ MakeROSMessage(const Oem7RawMessageIf::ConstPtr& msg, boost::shared_ptr& rosmsg);
+
+ void
+ GetDOPFromPSRDOP2(
+ const Oem7RawMessageIf::ConstPtr& msg,
+ uint32_t system_to_use,
+ double& gdop,
+ double& pdop,
+ double& hdop,
+ double& vdop,
+ double& tdop);
+}
+#endif
diff --git a/src/novatel_oem7_driver/include/novatel_oem7_driver/ros_messages.hpp b/src/novatel_oem7_driver/include/novatel_oem7_driver/ros_messages.hpp
new file mode 100644
index 0000000..5a4eb69
--- /dev/null
+++ b/src/novatel_oem7_driver/include/novatel_oem7_driver/ros_messages.hpp
@@ -0,0 +1,47 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __ROS_MESSAGES_HPP__
+#define __ROS_MESSAGES_HPP__
+
+#include
+
+
+namespace novatel_oem7_driver
+{
+
+ uint32_t GetNextMsgSequenceNumber();
+
+ template
+ void
+ SetROSHeader(
+ const std::string& frame_id,
+ boost::shared_ptr& msg)
+ {
+ msg->header.frame_id = frame_id;
+ msg->header.stamp = ros::Time::now();
+ msg->header.seq = GetNextMsgSequenceNumber();
+ }
+}
+#endif
diff --git a/src/novatel_oem7_driver/launch/oem7_gps_file.launch b/src/novatel_oem7_driver/launch/oem7_gps_file.launch
new file mode 100644
index 0000000..be27f0f
--- /dev/null
+++ b/src/novatel_oem7_driver/launch/oem7_gps_file.launch
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/launch/oem7_net.launch b/src/novatel_oem7_driver/launch/oem7_net.launch
new file mode 100644
index 0000000..dbd8978
--- /dev/null
+++ b/src/novatel_oem7_driver/launch/oem7_net.launch
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/launch/oem7_tty.launch b/src/novatel_oem7_driver/launch/oem7_tty.launch
new file mode 100644
index 0000000..2ec27d2
--- /dev/null
+++ b/src/novatel_oem7_driver/launch/oem7_tty.launch
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/novatel_oem7_driver_nodelets.xml b/src/novatel_oem7_driver/novatel_oem7_driver_nodelets.xml
new file mode 100644
index 0000000..f08c4da
--- /dev/null
+++ b/src/novatel_oem7_driver/novatel_oem7_driver_nodelets.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ Oem7 Log Nodelet.
+
+
+
+
+
+ Oem7 Message Nodelet.
+
+
+
+
+
+ Oem7 Config Nodelet.
+
+
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/novatel_oem7_driver_plugins.xml b/src/novatel_oem7_driver/novatel_oem7_driver_plugins.xml
new file mode 100644
index 0000000..4716acf
--- /dev/null
+++ b/src/novatel_oem7_driver/novatel_oem7_driver_plugins.xml
@@ -0,0 +1,66 @@
+
+
+
+
+ Oem7 Receiver TCP interface.
+
+
+
+
+
+ Oem7 Receiver UDP interface.
+
+
+
+
+
+ GPS file produced by Oem7 receiver.
+
+
+
+
+
+ Oem7 Receiver serial port interface
+
+
+
+
+
+
+
+ Standard Oem7 Message Decoder
+
+
+
+
+
+ Standard BESTPOS Handler.
+
+
+
+
+
+ Standard INS/IMU Handler.
+
+
+
+
+
+ ALIGN Handler.
+
+
+
+
+
+ Time-related messages.
+
+
+
+
+
+ Receiver Status (RXSTATUS) messages.
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/package.xml b/src/novatel_oem7_driver/package.xml
new file mode 100644
index 0000000..569483b
--- /dev/null
+++ b/src/novatel_oem7_driver/package.xml
@@ -0,0 +1,25 @@
+
+
+ novatel_oem7_driver
+ 0.1.5
+ NovAtel Oem7 ROS Driver
+
+ NovAtel Support
+
+ MIT
+
+ http://www.novatel.com
+
+ catkin
+ nodelet
+ roscpp
+ nodelet
+ roscpp
+ nodelet
+ roscpp
+
+
+
+
+
+
diff --git a/src/novatel_oem7_driver/src/align_handler.cpp b/src/novatel_oem7_driver/src/align_handler.cpp
new file mode 100644
index 0000000..b3e4260
--- /dev/null
+++ b/src/novatel_oem7_driver/src/align_handler.cpp
@@ -0,0 +1,85 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include
+
+
+#include
+
+#include
+#include
+
+#include
+
+
+namespace novatel_oem7_driver
+{
+
+ /***
+ * Handler of ALIGH-related messages
+ */
+ class ALIGNHandler: public Oem7MessageHandlerIf
+ {
+ Oem7RosPublisher HEADING2_pub_;
+
+ void publishHEADING2(
+ Oem7RawMessageIf::ConstPtr msg)
+ {
+ boost::shared_ptr heading2;
+ MakeROSMessage(msg, heading2);
+ HEADING2_pub_.publish(heading2);
+ }
+
+ public:
+ ALIGNHandler()
+ {
+ }
+
+ ~ALIGNHandler()
+ {
+ }
+
+ void initialize(ros::NodeHandle& nh)
+ {
+ HEADING2_pub_.setup("HEADING2", nh);
+ }
+
+ const std::vector& getMessageIds()
+ {
+ static const std::vector MSG_IDS({HEADING2_OEM7_MSGID});
+ return MSG_IDS;
+ }
+
+ void handleMsg(Oem7RawMessageIf::ConstPtr msg)
+ {
+ ROS_DEBUG_STREAM("ALIGN < [id= " << msg->getMessageId() << "]");
+
+ publishHEADING2(msg);
+ }
+ };
+}
+
+#include
+PLUGINLIB_EXPORT_CLASS(novatel_oem7_driver::ALIGNHandler, novatel_oem7_driver::Oem7MessageHandlerIf)
diff --git a/src/novatel_oem7_driver/src/bestpos_handler.cpp b/src/novatel_oem7_driver/src/bestpos_handler.cpp
new file mode 100644
index 0000000..7bb9e06
--- /dev/null
+++ b/src/novatel_oem7_driver/src/bestpos_handler.cpp
@@ -0,0 +1,428 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+#include
+
+
+#include
+#include
+
+#include "novatel_oem7_msgs/SolutionStatus.h"
+#include "novatel_oem7_msgs/PositionOrVelocityType.h"
+#include "novatel_oem7_msgs/BESTPOS.h"
+#include "novatel_oem7_msgs/BESTUTM.h"
+#include "novatel_oem7_msgs/BESTVEL.h"
+#include "novatel_oem7_msgs/INSPVA.h"
+
+#include "gps_common/GPSFix.h"
+#include "sensor_msgs/NavSatFix.h"
+
+#include
+#include
+
+
+namespace novatel_oem7_driver
+{
+
+
+ /***
+ * Derive ROS GPS Status from Oem7 BESTPOS
+ *
+ * @return ROS status.
+ */
+ int16_t ToROSGPSStatus(const novatel_oem7_msgs::BESTPOS::Ptr bestpos)
+ {
+ if(bestpos->pos_type.type == novatel_oem7_msgs::PositionOrVelocityType::NONE)
+ return gps_common::GPSStatus::STATUS_NO_FIX;
+
+ return gps_common::GPSStatus::STATUS_FIX;
+ }
+
+ /***
+ * Convert GPS time to seconds
+ *
+ * @return seconds
+ */
+ double MakeGpsTime_Seconds(uint16_t gps_week, uint32_t gps_milliseconds)
+ {
+ static const double SECONDS_IN_GPS_WEEK = 604800.0;
+ static const double MILLISECONDS_IN_SECOND = 1000.0;
+
+ return gps_week * SECONDS_IN_GPS_WEEK +
+ gps_milliseconds / MILLISECONDS_IN_SECOND;
+ }
+
+ /***
+ * Converts covariance form GPSFix to NavSatFix
+ * @return NavSatFix covariance
+ */
+ uint8_t GpsFixCovTypeToNavSatFixCovType(uint8_t covariance_type)
+ {
+ switch(covariance_type)
+ {
+ case gps_common::GPSFix::COVARIANCE_TYPE_APPROXIMATED:
+ return sensor_msgs::NavSatFix::COVARIANCE_TYPE_APPROXIMATED;
+
+ case gps_common::GPSFix::COVARIANCE_TYPE_DIAGONAL_KNOWN:
+ return sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
+
+ case gps_common::GPSFix::COVARIANCE_TYPE_KNOWN:
+ return sensor_msgs::NavSatFix::COVARIANCE_TYPE_KNOWN;
+
+ case gps_common::GPSFix::COVARIANCE_TYPE_UNKNOWN:
+ return sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
+
+ default:
+ ROS_ERROR_STREAM("Unknown GPSFix covariance type: " << covariance_type);
+ return sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
+ }
+ }
+
+
+ /*** Generates NavSatFix object from GpsFix
+ */
+ void GpsFixToNavSatFix(const gps_common::GPSFix::Ptr gpsfix, sensor_msgs::NavSatFix::Ptr navsatfix)
+ {
+ navsatfix->latitude = gpsfix->latitude;
+ navsatfix->longitude = gpsfix->longitude;
+ navsatfix->altitude = gpsfix->altitude;
+
+ navsatfix->position_covariance[0] = gpsfix->position_covariance[0];
+ navsatfix->position_covariance[4] = gpsfix->position_covariance[4];
+ navsatfix->position_covariance[8] = gpsfix->position_covariance[8];
+
+ navsatfix->position_covariance_type = GpsFixCovTypeToNavSatFixCovType(gpsfix->position_covariance_type);
+ }
+
+ /***
+ * Handler of position-related messages. Synthesizes ROS messagse GPSFix and NavSatFix from native Oem7 Messages.
+ */
+ class BESTPOSHandler: public Oem7MessageHandlerIf
+ {
+ Oem7RosPublisher BESTPOS_pub_;
+ Oem7RosPublisher BESTUTM_pub_;
+ Oem7RosPublisher BESTVEL_pub_;
+ Oem7RosPublisher INSPVA_pub_;
+
+ Oem7RosPublisher GPSFix_pub_;
+ Oem7RosPublisher NavSatFix_pub_;
+
+ boost::shared_ptr bestpos_;
+ boost::shared_ptr bestvel_;
+ boost::shared_ptr inspva_;
+
+ boost::shared_ptr gpsfix_;
+
+ Oem7RawMessageIf::ConstPtr psrdop2_;
+
+ int64_t last_bestpos_;
+ int64_t last_bestvel_;
+ int64_t last_inspva_;
+
+ int32_t bestpos_period_;
+ int32_t bestvel_period_;
+ int32_t inspva_period_;
+
+
+ /***
+ * @return true if the specified period is the shortest in all messages.
+ */
+ bool isShortestPeriod(int32_t period)
+ {
+ return period <= bestpos_period_ &&
+ period <= bestvel_period_ &&
+ period <= inspva_period_;
+ }
+
+ /***
+ * Updates message period
+ */
+ template
+ void updatePeriod(
+ const T& msg,
+ int64_t& last_msg_msec,
+ int32_t& msg_period)
+ {
+ int64_t cur_msg_msec = GPSTimeToMsec(msg->nov_header);
+ if(last_msg_msec > 0)
+ {
+ int32_t period = cur_msg_msec - last_msg_msec;
+ if(period >= 0)
+ {
+ msg_period = period;
+ }
+ else // Could be input corruption; do not update anything.
+ {
+ ROS_ERROR_STREAM("updatePeriod: msg= " << msg->nov_header.message_id << "; per= " << period << "; ignored.");
+ }
+ }
+
+ last_msg_msec = cur_msg_msec;
+ }
+
+ void publishBESTPOS(Oem7RawMessageIf::ConstPtr msg)
+ {
+ MakeROSMessage(msg, bestpos_);
+ updatePeriod(bestpos_, last_bestpos_, bestpos_period_);
+
+
+ BESTPOS_pub_.publish(bestpos_);
+ }
+
+ void publishBESTVEL(Oem7RawMessageIf::ConstPtr msg)
+ {
+ MakeROSMessage(msg, bestvel_);
+ updatePeriod(bestvel_, last_bestvel_, bestvel_period_);
+ BESTVEL_pub_.publish(bestvel_);
+ }
+
+ void publishBESTUTM(Oem7RawMessageIf::ConstPtr msg)
+ {
+ boost::shared_ptr bestutm;
+ MakeROSMessage(msg, bestutm);
+ BESTUTM_pub_.publish(bestutm);
+ }
+
+ void publishINSVPA(Oem7RawMessageIf::ConstPtr msg)
+ {
+ MakeROSMessage(msg, inspva_);
+ updatePeriod(inspva_, last_inspva_, inspva_period_);
+
+ INSPVA_pub_.publish(inspva_);
+ }
+
+ void publishGPSFix()
+ {
+ gpsfix_.reset(new gps_common::GPSFix);
+
+ gpsfix_->status.position_source = gps_common::GPSStatus::SOURCE_NONE;
+ gpsfix_->status.orientation_source = gps_common::GPSStatus::SOURCE_NONE;
+ gpsfix_->status.motion_source = gps_common::GPSStatus::SOURCE_NONE;
+
+ // When INS is available, BESTPOS is the best of GNSS + INS, so it is always preferred.
+ if(bestpos_)
+ {
+ gpsfix_->latitude = bestpos_->lat;
+ gpsfix_->longitude = bestpos_->lon;
+ gpsfix_->altitude = bestpos_->hgt;
+
+ // Convert stdev to diagonal covariance
+ gpsfix_->position_covariance[0] = std::pow(bestpos_->lon_stdev, 2);
+ gpsfix_->position_covariance[4] = std::pow(bestpos_->lat_stdev, 2);
+ gpsfix_->position_covariance[8] = std::pow(bestpos_->hgt_stdev, 2);
+ gpsfix_->position_covariance_type = gps_common::GPSFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
+
+ gpsfix_->time = MakeGpsTime_Seconds(
+ bestpos_->nov_header.gps_week_number,
+ bestpos_->nov_header.gps_week_milliseconds);
+
+
+ gpsfix_->status.satellites_used = bestpos_->num_sol_svs;
+ gpsfix_->status.status = ToROSGPSStatus(bestpos_);
+
+ gpsfix_->status.position_source = gps_common::GPSStatus::SOURCE_GPS;
+ }
+
+ if(bestvel_)
+ {
+ gpsfix_->track = bestvel_->trk_gnd;
+ gpsfix_->speed = bestvel_->hor_speed;
+ gpsfix_->climb = bestvel_->ver_speed;
+
+ if(gpsfix_->time == 0.0) // Not populated yet
+ {
+ gpsfix_->time = MakeGpsTime_Seconds(
+ bestvel_->nov_header.gps_week_number,
+ bestvel_->nov_header.gps_week_milliseconds);
+ }
+
+ if(bestvel_->vel_type.type == novatel_oem7_msgs::PositionOrVelocityType::DOPPLER_VELOCITY)
+ {
+ gpsfix_->status.motion_source != gps_common::GPSStatus::SOURCE_DOPPLER;
+ }
+ else
+ {
+ gpsfix_->status.motion_source |= gps_common::GPSStatus::SOURCE_POINTS;
+ }
+ }
+
+
+ if(inspva_ )
+ {
+ if(!bestpos_) // BESTPOS is not available
+ {
+ gpsfix_->latitude = inspva_->latitude;
+ gpsfix_->longitude = inspva_->longitude;
+ gpsfix_->altitude = inspva_->height;
+
+ // TODO: compute variance form INSSTDEV instead?
+ gpsfix_->position_covariance_type = gps_common::GPSFix::COVARIANCE_TYPE_UNKNOWN;
+ }
+
+ gpsfix_->pitch = inspva_->pitch;
+ gpsfix_->roll = inspva_->roll;
+ //gpsfix->dip: not populated.
+
+ gpsfix_->status.position_source |= (gps_common::GPSStatus::SOURCE_GYRO | gps_common::GPSStatus::SOURCE_ACCEL);
+ gpsfix_->status.orientation_source = (gps_common::GPSStatus::SOURCE_GYRO | gps_common::GPSStatus::SOURCE_ACCEL);
+ gpsfix_->status.motion_source = (gps_common::GPSStatus::SOURCE_GYRO | gps_common::GPSStatus::SOURCE_ACCEL);
+
+ if(gpsfix_->time == 0.0) // Not populated yet
+ {
+ gpsfix_->time = MakeGpsTime_Seconds(
+ inspva_->nov_header.gps_week_number,
+ inspva_->nov_header.gps_week_milliseconds);
+ }
+ }
+
+ if(psrdop2_)
+ {
+ GetDOPFromPSRDOP2(
+ psrdop2_,
+ 0, // GPS
+ gpsfix_->gdop,
+ gpsfix_->pdop,
+ gpsfix_->hdop,
+ gpsfix_->vdop,
+ gpsfix_->tdop);
+ }
+
+ GPSFix_pub_.publish(gpsfix_);
+ }
+
+ void publishNavSatFix()
+ {
+ if(!gpsfix_)
+ {
+ return;
+ }
+
+ boost::shared_ptr navsatfix(new sensor_msgs::NavSatFix);
+
+ // Derive from GPSFix.
+ GpsFixToNavSatFix(gpsfix_, navsatfix);
+
+ NavSatFix_pub_.publish(navsatfix);
+ }
+
+ void publishROSMessages()
+ {
+ publishGPSFix(); // Must be published first, since other message may be derived from it.
+ publishNavSatFix();
+ }
+
+
+
+ public:
+ BESTPOSHandler():
+ last_bestpos_(0),
+ last_bestvel_(0),
+ last_inspva_(0),
+ bestpos_period_(INT_MAX),
+ bestvel_period_(INT_MAX),
+ inspva_period_( INT_MAX)
+ {
+ }
+
+ ~BESTPOSHandler()
+ {
+ }
+
+ void initialize(ros::NodeHandle& nh)
+ {
+ BESTPOS_pub_.setup("BESTPOS", nh);
+ BESTVEL_pub_.setup("BESTVEL", nh);
+ BESTUTM_pub_.setup("BESTUTM", nh);
+ INSPVA_pub_.setup( "INSPVA", nh);
+ GPSFix_pub_.setup( "GPSFix", nh);
+ NavSatFix_pub_.setup( "NavSatFix", nh);
+ }
+
+ const std::vector& getMessageIds()
+ {
+ static const std::vector MSG_IDS({BESTPOS_OEM7_MSGID, BESTVEL_OEM7_MSGID, BESTUTM_OEM7_MSGID, INSPVAS_OEM7_MSGID, PSRDOP2_OEM7_MSGID});
+ return MSG_IDS;
+ }
+
+ void handleMsg(Oem7RawMessageIf::ConstPtr msg)
+ {
+ ROS_DEBUG_STREAM("BESTPOS < [id=" << msg->getMessageId() << "] periods (BP BV PVA):" <<
+ bestpos_period_ << " " <<
+ bestvel_period_ << " " <<
+ inspva_period_);
+
+ // It is assumed all the messages are logged at reasonable rates.
+ // BESTPOS and BESTVEL are always logged together.
+ // On units with IMU, INSPVA would trigger publishing of ROS messages.
+ // On non-IMU units, BESTVEL be.
+
+ if(msg->getMessageId() == BESTPOS_OEM7_MSGID)
+ {
+ publishBESTPOS(msg);
+
+ if(isShortestPeriod(bestpos_period_))
+ {
+ publishROSMessages();
+ }
+ }
+
+ if(msg->getMessageId() == BESTVEL_OEM7_MSGID)
+ {
+ publishBESTVEL(msg);
+
+ if(isShortestPeriod(bestvel_period_))
+ {
+ publishROSMessages();
+ }
+ }
+
+ if(msg->getMessageId() == BESTUTM_OEM7_MSGID)
+ {
+ publishBESTUTM(msg);
+ }
+
+ if(msg->getMessageId() == INSPVAS_OEM7_MSGID)
+ {
+ publishINSVPA(msg);
+
+ if(isShortestPeriod(inspva_period_))
+ {
+ publishROSMessages();
+ }
+ }
+
+ if(msg->getMessageId() == PSRDOP2_OEM7_MSGID)
+ {
+ psrdop2_ = msg;
+ }
+ }
+ };
+
+}
+
+#include
+PLUGINLIB_EXPORT_CLASS(novatel_oem7_driver::BESTPOSHandler, novatel_oem7_driver::Oem7MessageHandlerIf)
diff --git a/src/novatel_oem7_driver/src/ins_handler.cpp b/src/novatel_oem7_driver/src/ins_handler.cpp
new file mode 100644
index 0000000..19c6d2e
--- /dev/null
+++ b/src/novatel_oem7_driver/src/ins_handler.cpp
@@ -0,0 +1,296 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2020 NovAtel Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include
+
+
+#include
+
+#include
+
+#include "sensor_msgs/Imu.h"
+#include "novatel_oem7_msgs/CORRIMU.h"
+#include "novatel_oem7_msgs/IMURATECORRIMU.h"
+#include "novatel_oem7_msgs/INSSTDEV.h"
+#include "novatel_oem7_msgs/INSCONFIG.h"
+#include "novatel_oem7_msgs/INSPVA.h"
+#include "novatel_oem7_msgs/INSPVAX.h"
+
+#include
+#include
+
+#include
+#include