Goby v2
iFrontSeat.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 <boost/algorithm/string.hpp>
25 #include <boost/signals2.hpp>
26 
27 #include "goby/acomms/connect.h"
28 #include "goby/common/logger.h"
29 #include "goby/common/time.h"
30 
31 #include "iFrontSeat.h"
32 
33 using namespace goby::common::logger;
34 namespace gpb = goby::moos::protobuf;
35 using goby::glog;
37 
38 iFrontSeatConfig iFrontSeat::cfg_;
39 iFrontSeat* iFrontSeat::inst_ = 0;
40 void* iFrontSeat::driver_library_handle_ = 0;
41 
42 int main(int argc, char* argv[])
43 {
44  // load plugin driver from environmental variable IFRONTSEAT_DRIVER_LIBRARY
45  char* driver_lib_path = getenv("IFRONTSEAT_DRIVER_LIBRARY");
46  if (driver_lib_path)
47  {
48  std::cerr << "Loading iFrontSeat driver library: " << driver_lib_path << std::endl;
49  iFrontSeat::driver_library_handle_ = dlopen(driver_lib_path, RTLD_LAZY);
50  if (!iFrontSeat::driver_library_handle_)
51  {
52  std::cerr << "Failed to open library: " << driver_lib_path << std::endl;
53  exit(EXIT_FAILURE);
54  }
55  }
56  else
57  {
58  std::cerr << "Environmental variable IFRONTSEAT_DRIVER_LIBRARY must be set with name of "
59  "the dynamic library containing the specific driver to use."
60  << std::endl;
61  exit(EXIT_FAILURE);
62  }
63 
64  return goby::moos::run<iFrontSeat>(argc, argv);
65 }
66 
67 iFrontSeat* iFrontSeat::get_instance()
68 {
69  if (!inst_)
70  inst_ = new iFrontSeat();
71  return inst_;
72 }
73 
75 {
76  typedef FrontSeatInterfaceBase* (*driver_load_func)(iFrontSeatConfig*);
77  driver_load_func driver_load_ptr =
78  (driver_load_func)dlsym(iFrontSeat::driver_library_handle_, "frontseat_driver_load");
79 
80  if (!driver_load_ptr)
81  glog.is(DIE) && glog << "Function frontseat_driver_load in library defined in "
82  "IFRONTSEAT_DRIVER_LIBRARY does not exist."
83  << std::endl;
84 
85  FrontSeatInterfaceBase* driver = (*driver_load_ptr)(cfg);
86 
87  if (!driver)
88  glog.is(DIE) && glog << "Function frontseat_driver_load in library defined in "
89  "IFRONTSEAT_DRIVER_LIBRARY returned a null pointer."
90  << std::endl;
91 
92  return driver;
93 }
94 
95 iFrontSeat::iFrontSeat() : GobyMOOSApp(&cfg_), frontseat_(load_driver(&cfg_)), translator_(this)
96 {
97  // commands
98  subscribe(cfg_.moos_var().prefix() + cfg_.moos_var().command_request(),
99  &iFrontSeat::handle_mail_command_request, this);
100  goby::acomms::connect(&frontseat_->signal_command_response, this,
101  &iFrontSeat::handle_driver_command_response);
102 
103  // data
104  subscribe(cfg_.moos_var().prefix() + cfg_.moos_var().data_to_frontseat(),
105  &iFrontSeat::handle_mail_data_to_frontseat, this);
106  goby::acomms::connect(&frontseat_->signal_data_from_frontseat, this,
107  &iFrontSeat::handle_driver_data_from_frontseat);
108 
109  // raw
110  subscribe(cfg_.moos_var().prefix() + cfg_.moos_var().raw_out(),
111  &iFrontSeat::handle_mail_raw_out, this);
112  goby::acomms::connect(&frontseat_->signal_raw_from_frontseat, this,
113  &iFrontSeat::handle_driver_raw_in);
114 
115  goby::acomms::connect(&frontseat_->signal_raw_to_frontseat, this,
116  &iFrontSeat::handle_driver_raw_out);
117 
118  // IvP Helm State
119  subscribe("IVPHELM_STATE", &iFrontSeat::handle_mail_helm_state, this);
120 
121  register_timer(cfg_.status_period(), boost::bind(&iFrontSeat::status_loop, this));
122 }
123 
124 void iFrontSeat::loop()
125 {
126  frontseat_->do_work();
127 
128  if (cfg_.exit_on_error() && (frontseat_->state() == gpb::INTERFACE_FS_ERROR ||
129  frontseat_->state() == gpb::INTERFACE_HELM_ERROR))
130  {
131  glog.is(DIE) &&
132  glog << "Error state detected and `exit_on_error` == true, so quitting. Bye!"
133  << std::endl;
134  }
135 }
136 
137 void iFrontSeat::status_loop()
138 {
139  glog.is(DEBUG1) && glog << "Status: " << frontseat_->status().ShortDebugString() << std::endl;
140  publish_pb(cfg_.moos_var().prefix() + cfg_.moos_var().status(), frontseat_->status());
141 }
142 
143 void iFrontSeat::handle_mail_command_request(const CMOOSMsg& msg)
144 {
145  if (frontseat_->state() != gpb::INTERFACE_COMMAND)
146  {
147  glog.is(DEBUG1) &&
148  glog << "Not sending command because the interface is not in the command state"
149  << std::endl;
150  }
151  else
152  {
153  gpb::CommandRequest command;
154  parse_for_moos(msg.GetString(), &command);
155  frontseat_->send_command_to_frontseat(command);
156  }
157 }
158 
159 void iFrontSeat::handle_mail_data_to_frontseat(const CMOOSMsg& msg)
160 {
161  if (frontseat_->state() != gpb::INTERFACE_COMMAND &&
162  frontseat_->state() != gpb::INTERFACE_LISTEN)
163  {
164  glog.is(DEBUG1) &&
165  glog << "Not sending data because the interface is not in the command or listen state"
166  << std::endl;
167  }
168  else
169  {
171  parse_for_moos(msg.GetString(), &data);
172  frontseat_->send_data_to_frontseat(data);
173  }
174 }
175 
176 void iFrontSeat::handle_mail_raw_out(const CMOOSMsg& msg)
177 {
178  // no recursively sending our own messages
179  if (msg.GetSource() == GetAppName())
180  return;
181 
182  if (frontseat_->state() != gpb::INTERFACE_COMMAND &&
183  frontseat_->state() != gpb::INTERFACE_LISTEN)
184  {
185  glog.is(DEBUG1) &&
186  glog << "Not sending raw because the interface is not in the command or listen state"
187  << std::endl;
188  }
189  else
190  {
191  gpb::FrontSeatRaw raw;
192  parse_for_moos(msg.GetString(), &raw);
193  frontseat_->send_raw_to_frontseat(raw);
194  }
195 }
196 
197 void iFrontSeat::handle_mail_helm_state(const CMOOSMsg& msg)
198 {
199  std::string sval = msg.GetString();
200  boost::trim(sval);
201  if (boost::iequals(sval, "drive"))
202  frontseat_->set_helm_state(gpb::HELM_DRIVE);
203  else if (boost::iequals(sval, "park"))
204  frontseat_->set_helm_state(gpb::HELM_PARK);
205  else
206  frontseat_->set_helm_state(gpb::HELM_NOT_RUNNING);
207 }
208 
209 void iFrontSeat::handle_driver_command_response(
211 {
212  publish_pb(cfg_.moos_var().prefix() + cfg_.moos_var().command_response(), response);
213 }
214 
215 void iFrontSeat::handle_driver_data_from_frontseat(
217 {
218  publish_pb(cfg_.moos_var().prefix() + cfg_.moos_var().data_from_frontseat(), data);
219  if (data.has_node_status())
220  publish_pb(cfg_.moos_var().prefix() + cfg_.moos_var().node_status(), data.node_status());
221 }
222 
223 void iFrontSeat::handle_driver_raw_in(const goby::moos::protobuf::FrontSeatRaw& data)
224 {
225  publish_pb(cfg_.moos_var().prefix() + cfg_.moos_var().raw_in(), data);
226 }
227 
228 void iFrontSeat::handle_driver_raw_out(const goby::moos::protobuf::FrontSeatRaw& data)
229 {
230  publish_pb(cfg_.moos_var().prefix() + cfg_.moos_var().raw_out(), data);
231 }
void parse_for_moos(const std::string &in, google::protobuf::Message *msg)
Parses the string in to Google Protocol Buffers message msg. All errors are written to the goby::util...
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime.
Definition: time.h:104
void connect(Signal *signal, Slot slot)
connect a signal to a slot (e.g. function pointer)
Definition: connect.h:36
common::FlexOstream glog
Access the Goby logger through this object.
void subscribe(int socket_id, boost::function< void(const ProtoBufMessage &)> handler=boost::function< void(const ProtoBufMessage &)>(), const std::string &group="")
Subscribe to a message (of any type derived from google::protobuf::Message)