Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
mm_driver.h
Go to the documentation of this file.
1// Copyright 2009-2021:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7// Russ Webber <russ@rw.id.au>
8//
9//
10// This file is part of the Goby Underwater Autonomy Project Libraries
11// ("The Goby Libraries").
12//
13// The Goby Libraries are free software: you can redistribute them and/or modify
14// them under the terms of the GNU Lesser General Public License as published by
15// the Free Software Foundation, either version 2.1 of the License, or
16// (at your option) any later version.
17//
18// The Goby Libraries are distributed in the hope that they will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public License
24// along with Goby. If not, see <http://www.gnu.org/licenses/>.
25
26#ifndef GOBY_ACOMMS_MODEMDRIVER_MM_DRIVER_H
27#define GOBY_ACOMMS_MODEMDRIVER_MM_DRIVER_H
28
29#include <cstdint> // for uint32_t
30#include <deque> // for deque
31#include <map> // for map
32#include <memory> // for unique_ptr
33#include <mutex> // for mutex
34#include <set> // for set
35#include <string> // for string
36
37#include "driver_base.h" // for ModemDriverBase
38#include "goby/acomms/protobuf/driver_base.pb.h" // for DriverConfig
39#include "goby/acomms/protobuf/mm_driver.pb.h" // for Config, MessageT...
40#include "goby/acomms/protobuf/modem_message.pb.h" // for ModemTransmission
41#include "goby/time/system_clock.h" // for SystemClock, Sys...
42#include "goby/util/linebasedcomms/nmea_sentence.h" // for NMEASentence
43
44namespace dccl
45{
46class Codec;
47} // namespace dccl
48
49namespace goby
50{
51namespace acomms
52{
57{
58 public:
62 ~MMDriver() override;
63
67 void startup(const protobuf::DriverConfig& cfg) override;
68
69 void update_cfg(const protobuf::DriverConfig& cfg) override;
70
72 void shutdown() override;
73
75 void do_work() override;
76
79
81 int clk_mode() { return clk_mode_; }
82
83 bool is_started() const { return startup_done_; }
84
85 static unsigned packet_frame_count(int rate) { return PACKET_FRAME_COUNT[rate]; }
86
87 static unsigned packet_size(int rate) { return PACKET_SIZE[rate]; }
88
89 void set_silent(bool silent);
90 void write_single_cfg(const std::string& s); // write a single NVRAM value
91
92 private:
93 enum SentenceIDs
94 {
95 SENTENCE_NOT_DEFINED = 0,
96 ACK,
97 DRQ,
98 RXA,
99 RXD,
100 RXP,
101 TXD,
102 TXA,
103 TXP,
104 TXF,
105 CYC,
106 MPC,
107 MPA,
108 MPR,
109 RSP,
110 MSC,
111 MSA,
112 MSR,
113 EXL,
114 MEC,
115 MEA,
116 MER,
117 MUC,
118 MUA,
119 MUR,
120 PDT,
121 PNT,
122 TTA,
123 MFD,
124 CLK,
125 CFG,
126 AGC,
127 BBD,
128 CFR,
129 CST,
130 MSG,
131 REV,
132 DQF,
133 SHF,
134 SNR,
135 DOP,
136 DBG,
137 FFL,
138 FST,
139 ERR,
140 TOA,
141 XST,
142 RDP,
143 TDP,
144 TMS,
145 TMQ,
146 TMG,
147 SWP,
148 MSQ
149 };
150
151 // startup
152 void initialize_talkers(); // insert strings into sentence_id_map_, etc for later use
153 void set_clock(); // set the modem clock from the system (goby) clock
154 void write_cfg(); // write the NVRAM configuration values to the modem
155 void query_all_cfg(); // query the current NVRAM configuration of the modem
156 void set_hydroid_gateway_prefix(int id); // if using the hydroid gateway, set its id number
157
158 // output
159
160 void cccyc(protobuf::ModemTransmission* msg);
161 void ccmuc(protobuf::ModemTransmission* msg);
162 void cctdp(protobuf::ModemTransmission* msg);
163 void ccmpc(const protobuf::ModemTransmission& msg);
164 void ccpdt(const protobuf::ModemTransmission& msg);
165 void ccpnt(const protobuf::ModemTransmission& msg);
166 void ccmec(const protobuf::ModemTransmission& msg);
167 void ccpgt(const protobuf::ModemTransmission& msg);
168 void ccswp(const protobuf::ModemTransmission& msg);
169 void ccmsq(const protobuf::ModemTransmission& msg);
170
171 void try_send(); // try to send another NMEA message to the modem
172 void pop_out(); // pop the NMEA send deque upon successful NMEA acknowledgment
173 void cache_outgoing_data(protobuf::ModemTransmission* msg); // cache data upon a CCCYC
174 void append_to_write_queue(const util::NMEASentence& nmea); // add a message
175 void mm_write(const util::NMEASentence&
176 nmea); // actually write a message (appends hydroid prefix if needed)
177 void increment_present_fail();
178 void present_fail_exceeds_retries();
179
180 // input
181 void process_receive(
182 const util::NMEASentence& nmea); // parse a receive message and call proper method
183
184 // data cycle
185 void cacyc(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CACYC
186 void carxd(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CARXD
187 void camsg(const util::NMEASentence& nmea, protobuf::ModemTransmission* m);
188
189 void caack(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAACK
190 void handle_ack(std::uint32_t src, std::uint32_t dest, std::uint32_t frame,
192
193 // mini packet
194 void camua(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMUA
195
196 // flexible data protocol
197 void cardp(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CARDP
198
199 // ranging (pings)
200 void campr(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMPR
201 void campa(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMPA
202 void sntta(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $SNTTA
203
204 // hardware control
205 void camer(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAMER
206
207 // local modem
208 void caxst(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CAXST
209 void cacst(const util::NMEASentence& nmea, protobuf::ModemTransmission* msg); // $CACST
210 void carev(const util::NMEASentence& nmea); // $CAREV
211 void caerr(const util::NMEASentence& nmea); // $CAERR
212 void cacfg(const util::NMEASentence& nmea);
213 void receive_time(const util::NMEASentence& nmea, SentenceIDs sentence_id); // $CACLK
214 void catms(const util::NMEASentence& nmea); // $CATMS
215 void cadrq(const util::NMEASentence& nmea, const protobuf::ModemTransmission& m); // $CADRQ
216
217 void validate_transmission_start(const protobuf::ModemTransmission& message);
218
219 void signal_receive_and_clear(protobuf::ModemTransmission* message);
220
221 // application acks
222 void process_incoming_app_ack(protobuf::ModemTransmission* m);
223 void process_outgoing_app_ack(protobuf::ModemTransmission* msg);
224
225 // Serial port methods
226 void set_rts(bool state);
227
228 const micromodem::protobuf::Config& mm_driver_cfg() const
229 {
230 return driver_cfg_.GetExtension(micromodem::protobuf::config);
231 }
232
233 // doxygen
234
236 // \example acomms/chat/chat.cpp
237
238 private:
239 // for the serial connection ($CCCFG,BR1,3)
240 enum
241 {
242 DEFAULT_BAUD = 19200
243 };
244 // failures before closing port and throwing exception
245 enum
246 {
247 MAX_FAILS_BEFORE_DEAD = 5
248 };
249 // how many retries on a given message
250 enum
251 {
252 RETRIES = 3
253 };
254 enum
255 {
256 ROUGH_SPEED_OF_SOUND = 1500
257 }; // m/s
258
259 // time to wait for modem to respond
260 static const goby::time::SystemClock::duration MODEM_WAIT;
261 // time to wait for modem to respond
262 static const goby::time::SystemClock::duration MULTI_REPLY_WAIT;
263 // time to wait after modem reboot
264 static const goby::time::SystemClock::duration WAIT_AFTER_REBOOT;
265
266 static const std::string SERIAL_DELIMITER;
267 // number of frames for a given packet type
268 static const unsigned PACKET_FRAME_COUNT[];
269 // size of packet (in bytes) for a given modem rate
270 static const unsigned PACKET_SIZE[];
271
272 // all startup configuration (DriverConfig defined in acomms_driver_base.proto and extended in acomms_mm_driver.proto)
273 protobuf::DriverConfig driver_cfg_;
274
275 // deque for outgoing messages to the modem, we queue them up and send
276 // as the modem acknowledges them
277 std::deque<util::NMEASentence> out_;
278
279 // time of the last message written. we timeout and resend after MODEM_WAIT seconds
281
282 // are we waiting for a command ack (CA) from the modem or can we send another output?
283 bool waiting_for_modem_{false};
284
285 // are we waiting for a multi-message reply
286 bool waiting_for_multimsg_{false};
287
288 // set after the startup routines finish once. we can't startup on instantiation because
289 // the base class sets some of our references (from the MOOS file)
290 bool startup_done_{false};
291
292 // keeps track of number of failures and exits after reaching MAX_FAILS, assuming modem dead
293 unsigned global_fail_count_{0};
294
295 // keeps track of number of failures on the present talker and moves on to the next talker
296 // if exceeded
297 unsigned present_fail_count_{0};
298
299 // keeps track of clock mode, necessary for synchronous navigation
301
302 // has the clock been properly set. we must reset the clock after reboot ($CAREV,INIT)
303 bool clock_set_{false};
304
305 enum TalkerIDs
306 {
307 TALKER_NOT_DEFINED = 0,
308 CA,
309 CC,
310 SN,
311 GP
312 };
313
314 std::map<std::string, TalkerIDs> talker_id_map_;
315 std::map<std::string, SentenceIDs> sentence_id_map_;
316 std::map<std::string, std::string> description_map_;
317 std::map<std::string, std::string> cfg_map_;
318
319 //
320 // stuff to deal with the non-standard Hydroid gateway buoy
321 //
322
323 // length of #G1 or #M1
324 enum
325 {
326 HYDROID_GATEWAY_PREFIX_LENGTH = 3
327 };
328 // time between requests to the hydroid gateway buoy gps
329 static const goby::time::SystemClock::duration HYDROID_GATEWAY_GPS_REQUEST_INTERVAL;
330 goby::time::SystemClock::time_point last_hydroid_gateway_gps_request_;
331 bool is_hydroid_gateway_{false};
332 std::string hydroid_gateway_modem_prefix_;
333 std::string hydroid_gateway_gps_request_;
334
335 // NVRAM parameters like SRC, DTO, PTO, etc.
336 std::map<std::string, int> nvram_cfg_;
337
338 protobuf::ModemTransmission transmit_msg_;
339 unsigned expected_remaining_caxst_{
340 0}; // used to determine how many CAXST to aggregate (so that bost rate 0 transmissions [CYC and TXD] are provided as a single logical unit)
341
342 protobuf::ModemTransmission receive_msg_;
343 unsigned expected_remaining_cacst_{
344 0}; // used to determine how many CACST to aggregate (so that rate 0 transmissions [CYC and RXD] are provided as a single logical unit)
345
346 // keep track of which frames we've sent and are awaiting acks for. This
347 // way we have a chance of intercepting unexpected behavior of the modem
348 // relating to ACKs
349 std::set<unsigned> frames_waiting_for_ack_;
350
351 // keep track of where we sent the message to be acked to work around a bug in
352 // the MM1 firmware that reports third-party acks with a destination of the local modem
353 unsigned expected_ack_destination_{0};
354
355 std::set<unsigned> frames_waiting_to_receive_;
356
357 // true if we initiated the last cycle ($CCCYC) (and thereby cache data for it)?
358 // false if a third party initiated the last cycle
359 bool local_cccyc_{false};
360
362
363 goby::time::SystemClock::time_point last_keep_alive_time_;
364
365 // time of the last multi-message reply received. we timeout and pop after MULTI_REPLY_WAIT seconds
366 goby::time::SystemClock::time_point last_multimsg_rx_time_;
367
368 struct MMRevision
369 {
370 MMRevision() = default;
371 int mm_major{0};
372 int mm_minor{0};
373 int mm_patch{0};
374 };
375 MMRevision revision_;
376
377 bool using_application_acks_{false};
378 int application_ack_max_frames_{0};
379
380 // ids we are providing acks for, normally just our modem_id()
381 std::set<unsigned> application_ack_ids_;
382
383 int next_frame_{0};
384
385 // modem id to frames
386 std::map<unsigned, std::set<unsigned> > frames_to_ack_;
387
388 std::unique_ptr<dccl::Codec> dccl_;
389 // DCCL requires full memory barrier...
390 static std::mutex dccl_mutex_;
391};
392} // namespace acomms
393} // namespace goby
394#endif
provides an API to the WHOI Micro-Modem driver
Definition mm_driver.h:57
void startup(const protobuf::DriverConfig &cfg) override
Starts the driver.
void handle_initiate_transmission(const protobuf::ModemTransmission &m) override
See ModemDriverBase::handle_initiate_transmission()
void do_work() override
See ModemDriverBase::do_work()
bool is_started() const
Definition mm_driver.h:83
static unsigned packet_frame_count(int rate)
Definition mm_driver.h:85
void update_cfg(const protobuf::DriverConfig &cfg) override
Update configuration while running (not required to be implemented)
int clk_mode()
Current clock mode of the modem, necessary for synchronous navigation.
Definition mm_driver.h:81
void write_single_cfg(const std::string &s)
void set_silent(bool silent)
MMDriver()
Default constructor.
~MMDriver() override
Destructor.
static unsigned packet_size(int rate)
Definition mm_driver.h:87
void shutdown() override
Stops the driver.
provides an abstract base class for acoustic modem drivers. This is subclassed by the various drivers...
Definition driver_base.h:59
_proto_TypeTraits::Singular::ConstType GetExtension(const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< DriverConfig, _proto_TypeTraits, _field_type, _is_packed > &id) const
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::goby::acomms::protobuf::DriverConfig, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::acomms::micromodem::protobuf::Config >, 11, false > config
The global namespace for the Goby project.
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::PROTOBUF_NAMESPACE_ID::MessageOptions, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::GobyMessageOptions >, 11, false > msg
std::chrono::time_point< SystemClock > time_point
std::chrono::microseconds duration
Duration type.