Goby v2
mm_driver.h
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 #ifndef Modem20091211H
24 #define Modem20091211H
25 
26 #include <dccl.h>
27 
28 #include "goby/common/time.h"
29 
30 #include "driver_base.h"
31 #include "goby/acomms/acomms_helpers.h"
32 #include "goby/acomms/protobuf/mm_driver.pb.h"
33 
34 namespace goby
35 {
36 namespace acomms
37 {
41 class MMDriver : public ModemDriverBase
42 {
43  public:
45  MMDriver();
47  ~MMDriver();
48 
52  void startup(const protobuf::DriverConfig& cfg);
53 
54  void update_cfg(const protobuf::DriverConfig& cfg);
55 
57  void shutdown();
58 
60  void do_work();
61 
64 
66  int clk_mode() { return clk_mode_; }
67 
68  bool is_started() const { return startup_done_; }
69 
70  static unsigned packet_frame_count(int rate) { return PACKET_FRAME_COUNT[rate]; }
71 
72  static unsigned packet_size(int rate) { return PACKET_SIZE[rate]; }
73 
74  void set_silent(bool silent);
75  void write_single_cfg(const std::string& s); // write a single NVRAM value
76 
77  private:
78  enum SentenceIDs
79  {
80  SENTENCE_NOT_DEFINED = 0,
81  ACK,
82  DRQ,
83  RXA,
84  RXD,
85  RXP,
86  TXD,
87  TXA,
88  TXP,
89  TXF,
90  CYC,
91  MPC,
92  MPA,
93  MPR,
94  RSP,
95  MSC,
96  MSA,
97  MSR,
98  EXL,
99  MEC,
100  MEA,
101  MER,
102  MUC,
103  MUA,
104  MUR,
105  PDT,
106  PNT,
107  TTA,
108  MFD,
109  CLK,
110  CFG,
111  AGC,
112  BBD,
113  CFR,
114  CST,
115  MSG,
116  REV,
117  DQF,
118  SHF,
119  SNR,
120  DOP,
121  DBG,
122  FFL,
123  FST,
124  ERR,
125  TOA,
126  XST,
127  RDP,
128  TDP,
129  TMS,
130  TMQ,
131  TMG,
132  SWP,
133  MSQ
134  };
135 
136  // startup
137  void initialize_talkers(); // insert strings into sentence_id_map_, etc for later use
138  void set_clock(); // set the modem clock from the system (goby) clock
139  void write_cfg(); // write the NVRAM configuration values to the modem
140  void query_all_cfg(); // query the current NVRAM configuration of the modem
141  void set_hydroid_gateway_prefix(int id); // if using the hydroid gateway, set its id number
142 
143  // output
144 
145  void cccyc(protobuf::ModemTransmission* msg);
146  void ccmuc(protobuf::ModemTransmission* msg);
147  void cctdp(protobuf::ModemTransmission* msg);
148  void ccmpc(const protobuf::ModemTransmission& msg);
149  void ccpdt(const protobuf::ModemTransmission& msg);
150  void ccpnt(const protobuf::ModemTransmission& msg);
151  void ccmec(const protobuf::ModemTransmission& msg);
152  void ccpgt(const protobuf::ModemTransmission& msg);
153  void ccswp(const protobuf::ModemTransmission& msg);
154  void ccmsq(const protobuf::ModemTransmission& msg);
155 
156  void try_send(); // try to send another NMEA message to the modem
157  void pop_out(); // pop the NMEA send deque upon successful NMEA acknowledgment
158  void cache_outgoing_data(protobuf::ModemTransmission* msg); // cache data upon a CCCYC
159  void append_to_write_queue(const util::NMEASentence& nmea); // add a message
160  void mm_write(const util::NMEASentence&
161  nmea); // actually write a message (appends hydroid prefix if needed)
162  void increment_present_fail();
163  void present_fail_exceeds_retries();
164 
165  // input
166  void process_receive(
167  const util::NMEASentence& nmea); // parse a receive message and call proper method
168 
169  // data cycle
170  void cacyc(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CACYC
171  void carxd(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CARXD
172  void camsg(const util::NMEASentence& nmea, protobuf::ModemTransmission* m);
173 
174  void caack(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAACK
175  void handle_ack(uint32 src, uint32 dest, uint32 frame, protobuf::ModemTransmission* m);
176 
177  // mini packet
178  void camua(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMUA
179 
180  // flexible data protocol
181  void cardp(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CARDP
182 
183  // ranging (pings)
184  void campr(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMPR
185  void campa(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMPA
186  void sntta(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $SNTTA
187 
188  // hardware control
189  void camer(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMER
190 
191  // local modem
192  void caxst(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAXST
193  void cacst(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CACST
194  void carev(const util::NMEASentence& nmea); // $CAREV
195  void caerr(const util::NMEASentence& nmea); // $CAERR
196  void cacfg(const util::NMEASentence& nmea);
197  void receive_time(const util::NMEASentence& nmea, SentenceIDs sentence_id); // $CACLK
198  void catms(const util::NMEASentence& nmea); // $CATMS
199  void cadrq(const util::NMEASentence& nmea, const protobuf::ModemTransmission& m); // $CADRQ
200 
201  void validate_transmission_start(const protobuf::ModemTransmission& message);
202 
203  void signal_receive_and_clear(protobuf::ModemTransmission* message);
204 
205  // application acks
206  void process_incoming_app_ack(protobuf::ModemTransmission* m);
207  void process_outgoing_app_ack(protobuf::ModemTransmission* msg);
208 
209  // Serial port methods
210  void set_rts(bool state);
211  bool query_rts();
212 
213  // doxygen
214 
216 
218 
219  private:
220  // for the serial connection ($CCCFG,BR1,3)
221  enum
222  {
223  DEFAULT_BAUD = 19200
224  };
225  // failures before closing port and throwing exception
226  enum
227  {
228  MAX_FAILS_BEFORE_DEAD = 5
229  };
230  // how many retries on a given message
231  enum
232  {
233  RETRIES = 3
234  };
235  enum
236  {
237  ROUGH_SPEED_OF_SOUND = 1500
238  }; // m/s
239 
240  // seconds to wait for modem to respond
241  static const boost::posix_time::time_duration MODEM_WAIT;
242  // seconds to wait after modem reboot
243  static const boost::posix_time::time_duration WAIT_AFTER_REBOOT;
244  // allowed time diff in millisecs between our clock and the modem clock
245  static const int ALLOWED_MS_DIFF;
246 
247  static const std::string SERIAL_DELIMITER;
248  // number of frames for a given packet type
249  static const unsigned PACKET_FRAME_COUNT[];
250  // size of packet (in bytes) for a given modem rate
251  static const unsigned PACKET_SIZE[];
252 
253  // all startup configuration (DriverConfig defined in acomms_driver_base.proto and extended in acomms_mm_driver.proto)
254  protobuf::DriverConfig driver_cfg_;
255 
256  // deque for outgoing messages to the modem, we queue them up and send
257  // as the modem acknowledges them
258  std::deque<util::NMEASentence> out_;
259 
260  // time of the last message written. we timeout and resend after MODEM_WAIT seconds
261  boost::posix_time::ptime last_write_time_;
262 
263  // are we waiting for a command ack (CA) from the modem or can we send another output?
264  bool waiting_for_modem_;
265 
266  // set after the startup routines finish once. we can't startup on instantiation because
267  // the base class sets some of our references (from the MOOS file)
268  bool startup_done_;
269 
270  // keeps track of number of failures and exits after reaching MAX_FAILS, assuming modem dead
271  unsigned global_fail_count_;
272 
273  // keeps track of number of failures on the present talker and moves on to the next talker
274  // if exceeded
275  unsigned present_fail_count_;
276 
277  // keeps track of clock mode, necessary for synchronous navigation
278  micromodem::protobuf::ClockMode clk_mode_;
279 
280  // has the clock been properly set. we must reset the clock after reboot ($CAREV,INIT)
281  bool clock_set_;
282 
283  enum TalkerIDs
284  {
285  TALKER_NOT_DEFINED = 0,
286  CA,
287  CC,
288  SN,
289  GP
290  };
291 
292  std::map<std::string, TalkerIDs> talker_id_map_;
293  std::map<std::string, SentenceIDs> sentence_id_map_;
294  std::map<std::string, std::string> description_map_;
295  std::map<std::string, std::string> cfg_map_;
296 
297  //
298  // stuff to deal with the non-standard Hydroid gateway buoy
299  //
300 
301  // length of #G1 or #M1
302  enum
303  {
304  HYDROID_GATEWAY_PREFIX_LENGTH = 3
305  };
306  // time between requests to the hydroid gateway buoy gps
307  static const boost::posix_time::time_duration HYDROID_GATEWAY_GPS_REQUEST_INTERVAL;
308  boost::posix_time::ptime last_hydroid_gateway_gps_request_;
309  bool is_hydroid_gateway_;
310  std::string hydroid_gateway_modem_prefix_;
311  std::string hydroid_gateway_gps_request_;
312 
313  // NVRAM parameters like SRC, DTO, PTO, etc.
314  std::map<std::string, int> nvram_cfg_;
315 
316  protobuf::ModemTransmission transmit_msg_;
317  unsigned
318  expected_remaining_caxst_; // used to determine how many CAXST to aggregate (so that bost rate 0 transmissions [CYC and TXD] are provided as a single logical unit)
319 
320  protobuf::ModemTransmission receive_msg_;
321  unsigned
322  expected_remaining_cacst_; // used to determine how many CACST to aggregate (so that rate 0 transmissions [CYC and RXD] are provided as a single logical unit)
323 
324  // keep track of which frames we've sent and are awaiting acks for. This
325  // way we have a chance of intercepting unexpected behavior of the modem
326  // relating to ACKs
327  std::set<unsigned> frames_waiting_for_ack_;
328 
329  // keep track of where we sent the message to be acked to work around a bug in
330  // the MM1 firmware that reports third-party acks with a destination of the local modem
331  unsigned expected_ack_destination_;
332 
333  std::set<unsigned> frames_waiting_to_receive_;
334 
335  // true if we initiated the last cycle ($CCCYC) (and thereby cache data for it)?
336  // false if a third party initiated the last cycle
337  bool local_cccyc_;
338 
339  micromodem::protobuf::TransmissionType last_lbl_type_;
340 
341  double last_keep_alive_time_;
342 
343  struct MMRevision
344  {
345  MMRevision() : mm_major(0), mm_minor(0), mm_patch(0) {}
346  int mm_major;
347  int mm_minor;
348  int mm_patch;
349  };
350  MMRevision revision_;
351 
352  bool using_application_acks_;
353  int application_ack_max_frames_;
354  int next_frame_;
355 
356  // modem id to frames
357  std::map<unsigned, std::set<unsigned> > frames_to_ack_;
358 
359  dccl::Codec dccl_;
360 
361  int serial_fd_;
362 };
363 } // namespace acomms
364 } // namespace goby
365 #endif
void shutdown()
Stops the driver.
Definition: mm_driver.cpp:450
MMDriver()
Default constructor.
Definition: mm_driver.cpp:65
int clk_mode()
Current clock mode of the modem, necessary for synchronous navigation.
Definition: mm_driver.h:66
google::protobuf::uint32 uint32
an unsigned 32 bit integer
void handle_initiate_transmission(const protobuf::ModemTransmission &m)
See ModemDriverBase::handle_initiate_transmission()
Definition: mm_driver.cpp:521
provides an API to the WHOI Micro-Modem driver
Definition: mm_driver.h:41
void do_work()
See ModemDriverBase::do_work()
Definition: mm_driver.cpp:463
~MMDriver()
Destructor.
Definition: mm_driver.cpp:457
The global namespace for the Goby project.
provides an abstract base class for acoustic modem drivers. This is subclassed by the various drivers...
Definition: driver_base.h:47
void startup(const protobuf::DriverConfig &cfg)
Starts the driver.
Definition: mm_driver.cpp:76
void update_cfg(const protobuf::DriverConfig &cfg)
Update configuration while running (not required to be implemented)
Definition: mm_driver.cpp:192