interface.cpp
Go to the documentation of this file.
1 
9 /*
10  * libmavconn
11  * Copyright 2013,2014,2015,2016 Vladimir Ermakov, All rights reserved.
12  *
13  * This file is part of the mavros package and subject to the license terms
14  * in the top-level LICENSE file of the mavros repository.
15  * https://github.com/mavlink/mavros/tree/master/LICENSE.md
16  */
17 
18 #include <set>
19 #include <cassert>
20 
22 #include <mavconn/interface.h>
23 #include <mavconn/msgbuffer.h>
24 #include <mavconn/serial.h>
25 #include <mavconn/udp.h>
26 #include <mavconn/tcp.h>
27 
28 namespace mavconn {
29 #define PFX "mavconn: "
30 
31 using mavlink::mavlink_message_t;
32 using mavlink::mavlink_status_t;
33 
34 // static members
35 std::once_flag MAVConnInterface::init_flag;
36 std::unordered_map<mavlink::msgid_t, const mavlink::mavlink_msg_entry_t*> MAVConnInterface::message_entries {};
37 std::atomic<size_t> MAVConnInterface::conn_id_counter {0};
38 
39 
40 MAVConnInterface::MAVConnInterface(uint8_t system_id, uint8_t component_id) :
41  sys_id(system_id),
42  comp_id(component_id),
43  m_parse_status {},
44  m_buffer {},
46  tx_total_bytes(0),
47  rx_total_bytes(0),
50  last_iostat(steady_clock::now())
51 {
52  conn_id = conn_id_counter.fetch_add(1);
53  std::call_once(init_flag, init_msg_entry);
54 }
55 
57 {
58  return m_mavlink_status;
59 }
60 
62 {
63  std::lock_guard<std::recursive_mutex> lock(iostat_mutex);
64  IOStat stat;
65 
68 
69  auto d_tx = stat.tx_total_bytes - last_tx_total_bytes;
70  auto d_rx = stat.rx_total_bytes - last_rx_total_bytes;
73 
74  auto now = steady_clock::now();
75  auto dt = now - last_iostat;
76  last_iostat = now;
77 
78  float dt_s = std::chrono::duration_cast<std::chrono::seconds>(dt).count();
79 
80  stat.tx_speed = d_tx / dt_s;
81  stat.rx_speed = d_rx / dt_s;
82 
83  return stat;
84 }
85 
87 {
88  tx_total_bytes += bytes;
89 }
90 
92 {
93  rx_total_bytes += bytes;
94 }
95 
96 void MAVConnInterface::parse_buffer(const char *pfx, uint8_t *buf, const size_t bufsize, size_t bytes_received)
97 {
98  mavlink::mavlink_message_t message;
99 
100  assert(bufsize >= bytes_received);
101 
102  iostat_rx_add(bytes_received);
103  for (; bytes_received > 0; bytes_received--) {
104  auto c = *buf++;
105 
106  auto msg_received = static_cast<Framing>(mavlink::mavlink_frame_char_buffer(&m_buffer, &m_parse_status, c, &message, &m_mavlink_status));
107 
108  if (msg_received != Framing::incomplete) {
109  log_recv(pfx, message, msg_received);
110 
112  message_received_cb(&message, msg_received);
113  }
114  }
115 }
116 
117 void MAVConnInterface::log_recv(const char *pfx, mavlink_message_t &msg, Framing framing)
118 {
119  const char *framing_str = (framing == Framing::ok) ? "OK" :
120  (framing == Framing::bad_crc) ? "!CRC" :
121  (framing == Framing::bad_signature) ? "!SIG" : "ERR";
122 
123  const char *proto_version_str = (msg.magic == MAVLINK_STX) ? "v2.0" : "v1.0";
124 
125  CONSOLE_BRIDGE_logDebug("%s%zu: recv: %s %4s Message-Id: %u [%u bytes] IDs: %u.%u Seq: %u",
126  pfx, conn_id,
127  proto_version_str,
128  framing_str,
129  msg.msgid, msg.len, msg.sysid, msg.compid, msg.seq);
130 }
131 
132 void MAVConnInterface::log_send(const char *pfx, const mavlink_message_t *msg)
133 {
134  const char *proto_version_str = (msg->magic == MAVLINK_STX) ? "v2.0" : "v1.0";
135 
136  CONSOLE_BRIDGE_logDebug("%s%zu: send: %s Message-Id: %u [%u bytes] IDs: %u.%u Seq: %u",
137  pfx, conn_id,
138  proto_version_str,
139  msg->msgid, msg->len, msg->sysid, msg->compid, msg->seq);
140 }
141 
142 void MAVConnInterface::log_send_obj(const char *pfx, const mavlink::Message &msg)
143 {
144  CONSOLE_BRIDGE_logDebug("%s%zu: send: %s", pfx, conn_id, msg.to_yaml().c_str());
145 }
146 
147 void MAVConnInterface::send_message_ignore_drop(const mavlink::mavlink_message_t *msg)
148 {
149  try {
150  send_message(msg);
151  }
152  catch (std::length_error &e) {
153  CONSOLE_BRIDGE_logError(PFX "%zu: DROPPED Message-Id %u [%u bytes] IDs: %u.%u Seq: %u: %s",
154  conn_id,
155  msg->msgid, msg->len, msg->sysid, msg->compid, msg->seq,
156  e.what());
157  }
158 }
159 
160 void MAVConnInterface::send_message_ignore_drop(const mavlink::Message &msg, uint8_t source_compid)
161 {
162  try {
163  send_message(msg, source_compid);
164  }
165  catch (std::length_error &e) {
166  CONSOLE_BRIDGE_logError(PFX "%zu: DROPPED Message %s: %s",
167  conn_id,
168  msg.get_name().c_str(),
169  e.what());
170  }
171 }
172 
174 {
175  if (pver == Protocol::V10) {
178 
179  }
180  else {
183  }
184 }
185 
187 {
189  return Protocol::V10;
190  else
191  return Protocol::V20;
192 }
193 
197 static void url_parse_host(std::string host,
198  std::string &host_out, int &port_out,
199  const std::string def_host, const int def_port)
200 {
201  std::string port;
202 
203  auto sep_it = std::find(host.begin(), host.end(), ':');
204  if (sep_it == host.end()) {
205  // host
206  if (!host.empty()) {
207  host_out = host;
208  port_out = def_port;
209  }
210  else {
211  host_out = def_host;
212  port_out = def_port;
213  }
214  return;
215  }
216 
217  if (sep_it == host.begin()) {
218  // :port
219  host_out = def_host;
220  }
221  else {
222  // host:port
223  host_out.assign(host.begin(), sep_it);
224  }
225 
226  port.assign(sep_it + 1, host.end());
227  port_out = std::stoi(port);
228 }
229 
233 static void url_parse_query(std::string query, uint8_t &sysid, uint8_t &compid)
234 {
235  const std::string ids_end("ids=");
236  std::string sys, comp;
237 
238  if (query.empty())
239  return;
240 
241  auto ids_it = std::search(query.begin(), query.end(),
242  ids_end.begin(), ids_end.end());
243  if (ids_it == query.end()) {
244  CONSOLE_BRIDGE_logWarn(PFX "URL: unknown query arguments");
245  return;
246  }
247 
248  std::advance(ids_it, ids_end.length());
249  auto comma_it = std::find(ids_it, query.end(), ',');
250  if (comma_it == query.end()) {
251  CONSOLE_BRIDGE_logError(PFX "URL: no comma in ids= query");
252  return;
253  }
254 
255  sys.assign(ids_it, comma_it);
256  comp.assign(comma_it + 1, query.end());
257 
258  sysid = std::stoi(sys);
259  compid = std::stoi(comp);
260 
261  CONSOLE_BRIDGE_logDebug(PFX "URL: found system/component id = [%u, %u]", sysid, compid);
262 }
263 
265  std::string path, std::string query,
266  uint8_t system_id, uint8_t component_id, bool hwflow)
267 {
268  std::string file_path;
269  int baudrate;
270 
271  // /dev/ttyACM0:57600
273  url_parse_query(query, system_id, component_id);
274 
275  return std::make_shared<MAVConnSerial>(system_id, component_id,
276  file_path, baudrate, hwflow);
277 }
278 
280  std::string hosts, std::string query,
281  uint8_t system_id, uint8_t component_id, bool is_udpb, bool permanent_broadcast)
282 {
283  std::string bind_pair, remote_pair;
284  std::string bind_host, remote_host;
285  int bind_port, remote_port;
286 
287  auto sep_it = std::find(hosts.begin(), hosts.end(), '@');
288  if (sep_it == hosts.end()) {
289  CONSOLE_BRIDGE_logError(PFX "UDP URL should contain @!");
290  throw DeviceError("url", "UDP separator not found");
291  }
292 
293  bind_pair.assign(hosts.begin(), sep_it);
294  remote_pair.assign(sep_it + 1, hosts.end());
295 
296  // udp://0.0.0.0:14555@:14550
297  url_parse_host(bind_pair, bind_host, bind_port, "0.0.0.0", MAVConnUDP::DEFAULT_BIND_PORT);
298  url_parse_host(remote_pair, remote_host, remote_port, MAVConnUDP::DEFAULT_REMOTE_HOST, MAVConnUDP::DEFAULT_REMOTE_PORT);
299  url_parse_query(query, system_id, component_id);
300 
301  if (is_udpb)
303 
304  return std::make_shared<MAVConnUDP>(system_id, component_id,
305  bind_host, bind_port,
306  remote_host, remote_port);
307 }
308 
310  std::string host, std::string query,
311  uint8_t system_id, uint8_t component_id)
312 {
313  std::string server_host;
314  int server_port;
315 
316  // tcp://localhost:5760
317  url_parse_host(host, server_host, server_port, "localhost", 5760);
318  url_parse_query(query, system_id, component_id);
319 
320  return std::make_shared<MAVConnTCPClient>(system_id, component_id,
321  server_host, server_port);
322 }
323 
325  std::string host, std::string query,
326  uint8_t system_id, uint8_t component_id)
327 {
328  std::string bind_host;
329  int bind_port;
330 
331  // tcp-l://0.0.0.0:5760
332  url_parse_host(host, bind_host, bind_port, "0.0.0.0", 5760);
333  url_parse_query(query, system_id, component_id);
334 
335  return std::make_shared<MAVConnTCPServer>(system_id, component_id,
336  bind_host, bind_port);
337 }
338 
340  std::string url,
341  uint8_t system_id,
342  uint8_t component_id)
343 {
344  /* Based on code found here:
345  * http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform
346  */
347 
348  const std::string proto_end("://");
349  std::string proto;
350  std::string host;
351  std::string path;
352  std::string query;
353 
354  auto proto_it = std::search(
355  url.begin(), url.end(),
356  proto_end.begin(), proto_end.end());
357  if (proto_it == url.end()) {
358  // looks like file path
359  CONSOLE_BRIDGE_logDebug(PFX "URL: %s: looks like file path", url.c_str());
360  return url_parse_serial(url, "", system_id, component_id, false);
361  }
362 
363  // copy protocol
364  proto.reserve(std::distance(url.begin(), proto_it));
365  std::transform(url.begin(), proto_it,
366  std::back_inserter(proto),
367  std::ref(tolower));
368 
369  // copy host
370  std::advance(proto_it, proto_end.length());
371  auto path_it = std::find(proto_it, url.end(), '/');
372  std::transform(proto_it, path_it,
373  std::back_inserter(host),
374  std::ref(tolower));
375 
376  // copy path, and query if exists
377  auto query_it = std::find(path_it, url.end(), '?');
378  path.assign(path_it, query_it);
379  if (query_it != url.end())
380  ++query_it;
381  query.assign(query_it, url.end());
382 
383  CONSOLE_BRIDGE_logDebug(PFX "URL: %s: proto: %s, host: %s, path: %s, query: %s",
384  url.c_str(), proto.c_str(), host.c_str(),
385  path.c_str(), query.c_str());
386 
387  MAVConnInterface::Ptr interface_ptr;
388 
389  if (proto == "udp")
390  interface_ptr = url_parse_udp(host, query, system_id, component_id, false, false);
391  else if (proto == "udp-b")
392  interface_ptr = url_parse_udp(host, query, system_id, component_id, true, false);
393  else if (proto == "udp-pb")
394  interface_ptr = url_parse_udp(host, query, system_id, component_id, true, true);
395  else if (proto == "tcp")
396  interface_ptr = url_parse_tcp_client(host, query, system_id, component_id);
397  else if (proto == "tcp-l")
398  interface_ptr = url_parse_tcp_server(host, query, system_id, component_id);
399  else if (proto == "serial")
400  interface_ptr = url_parse_serial(path, query, system_id, component_id, false);
401  else if (proto == "serial-hwfc")
402  interface_ptr = url_parse_serial(path, query, system_id, component_id, true);
403  else
404  throw DeviceError("url", "Unknown URL type");
405 
406  return interface_ptr;
407 }
408 
410  std::string url,
411  uint8_t system_id,
412  uint8_t component_id,
413  const ReceivedCb &cb_handle_message,
414  const ClosedCb &cb_handle_closed_port)
415 {
416  auto interface_ptr = open_url_no_connect(url, system_id, component_id);
417  if (interface_ptr)
418  {
419  if (!cb_handle_message)
420  {
421  CONSOLE_BRIDGE_logWarn(PFX "You did not provide message handling callback to open_url(), it is unsafe to set it later.");
422  }
423  interface_ptr->connect(cb_handle_message, cb_handle_closed_port);
424  }
425 
426  return interface_ptr;
427 
428 }
429 
430 } // namespace mavconn
virtual void send_message(const mavlink::mavlink_message_t *message)=0
Send message (mavlink_message_t)
mavlink::mavlink_status_t m_mavlink_status
Definition: interface.h:301
virtual mavlink::mavlink_status_t get_status()
Definition: interface.cpp:56
float rx_speed
current receive speed [B/s]
Definition: interface.h:112
void log_send(const char *pfx, const mavlink::mavlink_message_t *msg)
Definition: interface.cpp:132
void parse_buffer(const char *pfx, uint8_t *buf, const size_t bufsize, size_t bytes_received)
Definition: interface.cpp:96
static void init_msg_entry()
static std::once_flag init_flag
init_msg_entry() once flag
Definition: interface.h:312
std::function< void(const mavlink::mavlink_message_t *message, const Framing framing)> ReceivedCb
Definition: interface.h:102
#define CONSOLE_BRIDGE_logWarn(fmt,...)
void send_message_ignore_drop(const mavlink::mavlink_message_t *message)
Send message and ignore possible drop due to Tx queue limit.
Definition: interface.cpp:147
Common exception for communication error.
Definition: interface.h:64
static MAVConnInterface::Ptr url_parse_tcp_client(std::string host, std::string query, uint8_t system_id, uint8_t component_id)
Definition: interface.cpp:309
static constexpr auto DEFAULT_BIND_PORT
Definition: udp.h:35
#define CONSOLE_BRIDGE_logDebug(fmt,...)
void log_send_obj(const char *pfx, const mavlink::Message &msg)
Definition: interface.cpp:142
ReceivedCb message_received_cb
Message receive callback.
Definition: interface.h:200
std::chrono::time_point< steady_clock > last_iostat
Definition: interface.h:306
float tx_speed
current transfer speed [B/s]
Definition: interface.h:111
static MAVConnInterface::Ptr url_parse_serial(std::string path, std::string query, uint8_t system_id, uint8_t component_id, bool hwflow)
Definition: interface.cpp:264
MAVConn class interface.
static void url_parse_host(std::string host, std::string &host_out, int &port_out, const std::string def_host, const int def_port)
Definition: interface.cpp:197
void iostat_tx_add(size_t bytes)
Definition: interface.cpp:86
static std::unordered_map< mavlink::msgid_t, const mavlink::mavlink_msg_entry_t * > message_entries
This map merge all dialect mavlink_msg_entry_t structs. Needed for packet parser. ...
Definition: interface.h:271
std::function< void(void)> ClosedCb
Definition: interface.h:103
size_t conn_id
Channel number used for logging.
Definition: interface.h:274
#define CONSOLE_BRIDGE_logError(fmt,...)
static constexpr auto BROADCAST_REMOTE_HOST
Markers for broadcast modes. Not valid domain names.
Definition: udp.h:39
MAVConn message buffer class (internal)
MAVConn Serial link class.
static constexpr auto DEFAULT_DEVICE
Definition: serial.h:32
static constexpr auto DEFAULT_REMOTE_PORT
Definition: udp.h:37
static MAVConnInterface::Ptr url_parse_udp(std::string hosts, std::string query, uint8_t system_id, uint8_t component_id, bool is_udpb, bool permanent_broadcast)
Definition: interface.cpp:279
virtual IOStat get_iostat()
Definition: interface.cpp:61
MAVConnInterface(const MAVConnInterface &)=delete
mavlink::mavlink_message_t m_buffer
Definition: interface.h:300
std::atomic< size_t > rx_total_bytes
Definition: interface.h:303
size_t rx_total_bytes
total bytes received
Definition: interface.h:110
size_t tx_total_bytes
total bytes transferred
Definition: interface.h:109
MAVConn console-bridge compatibility header.
static constexpr auto PERMANENT_BROADCAST_REMOTE_HOST
Definition: udp.h:40
Protocol get_protocol_version()
Definition: interface.cpp:186
static constexpr auto DEFAULT_BAUDRATE
Definition: serial.h:33
static std::atomic< size_t > conn_id_counter
monotonic counter (increment only)
Definition: interface.h:309
void set_protocol_version(Protocol pver)
Definition: interface.cpp:173
mavlink::mavlink_status_t m_parse_status
Definition: interface.h:299
#define PFX
Definition: interface.cpp:29
void iostat_rx_add(size_t bytes)
Definition: interface.cpp:91
Protocol
MAVLink protocol version.
Definition: interface.h:56
static Ptr open_url_no_connect(std::string url, uint8_t system_id=1, uint8_t component_id=MAV_COMP_ID_UDP_BRIDGE)
version of open_url() which do not perform connect()
Definition: interface.cpp:339
static void url_parse_query(std::string query, uint8_t &sysid, uint8_t &compid)
Definition: interface.cpp:233
static constexpr auto DEFAULT_REMOTE_HOST
Definition: udp.h:36
static Ptr open_url(std::string url, uint8_t system_id=1, uint8_t component_id=MAV_COMP_ID_UDP_BRIDGE, const ReceivedCb &cb_handle_message=ReceivedCb(), const ClosedCb &cb_handle_closed_port=ClosedCb())
Construct connection from URL.
Definition: interface.cpp:409
std::recursive_mutex iostat_mutex
Definition: interface.h:304
static MAVConnInterface::Ptr url_parse_tcp_server(std::string host, std::string query, uint8_t system_id, uint8_t component_id)
Definition: interface.cpp:324
void log_recv(const char *pfx, mavlink::mavlink_message_t &msg, Framing framing)
Definition: interface.cpp:117
std::atomic< size_t > tx_total_bytes
Definition: interface.h:303
Framing
Rx packer framing status. (same as mavlink::mavlink_framing_t)
Definition: interface.h:48
std::shared_ptr< MAVConnInterface > Ptr
Definition: interface.h:104


libmavconn
Author(s): Vladimir Ermakov
autogenerated on Tue Jun 13 2023 02:17:45