Goby v2
pTranslator.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 //
5 //
6 // This file is part of the Goby Underwater Autonomy Project Binaries
7 // ("The Goby Binaries").
8 //
9 // The Goby Binaries are free software: you can redistribute them and/or modify
10 // them under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // The Goby Binaries are distributed in the hope that they will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
21 
22 #include <dlfcn.h>
23 
24 #include "goby/moos/moos_string.h"
25 
26 #include "pTranslator.h"
27 
28 using goby::glog;
29 using namespace goby::common::logger;
30 using goby::moos::operator<<;
31 
32 pTranslatorConfig CpTranslator::cfg_;
33 CpTranslator* CpTranslator::inst_ = 0;
34 
35 CpTranslator* CpTranslator::get_instance()
36 {
37  if (!inst_)
38  inst_ = new CpTranslator();
39  return inst_;
40 }
41 
42 void CpTranslator::delete_instance() { delete inst_; }
43 
44 CpTranslator::CpTranslator()
45  : GobyMOOSApp(&cfg_), translator_(cfg_.translator_entry(), cfg_.common().lat_origin(),
46  cfg_.common().lon_origin(), cfg_.modem_id_lookup_path()),
47  work_(timer_io_service_)
48 {
49  goby::util::DynamicProtobufManager::enable_compilation();
50 
51  // load all shared libraries
52  for (int i = 0, n = cfg_.load_shared_library_size(); i < n; ++i)
53  {
54  glog.is(VERBOSE) && glog << "Loading shared library: " << cfg_.load_shared_library(i)
55  << std::endl;
56 
57  void* handle = dlopen(cfg_.load_shared_library(i).c_str(), RTLD_LAZY);
58  if (!handle)
59  {
60  glog << die << "Failed ... check path provided or add to /etc/ld.so.conf "
61  << "or LD_LIBRARY_PATH" << std::endl;
62  }
63  }
64 
65  // load all .proto files
66  for (int i = 0, n = cfg_.load_proto_file_size(); i < n; ++i)
67  {
68  glog.is(VERBOSE) && glog << "Loading protobuf file: " << cfg_.load_proto_file(i)
69  << std::endl;
70 
71  if (!goby::util::DynamicProtobufManager::find_descriptor(cfg_.load_proto_file(i)))
72  glog.is(DIE) && glog << "Failed to load file." << std::endl;
73  }
74 
75  // process translator entries
76  for (int i = 0, n = cfg_.translator_entry_size(); i < n; ++i)
77  {
78  typedef boost::shared_ptr<google::protobuf::Message> GoogleProtobufMessagePointer;
79  glog.is(VERBOSE) && glog << "Checking translator entry: "
80  << cfg_.translator_entry(i).DebugString() << std::flush;
81 
82  // check that the protobuf file is loaded somehow
83  goby::util::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(
84  cfg_.translator_entry(i).protobuf_name());
85 
86  if (cfg_.translator_entry(i).trigger().type() ==
87  goby::moos::protobuf::TranslatorEntry::Trigger::TRIGGER_PUBLISH)
88  {
89  // subscribe for trigger publish variables
90  GobyMOOSApp::subscribe(
91  cfg_.translator_entry(i).trigger().moos_var(),
92  boost::bind(&CpTranslator::create_on_publish, this, _1, cfg_.translator_entry(i)));
93  }
94  else if (cfg_.translator_entry(i).trigger().type() ==
95  goby::moos::protobuf::TranslatorEntry::Trigger::TRIGGER_TIME)
96  {
97  timers_.push_back(boost::shared_ptr<Timer>(new Timer(timer_io_service_)));
98 
99  Timer& new_timer = *timers_.back();
100 
101  new_timer.expires_from_now(
102  boost::posix_time::seconds(cfg_.translator_entry(i).trigger().period()));
103  // Start an asynchronous wait.
104  new_timer.async_wait(boost::bind(&CpTranslator::create_on_timer, this, _1,
105  cfg_.translator_entry(i), &new_timer));
106  }
107 
108  for (int j = 0, m = cfg_.translator_entry(i).create_size(); j < m; ++j)
109  {
110  // subscribe for all create variables
111  subscribe(cfg_.translator_entry(i).create(j).moos_var());
112  }
113  }
114 
115  for (int i = 0, m = cfg_.multiplex_create_moos_var_size(); i < m; ++i)
116  {
117  GobyMOOSApp::subscribe(cfg_.multiplex_create_moos_var(i),
118  &CpTranslator::create_on_multiplex_publish, this);
119  }
120 }
121 
122 CpTranslator::~CpTranslator() {}
123 
124 void CpTranslator::loop() { timer_io_service_.poll(); }
125 
126 void CpTranslator::create_on_publish(const CMOOSMsg& trigger_msg,
128 {
129  glog.is(VERBOSE) && glog << "Received trigger: " << trigger_msg << std::endl;
130 
131  if (!entry.trigger().has_mandatory_content() ||
132  trigger_msg.GetString().find(entry.trigger().mandatory_content()) != std::string::npos)
133  do_translation(entry);
134  else
135  glog.is(VERBOSE) &&
136  glog << "Message missing mandatory content for: " << entry.protobuf_name() << std::endl;
137 }
138 
139 void CpTranslator::create_on_multiplex_publish(const CMOOSMsg& moos_msg)
140 {
141  boost::shared_ptr<google::protobuf::Message> msg = dynamic_parse_for_moos(moos_msg.GetString());
142 
143  if (!msg)
144  {
145  glog.is(WARN) && glog << "Multiplex receive failed: Unknown Protobuf type for "
146  << moos_msg.GetString()
147  << "; be sure it is compiled in or directly loaded into the "
148  "goby::util::DynamicProtobufManager."
149  << std::endl;
150  return;
151  }
152 
153  std::multimap<std::string, CMOOSMsg> out;
154 
155  try
156  {
157  out = translator_.protobuf_to_inverse_moos(*msg);
158 
159  for (std::multimap<std::string, CMOOSMsg>::iterator it = out.begin(), n = out.end();
160  it != n; ++it)
161  {
162  glog.is(VERBOSE) && glog << "Inverse Publishing: " << it->second.GetKey() << std::endl;
163  publish(it->second);
164  }
165  }
166  catch (std::exception& e)
167  {
168  glog.is(WARN) && glog << "Failed to inverse publish: " << e.what() << std::endl;
169  }
170 }
171 
172 void CpTranslator::create_on_timer(const boost::system::error_code& error,
173  const goby::moos::protobuf::TranslatorEntry& entry, Timer* timer)
174 {
175  if (!error)
176  {
177  double skew_seconds = std::abs(goby::common::goby_time<double>() -
178  goby::util::as<double>(timer->expires_at()));
179  if (skew_seconds > ALLOWED_TIMER_SKEW_SECONDS)
180  {
181  glog.is(VERBOSE) && glog << "clock skew of " << skew_seconds
182  << " seconds detected, resetting timer." << std::endl;
183  timer->expires_at(
185  boost::posix_time::seconds(boost::posix_time::seconds(entry.trigger().period())));
186  }
187  else
188  {
189  // reset the timer
190  timer->expires_at(timer->expires_at() +
191  boost::posix_time::seconds(entry.trigger().period()));
192  }
193 
194  timer->async_wait(boost::bind(&CpTranslator::create_on_timer, this, _1, entry, timer));
195 
196  glog.is(VERBOSE) && glog << "Received trigger for: " << entry.protobuf_name() << std::endl;
197  glog.is(VERBOSE) && glog << "Next expiry: " << timer->expires_at() << std::endl;
198 
199  do_translation(entry);
200  }
201 }
202 
203 void CpTranslator::do_translation(const goby::moos::protobuf::TranslatorEntry& entry)
204 {
205  boost::shared_ptr<google::protobuf::Message> created_message =
206  translator_.moos_to_protobuf<boost::shared_ptr<google::protobuf::Message> >(
207  dynamic_vars().all(), entry.protobuf_name());
208 
209  glog.is(DEBUG1) && glog << "Created message: \n" << created_message->DebugString() << std::endl;
210 
211  do_publish(created_message);
212 }
213 
214 void CpTranslator::do_publish(boost::shared_ptr<google::protobuf::Message> created_message)
215 {
216  std::multimap<std::string, CMOOSMsg> out;
217 
218  out = translator_.protobuf_to_moos(*created_message);
219 
220  for (std::multimap<std::string, CMOOSMsg>::iterator it = out.begin(), n = out.end(); it != n;
221  ++it)
222  {
223  glog.is(VERBOSE) && glog << "Publishing: " << it->second << std::endl;
224  publish(it->second);
225  }
226 }
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.