0.4.1
Loading...
Searching...
No Matches
udp_port.cpp
Go to the documentation of this file.
1/****************************************************************************
2 *
3 * Copyright (c) 2018 MAVlink Development Team. All rights reserved.
4 * Author: Hannes Diethelm, <hannes.diethelm@gmail.com>
5 * Trent Lukaczyk, <aerialhedgehog@gmail.com>
6 * Jaycee Lock, <jaycee.lock@gmail.com>
7 * Lorenz Meier, <lm@inf.ethz.ch>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 * 3. Neither the name PX4 nor the names of its contributors may be
20 * used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 ****************************************************************************/
37
38/**
39 * @file udp_port.cpp
40 *
41 * @brief UDP interface functions
42 *
43 * Functions for opening, closing, reading and writing via UDP ports
44 *
45 * @author Hannes Diethelm, <hannes.diethelm@gmail.com>
46 * @author Trent Lukaczyk, <aerialhedgehog@gmail.com>
47 * @author Jaycee Lock, <jaycee.lock@gmail.com>
48 * @author Lorenz Meier, <lm@inf.ethz.ch>
49 *
50 */
51
52// ------------------------------------------------------------------------------
53// Includes
54// ------------------------------------------------------------------------------
55
56#if __linux__ || __APPLE__
57
58 #include "udp_port.hpp"
59 #include "util/Logger.hpp"
60
61// ----------------------------------------------------------------------------------
62// UDP Port Manager Class
63// ----------------------------------------------------------------------------------
64
65// ------------------------------------------------------------------------------
66// Con/De structors
67// ------------------------------------------------------------------------------
68UDP_Port::UDP_Port(const char* target_ip_, int udp_port_) : lastStatus(), lock(), buff(), target_ip(target_ip_), rx_port(udp_port_)
69{
70 initialize_defaults();
71}
72
73UDP_Port::UDP_Port()
74{
75 initialize_defaults();
76}
77
78UDP_Port::~UDP_Port()
79{
80 // destroy mutex
81 pthread_mutex_destroy(&lock);
82}
83
84void UDP_Port::initialize_defaults()
85{
86 // Start mutex
87 int result = pthread_mutex_init(&lock, nullptr);
88 if (result != 0)
89 {
90 LOG_DEBUG("Mavlink - udp_port.cpp: mutex init failed");
91 }
92}
93
94// ------------------------------------------------------------------------------
95// Read from UDP
96// ------------------------------------------------------------------------------
97int UDP_Port::read_message(mavlink_message_t& message)
98{
99 uint8_t cp{};
100 mavlink_status_t status;
101 uint8_t msgReceived = false;
102
103 // --------------------------------------------------------------------------
104 // READ FROM PORT
105 // --------------------------------------------------------------------------
106
107 // this function locks the port during read
108 int result = _read_port(cp);
109
110 // --------------------------------------------------------------------------
111 // PARSE MESSAGE
112 // --------------------------------------------------------------------------
113 if (result > 0)
114 {
115 // the parsing
116 msgReceived = mavlink_parse_char(MAVLINK_COMM_1, cp, &message, &status);
117
118 // check for dropped packets
119 if ((lastStatus.packet_rx_drop_count != status.packet_rx_drop_count) && debug)
120 {
121 // printf("ERROR: DROPPED %d PACKETS\n", status.packet_rx_drop_count);
122 LOG_ERROR("Mavlink - udp_port.cpp: DROPPED {} PACKETS\n", status.packet_rx_drop_count);
123 // unsigned char v = cp;
124 // fprintf(stderr, "%02x ", v);
125 }
126 lastStatus = status;
127 }
128
129 // Couldn't read from port
130 else
131 {
132 // fprintf(stderr, "ERROR: Could not read, res = %d, errno = %d : %m\n", result, errno);
133 LOG_ERROR("Mavlink - udp_port.cpp: Could not read, res = {}, errno = {} \n", result, errno);
134 }
135
136 // --------------------------------------------------------------------------
137 // DEBUGGING REPORTS
138 // --------------------------------------------------------------------------
139 if (msgReceived && debug)
140 {
141 // Report info
142 // printf("Received message from UDP with ID #%d (sys:%d|comp:%d):\n", message.msgid, message.sysid, message.compid);
143 // LOG_INFO("Mavlink - udp_port.cpp: Received message from UDP with ID #{} (sys:{}|comp:{}):\n", message.msgid, message.sysid, message.compid); // FIXME: cannot bind bit-field 'message.__mavlink_message::msgid' to 'unsigned int&'
144
145 LOG_INFO("Mavlink - udp_port.cpp: Received UDP data: ");
146 std::array<uint8_t, MAVLINK_MAX_PACKET_LEN> buffer{};
147
148 // check message is write length
149 auto messageLength = mavlink_msg_to_send_buffer(buffer.data(), &message);
150
151 // message length error
152 if (messageLength > MAVLINK_MAX_PACKET_LEN)
153 {
154 // fprintf(stderr, "\nFATAL ERROR: MESSAGE LENGTH IS LARGER THAN BUFFER SIZE\n");
155 LOG_ERROR("Mavlink - udp_port.cpp: FATAL ERROR: MESSAGE LENGTH IS LARGER THAN BUFFER SIZE");
156 }
157
158 // print out the buffer
159 else
160 {
161 for (size_t i = 0; i < static_cast<size_t>(messageLength); i++)
162 {
163 [[maybe_unused]] unsigned char v = buffer.at(i);
164 // fprintf(stderr, "%02x ", v);
165 LOG_INFO("Mavlink - udp_port.cpp: {}", v);
166 }
167 }
168 }
169
170 // Done!
171 return msgReceived;
172}
173
174// ------------------------------------------------------------------------------
175// Write to UDP
176// ------------------------------------------------------------------------------
177int UDP_Port::write_message(const mavlink_message_t& message)
178{
179 std::array<char, 300> buf{};
180
181 // Translate message to buffer
182 unsigned len = mavlink_msg_to_send_buffer(reinterpret_cast<uint8_t*>(buf.data()), &message);
183
184 // Write buffer to UDP port, locks port while writing
185 int bytesWritten = _write_port(buf.data(), len);
186 if (bytesWritten < 0)
187 {
188 // fprintf(stderr, "ERROR: Could not write, res = %d, errno = %d : %m\n", bytesWritten, errno);
189 LOG_ERROR("Mavlink - udp_port.cpp: Could not write, res = {}, errno = {}\n", bytesWritten, errno);
190 }
191
192 return bytesWritten;
193}
194
195// ------------------------------------------------------------------------------
196// Open UDP Port
197// ------------------------------------------------------------------------------
198/**
199 * throws EXIT_FAILURE if could not open the port
200 */
201void UDP_Port::start()
202{
203 // --------------------------------------------------------------------------
204 // OPEN PORT
205 // --------------------------------------------------------------------------
206
207 /* Create socket */
208 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
209 if (sock < 0)
210 {
211 LOG_ERROR("Mavlink - udp_port.cpp: error socket failed");
212 }
213
214 /* Bind the socket to rx_port - necessary to receive packets */
215 struct sockaddr_in addr
216 {};
217 memset(&addr, 0, sizeof(addr));
218 addr.sin_family = AF_INET;
219 addr.sin_addr.s_addr = inet_addr(target_ip);
220 ;
221 addr.sin_port = htons(static_cast<uint16_t>(rx_port));
222
223 if (bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(struct sockaddr)))
224 {
225 LOG_ERROR("Mavlink - udp_port.cpp: error bind failed");
226 close(sock);
227 sock = -1;
228 }
229 /*if (fcntl(sock, F_SETFL, O_NONBLOCK | O_ASYNC) < 0)
230 {
231 fprintf(stderr, "error setting nonblocking: %s\n", strerror(errno));
232 close(sock);
233 sock = -1;
234 throw EXIT_FAILURE;
235 }*/
236
237 // --------------------------------------------------------------------------
238 // CONNECTED!
239 // --------------------------------------------------------------------------
240 // printf("Listening to %s:%i\n", target_ip, rx_port);
241 LOG_INFO("Mavlink - udp_port.cpp: Listening to {}:{}\n", target_ip, rx_port);
242 lastStatus.packet_rx_drop_count = 0;
243
244 is_open = true;
245}
246
247// ------------------------------------------------------------------------------
248// Close UDP Port
249// ------------------------------------------------------------------------------
250void UDP_Port::stop()
251{
252 // printf("CLOSE PORT\n");
253 LOG_INFO("Mavlink - udp_port.cpp: CLOSE PORT");
254
255 int result = close(sock);
256 sock = -1;
257
258 if (result)
259 {
260 // fprintf(stderr, "WARNING: Error on port close (%i)\n", result);
261 LOG_WARN("Mavlink - udp_port.cpp: Error on port close ({})\n", result);
262 }
263
264 is_open = false;
265
266 // printf("\n");
267}
268
269// ------------------------------------------------------------------------------
270// Read Port with Lock
271// ------------------------------------------------------------------------------
272int UDP_Port::_read_port(uint8_t& cp)
273{
274 socklen_t len{};
275
276 // Lock
277 pthread_mutex_lock(&lock);
278
279 int result = -1;
280 if (buff_ptr < buff_len)
281 {
282 cp = buff.at(static_cast<uint8_t>(buff_ptr));
283 buff_ptr++;
284 result = 1;
285 }
286 else
287 {
288 struct sockaddr_in addr
289 {};
290 len = sizeof(struct sockaddr_in);
291 result = static_cast<int>(recvfrom(sock, &buff, BUFF_LEN, 0, reinterpret_cast<struct sockaddr*>(&addr), &len));
292 if (tx_port < 0)
293 {
294 if (strcmp(inet_ntoa(addr.sin_addr), target_ip) == 0) // NOLINT(concurrency-mt-unsafe)
295 {
296 tx_port = ntohs(addr.sin_port);
297 // printf("Got first packet, sending to %s:%i\n", target_ip, rx_port);
298 LOG_INFO("Mavlink - udp_port.cpp: Got first packet, sending to {}:{}\n", target_ip, rx_port);
299 }
300 else
301 {
302 // printf("ERROR: Got packet from %s:%i but listening on %s\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), target_ip);
303 LOG_ERROR("Mavlink - udp_port.cpp: Got packet from {}:{} but listening on {}\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), target_ip); // NOLINT(concurrency-mt-unsafe)
304 }
305 }
306 if (result > 0)
307 {
308 buff_len = result;
309 buff_ptr = 0;
310 cp = buff.at(static_cast<uint8_t>(buff_ptr));
311 buff_ptr++;
312 // printf("recvfrom: %i %i\n", result, cp);
313 }
314 }
315
316 // Unlock
317 pthread_mutex_unlock(&lock);
318
319 return result;
320}
321
322// ------------------------------------------------------------------------------
323// Write Port with Lock
324// ------------------------------------------------------------------------------
325int UDP_Port::_write_port(char* buf, unsigned len)
326{
327 // Lock
328 pthread_mutex_lock(&lock);
329
330 // Write packet via UDP link
331 int bytesWritten = 0;
332 if (tx_port > 0)
333 {
334 struct sockaddr_in addr
335 {};
336 memset(&addr, 0, sizeof(addr));
337 addr.sin_family = AF_INET;
338 addr.sin_addr.s_addr = inet_addr(target_ip);
339 addr.sin_port = htons(static_cast<uint16_t>(tx_port));
340 bytesWritten = static_cast<unsigned char>(sendto(sock, buf, len, 0, reinterpret_cast<struct sockaddr*>(&addr), sizeof(struct sockaddr_in))); // NOLINT(bugprone-signed-char-misuse)
341 // printf("sendto: %i\n", bytesWritten);
342 }
343 else
344 {
345 LOG_ERROR("Mavlink - udp_port.cpp: Sending before first packet received!\n");
346 bytesWritten = -1;
347 }
348
349 // Unlock
350 pthread_mutex_unlock(&lock);
351
352 return bytesWritten;
353}
354
355#endif
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_INFO
Info to the user on the state of the program.
Definition Logger.hpp:69
UDP interface definition.