Skip to content

Commit af4e99d

Browse files
authored
Merge pull request #37 from nocoinman/feature-pcap
[FEATURE] Handling and publishing from PCAP files
2 parents 11372a5 + 583fefb commit af4e99d

File tree

11 files changed

+467
-34
lines changed

11 files changed

+467
-34
lines changed

CMakeLists.txt

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ find_package(catkin REQUIRED COMPONENTS
2424
## System dependencies are found with CMake's conventions
2525
find_package(Boost REQUIRED COMPONENTS system thread regex)
2626

27+
## For PCAP file handling
28+
find_library(libpcap_LIBRARIES pcap)
29+
if ("${libpcap_LIBRARIES}" STREQUAL "pcap-NOTFOUND")
30+
set(libpcap_FOUND FALSE)
31+
else ()
32+
set(libpcap_FOUND TRUE)
33+
endif ()
2734

2835
## Uncomment this if the package has a setup.py. This macro ensures
2936
## modules and global scripts declared therein get installed
@@ -150,7 +157,21 @@ include_directories(
150157
## Declare a C++ executable
151158
## With catkin_make all packages are built within a single CMake context
152159
## The recommended prefix ensures that target names across packages don't collide
153-
add_executable(${PROJECT_NAME}_node src/septentrio_gnss_driver/node/rosaic_node.cpp src/septentrio_gnss_driver/communication/circular_buffer.cpp src/septentrio_gnss_driver/parsers/parsing_utilities.cpp src/septentrio_gnss_driver/parsers/string_utilities.cpp src/septentrio_gnss_driver/parsers/nmea_parsers/gpgga.cpp src/septentrio_gnss_driver/parsers/nmea_parsers/gprmc.cpp src/septentrio_gnss_driver/parsers/nmea_parsers/gpgsa.cpp src/septentrio_gnss_driver/parsers/nmea_parsers/gpgsv.cpp src/septentrio_gnss_driver/crc/crc.c src/septentrio_gnss_driver/communication/communication_core.cpp src/septentrio_gnss_driver/communication/rx_message.cpp src/septentrio_gnss_driver/communication/callback_handlers.cpp)
160+
add_executable(${PROJECT_NAME}_node
161+
src/septentrio_gnss_driver/node/rosaic_node.cpp
162+
src/septentrio_gnss_driver/communication/circular_buffer.cpp
163+
src/septentrio_gnss_driver/parsers/parsing_utilities.cpp
164+
src/septentrio_gnss_driver/parsers/string_utilities.cpp
165+
src/septentrio_gnss_driver/parsers/nmea_parsers/gpgga.cpp
166+
src/septentrio_gnss_driver/parsers/nmea_parsers/gprmc.cpp
167+
src/septentrio_gnss_driver/parsers/nmea_parsers/gpgsa.cpp
168+
src/septentrio_gnss_driver/parsers/nmea_parsers/gpgsv.cpp
169+
src/septentrio_gnss_driver/crc/crc.c
170+
src/septentrio_gnss_driver/communication/communication_core.cpp
171+
src/septentrio_gnss_driver/communication/rx_message.cpp
172+
src/septentrio_gnss_driver/communication/callback_handlers.cpp
173+
src/septentrio_gnss_driver/communication/pcap_reader.cpp
174+
)
154175

155176
## Rename C++ executable without prefix
156177
## The above recommended prefix causes long target names, the following renames the
@@ -164,7 +185,7 @@ add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catk
164185

165186
## Specify libraries to link a library or executable target against
166187
target_link_libraries(${PROJECT_NAME}_node
167-
${catkin_LIBRARIES} ${Boost_LIBRARIES}
188+
${catkin_LIBRARIES} ${Boost_LIBRARIES} ${libpcap_LIBRARIES}
168189
)
169190

170191
#############

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Please [let the maintainers know](mailto:[email protected]?subject=[GitH
1717
The `master` branch for this driver functions on both ROS Melodic (Ubuntu 18.04) and Noetic (Ubuntu 20.04). It is thus necessary to [install](https://wiki.ros.org/Installation/Ubuntu) the ROS version that has been designed for your Linux distro.<br><br>
1818
The serial and TCP/IP communication interface of the ROS driver is established by means of the [Boost C++ library](https://www.boost.org/). In the unlikely event that the below installation instructions fail to install Boost on the fly, please install the Boost libraries via<br><br>
1919
`sudo apt install libboost-all-dev`.<br><br>
20+
Compatiblity with PCAP captures are incorporated through [pcap libraries](https://github.com/the-tcpdump-group/libpcap). Install the necessary headers via<br><br>
21+
`sudo apt install libpcap-dev`.<br><br>
2022

2123
## Usage
2224
The binary release is now available for Melodic, yet will take another few days for Noetic. To install the binary package on Melodic, simply run<br><br>
@@ -116,6 +118,7 @@ The following is a list of ROSaic parameters found in the `config/rover.yaml` fi
116118
- `device`: location of device connection
117119
- `serial:xxx` format for serial connections, where `xxx` is the device node, e.g. `serial:/dev/ttyUSB0`
118120
- `file_name:path/to/file.sbf` format for publishing from an SBF log
121+
- `file_name:path/to/file.pcap` format for publishing from PCAP capture.
119122
- Regarding the file path, ROS_HOME=\`pwd\` in front of `roslaunch septentrio...` might be useful to specify that the node should be started using the executable's directory as its working-directory.
120123
- `tcp://host:port` format for TCP/IP connections
121124
- `28784` should be used as the default (command) port for TCP/IP connections. If another port is specified, the receiver needs to be (re-)configured via the Web Interface before ROSaic can be used.
@@ -206,7 +209,6 @@ A selection of NMEA sentences, the majority being standardized sentences, and pr
206209

207210
## Suggestions for Improvements
208211
- Automatic Search: If the host address of the receiver is omitted in the `host:port` specification, the driver could automatically search and establish a connection on the specified port.
209-
- Incorporating PCAP: For PCAP connections the ROS parameter `device` could be generalized to accept the path to the .pcap file. In this case, the node could exit automatically after finishing playback.
210212
- Publishing the topic `/measepoch`: It could accept the custom ROS message `septentrio_gnss_driver/MeasEpoch.msg`, corresponding to the SBF block `MeasEpoch` (raw GNSS data).
211213
- Publishing the topic `/twist`: It could accept the generic ROS message [`geometry_msgs/TwistWithCovarianceStamped.msg`](https://docs.ros.org/melodic/api/geometry_msgs/html/msg/TwistWithCovarianceStamped.html), converted from the SBF blocks `PVTGeodetic`, `PosCovGeodetic` and others or via standardized NMEA sentences (cf. the [NMEA driver](https://wiki.ros.org/nmea_navsat_driver)).
212214
- The ROS message [`geometry_msgs/TwistWithCovarianceStamped.msg`](https://docs.ros.org/melodic/api/geometry_msgs/html/msg/TwistWithCovarianceStamped.html) could be fed directly into the [`robot_localization`](https://docs.ros.org/melodic/api/robot_localization/html/index.html) nodes of the ROS navigation stack.

include/septentrio_gnss_driver/communication/communication_core.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ namespace io_comm_rx {
142142
* @param[in] file_name The name of (or path to) the SBF file, e.g. "xyz.sbf"
143143
*/
144144
void initializeSBFFileReading(std::string file_name);
145+
146+
/**
147+
* @brief Initializes PCAP file reading and reads PCAP file by repeatedly
148+
* calling read_callback_()
149+
* @param[in] file_name The name of (or path to) the PCAP file, e.g. "/tmp/capture.pcap"
150+
*/
151+
void initializePCAPFileReading(std::string file_name);
152+
145153
/**
146154
* @brief Set the I/O manager
147155
* @param[in] manager An I/O handler
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// *****************************************************************************
2+
//
3+
// © Copyright 2020, Septentrio NV/SA.
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are met:
8+
// 1. Redistributions of source code must retain the above copyright
9+
// notice, this list of conditions and the following disclaimer.
10+
// 2. Redistributions in binary form must reproduce the above copyright
11+
// notice, this list of conditions and the following disclaimer in the
12+
// documentation and/or other materials provided with the distribution.
13+
// 3. Neither the name of the copyright holder nor the names of its
14+
// contributors may be used to endorse or promote products derived
15+
// from this software without specific prior written permission.
16+
//
17+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
// POSSIBILITY OF SUCH DAMAGE.
28+
//
29+
// *****************************************************************************
30+
31+
#ifndef PCAP_READER_H
32+
#define PCAP_READER_H
33+
34+
#include <pcap/pcap.h>
35+
#include <stdint.h>
36+
#include <vector>
37+
38+
/**
39+
* @file pcap_reader.hpp
40+
* @date 07/05/2021
41+
* @author Ashwin A Nayar
42+
*
43+
* @brief Declares a class for handling pcap files.
44+
*/
45+
46+
namespace pcapReader {
47+
48+
using buffer_t = std::vector<uint8_t>;
49+
50+
//! Read operation status
51+
enum ReadResult
52+
{
53+
/// Data read successfully
54+
READ_SUCCESS = 0,
55+
READ_INSUFFICIENT_DATA = 1,
56+
READ_TIMEOUT = 2,
57+
READ_INTERRUPTED = 3,
58+
READ_ERROR = -1,
59+
/// Unable to parse data, parsing error
60+
READ_PARSE_FAILED = -2
61+
62+
};
63+
64+
/**
65+
* @class PcapDevice
66+
* @brief Class for handling a pcap file
67+
*/
68+
class PcapDevice
69+
{
70+
public:
71+
static const size_t BUFFSIZE = 100;
72+
73+
/**
74+
* @brief Constructor for PcapDevice
75+
* @param[out] buffer Buffer to write read raw data to
76+
*/
77+
explicit PcapDevice(buffer_t& buffer);
78+
79+
/**
80+
* @brief Try to open a pcap file
81+
* @param[in] device Path to pcap file
82+
* @return True if success, false otherwise
83+
*/
84+
bool connect(const char* device);
85+
86+
/**
87+
* @brief Close connected file
88+
*/
89+
void disconnect();
90+
91+
/**
92+
* @brief Check if file is open and healthy
93+
* @return True if file is open, false otherwise
94+
*/
95+
bool isConnected() const;
96+
97+
/**
98+
* @brief Attempt to read a packet and store data to buffer
99+
* @return Result of read operation
100+
*/
101+
ReadResult read();
102+
103+
//! Destructor for PcapDevice
104+
~PcapDevice();
105+
106+
private:
107+
//! Reference to raw data buffer to write to
108+
buffer_t& m_dataBuff;
109+
//! File handle to pcap file
110+
pcap_t* m_device{nullptr};
111+
bpf_program m_pktFilter{};
112+
char m_errBuff[BUFFSIZE]{};
113+
char* m_deviceName;
114+
buffer_t m_lastPkt;
115+
};
116+
} // namespace pcapReader
117+
118+
#endif // PCAP_READER_H

include/septentrio_gnss_driver/communication/rx_message.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ extern boost::shared_ptr<ros::NodeHandle> g_nh;
172172
extern const uint32_t g_ROS_QUEUE_SIZE;
173173
extern ros::Time g_unix_time;
174174
extern bool g_read_from_sbf_log;
175+
extern bool g_read_from_pcap;
175176

176177
//! Enum for NavSatFix's status.status field, which is obtained from PVTGeodetic's
177178
//! Mode field

include/septentrio_gnss_driver/node/rosaic_node.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ namespace rosaic_node {
219219
*/
220220
void prepareSBFFileReading(std::string file_name);
221221

222+
/**
223+
* @brief Sets up the stage for PCAP file reading
224+
* @param[in] file_name The path to PCAP file, e.g. "/tmp/capture.sbf"
225+
*/
226+
void preparePCAPFileReading(std::string file_name);
227+
222228
/**
223229
* @brief Attempts to (re)connect every reconnect_delay_s_ seconds
224230
*/

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
<depend>geometry_msgs</depend>
5656
<depend>gps_common</depend>
5757
<depend>boost</depend>
58+
<depend>libpcap</depend>
5859

5960

6061
<build_depend>cpp_common</build_depend>

src/septentrio_gnss_driver/communication/communication_core.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
// *****************************************************************************
3030

3131
#include <septentrio_gnss_driver/communication/communication_core.hpp>
32+
#include <septentrio_gnss_driver/communication/pcap_reader.hpp>
3233

3334
/**
3435
* @file communication_core.cpp
@@ -159,6 +160,58 @@ void io_comm_rx::Comm_IO::initializeSBFFileReading(std::string file_name)
159160
ROS_DEBUG("Leaving initializeSBFFileReading() method..");
160161
}
161162

163+
void io_comm_rx::Comm_IO::initializePCAPFileReading(std::string file_name)
164+
{
165+
ROS_DEBUG("Calling initializePCAPFileReading() method..");
166+
pcapReader::buffer_t vec_buf;
167+
pcapReader::PcapDevice device(vec_buf);
168+
169+
if (!device.connect(file_name.c_str()))
170+
{
171+
ROS_ERROR("Unable to find file or either it is corrupted");
172+
return;
173+
}
174+
175+
ROS_INFO("Reading ...");
176+
while (device.isConnected() && device.read() == pcapReader::READ_SUCCESS)
177+
;
178+
device.disconnect();
179+
180+
std::size_t buffer_size = pcapReader::PcapDevice::BUFFSIZE;
181+
uint8_t* to_be_parsed = new uint8_t[buffer_size];
182+
to_be_parsed = &vec_buf[0];
183+
184+
while (1) // Loop will stop if we are done reading the SBF file
185+
{
186+
try
187+
{
188+
ROS_DEBUG(
189+
"Calling read_callback_() method, with number of bytes to be parsed being %li",
190+
buffer_size);
191+
handlers_.readCallback(to_be_parsed, buffer_size);
192+
} catch (std::size_t& parsing_failed_here)
193+
{
194+
if (to_be_parsed - &vec_buf[0] >= vec_buf.size() * sizeof(uint8_t))
195+
{
196+
break;
197+
}
198+
if (!parsing_failed_here)
199+
parsing_failed_here = 1;
200+
201+
to_be_parsed = to_be_parsed + parsing_failed_here;
202+
ROS_DEBUG("Parsing_failed_here is %li", parsing_failed_here);
203+
continue;
204+
}
205+
if (to_be_parsed - &vec_buf[0] >= vec_buf.size() * sizeof(uint8_t))
206+
{
207+
break;
208+
}
209+
to_be_parsed = to_be_parsed + buffer_size;
210+
}
211+
delete[] to_be_parsed;
212+
ROS_DEBUG("Leaving initializePCAPFileReading() method..");
213+
}
214+
162215
bool io_comm_rx::Comm_IO::initializeSerial(std::string port, uint32_t baudrate,
163216
std::string flowcontrol)
164217
{

0 commit comments

Comments
 (0)