INSTINCT Code Coverage Report


Directory: src/
File: util/Vendor/MavLink/udp_port.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 0 103 0.0%
Functions: 0 10 0.0%
Branches: 0 114 0.0%

Line Branch Exec Source
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 // ------------------------------------------------------------------------------
68 UDP_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
73 UDP_Port::UDP_Port()
74 {
75 initialize_defaults();
76 }
77
78 UDP_Port::~UDP_Port()
79 {
80 // destroy mutex
81 pthread_mutex_destroy(&lock);
82 }
83
84 void 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 // ------------------------------------------------------------------------------
97 int 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 // ------------------------------------------------------------------------------
177 int 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 */
201 void 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 // ------------------------------------------------------------------------------
250 void 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 // ------------------------------------------------------------------------------
272 int 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 // ------------------------------------------------------------------------------
325 int 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
356