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

mavlink / MAVSDK / 24114167644

08 Apr 2026 02:17AM UTC coverage: 50.468% (+0.003%) from 50.465%
24114167644

push

github

web-flow
core: hide symbols by default, export only public API (#2855)

* core: hide symbols by default, export only public API

Backport of #2824 to v3. Fixes segfault when MAVSDK is used alongside
ROS2 (or any library sharing bundled dependencies like OpenSSL/tinyxml2)
due to symbol conflicts from leaked third-party symbols.

- Add mavsdk_export.h with MAVSDK_PUBLIC, MAVSDK_TEST_EXPORT, and
  MAVSDK_TEMPL_INST macros
- Set CXX_VISIBILITY_PRESET=hidden and VISIBILITY_INLINES_HIDDEN=ON
- MAVSDK_SHARED compile definition gates dllexport/dllimport so that
  static builds on Windows are unaffected
- Annotate all public classes, free functions, operator overloads,
  and explicit template instantiations
- Update jinja2 templates to emit MAVSDK_PUBLIC on generated
  operator== and operator<< definitions
- Disable MSVC C4251 warning for DLL interface on STL members

Fixes #2852

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove stale asio includes from mission transfer client header

The backport patch incorrectly added asio includes that don't exist on
v3 (they were added on main after v3 branched).

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

15 of 379 new or added lines in 39 files covered. (3.96%)

4 existing lines in 3 files now uncovered.

19248 of 38139 relevant lines covered (50.47%)

672.95 hits per line

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

99.4
/src/system_tests/telemetry_timestamp.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 <cmath>
7
#include <chrono>
8
#include <future>
9
#include <thread>
10
#include <gtest/gtest.h>
11

12
using namespace mavsdk;
13

14
// Unit-level: verify struct default initialization and equality operators
15
TEST(SystemTest, TimestampStructDefaults)
4✔
16
{
17
    // Default-constructed structs should have timestamp_us == 0
18
    Telemetry::Altitude alt{};
1✔
19
    EXPECT_EQ(alt.timestamp_us, 0u);
1✔
20
    EXPECT_TRUE(std::isnan(alt.altitude_monotonic_m));
1✔
21

22
    Telemetry::GroundTruth gt{};
1✔
23
    EXPECT_EQ(gt.timestamp_us, 0u);
1✔
24
    EXPECT_TRUE(std::isnan(gt.latitude_deg));
1✔
25

26
    // Equality: same timestamps
27
    Telemetry::Altitude a1{};
1✔
28
    a1.timestamp_us = 100;
1✔
29
    a1.altitude_monotonic_m = 1.0f;
1✔
30
    a1.altitude_amsl_m = 2.0f;
1✔
31
    a1.altitude_local_m = 3.0f;
1✔
32
    a1.altitude_relative_m = 4.0f;
1✔
33
    a1.altitude_terrain_m = 5.0f;
1✔
34
    a1.bottom_clearance_m = 6.0f;
1✔
35

36
    Telemetry::Altitude a2 = a1;
1✔
37
    EXPECT_TRUE(a1 == a2);
1✔
38

39
    // Inequality: different timestamps
40
    a2.timestamp_us = 200;
1✔
41
    EXPECT_FALSE(a1 == a2);
1✔
42

43
    // GroundTruth equality
44
    Telemetry::GroundTruth g1{};
1✔
45
    g1.latitude_deg = 47.0;
1✔
46
    g1.longitude_deg = 8.0;
1✔
47
    g1.absolute_altitude_m = 500.0f;
1✔
48
    g1.timestamp_us = 300;
1✔
49

50
    Telemetry::GroundTruth g2 = g1;
1✔
51
    EXPECT_TRUE(g1 == g2);
1✔
52

53
    g2.timestamp_us = 400;
1✔
54
    EXPECT_FALSE(g1 == g2);
1✔
55
}
1✔
56

57
TEST(SystemTest, AltitudeTimestamp)
4✔
58
{
59
    Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1✔
60
    Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1✔
61

62
    ASSERT_EQ(
1✔
63
        mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:15200"),
64
        ConnectionResult::Success);
1✔
65
    ASSERT_EQ(
1✔
66
        mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:15200"), ConnectionResult::Success);
1✔
67

68
    auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1✔
69
    ASSERT_TRUE(maybe_system);
1✔
70
    auto system = maybe_system.value();
1✔
71

72
    // Wait for autopilot to discover the ground station connection
73
    while (mavsdk_autopilot.systems().size() == 0) {
2✔
74
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
75
    }
76
    auto gs_system = mavsdk_autopilot.systems().at(0);
1✔
77

78
    auto telemetry = Telemetry{system};
1✔
79
    auto sender = MavlinkDirect{gs_system};
1✔
80

81
    const uint64_t expected_timestamp_us = 123456789ULL;
1✔
82
    auto prom = std::promise<Telemetry::Altitude>{};
1✔
83
    auto fut = prom.get_future();
1✔
84
    std::atomic<bool> received{false};
1✔
85

86
    auto handle = telemetry.subscribe_altitude([&](const Telemetry::Altitude& altitude) {
2✔
87
        if (!received.exchange(true)) {
1✔
88
            prom.set_value(altitude);
1✔
89
        }
90
    });
1✔
91

92
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
93

94
    // Send ALTITUDE message via MavlinkDirect
95
    MavlinkDirect::MavlinkMessage msg;
1✔
96
    msg.message_name = "ALTITUDE";
1✔
97
    msg.system_id = 1;
1✔
98
    msg.component_id = 1;
1✔
99
    msg.target_system_id = 0;
1✔
100
    msg.target_component_id = 0;
1✔
101
    msg.fields_json =
102
        R"({"time_usec":123456789,"altitude_monotonic":100.0,"altitude_amsl":200.0,)"
103
        R"("altitude_local":300.0,"altitude_relative":400.0,"altitude_terrain":500.0,)"
104
        R"("bottom_clearance":600.0})";
1✔
105

106
    auto result = sender.send_message(msg);
1✔
107
    EXPECT_EQ(result, MavlinkDirect::Result::Success);
1✔
108

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

111
    auto received_altitude = fut.get();
1✔
112
    EXPECT_EQ(received_altitude.timestamp_us, expected_timestamp_us);
1✔
113
    EXPECT_FLOAT_EQ(received_altitude.altitude_monotonic_m, 100.0f);
1✔
114
    EXPECT_FLOAT_EQ(received_altitude.altitude_amsl_m, 200.0f);
1✔
115
    EXPECT_FLOAT_EQ(received_altitude.altitude_local_m, 300.0f);
1✔
116
    EXPECT_FLOAT_EQ(received_altitude.altitude_relative_m, 400.0f);
1✔
117
    EXPECT_FLOAT_EQ(received_altitude.altitude_terrain_m, 500.0f);
1✔
118
    EXPECT_FLOAT_EQ(received_altitude.bottom_clearance_m, 600.0f);
1✔
119

120
    telemetry.unsubscribe_altitude(handle);
1✔
121
}
1✔
122

123
TEST(SystemTest, GroundTruthTimestamp)
4✔
124
{
125
    Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1✔
126
    Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1✔
127

128
    ASSERT_EQ(
1✔
129
        mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:15201"),
130
        ConnectionResult::Success);
1✔
131
    ASSERT_EQ(
1✔
132
        mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:15201"), ConnectionResult::Success);
1✔
133

134
    auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1✔
135
    ASSERT_TRUE(maybe_system);
1✔
136
    auto system = maybe_system.value();
1✔
137

138
    while (mavsdk_autopilot.systems().size() == 0) {
2✔
139
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
140
    }
141
    auto gs_system = mavsdk_autopilot.systems().at(0);
1✔
142

143
    auto telemetry = Telemetry{system};
1✔
144
    auto sender = MavlinkDirect{gs_system};
1✔
145

146
    const uint64_t expected_timestamp_us = 987654321ULL;
1✔
147
    auto prom = std::promise<Telemetry::GroundTruth>{};
1✔
148
    auto fut = prom.get_future();
1✔
149
    std::atomic<bool> received{false};
1✔
150

151
    auto handle = telemetry.subscribe_ground_truth([&](const Telemetry::GroundTruth& ground_truth) {
2✔
152
        if (!received.exchange(true)) {
1✔
153
            prom.set_value(ground_truth);
1✔
154
        }
155
    });
1✔
156

157
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
158

159
    // Send HIL_STATE_QUATERNION message via MavlinkDirect
160
    MavlinkDirect::MavlinkMessage msg;
1✔
161
    msg.message_name = "HIL_STATE_QUATERNION";
1✔
162
    msg.system_id = 1;
1✔
163
    msg.component_id = 1;
1✔
164
    msg.target_system_id = 0;
1✔
165
    msg.target_component_id = 0;
1✔
166
    msg.fields_json = R"({"time_usec":987654321,"attitude_quaternion":[1.0,0.0,0.0,0.0],)"
167
                      R"("rollspeed":0.0,"pitchspeed":0.0,"yawspeed":0.0,)"
168
                      R"("lat":473977000,"lon":85456000,"alt":488000,)"
169
                      R"("vx":0,"vy":0,"vz":0,)"
170
                      R"("ind_airspeed":0,"true_airspeed":0,"xacc":0,"yacc":0,"zacc":0})";
1✔
171

172
    auto result = sender.send_message(msg);
1✔
173
    EXPECT_EQ(result, MavlinkDirect::Result::Success);
1✔
174

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

177
    auto received_ground_truth = fut.get();
1✔
178
    EXPECT_EQ(received_ground_truth.timestamp_us, expected_timestamp_us);
1✔
179
    EXPECT_NEAR(received_ground_truth.latitude_deg, 47.3977, 1e-4);
1✔
180
    EXPECT_NEAR(received_ground_truth.longitude_deg, 8.5456, 1e-4);
1✔
181
    EXPECT_NEAR(received_ground_truth.absolute_altitude_m, 488.0f, 0.1f);
1✔
182

183
    telemetry.unsubscribe_ground_truth(handle);
1✔
184
}
1✔
185

186
TEST(SystemTest, AltitudeTimestampUpdates)
4✔
187
{
188
    Mavsdk mavsdk_groundstation{Mavsdk::Configuration{ComponentType::GroundStation}};
1✔
189
    Mavsdk mavsdk_autopilot{Mavsdk::Configuration{ComponentType::Autopilot}};
1✔
190

191
    ASSERT_EQ(
1✔
192
        mavsdk_groundstation.add_any_connection("udpin://0.0.0.0:15202"),
193
        ConnectionResult::Success);
1✔
194
    ASSERT_EQ(
1✔
195
        mavsdk_autopilot.add_any_connection("udpout://127.0.0.1:15202"), ConnectionResult::Success);
1✔
196

197
    auto maybe_system = mavsdk_groundstation.first_autopilot(10.0);
1✔
198
    ASSERT_TRUE(maybe_system);
1✔
199
    auto system = maybe_system.value();
1✔
200

201
    while (mavsdk_autopilot.systems().size() == 0) {
1✔
UNCOV
202
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
×
203
    }
204
    auto gs_system = mavsdk_autopilot.systems().at(0);
1✔
205

206
    auto telemetry = Telemetry{system};
1✔
207
    auto sender = MavlinkDirect{gs_system};
1✔
208

209
    // Track all received timestamps
210
    std::mutex mtx;
1✔
211
    std::vector<uint64_t> received_timestamps;
1✔
212
    auto handle = telemetry.subscribe_altitude([&](const Telemetry::Altitude& altitude) {
4✔
213
        std::lock_guard<std::mutex> lock(mtx);
3✔
214
        received_timestamps.push_back(altitude.timestamp_us);
3✔
215
    });
3✔
216

217
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
1✔
218

219
    // Send 3 altitude messages with increasing timestamps
220
    const uint64_t timestamps[] = {1000000ULL, 2000000ULL, 3000000ULL};
1✔
221
    for (auto ts : timestamps) {
4✔
222
        MavlinkDirect::MavlinkMessage msg;
3✔
223
        msg.message_name = "ALTITUDE";
3✔
224
        msg.system_id = 1;
3✔
225
        msg.component_id = 1;
3✔
226
        msg.target_system_id = 0;
3✔
227
        msg.target_component_id = 0;
3✔
228
        msg.fields_json = "{\"time_usec\":" + std::to_string(ts) +
6✔
229
                          ",\"altitude_monotonic\":1.0,\"altitude_amsl\":2.0,"
230
                          "\"altitude_local\":3.0,\"altitude_relative\":4.0,"
231
                          "\"altitude_terrain\":5.0,\"bottom_clearance\":6.0}";
3✔
232

233
        auto result = sender.send_message(msg);
3✔
234
        EXPECT_EQ(result, MavlinkDirect::Result::Success);
3✔
235
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
3✔
236
    }
3✔
237

238
    // Wait for all messages to arrive
239
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
1✔
240

241
    telemetry.unsubscribe_altitude(handle);
1✔
242

243
    // Verify we received at least 3 messages with the expected timestamps
244
    std::lock_guard<std::mutex> lock(mtx);
1✔
245
    ASSERT_GE(received_timestamps.size(), 3u);
1✔
246
    // Check that all 3 timestamps appeared in order
247
    bool found_1 = false, found_2 = false, found_3 = false;
1✔
248
    for (auto ts : received_timestamps) {
4✔
249
        if (ts == 1000000ULL)
3✔
250
            found_1 = true;
1✔
251
        if (ts == 2000000ULL)
3✔
252
            found_2 = true;
1✔
253
        if (ts == 3000000ULL)
3✔
254
            found_3 = true;
1✔
255
    }
256
    EXPECT_TRUE(found_1) << "Missing timestamp 1000000";
1✔
257
    EXPECT_TRUE(found_2) << "Missing timestamp 2000000";
1✔
258
    EXPECT_TRUE(found_3) << "Missing timestamp 3000000";
1✔
259

260
    // Verify poll also returns the latest timestamp
261
    auto polled = telemetry.altitude();
1✔
262
    EXPECT_EQ(polled.timestamp_us, 3000000ULL);
1✔
263
}
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