ROSaic
Public Member Functions | Data Fields | Private Types | Private Member Functions | Private Attributes | Static Private Attributes
io_comm_rx::RxMessage Class Reference

Can search buffer for messages, read/parse them, and so on. More...

#include <rx_message.hpp>

Collaboration diagram for io_comm_rx::RxMessage:
Collaboration graph
[legend]

Public Member Functions

 RxMessage (const uint8_t *data, std::size_t &size)
 Constructor of the RxMessage class. More...
 
bool isMessage (const uint16_t ID)
 Determines whether data_ points to the SBF block with ID "ID", e.g. 5003. More...
 
bool isMessage (std::string ID)
 Determines whether data_ points to the NMEA message with ID "ID", e.g. "$GPGGA". More...
 
bool isSBF ()
 Determines whether data_ currently points to an SBF block. More...
 
bool isNMEA ()
 Determines whether data_ currently points to an NMEA message. More...
 
bool isResponse ()
 Determines whether data_ currently points to an NMEA message. More...
 
bool isConnectionDescriptor ()
 
bool isErrorMessage ()
 Determines whether data_ currently points to an error message reply from the Rx. More...
 
std::size_t messageSize ()
 Determines size of the message (also command reply) that data_ is currently pointing at. More...
 
std::string messageID ()
 
std::size_t getCount ()
 Returns the count_ variable. More...
 
const uint8_t * search ()
 Searches the buffer for the beginning of the next message (NMEA or SBF) More...
 
uint16_t getBlockLength ()
 Gets the length of the SBF block. More...
 
const uint8_t * getPosBuffer ()
 Gets the current position in the read buffer. More...
 
const uint8_t * getEndBuffer ()
 Gets the end position in the read buffer. More...
 
bool found ()
 Has an NMEA message, SBF block or command reply been found in the buffer? More...
 
void next ()
 Goes to the start of the next message based on the calculated length of current message. More...
 
template<typename T >
bool read (typename boost::call_traits< T >::reference message, std::string message_key, bool search=false)
 Performs the CRC check (if SBF) and populates ROS message "message" with the necessary content. More...
 

Data Fields

bool found_
 Whether or not a message has been found. More...
 

Private Types

typedef std::map< uint16_t, TypeOfPVT_EnumTypeOfPVTMap
 Shorthand for the map responsible for matching PVTGeodetic's Mode field to an enum value. More...
 
typedef std::map< std::string, RxID_EnumRxIDMap
 Shorthand for the map responsible for matching ROS message identifiers to an enum value. More...
 

Private Member Functions

septentrio_gnss_driver::PVTCartesianPtr PVTCartesianCallback (PVTCartesian &data)
 Callback function when reading PVTCartesian blocks. More...
 
septentrio_gnss_driver::PVTGeodeticPtr PVTGeodeticCallback (PVTGeodetic &data)
 Callback function when reading PVTGeodetic blocks. More...
 
septentrio_gnss_driver::PosCovCartesianPtr PosCovCartesianCallback (PosCovCartesian &data)
 Callback function when reading PosCovCartesian blocks. More...
 
septentrio_gnss_driver::PosCovGeodeticPtr PosCovGeodeticCallback (PosCovGeodetic &data)
 Callback function when reading PosCovGeodetic blocks. More...
 
septentrio_gnss_driver::AttEulerPtr AttEulerCallback (AttEuler &data)
 Callback function when reading AttEuler blocks. More...
 
septentrio_gnss_driver::AttCovEulerPtr AttCovEulerCallback (AttCovEuler &data)
 Callback function when reading AttCovEuler blocks. More...
 
sensor_msgs::NavSatFixPtr NavSatFixCallback ()
 "Callback" function when constructing NavSatFix messages More...
 
gps_common::GPSFixPtr GPSFixCallback ()
 "Callback" function when constructing GPSFix messages More...
 
geometry_msgs::PoseWithCovarianceStampedPtr PoseWithCovarianceStampedCallback ()
 "Callback" function when constructing PoseWithCovarianceStamped messages More...
 
diagnostic_msgs::DiagnosticArrayPtr DiagnosticArrayCallback ()
 "Callback" function when constructing diagnostic_msgs::DiagnosticArray messages More...
 

Private Attributes

const uint8_t * data_
 Pointer to the buffer of messages. More...
 
std::size_t count_
 Number of unread bytes in the buffer. More...
 
bool crc_check_
 Whether the CRC check as evaluated in the read() method was successful or not is stored here. More...
 
std::size_t message_size_
 Helps to determine size of response message / NMEA message / SBF block. More...
 

Static Private Attributes

static uint32_t count_gpsfix_ = 0
 Number of times the gps_common::GPSFix message has been published. More...
 
static PVTGeodetic last_pvtgeodetic_ = PVTGeodetic()
 Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks need to be stored. More...
 
static PosCovGeodetic last_poscovgeodetic_ = PosCovGeodetic()
 Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic blocks need to be stored. More...
 
static AttEuler last_atteuler_ = AttEuler()
 Since GPSFix etc. need AttEuler, incoming AttEuler blocks need to be stored. More...
 
static AttCovEuler last_attcoveuler_ = AttCovEuler()
 Since GPSFix etc. need AttCovEuler, incoming AttCovEuler blocks need to be stored. More...
 
static ChannelStatus last_channelstatus_ = ChannelStatus()
 Since GPSFix needs ChannelStatus, incoming ChannelStatus blocks need to be stored. More...
 
static MeasEpoch last_measepoch_ = MeasEpoch()
 Since GPSFix needs MeasEpoch (for SNRs), incoming MeasEpoch blocks need to be stored. More...
 
static DOP last_dop_ = DOP()
 Since GPSFix needs DOP, incoming DOP blocks need to be stored. More...
 
static VelCovGeodetic last_velcovgeodetic_ = VelCovGeodetic()
 Since GPSFix needs VelCovGeodetic, incoming VelCovGeodetic blocks need to be stored. More...
 
static ReceiverStatus last_receiverstatus_ = ReceiverStatus()
 Since DiagnosticArray needs ReceiverStatus, incoming ReceiverStatus blocks need to be stored. More...
 
static QualityInd last_qualityind_ = QualityInd()
 Since DiagnosticArray needs QualityInd, incoming QualityInd blocks need to be stored. More...
 
static ReceiverSetup last_receiversetup_ = ReceiverSetup()
 Since DiagnosticArray needs ReceiverSetup, incoming ReceiverSetup blocks need to be stored. More...
 
static TypeOfPVTMap type_of_pvt_map
 All instances of the RxMessage class shall have access to the map without reinitializing it, hence static. More...
 
static RxIDMap rx_id_map
 All instances of the RxMessage class shall have access to the map without reinitializing it, hence static. More...
 

Detailed Description

Can search buffer for messages, read/parse them, and so on.

Definition at line 200 of file rx_message.hpp.

Member Typedef Documentation

◆ RxIDMap

typedef std::map<std::string, RxID_Enum> io_comm_rx::RxMessage::RxIDMap
private

Shorthand for the map responsible for matching ROS message identifiers to an enum value.

Definition at line 384 of file rx_message.hpp.

◆ TypeOfPVTMap

typedef std::map<uint16_t, TypeOfPVT_Enum> io_comm_rx::RxMessage::TypeOfPVTMap
private

Shorthand for the map responsible for matching PVTGeodetic's Mode field to an enum value.

Definition at line 376 of file rx_message.hpp.

Constructor & Destructor Documentation

◆ RxMessage()

io_comm_rx::RxMessage::RxMessage ( const uint8_t *  data,
std::size_t &  size 
)
inline

Constructor of the RxMessage class.

One can always provide a non-const value where a const one was expected. The const-ness of the argument just means the function promises not to change it.. Recall: static_cast by the way can remove or add const-ness, no other C++ cast is capable of removing it (not even reinterpret_cast)

Parameters
[in]dataPointer to the buffer that is about to be analyzed
[in]sizeSize of the buffer (as handed over by async_read_some)

Definition at line 213 of file rx_message.hpp.

References crc_check_, found_, isConnectionDescriptor(), isErrorMessage(), isMessage(), isNMEA(), isResponse(), isSBF(), message_size_, messageID(), and messageSize().

213  : data_(data), count_(size)
214  {found_ = false; crc_check_ = false; message_size_ = 0;}
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
bool found_
Whether or not a message has been found.
Definition: rx_message.hpp:291
std::size_t message_size_
Helps to determine size of response message / NMEA message / SBF block.
Definition: rx_message.hpp:313
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
bool crc_check_
Whether the CRC check as evaluated in the read() method was successful or not is stored here...
Definition: rx_message.hpp:308
Here is the call graph for this function:

Member Function Documentation

◆ AttCovEulerCallback()

septentrio_gnss_driver::AttCovEulerPtr io_comm_rx::RxMessage::AttCovEulerCallback ( AttCovEuler data)
private

Callback function when reading AttCovEuler blocks.

Parameters
[in]dataThe (packed and aligned) struct instance used to populate the ROS message AttCovEuler
Returns
A smart pointer to the ROS message AttCovEuler just created

Definition at line 252 of file rx_message.cpp.

References AttCovEuler::block_header, AttCovEuler::cov_headhead, AttCovEuler::cov_headpitch, AttCovEuler::cov_headroll, AttCovEuler::cov_pitchpitch, AttCovEuler::cov_pitchroll, AttCovEuler::cov_rollroll, BlockHeader_t::crc, AttCovEuler::error, BlockHeader_t::id, BlockHeader_t::length, BlockHeader_t::sync_1, BlockHeader_t::sync_2, AttCovEuler::tow, and AttCovEuler::wnc.

Referenced by read().

253 {
254  septentrio_gnss_driver::AttCovEulerPtr msg = boost::make_shared<septentrio_gnss_driver::AttCovEuler>();
255  msg->block_header.sync_1 = data.block_header.sync_1;
256  msg->block_header.sync_2 = data.block_header.sync_2;
257  msg->block_header.crc = data.block_header.crc;
258  msg->block_header.id = data.block_header.id;
259  msg->block_header.length = data.block_header.length;
260  msg->block_header.tow = data.tow;
261  msg->block_header.wnc = data.wnc;
262  msg->error = data.error;
263  msg->cov_headhead = data.cov_headhead;
264  msg->cov_pitchpitch = data.cov_pitchpitch;
265  msg->cov_rollroll = data.cov_rollroll;
266  msg->cov_headpitch = data.cov_headpitch;
267  msg->cov_headroll = data.cov_headroll;
268  msg->cov_pitchroll = data.cov_pitchroll;
269  return msg;
270 };
float cov_headroll
float cov_rollroll
uint16_t length
Length of the entire message including the header. A multiple of 4 between 8 and 4096.
float cov_headpitch
uint16_t crc
The check sum.
uint16_t wnc
uint8_t sync_1
first sync byte is $ or 0x24
uint32_t tow
float cov_pitchroll
float cov_headhead
uint16_t id
This is the block ID.
uint8_t sync_2
2nd sync byte is @ or 0x40
float cov_pitchpitch
BlockHeader_t block_header
uint8_t error
Here is the caller graph for this function:

◆ AttEulerCallback()

septentrio_gnss_driver::AttEulerPtr io_comm_rx::RxMessage::AttEulerCallback ( AttEuler data)
private

Callback function when reading AttEuler blocks.

Parameters
[in]dataThe (packed and aligned) struct instance used to populate the ROS message AttEuler
Returns
A smart pointer to the ROS message AttEuler just created

Definition at line 230 of file rx_message.cpp.

References AttEuler::block_header, BlockHeader_t::crc, AttEuler::error, AttEuler::heading, AttEuler::heading_dot, BlockHeader_t::id, BlockHeader_t::length, AttEuler::mode, AttEuler::nr_sv, AttEuler::pitch, AttEuler::pitch_dot, AttEuler::roll, AttEuler::roll_dot, BlockHeader_t::sync_1, BlockHeader_t::sync_2, AttEuler::tow, and AttEuler::wnc.

Referenced by read().

231 {
232  septentrio_gnss_driver::AttEulerPtr msg = boost::make_shared<septentrio_gnss_driver::AttEuler>();
233  msg->block_header.sync_1 = data.block_header.sync_1;
234  msg->block_header.sync_2 = data.block_header.sync_2;
235  msg->block_header.crc = data.block_header.crc;
236  msg->block_header.id = data.block_header.id;
237  msg->block_header.length = data.block_header.length;
238  msg->block_header.tow = data.tow;
239  msg->block_header.wnc = data.wnc;
240  msg->nr_sv = data.nr_sv;
241  msg->error = data.error;
242  msg->mode = data.mode;
243  msg->heading = data.heading;
244  msg->pitch = data.pitch;
245  msg->roll = data.roll;
246  msg->pitch_dot = data.pitch_dot;
247  msg->roll_dot = data.roll_dot;
248  msg->heading_dot = data.heading_dot;
249  return msg;
250 };
uint16_t mode
uint16_t length
Length of the entire message including the header. A multiple of 4 between 8 and 4096.
uint16_t crc
The check sum.
float heading_dot
float roll_dot
uint8_t sync_1
first sync byte is $ or 0x24
float pitch_dot
uint8_t error
float heading
float pitch
BlockHeader_t block_header
uint32_t tow
uint16_t id
This is the block ID.
uint8_t sync_2
2nd sync byte is @ or 0x40
uint8_t nr_sv
float roll
uint16_t wnc
Here is the caller graph for this function:

◆ DiagnosticArrayCallback()

diagnostic_msgs::DiagnosticArrayPtr io_comm_rx::RxMessage::DiagnosticArrayCallback ( )
private

"Callback" function when constructing diagnostic_msgs::DiagnosticArray messages

Returns
A smart pointer to the ROS message diagnostic_msgs::DiagnosticArray just created

Definition at line 332 of file rx_message.cpp.

References QualityInd::indicators, last_qualityind_, last_receiversetup_, last_receiverstatus_, QualityInd::n, ReceiverStatus::rx_error, and ReceiverSetup::rx_serial_number.

Referenced by read().

333 {
334  diagnostic_msgs::DiagnosticArrayPtr msg = boost::make_shared<diagnostic_msgs::DiagnosticArray>();
335  std::string serialnumber(last_receiversetup_.rx_serial_number);
336  diagnostic_msgs::DiagnosticStatusPtr gnss_status = boost::make_shared<diagnostic_msgs::DiagnosticStatus>();
337  // Constructing the "level of operation" field
338  uint16_t indicators_type_mask = static_cast<uint16_t>(255);
339  uint16_t indicators_value_mask = static_cast<uint16_t>(3840);
340  uint16_t qualityind_pos;
341  for(uint16_t i = static_cast<uint16_t>(0); i != last_qualityind_.n; ++i)
342  {
343  if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(0))
344  {
345  qualityind_pos = i;
346  if(((last_qualityind_.indicators[i] & indicators_value_mask) >> 8) == static_cast<uint16_t>(0))
347  {
348  gnss_status->level = diagnostic_msgs::DiagnosticStatus::STALE;
349  }
350  else if(((last_qualityind_.indicators[i] & indicators_value_mask) >> 8) == static_cast<uint16_t>(1)
351  || ((last_qualityind_.indicators[i] & indicators_value_mask) >> 8)== static_cast<uint16_t>(2))
352  {
353  gnss_status->level = diagnostic_msgs::DiagnosticStatus::WARN;
354  }
355  else
356  {
357  gnss_status->level = diagnostic_msgs::DiagnosticStatus::OK;
358  }
359  break;
360  }
361  }
362  // If the ReceiverStatus's RxError field is not 0, then at least one error has been detected.
363  if(last_receiverstatus_.rx_error != static_cast<uint32_t>(0))
364  {
365  gnss_status->level = diagnostic_msgs::DiagnosticStatus::ERROR;
366  }
367  // Creating an array of values associated with the GNSS status
368  gnss_status->values.resize(static_cast<uint16_t>(last_qualityind_.n-1));
369  for(uint16_t i = static_cast<uint16_t>(0); i != static_cast<uint16_t>(last_qualityind_.n); ++i)
370  {
371  if(i == qualityind_pos)
372  {
373  continue;
374  }
375  if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(1))
376  {
377  gnss_status->values[i].key = "GNSS Signals, Main Antenna";
378  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
379  }
380  else if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(2))
381  {
382  gnss_status->values[i].key = "GNSS Signals, Aux1 Antenna";
383  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
384  }
385  else if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(11))
386  {
387  gnss_status->values[i].key = "RF Power, Main Antenna";
388  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
389  }
390  else if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(12))
391  {
392  gnss_status->values[i].key = "RF Power, Aux1 Antenna";
393  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
394  }
395  else if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(21))
396  {
397  gnss_status->values[i].key = "CPU Headroom";
398  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
399  }
400  else if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(25))
401  {
402  gnss_status->values[i].key = "OCXO Stability";
403  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
404  }
405  else if((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(30))
406  {
407  gnss_status->values[i].key = "Base Station Measurements";
408  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
409  }
410  else
411  {
412  assert ((last_qualityind_.indicators[i] & indicators_type_mask) == static_cast<uint16_t>(31));
413  gnss_status->values[i].key = "RTK Post-Processing";
414  gnss_status->values[i].value = std::to_string((last_qualityind_.indicators[i] & indicators_value_mask) >> 8);
415  }
416  }
417  gnss_status->hardware_id = serialnumber;
418  gnss_status->name = "GNSS";
419  gnss_status->message = "Quality Indicators (from 0 for low quality to 10 for high quality, 15 if unknown)";
420  msg->status.push_back(*gnss_status);
421  return msg;
422 }
char rx_serial_number[20]
static ReceiverStatus last_receiverstatus_
Since DiagnosticArray needs ReceiverStatus, incoming ReceiverStatus blocks need to be stored...
Definition: rx_message.hpp:363
uint16_t indicators[40]
uint32_t rx_error
static ReceiverSetup last_receiversetup_
Since DiagnosticArray needs ReceiverSetup, incoming ReceiverSetup blocks need to be stored...
Definition: rx_message.hpp:373
static QualityInd last_qualityind_
Since DiagnosticArray needs QualityInd, incoming QualityInd blocks need to be stored.
Definition: rx_message.hpp:368
Here is the caller graph for this function:

◆ found()

bool io_comm_rx::RxMessage::found ( )

Has an NMEA message, SBF block or command reply been found in the buffer?

Returns
True if a message with the correct header & length has been found

Definition at line 820 of file rx_message.cpp.

References found_, g_read_cd, isConnectionDescriptor(), isNMEA(), isResponse(), and isSBF().

Referenced by getCount(), next(), read(), and io_comm_rx::CallbackHandlers::readCallback().

821 {
822  if (found_) return true;
823 
824  // Verify header bytes
825  if (!this->isSBF() && !this->isNMEA() && !this->isResponse() && !(g_read_cd && this->isConnectionDescriptor()))
826  {
827  return false;
828  }
829 
830  found_ = true;
831  return true;
832 }
bool isResponse()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:972
bool isNMEA()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:952
bool g_read_cd
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
bool found_
Whether or not a message has been found.
Definition: rx_message.hpp:291
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getBlockLength()

uint16_t io_comm_rx::RxMessage::getBlockLength ( )

Gets the length of the SBF block.

It determines the length from the header of the SBF block. The block length thus includes the header length.

Returns
The length of the SBF block

Definition at line 1066 of file rx_message.cpp.

References data_, and isSBF().

Referenced by getCount(), next(), and io_comm_rx::CallbackHandlers::readCallback().

1067 {
1068  if (this->isSBF())
1069  {
1070  uint16_t block_length;
1071  // Note that static_cast<uint16_t>(data_[6]) would just take the one byte "data_[6]"
1072  // and cast it as requested, !neglecting! the byte "data_[7]".
1073  block_length = *(reinterpret_cast<const uint16_t*>(data_ + 6));
1074  return block_length;
1075  }
1076  else
1077  {
1078  return 0;
1079  }
1080 }
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCount()

std::size_t io_comm_rx::RxMessage::getCount ( )
inline

Returns the count_ variable.

Returns
The variable count_

Definition at line 241 of file rx_message.hpp.

References count_, found(), getBlockLength(), getEndBuffer(), getPosBuffer(), next(), read(), and search().

Referenced by io_comm_rx::CallbackHandlers::readCallback().

241 {return count_;};
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getEndBuffer()

const uint8_t * io_comm_rx::RxMessage::getEndBuffer ( )

Gets the end position in the read buffer.

Returns
A pointer pointing to just after the read buffer (matches search()'s final pointer in case no valid message is found)

Definition at line 1061 of file rx_message.cpp.

References count_, and data_.

Referenced by getCount(), and io_comm_rx::CallbackHandlers::readCallback().

1062 {
1063  return data_ + count_;
1064 }
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the caller graph for this function:

◆ getPosBuffer()

const uint8_t * io_comm_rx::RxMessage::getPosBuffer ( )

Gets the current position in the read buffer.

Returns
The current position of the read buffer

Definition at line 1056 of file rx_message.cpp.

References data_.

Referenced by getCount(), and io_comm_rx::CallbackHandlers::readCallback().

1057 {
1058  return data_;
1059 }
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the caller graph for this function:

◆ GPSFixCallback()

gps_common::GPSFixPtr io_comm_rx::RxMessage::GPSFixCallback ( )
private

"Callback" function when constructing GPSFix messages

Returns
A smart pointer to the ROS message GPSFix just created

For some unknown reason, the first 2 entries of the GPSStatus field's arrays are not shown properly when published. Please consult section 4.1.9 of the firmware (at least for mosaic-x5) to understand the meaning of the SV identifiers used in the arrays of the GPSStatus field. Note that the field "dip" denotes the local magnetic inclination in degrees (positive when the magnetic field points downwards (into the Earth)). This quantity cannot be calculated by most Septentrio receivers. We assume that for the ROS field "err_time", we are requested to provide the 2 sigma uncertainty on the clock bias estimate in square meters, not the clock drift estimate (latter would be "2*std::sqrt(static_cast<double>(last_velcovgeodetic_.Cov_DtDt))"). The "err_track" entry is calculated via the Gaussian error propagation formula from the eastward and the northward velocities. For the formula's usage we have to assume that the eastward and the northward velocities are independent variables. Note that elevations and azimuths of visible satellites are taken from the ChannelStatus block, which provides 1 degree precision, while the SatVisibility block could provide hundredths of degrees precision. Change if imperative for your application... Definition of "visible satellite" adopted here: We define a visible satellite as being !up to! "in sync" mode with the receiver, which corresponds to last_measepoch_.N (signal-to-noise ratios are thereby available for these), though not last_channelstatus_.N, which also includes those "in search". In case certain values appear unphysical, please consult the firmware, since those most likely refer to Do-Not-Use values.

Definition at line 519 of file rx_message.cpp.

References ChannelSatInfo::az_rise_set, ChannelStatus::block_header, MeasEpoch::block_header, MeasEpochChannelType1::cn0, PVTGeodetic::cog, PosCovGeodetic::cov_bb, PosCovGeodetic::cov_hgthgt, PosCovGeodetic::cov_lathgt, PosCovGeodetic::cov_latlat, PosCovGeodetic::cov_latlon, PosCovGeodetic::cov_lonhgt, PosCovGeodetic::cov_lonlon, AttCovEuler::cov_pitchpitch, AttCovEuler::cov_rollroll, VelCovGeodetic::cov_veve, VelCovGeodetic::cov_vnvn, VelCovGeodetic::cov_vuvu, ChannelStatus::data, MeasEpoch::data, ChannelSatInfo::elev, evDGPS, evFixed, evMovingBaseRTKFixed, evMovingBaseRTKFloat, evNoPVT, evPPP, evRTKFixed, evRTKFloat, evSBAS, evStandAlone, DOP::hdop, PVTGeodetic::height, last_attcoveuler_, last_atteuler_, last_channelstatus_, last_dop_, last_measepoch_, last_poscovgeodetic_, last_pvtgeodetic_, last_velcovgeodetic_, PVTGeodetic::latitude, PVTGeodetic::longitude, PVTGeodetic::mode, ChannelStatus::n, MeasEpoch::n, ChannelSatInfo::n2, MeasEpochChannelType1::n_type2, PVTGeodetic::nr_sv, DOP::pdop, AttEuler::pitch, ChannelStateInfo::pvt_status, PVTGeodetic::reference_id, AttEuler::roll, ChannelStatus::sb1_size, MeasEpoch::sb1_size, ChannelStatus::sb2_size, MeasEpoch::sb2_size, ChannelSatInfo::sv_id, MeasEpochChannelType1::sv_id, BlockHeader_t::sync_1, DOP::tdop, PVTGeodetic::tow, MeasEpochChannelType1::type, type_of_pvt_map, DOP::vdop, PVTGeodetic::ve, PVTGeodetic::vn, PVTGeodetic::vu, and PVTGeodetic::wnc.

Referenced by read().

520 {
521  gps_common::GPSFixPtr msg = boost::make_shared<gps_common::GPSFix>();
522 
523  msg->status.satellites_used = static_cast<uint16_t>(last_pvtgeodetic_.nr_sv);
524 
525  // MeasEpoch Processing
526  std::vector<int32_t> cno_tracked;
527  std::vector<int32_t> svid_in_sync;
528  {
529  uint8_t sb1_size = last_measepoch_.sb1_size;
530  uint8_t sb2_size = last_measepoch_.sb2_size;
531  uint8_t *sb_start = &last_measepoch_.data[0];
532  int32_t index = sb_start - &last_measepoch_.block_header.sync_1;
533  for (int32_t i = 0; i < static_cast<int32_t>(last_measepoch_.n); ++i)
534  {
535  // Define MeasEpochChannelType1 struct for the corresponding sub-block
536  MeasEpochChannelType1 *measepoch_channel_type1 =
537  reinterpret_cast<MeasEpochChannelType1*>(&last_measepoch_.block_header.sync_1 + index);
538  svid_in_sync.push_back(static_cast<int32_t>(measepoch_channel_type1->sv_id));
539  uint8_t type_mask = 15; // We extract the first four bits using this mask.
540  if (((measepoch_channel_type1->type & type_mask) == static_cast<uint8_t>(1)) ||
541  ((measepoch_channel_type1->type & type_mask) == static_cast<uint8_t>(2)))
542  {
543  cno_tracked.push_back(static_cast<int32_t>(measepoch_channel_type1->cn0)/4);
544  }
545  else
546  {
547  cno_tracked.push_back(static_cast<int32_t>(measepoch_channel_type1->cn0)/4+static_cast<int32_t>(10));
548  }
549  index += sb1_size;
550  for (int32_t j = 0; j < static_cast<int32_t>(measepoch_channel_type1->n_type2); j++)
551  {
552  index += sb2_size;
553  }
554  }
555  }
556 
557  // ChannelStatus Processing
558  std::vector<int32_t> svid_in_sync_2;
559  std::vector<int32_t> elevation_tracked;
560  std::vector<int32_t> azimuth_tracked;
561  std::vector<int32_t> svid_pvt;
562  svid_pvt.clear();
563  std::vector<int32_t> ordering;
564  {
565  uint8_t sb1_size = last_channelstatus_.sb1_size;
566  uint8_t sb2_size = last_channelstatus_.sb2_size;
567  uint8_t *sb_start = &last_channelstatus_.data[0];
568  int32_t index = sb_start - &last_channelstatus_.block_header.sync_1;
569  //ROS_DEBUG("index is %i", index); // yields 20, as expected
570 
571  uint16_t azimuth_mask = 511;
572  for (int32_t i = 0; i < static_cast<int32_t>(last_channelstatus_.n); i++)
573  {
574  // Define ChannelSatInfo struct for the corresponding sub-block
575  ChannelSatInfo *channel_sat_info =
576  reinterpret_cast<ChannelSatInfo*>(&last_channelstatus_.block_header.sync_1 + index);
577  bool to_be_added = false;
578  for (int32_t j = 0; j < static_cast<int32_t>(svid_in_sync.size()); ++j)
579  {
580  if (svid_in_sync[j] == static_cast<int32_t>(channel_sat_info->sv_id))
581  {
582  ordering.push_back(j);
583  to_be_added = true;
584  break;
585  }
586  }
587  if (to_be_added)
588  {
589  svid_in_sync_2.push_back(static_cast<int32_t>(channel_sat_info->sv_id));
590  elevation_tracked.push_back(static_cast<int32_t>(channel_sat_info->elev));
591  azimuth_tracked.push_back(static_cast<int32_t>((channel_sat_info->az_rise_set & azimuth_mask)));
592  }
593  index += sb1_size;
594  for (int32_t j = 0; j < static_cast<int32_t>(channel_sat_info->n2); j++)
595  {
596  // Define ChannelStateInfo struct for the corresponding sub-block
597  ChannelStateInfo *channel_state_info =
598  reinterpret_cast<ChannelStateInfo*>(&last_channelstatus_.block_header.sync_1 + index);
599  bool pvt_status = false;
600  uint16_t pvt_status_mask = std::pow(2,15)+std::pow(2,14);
601  for(int k = 15; k != -1; k -= 2)
602  {
603  uint16_t pvt_status_value = (channel_state_info->pvt_status & pvt_status_mask) >> k-1;
604  if (pvt_status_value == 2)
605  {
606  pvt_status = true;
607  }
608  if (k > 1)
609  {
610  pvt_status_mask = pvt_status_mask - std::pow(2,k) - std::pow(2,k-1)
611  + std::pow(2,k-2) + std::pow(2,k-3);
612  }
613  }
614  if (pvt_status)
615  {
616  svid_pvt.push_back(static_cast<int32_t>(channel_sat_info->sv_id));
617  }
618  index += sb2_size;
619  }
620  }
621  }
622  msg->status.satellite_used_prn = svid_pvt; // Entries such as int32[] in ROS messages are to be treated as std::vectors.
623  msg->status.satellites_visible = static_cast<uint16_t>(svid_in_sync.size());
624  msg->status.satellite_visible_prn = svid_in_sync_2;
625  msg->status.satellite_visible_z = elevation_tracked;
626  msg->status.satellite_visible_azimuth = azimuth_tracked;
627 
628  // Reordering CNO vector to that of all previous arrays
629  std::vector<int32_t> cno_tracked_reordered;
630  if (static_cast<int32_t>(last_channelstatus_.n) != 0)
631  {
632  for (int32_t k = 0; k < static_cast<int32_t>(ordering.size()); ++k)
633  {
634  cno_tracked_reordered.push_back(cno_tracked[ordering[k]]);
635  }
636  }
637  msg->status.satellite_visible_snr = cno_tracked_reordered;
638 
639  // PVT Status Analysis
640  uint16_t status_mask = 15; // We extract the first four bits using this mask.
641  uint16_t type_of_pvt = ((uint16_t) (last_pvtgeodetic_.mode)) & status_mask;
642  switch(type_of_pvt_map[type_of_pvt])
643  {
644  case evNoPVT:
645  {
646  msg->status.status = gps_common::GPSStatus::STATUS_NO_FIX;
647  break;
648  }
649  case evStandAlone: case evFixed:
650  {
651  msg->status.status = gps_common::GPSStatus::STATUS_FIX;
652  break;
653  }
654  case evDGPS: case evRTKFixed: case evRTKFloat: case evMovingBaseRTKFixed: case evMovingBaseRTKFloat: case evPPP:
655  {
656  msg->status.status = gps_common::GPSStatus::STATUS_GBAS_FIX;
657  break;
658  }
659  case evSBAS:
660  {
661  uint16_t reference_id = last_pvtgeodetic_.reference_id;
662  // Here come the PRNs of the 4 WAAS satellites..
663  if (reference_id == 131 || reference_id == 133 || reference_id == 135 || reference_id == 135)
664  {
665  msg->status.status = gps_common::GPSStatus::STATUS_WAAS_FIX;
666  }
667  else
668  {
669  msg->status.status = gps_common::GPSStatus::STATUS_SBAS_FIX;
670  }
671  break;
672  }
673  default:
674  {
675  throw std::runtime_error("PVTGeodetic's Mode field contains an invalid type of PVT solution.");
676  }
677  }
678  // Doppler is not used when calculating the velocities of, say, mosaic-x5, hence:
679  msg->status.motion_source = gps_common::GPSStatus::SOURCE_POINTS;
680  // Doppler is not used when calculating the orientation of, say, mosaic-x5, hence:
681  msg->status.orientation_source = gps_common::GPSStatus::SOURCE_POINTS;
682  msg->status.position_source = gps_common::GPSStatus::SOURCE_GPS;
683  msg->latitude = static_cast<double>(last_pvtgeodetic_.latitude)*360/(2*boost::math::constants::pi<double>());
684  msg->longitude = static_cast<double>(last_pvtgeodetic_.longitude)*360/(2*boost::math::constants::pi<double>());
685  msg->altitude = static_cast<double>(last_pvtgeodetic_.height);
686  // Note that cog is of type float32 while track is of type float64.
687  msg->track = static_cast<double>(last_pvtgeodetic_.cog);
688  msg->speed = std::sqrt(std::pow(static_cast<double>(last_pvtgeodetic_.vn), 2) +
689  std::pow(static_cast<double>(last_pvtgeodetic_.ve), 2));
690  msg->climb = static_cast<double>(last_pvtgeodetic_.vu);
691  msg->pitch = static_cast<double>(last_atteuler_.pitch);
692  msg->roll = static_cast<double>(last_atteuler_.roll);
693  if (last_dop_.pdop == static_cast<uint16_t>(0) || last_dop_.tdop == static_cast<uint16_t>(0))
694  {
695  msg->gdop = static_cast<double>(-1);
696  }
697  else
698  {
699  msg->gdop = std::sqrt(std::pow(static_cast<double>(last_dop_.pdop)/100, 2) +
700  std::pow(static_cast<double>(last_dop_.tdop)/100, 2));
701  }
702  if (last_dop_.pdop == static_cast<uint16_t>(0))
703  {
704  msg->pdop = static_cast<double>(-1);
705  }
706  else
707  {
708  msg->pdop = static_cast<double>(last_dop_.pdop)/100;
709  }
710  if (last_dop_.hdop == static_cast<uint16_t>(0))
711  {
712  msg->hdop = static_cast<double>(-1);
713  }
714  else
715  {
716  msg->hdop = static_cast<double>(last_dop_.hdop)/100;
717  }
718  if (last_dop_.vdop == static_cast<uint16_t>(0))
719  {
720  msg->vdop = static_cast<double>(-1);
721  }
722  else
723  {
724  msg->vdop = static_cast<double>(last_dop_.vdop)/100;
725  }
726  if (last_dop_.tdop == static_cast<uint16_t>(0))
727  {
728  msg->tdop = static_cast<double>(-1);
729  }
730  else
731  {
732  msg->tdop = static_cast<double>(last_dop_.tdop)/100;
733  }
734  msg->time = static_cast<double>(last_pvtgeodetic_.tow)/1000 + static_cast<double>(last_pvtgeodetic_.wnc*7*24*60*60);
735  msg->err = 2*(std::sqrt(static_cast<double>(last_poscovgeodetic_.cov_latlat) +
736  static_cast<double>(last_poscovgeodetic_.cov_lonlon) + static_cast<double>(last_poscovgeodetic_.cov_hgthgt)));
737  msg->err_horz = 2*(std::sqrt(static_cast<double>(last_poscovgeodetic_.cov_latlat) +
738  static_cast<double>(last_poscovgeodetic_.cov_lonlon)));
739  msg->err_vert = 2*std::sqrt(static_cast<double>(last_poscovgeodetic_.cov_hgthgt));
740  msg->err_track = 2*(std::sqrt(std::pow(static_cast<double>(1)/(static_cast<double>(last_pvtgeodetic_.vn) +
741  std::pow(static_cast<double>(last_pvtgeodetic_.ve),2)/static_cast<double>(last_pvtgeodetic_.vn)),2)*
742  static_cast<double>(last_poscovgeodetic_.cov_lonlon)+std::pow((static_cast<double>(last_pvtgeodetic_.ve))/
743  (std::pow(static_cast<double>(last_pvtgeodetic_.vn),2)+std::pow(static_cast<double>(last_pvtgeodetic_.ve),2)),2)*
744  static_cast<double>(last_poscovgeodetic_.cov_latlat)));
745  msg->err_speed = 2*(std::sqrt(static_cast<double>(last_velcovgeodetic_.cov_vnvn) +
746  static_cast<double>(last_velcovgeodetic_.cov_veve)));
747  msg->err_climb = 2*std::sqrt(static_cast<double>(last_velcovgeodetic_.cov_vuvu));
748  msg->err_time = 2*std::sqrt(static_cast<double>(last_poscovgeodetic_.cov_bb));
749  msg->err_pitch = 2*std::sqrt(static_cast<double>(last_attcoveuler_.cov_pitchpitch));
750  msg->err_roll = 2*std::sqrt(static_cast<double>(last_attcoveuler_.cov_rollroll));
751  msg->position_covariance[0] = static_cast<double>(last_poscovgeodetic_.cov_lonlon);
752  msg->position_covariance[1] = static_cast<double>(last_poscovgeodetic_.cov_latlon);
753  msg->position_covariance[2] = static_cast<double>(last_poscovgeodetic_.cov_lonhgt);
754  msg->position_covariance[3] = static_cast<double>(last_poscovgeodetic_.cov_latlon);
755  msg->position_covariance[4] = static_cast<double>(last_poscovgeodetic_.cov_latlat);
756  msg->position_covariance[5] = static_cast<double>(last_poscovgeodetic_.cov_lathgt);
757  msg->position_covariance[6] = static_cast<double>(last_poscovgeodetic_.cov_lonhgt);
758  msg->position_covariance[7] = static_cast<double>(last_poscovgeodetic_.cov_lathgt);
759  msg->position_covariance[8] = static_cast<double>(last_poscovgeodetic_.cov_hgthgt);
760  msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_KNOWN;
761 
762  return msg;
763 }
uint16_t pdop
static PVTGeodetic last_pvtgeodetic_
Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks need to be stored.
Definition: rx_message.hpp:323
uint8_t sb2_size
uint16_t tdop
float cov_rollroll
static PosCovGeodetic last_poscovgeodetic_
Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic blocks need to be stored...
Definition: rx_message.hpp:328
uint16_t vdop
static DOP last_dop_
Since GPSFix needs DOP, incoming DOP blocks need to be stored.
Definition: rx_message.hpp:353
BlockHeader_t block_header
static MeasEpoch last_measepoch_
Since GPSFix needs MeasEpoch (for SNRs), incoming MeasEpoch blocks need to be stored.
Definition: rx_message.hpp:348
uint16_t wnc
uint8_t sb1_size
Struct for the SBF sub-block "MeasEpochChannelType1".
uint8_t n
static ChannelStatus last_channelstatus_
Since GPSFix needs ChannelStatus, incoming ChannelStatus blocks need to be stored.
Definition: rx_message.hpp:343
uint8_t sb2_size
double latitude
uint8_t nr_sv
static AttEuler last_atteuler_
Since GPSFix etc. need AttEuler, incoming AttEuler blocks need to be stored.
Definition: rx_message.hpp:333
uint8_t sync_1
first sync byte is $ or 0x24
uint8_t sb1_size
uint16_t reference_id
double longitude
static VelCovGeodetic last_velcovgeodetic_
Since GPSFix needs VelCovGeodetic, incoming VelCovGeodetic blocks need to be stored.
Definition: rx_message.hpp:358
Struct for the SBF sub-block "ChannelStateInfo".
static TypeOfPVTMap type_of_pvt_map
All instances of the RxMessage class shall have access to the map without reinitializing it...
Definition: rx_message.hpp:381
float pitch
uint16_t az_rise_set
BlockHeader_t block_header
uint32_t tow
Struct for the SBF sub-block "ChannelSatInfo".
uint16_t hdop
uint8_t data[((80+1) *sizeof(MeasEpochChannelType1)+(((80+1)) *(((7) *(3)) -1)) *sizeof(MeasEpochChannelType2))]
uint8_t data[(80+1) *sizeof(ChannelSatInfo)+((80+1) *4) *sizeof(ChannelStateInfo)]
static AttCovEuler last_attcoveuler_
Since GPSFix etc. need AttCovEuler, incoming AttCovEuler blocks need to be stored.
Definition: rx_message.hpp:338
float roll
float cov_pitchpitch
uint8_t mode
Here is the caller graph for this function:

◆ isConnectionDescriptor()

bool io_comm_rx::RxMessage::isConnectionDescriptor ( )

Determines whether data_ currently points to a connection descriptor (right after initiating a TCP connection)

Definition at line 991 of file rx_message.cpp.

References CONNECTION_DESCRIPTOR_BYTE_1, CONNECTION_DESCRIPTOR_BYTE_2, count_, and data_.

Referenced by found(), next(), io_comm_rx::CallbackHandlers::readCallback(), RxMessage(), and search().

992 {
993  if (count_ >= 2)
994  {
996  {
997  return true;
998  }
999  else
1000  {
1001  return false;
1002  }
1003  }
1004  else
1005  {
1006  return false;
1007  }
1008 }
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
#define CONNECTION_DESCRIPTOR_BYTE_1
0x49 is ASCII for I - 1st character of connection descriptor sent by the Rx after initiating TCP conn...
Definition: rx_message.hpp:101
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
#define CONNECTION_DESCRIPTOR_BYTE_2
0x50 is ASCII for P - 2nd character of connection descriptor sent by the Rx after initiating TCP conn...
Definition: rx_message.hpp:105
Here is the caller graph for this function:

◆ isErrorMessage()

bool io_comm_rx::RxMessage::isErrorMessage ( )

Determines whether data_ currently points to an error message reply from the Rx.

Definition at line 1010 of file rx_message.cpp.

References count_, data_, RESPONSE_SYNC_BYTE_1, RESPONSE_SYNC_BYTE_2, and RESPONSE_SYNC_BYTE_3.

Referenced by io_comm_rx::CallbackHandlers::readCallback(), and RxMessage().

1011 {
1012  if (count_ >= 3)
1013  {
1015  {
1016  return true;
1017  }
1018  else
1019  {
1020  return false;
1021  }
1022  }
1023  else
1024  {
1025  return false;
1026  }
1027 }
#define RESPONSE_SYNC_BYTE_3
0x3F is ASCII for ? - 3rd byte in the response message from the Rx in case the command was invalid ...
Definition: rx_message.hpp:97
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
#define RESPONSE_SYNC_BYTE_1
0x24 is ASCII for $ - 1st byte in each response from the Rx
Definition: rx_message.hpp:81
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
#define RESPONSE_SYNC_BYTE_2
0x52 is ASCII for R (for "Response") - 2nd byte in each response from the Rx
Definition: rx_message.hpp:85
Here is the caller graph for this function:

◆ isMessage() [1/2]

bool io_comm_rx::RxMessage::isMessage ( const uint16_t  ID)

Determines whether data_ points to the SBF block with ID "ID", e.g. 5003.

Definition at line 886 of file rx_message.cpp.

References data_, and isSBF().

Referenced by RxMessage().

887 {
888  if (this->isSBF())
889  {
890  uint16_t mask = 8191;
891  if (*(reinterpret_cast<const uint16_t *>(data_ + 4)) & mask == static_cast<const uint16_t>(id))
892  // Caution: reinterpret_cast is the most dangerous cast. It's used primarily for particularly
893  // weird conversions and bit manipulations, like turning a raw data stream into actual data.
894  {
895  return true;
896  }
897  else
898  {
899  return false;
900  }
901  }
902  else
903  {
904  return false;
905  }
906 }
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the call graph for this function:
Here is the caller graph for this function:

◆ isMessage() [2/2]

bool io_comm_rx::RxMessage::isMessage ( std::string  ID)

Determines whether data_ points to the NMEA message with ID "ID", e.g. "$GPGGA".

Definition at line 909 of file rx_message.cpp.

References data_, isNMEA(), and messageSize().

910 {
911  if (this->isNMEA())
912  {
913  boost::char_separator<char> sep(",");
914  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
915  std::size_t nmea_size = this->messageSize();
916  std::string block_in_string(reinterpret_cast<const char*>(data_), nmea_size);
917  tokenizer tokens(block_in_string,sep);
918  if (*tokens.begin() == id)
919  {
920  return true;
921  }
922  else
923  {
924  return false;
925  }
926  }
927  else
928  {
929  return false;
930  }
931 }
bool isNMEA()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:952
std::size_t messageSize()
Determines size of the message (also command reply) that data_ is currently pointing at...
Definition: rx_message.cpp:852
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the call graph for this function:

◆ isNMEA()

bool io_comm_rx::RxMessage::isNMEA ( )

Determines whether data_ currently points to an NMEA message.

Definition at line 952 of file rx_message.cpp.

References count_, data_, NMEA_SYNC_BYTE_1, NMEA_SYNC_BYTE_2_1, and NMEA_SYNC_BYTE_2_2.

Referenced by found(), isMessage(), messageID(), next(), io_comm_rx::CallbackHandlers::readCallback(), RxMessage(), and search().

953 {
954  if (count_ >= 2)
955  {
957  && data_[1] == NMEA_SYNC_BYTE_2_2))
958  {
959  return true;
960  }
961  else
962  {
963  return false;
964  }
965  }
966  else
967  {
968  return false;
969  }
970 }
#define NMEA_SYNC_BYTE_1
0x24 is ASCII for $ - 1st byte in each message
Definition: rx_message.hpp:69
#define NMEA_SYNC_BYTE_2_1
0x47 is ASCII for G - 2nd byte to indicate NMEA-type ASCII message
Definition: rx_message.hpp:73
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
#define NMEA_SYNC_BYTE_2_2
0x50 is ASCII for P - 2nd byte to indicate proprietary ASCII message
Definition: rx_message.hpp:77
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the caller graph for this function:

◆ isResponse()

bool io_comm_rx::RxMessage::isResponse ( )

Determines whether data_ currently points to an NMEA message.

Definition at line 972 of file rx_message.cpp.

References count_, data_, RESPONSE_SYNC_BYTE_1, and RESPONSE_SYNC_BYTE_2.

Referenced by found(), messageSize(), next(), io_comm_rx::CallbackHandlers::readCallback(), RxMessage(), and search().

973 {
974  if (count_ >= 2)
975  {
977  {
978  return true;
979  }
980  else
981  {
982  return false;
983  }
984  }
985  else
986  {
987  return false;
988  }
989 }
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
#define RESPONSE_SYNC_BYTE_1
0x24 is ASCII for $ - 1st byte in each response from the Rx
Definition: rx_message.hpp:81
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
#define RESPONSE_SYNC_BYTE_2
0x52 is ASCII for R (for "Response") - 2nd byte in each response from the Rx
Definition: rx_message.hpp:85
Here is the caller graph for this function:

◆ isSBF()

bool io_comm_rx::RxMessage::isSBF ( )

Determines whether data_ currently points to an SBF block.

Definition at line 933 of file rx_message.cpp.

References count_, data_, SBF_SYNC_BYTE_1, and SBF_SYNC_BYTE_2.

Referenced by found(), getBlockLength(), isMessage(), messageID(), next(), read(), io_comm_rx::CallbackHandlers::readCallback(), RxMessage(), and search().

934 {
935  if (count_ >= 2)
936  {
937  if (data_[0] == SBF_SYNC_BYTE_1 && data_[1] == SBF_SYNC_BYTE_2)
938  {
939  return true;
940  }
941  else
942  {
943  return false;
944  }
945  }
946  else
947  {
948  return false;
949  }
950 }
#define SBF_SYNC_BYTE_2
0x40 is ASCII for @ - 2nd byte to indicate SBF block
Definition: rx_message.hpp:65
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
#define SBF_SYNC_BYTE_1
0x24 is ASCII for $ - 1st byte in each message
Definition: rx_message.hpp:61
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the caller graph for this function:

◆ messageID()

std::string io_comm_rx::RxMessage::messageID ( )

Returns the message ID of the message where data_ is pointing at at the moment, SBF identifiers embellished with inverted commas, e.g. "5003"

Definition at line 1029 of file rx_message.cpp.

References data_, isNMEA(), isSBF(), and messageSize().

Referenced by io_comm_rx::CallbackHandler< T >::handle(), io_comm_rx::CallbackHandlers::handle(), read(), io_comm_rx::CallbackHandlers::readCallback(), and RxMessage().

1030 {
1031  if (this->isSBF())
1032  {
1033  // Defines bit mask..
1034  // It is not as stated in the firmware: !first! three bits are for revision (not last 3), and rest for block number
1035  uint16_t mask = 8191;
1036  // Bitwise AND gives us all but first 3 bits set to zero, rest unchanged
1037  uint16_t value = (*(reinterpret_cast<const uint16_t*>(data_+4))) & mask;
1038  std::stringstream ss;
1039  ss << value;
1040  return ss.str();
1041  }
1042  if (this->isNMEA())
1043  {
1044  boost::char_separator<char> sep(",");
1045  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1046  std::size_t nmea_size = this->messageSize();
1047  std::string block_in_string(reinterpret_cast<const char*>(data_), nmea_size);
1048  tokenizer tokens(block_in_string,sep);
1049  return *tokens.begin();
1050  }
1051  return std::string(); // less CPU work than return "";
1052 }
bool isNMEA()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:952
std::size_t messageSize()
Determines size of the message (also command reply) that data_ is currently pointing at...
Definition: rx_message.cpp:852
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the call graph for this function:
Here is the caller graph for this function:

◆ messageSize()

std::size_t io_comm_rx::RxMessage::messageSize ( )

Determines size of the message (also command reply) that data_ is currently pointing at.

Definition at line 852 of file rx_message.cpp.

References CARRIAGE_RETURN, count_, data_, isResponse(), LINE_FEED, and message_size_.

Referenced by isMessage(), messageID(), read(), io_comm_rx::CallbackHandlers::readCallback(), and RxMessage().

853 {
854  uint16_t pos = 0;
855  message_size_ = 0;
856  std::size_t count_copy = count_;
857  if (this->isResponse())
858  {
859  do
860  {
861  ++message_size_;
862  ++pos;
863  --count_copy;
864  if (count_copy == 0) break;
865  } while(!((data_[pos] == CARRIAGE_RETURN && data_[pos+1] == LINE_FEED)) ||
866  (data_[pos] == CARRIAGE_RETURN && data_[pos+1] == LINE_FEED && data_[pos+2] == 0x20
867  && data_[pos+3] == 0x20 && data_[pos+4] == 0x4E) || (data_[pos] == CARRIAGE_RETURN &&
868  data_[pos+1] == LINE_FEED && data_[pos+2] == 0x20 && data_[pos+3] == 0x20 && data_[pos+4] == 0x53) ||
869  (data_[pos] == CARRIAGE_RETURN && data_[pos+1] == LINE_FEED && data_[pos+2] == 0x20 && data_[pos+3] == 0x20
870  && data_[pos+4] == 0x52));
871  }
872  else
873  {
874  do
875  {
876  ++message_size_;
877  ++pos;
878  --count_copy;
879  if (count_copy == 0) break;
880  } while(!((data_[pos] == CARRIAGE_RETURN && data_[pos+1] == LINE_FEED) || data_[pos] == CARRIAGE_RETURN
881  || data_[pos] == LINE_FEED));
882  }
883  return message_size_;
884 }
#define CARRIAGE_RETURN
0x0D is ASCII for "Carriage Return", i.e. "Enter"
Definition: rx_message.hpp:89
bool isResponse()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:972
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
std::size_t message_size_
Helps to determine size of response message / NMEA message / SBF block.
Definition: rx_message.hpp:313
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
#define LINE_FEED
0x0A is ASCII for "Line Feed", i.e. "New Line"
Definition: rx_message.hpp:93
Here is the call graph for this function:
Here is the caller graph for this function:

◆ NavSatFixCallback()

sensor_msgs::NavSatFixPtr io_comm_rx::RxMessage::NavSatFixCallback ( )
private

"Callback" function when constructing NavSatFix messages

Returns
A smart pointer to the ROS message NavSatFix just created

The position_covariance array is populated in row-major order, where the basis of the corresponding matrix is ENU (so Cov_lonlon is in location 11 of the matrix). The B2b signal type of BeiDou is not checked for usage, since the SignalInfo field of the PVTGeodetic block does not disclose it. For that, one would need to go to the ObsInfo field of the MeasEpochChannelType1 sub-block.

Definition at line 430 of file rx_message.cpp.

References PosCovGeodetic::cov_hgthgt, PosCovGeodetic::cov_lathgt, PosCovGeodetic::cov_latlat, PosCovGeodetic::cov_latlon, PosCovGeodetic::cov_lonhgt, PosCovGeodetic::cov_lonlon, evDGPS, evFixed, evMovingBaseRTKFixed, evMovingBaseRTKFloat, evNoPVT, evPPP, evRTKFixed, evRTKFloat, evSBAS, evStandAlone, PVTGeodetic::height, last_poscovgeodetic_, last_pvtgeodetic_, PVTGeodetic::latitude, PVTGeodetic::longitude, PVTGeodetic::mode, PVTGeodetic::signal_info, and type_of_pvt_map.

Referenced by read().

431 {
432  sensor_msgs::NavSatFixPtr msg = boost::make_shared<sensor_msgs::NavSatFix>();
433  uint16_t mask = 15; // We extract the first four bits using this mask.
434  uint16_t type_of_pvt = ((uint16_t) (last_pvtgeodetic_.mode)) & mask;
435  switch(type_of_pvt_map[type_of_pvt])
436  {
437  case evNoPVT:
438  {
439  msg->status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
440  break;
441  }
442  case evStandAlone: case evFixed:
443  {
444  msg->status.status = sensor_msgs::NavSatStatus::STATUS_FIX;
445  break;
446  }
447  case evDGPS: case evRTKFixed: case evRTKFloat: case evMovingBaseRTKFixed: case evMovingBaseRTKFloat: case evPPP:
448  {
449  msg->status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX;
450  break;
451  }
452  case evSBAS:
453  {
454  msg->status.status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX;
455  break;
456  }
457  default:
458  {
459  throw std::runtime_error("PVTGeodetic's Mode field contains an invalid type of PVT solution.");
460  }
461  }
462  bool gps_in_pvt = false;
463  bool glo_in_pvt = false;
464  bool com_in_pvt = false;
465  bool gal_in_pvt = false;
466  uint32_t mask_2 = 1;
467  for(int bit = 0; bit != 31; ++bit)
468  {
469  bool in_use = last_pvtgeodetic_.signal_info & mask_2;
470  if (bit <= 5 && in_use)
471  {
472  gps_in_pvt = true;
473  }
474  if (8 <= bit && bit <= 12 && in_use) glo_in_pvt = true;
475  if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use) com_in_pvt = true;
476  if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use) gal_in_pvt = true;
477  mask_2 *= 2;
478  }
479  // Below, booleans will be promoted to integers automatically.
480  uint16_t service = gps_in_pvt*1+glo_in_pvt*2+com_in_pvt*4+gal_in_pvt*8;
481  msg->status.service = service;
482  msg->latitude = last_pvtgeodetic_.latitude*360/(2*boost::math::constants::pi<double>());
483  msg->longitude = last_pvtgeodetic_.longitude*360/(2*boost::math::constants::pi<double>());
484  msg->altitude = last_pvtgeodetic_.height;
485  msg->position_covariance[0] = static_cast<double>(last_poscovgeodetic_.cov_lonlon);
486  msg->position_covariance[1] = static_cast<double>(last_poscovgeodetic_.cov_latlon);
487  msg->position_covariance[2] = static_cast<double>(last_poscovgeodetic_.cov_lonhgt);
488  msg->position_covariance[3] = static_cast<double>(last_poscovgeodetic_.cov_latlon);
489  msg->position_covariance[4] = static_cast<double>(last_poscovgeodetic_.cov_latlat);
490  msg->position_covariance[5] = static_cast<double>(last_poscovgeodetic_.cov_lathgt);
491  msg->position_covariance[6] = static_cast<double>(last_poscovgeodetic_.cov_lonhgt);
492  msg->position_covariance[7] = static_cast<double>(last_poscovgeodetic_.cov_lathgt);
493  msg->position_covariance[8] = static_cast<double>(last_poscovgeodetic_.cov_hgthgt);
494  msg->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_KNOWN;
495  return msg;
496 }
static PVTGeodetic last_pvtgeodetic_
Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks need to be stored.
Definition: rx_message.hpp:323
static PosCovGeodetic last_poscovgeodetic_
Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic blocks need to be stored...
Definition: rx_message.hpp:328
uint32_t signal_info
double latitude
double longitude
static TypeOfPVTMap type_of_pvt_map
All instances of the RxMessage class shall have access to the map without reinitializing it...
Definition: rx_message.hpp:381
uint8_t mode
Here is the caller graph for this function:

◆ next()

void io_comm_rx::RxMessage::next ( )

Goes to the start of the next message based on the calculated length of current message.

This method won't make data_ jump to the next message if the current one is an NMEA message or a command reply. In that case, search() will check the bytes one by one for the new message's sync bytes ($P, $G or $R).

Definition at line 1086 of file rx_message.cpp.

References count_, crc_check_, data_, found(), found_, g_cd_count, g_read_cd, getBlockLength(), isConnectionDescriptor(), isNMEA(), isResponse(), and isSBF().

Referenced by getCount(), and search().

1087 {
1088  std::size_t jump_size;
1089  if (found())
1090  {
1091  if (this->isNMEA() || this->isResponse() || (g_read_cd && this->isConnectionDescriptor()))
1092  {
1093  if (g_read_cd && this->isConnectionDescriptor() && g_cd_count == 2)
1094  {
1095  g_read_cd = false;
1096  }
1097  jump_size = static_cast<uint32_t>(1);
1098  }
1099  if (this->isSBF())
1100  {
1101  if (crc_check_)
1102  {
1103  jump_size = static_cast<std::size_t>(this->getBlockLength());
1104  // Some corrupted messages that survive the CRC check (this happened) could tell ROSaic their size is 0,
1105  // which would lead to an endless while loop in the ReadCallback() method of the CallbackHandlers class.
1106  if (jump_size == 0) jump_size = static_cast<std::size_t>(1);
1107  }
1108  else
1109  {
1110  jump_size = static_cast<std::size_t>(1);
1111  }
1112  }
1113  }
1114  found_ = false;
1115  data_ += jump_size; count_ -= jump_size;
1116  //ROS_DEBUG("Jump about to happen with jump size %li and count after jump being %li.", jump_size, count_);
1117  return; // For readability
1118 }
bool found()
Has an NMEA message, SBF block or command reply been found in the buffer?
Definition: rx_message.cpp:820
bool isResponse()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:972
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
bool isNMEA()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:952
uint16_t getBlockLength()
Gets the length of the SBF block.
bool g_read_cd
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
bool found_
Whether or not a message has been found.
Definition: rx_message.hpp:291
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
uint32_t g_cd_count
Since after SSSSSSSSSSS we need to wait for second connection descriptor, we have to count the connec...
bool crc_check_
Whether the CRC check as evaluated in the read() method was successful or not is stored here...
Definition: rx_message.hpp:308
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PosCovCartesianCallback()

septentrio_gnss_driver::PosCovCartesianPtr io_comm_rx::RxMessage::PosCovCartesianCallback ( PosCovCartesian data)
private

Callback function when reading PosCovCartesian blocks.

Parameters
[in]dataThe (packed and aligned) struct instance used to populate the ROS message PosCovCartesian
Returns
A smart pointer to the ROS message PosCovCartesian just created

Definition at line 179 of file rx_message.cpp.

References PosCovCartesian::block_header, PosCovCartesian::cov_bb, PosCovCartesian::cov_xb, PosCovCartesian::cov_xx, PosCovCartesian::cov_xy, PosCovCartesian::cov_xz, PosCovCartesian::cov_yb, PosCovCartesian::cov_yy, PosCovCartesian::cov_yz, PosCovCartesian::cov_zb, PosCovCartesian::cov_zz, BlockHeader_t::crc, PosCovCartesian::error, BlockHeader_t::id, BlockHeader_t::length, PosCovCartesian::mode, BlockHeader_t::sync_1, BlockHeader_t::sync_2, PosCovCartesian::tow, and PosCovCartesian::wnc.

Referenced by read().

180 {
181  septentrio_gnss_driver::PosCovCartesianPtr msg = boost::make_shared<septentrio_gnss_driver::PosCovCartesian>();
182  msg->block_header.sync_1 = data.block_header.sync_1;
183  msg->block_header.sync_2 = data.block_header.sync_2;
184  msg->block_header.crc = data.block_header.crc;
185  msg->block_header.id = data.block_header.id;
186  msg->block_header.length = data.block_header.length;
187  msg->block_header.tow = data.tow;
188  msg->block_header.wnc = data.wnc;
189  msg->mode = data.mode;
190  msg->error = data.error;
191  msg->cov_xx = data.cov_xx;
192  msg->cov_yy = data.cov_yy;
193  msg->cov_zz = data.cov_zz;
194  msg->cov_bb = data.cov_bb;
195  msg->cov_xy = data.cov_xy;
196  msg->cov_xz = data.cov_xz;
197  msg->cov_xb = data.cov_xb;
198  msg->cov_yz = data.cov_yz;
199  msg->cov_yb = data.cov_yb;
200  msg->cov_zb = data.cov_zb;
201  return msg;
202 }
uint16_t length
Length of the entire message including the header. A multiple of 4 between 8 and 4096.
uint16_t crc
The check sum.
uint8_t sync_1
first sync byte is $ or 0x24
BlockHeader_t block_header
uint16_t id
This is the block ID.
uint8_t sync_2
2nd sync byte is @ or 0x40
Here is the caller graph for this function:

◆ PosCovGeodeticCallback()

septentrio_gnss_driver::PosCovGeodeticPtr io_comm_rx::RxMessage::PosCovGeodeticCallback ( PosCovGeodetic data)
private

Callback function when reading PosCovGeodetic blocks.

Parameters
[in]dataThe (packed and aligned) struct instance used to populate the ROS message PosCovGeodetic
Returns
A smart pointer to the ROS message PosCovGeodetic just created

Definition at line 205 of file rx_message.cpp.

References PosCovGeodetic::block_header, PosCovGeodetic::cov_bb, PosCovGeodetic::cov_hb, PosCovGeodetic::cov_hgthgt, PosCovGeodetic::cov_latb, PosCovGeodetic::cov_lathgt, PosCovGeodetic::cov_latlat, PosCovGeodetic::cov_latlon, PosCovGeodetic::cov_lonb, PosCovGeodetic::cov_lonhgt, PosCovGeodetic::cov_lonlon, BlockHeader_t::crc, PosCovGeodetic::error, BlockHeader_t::id, BlockHeader_t::length, PosCovGeodetic::mode, BlockHeader_t::sync_1, BlockHeader_t::sync_2, PosCovGeodetic::tow, and PosCovGeodetic::wnc.

Referenced by read().

206 {
207  septentrio_gnss_driver::PosCovGeodeticPtr msg = boost::make_shared<septentrio_gnss_driver::PosCovGeodetic>();
208  msg->block_header.sync_1 = data.block_header.sync_1;
209  msg->block_header.sync_2 = data.block_header.sync_2;
210  msg->block_header.crc = data.block_header.crc;
211  msg->block_header.id = data.block_header.id;
212  msg->block_header.length = data.block_header.length;
213  msg->block_header.tow = data.tow;
214  msg->block_header.wnc = data.wnc;
215  msg->mode = data.mode;
216  msg->error = data.error;
217  msg->cov_latlat = data.cov_latlat;
218  msg->cov_lonlon = data.cov_lonlon;
219  msg->cov_hgthgt = data.cov_hgthgt;
220  msg->cov_bb = data.cov_bb;
221  msg->cov_latlon = data.cov_latlon;
222  msg->cov_lathgt = data.cov_lathgt;
223  msg->cov_latb = data.cov_latb;
224  msg->cov_lonhgt = data.cov_lonhgt;
225  msg->cov_lonb = data.cov_lonb;
226  msg->cov_hb = data.cov_hb;
227  return msg;
228 }
uint16_t length
Length of the entire message including the header. A multiple of 4 between 8 and 4096.
uint16_t crc
The check sum.
uint8_t sync_1
first sync byte is $ or 0x24
BlockHeader_t block_header
uint16_t id
This is the block ID.
uint8_t sync_2
2nd sync byte is @ or 0x40
Here is the caller graph for this function:

◆ PoseWithCovarianceStampedCallback()

geometry_msgs::PoseWithCovarianceStampedPtr io_comm_rx::RxMessage::PoseWithCovarianceStampedCallback ( )
private

"Callback" function when constructing PoseWithCovarianceStamped messages

Returns
A smart pointer to the ROS message PoseWithCovarianceStamped just created

The position_covariance array is populated in row-major order, where the basis of the correspond matrix is (E, N, U, Roll, Pitch, Heading). Important: The Euler angles (Roll, Pitch, Heading) are with respect to a vehicle-fixed (e.g. for mosaic-x5 in moving base mode via the command setAntennaLocation, ...) !local! NED frame. Thus the orientation is !not! given with respect to the same frame as the position is given in. The cross-covariances are hence (apart from the fact that e.g. mosaic receivers do not calculate these quantities) set to zero. The position and the partial (with 2 antennas) or full (for INS receivers) orientation have covariances matrices available e.g. in the PosCovGeodetic or AttCovEuler blocks, yet those are separate computations.

Definition at line 282 of file rx_message.cpp.

References parsing_utilities::convertEulerToQuaternion(), AttCovEuler::cov_headhead, AttCovEuler::cov_headpitch, AttCovEuler::cov_headroll, PosCovGeodetic::cov_hgthgt, PosCovGeodetic::cov_lathgt, PosCovGeodetic::cov_latlat, PosCovGeodetic::cov_latlon, PosCovGeodetic::cov_lonhgt, PosCovGeodetic::cov_lonlon, AttCovEuler::cov_pitchpitch, AttCovEuler::cov_pitchroll, AttCovEuler::cov_rollroll, AttEuler::heading, PVTGeodetic::height, last_attcoveuler_, last_atteuler_, last_poscovgeodetic_, last_pvtgeodetic_, PVTGeodetic::latitude, PVTGeodetic::longitude, AttEuler::pitch, and AttEuler::roll.

Referenced by read().

283 {
284  geometry_msgs::PoseWithCovarianceStampedPtr msg = boost::make_shared<geometry_msgs::PoseWithCovarianceStamped>();
285  // Filling in the pose data
286  msg->pose.pose.orientation = parsing_utilities::convertEulerToQuaternion(static_cast<double>(last_atteuler_.heading),
287  static_cast<double>(last_atteuler_.pitch), static_cast<double>(last_atteuler_.roll));
288  msg->pose.pose.position.x = static_cast<double>(last_pvtgeodetic_.longitude)*360/(2*boost::math::constants::pi<double>());
289  msg->pose.pose.position.y = static_cast<double>(last_pvtgeodetic_.latitude)*360/(2*boost::math::constants::pi<double>());
290  msg->pose.pose.position.z = static_cast<double>(last_pvtgeodetic_.height);
291  // Filling in the covariance data in row-major order
292  msg->pose.covariance[0] = static_cast<double>(last_poscovgeodetic_.cov_lonlon);
293  msg->pose.covariance[1] = static_cast<double>(last_poscovgeodetic_.cov_latlon);
294  msg->pose.covariance[2] = static_cast<double>(last_poscovgeodetic_.cov_lonhgt);
295  msg->pose.covariance[3] = 0;
296  msg->pose.covariance[4] = 0;
297  msg->pose.covariance[5] = 0;
298  msg->pose.covariance[6] = static_cast<double>(last_poscovgeodetic_.cov_latlon);
299  msg->pose.covariance[7] = static_cast<double>(last_poscovgeodetic_.cov_latlat);
300  msg->pose.covariance[8] = static_cast<double>(last_poscovgeodetic_.cov_lathgt);
301  msg->pose.covariance[9] = 0;
302  msg->pose.covariance[10] = 0;
303  msg->pose.covariance[11] = 0;
304  msg->pose.covariance[12] = static_cast<double>(last_poscovgeodetic_.cov_lonhgt);
305  msg->pose.covariance[13] = static_cast<double>(last_poscovgeodetic_.cov_lathgt);
306  msg->pose.covariance[14] = static_cast<double>(last_poscovgeodetic_.cov_hgthgt);
307  msg->pose.covariance[15] = 0;
308  msg->pose.covariance[16] = 0;
309  msg->pose.covariance[17] = 0;
310  msg->pose.covariance[18] = 0;
311  msg->pose.covariance[19] = 0;
312  msg->pose.covariance[20] = 0;
313  msg->pose.covariance[21] = static_cast<double>(last_attcoveuler_.cov_rollroll);
314  msg->pose.covariance[22] = static_cast<double>(last_attcoveuler_.cov_pitchroll);
315  msg->pose.covariance[23] = static_cast<double>(last_attcoveuler_.cov_headroll);
316  msg->pose.covariance[24] = 0;
317  msg->pose.covariance[25] = 0;
318  msg->pose.covariance[26] = 0;
319  msg->pose.covariance[27] = static_cast<double>(last_attcoveuler_.cov_pitchroll);
320  msg->pose.covariance[28] = static_cast<double>(last_attcoveuler_.cov_pitchpitch);
321  msg->pose.covariance[29] = static_cast<double>(last_attcoveuler_.cov_headpitch);
322  msg->pose.covariance[30] = 0;
323  msg->pose.covariance[31] = 0;
324  msg->pose.covariance[32] = 0;
325  msg->pose.covariance[33] = static_cast<double>(last_attcoveuler_.cov_headroll);
326  msg->pose.covariance[34] = static_cast<double>(last_attcoveuler_.cov_pitchroll);
327  msg->pose.covariance[35] = static_cast<double>(last_attcoveuler_.cov_headhead);
328 
329  return msg;
330 }
static PVTGeodetic last_pvtgeodetic_
Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks need to be stored.
Definition: rx_message.hpp:323
float cov_headroll
float cov_rollroll
static PosCovGeodetic last_poscovgeodetic_
Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic blocks need to be stored...
Definition: rx_message.hpp:328
float cov_headpitch
double latitude
static AttEuler last_atteuler_
Since GPSFix etc. need AttEuler, incoming AttEuler blocks need to be stored.
Definition: rx_message.hpp:333
double longitude
float cov_pitchroll
float heading
float pitch
float cov_headhead
static AttCovEuler last_attcoveuler_
Since GPSFix etc. need AttCovEuler, incoming AttCovEuler blocks need to be stored.
Definition: rx_message.hpp:338
float roll
float cov_pitchpitch
geometry_msgs::Quaternion convertEulerToQuaternion(double yaw, double pitch, double roll)
Transforms Euler angles to a quaternion.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PVTCartesianCallback()

septentrio_gnss_driver::PVTCartesianPtr io_comm_rx::RxMessage::PVTCartesianCallback ( PVTCartesian data)
private

Callback function when reading PVTCartesian blocks.

Parameters
[in]dataThe (packed and aligned) struct instance used to populate the ROS message PVTCartesian
Returns
A smart pointer to the ROS message PVTCartesian just created

Definition at line 140 of file rx_message.cpp.

References PVTCartesian::alert_flag, PVTCartesian::block_header, PVTCartesian::cog, BlockHeader_t::crc, PVTCartesian::datum, PVTCartesian::error, PVTCartesian::h_accuracy, BlockHeader_t::id, PVTCartesian::latency, BlockHeader_t::length, PVTCartesian::mean_corr_age, PVTCartesian::misc, PVTCartesian::mode, PVTCartesian::nr_bases, PVTCartesian::nr_sv, PVTCartesian::ppp_info, PVTCartesian::reference_id, PVTCartesian::rx_clk_bias, PVTCartesian::rx_clk_drift, PVTCartesian::signal_info, BlockHeader_t::sync_1, BlockHeader_t::sync_2, PVTCartesian::time_system, PVTCartesian::tow, PVTCartesian::undulation, PVTCartesian::v_accuracy, PVTCartesian::vx, PVTCartesian::vy, PVTCartesian::vz, PVTCartesian::wa_corr_info, PVTCartesian::wnc, PVTCartesian::x, PVTCartesian::y, and PVTCartesian::z.

Referenced by read().

141 {
142  septentrio_gnss_driver::PVTCartesianPtr msg = boost::make_shared<septentrio_gnss_driver::PVTCartesian>();
143  msg->block_header.sync_1 = data.block_header.sync_1;
144  msg->block_header.sync_2 = data.block_header.sync_2;
145  msg->block_header.crc = data.block_header.crc;
146  msg->block_header.id = data.block_header.id;
147  msg->block_header.length = data.block_header.length;
148  msg->block_header.tow = data.tow;
149  msg->block_header.wnc = data.wnc;
150  msg->mode = data.mode;
151  msg->error = data.error;
152  msg->x = data.x;
153  msg->y = data.y;
154  msg->z = data.z;
155  msg->undulation = data.undulation;
156  msg->vx = data.vx;
157  msg->vy = data.vy;
158  msg->vz = data.vz;
159  msg->cog = data.cog;
160  msg->rx_clk_bias = data.rx_clk_bias;
161  msg->rx_clk_drift = data.rx_clk_drift;
162  msg->time_system = data.time_system;
163  msg->datum = data.datum;
164  msg->nr_sv = data.nr_sv;
165  msg->wa_corr_info = data.wa_corr_info;
166  msg->reference_id = data.reference_id;
167  msg->mean_corr_age = data.mean_corr_age;
168  msg->signal_info = data.signal_info;
169  msg->alert_flag = data.alert_flag;
170  msg->nr_bases = data.nr_bases;
171  msg->ppp_info = data.ppp_info;
172  msg->latency = data.latency;
173  msg->h_accuracy = data.h_accuracy;
174  msg->v_accuracy = data.v_accuracy;
175  msg->misc = data.misc;
176  return msg;
177 }
uint8_t time_system
uint16_t reference_id
double rx_clk_bias
BlockHeader_t block_header
uint16_t length
Length of the entire message including the header. A multiple of 4 between 8 and 4096.
uint16_t v_accuracy
uint16_t crc
The check sum.
float rx_clk_drift
uint16_t latency
uint16_t ppp_info
uint32_t signal_info
uint8_t sync_1
first sync byte is $ or 0x24
uint16_t h_accuracy
uint32_t tow
uint8_t alert_flag
uint16_t id
This is the block ID.
uint8_t sync_2
2nd sync byte is @ or 0x40
uint16_t mean_corr_age
uint8_t nr_bases
uint8_t wa_corr_info
uint16_t wnc
Here is the caller graph for this function:

◆ PVTGeodeticCallback()

septentrio_gnss_driver::PVTGeodeticPtr io_comm_rx::RxMessage::PVTGeodeticCallback ( PVTGeodetic data)
private

Callback function when reading PVTGeodetic blocks.

Parameters
[in]dataThe (packed and aligned) struct instance used to populate the ROS message PVTGeodetic
Returns
A smart pointer to the ROS message PVTGeodetic just created

Definition at line 100 of file rx_message.cpp.

References PVTGeodetic::alert_flag, PVTGeodetic::block_header, PVTGeodetic::cog, BlockHeader_t::crc, PVTGeodetic::datum, PVTGeodetic::error, PVTGeodetic::h_accuracy, PVTGeodetic::height, BlockHeader_t::id, PVTGeodetic::latency, PVTGeodetic::latitude, BlockHeader_t::length, PVTGeodetic::longitude, PVTGeodetic::mean_corr_age, PVTGeodetic::misc, PVTGeodetic::mode, PVTGeodetic::nr_bases, PVTGeodetic::nr_sv, PVTGeodetic::ppp_info, PVTGeodetic::reference_id, PVTGeodetic::rx_clk_bias, PVTGeodetic::rx_clk_drift, PVTGeodetic::signal_info, BlockHeader_t::sync_1, BlockHeader_t::sync_2, PVTGeodetic::time_system, PVTGeodetic::tow, PVTGeodetic::undulation, PVTGeodetic::v_accuracy, PVTGeodetic::ve, PVTGeodetic::vn, PVTGeodetic::vu, PVTGeodetic::wa_corr_info, and PVTGeodetic::wnc.

Referenced by read().

101 {
102  septentrio_gnss_driver::PVTGeodeticPtr msg = boost::make_shared<septentrio_gnss_driver::PVTGeodetic>();
103  msg->block_header.sync_1 = data.block_header.sync_1;
104  msg->block_header.sync_2 = data.block_header.sync_2;
105  msg->block_header.crc = data.block_header.crc;
106  msg->block_header.id = data.block_header.id;
107  msg->block_header.length = data.block_header.length;
108  msg->block_header.tow = data.tow;
109  msg->block_header.wnc = data.wnc;
110  msg->mode = data.mode;
111  msg->error = data.error;
112  msg->latitude = data.latitude;
113  msg->longitude = data.longitude;
114  msg->height = data.height;
115  msg->undulation = data.undulation;
116  msg->vn = data.vn;
117  msg->ve = data.ve;
118  msg->vu = data.vu;
119  msg->cog = data.cog;
120  msg->rx_clk_bias = data.rx_clk_bias;
121  msg->rx_clk_drift = data.rx_clk_drift;
122  msg->time_system = data.time_system;
123  msg->datum = data.datum;
124  msg->nr_sv = data.nr_sv;
125  msg->wa_corr_info = data.wa_corr_info;
126  msg->reference_id = data.reference_id;
127  msg->mean_corr_age = data.mean_corr_age;
128  msg->signal_info = data.signal_info;
129  msg->alert_flag = data.alert_flag;
130  msg->nr_bases = data.nr_bases;
131  msg->ppp_info = data.ppp_info;
132  msg->latency = data.latency;
133  msg->h_accuracy = data.h_accuracy;
134  msg->v_accuracy = data.v_accuracy;
135  msg->misc = data.misc;
136  return msg;
137 }
uint8_t wa_corr_info
uint8_t time_system
uint16_t length
Length of the entire message including the header. A multiple of 4 between 8 and 4096.
uint16_t wnc
uint16_t v_accuracy
uint16_t crc
The check sum.
uint32_t signal_info
uint8_t misc
uint8_t nr_bases
uint16_t ppp_info
double latitude
uint8_t nr_sv
uint8_t sync_1
first sync byte is $ or 0x24
float rx_clk_drift
uint16_t reference_id
double longitude
uint16_t mean_corr_age
uint8_t alert_flag
uint8_t error
uint32_t tow
double rx_clk_bias
float undulation
uint16_t id
This is the block ID.
uint16_t h_accuracy
uint8_t datum
BlockHeader_t block_header
uint8_t sync_2
2nd sync byte is @ or 0x40
uint16_t latency
uint8_t mode
Here is the caller graph for this function:

◆ read()

template<typename T >
bool io_comm_rx::RxMessage::read ( typename boost::call_traits< T >::reference  message,
std::string  message_key,
bool  search = false 
)

Performs the CRC check (if SBF) and populates ROS message "message" with the necessary content.

Returns
True if read was successful, false otherwise

Note that the boost::call_traits<T>::reference is more robust than the traditional T&. Note that this function can also deal with the appropriate !derived! parser in case T is an NMEA message. Note that putting the default in the definition's argument list instead of the declaration's is an added extra that is not available for function templates, hence no search = false here. Also note that it is bad practice (one gets undefined reference to .. error) to separate the definition of template functions into the source file and declarations into header file. Also note that the SBF block header part of the SBF-echoing ROS messages have ID fields that only show the block number as found in the firmware (e.g. 4007 for PVTGeodetic), without the revision number. NMEA 0183 messages are at most 82 characters long in principle, but most Septentrio Rxs by default increase precision on lat/lon s.t. the maximum allowed e.g. for GGA seems to be 89 on a mosaic-x5. Luckily, when parsing we do not care since we just search for <LF><CR>.

Definition at line 477 of file rx_message.hpp.

References AttCovEulerCallback(), AttEulerCallback(), count_gpsfix_, crc_check_, data_, DiagnosticArrayCallback(), evAttCovEuler, evAttEuler, evChannelStatus, evDiagnosticArray, evDOP, evGAGSV, evGLGSV, evGPGGA, evGPGSA, evGPGSV, evGPRMC, evGPSFix, evGPST, evMeasEpoch, evNavSatFix, evPosCovCartesian, evPosCovGeodetic, evPoseWithCovarianceStamped, evPVTCartesian, evPVTGeodetic, evQualityInd, evReceiverSetup, evReceiverStatus, evVelCovGeodetic, found(), g_attcoveuler_has_arrived_gpsfix, g_attcoveuler_has_arrived_pose, g_atteuler_has_arrived_gpsfix, g_atteuler_has_arrived_pose, g_channelstatus_has_arrived_gpsfix, g_dop_has_arrived_gpsfix, g_frame_id, g_measepoch_has_arrived_gpsfix, g_nh, g_poscovgeodetic_has_arrived_gpsfix, g_poscovgeodetic_has_arrived_navsatfix, g_poscovgeodetic_has_arrived_pose, g_pvtgeodetic_has_arrived_gpsfix, g_pvtgeodetic_has_arrived_navsatfix, g_pvtgeodetic_has_arrived_pose, g_qualityind_has_arrived_diagnostics, g_receiverstatus_has_arrived_diagnostics, g_ROS_QUEUE_SIZE, g_use_gnss_time, g_velcovgeodetic_has_arrived_gpsfix, GPSFixCallback(), isSBF(), isValid(), last_attcoveuler_, last_atteuler_, last_channelstatus_, last_dop_, last_measepoch_, last_poscovgeodetic_, last_pvtgeodetic_, last_qualityind_, last_receiversetup_, last_receiverstatus_, last_velcovgeodetic_, messageID(), messageSize(), NavSatFixCallback(), GpgsaParser::parseASCII(), GpgsvParser::parseASCII(), GpggaParser::parseASCII(), GprmcParser::parseASCII(), PosCovCartesianCallback(), PosCovGeodeticCallback(), PoseWithCovarianceStampedCallback(), PVTCartesianCallback(), PVTGeodeticCallback(), rx_id_map, search(), io_comm_rx::timestampSBF(), and PVTGeodetic::tow.

Referenced by getCount(), and io_comm_rx::CallbackHandler< T >::handle().

478  {
479  if (search) this->search();
480  if (!found()) return false;
481  if (this->isSBF())
482  {
483  // If the CRC check is unsuccessful, throw an error message.
485  if (!crc_check_)
486  {
487  throw std::runtime_error("CRC Check returned False. Not a valid data block, perhaps noisy. Ignore..");
488  }
489  }
490  switch(rx_id_map[message_key])
491  {
492  case evPVTCartesian: // Position and velocity in XYZ
493  { // The curly bracket here is crucial: Declarations inside a block remain inside, and will die at
494  // the end of the block. Otherwise variable overloading etc.
495  septentrio_gnss_driver::PVTCartesianPtr msg = boost::make_shared<septentrio_gnss_driver::PVTCartesian>();
496  PVTCartesian pvtcartesian;
497  memcpy(&pvtcartesian, data_, sizeof(pvtcartesian));
498  msg = PVTCartesianCallback(pvtcartesian);
499  msg->header.frame_id = g_frame_id;
500  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
501  ros::Time time_obj;
502  time_obj = timestampSBF(tow, g_use_gnss_time);
503  msg->header.stamp.sec = time_obj.sec;
504  msg->header.stamp.nsec = time_obj.nsec;
505  msg->block_header.id = 4006;
506  memcpy(&message, msg.get(), sizeof(*msg));
507  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::PVTCartesian>("/pvtcartesian", g_ROS_QUEUE_SIZE);
508  publisher.publish(*msg);
509  break;
510  }
511  case evPVTGeodetic: // Position and velocity in geodetic coordinate frame (ENU frame)
512  {
513  septentrio_gnss_driver::PVTGeodeticPtr msg = boost::make_shared<septentrio_gnss_driver::PVTGeodetic>();
514  memcpy(&last_pvtgeodetic_, data_, sizeof(last_pvtgeodetic_));
516  msg->header.frame_id = g_frame_id;
517  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
518  ros::Time time_obj;
519  time_obj = timestampSBF(tow, g_use_gnss_time);
520  msg->header.stamp.sec = time_obj.sec;
521  msg->header.stamp.nsec = time_obj.nsec;
522  msg->block_header.id = 4007;
523  memcpy(&message, msg.get(), sizeof(*msg));
527  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::PVTGeodetic>("/pvtgeodetic", g_ROS_QUEUE_SIZE);
528  publisher.publish(*msg);
529  break;
530  }
531  case evPosCovCartesian:
532  {
533  septentrio_gnss_driver::PosCovCartesianPtr msg = boost::make_shared<septentrio_gnss_driver::PosCovCartesian>();
534  PosCovCartesian poscovcartesian;
535  memcpy(&poscovcartesian, data_, sizeof(poscovcartesian));
536  msg = PosCovCartesianCallback(poscovcartesian);
537  msg->header.frame_id = g_frame_id;
538  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
539  ros::Time time_obj;
540  time_obj = timestampSBF(tow, g_use_gnss_time);
541  msg->header.stamp.sec = time_obj.sec;
542  msg->header.stamp.nsec = time_obj.nsec;
543  msg->block_header.id = 5905;
544  memcpy(&message, msg.get(), sizeof(*msg));
545  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::PosCovCartesian>("/poscovcartesian", g_ROS_QUEUE_SIZE);
546  publisher.publish(*msg);
547  break;
548  }
549  case evPosCovGeodetic:
550  {
551  septentrio_gnss_driver::PosCovGeodeticPtr msg = boost::make_shared<septentrio_gnss_driver::PosCovGeodetic>();
554  msg->header.frame_id = g_frame_id;
555  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
556  ros::Time time_obj;
557  time_obj = timestampSBF(tow, g_use_gnss_time);
558  msg->header.stamp.sec = time_obj.sec;
559  msg->header.stamp.nsec = time_obj.nsec;
560  msg->block_header.id = 5906;
561  memcpy(&message, msg.get(), sizeof(*msg));
565  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::PosCovGeodetic>("/poscovgeodetic", g_ROS_QUEUE_SIZE);
566  publisher.publish(*msg);
567  break;
568  }
569  case evAttEuler:
570  {
571  septentrio_gnss_driver::AttEulerPtr msg = boost::make_shared<septentrio_gnss_driver::AttEuler>();
572  memcpy(&last_atteuler_, data_, sizeof(last_atteuler_));
574  msg->header.frame_id = g_frame_id;
575  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
576  ros::Time time_obj;
577  time_obj = timestampSBF(tow, g_use_gnss_time);
578  msg->header.stamp.sec = time_obj.sec;
579  msg->header.stamp.nsec = time_obj.nsec;
580  msg->block_header.id = 5938;
581  memcpy(&message, msg.get(), sizeof(*msg));
584  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::AttEuler>("/atteuler", g_ROS_QUEUE_SIZE);
585  publisher.publish(*msg);
586  break;
587  }
588  case evAttCovEuler:
589  {
590  septentrio_gnss_driver::AttCovEulerPtr msg = boost::make_shared<septentrio_gnss_driver::AttCovEuler>();
591  memcpy(&last_attcoveuler_, data_, sizeof(last_attcoveuler_));
593  msg->header.frame_id = g_frame_id;
594  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
595  ros::Time time_obj;
596  time_obj = timestampSBF(tow, g_use_gnss_time);
597  msg->header.stamp.sec = time_obj.sec;
598  msg->header.stamp.nsec = time_obj.nsec;
599  msg->block_header.id = 5939;
600  memcpy(&message, msg.get(), sizeof(*msg));
603  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::AttCovEuler>("/attcoveuler", g_ROS_QUEUE_SIZE);
604  publisher.publish(*msg);
605  break;
606  }
607  case evGPST:
608  {
609  sensor_msgs::TimeReferencePtr msg = boost::make_shared<sensor_msgs::TimeReference>();
610  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
611  ros::Time time_obj;
612  time_obj = timestampSBF(tow, true); // We need the GPS time, hence true
613  msg->time_ref.sec = time_obj.sec;
614  msg->time_ref.nsec = time_obj.nsec;
615  msg->source = "GPST";
616  memcpy(&message, msg.get(), sizeof(*msg));
617  static ros::Publisher publisher = g_nh->advertise<sensor_msgs::TimeReference>("/gpst", g_ROS_QUEUE_SIZE);
618  publisher.publish(*msg);
619  break;
620  }
621  case evGPGGA:
622  {
623  boost::char_separator<char> sep("\r");
624  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
625  std::size_t nmea_size = this->messageSize();
626  std::string block_in_string(reinterpret_cast<const char*>(data_), nmea_size);
627  tokenizer tokens(block_in_string, sep);
628 
629  std::string id = this->messageID();
630  std::string one_message = *tokens.begin();
631  // No kept delimiters, hence "". Also, we specify that empty tokens should show up in the output
632  // when two delimiters are next to each other.
633  // Hence we also append the checksum part of the GGA message to "body" below, though it is not parsed.
634  boost::char_separator<char> sep_2(",*", "", boost::keep_empty_tokens);
635  tokenizer tokens_2(one_message, sep_2);
636  std::vector<std::string> body;
637  for (tokenizer::iterator tok_iter = tokens_2.begin(); tok_iter != tokens_2.end(); ++tok_iter)
638  {
639  body.push_back(*tok_iter);
640  }
641  // Create NmeaSentence struct to pass to GpggaParser::parseASCII
642  NMEASentence gga_message(id, body);
643  septentrio_gnss_driver::GpggaPtr msg = boost::make_shared<septentrio_gnss_driver::Gpgga>();
644  GpggaParser parser_obj;
645  try
646  {
647  msg = parser_obj.parseASCII(gga_message);
648  }
649  catch (ParseException& e)
650  {
651  throw std::runtime_error(e.what());
652  }
653  memcpy(&message, msg.get(), sizeof(*msg));
654  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::Gpgga>("/gpgga", g_ROS_QUEUE_SIZE);
655  publisher.publish(*msg);
656  break;
657  }
658  case evGPRMC:
659  {
660  boost::char_separator<char> sep("\r");
661  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
662  std::size_t nmea_size = this->messageSize();
663  std::string block_in_string(reinterpret_cast<const char*>(data_), nmea_size);
664  tokenizer tokens(block_in_string, sep);
665 
666  std::string id = this->messageID();
667  std::string one_message = *tokens.begin();
668  boost::char_separator<char> sep_2(",*", "", boost::keep_empty_tokens);
669  tokenizer tokens_2(one_message, sep_2);
670  std::vector<std::string> body;
671  for (tokenizer::iterator tok_iter = tokens_2.begin(); tok_iter != tokens_2.end(); ++tok_iter)
672  {
673  body.push_back(*tok_iter);
674  }
675  // Create NmeaSentence struct to pass to GprmcParser::parseASCII
676  NMEASentence rmc_message(id, body);
677  septentrio_gnss_driver::GprmcPtr msg = boost::make_shared<septentrio_gnss_driver::Gprmc>();
678  GprmcParser parser_obj;
679  try
680  {
681  msg = parser_obj.parseASCII(rmc_message);
682  }
683  catch (ParseException& e)
684  {
685  throw std::runtime_error(e.what());
686  }
687  memcpy(&message, msg.get(), sizeof(*msg));
688  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::Gprmc>("/gprmc", g_ROS_QUEUE_SIZE);
689  publisher.publish(*msg);
690  break;
691  }
692  case evGPGSA:
693  {
694  boost::char_separator<char> sep("\r");
695  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
696  std::size_t nmea_size = this->messageSize();
697  std::string block_in_string(reinterpret_cast<const char*>(data_), nmea_size);
698  tokenizer tokens(block_in_string, sep);
699 
700  std::string id = this->messageID();
701  std::string one_message = *tokens.begin();
702  boost::char_separator<char> sep_2(",*", "", boost::keep_empty_tokens);
703  tokenizer tokens_2(one_message, sep_2);
704  std::vector<std::string> body;
705  for (tokenizer::iterator tok_iter = tokens_2.begin(); tok_iter != tokens_2.end(); ++tok_iter)
706  {
707  body.push_back(*tok_iter);
708  }
709  // Create NmeaSentence struct to pass to GpgsaParser::parseASCII
710  NMEASentence gsa_message(id, body);
711  septentrio_gnss_driver::GpgsaPtr msg = boost::make_shared<septentrio_gnss_driver::Gpgsa>();
712  GpgsaParser parser_obj;
713  try
714  {
715  msg = parser_obj.parseASCII(gsa_message);
716  }
717  catch (ParseException& e)
718  {
719  throw std::runtime_error(e.what());
720  }
721  uint32_t tow = last_pvtgeodetic_.tow;
722  ros::Time time_obj;
723  time_obj = timestampSBF(tow, g_use_gnss_time);
724  msg->header.stamp.sec = time_obj.sec;
725  msg->header.stamp.nsec = time_obj.nsec;
726  memcpy(&message, msg.get(), sizeof(*msg));
727  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::Gpgsa>("/gpgsa", g_ROS_QUEUE_SIZE);
728  publisher.publish(*msg);
729  break;
730  }
731  case evGPGSV: case evGLGSV: case evGAGSV:
732  {
733  boost::char_separator<char> sep("\r");
734  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
735  std::size_t nmea_size = this->messageSize();
736  std::string block_in_string(reinterpret_cast<const char*>(data_), nmea_size);
737  tokenizer tokens(block_in_string, sep);
738 
739  std::string id = this->messageID();
740  std::string one_message = *tokens.begin();
741  boost::char_separator<char> sep_2(",*", "", boost::keep_empty_tokens);
742  tokenizer tokens_2(one_message, sep_2);
743  std::vector<std::string> body;
744  for (tokenizer::iterator tok_iter = tokens_2.begin(); tok_iter != tokens_2.end(); ++tok_iter)
745  {
746  body.push_back(*tok_iter);
747  }
748  // Create NmeaSentence struct to pass to GpgsvParser::parseASCII
749  NMEASentence gsv_message(id, body);
750  septentrio_gnss_driver::GpgsvPtr msg = boost::make_shared<septentrio_gnss_driver::Gpgsv>();
751  GpgsvParser parser_obj;
752  try
753  {
754  msg = parser_obj.parseASCII(gsv_message);
755  }
756  catch (ParseException& e)
757  {
758  throw std::runtime_error(e.what());
759  }
760  uint32_t tow = last_pvtgeodetic_.tow;
761  ros::Time time_obj;
762  time_obj = timestampSBF(tow, g_use_gnss_time);
763  msg->header.stamp.sec = time_obj.sec;
764  msg->header.stamp.nsec = time_obj.nsec;
765  memcpy(&message, msg.get(), sizeof(*msg));
766  static ros::Publisher publisher = g_nh->advertise<septentrio_gnss_driver::Gpgsv>("/gpgsv", g_ROS_QUEUE_SIZE);
767  publisher.publish(*msg);
768  break;
769  }
770  case evNavSatFix:
771  {
772  sensor_msgs::NavSatFixPtr msg = boost::make_shared<sensor_msgs::NavSatFix>();
773  try
774  {
775  msg = NavSatFixCallback();
776  }
777  catch (std::runtime_error& e)
778  {
779  throw std::runtime_error(e.what());
780  }
781  msg->header.frame_id = g_frame_id;
782  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
783  ros::Time time_obj;
784  time_obj = timestampSBF(tow, g_use_gnss_time);
785  msg->header.stamp.sec = time_obj.sec;
786  msg->header.stamp.nsec = time_obj.nsec;
787  memcpy(&message, msg.get(), sizeof(*msg));
790  static ros::Publisher publisher = g_nh->advertise<sensor_msgs::NavSatFix>("/navsatfix", g_ROS_QUEUE_SIZE);
791  publisher.publish(*msg);
792  break;
793  }
794  case evGPSFix:
795  {
796  gps_common::GPSFixPtr msg = boost::make_shared<gps_common::GPSFix>();
797  try
798  {
799  msg = GPSFixCallback();
800  }
801  catch (std::runtime_error& e)
802  {
803  throw std::runtime_error(e.what());
804  }
805  msg->status.header.seq = count_gpsfix_;
806  msg->header.frame_id = g_frame_id;
807  msg->status.header.frame_id = g_frame_id;
808  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
809  ros::Time time_obj;
810  time_obj = timestampSBF(tow, g_use_gnss_time);
811  msg->header.stamp.sec = time_obj.sec;
812  msg->status.header.stamp.sec = time_obj.sec;
813  msg->header.stamp.nsec = time_obj.nsec;
814  msg->status.header.stamp.nsec = time_obj.nsec;
815  memcpy(&message, msg.get(), sizeof(*msg));
816  ++count_gpsfix_;
819  g_dop_has_arrived_gpsfix = false;
820  g_pvtgeodetic_has_arrived_gpsfix = false;
821  g_poscovgeodetic_has_arrived_gpsfix = false;
823  g_atteuler_has_arrived_gpsfix = false;
824  g_attcoveuler_has_arrived_gpsfix = false;
825  static ros::Publisher publisher = g_nh->advertise<gps_common::GPSFix>("/gpsfix", g_ROS_QUEUE_SIZE);
826  publisher.publish(*msg);
827  break;
828  }
830  {
831  geometry_msgs::PoseWithCovarianceStampedPtr msg = boost::make_shared<geometry_msgs::PoseWithCovarianceStamped>();
832  try
833  {
835  }
836  catch (std::runtime_error& e)
837  {
838  throw std::runtime_error(e.what());
839  }
840  msg->header.frame_id = g_frame_id;
841  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
842  ros::Time time_obj;
843  time_obj = timestampSBF(tow, g_use_gnss_time);
844  msg->header.stamp.sec = time_obj.sec;
845  msg->header.stamp.nsec = time_obj.nsec;
846  memcpy(&message, msg.get(), sizeof(*msg));
851  static ros::Publisher publisher = g_nh->advertise<geometry_msgs::PoseWithCovarianceStamped>("/pose", g_ROS_QUEUE_SIZE);
852  publisher.publish(*msg);
853  break;
854  }
855  case evChannelStatus:
856  {
857  memcpy(&last_channelstatus_, data_, sizeof(last_channelstatus_));
859  break;
860  }
861  case evMeasEpoch:
862  {
863  memcpy(&last_measepoch_, data_, sizeof(last_measepoch_));
865  break;
866  }
867  case evDOP:
868  {
869  memcpy(&last_dop_, data_, sizeof(last_dop_));
871  break;
872  }
873  case evVelCovGeodetic:
874  {
877  break;
878  }
879  case evDiagnosticArray:
880  {
881  diagnostic_msgs::DiagnosticArrayPtr msg = boost::make_shared<diagnostic_msgs::DiagnosticArray>();
882  try
883  {
884  msg = DiagnosticArrayCallback();
885  }
886  catch (std::runtime_error& e)
887  {
888  throw std::runtime_error(e.what());
889  }
890  msg->header.frame_id = g_frame_id;
891  uint32_t tow = *(reinterpret_cast<const uint32_t *>(data_ + 8));
892  ros::Time time_obj;
893  time_obj = timestampSBF(tow, g_use_gnss_time);
894  msg->header.stamp.sec = time_obj.sec;
895  msg->header.stamp.nsec = time_obj.nsec;
896  memcpy(&message, msg.get(), sizeof(*msg));
899  static ros::Publisher publisher = g_nh->advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", g_ROS_QUEUE_SIZE);
900  publisher.publish(*msg);
901  break;
902  }
903  case evReceiverStatus:
904  {
906  g_receiverstatus_has_arrived_diagnostics = true;
907  break;
908  }
909  case evQualityInd:
910  {
911  memcpy(&last_qualityind_, data_, sizeof(last_qualityind_));
913  break;
914  }
915  case evReceiverSetup:
916  {
917  memcpy(&last_receiversetup_, data_, sizeof(last_receiversetup_));
918  break;
919  }
920  // Many more to be implemented...
921  }
922  return true;
923  }
bool found()
Has an NMEA message, SBF block or command reply been found in the buffer?
Definition: rx_message.cpp:820
static PVTGeodetic last_pvtgeodetic_
Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks need to be stored.
Definition: rx_message.hpp:323
std::string g_frame_id
The frame ID used in the header of every published ROS message.
sensor_msgs::NavSatFixPtr NavSatFixCallback()
"Callback" function when constructing NavSatFix messages
Definition: rx_message.cpp:430
static PosCovGeodetic last_poscovgeodetic_
Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic blocks need to be stored...
Definition: rx_message.hpp:328
bool g_dop_has_arrived_gpsfix
For GPSFix: Whether the DOP block of the current epoch has arrived or not.
static DOP last_dop_
Since GPSFix needs DOP, incoming DOP blocks need to be stored.
Definition: rx_message.hpp:353
bool g_measepoch_has_arrived_gpsfix
For GPSFix: Whether the MeasEpoch block of the current epoch has arrived or not.
Derived class for parsing GSA messages.
Definition: gpgsa.hpp:82
static MeasEpoch last_measepoch_
Since GPSFix needs MeasEpoch (for SNRs), incoming MeasEpoch blocks need to be stored.
Definition: rx_message.hpp:348
Derived class for parsing GGA messages.
Definition: gpgga.hpp:83
bool g_attcoveuler_has_arrived_pose
For PoseWithCovarianceStamped: Whether the AttCovEuler block of the current epoch has arrived or not...
bool g_poscovgeodetic_has_arrived_gpsfix
For GPSFix: Whether the PosCovGeodetic block of the current epoch has arrived or not.
bool g_pvtgeodetic_has_arrived_navsatfix
For NavSatFix: Whether the PVTGeodetic block of the current epoch has arrived or not.
gps_common::GPSFixPtr GPSFixCallback()
"Callback" function when constructing GPSFix messages
Definition: rx_message.cpp:519
std::string messageID()
septentrio_gnss_driver::AttCovEulerPtr AttCovEulerCallback(AttCovEuler &data)
Callback function when reading AttCovEuler blocks.
Definition: rx_message.cpp:252
bool g_atteuler_has_arrived_gpsfix
For GPSFix: Whether the AttEuler block of the current epoch has arrived or not.
static ChannelStatus last_channelstatus_
Since GPSFix needs ChannelStatus, incoming ChannelStatus blocks need to be stored.
Definition: rx_message.hpp:343
bool g_receiverstatus_has_arrived_diagnostics
For DiagnosticArray: Whether the ReceiverStatus block of the current epoch has arrived or not...
static AttEuler last_atteuler_
Since GPSFix etc. need AttEuler, incoming AttEuler blocks need to be stored.
Definition: rx_message.hpp:333
bool g_attcoveuler_has_arrived_gpsfix
For GPSFix: Whether the AttCovEuler block of the current epoch has arrived or not.
bool g_poscovgeodetic_has_arrived_navsatfix
For NavSatFix: Whether the PosCovGeodetic block of the current epoch has arrived or not...
septentrio_gnss_driver::GpgsaPtr parseASCII(const NMEASentence &sentence) noexcept(false) override
Parses one GSA message.
Definition: gpgsa.cpp:51
static VelCovGeodetic last_velcovgeodetic_
Since GPSFix needs VelCovGeodetic, incoming VelCovGeodetic blocks need to be stored.
Definition: rx_message.hpp:358
septentrio_gnss_driver::PosCovGeodeticPtr PosCovGeodeticCallback(PosCovGeodetic &data)
Callback function when reading PosCovGeodetic blocks.
Definition: rx_message.cpp:205
static ReceiverStatus last_receiverstatus_
Since DiagnosticArray needs ReceiverStatus, incoming ReceiverStatus blocks need to be stored...
Definition: rx_message.hpp:363
Struct for the SBF block "PVTCartesian".
ros::Time timestampSBF(uint32_t tow, bool use_gnss)
Calculates the timestamp, in the Unix Epoch time format This is either done using the TOW as transmit...
Definition: rx_message.cpp:768
Struct for the SBF block "PosCovCartesian".
septentrio_gnss_driver::PVTCartesianPtr PVTCartesianCallback(PVTCartesian &data)
Callback function when reading PVTCartesian blocks.
Definition: rx_message.cpp:140
std::size_t messageSize()
Determines size of the message (also command reply) that data_ is currently pointing at...
Definition: rx_message.cpp:852
boost::shared_ptr< ros::NodeHandle > g_nh
bool g_atteuler_has_arrived_pose
For PoseWithCovarianceStamped: Whether the AttEuler block of the current epoch has arrived or not...
bool g_use_gnss_time
bool g_channelstatus_has_arrived_gpsfix
For GPSFix: Whether the ChannelStatus block of the current epoch has arrived or not.
uint32_t tow
static uint32_t count_gpsfix_
Number of times the gps_common::GPSFix message has been published.
Definition: rx_message.hpp:318
bool g_velcovgeodetic_has_arrived_gpsfix
For GPSFix: Whether the VelCovGeodetic block of the current epoch has arrived or not.
diagnostic_msgs::DiagnosticArrayPtr DiagnosticArrayCallback()
"Callback" function when constructing diagnostic_msgs::DiagnosticArray messages
Definition: rx_message.cpp:332
bool g_pvtgeodetic_has_arrived_pose
For PoseWithCovarianceStamped: Whether the PVTGeodetic block of the current epoch has arrived or not...
bool g_poscovgeodetic_has_arrived_pose
For PoseWithCovarianceStamped: Whether the PosCovGeodetic block of the current epoch has arrived or n...
Derived class for parsing RMC messages.
Definition: gprmc.hpp:83
geometry_msgs::PoseWithCovarianceStampedPtr PoseWithCovarianceStampedCallback()
"Callback" function when constructing PoseWithCovarianceStamped messages
Definition: rx_message.cpp:282
Struct to split an NMEA sentence into its ID and its body, the latter tokenized into a vector of stri...
Class to declare error message format when parsing, derived from the public class "std::runtime_error...
static ReceiverSetup last_receiversetup_
Since DiagnosticArray needs ReceiverSetup, incoming ReceiverSetup blocks need to be stored...
Definition: rx_message.hpp:373
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
const uint32_t g_ROS_QUEUE_SIZE
Queue size for ROS publishers.
septentrio_gnss_driver::PosCovCartesianPtr PosCovCartesianCallback(PosCovCartesian &data)
Callback function when reading PosCovCartesian blocks.
Definition: rx_message.cpp:179
Derived class for parsing GSV messages.
Definition: gpgsv.hpp:82
const uint8_t * search()
Searches the buffer for the beginning of the next message (NMEA or SBF)
Definition: rx_message.cpp:834
bool g_pvtgeodetic_has_arrived_gpsfix
For GPSFix: Whether the PVTGeodetic block of the current epoch has arrived or not.
septentrio_gnss_driver::GprmcPtr parseASCII(const NMEASentence &sentence) noexcept(false) override
Parses one RMC message.
Definition: gprmc.cpp:54
septentrio_gnss_driver::AttEulerPtr AttEulerCallback(AttEuler &data)
Callback function when reading AttEuler blocks.
Definition: rx_message.cpp:230
static QualityInd last_qualityind_
Since DiagnosticArray needs QualityInd, incoming QualityInd blocks need to be stored.
Definition: rx_message.hpp:368
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
static RxIDMap rx_id_map
All instances of the RxMessage class shall have access to the map without reinitializing it...
Definition: rx_message.hpp:392
static AttCovEuler last_attcoveuler_
Since GPSFix etc. need AttCovEuler, incoming AttCovEuler blocks need to be stored.
Definition: rx_message.hpp:338
bool g_qualityind_has_arrived_diagnostics
For DiagnosticArray: Whether the QualityInd block of the current epoch has arrived or not...
bool isValid(const void *block)
Validates whether the calculated CRC of the SBF block at hand matches the CRC field of the streamed S...
Definition: crc.c:68
septentrio_gnss_driver::PVTGeodeticPtr PVTGeodeticCallback(PVTGeodetic &data)
Callback function when reading PVTGeodetic blocks.
Definition: rx_message.cpp:100
bool crc_check_
Whether the CRC check as evaluated in the read() method was successful or not is stored here...
Definition: rx_message.hpp:308
septentrio_gnss_driver::GpggaPtr parseASCII(const NMEASentence &sentence) noexcept(false) override
Parses one GGA message.
Definition: gpgga.cpp:51
septentrio_gnss_driver::GpgsvPtr parseASCII(const NMEASentence &sentence) noexcept(false) override
Parses one GSV message.
Definition: gpgsv.cpp:52
Here is the call graph for this function:
Here is the caller graph for this function:

◆ search()

const uint8_t * io_comm_rx::RxMessage::search ( )

Searches the buffer for the beginning of the next message (NMEA or SBF)

Returns
A pointer to the start of the next message.

Definition at line 834 of file rx_message.cpp.

References count_, data_, found_, g_read_cd, isConnectionDescriptor(), isNMEA(), isResponse(), isSBF(), and next().

Referenced by getCount(), read(), and io_comm_rx::CallbackHandlers::readCallback().

835 {
836  if (found_)
837  {
838  next();
839  }
840  // Search for message or a response header
841  for( ; count_ > 0; --count_, ++data_)
842  {
843  if (this->isSBF() || this->isNMEA() || this->isResponse() || (g_read_cd && this->isConnectionDescriptor()))
844  {
845  break;
846  }
847  }
848  found_ = true;
849  return data_;
850 }
bool isResponse()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:972
void next()
Goes to the start of the next message based on the calculated length of current message.
std::size_t count_
Number of unread bytes in the buffer.
Definition: rx_message.hpp:303
bool isNMEA()
Determines whether data_ currently points to an NMEA message.
Definition: rx_message.cpp:952
bool g_read_cd
bool isSBF()
Determines whether data_ currently points to an SBF block.
Definition: rx_message.cpp:933
bool found_
Whether or not a message has been found.
Definition: rx_message.hpp:291
const uint8_t * data_
Pointer to the buffer of messages.
Definition: rx_message.hpp:298
Here is the call graph for this function:
Here is the caller graph for this function:

Field Documentation

◆ count_

std::size_t io_comm_rx::RxMessage::count_
private

Number of unread bytes in the buffer.

Definition at line 303 of file rx_message.hpp.

Referenced by getCount(), getEndBuffer(), isConnectionDescriptor(), isErrorMessage(), isNMEA(), isResponse(), isSBF(), messageSize(), next(), and search().

◆ count_gpsfix_

uint32_t io_comm_rx::RxMessage::count_gpsfix_ = 0
staticprivate

Number of times the gps_common::GPSFix message has been published.

Definition at line 318 of file rx_message.hpp.

Referenced by read().

◆ crc_check_

bool io_comm_rx::RxMessage::crc_check_
private

Whether the CRC check as evaluated in the read() method was successful or not is stored here.

Definition at line 308 of file rx_message.hpp.

Referenced by next(), read(), and RxMessage().

◆ data_

const uint8_t* io_comm_rx::RxMessage::data_
private

◆ found_

bool io_comm_rx::RxMessage::found_

Whether or not a message has been found.

Definition at line 291 of file rx_message.hpp.

Referenced by found(), next(), RxMessage(), and search().

◆ last_attcoveuler_

AttCovEuler io_comm_rx::RxMessage::last_attcoveuler_ = AttCovEuler()
staticprivate

Since GPSFix etc. need AttCovEuler, incoming AttCovEuler blocks need to be stored.

Definition at line 338 of file rx_message.hpp.

Referenced by GPSFixCallback(), PoseWithCovarianceStampedCallback(), and read().

◆ last_atteuler_

AttEuler io_comm_rx::RxMessage::last_atteuler_ = AttEuler()
staticprivate

Since GPSFix etc. need AttEuler, incoming AttEuler blocks need to be stored.

Definition at line 333 of file rx_message.hpp.

Referenced by GPSFixCallback(), PoseWithCovarianceStampedCallback(), and read().

◆ last_channelstatus_

ChannelStatus io_comm_rx::RxMessage::last_channelstatus_ = ChannelStatus()
staticprivate

Since GPSFix needs ChannelStatus, incoming ChannelStatus blocks need to be stored.

Definition at line 343 of file rx_message.hpp.

Referenced by GPSFixCallback(), and read().

◆ last_dop_

DOP io_comm_rx::RxMessage::last_dop_ = DOP()
staticprivate

Since GPSFix needs DOP, incoming DOP blocks need to be stored.

Definition at line 353 of file rx_message.hpp.

Referenced by GPSFixCallback(), and read().

◆ last_measepoch_

MeasEpoch io_comm_rx::RxMessage::last_measepoch_ = MeasEpoch()
staticprivate

Since GPSFix needs MeasEpoch (for SNRs), incoming MeasEpoch blocks need to be stored.

Definition at line 348 of file rx_message.hpp.

Referenced by GPSFixCallback(), and read().

◆ last_poscovgeodetic_

PosCovGeodetic io_comm_rx::RxMessage::last_poscovgeodetic_ = PosCovGeodetic()
staticprivate

Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic blocks need to be stored.

Definition at line 328 of file rx_message.hpp.

Referenced by GPSFixCallback(), NavSatFixCallback(), PoseWithCovarianceStampedCallback(), and read().

◆ last_pvtgeodetic_

PVTGeodetic io_comm_rx::RxMessage::last_pvtgeodetic_ = PVTGeodetic()
staticprivate

Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks need to be stored.

Definition at line 323 of file rx_message.hpp.

Referenced by GPSFixCallback(), NavSatFixCallback(), PoseWithCovarianceStampedCallback(), and read().

◆ last_qualityind_

QualityInd io_comm_rx::RxMessage::last_qualityind_ = QualityInd()
staticprivate

Since DiagnosticArray needs QualityInd, incoming QualityInd blocks need to be stored.

Definition at line 368 of file rx_message.hpp.

Referenced by DiagnosticArrayCallback(), and read().

◆ last_receiversetup_

ReceiverSetup io_comm_rx::RxMessage::last_receiversetup_ = ReceiverSetup()
staticprivate

Since DiagnosticArray needs ReceiverSetup, incoming ReceiverSetup blocks need to be stored.

Definition at line 373 of file rx_message.hpp.

Referenced by DiagnosticArrayCallback(), and read().

◆ last_receiverstatus_

ReceiverStatus io_comm_rx::RxMessage::last_receiverstatus_ = ReceiverStatus()
staticprivate

Since DiagnosticArray needs ReceiverStatus, incoming ReceiverStatus blocks need to be stored.

Definition at line 363 of file rx_message.hpp.

Referenced by DiagnosticArrayCallback(), and read().

◆ last_velcovgeodetic_

VelCovGeodetic io_comm_rx::RxMessage::last_velcovgeodetic_ = VelCovGeodetic()
staticprivate

Since GPSFix needs VelCovGeodetic, incoming VelCovGeodetic blocks need to be stored.

Definition at line 358 of file rx_message.hpp.

Referenced by GPSFixCallback(), and read().

◆ message_size_

std::size_t io_comm_rx::RxMessage::message_size_
private

Helps to determine size of response message / NMEA message / SBF block.

Definition at line 313 of file rx_message.hpp.

Referenced by messageSize(), and RxMessage().

◆ rx_id_map

io_comm_rx::RxMessage::RxIDMap io_comm_rx::RxMessage::rx_id_map
staticprivate

All instances of the RxMessage class shall have access to the map without reinitializing it, hence static.

This map is for mapping ROS message, SBF and NMEA identifiers to an enumeration and makes the switch-case formalism in rx_message.hpp more explicit.

Definition at line 392 of file rx_message.hpp.

Referenced by read().

◆ type_of_pvt_map

io_comm_rx::RxMessage::TypeOfPVTMap io_comm_rx::RxMessage::type_of_pvt_map
staticprivate

All instances of the RxMessage class shall have access to the map without reinitializing it, hence static.

Definition at line 381 of file rx_message.hpp.

Referenced by GPSFixCallback(), and NavSatFixCallback().


The documentation for this class was generated from the following files: