Goby v2
abc_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 "abc_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;
33 
34 goby::acomms::ABCDriver::ABCDriver()
35 {
36  // other initialization you can do before you have your goby::acomms::DriverConfig configuration object
37 }
38 
40 {
41  driver_cfg_ = cfg;
42  // check `driver_cfg_` to your satisfaction and then start the modem physical interface
43  if (!driver_cfg_.has_serial_baud())
44  driver_cfg_.set_serial_baud(DEFAULT_BAUD);
45 
46  glog.is(DEBUG1) && glog << group(glog_out_group())
47  << "ABCDriver configuration good. Starting modem..." << std::endl;
48  ModemDriverBase::modem_start(driver_cfg_);
49 
50  // set your local modem id (MAC address)
51  {
52  std::stringstream raw;
53  raw << "CONF,MAC:" << driver_cfg_.modem_id() << "\r\n";
54  signal_and_write(raw.str());
55  }
56 
57  // now set our special configuration values
58  {
59  std::stringstream raw;
60  raw << "CONF,FOO:" << driver_cfg_.GetExtension(ABCDriverConfig::enable_foo) << "\r\n";
61  signal_and_write(raw.str());
62  }
63  {
64  std::stringstream raw;
65  raw << "CONF,BAR:" << driver_cfg_.GetExtension(ABCDriverConfig::enable_bar) << "\r\n";
66  signal_and_write(raw.str());
67  }
68 } // startup
69 
71 {
72  // put the modem in a low power state?
73  // ...
74  ModemDriverBase::modem_close();
75 } // shutdown
76 
78  const protobuf::ModemTransmission& orig_msg)
79 {
80  // copy so we can modify
81  protobuf::ModemTransmission msg = orig_msg;
82 
83  // rate() can be 0 (lowest), 1, 2, 3, 4, or 5 (lowest). Map these integers onto real bit-rates
84  // in a meaningful way (on the WHOI Micro-Modem 0 ~= 80 bps, 5 ~= 5000 bps).
85  glog.is(DEBUG1) && glog << group(glog_out_group()) << "We were asked to transmit from "
86  << msg.src() << " to " << msg.dest() << " at bitrate code "
87  << msg.rate() << std::endl;
88 
89  // let's say ABC modem uses 500 byte packet
90  msg.set_max_frame_bytes(500);
91 
92  // no data given to us, let's ask for some
93  if (msg.frame_size() == 0)
94  ModemDriverBase::signal_data_request(&msg);
95 
96  glog.is(DEBUG1) && glog << group(glog_out_group()) << "Sending these data now: " << msg.frame(0)
97  << std::endl;
98 
99  // let's say we can send at three bitrates with ABC modem: map these onto 0-5
100  const unsigned BITRATE[] = {100, 1000, 10000, 10000, 10000, 10000};
101 
102  // I'm making up a syntax for the wire protocol...
103  std::stringstream raw;
104  raw << "SEND,TO:" << msg.dest() << ",FROM:" << msg.src() << ",HEX:" << hex_encode(msg.frame(0))
105  << ",BITRATE:" << BITRATE[msg.rate()] << ",ACK:TRUE"
106  << "\r\n";
107 
108  // let anyone who is interested know
109  signal_and_write(raw.str());
110 } // handle_initiate_transmission
111 
113 {
114  std::string in;
115  while (modem_read(&in))
116  {
117  std::map<std::string, std::string> parsed;
118 
119  // breaks `in`: "RECV,TO:3,FROM:6,HEX:ABCD015910"
120  // into `parsed`: "KEY"=>"RECV", "TO"=>"3", "FROM"=>"6", "HEX"=>"ABCD015910"
121  try
122  {
123  boost::trim(in); // get whitespace off from either end
124  parse_in(in, &parsed);
125 
126  // let others know about the raw feed
127  protobuf::ModemRaw raw;
128  raw.set_raw(in);
129  ModemDriverBase::signal_raw_incoming(raw);
130 
132  msg.set_src(goby::util::as<int32>(parsed["FROM"]));
133  msg.set_dest(goby::util::as<int32>(parsed["TO"]));
134  msg.set_time(goby::common::goby_time<uint64>());
135 
136  glog.is(DEBUG1) && glog << group(glog_in_group()) << in << std::endl;
137 
138  if (parsed["KEY"] == "RECV")
139  {
140  msg.set_type(protobuf::ModemTransmission::DATA);
141  msg.add_frame(hex_decode(parsed["HEX"]));
142  glog.is(DEBUG1) && glog << group(glog_in_group()) << "received: " << msg
143  << std::endl;
144  }
145  else if (parsed["KEY"] == "ACKN")
146  {
147  msg.set_type(protobuf::ModemTransmission::ACK);
148  }
149 
150  ModemDriverBase::signal_receive(msg);
151  }
152  catch (std::exception& e)
153  {
154  glog.is(WARN) && glog << "Bad line: " << in << std::endl;
155  glog.is(WARN) && glog << "Exception: " << e.what() << std::endl;
156  }
157  }
158 } // do_work
159 
160 void goby::acomms::ABCDriver::signal_and_write(const std::string& raw)
161 {
162  protobuf::ModemRaw raw_msg;
163  raw_msg.set_raw(raw);
164  ModemDriverBase::signal_raw_outgoing(raw_msg);
165 
166  glog.is(DEBUG1) && glog << group(glog_out_group()) << boost::trim_copy(raw) << std::endl;
167  ModemDriverBase::modem_write(raw);
168 }
169 
170 void goby::acomms::ABCDriver::parse_in(const std::string& in,
171  std::map<std::string, std::string>* out)
172 {
173  std::vector<std::string> comma_split;
174  boost::split(comma_split, in, boost::is_any_of(","));
175  out->insert(std::make_pair("KEY", comma_split.at(0)));
176  for (int i = 1, n = comma_split.size(); i < n; ++i)
177  {
178  std::vector<std::string> colon_split;
179  boost::split(colon_split, comma_split[i], boost::is_any_of(":"));
180  out->insert(std::make_pair(colon_split.at(0), colon_split.at(1)));
181  }
182 }
uint64 goby_time< uint64 >()
Returns current UTC time as integer microseconds since 1970-01-01 00:00:00.
Definition: time.h:113
void do_work()
Allows the modem driver to do its work.
Definition: abc_driver.cpp:112
common::FlexOstream glog
Access the Goby logger through this object.
void handle_initiate_transmission(const protobuf::ModemTransmission &m)
Virtual initiate_transmission method. Typically connected to MACManager::signal_initiate_transmission...
Definition: abc_driver.cpp:77
void startup(const protobuf::DriverConfig &cfg)
Starts the modem driver. Must be called before poll().
Definition: abc_driver.cpp:39
void shutdown()
Shuts down the modem driver.
Definition: abc_driver.cpp:70