Main MRPT website > C++ reference for MRPT 1.9.9
CGPSInterface.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "hwdrivers-precomp.h" // Precompiled headers
11 
12 #include <mrpt/system/os.h>
13 #include <mrpt/system/filesystem.h>
16 
17 #include <list>
18 #include <mutex>
19 #include <thread>
20 
21 using namespace mrpt::hwdrivers;
22 using namespace mrpt::obs;
23 using namespace mrpt::system;
24 using namespace mrpt::utils;
25 using namespace mrpt::comms;
26 using namespace std;
27 
29 
31 {
32  std::list<CGPSInterface::ptr_parser_t> all_parsers;
33 
34  static const TParsersRegistry& getInstance()
35  {
36  static TParsersRegistry reg;
37  return reg;
38  }
39 
40  private:
42  {
43  all_parsers.push_back(&CGPSInterface::implement_parser_NMEA);
44  all_parsers.push_back(&CGPSInterface::implement_parser_NOVATEL_OEM6);
45  }
46 };
47 
48 /* -----------------------------------------------------
49  Constructor
50  ----------------------------------------------------- */
52  : mrpt::utils::COutputLogger("CGPSInterface"),
53  m_data_stream(nullptr), // Typically a CSerialPort created by this class,
54  // but may be set externally.
55  m_data_stream_cs(nullptr),
56  m_data_stream_is_external(false),
57  m_customInit(),
58  m_rx_buffer(0x10000),
59  m_parser(CGPSInterface::AUTO),
60  m_raw_dump_file_prefix(),
61  m_COMname(),
62  m_COMbauds(4800),
63  m_sensorLabelAppendMsgType(true),
64  m_GPS_comsWork(false),
65  m_last_timestamp(INVALID_TIMESTAMP),
66  m_custom_cmds_delay(0.1),
67  m_custom_cmds_append_CRLF(true),
68 
69  m_JAVAD_rtk_src_port(),
70  m_JAVAD_rtk_src_baud(0),
71  m_JAVAD_rtk_format("cmr"),
72  m_topcon_useAIMMode(false),
73  m_topcon_AIMConfigured(false),
74  m_topcon_data_period(0.2) // 20 Hz
75 {
76  m_sensorLabel = "GPS";
77 }
78 
79 /* -----------------------------------------------------
80  loadConfig_sensorSpecific
81  ----------------------------------------------------- */
83  const mrpt::utils::CConfigFileBase& configSource,
84  const std::string& iniSection)
85 {
87  iniSection, "parser", m_parser, false /*Allow default values*/);
88  m_raw_dump_file_prefix = configSource.read_string(
89  iniSection, "raw_dump_file_prefix", m_raw_dump_file_prefix,
90  false /*Allow default values*/);
91 
92 #ifdef MRPT_OS_WINDOWS
93  m_COMname =
94  configSource.read_string(iniSection, "COM_port_WIN", m_COMname, true);
95 #else
96  m_COMname =
97  configSource.read_string(iniSection, "COM_port_LIN", m_COMname, true);
98 #endif
99 
100  m_COMbauds =
101  configSource.read_int(iniSection, "baudRate", m_COMbauds, true);
102  m_sensorLabelAppendMsgType = configSource.read_bool(
103  iniSection, "sensor_label_append_msg_type", m_sensorLabelAppendMsgType);
104 
105  // legacy custom cmds:
106  m_customInit =
107  configSource.read_string(iniSection, "customInit", m_customInit, false);
108 
109  // new custom cmds:
110  m_custom_cmds_delay = configSource.read_float(
111  iniSection, "custom_cmds_delay", m_custom_cmds_delay);
112  m_custom_cmds_append_CRLF = configSource.read_bool(
113  iniSection, "custom_cmds_append_CRLF", m_custom_cmds_append_CRLF);
114  // Load as many strings as found on the way:
115  m_setup_cmds.clear();
116  for (int i = 1; true; i++)
117  {
118  std::string sLine = configSource.read_string(
119  iniSection, mrpt::format("setup_cmd%i", i), std::string());
120  sLine = mrpt::system::trim(sLine);
121  if (sLine.empty()) break;
122  m_setup_cmds.push_back(sLine);
123  }
124 
125  m_shutdown_cmds.clear();
126  for (int i = 1; true; i++)
127  {
128  std::string sLine = configSource.read_string(
129  iniSection, mrpt::format("shutdown_cmd%i", i), std::string());
130  sLine = mrpt::system::trim(sLine);
131  if (sLine.empty()) break;
132  m_shutdown_cmds.push_back(sLine);
133  }
134 
136  configSource.read_float(iniSection, "pose_x", 0),
137  configSource.read_float(iniSection, "pose_y", 0),
138  configSource.read_float(iniSection, "pose_z", 0),
139  DEG2RAD(configSource.read_float(iniSection, "pose_yaw", 0)),
140  DEG2RAD(configSource.read_float(iniSection, "pose_pitch", 0)),
141  DEG2RAD(configSource.read_float(iniSection, "pose_roll", 0)));
142 
143  m_JAVAD_rtk_src_port = configSource.read_string(
144  iniSection, "JAVAD_rtk_src_port", m_JAVAD_rtk_src_port);
145  m_JAVAD_rtk_src_baud = configSource.read_int(
146  iniSection, "JAVAD_rtk_src_baud", m_JAVAD_rtk_src_baud);
147  m_JAVAD_rtk_format = configSource.read_string(
148  iniSection, "JAVAD_rtk_format", m_JAVAD_rtk_format);
149 
150  m_topcon_useAIMMode = configSource.read_bool(
151  iniSection, "JAVAD_useAIMMode", m_topcon_useAIMMode);
152  m_topcon_data_period = 1.0 /
153  configSource.read_double(
154  iniSection, "outputRate", m_topcon_data_period);
155 }
156 
158 {
160 
162  {
163  delete m_data_stream;
164  m_data_stream = nullptr;
165  }
166 }
167 
169 {
170  m_parser = parser;
171 }
174  mrpt::utils::CStream* external_stream, std::mutex* csOptionalExternalStream)
175 {
177  {
178  delete m_data_stream;
179  m_data_stream = nullptr;
180  }
181 
183  m_data_stream = external_stream;
184  m_data_stream_cs = csOptionalExternalStream;
185 }
186 void CGPSInterface::setSetupCommandsDelay(const double delay_secs)
187 {
188  m_custom_cmds_delay = delay_secs;
189 }
191 {
192  return m_custom_cmds_delay;
193 }
194 void CGPSInterface::setSetupCommands(const std::vector<std::string>& cmds)
195 {
196  m_setup_cmds = cmds;
197 }
198 const std::vector<std::string>& CGPSInterface::getSetupCommands() const
199 {
200  return m_setup_cmds;
201 }
202 void CGPSInterface::setShutdownCommands(const std::vector<std::string>& cmds)
203 {
204  m_shutdown_cmds = cmds;
205 }
206 const std::vector<std::string>& CGPSInterface::getShutdownCommands() const
207 {
208  return m_shutdown_cmds;
209 }
211 {
212  m_custom_cmds_append_CRLF = enable;
213 }
215 {
217 }
218 
219 /* -----------------------------------------------------
220  setSerialPortName
221 ----------------------------------------------------- */
223 {
224  // Dont allow changing the serial port if:
227  "Cannot change serial port name: an external stream has been "
228  "already bound manually.")
229 
230  if (m_data_stream)
231  {
232  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
233  auto serial = dynamic_cast<mrpt::comms::CSerialPort*>(m_data_stream);
234  if (serial && serial->isOpen())
236  "Cannot change serial port name when it is already open")
237  }
238 
239  // OK:
240  m_COMname = COM_port;
241 }
242 
243 /* -----------------------------------------------------
244  getSerialPortName
245 ----------------------------------------------------- */
247 /* -----------------------------------------------------
248  tryToOpenTheCOM
249 ----------------------------------------------------- */
251 {
252  // If this is the first use of the COM port, create it:
253  if (!m_data_stream)
254  {
257  }
258 
259  auto serial = dynamic_cast<CSerialPort*>(m_data_stream);
260  if (serial)
261  {
262  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
263  if (serial->isOpen()) return true; // Already open
264 
265  if (m_verbose)
266  cout << "[CGPSInterface] Opening " << m_COMname << " @ "
267  << m_COMbauds << endl;
268 
269  try
270  {
271  serial->open(m_COMname);
272  // Config:
273  serial->setConfig(m_COMbauds, 0, 8, 1);
274  serial->setTimeouts(1, 0, 1, 1, 1);
275 
276  // Do extra initialization?
278  {
279  serial->close();
280  return false;
281  }
282  return true; // All OK
283  }
284  catch (std::exception& e)
285  {
286  std::cerr << "[CGPSInterface::tryToOpenTheCOM] Error opening or "
287  "configuring serial port:"
288  << std::endl
289  << e.what();
290  serial->close();
291  return false;
292  }
293  } // end of this is a serial port
294 
295  return true; // All OK
296 }
297 
298 /* -----------------------------------------------------
299  isGPS_connected
300 ----------------------------------------------------- */
302 /* -----------------------------------------------------
303  doProcess
304 ----------------------------------------------------- */
306 {
307  // Is the COM open?
308  if (!tryToOpenTheCOM())
309  {
310  m_state = ssError;
311  THROW_EXCEPTION("Could not open the input stream");
312  }
313  ASSERT_(m_data_stream != nullptr)
314  CSerialPort* stream_serial = dynamic_cast<CSerialPort*>(m_data_stream);
315  CClientTCPSocket* stream_tcpip =
316  dynamic_cast<CClientTCPSocket*>(m_data_stream);
317 
318  // Read as many bytes as available:
319  uint8_t buf[0x1000];
320  const size_t to_read =
321  std::min(m_rx_buffer.available() - 1, sizeof(buf) - 1);
322  try
323  {
324  size_t nRead = 0;
325  if (to_read > 0)
326  {
327  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
328  if (stream_tcpip)
329  {
330  nRead = stream_tcpip->readAsync(buf, to_read, 100, 10);
331  }
332  else if (stream_serial)
333  {
334  nRead = stream_serial->Read(buf, to_read);
335  }
336  else
337  {
338  nRead = m_data_stream->ReadBuffer(buf, to_read);
339  }
340  }
341 
342  if (nRead) m_rx_buffer.push_many(buf, nRead);
343 
344  // Also dump to raw file:
345  if (!m_raw_dump_file_prefix.empty() &&
347  {
348  // 1st time open:
350  mrpt::system::timestampToParts(now(), parts, true);
351  string sFilePostfix = "_";
352  sFilePostfix += format(
353  "%04u-%02u-%02u_%02uh%02um%02us", (unsigned int)parts.year,
354  (unsigned int)parts.month, (unsigned int)parts.day,
355  (unsigned int)parts.hour, (unsigned int)parts.minute,
356  (unsigned int)parts.second);
357  const string sFileName =
360  string(".gps");
361 
362  if (m_verbose)
363  std::cout << "[CGPSInterface] Creating RAW dump file: `"
364  << sFileName << "`\n";
365  m_raw_output_file.open(sFileName);
366  }
367  if (nRead && m_raw_output_file.fileOpenCorrectly())
368  {
369  m_raw_output_file.WriteBuffer(buf, nRead);
370  }
371  }
372  catch (std::exception&)
373  {
374  // ERROR:
376  "[CGPSInterface::doProcess] Error reading stream of data: Closing "
377  "communications\n");
378  if (stream_serial)
379  {
380  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
381  stream_serial->close();
382  }
383  m_GPS_comsWork = false;
384  return;
385  }
386 
387  // Try to parse incomming data as messages:
388  parseBuffer();
389 
390  // Decide whether to push out a new observation in old legacy mode.
391  if (!m_customInit.empty())
392  { // "Advanced" (RTK,mmGPS) device (kept for backwards-compatibility)
393  bool do_append_obs = false;
394  // FAMD
395  // Append observation if:
396  // 0. the timestamp seems to be correct!
397  // 1. it contains both synched GGA and RMC data
398  // 2. it contains only GGA or RMC but the next one is not synched with
399  // it
401  {
402  if (m_verbose)
403  cout << "[CGPSInterface] Initial timestamp: "
406  << endl;
407  // Check if the initial timestamp seems to be OK (not a spurio one)
408  TTimeStamp tmNow = mrpt::system::now();
409  const double tdif = mrpt::system::timeDifference(
411  if (tdif >= 0 && tdif < 7500 /*Up to two hours*/)
413  else
414  {
415  if (m_verbose)
416  cout << "[CGPSInterface] Warning: The initial timestamp "
417  "seems to be wrong! : "
418  << tdif << endl;
419  }
420  } // end-if
421  else
422  {
423  const double time_diff = mrpt::system::timeDifference(
425  if (time_diff < 0 || time_diff > 300) // Assert that the current
426  // timestamp is after the
427  // previous one and not more
428  // than 5 minutes later ->
429  // remove spurious
430  {
431  if (m_verbose)
432  cout << "[CGPSInterface ] Bad timestamp difference" << endl;
433  return;
434  }
435 
436  if (time_diff - m_topcon_data_period > 0.25 * m_topcon_data_period)
437  {
438  if (m_verbose)
439  cout << "[CGPSInterface] WARNING: According to the "
440  "timestamps, we probably skipped one frame!"
441  << endl;
442  }
443 
444  // a. These GPS data have both synched RMC and GGA data
445  // don't append observation until we have both data
446  do_append_obs =
449  } // end-else
450 
451  if (do_append_obs) flushParsedMessagesNow();
452  }
453 }
454 
455 /** Queue out now the messages in \a m_just_parsed_messages, leaving it empty */
456 
458 {
459  // Generic observation data:
464  else
466  // Add observation to the output queue:
467  CObservationGPS::Ptr newObs = mrpt::make_aligned_shared<CObservationGPS>();
468  m_just_parsed_messages.swap(*newObs);
472 
473  // And this means the comms works:
474  m_GPS_comsWork = true;
475  m_state = ssWorking;
476 }
477 
478 /* -----------------------------------------------------
479  parseBuffer
480 ----------------------------------------------------- */
482 {
483  if (m_parser == CGPSInterface::NONE) return; // Dont try to parse data
484 
485  // Only one parser selected?
486  ptr_parser_t parser_ptr = nullptr;
487  switch (m_parser)
488  {
489  case CGPSInterface::NMEA:
491  break;
494  break;
495  case CGPSInterface::AUTO:
496  break; // Leave it as NULL
497  default:
498  throw std::runtime_error("[CGPSInterface] Unknown parser!");
499  };
500  if (parser_ptr)
501  {
502  // Use only one parser ----------
503  size_t min_bytes;
504  do
505  {
506  if (!(*this.*parser_ptr)(min_bytes))
507  {
508  m_rx_buffer.pop(); // Not the start of a frame, skip 1 byte
509  }
510  if (m_customInit.empty() /* If we are not in old legacy mode */ &&
513  } while (m_rx_buffer.size() >= min_bytes);
514  } // end one parser mode ----------
515  else
516  {
517  // AUTO mode --------
518  const std::list<CGPSInterface::ptr_parser_t>& all_parsers =
520 
521  size_t global_min_bytes_max = 0;
522  do
523  {
524  bool all_parsers_want_to_skip = true;
526  all_parsers.begin();
527  it != all_parsers.end(); ++it)
528  {
529  parser_ptr = *it;
530  size_t this_parser_min_bytes;
531  if ((*this.*parser_ptr)(this_parser_min_bytes))
532  all_parsers_want_to_skip = false;
534  global_min_bytes_max, this_parser_min_bytes);
535  }
536 
537  if (all_parsers_want_to_skip)
538  m_rx_buffer.pop(); // Not the start of a frame, skip 1 byte
539 
540  if (m_customInit.empty() /* If we are not in old legacy mode */ &&
543  } while (m_rx_buffer.size() >= global_min_bytes_max);
544  } // end AUTO mode ----
545 }
546 
547 /* -----------------------------------------------------
548  JAVAD_sendMessage
549 ----------------------------------------------------- */
550 void CGPSInterface::JAVAD_sendMessage(const char* str, bool waitForAnswer)
551 {
552  if (!str) return;
553  const size_t len = strlen(str);
554  CSerialPort* stream_serial = dynamic_cast<CSerialPort*>(m_data_stream);
555  if (!stream_serial) return;
556 
557  size_t written;
558 
559  {
560  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
561  written = stream_serial->Write(str, len);
562  }
563 
564  if (m_verbose) std::cout << "[CGPSInterface] TX: " << str;
565 
566  if (written != len)
567  throw std::runtime_error(
568  format("Error sending command: '%s'", str).c_str());
569  std::this_thread::sleep_for(5ms);
570 
571  if (!waitForAnswer) return;
572 
573  std::this_thread::sleep_for(200ms);
574  char buf[200];
575  buf[0] = '\0';
576 
577  int bad_counter = 0;
578  while (bad_counter < 10)
579  {
580  size_t nRead;
581  {
582  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
583  written = stream_serial->Write(str, len);
584  nRead = stream_serial->Read(buf, sizeof(buf));
585  }
586 
587  if (m_verbose) std::cout << "[CGPSInterface] RX: " << buf << std::endl;
588 
589  if (nRead < 3)
590  throw std::runtime_error(
591  format(
592  "ERROR: Invalid response '%s' for command '%s'", buf, str));
593 
594  if (nRead >= 3 && buf[0] == 'R' && buf[1] == 'E')
595  return; // Ok!
596  else
597  ++bad_counter;
598  }
599  throw std::runtime_error(
600  format("ERROR: Invalid response '%s' for command '%s'", buf, str));
601 }
602 
604 {
605  CSerialPort* stream_serial = dynamic_cast<CSerialPort*>(m_data_stream);
606 
607  if (stream_serial && !stream_serial->isOpen()) return false;
608 
609  // Send commands:
610  for (size_t i = 0; i < m_shutdown_cmds.size(); i++)
611  {
612  if (m_verbose)
613  cout << "[CGPSInterface] TX shutdown command: `"
614  << m_shutdown_cmds[i] << "`\n";
615 
616  std::string sTx = m_shutdown_cmds[i];
617  if (m_custom_cmds_append_CRLF) sTx += std::string("\r\n");
618  try
619  {
620  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
621  m_data_stream->WriteBuffer(&sTx[0], sTx.size());
622  }
623  catch (...)
624  {
625  return false; // On any I/O error
626  }
627 
628  std::this_thread::sleep_for(
629  std::chrono::duration<double, std::milli>(
630  m_custom_cmds_delay * 1000));
631  }
632  return true;
633 }
634 
635 /* -----------------------------------------------------
636  OnConnectionEstablished
637 ----------------------------------------------------- */
639 {
640  m_last_GGA.clear(); // On comms reset, empty this cache
642 
643  // Legacy behavior:
644  if (!os::_strcmpi(m_customInit.c_str(), "JAVAD") ||
645  !os::_strcmpi(m_customInit.c_str(), "TOPCON"))
646  {
648  }
649 
650  // Purge input:
651  CSerialPort* stream_serial = dynamic_cast<CSerialPort*>(m_data_stream);
652  if (stream_serial)
653  {
654  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
655  stream_serial->purgeBuffers();
656  }
657 
658  // New behavior: Send generic commands set-up by the user in the config
659  // file.
660 
661  // Send commands:
662  for (size_t i = 0; i < m_setup_cmds.size(); i++)
663  {
664  if (m_verbose)
665  cout << "[CGPSInterface] TX setup command: `" << m_setup_cmds[i]
666  << "`\n";
667 
668  std::string sTx = m_setup_cmds[i];
669  if (m_custom_cmds_append_CRLF) sTx += std::string("\r\n");
670 
671  try
672  {
673  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
674  m_data_stream->WriteBuffer(&sTx[0], sTx.size());
675  }
676  catch (std::exception& e)
677  {
678  std::cerr << "[CGPSInterface::OnConnectionEstablished] Error "
679  "sending setup cmds: "
680  << e.what() << std::endl;
681  return false;
682  }
683  std::this_thread::sleep_for(
684  std::chrono::duration<double, std::milli>(
685  m_custom_cmds_delay * 1000));
686  }
687  std::this_thread::sleep_for(
688  std::chrono::duration<double, std::milli>(m_custom_cmds_delay * 1000));
689  return true;
690 }
691 
693 {
694  MRPT_START
695  if (!os::_strcmpi(m_customInit.c_str(), "JAVAD") ||
696  !os::_strcmpi(m_customInit.c_str(), "TOPCON"))
697  {
698  // Stop messaging:
699  JAVAD_sendMessage("%%dm\r\n", false);
700  std::this_thread::sleep_for(500ms);
701  JAVAD_sendMessage("%%dm\r\n", false);
702  std::this_thread::sleep_for(1000ms);
703 
704  // Purge input:
705  CSerialPort* stream_serial = dynamic_cast<CSerialPort*>(m_data_stream);
706  if (stream_serial)
707  {
708  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
709  stream_serial->purgeBuffers();
710  }
711 
712  JAVAD_sendMessage("%%set,/par/cur/term/imode,cmd\r\n"); // set the
713  // current port
714  // in command
715  // mode
716  return true;
717  }
718  else
719  return true;
720  MRPT_END
721 } // end-unsetJAVAD_AIM_mode
722 
724 {
725  MRPT_START
726  if (!os::_strcmpi(m_customInit.c_str(), "JAVAD") ||
727  !os::_strcmpi(m_customInit.c_str(), "TOPCON"))
728  {
730  format("%%%%set,/par%s/imode,cmd\r\n", m_JAVAD_rtk_src_port.c_str())
731  .c_str()); // set the port in command mode
733  "%%set,/par/cur/term/jps/0,{nscmd,37,n,\"\"}\r\n"); // any command
734  // starting
735  // with % will
736  // be treated
737  // as normal
738 
739  ASSERT_(!m_JAVAD_rtk_format.empty())
740  cout << "Formato de correcciones para GR3: " << m_JAVAD_rtk_format
741  << endl;
742  if (m_JAVAD_rtk_format == "cmr")
743  {
745  format(
746  "%%%%set,/par/cur/term/jps/1,{cmr,-1,y,%s}\r\n",
747  m_JAVAD_rtk_src_port.c_str())
748  .c_str()); // set corrections type CMR or CMR+
749  JAVAD_sendMessage("%%set,/par/cur/term/jps/2,{none,-1,n,\"\"}\r\n");
751  format(
752  "%%%%set,/par%s/imode,cmr\r\n",
753  m_JAVAD_rtk_src_port.c_str())
754  .c_str());
755  }
756  else if (m_JAVAD_rtk_format == "rtcm")
757  {
759  format(
760  "%%%%set,/par/cur/term/jps/1,{rtcm,-1,y,%s}\r\n",
761  m_JAVAD_rtk_src_port.c_str())
762  .c_str()); // set corrections type RTCM
763  JAVAD_sendMessage("%%set,/par/cur/term/jps/2,{none,-1,n,\"\"}\r\n");
765  format(
766  "%%%%set,/par%s/imode,rtcm\r\n",
767  m_JAVAD_rtk_src_port.c_str())
768  .c_str());
769  }
770  else if (m_JAVAD_rtk_format == "rtcm3")
771  {
773  format(
774  "%%%%set,/par/cur/term/jps/1,{rtcm3,-1,y,%s}\r\n",
775  m_JAVAD_rtk_src_port.c_str())
776  .c_str()); // set corrections type RTCM 3.x
777  JAVAD_sendMessage("%%set,/par/cur/term/jps/2,{none,-1,n,\"\"}\r\n");
779  format(
780  "%%%%set,/par%s/imode,rtcm3\r\n",
781  m_JAVAD_rtk_src_port.c_str())
782  .c_str());
783  }
784  else
785  {
786  cout << "Unknown RTK corrections format. Only supported: CMR, RTCM "
787  "or RTCM3"
788  << endl;
789  return false;
790  }
791  JAVAD_sendMessage("%%set,/par/cur/term/imode,jps\r\n"); // sets current
792  // port into
793  // "JPS" mode
794 
795  return true;
796 
797  } // end-if
798  else
799  return true;
800  MRPT_END
801 } // end-setJAVAD_AIM_mode
802 
804 {
805  std::string ret = m_last_GGA;
806  if (reset) m_last_GGA.clear();
807  return ret;
808 }
809 
811 {
812  // Stop messaging:
813  JAVAD_sendMessage("%%dm\r\n", false);
814  std::this_thread::sleep_for(500ms);
815  JAVAD_sendMessage("%%dm\r\n", false);
816  std::this_thread::sleep_for(1000ms);
817 
818  // Purge input:
819  CSerialPort* stream_serial = dynamic_cast<CSerialPort*>(m_data_stream);
820  if (stream_serial)
821  {
822  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
823  stream_serial->purgeBuffers();
824  }
825 
826  // Configure RTK mode and source:
827  if (m_verbose) cout << "[CGPSInterface] Configure RTK options" << endl;
828 
829  if (!m_JAVAD_rtk_src_port.empty())
830  {
831  const int elevation_mask = 5; // Degs
832 
834  format("%%%%set,/par/lock/elm,%i\r\n", elevation_mask)
835  .c_str()); // Set elevation mask to track satellites
837  "%%set,/par/base/mode/,off\r\n"); // Set Base Mode off
838  JAVAD_sendMessage("%%set,/par/pos/pd/period,1.0\r\n"); // Differential
839  // Correction
840  // Interval
841  // JAVAD_sendMessage("%%set,hd/mode,off\r\n"); // fixed distance to rtk
842  // base: Off
843  // JAVAD_sendMessage("%%set,/par/pos/pd/hd/mode,off\r\n"); // fixed
844  // distance to rtk base: Off <-- Not working with TopCon GR3! (option
845  // disabled)
847  "%%set,/par/pos/pd/qcheck,off\r\n"); // Set Quality Checks Off
849  "%%set,/par/pos/mode/cur,pd\r\n"); // Pos Mode Phase Diff
851  "%%set,/par/pos/pd/textr,10\r\n"); // RTK Extrapolation Limit
853  "%%set,/par/pos/pd/inuse,-1\r\n"); // Set Rovers Reference Station
854  JAVAD_sendMessage("%%set,/par/pos/pd/nrs/mode,y\r\n"); // Enable
855  // Nearest
856  // Reference
857  // Station Mode
858  JAVAD_sendMessage("%%set,/par/pos/pd/mode,extrap\r\n"); // Enable
859  // EXTRAPOLATED
860  // mode in RTK
861  // corrections
862 
863  // Set Differential Correction Source
865  format(
866  "%%%%set,/par/pos/pd/port,%s\r\n", m_JAVAD_rtk_src_port.c_str())
867  .c_str());
868 
869  // Set port bauds:
873  format(
874  "%%%%set,/par%s/rate,%u\r\n", m_JAVAD_rtk_src_port.c_str(),
876  .c_str());
877 
878  // Set Input Mode: CMR,RTCM,...
879  if (!m_topcon_useAIMMode && !m_JAVAD_rtk_format.empty())
881  format(
882  "%%%%set,/par%s/imode,%s\r\n", m_JAVAD_rtk_src_port.c_str(),
883  m_JAVAD_rtk_format.c_str())
884  .c_str());
885  }
886 
887  // Start NMEA messaging:
888  // JAVAD_sendMessage("%%em,,/msg/nmea/GGA:0.2\r\n");
889  // JAVAD_sendMessage("%%em,,/msg/nmea/RMC:0.2\r\n");
890  // JAVAD_sendMessage("%%em,,/msg/jps/PS:0.2\r\n");
891 
893  {
894  if (m_verbose) cout << "[CGPSInterface] Using Advanced Input Mode";
896  if (m_verbose) cout << "... done" << endl;
897  }
899  format("%%%%em,,/msg/nmea/GGA:%.1f\r\n", m_topcon_data_period).c_str());
901  format("%%%%em,,/msg/nmea/RMC:%.1f\r\n", m_topcon_data_period)
902  .c_str()); // FAMD: 10 Hz
903 
905  {
906  if (m_verbose)
907  cout << "[CGPSInterface::OnConnectionEstablished] JAVAD/TopCon "
908  "commands sent successfully with AIM."
909  << endl;
910  }
911  else
912  {
913  if (m_verbose)
914  cout << "[CGPSInterface::OnConnectionEstablished] JAVAD/TopCon "
915  "commands sent successfully."
916  << endl;
917  }
918 
919  return true;
920 }
921 
922 /** Send a custom data block to the GNSS device right now. Can be used to change
923  * its behavior online as needed. */
924 bool CGPSInterface::sendCustomCommand(const void* data, const size_t datalen)
925 {
926  try
927  {
928  std::lock_guard<std::mutex> lock(*m_data_stream_cs);
929  m_data_stream->WriteBuffer(data, datalen);
930  return true;
931  }
932  catch (std::exception& e)
933  {
934  std::cerr << "[CGPSInterface::sendCustomCommand] Error sending cmd: "
935  << e.what() << std::endl;
936  return false;
937  }
938 }
uint64_t TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
Definition: datetime.h:32
bool fileOpenCorrectly()
Returns true if the file was open without errors.
size_t Write(const void *Buffer, size_t Count)
Implements the virtual method responsible for writing to the stream.
size_t ReadBuffer(void *Buffer, size_t Count)
Reads a block of bytes from the stream into Buffer.
Definition: CStream.cpp:40
void timestampToParts(TTimeStamp t, TTimeParts &p, bool localTime=false)
Gets the individual parts of a date/time (days, hours, minutes, seconds) - UTC time or local time...
Definition: datetime.cpp:103
static const TParsersRegistry & getInstance()
mrpt::utils::CStream * m_data_stream
Typically a CSerialPort created by this class, but may be set externally.
PARSERS
Read about parser selection in the documentation for CGPSInterface.
A class capable of reading GPS/GNSS/GNSS+IMU receiver data, from a serial port or from any input stre...
bool read_bool(const std::string &section, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
void JAVAD_sendMessage(const char *str, bool waitForAnswer=true)
Private auxiliary method.
void doProcess()
This method will be invoked at a minimum rate of "process_rate" (Hz)
#define min(a, b)
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
A communications serial port built as an implementation of a utils::CStream.
Definition: CSerialPort.h:47
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
bool isGPS_connected()
Returns true if communications work, i.e.
mrpt::obs::CObservationGPS m_just_parsed_messages
A private copy of the last received gps datum.
const std::vector< std::string > & getSetupCommands() const
bool OnConnectionShutdown()
Like OnConnectionEstablished() for sending optional shutdown commands.
std::string m_sensorLabel
See CGenericSensor.
size_t available() const
The maximum number of elements that can be written ("push") without rising an overflow error...
#define THROW_EXCEPTION(msg)
void swap(CObservationGPS &o)
message_list_t messages
The main piece of data in this class: a list of GNNS messages.
bool unsetJAVAD_AIM_mode()
Unset Advanced Input Mode for the primary port and use it only as a command port. ...
size_t size() const
Return the number of elements available for read ("pop") in the buffer (this is NOT the maximum size ...
void bindStream(mrpt::utils::CStream *external_stream, std::mutex *csOptionalExternalStream=nullptr)
This enforces the use of a given user stream, instead of trying to open the serial port set in this c...
void WriteBuffer(const void *Buffer, size_t Count)
Writes a block of bytes to the stream from Buffer.
Definition: CStream.cpp:64
bool m_topcon_AIMConfigured
Indicates if the AIM has been properly set up.
bool open(const std::string &fileName, bool append=false)
Open the given file for write.
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Definition: datetime.h:76
Contains classes for various device interfaces.
bool(CGPSInterface::* ptr_parser_t)(size_t &out_minimum_rx_buf_to_decide)
bool strCmp(const std::string &s1, const std::string &s2)
Return true if the two strings are equal (case sensitive)
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
void enableSetupCommandsAppendCRLF(const bool enable)
std::string timeToString(const mrpt::system::TTimeStamp t)
Convert a timestamp into this textual form (UTC): HH:MM:SS.MMMMMM.
Definition: datetime.cpp:337
STL namespace.
void parseBuffer()
Process data in "m_buffer" to extract GPS messages, and remove them from the buffer.
std::string fileNameStripInvalidChars(const std::string &filename, const char replacement_to_invalid_chars='_')
Replace invalid filename chars by underscores (&#39;_&#39;) or any other user-given char. ...
Definition: filesystem.cpp:327
bool sendCustomCommand(const void *data, const size_t datalen)
Send a custom data block to the GNSS device right now.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
bool tryToOpenTheCOM()
Returns true if the COM port is already open, or try to open it in other case.
unsigned int m_JAVAD_rtk_src_baud
Only used when "m_JAVAD_rtk_src_port" is not empty.
std::string m_JAVAD_rtk_src_port
If not empty, will send a cmd "set,/par/pos/pd/port,...".
GLenum GLsizei len
Definition: glext.h:4712
std::list< CGPSInterface::ptr_parser_t > all_parsers
bool isEnabledSetupCommandsAppendCRLF() const
This class allows loading and storing values and vectors of different types from a configuration text...
unsigned char uint8_t
Definition: rptypes.h:41
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
#define MRPT_END
internal_msg_test_proxy< gnss::NMEA_RMC > has_RMC_datum
Evaluates as a bool; true if the corresponding field exists in messages.
bool implement_parser_NMEA(size_t &out_minimum_rx_buf_to_decide)
The parts of a date/time (it&#39;s like the standard &#39;tm&#39; but with fractions of seconds).
Definition: datetime.h:38
void setSetupCommands(const std::vector< std::string > &cmds)
uint8_t day
Month (1-12)
Definition: datetime.h:42
bool isOpen() const
Returns if port has been correctly open.
void setSetupCommandsDelay(const double delay_secs)
This namespace contains representation of robot actions and observations.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
std::string m_JAVAD_rtk_format
Only used when "m_JAVAD_rtk_src_port" is not empty: format of RTK corrections: "cmr", "rtcm", "rtcm3", etc.
bool implement_parser_NOVATEL_OEM6(size_t &out_minimum_rx_buf_to_decide)
void purgeBuffers()
Purge tx and rx buffers.
mrpt::utils::circular_buffer< uint8_t > m_rx_buffer
Auxiliary buffer for readings.
#define DEG2RAD
GLsizei const GLchar ** string
Definition: glext.h:4101
bool OnConnectionEstablished()
Implements custom messages to be sent to the GPS unit just after connection and before normal use...
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
void close()
Close the port.
ENUMTYPE read_enum(const std::string &section, const std::string &name, const ENUMTYPE &defaultValue, bool failIfNotFound=false) const
Reads an "enum" value, where the value in the config file can be either a numerical value or the symb...
std::vector< std::string > m_setup_cmds
void appendObservation(const mrpt::utils::CSerializable::Ptr &obj)
Like appendObservations() but for just one observation.
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
Definition: datetime.h:16
T pop()
Retrieve an element from the buffer.
void clear()
Empties this observation, clearing the container messages.
double second
Minute (0-59)
Definition: datetime.h:45
std::string getSerialPortName() const
Get the serial port to use (COM1, ttyUSB0, etc).
#define MRPT_START
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
Definition: CObservation.h:60
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
uint8_t minute
Hour (0-23)
Definition: datetime.h:44
internal_msg_test_proxy< gnss::NMEA_GGA > has_GGA_datum
Evaluates as a bool; true if the corresponding field exists in messages.
mrpt::poses::CPose3D sensorPose
The sensor pose on the robot/vehicle.
bool setJAVAD_AIM_mode()
Set Advanced Input Mode for the primary port.
double read_double(const std::string &section, const std::string &name, double defaultValue, bool failIfNotFound=false) const
mrpt::utils::CFileOutputStream m_raw_output_file
void setFromValues(const double x0, const double y0, const double z0, const double yaw=0, const double pitch=0, const double roll=0)
Set the pose from a 3D position (meters) and yaw/pitch/roll angles (radians) - This method recomputes...
Definition: CPose3D.cpp:248
GLboolean reset
Definition: glext.h:3582
A TCP socket that can be connected to a TCP server, implementing MRPT&#39;s CStream interface for passing...
std::shared_ptr< CObservationGPS > Ptr
uint8_t month
The year.
Definition: datetime.h:41
#define ASSERT_(f)
void loadConfig_sensorSpecific(const mrpt::utils::CConfigFileBase &configSource, const std::string &iniSection)
See the class documentation at the top for expected parameters.
std::string getLastGGA(bool reset=true)
Gets the latest GGA command or an empty string if no newer GGA command was received since the last ca...
std::string trim(const std::string &str)
Removes leading and trailing spaces.
uint8_t hour
Day (1-31)
Definition: datetime.h:43
#define MRPT_LOG_ERROR(_STRING)
double m_topcon_data_period
The period in seconds which the data should be provided by the GPS.
double timeDifference(const mrpt::system::TTimeStamp t_first, const mrpt::system::TTimeStamp t_later)
Returns the time difference from t1 to t2 (positive if t2 is posterior to t1), in seconds...
Definition: datetime.cpp:208
Serial and networking devices and utilities.
mrpt::system::TTimeStamp m_last_timestamp
size_t readAsync(void *Buffer, const size_t Count, const int timeoutStart_ms=-1, const int timeoutBetween_ms=-1)
A method for reading from the socket with an optional timeout.
std::vector< std::string > m_shutdown_cmds
void push_many(T *array_elements, size_t count)
Insert an array of elements in the buffer.
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
std::string m_last_GGA
Used in getLastGGA()
size_t Read(void *Buffer, size_t Count)
Implements the virtual method responsible for reading from the stream - Unlike CStream::ReadBuffer, this method will not raise an exception on zero bytes read, as long as there is not any fatal error in the communications.
bool m_topcon_useAIMMode
Use this mode for receive RTK corrections from a external source through the primary port...
void flushParsedMessagesNow()
Queue out now the messages in m_just_parsed_messages, leaving it empty.
void keep_max(T &var, const K test_val)
If the second argument is above the first one, set the first argument to this higher value...
void setSerialPortName(const std::string &COM_port)
Set the serial port to use (COM1, ttyUSB0, etc).
void setParser(PARSERS parser)
Select the parser for incomming data, among the options enumerated in CGPSInterface.
const std::vector< std::string > & getShutdownCommands() const
void setShutdownCommands(const std::vector< std::string > &cmds)
int _strcmpi(const char *str1, const char *str2) noexcept
An OS-independent version of strcmpi.
Definition: os.cpp:319



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019