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

mavlink / MAVSDK / 16412450345

21 Jul 2025 08:44AM UTC coverage: 46.352% (+1.3%) from 45.093%
16412450345

Pull #2610

github

web-flow
Merge 459971f25 into ae05b10ff
Pull Request #2610: Integrate parts of libmav into MAVSDK and add MavlinkDirect plugin

765 of 987 new or added lines in 14 files covered. (77.51%)

10 existing lines in 1 file now uncovered.

16263 of 35086 relevant lines covered (46.35%)

359.85 hits per line

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

78.43
/src/mavsdk/core/libmav_receiver.cpp
1
#include "libmav_receiver.h"
2
#include <mav/MessageSet.h>
3
#include <mav/BufferParser.h>
4
#include <json/json.h>
5
#include <variant>
6
#include <cstring>
7
#include <sstream>
8
#include "log.h"
9

10
namespace mavsdk {
11

12
LibmavReceiver::LibmavReceiver(mav::MessageSet& message_set) : _message_set(message_set)
100✔
13
{
14
    // Initialize BufferParser with the provided MessageSet
15
    _buffer_parser = std::make_unique<mav::BufferParser>(_message_set);
100✔
16

17
    if (const char* env_p = std::getenv("MAVSDK_MAVLINK_DIRECT_DEBUGGING")) {
100✔
NEW
18
        if (std::string(env_p) == "1") {
×
NEW
19
            _debugging = true;
×
20
        }
21
    }
22
}
100✔
23

24
LibmavReceiver::~LibmavReceiver() = default;
100✔
25

26
void LibmavReceiver::set_new_datagram(char* datagram, unsigned datagram_len)
2,121✔
27
{
28
    _datagram = datagram;
2,121✔
29
    _datagram_len = datagram_len;
2,121✔
30
}
2,121✔
31

32
bool LibmavReceiver::parse_message()
4,241✔
33
{
34
    if (!_datagram || _datagram_len == 0) {
4,241✔
35
        return false;
2,119✔
36
    }
37

38
    // Use libmav to parse messages directly from the buffer
39
    return parse_libmav_message_from_buffer(
2,122✔
40
        reinterpret_cast<const uint8_t*>(_datagram), _datagram_len);
2,122✔
41
}
42

43
bool LibmavReceiver::parse_libmav_message_from_buffer(const uint8_t* buffer, size_t buffer_len)
2,122✔
44
{
45
    size_t bytes_consumed = 0;
2,122✔
46
    auto message_opt = _buffer_parser->parseMessage(buffer, buffer_len, bytes_consumed);
2,122✔
47

48
    if (!message_opt) {
2,122✔
NEW
49
        return false; // No complete message found
×
50
    }
51

52
    auto message = message_opt.value();
2,116✔
53

54
    if (_debugging) {
2,116✔
NEW
55
        LogDebug() << "Parsed message: " << message.name() << " (ID: " << message.id() << ")";
×
56
    }
57

58
    // Extract system and component IDs from header
59
    auto header = message.header();
2,116✔
60

61
    // Generate complete JSON with all field values
62
    std::string json = libmav_message_to_json(message);
2,119✔
63

64
    // Fill our LibmavMessage structure
65
    _last_message.message = message;
2,122✔
66
    _last_message.message_name = message.name();
2,118✔
67
    _last_message.system_id = header.systemId();
2,120✔
68
    _last_message.component_id = header.componentId();
2,121✔
69

70
    // Extract target_system and target_component if present in message fields
71
    uint8_t target_system = 0;
2,121✔
72
    uint8_t target_component = 0;
2,122✔
73
    if (message.get("target_system", target_system) == mav::MessageResult::Success) {
2,121✔
74
        _last_message.target_system = target_system;
1,719✔
75
    } else {
76
        _last_message.target_system = 0;
402✔
77
    }
78
    if (message.get("target_component", target_component) == mav::MessageResult::Success) {
2,121✔
79
        _last_message.target_component = target_component;
1,719✔
80
    } else {
81
        _last_message.target_component = 0;
401✔
82
    }
83

84
    _last_message.fields_json = json;
2,120✔
85

86
    // Clear the original datagram since we processed it
87
    _datagram = nullptr;
2,121✔
88
    _datagram_len = 0;
2,121✔
89

90
    return true;
2,121✔
91
}
2,121✔
92

93
std::string LibmavReceiver::libmav_message_to_json(const mav::Message& msg) const
2,122✔
94
{
95
    std::ostringstream json_stream;
2,122✔
96
    json_stream << "{";
2,120✔
97
    json_stream << "\"message_id\":" << msg.id();
2,122✔
98
    json_stream << ",\"message_name\":\"" << msg.name() << "\"";
2,121✔
99

100
    // Get message definition to iterate through all fields
101
    auto message_def_opt = _message_set.getMessageDefinition(static_cast<int>(msg.id()));
2,120✔
102
    if (message_def_opt) {
2,122✔
103
        auto& message_def = message_def_opt.get();
2,122✔
104

105
        // Get field names and iterate through them
106
        auto field_names = message_def.fieldNames();
2,122✔
107
        for (const auto& field_name : field_names) {
13,633✔
108
            json_stream << ",\"" << field_name << "\":";
11,512✔
109

110
            // Extract field value based on type and convert to JSON
111
            auto variant_opt = msg.getAsNativeTypeInVariant(field_name);
11,521✔
112
            if (variant_opt) {
11,519✔
113
                const auto& variant = variant_opt.value();
11,508✔
114

115
                // Convert variant to JSON string based on the field type
116
                std::visit(
11,509✔
117
                    [&json_stream](const auto& value) {
621,881✔
118
                        using T = std::decay_t<decltype(value)>;
119

120
                        if constexpr (
121
                            std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> ||
122
                            std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t> ||
123
                            std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t> ||
124
                            std::is_same_v<T, int32_t> || std::is_same_v<T, int64_t>) {
125
                            json_stream << static_cast<int64_t>(value);
8,233✔
126
                        } else if constexpr (std::is_same_v<T, char>) {
NEW
127
                            json_stream << static_cast<int>(value);
×
128
                        } else if constexpr (
129
                            std::is_same_v<T, float> || std::is_same_v<T, double>) {
130
                            json_stream << value;
1,597✔
131
                        } else if constexpr (std::is_same_v<T, std::string>) {
132
                            json_stream << "\"" << value << "\"";
281✔
133
                        } else if constexpr (
134
                            std::is_same_v<T, std::vector<uint8_t>> ||
135
                            std::is_same_v<T, std::vector<int8_t>>) {
136
                            // Handle uint8_t/int8_t vectors specially to avoid character output
137
                            json_stream << "[";
1,397✔
138
                            bool first = true;
1,397✔
139
                            for (const auto& elem : value) {
306,585✔
140
                                if (!first)
305,152✔
141
                                    json_stream << ",";
303,762✔
142
                                first = false;
305,177✔
143
                                json_stream << static_cast<int>(elem);
305,177✔
144
                            }
145
                            json_stream << "]";
1,398✔
146
                        } else if constexpr (
147
                            std::is_same_v<T, std::vector<uint16_t>> ||
148
                            std::is_same_v<T, std::vector<uint32_t>> ||
149
                            std::is_same_v<T, std::vector<uint64_t>> ||
150
                            std::is_same_v<T, std::vector<int16_t>> ||
151
                            std::is_same_v<T, std::vector<int32_t>> ||
152
                            std::is_same_v<T, std::vector<int64_t>> ||
153
                            std::is_same_v<T, std::vector<float>> ||
154
                            std::is_same_v<T, std::vector<double>>) {
155
                            // Handle other vector types
156
                            json_stream << "[";
4✔
157
                            bool first = true;
4✔
158
                            for (const auto& elem : value) {
20✔
159
                                if (!first)
16✔
160
                                    json_stream << ",";
12✔
161
                                first = false;
16✔
162
                                json_stream << elem;
16✔
163
                            }
164
                            json_stream << "]";
4✔
165
                        } else {
166
                            // Fallback for unknown types
167
                            json_stream << "null";
168
                        }
169
                    },
11,518✔
170
                    variant);
171
            } else {
172
                // Field not present or failed to extract
NEW
173
                json_stream << "null";
×
174
            }
175
        }
11,515✔
176
    }
2,119✔
177

178
    json_stream << "}";
2,118✔
179
    return json_stream.str();
2,121✔
180
}
2,122✔
181

NEW
182
std::optional<std::string> LibmavReceiver::message_id_to_name(uint32_t id) const
×
183
{
NEW
184
    auto message_def = _message_set.getMessageDefinition(static_cast<int>(id));
×
NEW
185
    if (message_def) {
×
NEW
186
        return message_def.get().name();
×
187
    }
NEW
188
    return std::nullopt;
×
189
}
190

NEW
191
std::optional<int> LibmavReceiver::message_name_to_id(const std::string& name) const
×
192
{
NEW
193
    return _message_set.idForMessage(name);
×
194
}
195

NEW
196
std::optional<mav::Message> LibmavReceiver::create_message(const std::string& message_name) const
×
197
{
NEW
198
    return _message_set.create(message_name);
×
199
}
200

NEW
201
bool LibmavReceiver::load_custom_xml(const std::string& xml_content)
×
202
{
203
    // Use libmav's addFromXMLString method to load custom XML
NEW
204
    auto result = _message_set.addFromXMLString(xml_content, false /* recursive_open_includes */);
×
205

NEW
206
    if (_debugging) {
×
NEW
207
        if (result == mav::MessageSetResult::Success) {
×
NEW
208
            LogDebug() << "Successfully loaded custom XML definitions";
×
209
        } else {
NEW
210
            LogDebug() << "Failed to load custom XML definitions";
×
211
        }
212
    }
213

NEW
214
    return result == mav::MessageSetResult::Success;
×
215
}
216

217
} // 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