Goby v2
moos_ufield_sim_driver.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 "moos_ufield_sim_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/moos/modem_id_convert.h"
28 #include "goby/moos/moos_string.h"
29 #include "goby/moos/protobuf/ufield_sim_driver.pb.h"
30 #include "goby/util/binary.h"
31 
32 using goby::glog;
33 using goby::util::hex_decode;
34 using goby::util::hex_encode;
35 using namespace goby::common::logger;
36 using goby::acomms::operator<<;
37 
38 goby::moos::UFldDriver::UFldDriver() : last_ccmpc_dest_(-1) {}
39 
41 {
42  glog.is(DEBUG1) && glog << group(glog_out_group())
43  << "Goby MOOS uField Toolbox driver starting up." << std::endl;
44 
45  driver_cfg_ = cfg;
46 
47  goby::glog.is(goby::common::logger::DEBUG1) &&
48  goby::glog << modem_lookup_.read_lookup_file(
49  driver_cfg_.GetExtension(protobuf::Config::modem_id_lookup_path))
50  << std::flush;
51 
52  // for(int i = 0, n = driver_cfg_.ExtensionSize(protobuf::Config::id_entry);
53  // i < n; ++ i)
54  // {
55  // const protobuf::ModemIdEntry& entry =
56  // driver_cfg_.GetExtension(protobuf::Config::id_entry, i);
57 
58  // modem_id2name_.left.insert(std::make_pair(entry.modem_id(), entry.name()));
59  // }
60 
61  const std::string& moos_server = driver_cfg_.GetExtension(protobuf::Config::moos_server);
62  int moos_port = driver_cfg_.GetExtension(protobuf::Config::moos_port);
63  moos_client_.Run(moos_server.c_str(), moos_port, "goby.moos.UFldDriver");
64 
65  int i = 0;
66  while (!moos_client_.IsConnected())
67  {
68  glog.is(DEBUG1) && glog << group(glog_out_group()) << "Trying to connect to MOOSDB at "
69  << moos_server << ":" << moos_port << ", try " << i++ << std::endl;
70  sleep(1);
71  }
72  glog.is(DEBUG1) && glog << group(glog_out_group()) << "Connected to MOOSDB." << std::endl;
73 
74  moos_client_.Register(driver_cfg_.GetExtension(protobuf::Config::incoming_moos_var), 0);
75  moos_client_.Register(
76  driver_cfg_.GetExtension(protobuf::Config::micromodem_mimic).range_report_var(), 0);
77 }
78 
79 void goby::moos::UFldDriver::shutdown() { moos_client_.Close(); }
80 
83 {
84  // copy so we can modify
86 
87  // allows zero to N third parties modify the transmission before sending.
89 
90  switch (msg.type())
91  {
92  case goby::acomms::protobuf::ModemTransmission::DATA:
93  {
94  if (driver_cfg_.modem_id() == msg.src())
95  {
96  // this is our transmission
97 
98  if (msg.rate() < driver_cfg_.ExtensionSize(protobuf::Config::rate_to_bytes))
99  msg.set_max_frame_bytes(
100  driver_cfg_.GetExtension(protobuf::Config::rate_to_bytes, msg.rate()));
101  else
102  msg.set_max_frame_bytes(DEFAULT_PACKET_SIZE);
103 
104  // no data given to us, let's ask for some
105  if (msg.frame_size() == 0)
106  ModemDriverBase::signal_data_request(&msg);
107 
108  // don't send an empty message
109  if (msg.frame_size() && msg.frame(0).size())
110  {
111  send_message(msg);
112  }
113  }
114  else
115  {
116  // send thirdparty "poll"
117  msg.SetExtension(goby::moos::protobuf::poll_src, msg.src());
118  msg.SetExtension(goby::moos::protobuf::poll_dest, msg.dest());
119 
120  msg.set_dest(msg.src());
121  msg.set_src(driver_cfg_.modem_id());
122 
123  msg.set_type(goby::acomms::protobuf::ModemTransmission::DRIVER_SPECIFIC);
124  msg.SetExtension(goby::moos::protobuf::type,
125  goby::moos::protobuf::UFIELD_DRIVER_POLL);
126 
127  send_message(msg);
128  }
129  }
130  break;
131 
132  case goby::acomms::protobuf::ModemTransmission::DRIVER_SPECIFIC:
133  {
134  if (msg.HasExtension(micromodem::protobuf::type))
135  {
136  switch (msg.GetExtension(micromodem::protobuf::type))
137  {
138  case micromodem::protobuf::MICROMODEM_TWO_WAY_PING: ccmpc(msg); break;
139  default:
140  glog.is(DEBUG1) &&
141  glog << group(glog_out_group()) << warn
142  << "Not initiating transmission because we were given a "
143  "DRIVER_SPECIFIC transmission type for the Micro-Modem that "
144  "isn't supported by the uFld simulator driver"
145  << msg.ShortDebugString() << std::endl;
146  break;
147  }
148  }
149  else
150  {
151  glog.is(DEBUG1) && glog << group(glog_out_group()) << warn
152  << "Not initiating transmission because we were given a "
153  "missing or unrecognized DRIVER_SPECIFIC type: "
154  << msg.ShortDebugString() << std::endl;
155  }
156  }
157  break;
158 
159  case goby::acomms::protobuf::ModemTransmission::UNKNOWN:
160  case goby::acomms::protobuf::ModemTransmission::ACK: break;
161  }
162 }
163 
164 void goby::moos::UFldDriver::send_message(const goby::acomms::protobuf::ModemTransmission& msg)
165 {
166  std::string dest = "unknown";
167  if (msg.dest() == acomms::BROADCAST_ID)
168  dest = "all";
169  else
170  dest = modem_lookup_.get_name_from_id(msg.dest());
171 
172  std::string src = modem_lookup_.get_name_from_id(msg.src());
173 
174  std::string hex = hex_encode(msg.SerializeAsString());
175 
176  std::stringstream out_ss;
177  out_ss << "src_node=" << src << ",dest_node=" << dest
178  << ",var_name=" << driver_cfg_.GetExtension(protobuf::Config::incoming_moos_var)
179  << ",string_val=" << hex;
180 
182  out_raw.set_raw(out_ss.str());
183  ModemDriverBase::signal_raw_outgoing(out_raw);
184 
185  const std::string& out_moos_var = driver_cfg_.GetExtension(protobuf::Config::outgoing_moos_var);
186 
187  glog.is(DEBUG1) && glog << group(glog_out_group()) << out_moos_var << ": " << hex << std::endl;
188 
189  moos_client_.Notify(out_moos_var, hex);
190 
191  const std::string& out_ufield_moos_var =
192  driver_cfg_.GetExtension(protobuf::Config::ufield_outgoing_moos_var);
193 
194  glog.is(DEBUG1) && glog << group(glog_out_group()) << out_ufield_moos_var << ": "
195  << out_ss.str() << std::endl;
196 
197  moos_client_.Notify(out_ufield_moos_var, out_ss.str());
198 }
199 
201 {
202  MOOSMSG_LIST msgs;
203  if (moos_client_.Fetch(msgs))
204  {
205  for (MOOSMSG_LIST::iterator it = msgs.begin(), end = msgs.end(); it != end; ++it)
206  {
207  const std::string& in_moos_var =
208  driver_cfg_.GetExtension(protobuf::Config::incoming_moos_var);
209  if (it->GetKey() == in_moos_var)
210  {
211  const std::string& value = it->GetString();
212 
213  glog.is(DEBUG1) && glog << group(glog_in_group()) << in_moos_var << ": " << value
214  << std::endl;
216  in_raw.set_raw(value);
217  ModemDriverBase::signal_raw_incoming(in_raw);
218 
220  msg.ParseFromString(hex_decode(value));
221  receive_message(msg);
222  }
223  else if (it->GetKey() == driver_cfg_.GetExtension(protobuf::Config::micromodem_mimic)
224  .range_report_var())
225  {
226  // response to our modem "ping"
227  // e.g "range=1722.3869,target=resolution,time=1364413337.272"
228  try
229  {
231  std::string target;
232  double range, time;
233  if (!val_from_string(target, it->GetString(), "target"))
234  throw(std::runtime_error("No `target` field"));
235  if (!val_from_string(range, it->GetString(), "range"))
236  throw(std::runtime_error("No `range` field"));
237  if (!val_from_string(time, it->GetString(), "time"))
238  throw(std::runtime_error("No `time` field"));
239 
240  if (target != modem_lookup_.get_name_from_id(last_ccmpc_dest_))
241  {
242  glog.is(DEBUG1) && glog << group(glog_in_group())
243  << "Ignoring report from target: " << target
244  << std::endl;
245  }
246  else
247  {
248  m.set_time(static_cast<uint64>(time) * 1000000);
249 
250  m.set_src(driver_cfg_.modem_id());
251  m.set_dest(last_ccmpc_dest_);
252 
253  micromodem::protobuf::RangingReply* ranging_reply =
254  m.MutableExtension(micromodem::protobuf::ranging_reply);
255 
256  ranging_reply->add_one_way_travel_time(range / NOMINAL_SPEED_OF_SOUND);
257 
258  m.set_type(goby::acomms::protobuf::ModemTransmission::DRIVER_SPECIFIC);
259  m.SetExtension(micromodem::protobuf::type,
260  micromodem::protobuf::MICROMODEM_TWO_WAY_PING);
261 
262  glog.is(DEBUG1) &&
263  glog << group(glog_in_group())
264  << "Received mimic of MICROMODEM_TWO_WAY_PING response from "
265  << m.src() << ", 1-way travel time: "
266  << ranging_reply->one_way_travel_time(
267  ranging_reply->one_way_travel_time_size() - 1)
268  << "s" << std::endl;
269 
270  ModemDriverBase::signal_receive(m);
271  last_ccmpc_dest_ = -1;
272  }
273  }
274  catch (std::exception& e)
275  {
276  glog.is(DEBUG1) && glog << group(glog_in_group()) << warn
277  << "Failed to parse incoming range report message: "
278  << e.what() << std::endl;
279  }
280  }
281  }
282  }
283 }
284 
285 void goby::moos::UFldDriver::receive_message(const goby::acomms::protobuf::ModemTransmission& msg)
286 {
287  if (msg.type() == goby::acomms::protobuf::ModemTransmission::DRIVER_SPECIFIC &&
288  msg.GetExtension(goby::moos::protobuf::type) == goby::moos::protobuf::UFIELD_DRIVER_POLL)
289  {
291  data_msg.set_type(goby::acomms::protobuf::ModemTransmission::DATA);
292  data_msg.set_src(msg.GetExtension(goby::moos::protobuf::poll_src));
293  data_msg.set_dest(msg.GetExtension(goby::moos::protobuf::poll_dest));
294 
295  data_msg.ClearExtension(goby::moos::protobuf::type);
296  data_msg.ClearExtension(goby::moos::protobuf::poll_dest);
297  data_msg.ClearExtension(goby::moos::protobuf::poll_src);
298 
300  }
301  else
302  {
303  // ack any packets
304  if (msg.type() == acomms::protobuf::ModemTransmission::DATA && msg.ack_requested() &&
305  msg.dest() != acomms::BROADCAST_ID)
306  {
308  ack.set_type(goby::acomms::protobuf::ModemTransmission::ACK);
309  ack.set_src(msg.dest());
310  ack.set_dest(msg.src());
311  for (int i = 0, n = msg.frame_size(); i < n; ++i) ack.add_acked_frame(i);
312  send_message(ack);
313  }
314 
315  ModemDriverBase::signal_receive(msg);
316  }
317 }
318 
319 // mimics the Micro-Modem ccpmc in uFld
320 void goby::moos::UFldDriver::ccmpc(const goby::acomms::protobuf::ModemTransmission& msg)
321 {
322  glog.is(DEBUG1) && glog << group(glog_out_group())
323  << "\tthis is a mimic of the MICROMODEM_TWO_WAY_PING transmission"
324  << std::endl;
325 
326  std::string src = modem_lookup_.get_name_from_id(msg.src());
327  last_ccmpc_dest_ = msg.dest();
328  moos_client_.Notify(
329  driver_cfg_.GetExtension(protobuf::Config::micromodem_mimic).range_request_var(),
330  "name=" + src);
331 }
void do_work()
Allows the modem driver to do its work.
void shutdown()
Shuts down the modem driver.
void startup(const goby::acomms::protobuf::DriverConfig &cfg)
Starts the modem driver. Must be called before poll().
const int BROADCAST_ID
special modem id for the broadcast destination - no one is assigned this address. Analogous to 192...
void handle_initiate_transmission(const goby::acomms::protobuf::ModemTransmission &m)
Virtual initiate_transmission method. Typically connected to MACManager::signal_initiate_transmission...
void handle_initiate_transmission(const goby::acomms::protobuf::ModemTransmission &m)
Virtual initiate_transmission method. Typically connected to MACManager::signal_initiate_transmission...
common::FlexOstream glog
Access the Goby logger through this object.
boost::signals2::signal< void(protobuf::ModemTransmission *msg_request)> signal_modify_transmission
Called before the modem driver begins processing a transmission. This allows a third party to modify ...
Definition: driver_base.h:102