Goby v2
driver_base.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/format.hpp>
24 #include <boost/thread/mutex.hpp>
25 
26 #include "goby/acomms/connect.h"
27 #include "goby/common/logger.h"
28 
29 #include "driver_base.h"
30 #include "driver_exception.h"
31 
32 using namespace goby::common::logger;
33 using namespace goby::common::logger_lock;
34 
35 int goby::acomms::ModemDriverBase::count_ = 0;
36 
37 goby::acomms::ModemDriverBase::ModemDriverBase() : raw_fs_connections_made_(false), order_(++count_)
38 {
39  glog_out_group_ = "goby::acomms::modemdriver::out::" + goby::util::as<std::string>(order_);
40  glog_in_group_ = "goby::acomms::modemdriver::in::" + goby::util::as<std::string>(order_);
41 
42  goby::glog.add_group(glog_out_group_, common::Colors::lt_magenta);
43  goby::glog.add_group(glog_in_group_, common::Colors::lt_blue);
44 }
45 
47 
48 void goby::acomms::ModemDriverBase::modem_write(const std::string& out)
49 {
50  if (modem_->active())
51  modem_->write(out);
52  else
53  throw(ModemDriverException("Modem physical connection failed.",
54  protobuf::ModemDriverStatus::CONNECTION_TO_MODEM_FAILED));
55 }
56 
58 {
59  if (modem_->active())
60  return modem_->readline(in);
61  else
62  throw(ModemDriverException("Modem physical connection failed.",
63  protobuf::ModemDriverStatus::CONNECTION_TO_MODEM_FAILED));
64 }
65 
67 
69 {
70  if (!cfg.has_modem_id())
71  throw(ModemDriverException("missing modem_id in configuration",
72  protobuf::ModemDriverStatus::INVALID_CONFIGURATION));
73 
74  switch (cfg.connection_type())
75  {
76  case protobuf::DriverConfig::CONNECTION_SERIAL:
77  goby::glog.is(DEBUG1) && goby::glog << group(glog_out_group_) << "opening serial port "
78  << cfg.serial_port() << " @ " << cfg.serial_baud()
79  << std::endl;
80 
81  if (!cfg.has_serial_port())
82  throw(ModemDriverException("missing serial port in configuration",
83  protobuf::ModemDriverStatus::INVALID_CONFIGURATION));
84  if (!cfg.has_serial_baud())
85  throw(ModemDriverException("missing serial baud in configuration",
86  protobuf::ModemDriverStatus::INVALID_CONFIGURATION));
87 
88  modem_.reset(
89  new util::SerialClient(cfg.serial_port(), cfg.serial_baud(), cfg.line_delimiter()));
90  break;
91 
92  case protobuf::DriverConfig::CONNECTION_TCP_AS_CLIENT:
93  goby::glog.is(DEBUG1) && goby::glog << group(glog_out_group_)
94  << "opening tcp client: " << cfg.tcp_server() << ":"
95  << cfg.tcp_port() << std::endl;
96  if (!cfg.has_tcp_server())
97  throw(ModemDriverException("missing tcp server address in configuration",
98  protobuf::ModemDriverStatus::INVALID_CONFIGURATION));
99  if (!cfg.has_tcp_port())
100  throw(ModemDriverException("missing tcp port in configuration",
101  protobuf::ModemDriverStatus::INVALID_CONFIGURATION));
102 
103  modem_.reset(new util::TCPClient(cfg.tcp_server(), cfg.tcp_port(), cfg.line_delimiter(),
104  cfg.reconnect_interval()));
105  break;
106 
107  case protobuf::DriverConfig::CONNECTION_TCP_AS_SERVER:
108  goby::glog.is(DEBUG1) && goby::glog << group(glog_out_group_)
109  << "opening tcp server on port" << cfg.tcp_port()
110  << std::endl;
111 
112  if (!cfg.has_tcp_port())
113  throw(ModemDriverException("missing tcp port in configuration",
114  protobuf::ModemDriverStatus::INVALID_CONFIGURATION));
115 
116  modem_.reset(new util::TCPServer(cfg.tcp_port(), cfg.line_delimiter()));
117  }
118 
119  if (cfg.has_raw_log())
120  {
121  using namespace boost::posix_time;
122  boost::format file_format(cfg.raw_log());
123  file_format.exceptions(boost::io::all_error_bits ^
124  (boost::io::too_many_args_bit | boost::io::too_few_args_bit));
125 
126  std::string file_name = (file_format % to_iso_string(second_clock::universal_time())).str();
127 
128  glog.is(DEBUG1) && glog << group(glog_out_group_)
129  << "logging raw output to file: " << file_name << std::endl;
130 
131  raw_fs_.reset(new std::ofstream(file_name.c_str()));
132 
133  if (raw_fs_->is_open())
134  {
135  if (!raw_fs_connections_made_)
136  {
138  boost::bind(&ModemDriverBase::write_raw, this, _1, true));
140  boost::bind(&ModemDriverBase::write_raw, this, _1, false));
141  raw_fs_connections_made_ = true;
142  }
143  }
144  else
145  {
146  glog.is(DEBUG1) && glog << group(glog_out_group_) << warn << "Failed to open log file"
147  << std::endl;
148  raw_fs_.reset();
149  }
150  }
151 
152  modem_->start();
153 
154  // give it this much startup time
155  const int max_startup_ms = 10000;
156  int startup_elapsed_ms = 0;
157  while (!modem_->active())
158  {
159  usleep(100000); // 100 ms
160  startup_elapsed_ms += 100;
161  if (startup_elapsed_ms >= max_startup_ms)
162  throw(ModemDriverException("Modem physical connection failed to startup.",
163  protobuf::ModemDriverStatus::STARTUP_FAILED));
164  }
165 }
166 
167 void goby::acomms::ModemDriverBase::write_raw(const protobuf::ModemRaw& msg, bool rx)
168 {
169  if (rx)
170  *raw_fs_ << "[rx] ";
171  else
172  *raw_fs_ << "[tx] ";
173  *raw_fs_ << msg.raw() << std::endl;
174 }
175 
177 {
178  goby::glog.is(WARN) && goby::glog << group(glog_out_group_)
179  << "Updating configuration is not implemented in this driver."
180  << std::endl;
181 }
provides a basic client for line by line text based communications over a 8N1 tty (such as an RS-232 ...
Definition: serial_client.h:35
void modem_write(const std::string &out)
write a line to the serial port.
Definition: driver_base.cpp:48
void modem_start(const protobuf::DriverConfig &cfg)
start the physical connection to the modem (serial port, TCP, etc.). must be called before ModemDrive...
Definition: driver_base.cpp:68
boost::signals2::signal< void(const protobuf::ModemRaw &msg)> signal_raw_incoming
Called after any message is received from the modem by the driver. Used by the MACManager for auto-di...
Definition: driver_base.h:107
provides a basic TCP client for line by line text based communications to a remote TCP server ...
Definition: tcp_client.h:34
provides a basic TCP server for line by line text based communications to a one or more remote TCP cl...
Definition: tcp_server.h:49
void add_group(const std::string &name, Colors::Color color=Colors::nocolor, const std::string &description="")
Add another group to the logger. A group provides related manipulator for categorizing log messages...
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.
virtual ~ModemDriverBase()
Public Destructor.
Definition: driver_base.cpp:46
boost::signals2::signal< void(const protobuf::ModemRaw &msg)> signal_raw_outgoing
Called after any message is sent from the driver to the modem. Useful for higher level analysis and d...
Definition: driver_base.h:112
bool modem_read(std::string *in)
read a line from the serial port, including end-of-line character(s)
Definition: driver_base.cpp:57
void modem_close()
closes the serial port. Use modem_start to reopen the port.
Definition: driver_base.cpp:66
virtual void update_cfg(const protobuf::DriverConfig &cfg)
Update configuration while running (not required to be implemented)