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