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 |
|
|
|