• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mavlink / MAVSDK / 29564081841

17 Jul 2026 07:09AM UTC coverage: 50.512% (+0.01%) from 50.498%
29564081841

push

github

web-flow
Merge pull request #2936 from mavlink/v3-backport

Backport various bugfixes to v3

162 of 257 new or added lines in 24 files covered. (63.04%)

56 existing lines in 15 files now uncovered.

19343 of 38294 relevant lines covered (50.51%)

669.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.15
/src/system_tests/telemetry_rc_status.cpp
1
#include "log.h"
2
#include "mavsdk.h"
3
#include "plugins/telemetry/telemetry.h"
4
#include "plugins/mavlink_direct/mavlink_direct.h"
5
#include <atomic>
6
#include <chrono>
7
#include <future>
8
#include <thread>
9
#include <gtest/gtest.h>
10

11
using namespace mavsdk;
12

13
// Test that RC status updates arrive via SYS_STATUS messages.
14
// This is the path used by ArduPilot where RC receiver health
15
// is reported through the SYS_STATUS sensor flags.
16
TEST(SystemTest, RcStatusViaSysStatus)
4✔
17
{
18
    Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1✔
19
    Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1✔
20

21
    ASSERT_EQ(
1✔
22
        mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:15220"),
23
        ConnectionResult::Success);
1✔
24
    ASSERT_EQ(
1✔
25
        mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:15220"), ConnectionResult::Success);
1✔
26

27
    auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1✔
28
    ASSERT_TRUE(maybe_system);
1✔
29
    auto system = maybe_system.value();
1✔
30

31
    while (mavsdk_autopilot.systems().size() == 0) {
2✔
32
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
33
    }
34
    auto gs_system = mavsdk_autopilot.systems().at(0);
1✔
35

36
    auto telemetry = Telemetry{system};
1✔
37
    auto sender = MavlinkDirect{gs_system};
1✔
38

39
    auto prom = std::promise<Telemetry::RcStatus>{};
1✔
40
    auto fut = prom.get_future();
1✔
41
    std::atomic<bool> received{false};
1✔
42

43
    auto handle = telemetry.subscribe_rc_status([&](const Telemetry::RcStatus& rc_status) {
2✔
44
        if (!received.exchange(true)) {
1✔
45
            prom.set_value(rc_status);
1✔
46
        }
47
    });
1✔
48

49
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
50

51
    // Send SYS_STATUS with RC receiver present and healthy
52
    // MAV_SYS_STATUS_SENSOR_RC_RECEIVER = 0x10000 = 65536
53
    const uint32_t rc_receiver_flag = 65536;
1✔
54
    MavlinkDirect::MavlinkMessage msg;
1✔
55
    msg.message_name = "SYS_STATUS";
1✔
56
    msg.system_id = 1;
1✔
57
    msg.component_id = 1;
1✔
58
    msg.target_system_id = 0;
1✔
59
    msg.target_component_id = 0;
1✔
60
    msg.fields_json =
61
        "{\"onboard_control_sensors_present\":" + std::to_string(rc_receiver_flag) +
2✔
62
        ",\"onboard_control_sensors_enabled\":" + std::to_string(rc_receiver_flag) +
4✔
63
        ",\"onboard_control_sensors_health\":" + std::to_string(rc_receiver_flag) +
4✔
64
        ",\"load\":0,\"voltage_battery\":0,\"current_battery\":0,"
65
        "\"battery_remaining\":-1,\"drop_rate_comm\":0,\"errors_comm\":0,"
66
        "\"errors_count1\":0,\"errors_count2\":0,\"errors_count3\":0,\"errors_count4\":0}";
1✔
67

68
    auto result = sender.send_message(msg);
1✔
69
    EXPECT_EQ(result, MavlinkDirect::Result::Success);
1✔
70

71
    ASSERT_EQ(fut.wait_for(std::chrono::seconds(5)), std::future_status::ready);
1✔
72

73
    auto rc_status = fut.get();
1✔
74
    // RC receiver is healthy → is_available should be true
75
    EXPECT_TRUE(rc_status.is_available);
1✔
76

77
    telemetry.unsubscribe_rc_status(handle);
1✔
78
}
1✔
79

80
// Test that RC status updates arrive via RC_CHANNELS messages.
81
// This is the path used by PX4 where RC signal strength is
82
// reported through the RC_CHANNELS message rssi field.
83
TEST(SystemTest, RcStatusViaRcChannels)
4✔
84
{
85
    Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1✔
86
    Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1✔
87

88
    ASSERT_EQ(
1✔
89
        mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:15221"),
90
        ConnectionResult::Success);
1✔
91
    ASSERT_EQ(
1✔
92
        mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:15221"), ConnectionResult::Success);
1✔
93

94
    auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1✔
95
    ASSERT_TRUE(maybe_system);
1✔
96
    auto system = maybe_system.value();
1✔
97

98
    while (mavsdk_autopilot.systems().size() == 0) {
1✔
UNCOV
99
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
×
100
    }
101
    auto gs_system = mavsdk_autopilot.systems().at(0);
1✔
102

103
    auto telemetry = Telemetry{system};
1✔
104
    auto sender = MavlinkDirect{gs_system};
1✔
105

106
    auto prom = std::promise<Telemetry::RcStatus>{};
1✔
107
    auto fut = prom.get_future();
1✔
108
    std::atomic<bool> received{false};
1✔
109

110
    auto handle = telemetry.subscribe_rc_status([&](const Telemetry::RcStatus& rc_status) {
2✔
111
        // Wait for a callback that has signal_strength set (from RC_CHANNELS)
112
        if (rc_status.signal_strength_percent > 0.0f && !received.exchange(true)) {
1✔
113
            prom.set_value(rc_status);
1✔
114
        }
115
    });
1✔
116

117
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
118

119
    // Send RC_CHANNELS with rssi = 200 (out of 255)
120
    MavlinkDirect::MavlinkMessage msg;
1✔
121
    msg.message_name = "RC_CHANNELS";
1✔
122
    msg.system_id = 1;
1✔
123
    msg.component_id = 1;
1✔
124
    msg.target_system_id = 0;
1✔
125
    msg.target_component_id = 0;
1✔
126
    msg.fields_json = R"({"time_boot_ms":1000,"chancount":8,"chan1_raw":1500,"chan2_raw":1500,)"
127
                      R"("chan3_raw":1500,"chan4_raw":1500,"chan5_raw":0,"chan6_raw":0,)"
128
                      R"("chan7_raw":0,"chan8_raw":0,"chan9_raw":0,"chan10_raw":0,)"
129
                      R"("chan11_raw":0,"chan12_raw":0,"chan13_raw":0,"chan14_raw":0,)"
130
                      R"("chan15_raw":0,"chan16_raw":0,"chan17_raw":0,"chan18_raw":0,"rssi":200})";
1✔
131

132
    auto result = sender.send_message(msg);
1✔
133
    EXPECT_EQ(result, MavlinkDirect::Result::Success);
1✔
134

135
    ASSERT_EQ(fut.wait_for(std::chrono::seconds(5)), std::future_status::ready);
1✔
136

137
    auto rc_status = fut.get();
1✔
138
    // rssi is stored directly as signal_strength_percent (raw value 0-254)
139
    EXPECT_FLOAT_EQ(rc_status.signal_strength_percent, 200.0f);
1✔
140

141
    telemetry.unsubscribe_rc_status(handle);
1✔
142
}
1✔
143

144
// Test that RC status correctly reports unavailable when
145
// SYS_STATUS reports RC receiver not healthy.
146
TEST(SystemTest, RcStatusUnavailableViaSysStatus)
4✔
147
{
148
    Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1✔
149
    Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1✔
150

151
    ASSERT_EQ(
1✔
152
        mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:15222"),
153
        ConnectionResult::Success);
1✔
154
    ASSERT_EQ(
1✔
155
        mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:15222"), ConnectionResult::Success);
1✔
156

157
    auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1✔
158
    ASSERT_TRUE(maybe_system);
1✔
159
    auto system = maybe_system.value();
1✔
160

161
    while (mavsdk_autopilot.systems().size() == 0) {
2✔
162
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
163
    }
164
    auto gs_system = mavsdk_autopilot.systems().at(0);
1✔
165

166
    auto telemetry = Telemetry{system};
1✔
167
    auto sender = MavlinkDirect{gs_system};
1✔
168

169
    auto prom = std::promise<Telemetry::RcStatus>{};
1✔
170
    auto fut = prom.get_future();
1✔
171
    std::atomic<bool> received{false};
1✔
172

173
    auto handle = telemetry.subscribe_rc_status([&](const Telemetry::RcStatus& rc_status) {
2✔
174
        if (!received.exchange(true)) {
1✔
175
            prom.set_value(rc_status);
1✔
176
        }
177
    });
1✔
178

179
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
180

181
    // Send SYS_STATUS with RC receiver present but NOT healthy
182
    // MAV_SYS_STATUS_SENSOR_RC_RECEIVER = 0x10000 = 65536
183
    const uint32_t rc_receiver_flag = 65536;
1✔
184
    MavlinkDirect::MavlinkMessage msg;
1✔
185
    msg.message_name = "SYS_STATUS";
1✔
186
    msg.system_id = 1;
1✔
187
    msg.component_id = 1;
1✔
188
    msg.target_system_id = 0;
1✔
189
    msg.target_component_id = 0;
1✔
190
    msg.fields_json =
191
        "{\"onboard_control_sensors_present\":" + std::to_string(rc_receiver_flag) +
2✔
192
        ",\"onboard_control_sensors_enabled\":" + std::to_string(rc_receiver_flag) +
4✔
193
        ",\"onboard_control_sensors_health\":0"
194
        ",\"load\":0,\"voltage_battery\":0,\"current_battery\":0,"
195
        "\"battery_remaining\":-1,\"drop_rate_comm\":0,\"errors_comm\":0,"
196
        "\"errors_count1\":0,\"errors_count2\":0,\"errors_count3\":0,\"errors_count4\":0}";
1✔
197

198
    auto result = sender.send_message(msg);
1✔
199
    EXPECT_EQ(result, MavlinkDirect::Result::Success);
1✔
200

201
    ASSERT_EQ(fut.wait_for(std::chrono::seconds(5)), std::future_status::ready);
1✔
202

203
    auto rc_status = fut.get();
1✔
204
    // RC receiver present but not healthy → is_available should be false
205
    EXPECT_FALSE(rc_status.is_available);
1✔
206

207
    telemetry.unsubscribe_rc_status(handle);
1✔
208
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc