Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
moos_translator.h
Go to the documentation of this file.
1// Copyright 2011-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//
8//
9// This file is part of the Goby Underwater Autonomy Project Libraries
10// ("The Goby Libraries").
11//
12// The Goby Libraries are free software: you can redistribute them and/or modify
13// them under the terms of the GNU Lesser General Public License as published by
14// the Free Software Foundation, either version 2.1 of the License, or
15// (at your option) any later version.
16//
17// The Goby Libraries are distributed in the hope that they will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Lesser General Public License for more details.
21//
22// You should have received a copy of the GNU Lesser General Public License
23// along with Goby. If not, see <http://www.gnu.org/licenses/>.
24
25#ifndef GOBY_MOOS_MOOS_TRANSLATOR_H
26#define GOBY_MOOS_MOOS_TRANSLATOR_H
27
28#include <limits> // for numeric_limits
29#include <map> // for map, multimap
30#include <mutex> // for lock_guard, mutex
31#include <ostream> // for operator<<, bas...
32#include <set> // for set
33#include <stdexcept> // for runtime_error
34#include <string> // for basic_string
35#include <utility> // for pair, make_pair
36#include <vector> // for vector
37
38#include <MOOS/libMOOS/Comms/MOOSMsg.h> // for CMOOSMsg, MOOS_...
39#include <MOOS/libMOOS/Utils/MOOSUtilityFunctions.h> // for MOOSTime
40#include <boost/lexical_cast.hpp> // for lexical_cast
41#include <boost/lexical_cast/bad_lexical_cast.hpp> // for bad_lexical_cast
42#include <google/protobuf/descriptor.h> // for Descriptor
43#include <google/protobuf/message.h> // for Message
44
45#include "dccl/dynamic_protobuf_manager.h" // for DynamicProtobuf...
46#include "goby/moos/modem_id_convert.h" // for ModemIdConvert
47#include "goby/moos/moos_protobuf_helpers.h" // for MOOSTranslation
48#include "goby/moos/protobuf/translator.pb.h" // for TranslatorEntry
49#include "goby/util/as.h" // for as
50#include "moos_geodesy.h" // for CMOOSGeodesy
51
52namespace goby
53{
54namespace moos
55{
56namespace transitional
57{
58class DCCLMessageVal;
59} // namespace transitional
60
63
64// applied to "T" (temperature), references are "S" (salinity), then "D" (depth)
66 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
67
68// ref_vals subtracted from val
70 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
71
72// ref_vals added to val
74 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
75
78
81
85
87
90
92{
93 public:
96 double lat_origin = std::numeric_limits<double>::quiet_NaN(),
97 double lon_origin = std::numeric_limits<double>::quiet_NaN(),
98 const std::string& modem_id_lookup_path = "")
99 {
100 initialize(lat_origin, lon_origin, modem_id_lookup_path);
101 if (entry.IsInitialized())
102 add_entry(entry);
103 }
104
107 double lat_origin = std::numeric_limits<double>::quiet_NaN(),
108 double lon_origin = std::numeric_limits<double>::quiet_NaN(),
109 const std::string& modem_id_lookup_path = "")
110 {
111 initialize(lat_origin, lon_origin, modem_id_lookup_path);
112 add_entry(entries);
113 }
114
115 void clear_entry(const std::string& protobuf_name) { dictionary_.erase(protobuf_name); }
116
118 {
119 if (dictionary_.count(entry.protobuf_name()))
120 throw(std::runtime_error("Duplicate translator entry for " + entry.protobuf_name()));
121 dictionary_[entry.protobuf_name()] = entry;
122 }
123
124 void add_entry(const std::set<goby::moos::protobuf::TranslatorEntry>& entries)
125 {
126 for (const auto& entry : entries) { add_entry(entry); }
127 }
128
131 {
132 for (const auto& entry : entries) { add_entry(entry); }
133 }
134
135 // ownership of returned pointer goes to caller (must use smart pointer or call delete)
136 template <typename GoogleProtobufMessagePointer, class StringCMOOSMsgMap>
137 GoogleProtobufMessagePointer moos_to_protobuf(const StringCMOOSMsgMap& moos_variables,
138 const std::string& protobuf_name);
139
140 std::multimap<std::string, CMOOSMsg>
141 protobuf_to_moos(const google::protobuf::Message& protobuf_msg);
142
143 // advanced: writes to create, instead of publish!
144 std::multimap<std::string, CMOOSMsg>
146
147 const std::map<std::string, goby::moos::protobuf::TranslatorEntry>& dictionary() const
148 {
149 return dictionary_;
150 }
151
152 static CMOOSMsg
153 make_moos_msg(const std::string& var, const std::string& str, bool is_binary,
155 const std::string& pb_name)
156 {
157 if (is_binary)
158 {
159 CMOOSMsg moos_msg(MOOS_NOTIFY, var, str.size(), str.data());
160 moos_msg.SetSourceAux(
161 pb_name + ":" +
163 return moos_msg;
164 }
165 else
166 {
167 try
168 {
169 auto return_double = boost::lexical_cast<double>(str);
170 return CMOOSMsg(MOOS_NOTIFY, var, return_double);
171 }
172 catch (boost::bad_lexical_cast&)
173 {
174 CMOOSMsg moos_msg(MOOS_NOTIFY, var, str);
175 moos_msg.SetSourceAux(
176 pb_name + ":" +
178 technique));
179 return moos_msg;
180 }
181 }
182 }
183
184 void update_utm_datum(double lat_origin, double lon_origin);
185
186 private:
187 void initialize(double lat_origin = std::numeric_limits<double>::quiet_NaN(),
188 double lon_origin = std::numeric_limits<double>::quiet_NaN(),
189 const std::string& modem_id_lookup_path = "");
190
191 void alg_lat2utm_y(moos::transitional::DCCLMessageVal& mv,
192 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
193
194 void alg_lon2utm_x(moos::transitional::DCCLMessageVal& mv,
195 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
196
197 void alg_utm_x2lon(moos::transitional::DCCLMessageVal& mv,
198 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
199
200 void alg_utm_y2lat(moos::transitional::DCCLMessageVal& mv,
201 const std::vector<moos::transitional::DCCLMessageVal>& ref_vals);
202
203 void alg_modem_id2name(moos::transitional::DCCLMessageVal& in);
204 void alg_modem_id2type(moos::transitional::DCCLMessageVal& in);
205 void alg_name2modem_id(moos::transitional::DCCLMessageVal& in);
206
207 private:
208 std::map<std::string, goby::moos::protobuf::TranslatorEntry> dictionary_;
209 CMOOSGeodesy geodesy_;
210 goby::moos::ModemIdConvert modem_lookup_;
211};
212
213inline std::ostream& operator<<(std::ostream& os, const MOOSTranslator& tl)
214{
215 os << "= Begin MOOSTranslator =\n";
216
217 int i = 0;
218 for (const auto& it : tl.dictionary())
219 {
220 os << "== Begin Entry " << i << " ==\n"
221 << it.second.DebugString() << "== End Entry " << i << " ==\n";
222
223 ++i;
224 }
225
226 os << "= End MOOSTranslator =";
227 return os;
228}
229
230namespace protobuf
231{
232inline bool operator<(const protobuf::TranslatorEntry& a, const protobuf::TranslatorEntry& b)
233{
234 return a.protobuf_name() < b.protobuf_name();
235}
236} // namespace protobuf
237
238} // namespace moos
239} // namespace goby
240
241inline std::multimap<std::string, CMOOSMsg>
243{
244 std::map<std::string, goby::moos::protobuf::TranslatorEntry>::const_iterator it =
245 dictionary_.find(protobuf_msg.GetDescriptor()->full_name());
246
247 const std::string& pb_name = protobuf_msg.GetDescriptor()->full_name();
248
249 if (it == dictionary_.end())
250 throw(std::runtime_error("No TranslatorEntry for Protobuf type: " + pb_name));
251
252 const goby::moos::protobuf::TranslatorEntry& entry = it->second;
253
254 std::multimap<std::string, CMOOSMsg> moos_msgs;
255
256 bool is_binary = false;
257
258 for (int i = 0, n = entry.publish_size(); i < n; ++i)
259 {
260 std::string return_string;
261 std::string moos_var = entry.publish(i).moos_var();
262
263 switch (entry.publish(i).technique())
264 {
268 serialize(&return_string, protobuf_msg);
269 break;
270
274 serialize(&return_string, protobuf_msg);
275 break;
276
280 serialize(&return_string, protobuf_msg);
281 break;
282
286 serialize(&return_string, protobuf_msg);
287 break;
288
292 serialize(&return_string, protobuf_msg);
293 is_binary = true;
294 break;
295
299 serialize(&return_string, protobuf_msg);
300 is_binary = true;
301 break;
302
306 serialize(&return_string, protobuf_msg, entry.publish(i).algorithm(),
307 entry.use_short_enum());
308 break;
309
311 // process moos_variable too (can be a format string itself!)
313 &moos_var, protobuf_msg, entry.publish(i).algorithm(),
314 entry.publish(i).moos_var(), entry.publish(i).repeated_delimiter(),
315 entry.use_short_enum());
316 // now do the format values
318 &return_string, protobuf_msg, entry.publish(i).algorithm(),
319 entry.publish(i).format(), entry.publish(i).repeated_delimiter(),
320 entry.use_short_enum());
321 break;
322 }
323
324 moos_msgs.insert(
325 std::make_pair(moos_var, make_moos_msg(moos_var, return_string, is_binary,
326 entry.publish(i).technique(), pb_name)));
327 }
328
329 return moos_msgs;
330}
331
332inline std::multimap<std::string, CMOOSMsg>
334{
335 std::map<std::string, goby::moos::protobuf::TranslatorEntry>::const_iterator it =
336 dictionary_.find(protobuf_msg.GetDescriptor()->full_name());
337
338 const std::string& pb_name = protobuf_msg.GetDescriptor()->full_name();
339
340 if (it == dictionary_.end())
341 throw(std::runtime_error("No TranslatorEntry for Protobuf type: " + pb_name));
342
343 const goby::moos::protobuf::TranslatorEntry& entry = it->second;
344
345 std::multimap<std::string, CMOOSMsg> moos_msgs;
346
347 bool is_binary = false;
348
349 for (int i = 0, n = entry.create_size(); i < n; ++i)
350 {
351 std::string return_string;
352 std::string moos_var = entry.create(i).moos_var();
353
354 switch (entry.create(i).technique())
355 {
359 serialize(&return_string, protobuf_msg);
360 break;
361
364 goby::moos::protobuf::TranslatorEntry::
365 TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT>::serialize(&return_string,
366 protobuf_msg);
367 break;
368
372 serialize(&return_string, protobuf_msg);
373 break;
374
378 serialize(&return_string, protobuf_msg);
379 break;
380
384 serialize(&return_string, protobuf_msg);
385 is_binary = true;
386 break;
387
390 goby::moos::protobuf::TranslatorEntry::
391 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED>::serialize(&return_string,
392 protobuf_msg);
393 is_binary = true;
394 break;
395
397 {
398 // workaround for bug in protobuf 2.3.0
401 empty_algorithms;
402
405 serialize(&return_string, protobuf_msg, empty_algorithms,
406 entry.use_short_enum());
407 }
408 break;
409
411 {
414 empty_algorithms;
415
417 &return_string, protobuf_msg, empty_algorithms, entry.create(i).format(),
418 entry.create(i).repeated_delimiter(), entry.use_short_enum());
419 }
420 break;
421 }
422
423 moos_msgs.insert(
424 std::make_pair(moos_var, make_moos_msg(moos_var, return_string, is_binary,
425 entry.create(i).technique(), pb_name)));
426 }
427
429 {
430 if (moos_msgs.count(entry.trigger().moos_var()))
431 {
432 // fake the trigger last so that all other inputs get read in first
433 typedef std::multimap<std::string, CMOOSMsg>::iterator It;
434 std::pair<It, It> p = moos_msgs.equal_range(entry.trigger().moos_var());
435 for (auto it = p.first; it != p.second; ++it) it->second.m_dfTime = MOOSTime();
436 }
437 else
438 {
439 // add a trigger
440 moos_msgs.insert(std::make_pair(entry.trigger().moos_var(),
441 CMOOSMsg(MOOS_NOTIFY, entry.trigger().moos_var(), "")));
442 }
443 }
444
445 return moos_msgs;
446}
447
448template <typename GoogleProtobufMessagePointer, class StringCMOOSMsgMap>
449GoogleProtobufMessagePointer
450goby::moos::MOOSTranslator::moos_to_protobuf(const StringCMOOSMsgMap& moos_variables,
451 const std::string& protobuf_name)
452{
453 std::map<std::string, goby::moos::protobuf::TranslatorEntry>::const_iterator it =
454 dictionary_.find(protobuf_name);
455
456 if (it == dictionary_.end())
457 throw(std::runtime_error("No TranslatorEntry for Protobuf type: " + protobuf_name));
458
459 const goby::moos::protobuf::TranslatorEntry& entry = it->second;
460
461 GoogleProtobufMessagePointer msg;
462
463 {
464 // dccl::DynamicProtobufManager appears not to be thread safe
465 const std::lock_guard<std::mutex> lock(goby::moos::dynamic_parse_mutex);
466 msg = dccl::DynamicProtobufManager::new_protobuf_message<GoogleProtobufMessagePointer>(
467 protobuf_name);
468 }
469
470 if (!msg)
471 throw(std::runtime_error("Unknown Protobuf type: " + protobuf_name +
472 "; be sure it is compiled in or directly loaded into the "
473 "dccl::DynamicProtobufManager."));
474
475 for (int i = 0, n = entry.create_size(); i < n; ++i)
476 {
477 auto it = moos_variables.find(entry.create(i).moos_var());
478 std::string source_string =
479 (it == moos_variables.end())
480 ? ""
481 : (it->second.IsString() ? it->second.GetString()
482 : goby::util::as<std::string>(it->second.GetDouble()));
483
484 switch (entry.create(i).technique())
485 {
489 &*msg);
490 break;
491
495 parse(source_string, &*msg);
496 break;
497
501 &*msg);
502 break;
503
507 parse(source_string, &*msg);
508 break;
509
513 parse(source_string, &*msg);
514 break;
515
519 parse(source_string, &*msg);
520 break;
521
525 parse(source_string, &*msg, entry.create(i).algorithm(),
526 entry.use_short_enum());
527 break;
528
531 source_string, &*msg, entry.create(i).format(),
532 entry.create(i).repeated_delimiter(), entry.create(i).algorithm(),
533 entry.use_short_enum());
534 break;
535 }
536 }
537
538 return msg;
539}
540
541#endif
static CMOOSMsg make_moos_msg(const std::string &var, const std::string &str, bool is_binary, goby::moos::protobuf::TranslatorEntry::ParserSerializerTechnique technique, const std::string &pb_name)
std::multimap< std::string, CMOOSMsg > protobuf_to_inverse_moos(const google::protobuf::Message &protobuf_msg)
void add_entry(const std::set< goby::moos::protobuf::TranslatorEntry > &entries)
MOOSTranslator(const goby::moos::protobuf::TranslatorEntry &entry=goby::moos::protobuf::TranslatorEntry(), double lat_origin=std::numeric_limits< double >::quiet_NaN(), double lon_origin=std::numeric_limits< double >::quiet_NaN(), const std::string &modem_id_lookup_path="")
std::multimap< std::string, CMOOSMsg > protobuf_to_moos(const google::protobuf::Message &protobuf_msg)
MOOSTranslator(const google::protobuf::RepeatedPtrField< goby::moos::protobuf::TranslatorEntry > &entries, double lat_origin=std::numeric_limits< double >::quiet_NaN(), double lon_origin=std::numeric_limits< double >::quiet_NaN(), const std::string &modem_id_lookup_path="")
void update_utm_datum(double lat_origin, double lon_origin)
void add_entry(const google::protobuf::RepeatedPtrField< goby::moos::protobuf::TranslatorEntry > &entries)
GoogleProtobufMessagePointer moos_to_protobuf(const StringCMOOSMsgMap &moos_variables, const std::string &protobuf_name)
const std::map< std::string, goby::moos::protobuf::TranslatorEntry > & dictionary() const
void add_entry(const goby::moos::protobuf::TranslatorEntry &entry)
void clear_entry(const std::string &protobuf_name)
::goby::moos::protobuf::TranslatorEntry_ParserSerializerTechnique technique() const
const ::goby::moos::protobuf::TranslatorEntry_CreateParser_Algorithm & algorithm(int index) const
const ::goby::moos::protobuf::TranslatorEntry_PublishSerializer_Algorithm & algorithm(int index) const
::goby::moos::protobuf::TranslatorEntry_ParserSerializerTechnique technique() const
::goby::moos::protobuf::TranslatorEntry_Trigger_Type type() const
const std::string & protobuf_name() const
static constexpr ParserSerializerTechnique TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX
static constexpr ParserSerializerTechnique TECHNIQUE_PROTOBUF_NATIVE_ENCODED
static constexpr ParserSerializerTechnique TECHNIQUE_FORMAT
static const std::string & ParserSerializerTechnique_Name(T enum_t_value)
static constexpr ParserSerializerTechnique TECHNIQUE_COMMA_SEPARATED_KEY_EQUALS_VALUE_PAIRS
static constexpr ParserSerializerTechnique TECHNIQUE_PROTOBUF_NATIVE_HEX
const ::goby::moos::protobuf::TranslatorEntry_PublishSerializer & publish(int index) const
const ::goby::moos::protobuf::TranslatorEntry_CreateParser & create(int index) const
static constexpr ParserSerializerTechnique TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED
static constexpr ParserSerializerTechnique TECHNIQUE_PROTOBUF_TEXT_FORMAT
const ::goby::moos::protobuf::TranslatorEntry_Trigger & trigger() const
static constexpr ParserSerializerTechnique TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT
const Descriptor * GetDescriptor() const
Definition message.h:357
Helpers for MOOS applications for serializing and parsed Google Protocol buffers messages.
void alg_lon2hemisphere_initial(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_to_upper(moos::transitional::DCCLMessageVal &val_to_mod)
std::mutex dynamic_parse_mutex
void alg_angle_0_360(moos::transitional::DCCLMessageVal &angle)
void alg_lon2nmea_lon(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_lat2hemisphere_initial(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_power_to_dB(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_angle_n180_180(moos::transitional::DCCLMessageVal &angle)
void alg_subtract(moos::transitional::DCCLMessageVal &val, const std::vector< moos::transitional::DCCLMessageVal > &ref_vals)
void alg_TSD_to_soundspeed(moos::transitional::DCCLMessageVal &val, const std::vector< moos::transitional::DCCLMessageVal > &ref_vals)
void alg_dB_to_power(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_abs(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_to_lower(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_lat2nmea_lat(moos::transitional::DCCLMessageVal &val_to_mod)
void alg_add(moos::transitional::DCCLMessageVal &val, const std::vector< moos::transitional::DCCLMessageVal > &ref_vals)
void alg_unix_time2nmea_time(moos::transitional::DCCLMessageVal &val_to_mod)
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