Goby v2
benthos_atm900_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 "benthos_atm900_driver.h"
24 #include "driver_exception.h"
25 
26 #include "goby/common/logger.h"
27 #include "goby/util/binary.h"
28 
29 using goby::glog;
30 using goby::util::hex_decode;
31 using goby::util::hex_encode;
32 using namespace goby::common::logger;
34 
35 const std::string goby::acomms::BenthosATM900Driver::SERIAL_DELIMITER = "\r\n";
36 
37 boost::shared_ptr<dccl::Codec> goby::acomms::benthos_header_dccl_;
38 
39 goby::acomms::BenthosATM900Driver::BenthosATM900Driver() : fsm_(driver_cfg_), next_frame_(0)
40 {
41  init_benthos_dccl();
42 }
43 
45 {
46  driver_cfg_ = cfg;
47 
48  if (!cfg.has_line_delimiter())
49  driver_cfg_.set_line_delimiter(SERIAL_DELIMITER);
50 
51  if (!driver_cfg_.has_serial_baud())
52  driver_cfg_.set_serial_baud(DEFAULT_BAUD);
53 
54  glog.is(DEBUG1) && glog << group(glog_out_group()) << "BenthosATM900Driver: Starting modem..."
55  << std::endl;
56  ModemDriverBase::modem_start(driver_cfg_);
57  fsm_.initiate();
58 
59  int i = 0;
60  while (fsm_.state_cast<const benthos_fsm::Ready*>() == 0)
61  {
62  do_work();
63 
64  const int pause_ms = 10;
65  usleep(pause_ms * 1000);
66  ++i;
67 
68  const int start_timeout =
69  driver_cfg_.GetExtension(benthos::protobuf::BenthosATM900DriverConfig::start_timeout);
70  if (i / (1000 / pause_ms) > start_timeout)
71  throw(ModemDriverException("Failed to startup.",
72  protobuf::ModemDriverStatus::STARTUP_FAILED));
73  }
74 }
75 
77 {
78  fsm_.process_event(benthos_fsm::EvReset());
79 
80  while (fsm_.state_cast<const benthos_fsm::Ready*>() == 0)
81  {
82  do_work();
83  usleep(10000);
84  }
85 
86  fsm_.process_event(benthos_fsm::EvRequestLowPower());
87 
88  while (fsm_.state_cast<const benthos_fsm::LowPower*>() == 0)
89  {
90  do_work();
91  usleep(10000);
92  }
93 
95  fsm_.terminate();
96 }
97 
99  const protobuf::ModemTransmission& orig_msg)
100 {
101  protobuf::ModemTransmission msg = orig_msg;
103 
104  switch (msg.type())
105  {
106  case protobuf::ModemTransmission::DATA:
107  {
108  // set the frame size, if not set or if it exceeds the max configured
109  if (!msg.has_max_frame_bytes() ||
110  msg.max_frame_bytes() >
111  driver_cfg_.GetExtension(
112  benthos::protobuf::BenthosATM900DriverConfig::max_frame_size))
113  msg.set_max_frame_bytes(driver_cfg_.GetExtension(
114  benthos::protobuf::BenthosATM900DriverConfig::max_frame_size));
115 
116  signal_data_request(&msg);
117 
118  if (!(msg.frame_size() == 0 || msg.frame(0).empty()))
119  send(msg);
120  }
121  break;
122 
123  case protobuf::ModemTransmission::DRIVER_SPECIFIC:
124  {
125  switch (msg.GetExtension(benthos::protobuf::type))
126  {
127  case benthos::protobuf::BENTHOS_TWO_WAY_PING:
128  fsm_.process_event(benthos_fsm::EvRange(msg.dest()));
129  break;
130  default:
131  glog.is(DEBUG1) &&
132  glog << group(glog_out_group()) << warn
133  << "Not initiating transmission because we were given an invalid "
134  "DRIVER_SPECIFIC transmission type for the Benthos ATM-900:"
135  << msg << std::endl;
136  break;
137  }
138  }
139  break;
140 
141  default:
142  glog.is(DEBUG1) && glog << group(glog_out_group()) << warn
143  << "Not initiating transmission because we were given an "
144  "invalid transmission type for the base Driver:"
145  << msg << std::endl;
146  break;
147  }
148 }
149 
151 {
152  try_serial_tx();
153 
154  std::string in;
155  while (modem_read(&in))
156  {
157  benthos_fsm::EvRxSerial data_event;
158  data_event.line = in;
159 
160  glog.is(DEBUG1) &&
161  glog << group(glog_in_group())
162  << (boost::algorithm::all(in, boost::is_print() || boost::is_any_of("\r\n"))
163  ? boost::trim_copy(in)
164  : goby::util::hex_encode(in))
165  << std::endl;
166 
167  fsm_.process_event(data_event);
168  }
169 
170  while (!fsm_.received().empty())
171  {
172  receive(fsm_.received().front());
173  fsm_.received().pop_front();
174  }
175 
176  try_serial_tx();
177 }
178 
179 void goby::acomms::BenthosATM900Driver::receive(const protobuf::ModemTransmission& msg)
180 {
181  glog.is(DEBUG2) && glog << group(glog_in_group()) << msg << std::endl;
182 
183  if (msg.type() == protobuf::ModemTransmission::DATA && msg.ack_requested() &&
184  msg.dest() == driver_cfg_.modem_id())
185  {
186  // make any acks
188  ack.set_type(goby::acomms::protobuf::ModemTransmission::ACK);
189  ack.set_src(msg.dest());
190  ack.set_dest(msg.src());
191  ack.set_rate(msg.rate());
192  for (int i = msg.frame_start(), n = msg.frame_size() + msg.frame_start(); i < n; ++i)
193  ack.add_acked_frame(i);
194  send(ack);
195  }
196 
197  signal_receive(msg);
198 }
199 
200 void goby::acomms::BenthosATM900Driver::send(const protobuf::ModemTransmission& msg)
201 {
202  glog.is(DEBUG2) && glog << group(glog_out_group()) << msg << std::endl;
203  fsm_.buffer_data_out(msg);
204  fsm_.process_event(benthos_fsm::EvDial(msg.dest(), msg.rate()));
205 }
206 
207 void goby::acomms::BenthosATM900Driver::try_serial_tx()
208 {
209  fsm_.process_event(benthos_fsm::EvTxSerial());
210 
211  while (!fsm_.serial_tx_buffer().empty())
212  {
213  const std::string& line = fsm_.serial_tx_buffer().front();
214 
215  glog.is(DEBUG1) &&
216  glog << group(glog_out_group())
217  << (boost::algorithm::all(line, boost::is_print() || boost::is_any_of("\r\n"))
218  ? boost::trim_copy(line)
219  : goby::util::hex_encode(line))
220  << std::endl;
221 
222  modem_write(line);
223 
224  fsm_.serial_tx_buffer().pop_front();
225  }
226 }
void shutdown()
Shuts down the modem driver.
void modem_write(const std::string &out)
write a line to the serial port.
Definition: driver_base.cpp:48
void handle_initiate_transmission(const protobuf::ModemTransmission &m)
Virtual initiate_transmission method. Typically connected to MACManager::signal_initiate_transmission...
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
void do_work()
Allows the modem driver to do its work.
Definition: abc_driver.cpp:112
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime.
Definition: time.h:104
boost::signals2::signal< void(const protobuf::ModemTransmission &message)> signal_receive
Called when a binary data transmission is received from the modem.
Definition: driver_base.h:85
void do_work()
Allows the modem driver to do its work.
common::FlexOstream glog
Access the Goby logger through this object.
void startup(const protobuf::DriverConfig &cfg)
Starts the modem driver. Must be called before poll().
bool modem_read(std::string *in)
read a line from the serial port, including end-of-line character(s)
Definition: driver_base.cpp:57
boost::signals2::signal< void(protobuf::ModemTransmission *msg)> signal_data_request
Called when the modem or modem driver needs data to send. The returned data should be stored in Modem...
Definition: driver_base.h:96
void modem_close()
closes the serial port. Use modem_start to reopen the port.
Definition: driver_base.cpp:66
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