Goby v2
bluefin.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Goby Underwater Autonomy Project Libraries
8 // ("The Goby Libraries").
9 //
10 // The Goby Libraries are free software: you can redistribute them and/or modify
11 // them under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // The Goby Libraries are distributed in the hope that they will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include <boost/algorithm/string/replace.hpp>
24 #include <boost/assign.hpp>
25 #include <boost/format.hpp>
26 #include <boost/math/special_functions/fpclassify.hpp> // for isnan
27 
28 #include "goby/common/logger.h"
29 #include "goby/util/as.h"
30 
31 #include "dccl/binary.h"
32 
33 #include "bluefin.h"
34 
35 namespace gpb = goby::moos::protobuf;
36 using goby::glog;
39 using namespace goby::common::logger;
40 using namespace goby::common::tcolor;
41 
42 extern "C"
43 {
44  FrontSeatInterfaceBase* frontseat_driver_load(iFrontSeatConfig* cfg)
45  {
46  return new BluefinFrontSeat(*cfg);
47  }
48 }
49 
50 BluefinFrontSeat::BluefinFrontSeat(const iFrontSeatConfig& cfg)
51  : FrontSeatInterfaceBase(cfg), bf_config_(cfg.GetExtension(bluefin_config)),
52  tcp_(bf_config_.huxley_tcp_address(), bf_config_.huxley_tcp_port(), "\r\n",
53  bf_config_.reconnect_interval()),
54  frontseat_providing_data_(false), last_frontseat_data_time_(0),
55  frontseat_state_(gpb::FRONTSEAT_NOT_CONNECTED), next_connect_attempt_time_(0),
56  last_write_time_(0), waiting_for_huxley_(false), nmea_demerits_(0),
57  nmea_present_fail_count_(0), last_heartbeat_time_(0)
58 {
59  load_nmea_mappings();
60  glog.is(VERBOSE) && glog << "Trying to connect to Huxley server @ "
61  << bf_config_.huxley_tcp_address() << ":"
62  << bf_config_.huxley_tcp_port() << std::endl;
63  tcp_.start();
64 }
65 
66 void BluefinFrontSeat::loop()
67 {
68  double now = goby_time<double>();
69 
70  // check the connection state
71  if (!tcp_.active())
72  {
73  frontseat_state_ = gpb::FRONTSEAT_NOT_CONNECTED;
74  }
75  else
76  {
77  if (frontseat_state_ == gpb::FRONTSEAT_NOT_CONNECTED)
78  {
79  glog.is(VERBOSE) && glog << "Connected to Huxley." << std::endl;
80  frontseat_state_ = gpb::FRONTSEAT_IDLE;
81  initialize_huxley();
82  }
83 
84  check_send_heartbeat();
85  try_send();
86  try_receive();
87  }
88 
89  if (now > last_frontseat_data_time_ + bf_config_.allow_missing_nav_interval())
90  frontseat_providing_data_ = false;
91 }
92 
93 void BluefinFrontSeat::send_command_to_frontseat(const gpb::CommandRequest& command)
94 {
95  if (command.has_cancel_request_id())
96  {
97  for (std::map<goby::moos::protobuf::BluefinExtraCommands::BluefinCommand,
99  it = outstanding_requests_.begin(),
100  end = outstanding_requests_.end();
101  it != end; ++it)
102  {
103  if (it->second.request_id() == command.cancel_request_id())
104  {
105  glog.is(DEBUG1) && glog << "Cancelled request: " << it->second.ShortDebugString()
106  << std::endl;
107  outstanding_requests_.erase(it);
108  return;
109  }
110  }
111  glog.is(DEBUG1) && glog << warn
112  << "Failed to cancel request: " << command.cancel_request_id()
113  << ", could not find such a request." << std::endl;
114  return;
115  }
116 
117  gpb::BluefinExtraCommands::BluefinCommand type = gpb::BluefinExtraCommands::UNKNOWN_COMMAND;
118 
119  // extra commands
120  if (command.HasExtension(gpb::bluefin_command))
121  {
122  const gpb::BluefinExtraCommands& bluefin_command =
123  command.GetExtension(gpb::bluefin_command);
124  type = bluefin_command.command();
125  switch (type)
126  {
127  case gpb::BluefinExtraCommands::UNKNOWN_COMMAND:
128  case gpb::BluefinExtraCommands::DESIRED_COURSE: break;
129 
130  case gpb::BluefinExtraCommands::TRIM_ADJUST:
131  {
132  glog.is(DEBUG1) &&
133  glog << "Bluefin Extra Command: Trim adjust requested by backseat."
134  << std::endl;
135  NMEASentence nmea("$BPTRM", NMEASentence::IGNORE);
136  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
137  append_to_write_queue(nmea);
138  }
139  break;
140 
141  case gpb::BluefinExtraCommands::BUOYANCY_ADJUST:
142  {
143  glog.is(DEBUG1) &&
144  glog << "Bluefin Extra Command: Buoyancy adjustment requested by backseat."
145  << std::endl;
146  NMEASentence nmea("$BPBOY", NMEASentence::IGNORE);
147  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
148  append_to_write_queue(nmea);
149  }
150  break;
151 
152  case gpb::BluefinExtraCommands::SILENT_MODE:
153  {
154  glog.is(DEBUG1) && glog << "Bluefin Extra Command: Silent mode change requested by "
155  "backseat to mode: "
156  << gpb::BluefinExtraCommands::SilentMode_Name(
157  bluefin_command.silent_mode())
158  << std::endl;
159  NMEASentence nmea("$BPSIL", NMEASentence::IGNORE);
160  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
161  nmea.push_back(static_cast<int>(bluefin_command.silent_mode()));
162  append_to_write_queue(nmea);
163  }
164  break;
165 
166  case gpb::BluefinExtraCommands::CANCEL_CURRENT_BEHAVIOR:
167  {
168  glog.is(DEBUG1) &&
169  glog << "Bluefin Extra Command: Cancel current behavior requested by backseat."
170  << std::endl;
171  NMEASentence nmea("$BPRCE", NMEASentence::IGNORE);
172  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
173  nmea.push_back(0);
174  append_to_write_queue(nmea);
175  }
176  break;
177 
178  case gpb::BluefinExtraCommands::ABORT_MISSION:
179  {
180  glog.is(DEBUG1) &&
181  glog << "Bluefin Extra Command: Abort mission requested by backseat; reason: "
182  << gpb::BluefinExtraCommands::AbortReason_Name(
183  bluefin_command.abort_reason())
184  << std::endl;
185  NMEASentence nmea("$BPABT", NMEASentence::IGNORE);
186  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
187  nmea.push_back("backseat abort");
188  nmea.push_back(static_cast<int>(bluefin_command.abort_reason()));
189  append_to_write_queue(nmea);
190  }
191  break;
192 
193  case gpb::BluefinExtraCommands::MISSION_START_CONFIRM:
194  {
195  glog.is(DEBUG1) &&
196  glog << "Bluefin Extra Command: Mission start confirmation by backseat "
197  << std::endl;
198  NMEASentence nmea("$BPSMC", NMEASentence::IGNORE);
199  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
200  nmea.push_back(1); //static_cast<int>(bluefin_command.start_confirm())
201  append_to_write_queue(nmea);
202  }
203  break;
204 
205  case gpb::BluefinExtraCommands::MISSION_END_CONFIRM:
206  {
207  glog.is(DEBUG1) &&
208  glog << "Bluefin Extra Command: Mission end confirmation by backseat "
209  << std::endl;
210  NMEASentence nmea("$BPRCE", NMEASentence::IGNORE);
211  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
212  nmea.push_back(0);
213  append_to_write_queue(nmea);
214  }
215  break;
216  }
217  }
218 
219  if (command.has_desired_course())
220  {
221  if (type != gpb::BluefinExtraCommands::UNKNOWN_COMMAND &&
222  type != gpb::BluefinExtraCommands::DESIRED_COURSE)
223  {
224  glog.is(WARN) && glog << "Ignoring desired course information in this message, as an "
225  "extra command was set. Only one command allowed per message."
226  << std::endl;
227  }
228  else if (static_cast<int>(command.desired_course().depth()) == 0 &&
229  static_cast<int>(command.desired_course().speed()) == 0)
230  {
231  type = gpb::BluefinExtraCommands::DESIRED_COURSE;
232  NMEASentence nmea("$BPRMB", NMEASentence::IGNORE);
233  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
234  nmea.push_back(0); // zero rudder
235  nmea.push_back(0); // zero pitch
236  nmea.push_back(2); // previous field is a pitch [2]
237  nmea.push_back(0); // zero rpm
238  nmea.push_back(0); // previous field is an rpm [0]
239  nmea.push_back(1); // first field is a rudder adjustment [1]
240  append_to_write_queue(nmea);
241  }
242  else
243  {
244  type = gpb::BluefinExtraCommands::DESIRED_COURSE;
245  NMEASentence nmea("$BPRMB", NMEASentence::IGNORE);
246  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
247  const goby::moos::protobuf::DesiredCourse& desired_course = command.desired_course();
248 
249  // for zero speed, send zero RPM, pitch, rudder
250  if (desired_course.speed() < 0.01)
251  {
252  nmea.push_back(0); // zero rudder
253  nmea.push_back(0); // zero pitch
254  nmea.push_back(2); // previous field is a pitch [2]
255  nmea.push_back(0); // zero rpm
256  nmea.push_back(0); // previous field is an rpm [0]
257  nmea.push_back(1); // first field is a rudder adjustment [1]
258  }
259  else
260  {
261  nmea.push_back(desired_course.heading());
262  nmea.push_back(desired_course.depth());
263  nmea.push_back(0); // previous field is a depth (not altitude [1] or pitch [2])
264  nmea.push_back(desired_course.speed());
265  nmea.push_back(1); // previous field is a speed (not rpm [0])
266  nmea.push_back(0); // first field is a heading (not rudder adjustment [1])
267  }
268 
269  append_to_write_queue(nmea);
270  }
271  }
272 
273  if (!bf_config_.disable_ack() && command.response_requested())
274  {
275  if (outstanding_requests_.count(type))
276  {
277  glog.is(WARN) && glog << "Request already outstanding for type: "
278  << gpb::BluefinExtraCommands::BluefinCommand_Name(type)
279  << ", overwriting old request." << std::endl;
280  }
281 
282  outstanding_requests_[type] = command;
283  }
284 }
285 
286 void BluefinFrontSeat::send_data_to_frontseat(const gpb::FrontSeatInterfaceData& data)
287 {
288  // glog.is(DEBUG1) && glog << "Data to FS: " << data.DebugString() << std::endl;
289 
290  // we need to send our CTD to Bluefin when we have it attached to our payload
291  if (data.has_ctd_sample())
292  {
293  NMEASentence nmea("$BPCTD", NMEASentence::IGNORE);
294  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
295 
296  // BF wants Siemens / meter, same as CTDSample
297  if (data.ctd_sample().has_conductivity())
298  nmea.push_back(goby::util::as<std::string>(data.ctd_sample().conductivity(), 10));
299  else
300  nmea.push_back("");
301 
302  // degrees C
303  if (!(boost::math::isnan)(data.ctd_sample().temperature()))
304  nmea.push_back(goby::util::as<std::string>(data.ctd_sample().temperature(), 10));
305  else
306  nmea.push_back("");
307 
308  // BF wants kPA; CTD sample uses Pascals
309  if (!(boost::math::isnan)(data.ctd_sample().pressure()))
310  nmea.push_back(goby::util::as<std::string>(data.ctd_sample().pressure() / 1.0e3, 10));
311  else
312  nmea.push_back("");
313 
314  nmea.push_back(unix_time2nmea_time(data.ctd_sample().time()));
315 
316  append_to_write_queue(nmea);
317  }
318 
319  if (data.has_dccl_message())
320  {
321  NMEASentence nmea("$BPDCL", NMEASentence::IGNORE);
322  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
323  nmea.push_back(boost::trim_copy(dccl::b64_encode(data.dccl_message())));
324  append_to_write_queue(nmea);
325  }
326 
327  if (data.HasExtension(gpb::bluefin_data))
328  {
329  const gpb::BluefinExtraData& bf_extra = data.GetExtension(gpb::bluefin_data);
330  // Bluefin wants our MicroModem feed so they can feel warm and fuzzy ... ?
331  if (bf_extra.has_micro_modem_raw_in() && bf_config_.send_tmr_messages())
332  {
333  NMEASentence nmea("$BPTMR", NMEASentence::IGNORE);
334  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
335  const int TRANSPORT_ACOUSTIC_MODEM = 3;
336  nmea.push_back(TRANSPORT_ACOUSTIC_MODEM);
337 
338  std::string modem_nmea = bf_extra.micro_modem_raw_in().raw();
339  boost::replace_all(modem_nmea, ",", ":");
340  boost::replace_all(modem_nmea, "*", "/");
341  boost::replace_all(modem_nmea, "\r", " ");
342  nmea.push_back(modem_nmea);
343  append_to_write_queue(nmea);
344  }
345 
346  for (int i = 0, n = bf_extra.payload_status_size(); i < n; ++i)
347  payload_status_.insert(std::make_pair(bf_extra.payload_status(i).expire_time(),
348  bf_extra.payload_status(i)));
349  }
350 }
351 
352 void BluefinFrontSeat::send_raw_to_frontseat(const gpb::FrontSeatRaw& data)
353 {
354  try
355  {
356  NMEASentence nmea(data.raw(), NMEASentence::IGNORE);
357  append_to_write_queue(nmea);
358  }
360  {
361  glog.is(DEBUG1) && glog << warn << "Refusing to send this invalid message: " << data.raw()
362  << ", " << e.what() << std::endl;
363  }
364 }
365 
366 void BluefinFrontSeat::check_send_heartbeat()
367 {
368  double now = goby_time<double>();
369  if (now > last_heartbeat_time_ + bf_config_.heartbeat_interval())
370  {
371  NMEASentence nmea("$BPSTS", NMEASentence::IGNORE);
372 
373  nmea.push_back(unix_time2nmea_time(goby_time<double>()));
374  const int FAILED = 0, ALL_OK = 1;
375  bool ok = state() != gpb::INTERFACE_HELM_ERROR && state() != gpb::INTERFACE_FS_ERROR;
376 
377  std::string status;
378  if (payload_status_.size())
379  {
380  std::map<int, std::string> seen_ids;
382  payload_status_.erase(
383  payload_status_.begin(),
384  payload_status_.upper_bound(goby::common::goby_time<goby::uint64>()));
385 
386  for (std::multimap<
387  goby::uint64,
389  it = payload_status_.begin(),
390  end = payload_status_.end();
391  it != end; ++it)
392  {
393  // only display the newest from a given ID
394  if (!seen_ids.count(it->second.id()))
395  {
396  ok = ok && it->second.all_ok();
397  seen_ids[it->second.id()] = it->second.msg();
398  }
399  }
400 
401  for (std::map<int, std::string>::const_iterator it = seen_ids.begin(),
402  end = seen_ids.end();
403  it != end; ++it)
404  {
405  status += "; ";
406  status += it->second;
407  }
408  }
409 
410  if (status.empty())
411  status = "Deploy";
412 
413  nmea.push_back(ok ? ALL_OK : FAILED);
414  nmea.push_back(status);
415  append_to_write_queue(nmea);
416 
417  last_heartbeat_time_ = now + bf_config_.heartbeat_interval();
418  }
419 }
420 
421 void BluefinFrontSeat::try_receive()
422 {
423  std::string in;
424  while (tcp_.readline(&in))
425  {
426  boost::trim(in);
427  // try to handle the received message, posting appropriate signals
428  try
429  {
430  NMEASentence nmea(in, NMEASentence::VALIDATE);
431  process_receive(nmea);
432  }
433  catch (std::exception& e)
434  {
435  glog.is(DEBUG1) && glog << warn << "Failed to handle message: " << e.what()
436  << std::endl;
437  }
438  }
439 }
440 
441 void BluefinFrontSeat::initialize_huxley()
442 {
443  nmea_demerits_ = 0;
444  waiting_for_huxley_ = false;
445  out_.clear();
446  pending_.clear();
447 
448  using boost::assign::operator+=;
449  std::vector<SentenceIDs> log_requests;
450  if (!bf_config_.disable_ack())
451  log_requests += ACK; // must request ACK first so we get NMEA ACKs for the other messages
452  log_requests += NVG, MIS, MSC, NVR, SVS, RVL, SHT, TOP, MBS, MBE, CTD, DVL, BOY, TRM;
453 
454  if (bf_config_.accepting_commands_hook() == BluefinFrontSeatConfig::BFCTL_TRIGGER)
455  log_requests += CTL;
456 
457  NMEASentence nmea("$BPLOG", NMEASentence::IGNORE);
458  nmea.push_back("");
459  nmea.push_back("ON");
460  for (std::vector<SentenceIDs>::const_iterator it = log_requests.begin(),
461  end = log_requests.end();
462  it != end; ++it)
463  {
464  nmea[1] = sentence_id_map_.right.at(*it);
465  append_to_write_queue(nmea);
466  }
467 
468  for (int i = 0, n = bf_config_.extra_bplog_size(); i < n; ++i)
469  {
470  nmea[1] = boost::to_upper_copy(bf_config_.extra_bplog(i));
471  append_to_write_queue(nmea);
472  }
473 }
474 
475 void BluefinFrontSeat::append_to_write_queue(const NMEASentence& nmea)
476 {
477  out_.push_back(nmea);
478  try_send(); // try to push it now without waiting for the next call to do_work();
479 }
480 
481 void BluefinFrontSeat::try_send()
482 {
483  if (out_.empty())
484  return;
485 
486  const NMEASentence& nmea = out_.front();
487 
488  bool resend = waiting_for_huxley_ &&
489  (last_write_time_ <= (goby_time<double>() - bf_config_.nmea_resend_interval()));
490 
491  if (!waiting_for_huxley_)
492  {
493  write(nmea);
494  }
495  else if (resend)
496  {
497  glog.is(DEBUG1) && glog << "resending last command; no NMEA ack in "
498  << bf_config_.nmea_resend_interval() << " second(s). " << std::endl;
499 
500  try
501  {
502  // try to increment the present (current NMEA sentence) fail counter
503  // will throw if fail counter exceeds nmea_resend_attempts
504  ++nmea_present_fail_count_;
505  if (nmea_present_fail_count_ >= bf_config_.nmea_resend_attempts())
506  throw(FrontSeatException(gpb::ERROR_FRONTSEAT_IGNORING_COMMANDS));
507  // assuming we're still ok, write the line again
508  write(nmea);
509  }
510  catch (FrontSeatException& e)
511  {
512  glog.is(DEBUG1) && glog << "Huxley did not respond to our command even after "
513  << bf_config_.nmea_resend_attempts()
514  << " retries. continuing onwards anyway..." << std::endl;
515  remove_from_write_queue();
516 
517  ++nmea_demerits_;
518  if (nmea_demerits_ > bf_config_.allowed_nmea_demerits())
519  {
520  glog.is(WARN) &&
521  glog << "Huxley server is connected but appears to not be responding."
522  << std::endl;
523  // force a disconnect
524  frontseat_state_ = gpb::FRONTSEAT_NOT_CONNECTED;
525  throw;
526  }
527  }
528  }
529 }
530 
531 void BluefinFrontSeat::remove_from_write_queue()
532 {
533  waiting_for_huxley_ = false;
534 
535  if (!out_.empty())
536  out_.pop_front();
537  else
538  {
539  glog.is(DEBUG1) && glog << "Expected to pop outgoing NMEA message but out_ deque is empty"
540  << std::endl;
541  }
542 
543  nmea_present_fail_count_ = 0;
544 }
545 
546 void BluefinFrontSeat::write(const NMEASentence& nmea)
547 {
548  gpb::FrontSeatRaw raw_msg;
549  raw_msg.set_raw(nmea.message());
550  raw_msg.set_description(description_map_[nmea.front()]);
551 
552  signal_raw_to_frontseat(raw_msg);
553 
554  tcp_.write(nmea.message_cr_nl());
555 
556  if (bf_config_.disable_ack())
557  {
558  remove_from_write_queue();
559  }
560  else
561  {
562  waiting_for_huxley_ = true;
563  last_write_time_ = goby_time<double>();
564  }
565 }
566 
567 void BluefinFrontSeat::process_receive(const NMEASentence& nmea)
568 {
569  gpb::FrontSeatRaw raw_msg;
570  raw_msg.set_raw(nmea.message());
571  raw_msg.set_description(description_map_[nmea.front()]);
572 
573  signal_raw_from_frontseat(raw_msg);
574 
575  nmea_demerits_ = 0;
576 
577  // look at the sentence id (last three characters of the NMEA 0183 talker)
578  switch (sentence_id_map_.left.at(nmea.sentence_id()))
579  {
580  case ACK: bfack(nmea); break; // nmea ack
581 
582  case NVG: bfnvg(nmea); break; // navigation
583  case NVR: bfnvr(nmea); break; // velocity and rate
584  case RVL: bfrvl(nmea); break; // raw vehicle speed
585 
586  case DVL: bfdvl(nmea); break; // raw DVL data
587  case CTD: bfctd(nmea); break; // raw CTD sensor data
588  case SVS: bfsvs(nmea); break; // sound velocity
589 
590  case MSC: bfmsc(nmea); break; // payload mission command
591  case SHT: bfsht(nmea); break; // payload shutdown
592 
593  case MBS: bfmbs(nmea); break; // begin new behavior
594  case MIS: bfmis(nmea); break; // mission status
595  case MBE: bfmbe(nmea); break; // end behavior
596 
597  case CTL: bfctl(nmea); break; // backseat control message (SPI 1.10+)
598 
599  case BOY: bfboy(nmea); break; // buoyancy status
600  case TRM: bftrm(nmea); break; // trim status
601 
602  case TOP: bftop(nmea); break; // request to send data topside
603  default: break;
604  }
605 }
606 
607 std::string BluefinFrontSeat::unix_time2nmea_time(double time)
608 {
609  boost::posix_time::ptime ptime = goby::common::unix_double2ptime(time);
610 
611  // HHMMSS.SSS
612  // it appears that exactly three digits of precision is important (sometimes)
613  boost::format f("%02d%02d%02d.%03d");
614  f % ptime.time_of_day().hours() % ptime.time_of_day().minutes() %
615  ptime.time_of_day().seconds() %
616  (ptime.time_of_day().fractional_seconds() * 1000 /
617  boost::posix_time::time_duration::ticks_per_second());
618 
619  return f.str();
620 }
621 
622 void BluefinFrontSeat::load_nmea_mappings()
623 {
624  boost::assign::insert(sentence_id_map_)("MSC", MSC)("SHT", SHT)("BDL", BDL)("SDL", SDL)(
625  "TOP", TOP)("DVT", DVT)("VER", VER)("NVG", NVG)("SVS", SVS)("RCM", RCM)("RDP", RDP)(
626  "RVL", RVL)("RBS", RBS)("MBS", MBS)("MBE", MBE)("MIS", MIS)("ERC", ERC)("DVL", DVL)(
627  "DV2", DV2)("IMU", IMU)("CTD", CTD)("RNV", RNV)("PIT", PIT)("CNV", CNV)("PLN", PLN)(
628  "ACK", ACK)("TRM", TRM)("LOG", LOG)("STS", STS)("DVR", DVR)("CPS", CPS)("CPR", CPR)(
629  "TRK", TRK)("RTC", RTC)("RGP", RGP)("RCN", RCN)("RCA", RCA)("RCB", RCB)("RMB", RMB)(
630  "EMB", EMB)("TMR", TMR)("ABT", ABT)("KIL", KIL)("MSG", MSG)("RMP", RMP)("SEM", SEM)(
631  "NPU", NPU)("CPD", CPD)("SIL", SIL)("BOY", BOY)("SUS", SUS)("CON", CON)("RES", RES)(
632  "SPD", SPD)("SAN", SAN)("GHP", GHP)("GBP", GBP)("RNS", RNS)("RBO", RBO)("CMA", CMA)(
633  "NVR", NVR)("TEL", TEL)("CTL", CTL)("DCL", DCL);
634 
635  boost::assign::insert(talker_id_map_)("BF", BF)("BP", BP);
636 
637  boost::assign::insert(description_map_)("$BFMSC", "Payload Mission Command")(
638  "$BFSHT", "Payload Shutdown")("$BFBDL", "Begin Data Logging")
639 
640  ("$BFSDL", "Stop Data Logging")("$BFTOP", "Topside Message (Not Implemented) ")(
641  "$BFDVT", "Begin/End DVL External Triggering")("$BFVER", "Vehicle Interface Version")(
642  "$BFNVG", "Navigation Update")("$BFNVR", "Velocity and Rate Update")(
643  "$BFTEL", "Telemetry Status (Not Implemented)")("$BFSVS", "Sound Velocity")(
644  "$BFRCM", "Raw Compass Data")("$BFRDP", "Raw Depth Sensor Data")("$BFRVL",
645  "Raw Vehicle Speed")(
646  "$BFRBS", "Battery Voltage")("$BFMBS", "Begin New Behavior")("$BFMBE", "End Behavior")(
647  "$BFMIS", "Mission Status")("$BFERC", "Elevator and Rudder Data")(
648  "$BFDVL", "Raw DVL Data")("$BFDV2", "Raw DVL Data, Extended")("$BFIMU", "Raw IMU Data")(
649  "$BFCTD", "Raw CTD Sensor Data")("$BFRNV", "Relative Navigation Position")(
650  "$BFPIT", "Pitch Servo Positions")("$BFCNV", "Cartesian Relative Navigation Position")(
651  "$BFPLN", "Mission Plan Element")("$BFACK", "Message Acknowledgement")(
652  "$BFTRM", "Trim Status")("$BPSMC", "Confirm Mission Start")(
653  "$BFBOY", "Buoyancy Status")("$BPLOG", "Logging Control")(
654  "$BPSTS", "Payload Status Message")("$BPTOP", "Request to Send Data Topside")(
655  "$BPDVR", "Request to Change DVL Triggering Method")("$BPTRK",
656  "Request Additional Trackline")(
657  "$BPRTC", "Request Additional Trackcircle")("$BPRGP", "Request Additional GPS Hits")(
658  "$BPRCN", "Cancel Requested Behavior")("$BPRCE", "Cancel Current Mission Element")(
659  "$BPRCA", "Cancel All Requested Behaviors")("$BPRCB", "Cancel Current Behavior")(
660  "$BPRMB", "Modify Current Behavior")("$BPEMB", "End Behavior Modify")(
661  "$BPTMR", "Topside Message Relay (Not Available on Most Vehicles)")(
662  "$BPCTD", "Raw CTD Sensor Data")("$BPABT", "Abort Mission")("$BPKIL", "Kill Mission")(
663  "$BPMSG", "Log Message")("$BPRMP", "Request Mission Plan")(
664  "$BPSEM", "Start Empty Mission (Not Implemented)")("$BPNPU",
665  "Navigation Position Update")(
666  "$BPSIL", "Silent Mode")("$BPTRM", "Request Trim Adjustment Behavior")(
667  "$BPBOY", "Request Buoyancy Adjustment Behavior")("$BPVER",
668  "Payload Interface Version")(
669  "$BPSUS", "Suspend Mission")("$BPCON", "Continue")("$BPRES", "Resume Mission")(
670  "$BPSPD", "Hull Relative Speed Limit")("$BPSAN", "Set Sonar Angle")(
671  "$BPGHP", "Go To Hull Position")("$BPGBP", "Go to Bottom Position")(
672  "$BPRNS", "Reset Relative Navigation")("$BPRBO", "Hull Relative Bearing Offset")(
673  "$BFCMA", "Communications Medium Access")("$BFCPS", "Communications Packet Sent")(
674  "$BFCPR", "Communications Packet Received Data")("$BPCPD",
675  "Communications Packet Data")(
676  "$BFCTL", "Backseat Control")("$BPDCL", "Forward DCCL message to Huxley from Payload");
677 }
Contains functions for adding color to Terminal window streams.
Definition: term_color.h:54
std::string goby_time_as_string(const boost::posix_time::ptime &t=goby_time())
Simple string representation of goby_time()
Definition: time.h:150
double goby_time< double >()
Returns current UTC time as seconds and fractional seconds since 1970-01-01 00:00:00.
Definition: time.h:130
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime.
Definition: time.h:104
common::FlexOstream glog
Access the Goby logger through this object.
google::protobuf::uint64 uint64
an unsigned 64 bit integer
boost::posix_time::ptime unix_double2ptime(double given_time)
convert to boost date_time ptime from the number of seconds (including fractional) since 1/1/1970 0:0...
Definition: time.cpp:47