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

mavlink / MAVSDK / 16636200771

30 Jul 2025 11:46PM UTC coverage: 44.271% (-2.0%) from 46.31%
16636200771

Pull #2626

github

web-flow
Merge bfd339d18 into c0a7c02a0
Pull Request #2626: core: flush after each Log* line

237 of 350 new or added lines in 32 files covered. (67.71%)

405 existing lines in 18 files now uncovered.

15319 of 34603 relevant lines covered (44.27%)

293.66 hits per line

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

0.0
/src/mavsdk/plugins/mavlink_direct/mavlink_direct_impl.cpp
1
#include "mavlink_direct_impl.h"
2
#include <mav/Message.h>
3
#include <mav/MessageSet.h>
4
#include <variant>
5
#include <json/json.h>
6
#include "log.h"
7
#include "connection.h"
8

9
namespace mavsdk {
10

11
MavlinkDirectImpl::MavlinkDirectImpl(System& system) : PluginImplBase(system)
×
12
{
13
    if (const char* env_p = std::getenv("MAVSDK_MAVLINK_DIRECT_DEBUGGING")) {
×
14
        if (std::string(env_p) == "1") {
×
15
            _debugging = true;
×
16
        }
17
    }
18
    _system_impl->register_plugin(this);
×
19
}
×
20

UNCOV
21
MavlinkDirectImpl::MavlinkDirectImpl(std::shared_ptr<System> system) :
×
UNCOV
22
    PluginImplBase(std::move(system))
×
23
{
UNCOV
24
    if (const char* env_p = std::getenv("MAVSDK_MAVLINK_DIRECT_DEBUGGING")) {
×
25
        if (std::string(env_p) == "1") {
×
26
            _debugging = true;
×
27
        }
28
    }
UNCOV
29
    _system_impl->register_plugin(this);
×
UNCOV
30
}
×
31

UNCOV
32
MavlinkDirectImpl::~MavlinkDirectImpl()
×
33
{
UNCOV
34
    _system_impl->unregister_plugin(this);
×
UNCOV
35
}
×
36

UNCOV
37
void MavlinkDirectImpl::init()
×
38
{
39
    // No need to initialize MessageSet here - LibmavReceiver handles that
40
    // No need to register for mavlink messages anymore - we'll use libmav subscription system
UNCOV
41
}
×
42

UNCOV
43
void MavlinkDirectImpl::deinit() {}
×
44

UNCOV
45
void MavlinkDirectImpl::enable() {}
×
46

UNCOV
47
void MavlinkDirectImpl::disable() {}
×
48

UNCOV
49
MavlinkDirect::Result MavlinkDirectImpl::send_message(MavlinkDirect::MavlinkMessage message)
×
50
{
51
    // Get access to the MessageSet through the system
UNCOV
52
    auto& message_set = _system_impl->get_message_set();
×
53

54
    // Create libmav message from the message name
UNCOV
55
    auto libmav_message_opt = message_set.create(message.message_name);
×
UNCOV
56
    if (!libmav_message_opt) {
×
57
        LogErr() << "Failed to create message: " << message.message_name;
×
58
        return MavlinkDirect::Result::InvalidMessage; // Message type not found
×
59
    }
60

UNCOV
61
    if (_debugging) {
×
62
        LogDebug() << "Created message " << message.message_name
×
63
                   << " with ID: " << libmav_message_opt.value().id();
×
64
    }
65

UNCOV
66
    auto libmav_message = libmav_message_opt.value();
×
67

68
    // Convert JSON fields to libmav message fields
UNCOV
69
    if (!json_to_libmav_message(message.fields_json, libmav_message)) {
×
70
        LogErr() << "Failed to convert JSON fields to libmav message for " << message.message_name;
×
71
        return MavlinkDirect::Result::InvalidField; // JSON conversion failed
×
72
    }
73

UNCOV
74
    if (_debugging) {
×
75
        LogDebug() << "Successfully populated fields for " << message.message_name;
×
76
    }
77

78
    // Set target system/component if specified
UNCOV
79
    if (message.target_system != 0) {
×
80
        // For messages that have target_system field, set it
81
        libmav_message.set("target_system", static_cast<uint8_t>(message.target_system));
×
82
    }
UNCOV
83
    if (message.target_component != 0) {
×
84
        // For messages that have target_component field, set it
85
        libmav_message.set("target_component", static_cast<uint8_t>(message.target_component));
×
86
    }
87

UNCOV
88
    if (_debugging) {
×
89
        LogDebug() << "Sending " << message.message_name << " via unified libmav API";
×
90
    }
91

UNCOV
92
    _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
93
        mavlink_message_t mavlink_message;
94

95
        // Use clean libmav helper methods to get payload data
UNCOV
96
        auto payload_view = libmav_message.getPayloadView();
×
UNCOV
97
        const uint8_t payload_length = libmav_message.getPayloadLength();
×
98

99
        // Set up the mavlink_message_t structure
UNCOV
100
        mavlink_message.msgid = libmav_message.id();
×
UNCOV
101
        mavlink_message.len = payload_length;
×
UNCOV
102
        memcpy(mavlink_message.payload64, payload_view.first, payload_length);
×
103

UNCOV
104
        mavlink_finalize_message_chan(
×
105
            &mavlink_message,
UNCOV
106
            mavlink_address.system_id,
×
UNCOV
107
            mavlink_address.component_id,
×
108
            channel,
109
            payload_length,
UNCOV
110
            libmav_message.type().maxPayloadSize(),
×
UNCOV
111
            libmav_message.type().crcExtra());
×
112

UNCOV
113
        return mavlink_message;
×
114
    });
115

UNCOV
116
    if (_debugging) {
×
117
        LogDebug() << "Successfully sent " << message.message_name << " as raw data";
×
118
    }
119

UNCOV
120
    return MavlinkDirect::Result::Success;
×
121
}
122

UNCOV
123
MavlinkDirect::MessageHandle MavlinkDirectImpl::subscribe_message(
×
124
    std::string message_name, const MavlinkDirect::MessageCallback& callback)
125
{
UNCOV
126
    std::lock_guard<std::mutex> lock(_message_callbacks_mutex);
×
127

128
    // Create a proper handle
UNCOV
129
    auto handle = _message_handle_factory.create();
×
130

131
    // Store the callback and message name mapped to the handle
UNCOV
132
    _message_callbacks[handle] = callback;
×
UNCOV
133
    _message_handle_to_name[handle] = message_name;
×
134

135
    // Register with SystemImpl
UNCOV
136
    _system_impl->register_libmav_message_handler(
×
137
        message_name, // Empty string means all messages, specific name means filtered
UNCOV
138
        [this, handle](const LibmavMessage& libmav_msg) {
×
UNCOV
139
            std::lock_guard<std::mutex> callback_lock(_message_callbacks_mutex);
×
UNCOV
140
            auto it = _message_callbacks.find(handle);
×
UNCOV
141
            if (it != _message_callbacks.end()) {
×
142
                // Convert LibmavMessage to MavlinkDirect::MavlinkMessage
UNCOV
143
                MavlinkDirect::MavlinkMessage message;
×
UNCOV
144
                message.message_name = libmav_msg.message_name;
×
UNCOV
145
                message.system_id = libmav_msg.system_id;
×
UNCOV
146
                message.component_id = libmav_msg.component_id;
×
UNCOV
147
                message.target_system = libmav_msg.target_system;
×
UNCOV
148
                message.target_component = libmav_msg.target_component;
×
UNCOV
149
                message.fields_json = libmav_msg.fields_json;
×
150

UNCOV
151
                it->second(message);
×
UNCOV
152
            }
×
UNCOV
153
        },
×
154
        &handle // Use handle address as cookie for specific unregistration
155
    );
156

UNCOV
157
    return handle;
×
UNCOV
158
}
×
159

UNCOV
160
void MavlinkDirectImpl::unsubscribe_message(MavlinkDirect::MessageHandle handle)
×
161
{
UNCOV
162
    std::lock_guard<std::mutex> lock(_message_callbacks_mutex);
×
163

164
    // Find the message name for this handle
UNCOV
165
    auto name_it = _message_handle_to_name.find(handle);
×
UNCOV
166
    if (name_it != _message_handle_to_name.end()) {
×
UNCOV
167
        const std::string& message_name = name_it->second;
×
168

169
        // Unregister from SystemImpl using the handle address as cookie
UNCOV
170
        _system_impl->unregister_libmav_message_handler(message_name, &handle);
×
171

172
        // Remove from our callback maps
UNCOV
173
        _message_callbacks.erase(handle);
×
UNCOV
174
        _message_handle_to_name.erase(handle);
×
175
    }
UNCOV
176
}
×
177

178
std::optional<uint32_t> MavlinkDirectImpl::message_name_to_id(const std::string& name) const
×
179
{
180
    // Get MessageSet to access message definitions
181
    auto& message_set = _system_impl->get_message_set();
×
182

183
    // Use MessageSet's message name to ID conversion
184
    auto id_opt = message_set.idForMessage(name);
×
185
    if (id_opt.has_value()) {
×
186
        return static_cast<uint32_t>(id_opt.value());
×
187
    }
188

189
    return std::nullopt;
×
190
}
191

192
std::optional<std::string> MavlinkDirectImpl::message_id_to_name(uint32_t id) const
×
193
{
194
    // Get MessageSet to access message definitions
195
    auto& message_set = _system_impl->get_message_set();
×
196

197
    // Use MessageSet's message ID to name conversion
198
    auto message_def = message_set.getMessageDefinition(static_cast<int>(id));
×
199
    if (message_def) {
×
200
        return message_def.get().name();
×
201
    }
202
    return std::nullopt;
×
203
}
204

205
Json::Value MavlinkDirectImpl::libmav_to_json(const mav::Message& msg) const
×
206
{
207
    (void)msg;
208
    // TODO: Implement field iteration once libmav noexcept API is stable
209
    return Json::Value();
×
210
}
211

212
bool MavlinkDirectImpl::json_to_libmav(const Json::Value& json, mav::Message& msg) const
×
213
{
214
    (void)json;
215
    (void)msg;
216
    // TODO: Implement once libmav noexcept API set methods are stable
217
    return false;
×
218
}
219

UNCOV
220
bool MavlinkDirectImpl::json_to_libmav_message(
×
221
    const std::string& json_string, mav::Message& msg) const
222
{
UNCOV
223
    Json::Value json;
×
UNCOV
224
    Json::Reader reader;
×
225

UNCOV
226
    if (!reader.parse(json_string, json)) {
×
227
        LogErr() << "Failed to parse JSON: " << json_string;
×
228
        return false;
×
229
    }
230

231
    // Iterate through all JSON fields and set them in the libmav message
UNCOV
232
    for (const auto& field_name : json.getMemberNames()) {
×
UNCOV
233
        const Json::Value& field_value = json[field_name];
×
234

235
        // Convert JSON values to appropriate types and set in message
UNCOV
236
        if (field_value.isInt()) {
×
UNCOV
237
            auto result = msg.set(field_name, static_cast<int32_t>(field_value.asInt()));
×
UNCOV
238
            if (result != ::mav::MessageResult::Success) {
×
239
                // Try as other integer types
240
                if (msg.set(field_name, static_cast<uint32_t>(field_value.asUInt())) !=
×
241
                        ::mav::MessageResult::Success &&
×
242
                    msg.set(field_name, static_cast<int16_t>(field_value.asInt())) !=
×
243
                        ::mav::MessageResult::Success &&
×
244
                    msg.set(field_name, static_cast<uint16_t>(field_value.asUInt())) !=
×
245
                        ::mav::MessageResult::Success &&
×
246
                    msg.set(field_name, static_cast<int8_t>(field_value.asInt())) !=
×
247
                        ::mav::MessageResult::Success &&
×
248
                    msg.set(field_name, static_cast<uint8_t>(field_value.asUInt())) !=
×
249
                        ::mav::MessageResult::Success) {
250
                    LogWarn() << "Failed to set integer field " << field_name << " = "
×
251
                              << field_value.asInt();
×
252
                }
253
            }
UNCOV
254
        } else if (field_value.isUInt()) {
×
255
            auto result = msg.set(field_name, static_cast<uint32_t>(field_value.asUInt()));
×
256
            if (result != ::mav::MessageResult::Success) {
×
257
                // Try as other unsigned integer types
258
                if (msg.set(field_name, static_cast<uint64_t>(field_value.asUInt64())) !=
×
259
                        ::mav::MessageResult::Success &&
×
260
                    msg.set(field_name, static_cast<uint16_t>(field_value.asUInt())) !=
×
261
                        ::mav::MessageResult::Success &&
×
262
                    msg.set(field_name, static_cast<uint8_t>(field_value.asUInt())) !=
×
263
                        ::mav::MessageResult::Success) {
264
                    LogWarn() << "Failed to set unsigned integer field " << field_name << " = "
×
265
                              << field_value.asUInt();
×
266
                }
267
            }
UNCOV
268
        } else if (field_value.isDouble()) {
×
269
            auto result = msg.set(field_name, static_cast<float>(field_value.asFloat()));
×
270
            if (result != ::mav::MessageResult::Success) {
×
271
                // Try as double
272
                if (msg.set(field_name, field_value.asDouble()) != ::mav::MessageResult::Success) {
×
273
                    LogWarn() << "Failed to set float/double field " << field_name << " = "
×
274
                              << field_value.asDouble();
×
275
                }
276
            }
UNCOV
277
        } else if (field_value.isString()) {
×
278
            auto result = msg.setString(field_name, field_value.asString());
×
279
            if (result != ::mav::MessageResult::Success) {
×
280
                LogWarn() << "Failed to set string field " << field_name << " = "
×
281
                          << field_value.asString();
×
282
            }
UNCOV
283
        } else if (field_value.isArray()) {
×
284
            // Handle array fields
UNCOV
285
            auto array_size = field_value.size();
×
286

287
            // Try different vector types based on typical MAVLink array field types
UNCOV
288
            std::vector<uint8_t> uint8_vec;
×
UNCOV
289
            std::vector<uint16_t> uint16_vec;
×
UNCOV
290
            std::vector<uint32_t> uint32_vec;
×
UNCOV
291
            std::vector<int8_t> int8_vec;
×
UNCOV
292
            std::vector<int16_t> int16_vec;
×
UNCOV
293
            std::vector<int32_t> int32_vec;
×
UNCOV
294
            std::vector<float> float_vec;
×
UNCOV
295
            std::vector<double> double_vec;
×
296

297
            // Convert JSON array to vectors of different types
UNCOV
298
            uint8_vec.reserve(array_size);
×
UNCOV
299
            uint16_vec.reserve(array_size);
×
UNCOV
300
            uint32_vec.reserve(array_size);
×
UNCOV
301
            int8_vec.reserve(array_size);
×
UNCOV
302
            int16_vec.reserve(array_size);
×
UNCOV
303
            int32_vec.reserve(array_size);
×
UNCOV
304
            float_vec.reserve(array_size);
×
UNCOV
305
            double_vec.reserve(array_size);
×
306

UNCOV
307
            for (Json::ArrayIndex i = 0; i < array_size; ++i) {
×
UNCOV
308
                const auto& elem = field_value[i];
×
UNCOV
309
                if (elem.isNumeric()) {
×
UNCOV
310
                    uint8_vec.push_back(static_cast<uint8_t>(elem.asUInt()));
×
UNCOV
311
                    uint16_vec.push_back(static_cast<uint16_t>(elem.asUInt()));
×
UNCOV
312
                    uint32_vec.push_back(static_cast<uint32_t>(elem.asUInt()));
×
UNCOV
313
                    int8_vec.push_back(static_cast<int8_t>(elem.asInt()));
×
UNCOV
314
                    int16_vec.push_back(static_cast<int16_t>(elem.asInt()));
×
UNCOV
315
                    int32_vec.push_back(static_cast<int32_t>(elem.asInt()));
×
UNCOV
316
                    float_vec.push_back(static_cast<float>(elem.asFloat()));
×
UNCOV
317
                    double_vec.push_back(elem.asDouble());
×
318
                } else {
319
                    // Default to 0 for non-numeric values
320
                    uint8_vec.push_back(0);
×
321
                    uint16_vec.push_back(0);
×
322
                    uint32_vec.push_back(0);
×
323
                    int8_vec.push_back(0);
×
324
                    int16_vec.push_back(0);
×
325
                    int32_vec.push_back(0);
×
326
                    float_vec.push_back(0.0f);
×
327
                    double_vec.push_back(0.0);
×
328
                }
329
            }
330

331
            // Try to set the array field with different vector types
UNCOV
332
            if (msg.set(field_name, uint8_vec) == ::mav::MessageResult::Success ||
×
333
                msg.set(field_name, uint16_vec) == ::mav::MessageResult::Success ||
×
334
                msg.set(field_name, uint32_vec) == ::mav::MessageResult::Success ||
×
335
                msg.set(field_name, int8_vec) == ::mav::MessageResult::Success ||
×
336
                msg.set(field_name, int16_vec) == ::mav::MessageResult::Success ||
×
337
                msg.set(field_name, int32_vec) == ::mav::MessageResult::Success ||
×
UNCOV
338
                msg.set(field_name, float_vec) == ::mav::MessageResult::Success ||
×
339
                msg.set(field_name, double_vec) == ::mav::MessageResult::Success) {
×
340
                // Successfully set the array field
341
            } else {
342
                LogWarn() << "Failed to set array field " << field_name;
×
343
            }
UNCOV
344
        } else {
×
345
            LogWarn() << "Unsupported JSON field type for " << field_name;
×
346
        }
UNCOV
347
    }
×
348

UNCOV
349
    return true;
×
UNCOV
350
}
×
351

UNCOV
352
MavlinkDirect::Result MavlinkDirectImpl::load_custom_xml(const std::string& xml_content)
×
353
{
354
    // Get access to the MessageSet through the system
UNCOV
355
    auto& message_set = _system_impl->get_message_set();
×
356

UNCOV
357
    if (_debugging) {
×
358
        LogDebug() << "Loading custom XML definitions...";
×
359
    }
360

361
    // Load the custom XML into the MessageSet
UNCOV
362
    auto result = message_set.addFromXMLString(xml_content, false /* recursive_open_includes */);
×
UNCOV
363
    bool success = (result == ::mav::MessageSetResult::Success);
×
364

UNCOV
365
    if (success) {
×
UNCOV
366
        if (_debugging) {
×
367
            LogDebug() << "Successfully loaded custom XML definitions";
×
368
        }
UNCOV
369
        return MavlinkDirect::Result::Success;
×
370
    } else {
371
        LogErr() << "Failed to load custom XML definitions";
×
372
        return MavlinkDirect::Result::Error;
×
373
    }
374
}
375

376
} // namespace mavsdk
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