23 #include "moos_bluefin_driver.h" 24 #include "goby/acomms/modemdriver/driver_exception.h" 25 #include "goby/acomms/protobuf/mm_driver.pb.h" 26 #include "goby/common/logger.h" 27 #include "goby/common/time.h" 29 #include "goby/moos/moos_string.h" 30 #include "goby/moos/protobuf/bluefin_driver.pb.h" 31 #include "goby/util/binary.h" 32 #include "goby/util/linebasedcomms/nmea_sentence.h" 33 #include <boost/format.hpp> 36 using goby::util::hex_decode;
37 using goby::util::hex_encode;
39 using goby::acomms::operator<<;
41 using goby::common::nmea_time2ptime;
45 : end_of_mac_window_(0), mac_(mac), last_request_id_(1 << 24)
51 glog.is(DEBUG1) &&
glog << group(glog_out_group())
52 <<
"Goby MOOS Bluefin Comms driver starting up." << std::endl;
56 modem_to_rate_to_bytes_.clear();
57 for (
int i = 0, n = driver_cfg_.ExtensionSize(protobuf::BluefinConfig::hardware_to_rate); i < n;
61 driver_cfg_.GetExtension(protobuf::BluefinConfig::hardware_to_rate, i);
62 modem_to_rate_to_bytes_[hardware_to_rate.hardware_name()][hardware_to_rate.rate()] =
63 hardware_to_rate.packet_bytes();
66 goby_to_bluefin_id_.clear();
67 for (
int i = 0, n = driver_cfg_.ExtensionSize(protobuf::BluefinConfig::modem_lookup); i < n;
71 driver_cfg_.GetExtension(protobuf::BluefinConfig::modem_lookup, i);
72 goby_to_bluefin_id_.left.insert(
73 std::make_pair(modem_lookup.goby_id(), modem_lookup.bluefin_id()));
76 const std::string& moos_server = driver_cfg_.GetExtension(protobuf::BluefinConfig::moos_server);
77 int moos_port = driver_cfg_.GetExtension(protobuf::BluefinConfig::moos_port);
78 moos_client_.Run(moos_server.c_str(), moos_port,
"goby.moos.BluefinCommsDriver");
81 while (!moos_client_.IsConnected())
83 glog.is(DEBUG1) &&
glog << group(glog_out_group()) <<
"Trying to connect to MOOSDB at " 84 << moos_server <<
":" << moos_port <<
", try " << i++ << std::endl;
87 glog.is(DEBUG1) &&
glog << group(glog_out_group()) <<
"Connected to MOOSDB." << std::endl;
89 moos_client_.Register(driver_cfg_.GetExtension(protobuf::BluefinConfig::nmea_in_moos_var), 0);
101 signal_modify_transmission(&msg);
105 case goby::acomms::protobuf::ModemTransmission::DATA:
107 if (driver_cfg_.modem_id() == msg.src())
110 if (!modem_to_rate_to_bytes_.count(current_modem_))
114 << group(glog_out_group()) <<
"Modem \"" << current_modem_
115 <<
"\" not configured for rate and bytes. Cannot initiate transmission." 120 std::map<int, int>& rate_to_bytes = modem_to_rate_to_bytes_[current_modem_];
122 if (!rate_to_bytes.count(msg.rate()))
124 glog.is(WARN) &&
glog << group(glog_out_group()) <<
"Modem \"" << current_modem_
125 <<
"\" not configured for rate: " << msg.rate()
126 <<
". Cannot initiate transmission." << std::endl;
130 msg.set_max_frame_bytes(rate_to_bytes[msg.rate()]);
133 if (msg.frame_size() == 0)
134 ModemDriverBase::signal_data_request(&msg);
137 if (msg.frame_size() && msg.frame(0).size())
141 nmea.push_back(++last_request_id_);
143 int bf_dest = goby_to_bluefin_id_.left.count(msg.dest())
144 ? goby_to_bluefin_id_.left.at(msg.dest())
146 nmea.push_back(bf_dest);
147 nmea.push_back(msg.rate());
148 nmea.push_back(static_cast<int>(msg.ack_requested()));
149 nmea.push_back(msg.frame_size());
150 for (
int i = 0; i < 8; ++i)
151 nmea.push_back(i < msg.frame_size()
152 ? boost::to_upper_copy(hex_encode(msg.frame(i)))
155 std::stringstream ss;
156 ss <<
"@PB[lamss.protobuf.FrontSeatRaw] raw: \"" << nmea.message() <<
"\"";
159 out_raw.set_raw(ss.str());
160 ModemDriverBase::signal_raw_outgoing(out_raw);
162 const std::string& out_moos_var =
163 driver_cfg_.GetExtension(protobuf::BluefinConfig::nmea_out_moos_var);
165 glog.is(DEBUG1) &&
glog << group(glog_out_group()) << out_moos_var <<
": " 166 << ss.str() << std::endl;
168 moos_client_.Notify(out_moos_var, ss.str());
169 last_data_msg_ = msg;
175 case goby::acomms::protobuf::ModemTransmission::UNKNOWN:
176 case goby::acomms::protobuf::ModemTransmission::DRIVER_SPECIFIC:
177 case goby::acomms::protobuf::ModemTransmission::ACK:
178 glog.is(DEBUG1) &&
glog << group(glog_out_group())
179 <<
"Not initiating transmission: " << msg.ShortDebugString()
180 <<
"; invalid transmission type." << std::endl;
187 if (mac_ && mac_->running() && end_of_mac_window_ < goby_time<double>())
191 if (moos_client_.Fetch(msgs))
193 for (MOOSMSG_LIST::iterator it = msgs.begin(), end = msgs.end(); it != end; ++it)
195 const std::string& in_moos_var =
196 driver_cfg_.GetExtension(protobuf::BluefinConfig::nmea_in_moos_var);
197 const std::string& s_val = it->GetString();
199 const std::string raw =
"raw: \"";
200 const std::string::size_type raw_pos = s_val.find(raw);
201 if (raw_pos == std::string::npos)
204 const std::string::size_type end_pos = s_val.find(
"\"", raw_pos + raw.size());
205 if (end_pos == std::string::npos)
209 s_val.substr(raw_pos + raw.size(), end_pos - (raw_pos + raw.size()));
211 if (it->GetKey() == in_moos_var &&
212 (value.substr(0, 5) ==
"$BFCP" || value.substr(0, 6) ==
"$BFCMA"))
215 in_raw.set_raw(s_val);
216 ModemDriverBase::signal_raw_incoming(in_raw);
219 glog.is(DEBUG1) &&
glog << group(glog_in_group()) << in_moos_var <<
": " 220 << s_val << std::endl;
222 if (nmea.sentence_id() ==
"CMA")
224 else if (nmea.sentence_id() ==
"CPS")
226 else if (nmea.sentence_id() ==
"CPR")
229 catch (std::exception& e)
231 glog.is(DEBUG1) &&
glog << warn <<
"Failed to handle message: " << e.what()
239 std::string goby::moos::BluefinCommsDriver::unix_time2nmea_time(
double time)
245 boost::format f(
"%02d%02d%02d.%03d");
246 f % ptime.time_of_day().hours() % ptime.time_of_day().minutes() %
247 ptime.time_of_day().seconds() %
248 (ptime.time_of_day().fractional_seconds() * 1000 /
249 boost::posix_time::time_duration::ticks_per_second());
259 END_OF_TIME_WINDOW = 2,
263 end_of_mac_window_ = goby::util::as<double>(nmea_time2ptime(nmea.at(END_OF_TIME_WINDOW)));
264 current_modem_ = nmea.at(DEVICE_TYPE);
274 ACOUSTIC_MESSAGE_TIMESTAMP = 2,
276 NUMBER_OF_FRAMES = 4,
287 if (nmea.as<
int>(REQUEST_ID) == last_request_id_)
291 msg.set_src(last_data_msg_.dest());
292 msg.set_dest(last_data_msg_.src());
293 msg.set_type(goby::acomms::protobuf::ModemTransmission::ACK);
295 for (
int i = 0, n = nmea.as<
int>(NUMBER_OF_FRAMES); i < n; ++i)
297 if (nmea.as<
int>(FRAME_0_STATUS + i) == 2)
298 msg.add_acked_frame(i);
301 ModemDriverBase::signal_receive(msg);
306 glog << group(glog_in_group()) << warn
307 <<
"Received CPS for message ID that was not the last request sent, ignoring..." 321 NUMBER_OF_FRAMES = 6,
341 msg.set_time(goby::util::as<uint64>(nmea_time2ptime(nmea.at(ARRIVAL_TIME))));
342 msg.set_time_source(goby::acomms::protobuf::ModemTransmission::MODEM_TIME);
344 int goby_src = goby_to_bluefin_id_.right.count(nmea.as<
int>(SOURCE))
345 ? goby_to_bluefin_id_.right.at(nmea.as<
int>(SOURCE))
347 msg.set_src(goby_src);
349 int goby_dest = goby_to_bluefin_id_.right.count(nmea.as<
int>(DESTINATION))
350 ? goby_to_bluefin_id_.right.at(nmea.as<
int>(DESTINATION))
353 msg.set_dest(goby_dest);
354 msg.set_type(goby::acomms::protobuf::ModemTransmission::DATA);
355 for (
int i = 0, n = nmea.as<
int>(NUMBER_OF_FRAMES); i < n; ++i)
357 if (nmea.as<
int>(FRAME_0_STATUS + 2 * i) == 1)
358 msg.add_frame(hex_decode(nmea.at(FRAME_0_HEX + 2 * i)));
361 glog.is(DEBUG1) &&
glog << group(glog_in_group())
362 <<
"Received BFCPR incoming data message: " << msg.DebugString()
365 ModemDriverBase::signal_receive(msg);
uint64 goby_time< uint64 >()
Returns current UTC time as integer microseconds since 1970-01-01 00:00:00.
Helpers for MOOS applications for serializing and parsed Google Protocol buffers messages.
double goby_time< double >()
Returns current UTC time as seconds and fractional seconds since 1970-01-01 00:00:00.
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime.
void handle_initiate_transmission(const goby::acomms::protobuf::ModemTransmission &m)
Virtual initiate_transmission method. Typically connected to MACManager::signal_initiate_transmission...
provides an API to the goby-acomms MAC library. MACManager is essentially a std::list<protobuf::Modem...
void shutdown()
Shutdown the MAC.
common::FlexOstream glog
Access the Goby logger through this object.
void do_work()
Allows the modem driver to do its work.
void restart()
Restarts the MAC with original configuration.
void shutdown()
Shuts down the modem driver.
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...
void startup(const goby::acomms::protobuf::DriverConfig &cfg)
Starts the modem driver. Must be called before poll().