sbf_blocks.hpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // © Copyright 2020, Septentrio NV/SA.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holder nor the names of its
14 // contributors may be used to endorse or promote products derived
15 // from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 // *****************************************************************************
30 
31 #pragma once
32 
33 #include <cstdint>
34 
36 static const uint8_t NR_OF_LOGICALCHANNELS = 80;
38 static const uint8_t MAX_NB_INMARSATCHANNELS = 1;
40 static const uint8_t MAX_NR_OF_SIGNALS_PER_SATELLITE = 7;
42 static const uint8_t NR_OF_ANTENNAS = 3;
44 static const uint8_t MAXSB_NBRANTENNA = 4;
46 static const uint8_t MAXSB_CHANNELSATINFO =
49 static const uint16_t MAXSB_CHANNELSTATEINFO =
52 static const uint8_t MAXSB_MEASEPOCH_T1 =
55 static const uint16_t MAXSB_MEASEPOCH_T2 =
59 static const uint8_t MAXSB_NBVECTORINFO = 30;
60 
62 static const uint8_t SBF_SYNC_1 = 0x24;
64 static const uint8_t SBF_SYNC_2 = 0x40;
65 
66 // C++
67 #include <algorithm>
68 // Boost
69 #include <boost/spirit/include/qi.hpp>
70 // ROSaic
73 
85 {
86  uint8_t sync_1;
87  uint8_t sync_2;
88  uint16_t crc;
89  uint16_t id;
90  uint8_t revision;
91  uint16_t length;
92  uint32_t tow;
94  uint16_t wnc;
95 };
96 
102 {
103  uint8_t antenna;
104  uint16_t tracking_status;
105  uint16_t pvt_status;
106  uint16_t pvt_info;
107 };
108 
114 {
115  uint8_t sv_id;
116  uint8_t freq_nr;
117  uint16_t az_rise_set;
118  uint16_t health_status;
119  int8_t elev;
120  uint8_t n2;
121  uint8_t rx_channel;
122 
123  std::vector<ChannelStateInfo> stateInfo;
124 };
125 
131 {
133 
134  uint8_t n;
135  uint8_t sb1_length;
136  uint8_t sb2_length;
137 
138  std::vector<ChannelSatInfo> satInfo;
139 };
140 
145 struct Dop
146 {
148 
149  uint8_t nr_sv;
150  double pdop;
151  double tdop;
152  double hdop;
153  double vdop;
154  float hpl;
155  float vpl;
156 };
157 
163 {
165 
166  std::string marker_name;
167  std::string marker_number;
168  std::string observer;
169  std::string agency;
170  std::string rx_serial_number;
171  std::string rx_name;
172  std::string rx_version;
173  std::string ant_serial_nbr;
174  std::string ant_type;
175  float delta_h; /* [m] */
176  float delta_e; /* [m] */
177  float delta_n; /* [m] */
178  std::string marker_type;
179  std::string gnss_fw_version;
180  std::string product_name;
181  double latitude;
182  double longitude;
183  float height;
184  std::string station_code;
185  uint8_t monument_idx;
186  uint8_t receiver_idx;
187  std::string country_code;
188 };
189 
195 {
197 
198  uint8_t n = 0;
199 
200  std::vector<uint16_t> indicators;
201 };
202 
206 struct AgcState
207 {
208  uint8_t frontend_id;
209  int8_t gain;
210  uint8_t sample_var;
211  uint8_t blanking_stat;
212 };
213 
219 {
221 
222  uint8_t cpu_load;
223  uint8_t ext_error;
224  uint32_t up_time;
225  uint32_t rx_status;
226  uint32_t rx_error;
227  uint8_t n;
228  uint8_t sb_length;
229  uint8_t cmd_count;
230  uint8_t temperature;
231 
232  std::vector<AgcState> agc_state;
233 };
234 
240 static const std::array<uint16_t, 256> CRC_LOOK_UP = {
241  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129,
242  0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252,
243  0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
244  0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
245  0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672,
246  0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
247  0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861,
248  0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
249  0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
250  0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5,
251  0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b,
252  0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
253  0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9,
254  0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3,
255  0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
256  0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
257  0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3,
258  0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
259  0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676,
260  0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
261  0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
262  0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16,
263  0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b,
264  0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
265  0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36,
266  0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
267 
268 namespace qi = boost::spirit::qi;
269 
274 template <typename T>
275 [[nodiscard]] bool validValue(T s)
276 {
277  static_assert(std::is_same<uint16_t, T>::value ||
278  std::is_same<uint32_t, T>::value ||
279  std::is_same<float, T>::value || std::is_same<double, T>::value);
280  if (std::is_same<uint16_t, T>::value)
281  {
282  return (s != static_cast<uint16_t>(65535));
283  } else if (std::is_same<uint32_t, T>::value)
284  {
285  return (s != 4294967295u);
286  } else if (std::is_same<float, T>::value)
287  {
288  return (s != -2e10f);
289  } else if (std::is_same<double, T>::value)
290  {
291  return (s != -2e10);
292  }
293 }
294 
299 template <typename Val>
300 void setDoNotUse(Val& s)
301 {
302  static_assert(
303  std::is_same<uint16_t, Val>::value || std::is_same<uint32_t, Val>::value ||
304  std::is_same<uint64_t, Val>::value || std::is_same<float, Val>::value ||
305  std::is_same<double, Val>::value);
306 
307  if (std::is_same<uint16_t, Val>::value)
308  {
309  s = 65535;
310  } else if (std::is_same<uint32_t, Val>::value)
311  {
312  s = 4294967295ul;
313  } else if (std::is_same<float, Val>::value)
314  {
315  s = -2e10f;
316  } else if (std::is_same<double, Val>::value)
317  {
318  s = -2e10;
319  }
320  // TODO add more
321 }
322 
327 template <typename It, typename Val>
328 void qiLittleEndianParser(It& it, Val& val)
329 {
330  static_assert(
331  std::is_same<int8_t, Val>::value || std::is_same<uint8_t, Val>::value ||
332  std::is_same<int16_t, Val>::value || std::is_same<uint16_t, Val>::value ||
333  std::is_same<int32_t, Val>::value || std::is_same<uint32_t, Val>::value ||
334  std::is_same<int64_t, Val>::value || std::is_same<uint64_t, Val>::value ||
335  std::is_same<float, Val>::value || std::is_same<double, Val>::value);
336 
337  if (std::is_same<int8_t, Val>::value)
338  {
339  qi::parse(it, it + 1, qi::char_, val);
340  } else if (std::is_same<uint8_t, Val>::value)
341  {
342  qi::parse(it, it + 1, qi::byte_, val);
343  } else if ((std::is_same<int16_t, Val>::value) ||
344  (std::is_same<uint16_t, Val>::value))
345  {
346  qi::parse(it, it + 2, qi::little_word, val);
347  } else if ((std::is_same<int32_t, Val>::value) ||
348  (std::is_same<uint32_t, Val>::value))
349  {
350  qi::parse(it, it + 4, qi::little_dword, val);
351  } else if ((std::is_same<int64_t, Val>::value) ||
352  (std::is_same<uint64_t, Val>::value))
353  {
354  qi::parse(it, it + 8, qi::little_qword, val);
355  } else if (std::is_same<float, Val>::value)
356  {
357  qi::parse(it, it + 4, qi::little_bin_float, val);
358  } else if (std::is_same<double, Val>::value)
359  {
360  qi::parse(it, it + 8, qi::little_bin_double, val);
361  }
362 }
363 
368 template <typename It>
369 void qiCharsToStringParser(It& it, std::string& val, std::size_t num)
370 {
371  val.clear();
372  qi::parse(it, it + num, qi::repeat(num)[qi::char_], val);
373  // remove string termination characters '\0'
374  val.erase(std::remove(val.begin(), val.end(), '\0'), val.end());
375 }
376 
381 template <typename It, typename Hdr>
382 [[nodiscard]] bool BlockHeaderParser(ROSaicNodeBase* node, It& it, Hdr& block_header)
383 {
384  qiLittleEndianParser(it, block_header.sync_1);
385  if (block_header.sync_1 != SBF_SYNC_1)
386  {
387  node->log(log_level::ERROR, "Parse error: Wrong sync byte 1.");
388  return false;
389  }
390  qiLittleEndianParser(it, block_header.sync_2);
391  if (block_header.sync_2 != SBF_SYNC_2)
392  {
393  node->log(log_level::ERROR, "Parse error: Wrong sync byte 2.");
394  return false;
395  }
396  qiLittleEndianParser(it, block_header.crc);
397  uint16_t ID;
398  qiLittleEndianParser(it, ID);
399  block_header.id = ID & 8191; // lower 13 bits are id
400  block_header.revision = ID >> 13; // upper 3 bits are revision
401  qiLittleEndianParser(it, block_header.length);
402  qiLittleEndianParser(it, block_header.tow);
403  qiLittleEndianParser(it, block_header.wnc);
404  return true;
405 }
406 
411 template <typename It>
412 void ChannelStateInfoParser(It& it, ChannelStateInfo& msg, uint8_t sb2_length)
413 {
414  qiLittleEndianParser(it, msg.antenna);
415  ++it; // reserved
419  std::advance(it, sb2_length - 8); // skip padding
420 };
421 
426 template <typename It>
427 [[nodiscard]] bool ChannelSatInfoParser(ROSaicNodeBase* node, It& it,
428  ChannelSatInfo& msg, uint8_t sb1_length,
429  uint8_t sb2_length)
430 {
431  qiLittleEndianParser(it, msg.sv_id);
432  qiLittleEndianParser(it, msg.freq_nr);
433  std::advance(it, 2); // reserved
436  qiLittleEndianParser(it, msg.elev);
437  qiLittleEndianParser(it, msg.n2);
438  if (msg.n2 > MAXSB_CHANNELSTATEINFO)
439  {
440  node->log(log_level::ERROR, "Parse error: Too many ChannelStateInfo " +
441  std::to_string(msg.n2));
442  return false;
443  }
445  ++it; // reserved
446  std::advance(it, sb1_length - 12); // skip padding
447  msg.stateInfo.resize(msg.n2);
448  for (auto& stateInfo : msg.stateInfo)
449  {
450  ChannelStateInfoParser(it, stateInfo, sb2_length);
451  }
452  return true;
453 };
454 
459 template <typename It>
460 [[nodiscard]] bool ChannelStatusParser(ROSaicNodeBase* node, It it, It itEnd,
461  ChannelStatus& msg)
462 {
463  if (!BlockHeaderParser(node, it, msg.block_header))
464  return false;
465  if (msg.block_header.id != 4013)
466  {
467  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
468  std::to_string(msg.block_header.id));
469  return false;
470  }
471  qiLittleEndianParser(it, msg.n);
472  if (msg.n > MAXSB_CHANNELSATINFO)
473  {
474  node->log(log_level::ERROR,
475  "Parse error: Too many ChannelSatInfo " + std::to_string(msg.n));
476  return false;
477  }
480  std::advance(it, 3); // reserved
481  msg.satInfo.resize(msg.n);
482  for (auto& satInfo : msg.satInfo)
483  {
484  if (!ChannelSatInfoParser(node, it, satInfo, msg.sb1_length, msg.sb2_length))
485  return false;
486  }
487  if (it > itEnd)
488  {
489  node->log(log_level::ERROR, "Parse error: iterator past end.");
490  return false;
491  }
492  return true;
493 };
494 
499 template <typename It>
500 [[nodiscard]] bool DOPParser(ROSaicNodeBase* node, It it, It itEnd, Dop& msg)
501 {
502 
503  if (!BlockHeaderParser(node, it, msg.block_header))
504  return false;
505  if (msg.block_header.id != 4001)
506  {
507  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
508  std::to_string(msg.block_header.id));
509  return false;
510  }
511  qiLittleEndianParser(it, msg.nr_sv);
512  ++it; // reserved
513  uint16_t temp;
514  qiLittleEndianParser(it, temp);
515  msg.pdop = temp / 100.0;
516  qiLittleEndianParser(it, temp);
517  msg.tdop = temp / 100.0;
518  qiLittleEndianParser(it, temp);
519  msg.hdop = temp / 100.0;
520  qiLittleEndianParser(it, temp);
521  msg.vdop = temp / 100.0;
522  qiLittleEndianParser(it, msg.hpl);
523  qiLittleEndianParser(it, msg.vpl);
524  if (it > itEnd)
525  {
526  node->log(log_level::ERROR, "Parse error: iterator past end.");
527  return false;
528  }
529  return true;
530 };
531 
536 template <typename It>
538  uint8_t sb2_length)
539 {
540  qiLittleEndianParser(it, msg.type);
541  qiLittleEndianParser(it, msg.lock_time);
542  qiLittleEndianParser(it, msg.cn0);
543  qiLittleEndianParser(it, msg.offsets_msb);
544  qiLittleEndianParser(it, msg.carrier_msb);
545  qiLittleEndianParser(it, msg.obs_info);
546  qiLittleEndianParser(it, msg.code_offset_lsb);
547  qiLittleEndianParser(it, msg.carrier_lsb);
548  qiLittleEndianParser(it, msg.doppler_offset_lsb);
549  std::advance(it, sb2_length - 12); // skip padding
550 };
551 
556 template <typename It>
557 [[nodiscard]] bool MeasEpochChannelType1Parser(ROSaicNodeBase* node, It& it,
559  uint8_t sb1_length,
560  uint8_t sb2_length)
561 {
562  qiLittleEndianParser(it, msg.rx_channel);
563  qiLittleEndianParser(it, msg.type);
564  qiLittleEndianParser(it, msg.sv_id);
565  qiLittleEndianParser(it, msg.misc);
566  qiLittleEndianParser(it, msg.code_lsb);
567  qiLittleEndianParser(it, msg.doppler);
568  qiLittleEndianParser(it, msg.carrier_lsb);
569  qiLittleEndianParser(it, msg.carrier_msb);
570  qiLittleEndianParser(it, msg.cn0);
571  qiLittleEndianParser(it, msg.lock_time);
572  qiLittleEndianParser(it, msg.obs_info);
573  qiLittleEndianParser(it, msg.n2);
574  std::advance(it, sb1_length - 20); // skip padding
575  if (msg.n2 > MAXSB_MEASEPOCH_T2)
576  {
577  node->log(log_level::ERROR, "Parse error: Too many MeasEpochChannelType2 " +
578  std::to_string(msg.n2));
579  return false;
580  }
581  msg.type2.resize(msg.n2);
582  for (auto& type2 : msg.type2)
583  {
584  MeasEpochChannelType2Parser(it, type2, sb2_length);
585  }
586  return true;
587 };
588 
593 template <typename It>
594 [[nodiscard]] bool MeasEpochParser(ROSaicNodeBase* node, It it, It itEnd,
595  MeasEpochMsg& msg)
596 {
597  if (!BlockHeaderParser(node, it, msg.block_header))
598  return false;
599  if (msg.block_header.id != 4027)
600  {
601  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
602  std::to_string(msg.block_header.id));
603  return false;
604  }
605  qiLittleEndianParser(it, msg.n);
606  if (msg.n > MAXSB_MEASEPOCH_T1)
607  {
608  node->log(log_level::ERROR, "Parse error: Too many MeasEpochChannelType1 " +
609  std::to_string(msg.n));
610  return false;
611  }
612  qiLittleEndianParser(it, msg.sb1_length);
613  qiLittleEndianParser(it, msg.sb2_length);
614  qiLittleEndianParser(it, msg.common_flags);
615  if (msg.block_header.revision > 0)
616  qiLittleEndianParser(it, msg.cum_clk_jumps);
617  ++it; // reserved
618  msg.type1.resize(msg.n);
619  for (auto& type1 : msg.type1)
620  {
621  if (!MeasEpochChannelType1Parser(node, it, type1, msg.sb1_length,
622  msg.sb2_length))
623  return false;
624  }
625  if (it > itEnd)
626  {
627  node->log(log_level::ERROR, "Parse error: iterator past end.");
628  return false;
629  }
630  return true;
631 };
632 
637 template <typename It>
638 [[nodiscard]] bool GalAuthStatusParser(ROSaicNodeBase* node, It it, It itEnd,
639  GalAuthStatusMsg& msg)
640 {
641  if (!BlockHeaderParser(node, it, msg.block_header))
642  return false;
643  if (msg.block_header.id != 4245)
644  {
645  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
646  std::to_string(msg.block_header.id));
647  return false;
648  }
649  qiLittleEndianParser(it, msg.osnma_status);
650  qiLittleEndianParser(it, msg.trusted_time_delta);
651  qiLittleEndianParser(it, msg.gal_active_mask);
652  qiLittleEndianParser(it, msg.gal_authentic_mask);
653  qiLittleEndianParser(it, msg.gps_active_mask);
654  qiLittleEndianParser(it, msg.gps_authentic_mask);
655  if (it > itEnd)
656  {
657  node->log(log_level::ERROR, "Parse error: iterator past end.");
658  return false;
659  }
660  return true;
661 };
662 
667 template <typename It>
668 void RfBandParser(It& it, RfBandMsg& msg, uint8_t sb_length)
669 {
670  qiLittleEndianParser(it, msg.frequency);
671  qiLittleEndianParser(it, msg.bandwidth);
672  qiLittleEndianParser(it, msg.info);
673  std::advance(it, sb_length - 7); // skip padding
674 };
675 
680 template <typename It>
681 [[nodiscard]] bool RfStatusParser(ROSaicNodeBase* node, It it, It itEnd,
682  RfStatusMsg& msg)
683 {
684  if (!BlockHeaderParser(node, it, msg.block_header))
685  return false;
686  if (msg.block_header.id != 4092)
687  {
688  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
689  std::to_string(msg.block_header.id));
690  return false;
691  }
692  qiLittleEndianParser(it, msg.n);
693  qiLittleEndianParser(it, msg.sb_length);
694  qiLittleEndianParser(it, msg.flags);
695  std::advance(it, 3); // reserved
696  msg.rfband.resize(msg.n);
697  for (auto& rfband : msg.rfband)
698  {
699  RfBandParser(it, rfband, msg.sb_length);
700  }
701  if (it > itEnd)
702  {
703  node->log(log_level::ERROR, "Parse error: iterator past end.");
704  return false;
705  }
706  return true;
707 };
708 
713 template <typename It>
714 [[nodiscard]] bool ReceiverSetupParser(ROSaicNodeBase* node, It it, It itEnd,
715  ReceiverSetup& msg)
716 {
717  if (!BlockHeaderParser(node, it, msg.block_header))
718  return false;
719  if (msg.block_header.id != 5902)
720  {
721  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
722  std::to_string(msg.block_header.id));
723  return false;
724  }
725  std::advance(it, 2); // reserved
726  qiCharsToStringParser(it, msg.marker_name, 60);
728  qiCharsToStringParser(it, msg.observer, 20);
729  qiCharsToStringParser(it, msg.agency, 40);
731  qiCharsToStringParser(it, msg.rx_name, 20);
732  qiCharsToStringParser(it, msg.rx_version, 20);
734  qiCharsToStringParser(it, msg.ant_type, 20);
735  qiLittleEndianParser(it, msg.delta_h);
736  qiLittleEndianParser(it, msg.delta_e);
737  qiLittleEndianParser(it, msg.delta_n);
738  if (msg.block_header.revision > 0)
739  qiCharsToStringParser(it, msg.marker_type, 20);
740  if (msg.block_header.revision > 1)
742  if (msg.block_header.revision > 2)
743  qiCharsToStringParser(it, msg.product_name, 40);
744  if (msg.block_header.revision > 3)
745  {
748  qiLittleEndianParser(it, msg.height);
749  qiCharsToStringParser(it, msg.station_code, 10);
753  } else
754  {
755  setDoNotUse(msg.latitude);
756  setDoNotUse(msg.longitude);
757  setDoNotUse(msg.height);
758  }
759  if (it > itEnd)
760  {
761  node->log(log_level::ERROR, "Parse error: iterator past end.");
762  return false;
763  }
764  return true;
765 };
766 
771 template <typename It>
772 [[nodiscard]] bool ReceiverTimesParser(ROSaicNodeBase* node, It it, It itEnd,
773  ReceiverTimeMsg& msg)
774 {
775  if (!BlockHeaderParser(node, it, msg.block_header))
776  return false;
777  if (msg.block_header.id != 5914)
778  {
779  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
780  std::to_string(msg.block_header.id));
781  return false;
782  }
783  qiLittleEndianParser(it, msg.utc_year);
784  qiLittleEndianParser(it, msg.utc_month);
785  qiLittleEndianParser(it, msg.utc_day);
786  qiLittleEndianParser(it, msg.utc_hour);
787  qiLittleEndianParser(it, msg.utc_min);
788  qiLittleEndianParser(it, msg.utc_second);
789  qiLittleEndianParser(it, msg.delta_ls);
790  qiLittleEndianParser(it, msg.sync_level);
791  if (it > itEnd)
792  {
793  node->log(log_level::ERROR, "Parse error: iterator past end.");
794  return false;
795  }
796  return true;
797 };
798 
803 template <typename It>
804 [[nodiscard]] bool PVTCartesianParser(ROSaicNodeBase* node, It it, It itEnd,
805  PVTCartesianMsg& msg)
806 {
807  if (!BlockHeaderParser(node, it, msg.block_header))
808  return false;
809  if (msg.block_header.id != 4006)
810  {
811  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
812  std::to_string(msg.block_header.id));
813  return false;
814  }
815  qiLittleEndianParser(it, msg.mode);
816  qiLittleEndianParser(it, msg.error);
817  qiLittleEndianParser(it, msg.x);
818  qiLittleEndianParser(it, msg.y);
819  qiLittleEndianParser(it, msg.z);
820  qiLittleEndianParser(it, msg.undulation);
821  qiLittleEndianParser(it, msg.vx);
822  qiLittleEndianParser(it, msg.vy);
823  qiLittleEndianParser(it, msg.vz);
824  qiLittleEndianParser(it, msg.cog);
825  qiLittleEndianParser(it, msg.rx_clk_bias);
826  qiLittleEndianParser(it, msg.rx_clk_drift);
827  qiLittleEndianParser(it, msg.time_system);
828  qiLittleEndianParser(it, msg.datum);
829  qiLittleEndianParser(it, msg.nr_sv);
830  qiLittleEndianParser(it, msg.wa_corr_info);
831  qiLittleEndianParser(it, msg.reference_id);
832  qiLittleEndianParser(it, msg.mean_corr_age);
833  qiLittleEndianParser(it, msg.signal_info);
834  qiLittleEndianParser(it, msg.alert_flag);
835  if (msg.block_header.revision > 0)
836  {
837  qiLittleEndianParser(it, msg.nr_bases);
838  qiLittleEndianParser(it, msg.ppp_info);
839  }
840  if (msg.block_header.revision > 1)
841  {
842  qiLittleEndianParser(it, msg.latency);
843  qiLittleEndianParser(it, msg.h_accuracy);
844  qiLittleEndianParser(it, msg.v_accuracy);
845  qiLittleEndianParser(it, msg.misc);
846  }
847  if (it > itEnd)
848  {
849  node->log(log_level::ERROR, "Parse error: iterator past end.");
850  return false;
851  }
852  return true;
853 }
854 
859 template <typename It>
860 [[nodiscard]] bool PVTGeodeticParser(ROSaicNodeBase* node, It it, It itEnd,
861  PVTGeodeticMsg& msg)
862 {
863  if (!BlockHeaderParser(node, it, msg.block_header))
864  return false;
865  if (msg.block_header.id != 4007)
866  {
867  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
868  std::to_string(msg.block_header.id));
869  return false;
870  }
871  qiLittleEndianParser(it, msg.mode);
872  qiLittleEndianParser(it, msg.error);
873  qiLittleEndianParser(it, msg.latitude);
874  qiLittleEndianParser(it, msg.longitude);
875  qiLittleEndianParser(it, msg.height);
876  qiLittleEndianParser(it, msg.undulation);
877  qiLittleEndianParser(it, msg.vn);
878  qiLittleEndianParser(it, msg.ve);
879  qiLittleEndianParser(it, msg.vu);
880  qiLittleEndianParser(it, msg.cog);
881  qiLittleEndianParser(it, msg.rx_clk_bias);
882  qiLittleEndianParser(it, msg.rx_clk_drift);
883  qiLittleEndianParser(it, msg.time_system);
884  qiLittleEndianParser(it, msg.datum);
885  qiLittleEndianParser(it, msg.nr_sv);
886  qiLittleEndianParser(it, msg.wa_corr_info);
887  qiLittleEndianParser(it, msg.reference_id);
888  qiLittleEndianParser(it, msg.mean_corr_age);
889  qiLittleEndianParser(it, msg.signal_info);
890  qiLittleEndianParser(it, msg.alert_flag);
891  if (msg.block_header.revision > 0)
892  {
893  qiLittleEndianParser(it, msg.nr_bases);
894  qiLittleEndianParser(it, msg.ppp_info);
895  }
896  if (msg.block_header.revision > 1)
897  {
898  qiLittleEndianParser(it, msg.latency);
899  qiLittleEndianParser(it, msg.h_accuracy);
900  qiLittleEndianParser(it, msg.v_accuracy);
901  qiLittleEndianParser(it, msg.misc);
902  }
903  if (it > itEnd)
904  {
905  node->log(log_level::ERROR, "Parse error: iterator past end.");
906  return false;
907  }
908  return true;
909 }
910 
915 template <typename It>
916 [[nodiscard]] bool AttEulerParser(ROSaicNodeBase* node, It it, It itEnd,
917  AttEulerMsg& msg, bool use_ros_axis_orientation)
918 {
919  if (!BlockHeaderParser(node, it, msg.block_header))
920  return false;
921  if (msg.block_header.id != 5938)
922  {
923  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
924  std::to_string(msg.block_header.id));
925  return false;
926  }
927  qiLittleEndianParser(it, msg.nr_sv);
928  qiLittleEndianParser(it, msg.error);
929  qiLittleEndianParser(it, msg.mode);
930  std::advance(it, 2); // reserved
931  qiLittleEndianParser(it, msg.heading);
932  qiLittleEndianParser(it, msg.pitch);
933  qiLittleEndianParser(it, msg.roll);
934  qiLittleEndianParser(it, msg.pitch_dot);
935  qiLittleEndianParser(it, msg.roll_dot);
936  qiLittleEndianParser(it, msg.heading_dot);
937  if (use_ros_axis_orientation)
938  {
939  if (validValue(msg.heading))
940  msg.heading = -msg.heading + 90;
941  if (validValue(msg.pitch))
942  msg.pitch = -msg.pitch;
943  if (validValue(msg.pitch_dot))
944  msg.pitch_dot = -msg.pitch_dot;
945  if (validValue(msg.heading_dot))
946  msg.heading_dot = -msg.heading_dot;
947  }
948  if (it > itEnd)
949  {
950  node->log(log_level::ERROR, "Parse error: iterator past end.");
951  return false;
952  }
953  return true;
954 };
955 
960 template <typename It>
961 [[nodiscard]] bool AttCovEulerParser(ROSaicNodeBase* node, It it, It itEnd,
962  AttCovEulerMsg& msg,
963  bool use_ros_axis_orientation)
964 {
965  if (!BlockHeaderParser(node, it, msg.block_header))
966  return false;
967  if (msg.block_header.id != 5939)
968  {
969  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
970  std::to_string(msg.block_header.id));
971  return false;
972  }
973  ++it; // reserved
974  qiLittleEndianParser(it, msg.error);
975  qiLittleEndianParser(it, msg.cov_headhead);
976  qiLittleEndianParser(it, msg.cov_pitchpitch);
977  qiLittleEndianParser(it, msg.cov_rollroll);
978  qiLittleEndianParser(it, msg.cov_headpitch);
979  qiLittleEndianParser(it, msg.cov_headroll);
980  qiLittleEndianParser(it, msg.cov_pitchroll);
981  if (use_ros_axis_orientation)
982  {
983  if (validValue(msg.cov_headroll))
984  msg.cov_headroll = -msg.cov_headroll;
985  if (validValue(msg.cov_pitchroll))
986  msg.cov_pitchroll = -msg.cov_pitchroll;
987  }
988  if (it > itEnd)
989  {
990  node->log(log_level::ERROR, "Parse error: iterator past end.");
991  return false;
992  }
993  return true;
994 };
995 
1000 template <typename It>
1001 void VectorInfoCartParser(It& it, VectorInfoCartMsg& msg, uint8_t sb_length)
1002 {
1003  qiLittleEndianParser(it, msg.nr_sv);
1004  qiLittleEndianParser(it, msg.error);
1005  qiLittleEndianParser(it, msg.mode);
1006  qiLittleEndianParser(it, msg.misc);
1007  qiLittleEndianParser(it, msg.delta_x);
1008  qiLittleEndianParser(it, msg.delta_y);
1009  qiLittleEndianParser(it, msg.delta_z);
1010  qiLittleEndianParser(it, msg.delta_vx);
1011  qiLittleEndianParser(it, msg.delta_vy);
1012  qiLittleEndianParser(it, msg.delta_vz);
1013  qiLittleEndianParser(it, msg.azimuth);
1014  qiLittleEndianParser(it, msg.elevation);
1015  qiLittleEndianParser(it, msg.reference_id);
1016  qiLittleEndianParser(it, msg.corr_age);
1017  qiLittleEndianParser(it, msg.signal_info);
1018  std::advance(it, sb_length - 52); // skip padding
1019 };
1020 
1025 template <typename It>
1026 [[nodiscard]] bool BaseVectorCartParser(ROSaicNodeBase* node, It it, It itEnd,
1027  BaseVectorCartMsg& msg)
1028 {
1029  if (!BlockHeaderParser(node, it, msg.block_header))
1030  return false;
1031  if (msg.block_header.id != 4043)
1032  {
1033  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1034  std::to_string(msg.block_header.id));
1035  return false;
1036  }
1037  qiLittleEndianParser(it, msg.n);
1038  if (msg.n > MAXSB_NBVECTORINFO)
1039  {
1040  node->log(log_level::ERROR,
1041  "Parse error: Too many VectorInfoCart " + std::to_string(msg.n));
1042  return false;
1043  }
1044  qiLittleEndianParser(it, msg.sb_length);
1045  msg.vector_info_cart.resize(msg.n);
1046  for (auto& vector_info_cart : msg.vector_info_cart)
1047  {
1048  VectorInfoCartParser(it, vector_info_cart, msg.sb_length);
1049  }
1050  if (it > itEnd)
1051  {
1052  node->log(log_level::ERROR, "Parse error: iterator past end.");
1053  return false;
1054  }
1055  return true;
1056 };
1057 
1062 template <typename It>
1063 void VectorInfoGeodParser(It& it, VectorInfoGeodMsg& msg, uint8_t sb_length)
1064 {
1065  qiLittleEndianParser(it, msg.nr_sv);
1066  qiLittleEndianParser(it, msg.error);
1067  qiLittleEndianParser(it, msg.mode);
1068  qiLittleEndianParser(it, msg.misc);
1069  qiLittleEndianParser(it, msg.delta_east);
1070  qiLittleEndianParser(it, msg.delta_north);
1071  qiLittleEndianParser(it, msg.delta_up);
1072  qiLittleEndianParser(it, msg.delta_ve);
1073  qiLittleEndianParser(it, msg.delta_vn);
1074  qiLittleEndianParser(it, msg.delta_vu);
1075  qiLittleEndianParser(it, msg.azimuth);
1076  qiLittleEndianParser(it, msg.elevation);
1077  qiLittleEndianParser(it, msg.reference_id);
1078  qiLittleEndianParser(it, msg.corr_age);
1079  qiLittleEndianParser(it, msg.signal_info);
1080  std::advance(it, sb_length - 52); // skip padding
1081 };
1082 
1087 template <typename It>
1088 [[nodiscard]] bool BaseVectorGeodParser(ROSaicNodeBase* node, It it, It itEnd,
1089  BaseVectorGeodMsg& msg)
1090 {
1091  if (!BlockHeaderParser(node, it, msg.block_header))
1092  return false;
1093  if (msg.block_header.id != 4028)
1094  {
1095  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1096  std::to_string(msg.block_header.id));
1097  return false;
1098  }
1099  qiLittleEndianParser(it, msg.n);
1100  if (msg.n > MAXSB_NBVECTORINFO)
1101  {
1102  node->log(log_level::ERROR,
1103  "Parse error: Too many VectorInfoGeod " + std::to_string(msg.n));
1104  return false;
1105  }
1106  qiLittleEndianParser(it, msg.sb_length);
1107  msg.vector_info_geod.resize(msg.n);
1108  for (auto& vector_info_geod : msg.vector_info_geod)
1109  {
1110  VectorInfoGeodParser(it, vector_info_geod, msg.sb_length);
1111  }
1112  if (it > itEnd)
1113  {
1114  node->log(log_level::ERROR, "Parse error: iterator past end.");
1115  return false;
1116  }
1117  return true;
1118 };
1119 
1124 template <typename It>
1125 [[nodiscard]] bool INSNavCartParser(ROSaicNodeBase* node, It it, It itEnd,
1126  INSNavCartMsg& msg,
1127  bool use_ros_axis_orientation)
1128 {
1129  if (!BlockHeaderParser(node, it, msg.block_header))
1130  return false;
1131  if ((msg.block_header.id != 4225) && (msg.block_header.id != 4229))
1132  {
1133  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1134  std::to_string(msg.block_header.id));
1135  return false;
1136  }
1137  qiLittleEndianParser(it, msg.gnss_mode);
1138  qiLittleEndianParser(it, msg.error);
1139  qiLittleEndianParser(it, msg.info);
1140  qiLittleEndianParser(it, msg.gnss_age);
1141  qiLittleEndianParser(it, msg.x);
1142  qiLittleEndianParser(it, msg.y);
1143  qiLittleEndianParser(it, msg.z);
1144  qiLittleEndianParser(it, msg.accuracy);
1145  qiLittleEndianParser(it, msg.latency);
1146  qiLittleEndianParser(it, msg.datum);
1147  ++it; // reserved
1148  qiLittleEndianParser(it, msg.sb_list);
1149  if ((msg.sb_list & 1) != 0)
1150  {
1151  qiLittleEndianParser(it, msg.x_std_dev);
1152  qiLittleEndianParser(it, msg.y_std_dev);
1153  qiLittleEndianParser(it, msg.z_std_dev);
1154  } else
1155  {
1156  setDoNotUse(msg.x_std_dev);
1157  setDoNotUse(msg.y_std_dev);
1158  setDoNotUse(msg.z_std_dev);
1159  }
1160  if ((msg.sb_list & 2) != 0)
1161  {
1162  qiLittleEndianParser(it, msg.heading);
1163  qiLittleEndianParser(it, msg.pitch);
1164  qiLittleEndianParser(it, msg.roll);
1165  if (use_ros_axis_orientation)
1166  {
1167  if (validValue(msg.heading))
1168  msg.heading = -msg.heading + 90;
1169  if (validValue(msg.pitch))
1170  msg.pitch = -msg.pitch;
1171  }
1172  } else
1173  {
1174  setDoNotUse(msg.heading);
1175  setDoNotUse(msg.pitch);
1176  setDoNotUse(msg.roll);
1177  }
1178  if ((msg.sb_list & 4) != 0)
1179  {
1180  qiLittleEndianParser(it, msg.heading_std_dev);
1181  qiLittleEndianParser(it, msg.pitch_std_dev);
1182  qiLittleEndianParser(it, msg.roll_std_dev);
1183  } else
1184  {
1185  setDoNotUse(msg.heading_std_dev);
1186  setDoNotUse(msg.pitch_std_dev);
1187  setDoNotUse(msg.roll_std_dev);
1188  }
1189  if ((msg.sb_list & 8) != 0)
1190  {
1191  qiLittleEndianParser(it, msg.vx);
1192  qiLittleEndianParser(it, msg.vy);
1193  qiLittleEndianParser(it, msg.vz);
1194  } else
1195  {
1196  setDoNotUse(msg.vx);
1197  setDoNotUse(msg.vy);
1198  setDoNotUse(msg.vz);
1199  }
1200  if ((msg.sb_list & 16) != 0)
1201  {
1202  qiLittleEndianParser(it, msg.vx_std_dev);
1203  qiLittleEndianParser(it, msg.vy_std_dev);
1204  qiLittleEndianParser(it, msg.vz_std_dev);
1205  } else
1206  {
1207  setDoNotUse(msg.vx_std_dev);
1208  setDoNotUse(msg.vy_std_dev);
1209  setDoNotUse(msg.vz_std_dev);
1210  }
1211  if ((msg.sb_list & 32) != 0)
1212  {
1213  qiLittleEndianParser(it, msg.xy_cov);
1214  qiLittleEndianParser(it, msg.xz_cov);
1215  qiLittleEndianParser(it, msg.yz_cov);
1216  } else
1217  {
1218  setDoNotUse(msg.xy_cov);
1219  setDoNotUse(msg.xz_cov);
1220  setDoNotUse(msg.yz_cov);
1221  }
1222  if ((msg.sb_list & 64) != 0)
1223  {
1224  qiLittleEndianParser(it, msg.heading_pitch_cov);
1225  qiLittleEndianParser(it, msg.heading_roll_cov);
1226  qiLittleEndianParser(it, msg.pitch_roll_cov);
1227  if (use_ros_axis_orientation)
1228  {
1229  if (validValue(msg.heading_roll_cov))
1230  msg.heading_roll_cov = -msg.heading_roll_cov;
1231  if (validValue(msg.pitch_roll_cov))
1232  msg.pitch_roll_cov = -msg.pitch_roll_cov;
1233  }
1234  } else
1235  {
1236  setDoNotUse(msg.heading_pitch_cov);
1237  setDoNotUse(msg.heading_roll_cov);
1238  setDoNotUse(msg.pitch_roll_cov);
1239  }
1240  if ((msg.sb_list & 128) != 0)
1241  {
1242  qiLittleEndianParser(it, msg.vx_vy_cov);
1243  qiLittleEndianParser(it, msg.vx_vz_cov);
1244  qiLittleEndianParser(it, msg.vy_vz_cov);
1245  } else
1246  {
1247  setDoNotUse(msg.vx_vy_cov);
1248  setDoNotUse(msg.vx_vz_cov);
1249  setDoNotUse(msg.vy_vz_cov);
1250  }
1251  if (it > itEnd)
1252  {
1253  node->log(log_level::ERROR, "Parse error: iterator past end.");
1254  return false;
1255  }
1256  return true;
1257 };
1258 
1263 template <typename It>
1264 [[nodiscard]] bool PosCovCartesianParser(ROSaicNodeBase* node, It it, It itEnd,
1265  PosCovCartesianMsg& msg)
1266 {
1267  if (!BlockHeaderParser(node, it, msg.block_header))
1268  return false;
1269  if (msg.block_header.id != 5905)
1270  {
1271  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1272  std::to_string(msg.block_header.id));
1273  return false;
1274  }
1275  qiLittleEndianParser(it, msg.mode);
1276  qiLittleEndianParser(it, msg.error);
1277  qiLittleEndianParser(it, msg.cov_xx);
1278  qiLittleEndianParser(it, msg.cov_yy);
1279  qiLittleEndianParser(it, msg.cov_zz);
1280  qiLittleEndianParser(it, msg.cov_bb);
1281  qiLittleEndianParser(it, msg.cov_xy);
1282  qiLittleEndianParser(it, msg.cov_xz);
1283  qiLittleEndianParser(it, msg.cov_xb);
1284  qiLittleEndianParser(it, msg.cov_yz);
1285  qiLittleEndianParser(it, msg.cov_yb);
1286  qiLittleEndianParser(it, msg.cov_zb);
1287  if (it > itEnd)
1288  {
1289  node->log(log_level::ERROR, "Parse error: iterator past end.");
1290  return false;
1291  }
1292  return true;
1293 };
1294 
1299 template <typename It>
1300 [[nodiscard]] bool PosCovGeodeticParser(ROSaicNodeBase* node, It it, It itEnd,
1301  PosCovGeodeticMsg& msg)
1302 {
1303  if (!BlockHeaderParser(node, it, msg.block_header))
1304  return false;
1305  if (msg.block_header.id != 5906)
1306  {
1307  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1308  std::to_string(msg.block_header.id));
1309  return false;
1310  }
1311  qiLittleEndianParser(it, msg.mode);
1312  qiLittleEndianParser(it, msg.error);
1313  qiLittleEndianParser(it, msg.cov_latlat);
1314  qiLittleEndianParser(it, msg.cov_lonlon);
1315  qiLittleEndianParser(it, msg.cov_hgthgt);
1316  qiLittleEndianParser(it, msg.cov_bb);
1317  qiLittleEndianParser(it, msg.cov_latlon);
1318  qiLittleEndianParser(it, msg.cov_lathgt);
1319  qiLittleEndianParser(it, msg.cov_latb);
1320  qiLittleEndianParser(it, msg.cov_lonhgt);
1321  qiLittleEndianParser(it, msg.cov_lonb);
1322  qiLittleEndianParser(it, msg.cov_hb);
1323  if (it > itEnd)
1324  {
1325  node->log(log_level::ERROR, "Parse error: iterator past end.");
1326  return false;
1327  }
1328  return true;
1329 };
1330 
1335 template <typename It>
1336 [[nodiscard]] bool VelCovCartesianParser(ROSaicNodeBase* node, It it, It itEnd,
1337  VelCovCartesianMsg& msg)
1338 {
1339  if (!BlockHeaderParser(node, it, msg.block_header))
1340  return false;
1341  if (msg.block_header.id != 5907)
1342  {
1343  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1344  std::to_string(msg.block_header.id));
1345  return false;
1346  }
1347  qiLittleEndianParser(it, msg.mode);
1348  qiLittleEndianParser(it, msg.error);
1349  qiLittleEndianParser(it, msg.cov_vxvx);
1350  qiLittleEndianParser(it, msg.cov_vyvy);
1351  qiLittleEndianParser(it, msg.cov_vzvz);
1352  qiLittleEndianParser(it, msg.cov_dtdt);
1353  qiLittleEndianParser(it, msg.cov_vxvy);
1354  qiLittleEndianParser(it, msg.cov_vxvz);
1355  qiLittleEndianParser(it, msg.cov_vxdt);
1356  qiLittleEndianParser(it, msg.cov_vyvz);
1357  qiLittleEndianParser(it, msg.cov_vydt);
1358  qiLittleEndianParser(it, msg.cov_vzdt);
1359  if (it > itEnd)
1360  {
1361  node->log(log_level::ERROR, "Parse error: iterator past end.");
1362  return false;
1363  }
1364  return true;
1365 };
1366 
1371 template <typename It>
1372 [[nodiscard]] bool VelCovGeodeticParser(ROSaicNodeBase* node, It it, It itEnd,
1373  VelCovGeodeticMsg& msg)
1374 {
1375  if (!BlockHeaderParser(node, it, msg.block_header))
1376  return false;
1377  if (msg.block_header.id != 5908)
1378  {
1379  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1380  std::to_string(msg.block_header.id));
1381  return false;
1382  }
1383  qiLittleEndianParser(it, msg.mode);
1384  qiLittleEndianParser(it, msg.error);
1385  qiLittleEndianParser(it, msg.cov_vnvn);
1386  qiLittleEndianParser(it, msg.cov_veve);
1387  qiLittleEndianParser(it, msg.cov_vuvu);
1388  qiLittleEndianParser(it, msg.cov_dtdt);
1389  qiLittleEndianParser(it, msg.cov_vnve);
1390  qiLittleEndianParser(it, msg.cov_vnvu);
1391  qiLittleEndianParser(it, msg.cov_vndt);
1392  qiLittleEndianParser(it, msg.cov_vevu);
1393  qiLittleEndianParser(it, msg.cov_vedt);
1394  qiLittleEndianParser(it, msg.cov_vudt);
1395  if (it > itEnd)
1396  {
1397  node->log(log_level::ERROR, "Parse error: iterator past end.");
1398  return false;
1399  }
1400  return true;
1401 };
1402 
1407 template <typename It>
1408 [[nodiscard]] bool QualityIndParser(ROSaicNodeBase* node, It it, It itEnd,
1409  QualityInd& msg)
1410 {
1411  if (!BlockHeaderParser(node, it, msg.block_header))
1412  return false;
1413  if (msg.block_header.id != 4082)
1414  {
1415  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1416  std::to_string(msg.block_header.id));
1417  return false;
1418  }
1419  qiLittleEndianParser(it, msg.n);
1420  if (msg.n > 40)
1421  {
1422  node->log(log_level::ERROR,
1423  "Parse error: Too many indicators " + std::to_string(msg.n));
1424  return false;
1425  }
1426  ++it; // reserved
1427  msg.indicators.resize(msg.n);
1428  std::vector<uint16_t> indicators;
1429  for (auto& indicators : msg.indicators)
1430  {
1431  qiLittleEndianParser(it, indicators);
1432  }
1433  if (it > itEnd)
1434  {
1435  node->log(log_level::ERROR, "Parse error: iterator past end.");
1436  return false;
1437  }
1438  return true;
1439 };
1440 
1445 template <typename It>
1446 void AgcStateParser(It it, AgcState& msg, uint8_t sb_length)
1447 {
1449  qiLittleEndianParser(it, msg.gain);
1452  std::advance(it, sb_length - 4); // skip padding
1453 };
1454 
1459 template <typename It>
1460 [[nodiscard]] bool ReceiverStatusParser(ROSaicNodeBase* node, It it, It itEnd,
1461  ReceiverStatus& msg)
1462 {
1463  if (!BlockHeaderParser(node, it, msg.block_header))
1464  return false;
1465  if (msg.block_header.id != 4014)
1466  {
1467  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1468  std::to_string(msg.block_header.id));
1469  return false;
1470  }
1471  qiLittleEndianParser(it, msg.cpu_load);
1473  qiLittleEndianParser(it, msg.up_time);
1475  qiLittleEndianParser(it, msg.rx_error);
1476  qiLittleEndianParser(it, msg.n);
1477  if (msg.n > 18)
1478  {
1479  node->log(log_level::ERROR,
1480  "Parse error: Too many AGCState " + std::to_string(msg.n));
1481  return false;
1482  }
1486  msg.agc_state.resize(msg.n);
1487  for (auto& agc_state : msg.agc_state)
1488  {
1489  AgcStateParser(it, agc_state, msg.sb_length);
1490  }
1491  if (it > itEnd)
1492  {
1493  node->log(log_level::ERROR, "Parse error: iterator past end.");
1494  return false;
1495  }
1496  return true;
1497 };
1498 
1503 template <typename It>
1504 [[nodiscard]] bool ReceiverTimeParser(ROSaicNodeBase* node, It it, It itEnd,
1505  ReceiverTimeMsg& msg)
1506 {
1507  if (!BlockHeaderParser(node, it, msg.block_header))
1508  return false;
1509  if (msg.block_header.id != 5914)
1510  {
1511  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1512  std::to_string(msg.block_header.id));
1513  return false;
1514  }
1515  qiLittleEndianParser(it, msg.utc_year);
1516  qiLittleEndianParser(it, msg.utc_month);
1517  qiLittleEndianParser(it, msg.utc_day);
1518  qiLittleEndianParser(it, msg.utc_hour);
1519  qiLittleEndianParser(it, msg.utc_min);
1520  qiLittleEndianParser(it, msg.utc_second);
1521  qiLittleEndianParser(it, msg.delta_ls);
1522  qiLittleEndianParser(it, msg.sync_level);
1523  if (it > itEnd)
1524  {
1525  node->log(log_level::ERROR, "Parse error: iterator past end.");
1526  return false;
1527  }
1528  return true;
1529 };
1530 
1535 template <typename It>
1536 [[nodiscard]] bool INSNavGeodParser(ROSaicNodeBase* node, It it, It itEnd,
1537  INSNavGeodMsg& msg,
1538  bool use_ros_axis_orientation)
1539 {
1540  if (!BlockHeaderParser(node, it, msg.block_header))
1541  return false;
1542  if ((msg.block_header.id != 4226) && (msg.block_header.id != 4230))
1543  {
1544  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1545  std::to_string(msg.block_header.id));
1546  return false;
1547  }
1548  qiLittleEndianParser(it, msg.gnss_mode);
1549  qiLittleEndianParser(it, msg.error);
1550  qiLittleEndianParser(it, msg.info);
1551  qiLittleEndianParser(it, msg.gnss_age);
1552  qiLittleEndianParser(it, msg.latitude);
1553  qiLittleEndianParser(it, msg.longitude);
1554  qiLittleEndianParser(it, msg.height);
1555  qiLittleEndianParser(it, msg.undulation);
1556  qiLittleEndianParser(it, msg.accuracy);
1557  qiLittleEndianParser(it, msg.latency);
1558  qiLittleEndianParser(it, msg.datum);
1559  ++it; // reserved
1560  qiLittleEndianParser(it, msg.sb_list);
1561  if ((msg.sb_list & 1) != 0)
1562  {
1563  qiLittleEndianParser(it, msg.latitude_std_dev);
1564  qiLittleEndianParser(it, msg.longitude_std_dev);
1565  qiLittleEndianParser(it, msg.height_std_dev);
1566  } else
1567  {
1568  setDoNotUse(msg.latitude_std_dev);
1569  setDoNotUse(msg.longitude_std_dev);
1570  setDoNotUse(msg.height_std_dev);
1571  }
1572  if ((msg.sb_list & 2) != 0)
1573  {
1574  qiLittleEndianParser(it, msg.heading);
1575  qiLittleEndianParser(it, msg.pitch);
1576  qiLittleEndianParser(it, msg.roll);
1577  if (use_ros_axis_orientation)
1578  {
1579  if (validValue(msg.heading))
1580  msg.heading = -msg.heading + 90;
1581  if (validValue(msg.pitch))
1582  msg.pitch = -msg.pitch;
1583  }
1584  } else
1585  {
1586  setDoNotUse(msg.heading);
1587  setDoNotUse(msg.pitch);
1588  setDoNotUse(msg.roll);
1589  }
1590  if ((msg.sb_list & 4) != 0)
1591  {
1592  qiLittleEndianParser(it, msg.heading_std_dev);
1593  qiLittleEndianParser(it, msg.pitch_std_dev);
1594  qiLittleEndianParser(it, msg.roll_std_dev);
1595  } else
1596  {
1597  setDoNotUse(msg.heading_std_dev);
1598  setDoNotUse(msg.pitch_std_dev);
1599  setDoNotUse(msg.roll_std_dev);
1600  }
1601  if ((msg.sb_list & 8) != 0)
1602  {
1603  qiLittleEndianParser(it, msg.ve);
1604  qiLittleEndianParser(it, msg.vn);
1605  qiLittleEndianParser(it, msg.vu);
1606  } else
1607  {
1608  setDoNotUse(msg.ve);
1609  setDoNotUse(msg.vn);
1610  setDoNotUse(msg.vu);
1611  }
1612  if ((msg.sb_list & 16) != 0)
1613  {
1614  qiLittleEndianParser(it, msg.ve_std_dev);
1615  qiLittleEndianParser(it, msg.vn_std_dev);
1616  qiLittleEndianParser(it, msg.vu_std_dev);
1617  } else
1618  {
1619  setDoNotUse(msg.ve_std_dev);
1620  setDoNotUse(msg.vn_std_dev);
1621  setDoNotUse(msg.vu_std_dev);
1622  }
1623  if ((msg.sb_list & 32) != 0)
1624  {
1625  qiLittleEndianParser(it, msg.latitude_longitude_cov);
1626  qiLittleEndianParser(it, msg.latitude_height_cov);
1627  qiLittleEndianParser(it, msg.longitude_height_cov);
1628  } else
1629  {
1630  setDoNotUse(msg.latitude_longitude_cov);
1631  setDoNotUse(msg.latitude_height_cov);
1632  setDoNotUse(msg.longitude_height_cov);
1633  }
1634  if ((msg.sb_list & 64) != 0)
1635  {
1636  qiLittleEndianParser(it, msg.heading_pitch_cov);
1637  qiLittleEndianParser(it, msg.heading_roll_cov);
1638  qiLittleEndianParser(it, msg.pitch_roll_cov);
1639  if (use_ros_axis_orientation)
1640  {
1641  if (validValue(msg.heading_roll_cov))
1642  msg.heading_roll_cov = -msg.heading_roll_cov;
1643  if (validValue(msg.pitch_roll_cov))
1644  msg.pitch_roll_cov = -msg.pitch_roll_cov;
1645  }
1646  } else
1647  {
1648  setDoNotUse(msg.heading_pitch_cov);
1649  setDoNotUse(msg.heading_roll_cov);
1650  setDoNotUse(msg.pitch_roll_cov);
1651  }
1652  if ((msg.sb_list & 128) != 0)
1653  {
1654  qiLittleEndianParser(it, msg.ve_vn_cov);
1655  qiLittleEndianParser(it, msg.ve_vu_cov);
1656  qiLittleEndianParser(it, msg.vn_vu_cov);
1657  } else
1658  {
1659  setDoNotUse(msg.ve_vn_cov);
1660  setDoNotUse(msg.ve_vu_cov);
1661  setDoNotUse(msg.vn_vu_cov);
1662  }
1663  if (it > itEnd)
1664  {
1665  node->log(log_level::ERROR, "Parse error: iterator past end.");
1666  return false;
1667  }
1668  return true;
1669 };
1670 
1675 template <typename It>
1676 [[nodiscard]] bool IMUSetupParser(ROSaicNodeBase* node, It it, It itEnd,
1677  IMUSetupMsg& msg, bool use_ros_axis_orientation)
1678 {
1679  if (!BlockHeaderParser(node, it, msg.block_header))
1680  return false;
1681  if (msg.block_header.id != 4224)
1682  {
1683  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1684  std::to_string(msg.block_header.id));
1685  return false;
1686  }
1687  ++it; // reserved
1688  qiLittleEndianParser(it, msg.serial_port);
1689  qiLittleEndianParser(it, msg.ant_lever_arm_x);
1690  qiLittleEndianParser(it, msg.ant_lever_arm_y);
1691  qiLittleEndianParser(it, msg.ant_lever_arm_z);
1692  qiLittleEndianParser(it, msg.theta_x);
1693  qiLittleEndianParser(it, msg.theta_y);
1694  qiLittleEndianParser(it, msg.theta_z);
1695  if (use_ros_axis_orientation)
1696  {
1697  msg.ant_lever_arm_y = -msg.ant_lever_arm_y;
1698  msg.ant_lever_arm_z = -msg.ant_lever_arm_z;
1699  msg.theta_x = parsing_utilities::wrapAngle180to180(msg.theta_x - 180.0f);
1700  }
1701  if (it > itEnd)
1702  {
1703  node->log(log_level::ERROR, "Parse error: iterator past end.");
1704  return false;
1705  }
1706  return true;
1707 };
1708 
1713 template <typename It>
1714 [[nodiscard]] bool VelSensorSetupParser(ROSaicNodeBase* node, It it, It itEnd,
1715  VelSensorSetupMsg& msg,
1716  bool use_ros_axis_orientation)
1717 {
1718  if (!BlockHeaderParser(node, it, msg.block_header))
1719  return false;
1720  if (msg.block_header.id != 4244)
1721  {
1722  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1723  std::to_string(msg.block_header.id));
1724  return false;
1725  }
1726  ++it; // reserved
1727  qiLittleEndianParser(it, msg.port);
1728  qiLittleEndianParser(it, msg.lever_arm_x);
1729  qiLittleEndianParser(it, msg.lever_arm_y);
1730  qiLittleEndianParser(it, msg.lever_arm_z);
1731  if (use_ros_axis_orientation)
1732  {
1733  msg.lever_arm_y = -msg.lever_arm_y;
1734  msg.lever_arm_z = -msg.lever_arm_z;
1735  }
1736  if (it > itEnd)
1737  {
1738  node->log(log_level::ERROR, "Parse error: iterator past end.");
1739  return false;
1740  }
1741  return true;
1742 };
1743 
1748 template <typename It>
1749 [[nodiscard]] bool
1751  bool use_ros_axis_orientation, bool& hasImuMeas)
1752 {
1753  if (!BlockHeaderParser(node, it, msg.block_header))
1754  return false;
1755  if (msg.block_header.id != 4050)
1756  {
1757  node->log(log_level::ERROR, "Parse error: Wrong header ID " +
1758  std::to_string(msg.block_header.id));
1759  return false;
1760  }
1761  qiLittleEndianParser(it, msg.n);
1762  qiLittleEndianParser(it, msg.sb_length);
1763  if (msg.sb_length != 28)
1764  {
1765  node->log(log_level::ERROR,
1766  "Parse error: Wrong sb_length " + std::to_string(msg.sb_length));
1767  return false;
1768  }
1769 
1770  msg.acceleration_x = std::numeric_limits<double>::quiet_NaN();
1771  msg.acceleration_y = std::numeric_limits<double>::quiet_NaN();
1772  msg.acceleration_z = std::numeric_limits<double>::quiet_NaN();
1773 
1774  msg.angular_rate_x = std::numeric_limits<double>::quiet_NaN();
1775  msg.angular_rate_y = std::numeric_limits<double>::quiet_NaN();
1776  msg.angular_rate_z = std::numeric_limits<double>::quiet_NaN();
1777 
1778  msg.velocity_x = std::numeric_limits<double>::quiet_NaN();
1779  msg.velocity_y = std::numeric_limits<double>::quiet_NaN();
1780  msg.velocity_z = std::numeric_limits<double>::quiet_NaN();
1781 
1782  msg.std_dev_x = std::numeric_limits<double>::quiet_NaN();
1783  msg.std_dev_y = std::numeric_limits<double>::quiet_NaN();
1784  msg.std_dev_z = std::numeric_limits<double>::quiet_NaN();
1785 
1786  msg.sensor_temperature = std::numeric_limits<float>::quiet_NaN();
1787  msg.zero_velocity_flag = std::numeric_limits<double>::quiet_NaN();
1788 
1789  msg.source.resize(msg.n);
1790  msg.sensor_model.resize(msg.n);
1791  msg.type.resize(msg.n);
1792  msg.obs_info.resize(msg.n);
1793  bool hasAcc = false;
1794  bool hasOmega = false;
1795  hasImuMeas = false;
1796  for (size_t i = 0; i < msg.n; i++)
1797  {
1798  qiLittleEndianParser(it, msg.source[i]);
1799  qiLittleEndianParser(it, msg.sensor_model[i]);
1800  qiLittleEndianParser(it, msg.type[i]);
1801  qiLittleEndianParser(it, msg.obs_info[i]);
1802 
1803  switch (msg.type[i])
1804  {
1805  case 0:
1806  {
1807  qiLittleEndianParser(it, msg.acceleration_x);
1808  qiLittleEndianParser(it, msg.acceleration_y);
1809  qiLittleEndianParser(it, msg.acceleration_z);
1810  hasAcc = true;
1811  break;
1812  }
1813  case 1:
1814  {
1815  qiLittleEndianParser(it, msg.angular_rate_x);
1816  qiLittleEndianParser(it, msg.angular_rate_y);
1817  qiLittleEndianParser(it, msg.angular_rate_z);
1818  hasOmega = true;
1819  break;
1820  }
1821  case 3:
1822  {
1823  int16_t temp;
1824  qiLittleEndianParser(it, temp);
1825  if (temp != -32768)
1826  msg.sensor_temperature = temp / 100.0f;
1827  else
1828  msg.sensor_temperature = std::numeric_limits<float>::quiet_NaN();
1829  std::advance(it, 22); // reserved
1830  break;
1831  }
1832  case 4:
1833  {
1834  qiLittleEndianParser(it, msg.velocity_x);
1835  qiLittleEndianParser(it, msg.velocity_y);
1836  qiLittleEndianParser(it, msg.velocity_z);
1837  qiLittleEndianParser(it, msg.std_dev_x);
1838  qiLittleEndianParser(it, msg.std_dev_y);
1839  qiLittleEndianParser(it, msg.std_dev_z);
1840  if (use_ros_axis_orientation)
1841  {
1842  if (validValue(msg.velocity_y))
1843  msg.velocity_y = -msg.velocity_y;
1844  if (validValue(msg.velocity_z))
1845  msg.velocity_z = -msg.velocity_z;
1846  }
1847  break;
1848  }
1849  case 20:
1850  {
1851  qiLittleEndianParser(it, msg.zero_velocity_flag);
1852  std::advance(it, 16); // reserved
1853  break;
1854  }
1855  default:
1856  {
1857  node->log(
1859  "Unknown external sensor measurement type in SBF ExtSensorMeas: " +
1860  std::to_string(msg.type[i]));
1861  std::advance(it, 24);
1862  break;
1863  }
1864  }
1865  }
1866  if (it > itEnd)
1867  {
1868  node->log(log_level::ERROR, "Parse error: iterator past end.");
1869  return false;
1870  }
1871  hasImuMeas = hasAcc && hasOmega;
1872  return true;
1873 };
BlockHeader::length
uint16_t length
Definition: sbf_blocks.hpp:91
log_level::DEBUG
@ DEBUG
Definition: typedefs.hpp:172
VectorInfoGeodMsg
septentrio_gnss_driver::VectorInfoGeod VectorInfoGeodMsg
Definition: typedefs.hpp:130
ReceiverSetup::delta_h
float delta_h
Definition: sbf_blocks.hpp:175
BlockHeader::wnc
uint16_t wnc
This is the GPS week counter.
Definition: sbf_blocks.hpp:94
ExtSensorMeasParser
bool ExtSensorMeasParser(ROSaicNodeBase *node, It it, It itEnd, ExtSensorMeasMsg &msg, bool use_ros_axis_orientation, bool &hasImuMeas)
Qi based parser for the SBF block "ExtSensorMeas".
Definition: sbf_blocks.hpp:1750
QualityInd
Struct for the SBF block "QualityInd".
Definition: sbf_blocks.hpp:194
ChannelStatus::sb1_length
uint8_t sb1_length
Definition: sbf_blocks.hpp:135
ChannelStateInfoParser
void ChannelStateInfoParser(It &it, ChannelStateInfo &msg, uint8_t sb2_length)
Qi based parser for the SBF sub-block "ChannelStateInfo".
Definition: sbf_blocks.hpp:412
QualityIndParser
bool QualityIndParser(ROSaicNodeBase *node, It it, It itEnd, QualityInd &msg)
Qi based parser for the SBF block "QualityInd".
Definition: sbf_blocks.hpp:1408
ReceiverSetup::agency
std::string agency
Definition: sbf_blocks.hpp:169
PosCovGeodeticParser
bool PosCovGeodeticParser(ROSaicNodeBase *node, It it, It itEnd, PosCovGeodeticMsg &msg)
Qi based parser for the SBF block "PosCovGeodetic".
Definition: sbf_blocks.hpp:1300
ChannelStatus::satInfo
std::vector< ChannelSatInfo > satInfo
Definition: sbf_blocks.hpp:138
ChannelStateInfo::pvt_info
uint16_t pvt_info
Definition: sbf_blocks.hpp:106
MeasEpochChannelType1Parser
bool MeasEpochChannelType1Parser(ROSaicNodeBase *node, It &it, MeasEpochChannelType1Msg &msg, uint8_t sb1_length, uint8_t sb2_length)
Qi based parser for the SBF sub-block "MeasEpochChannelType1".
Definition: sbf_blocks.hpp:557
ReceiverSetup::delta_e
float delta_e
Definition: sbf_blocks.hpp:176
NR_OF_ANTENNAS
static const uint8_t NR_OF_ANTENNAS
Using maximum value of NR_OF_ANTENNAS for SBF definitions.
Definition: sbf_blocks.hpp:42
ChannelStateInfo
Struct for the SBF sub-block "ChannelStateInfo".
Definition: sbf_blocks.hpp:101
ChannelSatInfo::rx_channel
uint8_t rx_channel
Definition: sbf_blocks.hpp:121
ReceiverSetup::rx_serial_number
std::string rx_serial_number
Definition: sbf_blocks.hpp:170
SBF_SYNC_2
static const uint8_t SBF_SYNC_2
0x40 is ASCII for @ - 2nd byte to indicate SBF block
Definition: sbf_blocks.hpp:64
AgcState::frontend_id
uint8_t frontend_id
Definition: sbf_blocks.hpp:208
ROSaicNodeBase::log
void log(log_level::LogLevel logLevel, const std::string &s) const
Log function to provide abstraction of ROS loggers.
Definition: typedefs.hpp:257
s
XmlRpcServer s
MAXSB_MEASEPOCH_T2
static const uint16_t MAXSB_MEASEPOCH_T2
Max number of bytes that MeasEpochChannelType2 sub-block can consist of.
Definition: sbf_blocks.hpp:55
BlockHeader::sync_2
uint8_t sync_2
2nd sync byte is @ or 0x40
Definition: sbf_blocks.hpp:87
parsing_utilities::wrapAngle180to180
double wrapAngle180to180(double angle)
Wraps an angle between -180 and 180 degrees.
Definition: parsing_utilities.cpp:51
ChannelStatusParser
bool ChannelStatusParser(ROSaicNodeBase *node, It it, It itEnd, ChannelStatus &msg)
Qi based parser for the SBF block "ChannelStatus".
Definition: sbf_blocks.hpp:460
ReceiverSetup::ant_type
std::string ant_type
Definition: sbf_blocks.hpp:174
ReceiverSetup::monument_idx
uint8_t monument_idx
Definition: sbf_blocks.hpp:185
BlockHeader::tow
uint32_t tow
This is the time of week in ms.
Definition: sbf_blocks.hpp:93
AgcStateParser
void AgcStateParser(It it, AgcState &msg, uint8_t sb_length)
Struct for the SBF sub-block "AGCState".
Definition: sbf_blocks.hpp:1446
RfStatusParser
bool RfStatusParser(ROSaicNodeBase *node, It it, It itEnd, RfStatusMsg &msg)
Qi based parser for the SBF block "RFStatus".
Definition: sbf_blocks.hpp:681
VectorInfoGeodParser
void VectorInfoGeodParser(It &it, VectorInfoGeodMsg &msg, uint8_t sb_length)
Qi based parser for the SBF sub-block "VectorInfoGeod".
Definition: sbf_blocks.hpp:1063
MAXSB_NBVECTORINFO
static const uint8_t MAXSB_NBVECTORINFO
Max number of vector info sub-blocks.
Definition: sbf_blocks.hpp:59
ChannelSatInfo::n2
uint8_t n2
Definition: sbf_blocks.hpp:120
ReceiverTimeParser
bool ReceiverTimeParser(ROSaicNodeBase *node, It it, It itEnd, ReceiverTimeMsg &msg)
Struct for the SBF block "ReceiverTime".
Definition: sbf_blocks.hpp:1504
VelCovGeodeticMsg
septentrio_gnss_driver::VelCovGeodetic VelCovGeodeticMsg
Definition: typedefs.hpp:132
ReceiverTimeMsg
septentrio_gnss_driver::ReceiverTime ReceiverTimeMsg
Definition: typedefs.hpp:128
ReceiverSetup::block_header
BlockHeader block_header
Definition: sbf_blocks.hpp:164
CRC_LOOK_UP
static const std::array< uint16_t, 256 > CRC_LOOK_UP
CRC look-up table for fast computation of the 16-bit CRC for SBF blocks.
Definition: sbf_blocks.hpp:240
MeasEpochParser
bool MeasEpochParser(ROSaicNodeBase *node, It it, It itEnd, MeasEpochMsg &msg)
Qi based parser for the SBF block "MeasEpoch".
Definition: sbf_blocks.hpp:594
RfBandParser
void RfBandParser(It &it, RfBandMsg &msg, uint8_t sb_length)
Qi based parser for the SBF sub-block "RFBand".
Definition: sbf_blocks.hpp:668
QualityInd::indicators
std::vector< uint16_t > indicators
Definition: sbf_blocks.hpp:200
ChannelStatus::sb2_length
uint8_t sb2_length
Definition: sbf_blocks.hpp:136
validValue
bool validValue(T s)
Check if value is not set to Do-Not-Use.
Definition: sbf_blocks.hpp:275
Dop::nr_sv
uint8_t nr_sv
Definition: sbf_blocks.hpp:149
SBF_SYNC_1
static const uint8_t SBF_SYNC_1
0x24 is ASCII for $ - 1st byte in each message
Definition: sbf_blocks.hpp:62
ChannelSatInfo::az_rise_set
uint16_t az_rise_set
Definition: sbf_blocks.hpp:117
AgcState
Struct for the SBF sub-block "AGCState".
Definition: sbf_blocks.hpp:206
INSNavCartMsg
septentrio_gnss_driver::INSNavCart INSNavCartMsg
Definition: typedefs.hpp:141
ReceiverStatus::block_header
BlockHeader block_header
Definition: sbf_blocks.hpp:220
ROSaicNodeBase
This class is the base class for abstraction.
Definition: typedefs.hpp:184
ReceiverSetup::ant_serial_nbr
std::string ant_serial_nbr
Definition: sbf_blocks.hpp:173
MAX_NB_INMARSATCHANNELS
static const uint8_t MAX_NB_INMARSATCHANNELS
Inmarsat is a British satellite telecommunications company.
Definition: sbf_blocks.hpp:38
Dop::pdop
double pdop
Definition: sbf_blocks.hpp:150
VelCovCartesianParser
bool VelCovCartesianParser(ROSaicNodeBase *node, It it, It itEnd, VelCovCartesianMsg &msg)
Qi based parser for the SBF block "VelCovCartesian".
Definition: sbf_blocks.hpp:1336
ReceiverStatus::up_time
uint32_t up_time
Definition: sbf_blocks.hpp:224
PVTGeodeticMsg
septentrio_gnss_driver::PVTGeodetic PVTGeodeticMsg
Definition: typedefs.hpp:125
GalAuthStatusParser
bool GalAuthStatusParser(ROSaicNodeBase *node, It it, It itEnd, GalAuthStatusMsg &msg)
Qi based parser for the SBF block "GALAuthStatus".
Definition: sbf_blocks.hpp:638
PosCovGeodeticMsg
septentrio_gnss_driver::PosCovGeodetic PosCovGeodeticMsg
Definition: typedefs.hpp:127
GalAuthStatusMsg
septentrio_gnss_driver::GALAuthStatus GalAuthStatusMsg
Definition: typedefs.hpp:116
Dop::tdop
double tdop
Definition: sbf_blocks.hpp:151
INSNavCartParser
bool INSNavCartParser(ROSaicNodeBase *node, It it, It itEnd, INSNavCartMsg &msg, bool use_ros_axis_orientation)
Qi based parser for the SBF block "INSNavCart".
Definition: sbf_blocks.hpp:1125
ReceiverSetup::longitude
double longitude
Definition: sbf_blocks.hpp:182
BlockHeaderParser
bool BlockHeaderParser(ROSaicNodeBase *node, It &it, Hdr &block_header)
Qi based parser for the SBF block "BlockHeader" plus receiver time stamp.
Definition: sbf_blocks.hpp:382
MeasEpochChannelType1Msg
septentrio_gnss_driver::MeasEpochChannelType1 MeasEpochChannelType1Msg
Definition: typedefs.hpp:120
ReceiverSetup::rx_version
std::string rx_version
Definition: sbf_blocks.hpp:172
PVTCartesianParser
bool PVTCartesianParser(ROSaicNodeBase *node, It it, It itEnd, PVTCartesianMsg &msg)
Qi based parser for the SBF block "PVTCartesian".
Definition: sbf_blocks.hpp:804
VelSensorSetupParser
bool VelSensorSetupParser(ROSaicNodeBase *node, It it, It itEnd, VelSensorSetupMsg &msg, bool use_ros_axis_orientation)
Qi based parser for the SBF block "VelSensorSetup".
Definition: sbf_blocks.hpp:1714
PVTCartesianMsg
septentrio_gnss_driver::PVTCartesian PVTCartesianMsg
Definition: typedefs.hpp:124
VelCovCartesianMsg
septentrio_gnss_driver::VelCovCartesian VelCovCartesianMsg
Definition: typedefs.hpp:131
ReceiverStatus::agc_state
std::vector< AgcState > agc_state
Definition: sbf_blocks.hpp:232
PosCovCartesianMsg
septentrio_gnss_driver::PosCovCartesian PosCovCartesianMsg
Definition: typedefs.hpp:126
Dop::block_header
BlockHeader block_header
Definition: sbf_blocks.hpp:147
AgcState::sample_var
uint8_t sample_var
Definition: sbf_blocks.hpp:210
parsing_utilities.hpp
Declares utility functions used when parsing messages.
RfBandMsg
septentrio_gnss_driver::RFBand RfBandMsg
Definition: typedefs.hpp:118
ChannelStateInfo::pvt_status
uint16_t pvt_status
Definition: sbf_blocks.hpp:105
VelCovGeodeticParser
bool VelCovGeodeticParser(ROSaicNodeBase *node, It it, It itEnd, VelCovGeodeticMsg &msg)
Qi based parser for the SBF block "VelCovGeodetic".
Definition: sbf_blocks.hpp:1372
ReceiverStatus::cpu_load
uint8_t cpu_load
Definition: sbf_blocks.hpp:222
ChannelSatInfo::health_status
uint16_t health_status
Definition: sbf_blocks.hpp:118
AgcState::blanking_stat
uint8_t blanking_stat
Definition: sbf_blocks.hpp:211
Dop
Definition: sbf_blocks.hpp:145
BlockHeader::sync_1
uint8_t sync_1
first sync byte is $ or 0x24
Definition: sbf_blocks.hpp:86
AttCovEulerMsg
septentrio_gnss_driver::AttCovEuler AttCovEulerMsg
Definition: typedefs.hpp:122
ReceiverStatusParser
bool ReceiverStatusParser(ROSaicNodeBase *node, It it, It itEnd, ReceiverStatus &msg)
Struct for the SBF block "ReceiverStatus".
Definition: sbf_blocks.hpp:1460
MAXSB_CHANNELSATINFO
static const uint8_t MAXSB_CHANNELSATINFO
Max number of bytes that ChannelSatInfo sub-block can consist of.
Definition: sbf_blocks.hpp:46
ReceiverTimesParser
bool ReceiverTimesParser(ROSaicNodeBase *node, It it, It itEnd, ReceiverTimeMsg &msg)
Struct for the SBF block "ReceiverTime".
Definition: sbf_blocks.hpp:772
Dop::vpl
float vpl
Definition: sbf_blocks.hpp:155
qiLittleEndianParser
void qiLittleEndianParser(It &it, Val &val)
Qi little endian parsers for numeric values.
Definition: sbf_blocks.hpp:328
QualityInd::n
uint8_t n
Definition: sbf_blocks.hpp:198
ReceiverSetup::product_name
std::string product_name
Definition: sbf_blocks.hpp:180
ReceiverSetup::country_code
std::string country_code
Definition: sbf_blocks.hpp:187
INSNavGeodMsg
septentrio_gnss_driver::INSNavGeod INSNavGeodMsg
Definition: typedefs.hpp:142
NR_OF_LOGICALCHANNELS
static const uint8_t NR_OF_LOGICALCHANNELS
Using maximum value of NR_OF_LOGICALCHANNELS for SBF definitions.
Definition: sbf_blocks.hpp:36
MAXSB_MEASEPOCH_T1
static const uint8_t MAXSB_MEASEPOCH_T1
Max number of bytes that MeasEpochChannelType1 sub-block can consist of.
Definition: sbf_blocks.hpp:52
ReceiverSetup::gnss_fw_version
std::string gnss_fw_version
Definition: sbf_blocks.hpp:179
ReceiverStatus::rx_error
uint32_t rx_error
Definition: sbf_blocks.hpp:226
log_level::ERROR
@ ERROR
Definition: typedefs.hpp:175
typedefs.hpp
ReceiverStatus::n
uint8_t n
Definition: sbf_blocks.hpp:227
ReceiverSetup::marker_name
std::string marker_name
Definition: sbf_blocks.hpp:166
IMUSetupParser
bool IMUSetupParser(ROSaicNodeBase *node, It it, It itEnd, IMUSetupMsg &msg, bool use_ros_axis_orientation)
Qi based parser for the SBF block "IMUSetup".
Definition: sbf_blocks.hpp:1676
ReceiverStatus::rx_status
uint32_t rx_status
Definition: sbf_blocks.hpp:225
QualityInd::block_header
BlockHeader block_header
Definition: sbf_blocks.hpp:196
Dop::hdop
double hdop
Definition: sbf_blocks.hpp:152
ReceiverStatus::ext_error
uint8_t ext_error
Definition: sbf_blocks.hpp:223
ReceiverStatus::sb_length
uint8_t sb_length
Definition: sbf_blocks.hpp:228
ChannelSatInfo::freq_nr
uint8_t freq_nr
Definition: sbf_blocks.hpp:116
BlockHeader::id
uint16_t id
This is the block ID.
Definition: sbf_blocks.hpp:89
ExtSensorMeasMsg
septentrio_gnss_driver::ExtSensorMeas ExtSensorMeasMsg
Definition: typedefs.hpp:145
MAXSB_NBRANTENNA
static const uint8_t MAXSB_NBRANTENNA
Maximum number of antennas that mosaic etc. can handle.
Definition: sbf_blocks.hpp:44
BaseVectorCartParser
bool BaseVectorCartParser(ROSaicNodeBase *node, It it, It itEnd, BaseVectorCartMsg &msg)
Qi based parser for the SBF block "BaseVectorCart".
Definition: sbf_blocks.hpp:1026
ChannelStatus
Struct for the SBF block "ChannelStatus".
Definition: sbf_blocks.hpp:130
ReceiverStatus::cmd_count
uint8_t cmd_count
Definition: sbf_blocks.hpp:229
BlockHeader
Struct for the SBF block's header message.
Definition: sbf_blocks.hpp:84
MAX_NR_OF_SIGNALS_PER_SATELLITE
static const uint8_t MAX_NR_OF_SIGNALS_PER_SATELLITE
Using maximum value of MAX_NR_OF_SIGNALS_PER_SATELLITE for SBF definitions.
Definition: sbf_blocks.hpp:40
ReceiverSetup
Struct for the SBF block "ReceiverSetup".
Definition: sbf_blocks.hpp:162
ChannelStatus::block_header
BlockHeader block_header
Definition: sbf_blocks.hpp:132
ReceiverSetup::delta_n
float delta_n
Definition: sbf_blocks.hpp:177
ChannelSatInfo
Struct for the SBF sub-block "ChannelSatInfo".
Definition: sbf_blocks.hpp:113
BaseVectorGeodParser
bool BaseVectorGeodParser(ROSaicNodeBase *node, It it, It itEnd, BaseVectorGeodMsg &msg)
Qi based parser for the SBF block "BaseVectorGeod".
Definition: sbf_blocks.hpp:1088
setDoNotUse
void setDoNotUse(Val &s)
Sets scalar to Do-Not-Use value.
Definition: sbf_blocks.hpp:300
AgcState::gain
int8_t gain
Definition: sbf_blocks.hpp:209
BaseVectorGeodMsg
septentrio_gnss_driver::BaseVectorGeod BaseVectorGeodMsg
Definition: typedefs.hpp:114
ReceiverStatus::temperature
uint8_t temperature
Definition: sbf_blocks.hpp:230
RfStatusMsg
septentrio_gnss_driver::RFStatus RfStatusMsg
Definition: typedefs.hpp:117
Dop::vdop
double vdop
Definition: sbf_blocks.hpp:153
MAXSB_CHANNELSTATEINFO
static const uint16_t MAXSB_CHANNELSTATEINFO
Max number of bytes that ChannelStateInfo sub-block can consist of.
Definition: sbf_blocks.hpp:49
ChannelStateInfo::antenna
uint8_t antenna
Definition: sbf_blocks.hpp:103
VectorInfoCartMsg
septentrio_gnss_driver::VectorInfoCart VectorInfoCartMsg
Definition: typedefs.hpp:129
PosCovCartesianParser
bool PosCovCartesianParser(ROSaicNodeBase *node, It it, It itEnd, PosCovCartesianMsg &msg)
Qi based parser for the SBF block "PosCovCartesian".
Definition: sbf_blocks.hpp:1264
ReceiverSetup::rx_name
std::string rx_name
Definition: sbf_blocks.hpp:171
ReceiverSetup::marker_type
std::string marker_type
Definition: sbf_blocks.hpp:178
VelSensorSetupMsg
septentrio_gnss_driver::VelSensorSetup VelSensorSetupMsg
Definition: typedefs.hpp:144
BaseVectorCartMsg
septentrio_gnss_driver::BaseVectorCart BaseVectorCartMsg
Definition: typedefs.hpp:113
MeasEpochChannelType2Parser
void MeasEpochChannelType2Parser(It &it, MeasEpochChannelType2Msg &msg, uint8_t sb2_length)
Qi based parser for the SBF sub-block "MeasEpochChannelType2".
Definition: sbf_blocks.hpp:537
INSNavGeodParser
bool INSNavGeodParser(ROSaicNodeBase *node, It it, It itEnd, INSNavGeodMsg &msg, bool use_ros_axis_orientation)
Qi based parser for the SBF block "INSNavGeod".
Definition: sbf_blocks.hpp:1536
ChannelSatInfo::elev
int8_t elev
Definition: sbf_blocks.hpp:119
MeasEpochMsg
septentrio_gnss_driver::MeasEpoch MeasEpochMsg
Definition: typedefs.hpp:119
ChannelStatus::n
uint8_t n
Definition: sbf_blocks.hpp:134
ReceiverSetup::receiver_idx
uint8_t receiver_idx
Definition: sbf_blocks.hpp:186
VectorInfoCartParser
void VectorInfoCartParser(It &it, VectorInfoCartMsg &msg, uint8_t sb_length)
Qi based parser for the SBF sub-block "VectorInfoCart".
Definition: sbf_blocks.hpp:1001
ReceiverSetup::height
float height
Definition: sbf_blocks.hpp:183
ReceiverSetup::observer
std::string observer
Definition: sbf_blocks.hpp:168
AttEulerParser
bool AttEulerParser(ROSaicNodeBase *node, It it, It itEnd, AttEulerMsg &msg, bool use_ros_axis_orientation)
Qi based parser for the SBF block "AttEuler".
Definition: sbf_blocks.hpp:916
AttCovEulerParser
bool AttCovEulerParser(ROSaicNodeBase *node, It it, It itEnd, AttCovEulerMsg &msg, bool use_ros_axis_orientation)
Qi based parser for the SBF block "AttCovEuler".
Definition: sbf_blocks.hpp:961
MeasEpochChannelType2Msg
septentrio_gnss_driver::MeasEpochChannelType2 MeasEpochChannelType2Msg
Definition: typedefs.hpp:121
ChannelSatInfo::stateInfo
std::vector< ChannelStateInfo > stateInfo
Definition: sbf_blocks.hpp:123
ReceiverSetupParser
bool ReceiverSetupParser(ROSaicNodeBase *node, It it, It itEnd, ReceiverSetup &msg)
Qi based parser for the SBF block "ReceiverSetup".
Definition: sbf_blocks.hpp:714
BlockHeader::revision
uint8_t revision
This is the block revision.
Definition: sbf_blocks.hpp:90
ReceiverSetup::station_code
std::string station_code
Definition: sbf_blocks.hpp:184
ReceiverStatus
Struct for the SBF block "ReceiverStatus".
Definition: sbf_blocks.hpp:218
IMUSetupMsg
septentrio_gnss_driver::IMUSetup IMUSetupMsg
Definition: typedefs.hpp:143
ReceiverSetup::latitude
double latitude
Definition: sbf_blocks.hpp:181
BlockHeader::crc
uint16_t crc
The check sum.
Definition: sbf_blocks.hpp:88
ReceiverSetup::marker_number
std::string marker_number
Definition: sbf_blocks.hpp:167
PVTGeodeticParser
bool PVTGeodeticParser(ROSaicNodeBase *node, It it, It itEnd, PVTGeodeticMsg &msg)
Qi based parser for the SBF block "PVTGeodetic".
Definition: sbf_blocks.hpp:860
Dop::hpl
float hpl
Definition: sbf_blocks.hpp:154
ChannelSatInfo::sv_id
uint8_t sv_id
Definition: sbf_blocks.hpp:115
qiCharsToStringParser
void qiCharsToStringParser(It &it, std::string &val, std::size_t num)
Qi parser for char array to string.
Definition: sbf_blocks.hpp:369
DOPParser
bool DOPParser(ROSaicNodeBase *node, It it, It itEnd, Dop &msg)
Qi based parser for the SBF block "DOP".
Definition: sbf_blocks.hpp:500
ChannelSatInfoParser
bool ChannelSatInfoParser(ROSaicNodeBase *node, It &it, ChannelSatInfo &msg, uint8_t sb1_length, uint8_t sb2_length)
Qi based parser or the SBF sub-block "ChannelSatInfo".
Definition: sbf_blocks.hpp:427
ChannelStateInfo::tracking_status
uint16_t tracking_status
Definition: sbf_blocks.hpp:104
AttEulerMsg
septentrio_gnss_driver::AttEuler AttEulerMsg
Definition: typedefs.hpp:123


septentrio_gnss_driver
Author(s): Tibor Dome
autogenerated on Wed Nov 22 2023 04:04:27