Skip to content

Commit 721efdc

Browse files
authored
core: fix MAVLink message sequence (#2762)
* core: fix MAVLink message sequence The MAVLink headers use an inline function to get the mavlink channel, so we end up having separate sequence numbers in different translation units. By defining this function ourselves and linking it later, we make sure to use the same sequence everywhere. This should fix seq numbering that's invalid (per component). We also add a system test to actually test this. * system_tests: fixup thread sanitizer issues * system_tests: use TCP for seq to avoid drops
1 parent b84eae3 commit 721efdc

File tree

9 files changed

+129
-43
lines changed

9 files changed

+129
-43
lines changed

src/mavsdk/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ target_sources(mavsdk
6262
math_utils.cpp
6363
mavsdk.cpp
6464
mavsdk_impl.cpp
65+
mavlink_channel_status.cpp
6566
mavlink_channels.cpp
6667
mavlink_command_receiver.cpp
6768
mavlink_command_sender.cpp
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
#pragma once
22

3+
#include "mavlink/mavlink_types.h"
4+
5+
#define MAVLINK_GET_CHANNEL_STATUS
6+
mavlink_status_t* mavlink_get_channel_status(uint8_t chan);
7+
38
#include "mavlink/@MAVLINK_DIALECT@/mavlink.h"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "mavlink_include.h"
2+
3+
mavlink_status_t* mavlink_get_channel_status(uint8_t chan)
4+
{
5+
static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
6+
return &m_mavlink_status[chan];
7+
}

src/mavsdk/plugins/camera_server/camera_server_impl.cpp

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,27 +1769,29 @@ std::optional<mavlink_command_ack_t> CameraServerImpl::process_video_stream_info
17691769

17701770
_video_streaming.rtsp_uri.resize(sizeof(mavlink_video_stream_information_t::uri));
17711771

1772-
mavlink_message_t msg{};
1773-
mavlink_msg_video_stream_information_pack(
1774-
_server_component_impl->get_own_system_id(),
1775-
_server_component_impl->get_own_component_id(),
1776-
&msg,
1777-
0, // Stream id
1778-
0, // Count
1779-
VIDEO_STREAM_TYPE_RTSP,
1780-
VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1781-
0, // famerate
1782-
0, // resolution horizontal
1783-
0, // resolution vertical
1784-
0, // bitrate
1785-
0, // rotation
1786-
0, // horizontal field of view
1787-
name,
1788-
_video_streaming.rtsp_uri.c_str(),
1789-
0,
1790-
0);
1791-
1792-
_server_component_impl->send_message(msg);
1772+
_server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
1773+
mavlink_message_t msg{};
1774+
mavlink_msg_video_stream_information_pack_chan(
1775+
mavlink_address.system_id,
1776+
mavlink_address.component_id,
1777+
channel,
1778+
&msg,
1779+
0, // Stream id
1780+
0, // Count
1781+
VIDEO_STREAM_TYPE_RTSP,
1782+
VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1783+
0, // famerate
1784+
0, // resolution horizontal
1785+
0, // resolution vertical
1786+
0, // bitrate
1787+
0, // rotation
1788+
0, // horizontal field of view
1789+
name,
1790+
_video_streaming.rtsp_uri.c_str(),
1791+
0,
1792+
0);
1793+
return msg;
1794+
});
17931795

17941796
// Ack already sent.
17951797
return std::nullopt;
@@ -1819,21 +1821,24 @@ std::optional<mavlink_command_ack_t> CameraServerImpl::process_video_stream_stat
18191821
_server_component_impl->send_command_ack(command_ack);
18201822
LogDebug() << "sent video streaming ack";
18211823

1822-
mavlink_message_t msg{};
1823-
mavlink_msg_video_stream_status_pack(
1824-
_server_component_impl->get_own_system_id(),
1825-
_server_component_impl->get_own_component_id(),
1826-
&msg,
1827-
0, // Stream id
1828-
VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1829-
0, // framerate
1830-
0, // resolution horizontal
1831-
0, // resolution vertical
1832-
0, // bitrate
1833-
0, // rotation
1834-
0, // horizontal field of view
1835-
0);
1836-
_server_component_impl->send_message(msg);
1824+
_server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
1825+
mavlink_message_t msg{};
1826+
mavlink_msg_video_stream_status_pack_chan(
1827+
mavlink_address.system_id,
1828+
mavlink_address.component_id,
1829+
channel,
1830+
&msg,
1831+
0, // Stream id
1832+
VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1833+
0, // framerate
1834+
0, // resolution horizontal
1835+
0, // resolution vertical
1836+
0, // bitrate
1837+
0, // rotation
1838+
0, // horizontal field of view
1839+
0);
1840+
return msg;
1841+
});
18371842

18381843
// ack was already sent
18391844
return std::nullopt;

src/mavsdk/plugins/events/event_handler.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ EventHandler::EventHandler(
3838
};
3939

4040
const auto send_request_cb = [this](const mavlink_request_event_t& msg) {
41-
mavlink_message_t message;
42-
mavlink_msg_request_event_encode(
43-
_system_impl.get_own_system_id(), _system_impl.get_own_component_id(), &message, &msg);
44-
_system_impl.send_message(message);
41+
_system_impl.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
42+
mavlink_message_t message;
43+
mavlink_msg_request_event_encode_chan(
44+
mavlink_address.system_id, mavlink_address.component_id, channel, &message, &msg);
45+
return message;
46+
});
4547
};
4648

4749
_parser.setProfile(profile);

src/system_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_executable(system_tests_runner
2828
intercept.cpp
2929
mavlink_direct.cpp
3030
mavlink_direct_forwarding.cpp
31+
mavlink_seq.cpp
3132
mission_cancellation.cpp
3233
mission_changed.cpp
3334
mission_transfer_lossy.cpp

src/system_tests/intercept.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ TEST(SystemTest, InterceptIncomingModifyLocal)
8686
pos.lat = static_cast<int32_t>(modified_lat * 1e7);
8787
pos.lon = static_cast<int32_t>(modified_lon * 1e7);
8888

89-
// Re-encode the modified message
90-
mavlink_msg_global_position_int_encode(message.sysid, message.compid, &message, &pos);
89+
// Re-encode the modified message using a dedicated channel to avoid
90+
// racing with ServerComponentImpl::queue_message on channel 0.
91+
mavlink_msg_global_position_int_encode_chan(
92+
message.sysid, message.compid, MAVLINK_COMM_NUM_BUFFERS - 1, &message, &pos);
9193

9294
LogInfo() << "Modified coordinates to San Francisco: lat=" << (pos.lat / 1e7)
9395
<< ", lon=" << (pos.lon / 1e7);

src/system_tests/mavlink_seq.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "log.h"
2+
#include "mavsdk.h"
3+
#include <chrono>
4+
#include <thread>
5+
#include <mutex>
6+
#include <vector>
7+
#include <gtest/gtest.h>
8+
9+
using namespace mavsdk;
10+
11+
TEST(SystemTest, MavlinkSeqSequential)
12+
{
13+
Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
14+
Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
15+
16+
ASSERT_EQ(
17+
mavsdk_groundstation.add_any_connection("tcpin://0.0.0.0:17012"),
18+
ConnectionResult::Success);
19+
ASSERT_EQ(
20+
mavsdk_autopilot.add_any_connection("tcpout://127.0.0.1:17012"), ConnectionResult::Success);
21+
22+
auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
23+
ASSERT_TRUE(maybe_system);
24+
25+
std::mutex seq_mutex;
26+
std::vector<uint8_t> seq_numbers;
27+
28+
constexpr unsigned num_messages = 10;
29+
30+
// Intercept all incoming messages on the ground station and record
31+
// sequence numbers from the autopilot system (sysid 1, compid 1).
32+
mavsdk_groundstation.intercept_incoming_messages_async([&](mavlink_message_t& message) -> bool {
33+
if (message.sysid == 1 && message.compid == MAV_COMP_ID_AUTOPILOT1) {
34+
std::lock_guard<std::mutex> lock(seq_mutex);
35+
seq_numbers.push_back(message.seq);
36+
}
37+
return true;
38+
});
39+
40+
// Collect messages (heartbeats at 1 Hz plus any other traffic).
41+
for (unsigned i = 0; i < 150; ++i) {
42+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
43+
std::lock_guard<std::mutex> lock(seq_mutex);
44+
if (seq_numbers.size() >= num_messages) {
45+
break;
46+
}
47+
}
48+
49+
// Stop intercepting.
50+
mavsdk_groundstation.intercept_incoming_messages_async(nullptr);
51+
52+
std::lock_guard<std::mutex> lock(seq_mutex);
53+
ASSERT_GE(seq_numbers.size(), num_messages);
54+
55+
// Verify that all messages from the autopilot component have strictly
56+
// sequential seq numbers (incrementing by 1 with uint8_t wrapping).
57+
for (unsigned i = 1; i < num_messages; ++i) {
58+
uint8_t expected = static_cast<uint8_t>(seq_numbers[i - 1] + 1);
59+
EXPECT_EQ(seq_numbers[i], expected)
60+
<< "seq[" << i - 1 << "]=" << static_cast<int>(seq_numbers[i - 1]) << " seq[" << i
61+
<< "]=" << static_cast<int>(seq_numbers[i]);
62+
}
63+
}

src/system_tests/raw_bytes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ TEST(SystemTest, RawBytesSendReceive)
8585
ping.target_system = 0; // Broadcast
8686
ping.target_component = 0;
8787

88-
mavlink_msg_ping_encode(1, 1, &ping_msg, &ping);
88+
mavlink_msg_ping_encode_chan(1, 1, MAVLINK_COMM_NUM_BUFFERS - 1, &ping_msg, &ping);
8989

9090
// Serialize to bytes
9191
std::vector<uint8_t> ping_bytes(MAVLINK_MAX_PACKET_LEN);

0 commit comments

Comments
 (0)