Goby3  3.1.5
2024.05.14
iridium_driver_common.h
Go to the documentation of this file.
1 // Copyright 2015-2023:
2 // GobySoft, LLC (2013-)
3 // Community contributors (see AUTHORS file)
4 // File authors:
5 // Toby Schneider <toby@gobysoft.org>
6 //
7 //
8 // This file is part of the Goby Underwater Autonomy Project Libraries
9 // ("The Goby Libraries").
10 //
11 // The Goby Libraries are free software: you can redistribute them and/or modify
12 // them under the terms of the GNU Lesser General Public License as published by
13 // the Free Software Foundation, either version 2.1 of the License, or
14 // (at your option) any later version.
15 //
16 // The Goby Libraries are distributed in the hope that they will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public License
22 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
23 
24 #ifndef GOBY_ACOMMS_MODEMDRIVER_IRIDIUM_DRIVER_COMMON_H
25 #define GOBY_ACOMMS_MODEMDRIVER_IRIDIUM_DRIVER_COMMON_H
26 
27 #include <dccl/codec.h>
28 #include <dccl/field_codec_fixed.h>
29 #include <dccl/field_codec_manager.h>
30 
33 #include "goby/exception.h"
34 #include "goby/time/system_clock.h"
35 #include "goby/util/dccl_compat.h"
36 
37 namespace goby
38 {
39 namespace acomms
40 {
41 enum
42 {
44  RATE_SBD = 0
45 };
46 
48 {
51 };
52 
54 {
55  public:
57  : last_tx_time_(time::SystemClock::now().time_since_epoch() / std::chrono::seconds(1)),
58  last_rx_time_(0),
59  bye_received_(false),
60  bye_sent_(false),
61  total_bytes_sent_(0),
62  last_bytes_sent_(0)
63  {
64  }
65  double last_rx_tx_time() const { return std::max(last_tx_time_, last_rx_time_); }
66  double last_rx_time() const { return last_rx_time_; }
67  double last_tx_time() const { return last_tx_time_; }
68 
69  int last_bytes_sent() const { return last_bytes_sent_; }
70  int total_bytes_sent() const { return total_bytes_sent_; }
71 
72  void set_bye_received(bool b) { bye_received_ = b; }
73  void set_bye_sent(bool b) { bye_sent_ = b; }
74 
75  bool bye_received() const { return bye_received_; }
76  bool bye_sent() const { return bye_sent_; }
77 
78  void set_last_tx_time(double d) { last_tx_time_ = d; }
79  void set_last_rx_time(double d) { last_rx_time_ = d; }
80 
81  void set_last_bytes_sent(int i)
82  {
83  last_bytes_sent_ = i;
84  total_bytes_sent_ += i;
85  }
86 
87  private:
88  double last_tx_time_;
89  double last_rx_time_;
90  bool bye_received_;
91  bool bye_sent_;
92  int total_bytes_sent_;
93  int last_bytes_sent_;
94 };
95 
96 // placeholder id codec that uses no bits, since we're always sending just this message on the wire
97 class IridiumHeaderIdentifierCodec : public dccl::TypedFixedFieldCodec<std::uint32_t>
98 {
99  dccl::Bitset encode() { return dccl::Bitset(); }
100  dccl::Bitset encode(const std::uint32_t& wire_value) { return dccl::Bitset(); }
101  std::uint32_t decode(dccl::Bitset* bits) { return 0; }
102  virtual unsigned size() { return 0; }
103 };
104 
105 extern std::shared_ptr<dccl::Codec> iridium_header_dccl_;
106 
107 inline void init_iridium_dccl()
108 {
109  auto iridium_id_name = "iridium_header_id";
110 #ifdef DCCL_VERSION_4_1_OR_NEWER
111  iridium_header_dccl_.reset(new dccl::Codec(iridium_id_name, IridiumHeaderIdentifierCodec()));
112 #else
113  dccl::FieldCodecManager::add<IridiumHeaderIdentifierCodec>(iridium_id_name);
114  iridium_header_dccl_.reset(new dccl::Codec(iridium_id_name));
115 #endif
116  iridium_header_dccl_->load<goby::acomms::iridium::protobuf::IridiumHeader>();
117 }
118 
119 inline void serialize_iridium_modem_message(std::string* out,
120  const goby::acomms::protobuf::ModemTransmission& in)
121 {
122  goby::acomms::iridium::protobuf::IridiumHeader header;
123  header.set_src(in.src());
124  header.set_dest(in.dest());
125  if (in.has_rate())
126  header.set_rate(in.rate());
127  header.set_type(in.type());
128  if (in.has_ack_requested())
129  header.set_ack_requested(in.ack_requested());
130  if (in.has_frame_start())
131  header.set_frame_start(in.frame_start());
132  if (in.acked_frame_size())
133  header.set_acked_frame(in.acked_frame(0));
134 
135  iridium_header_dccl_->encode(out, header);
136  if (in.frame_size())
137  *out += in.frame(0);
138 }
139 
140 inline void parse_iridium_modem_message(std::string in,
141  goby::acomms::protobuf::ModemTransmission* out)
142 {
143  goby::acomms::iridium::protobuf::IridiumHeader header;
144  iridium_header_dccl_->decode(&in, &header);
145 
146  out->set_src(header.src());
147  out->set_dest(header.dest());
148  if (header.has_rate())
149  out->set_rate(header.rate());
150  out->set_type(header.type());
151  if (header.has_ack_requested())
152  out->set_ack_requested(header.ack_requested());
153  if (header.has_frame_start())
154  out->set_frame_start(header.frame_start());
155  if (header.has_acked_frame())
156  out->add_acked_frame(header.acked_frame());
157 
158  if (in.size())
159  out->add_frame(in);
160 }
161 
162 inline unsigned iridium_rate_to_bytes(int rate, iridium::protobuf::DeviceType device,
163  Direction direction)
164 {
165  if (rate == RATE_RUDICS)
166  {
168  throw(
169  goby::Exception("Must use device = DEVICE_VOICE_ENABLED_ISU for RUDICS support."));
170 
171  return 1500; // somewhat arbitrary choice as we're dealing with a stream protocol
172  }
173  else if (rate == RATE_SBD)
174  {
175  const auto head_bytes{goby::acomms::iridium::protobuf::IridiumHeader::descriptor()
176  ->options()
177  .GetExtension(dccl::msg)
178  .max_bytes()};
179 
180  const auto crc_bytes{goby::acomms::IRIDIUM_SBD_CRC_BYTE_SIZE};
181 
182  const auto overhead_bytes = head_bytes + crc_bytes;
183 
184  switch (direction)
185  {
187  // From ISU AT Command Reference
188  // The maximum mobile originated SBD message length is 1960 bytes for voice-enabled ISUs,
189  // 340 bytes for the 9602, 9602-SB, and 9603, and 205 bytes for the 9601. The minimum
190  // mobile originated SBD message length is 1 byte.
191  switch (device)
192  {
193  case iridium::protobuf::DEVICE_VOICE_ENABLED_ISU: return 1960 - overhead_bytes;
194  case iridium::protobuf::DEVICE_IRIDIUM_9602_9603: return 340 - overhead_bytes;
195  }
197  // For voice-enabled ISUs: The maximum mobile terminated SBD message length is 1890 bytes.
198  // For the 9602, 9602-SB, and 9603: The maximum mobile terminated SBD message length
199  // is limited by configuration in the Iridium network, normally to either 135 or 270 bytes
200  // (i.e. one or two segments). However the modem can receive SBD messages up to 1960 bytes.
201  switch (device)
202  {
203  case iridium::protobuf::DEVICE_VOICE_ENABLED_ISU: return 1890 - overhead_bytes;
205  return 270 -
206  overhead_bytes; // the user can limit this further if using a 1-segment configuration. RockBLOCK is 270B.
207  }
208  default: throw(goby::Exception("Invalid direction for the Iridium driver"));
209  }
210  }
211  else
212  {
213  throw(goby::Exception("Invalid rate " + std::to_string(rate) + " for the Iridium driver"));
214  }
215 }
216 
217 } // namespace acomms
218 } // namespace goby
219 
220 #endif
simple exception class for goby applications
Definition: exception.h:35
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.hpp:24301
unit< time_dimension, si::system > time
Definition: time.hpp:22
dccl::Bitset Bitset
Definition: dccl.h:126
constexpr int IRIDIUM_SBD_CRC_BYTE_SIZE
void serialize_iridium_modem_message(std::string *out, const goby::acomms::protobuf::ModemTransmission &in)
void parse_iridium_modem_message(std::string in, goby::acomms::protobuf::ModemTransmission *out)
std::shared_ptr< dccl::Codec > iridium_header_dccl_
unsigned iridium_rate_to_bytes(int rate, iridium::protobuf::DeviceType device, Direction direction)
The global namespace for the Goby project.
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::google::protobuf::MessageOptions, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::GobyMessageOptions >, 11, false > msg