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

mavlink / MAVSDK / 12128085511

02 Dec 2024 09:14PM UTC coverage: 43.581% (+4.9%) from 38.69%
12128085511

Pull #2386

github

web-flow
Merge 6aae1420a into 68856f27a
Pull Request #2386: camera: support multiple cameras within one instance

1368 of 2039 new or added lines in 47 files covered. (67.09%)

47 existing lines in 7 files now uncovered.

13875 of 31837 relevant lines covered (43.58%)

287.07 hits per line

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

72.63
/src/mavsdk/core/mavlink_request_message.cpp
1

2
#include "log.h"
3
#include "mavlink_request_message.h"
4
#include "system_impl.h"
5
#include <cstdint>
6
#include <string>
7

8
namespace mavsdk {
9

10
MavlinkRequestMessage::MavlinkRequestMessage(
86✔
11
    SystemImpl& system_impl,
12
    MavlinkCommandSender& command_sender,
13
    MavlinkMessageHandler& message_handler,
14
    TimeoutHandler& timeout_handler) :
86✔
15
    _system_impl(system_impl),
86✔
16
    _command_sender(command_sender),
86✔
17
    _message_handler(message_handler),
86✔
18
    _timeout_handler(timeout_handler)
86✔
19
{}
86✔
20

21
void MavlinkRequestMessage::request(
65✔
22
    uint32_t message_id,
23
    uint8_t target_component,
24
    MavlinkRequestMessageCallback callback,
25
    uint32_t param2)
26
{
27
    std::unique_lock<std::mutex> lock(_mutex);
65✔
28

29
    // Cleanup previous requests.
30
    for (const auto id : _deferred_message_cleanup) {
76✔
31
        _message_handler.unregister_one(id, this);
11✔
32
    }
33
    _deferred_message_cleanup.clear();
65✔
34

35
    // Respond with 'Busy' if already in progress.
36
    for (auto& item : _work_items) {
100✔
37
        if (item.message_id == message_id && item.param2 == param2) {
35✔
38
            lock.unlock();
×
39
            if (callback) {
×
40
                callback(MavlinkCommandSender::Result::Busy, {});
×
41
            }
42
            return;
×
43
        }
44
    }
45

46
    // Otherwise, schedule it.
47
    _work_items.emplace_back(WorkItem{message_id, target_component, callback, param2});
65✔
48

49
    // Register for message
50
    _message_handler.register_one(
65✔
51
        message_id,
52
        [this](const mavlink_message_t& message) { handle_any_message(message); },
57✔
53
        this);
54

55
    // And send off command
56
    send_request(_work_items.back());
65✔
57
}
65✔
58

59
void MavlinkRequestMessage::send_request(WorkItem& item)
98✔
60
{
61
    // Every second time, starting with first retry, we try the old request commands.
62
    // If no old commands exist, we of course just send the new one again.
63
    if (item.retries % 2 != 0) {
98✔
64
        if (!try_sending_request_using_old_command(item)) {
23✔
65
            send_request_using_new_command(item);
×
66
        }
67
    } else {
68
        send_request_using_new_command(item);
75✔
69
    }
70
}
98✔
71

72
void MavlinkRequestMessage::send_request_using_new_command(WorkItem& item)
75✔
73
{
74
    if (item.retries > 0) {
75✔
75
        LogWarn() << "Request message " << item.message_id
20✔
76
                  << " again using REQUEST_MESSAGE (retries: " << item.retries << ")";
20✔
77
    } else {
78
        LogDebug() << "Request message " << item.message_id << " using REQUEST_MESSAGE";
65✔
79
    }
80

81
    MavlinkCommandSender::CommandLong command_request_message{};
75✔
82
    command_request_message.command = MAV_CMD_REQUEST_MESSAGE;
75✔
83
    command_request_message.target_system_id = _system_impl.get_system_id();
75✔
84
    command_request_message.target_component_id = item.target_component;
75✔
85
    command_request_message.params.maybe_param1 = {static_cast<float>(item.message_id)};
75✔
86
    _command_sender.queue_command_async(
150✔
87
        command_request_message,
88
        [this, message_id = item.message_id](MavlinkCommandSender::Result result, float) {
75✔
89
            if (result != MavlinkCommandSender::Result::InProgress) {
74✔
90
                handle_command_result(message_id, result);
74✔
91
            }
92
        },
74✔
93
        1);
94
}
75✔
95

96
bool MavlinkRequestMessage::try_sending_request_using_old_command(WorkItem& item)
23✔
97
{
98
    LogInfo() << "Try old command";
23✔
99
    MavlinkCommandSender::CommandLong command_request_message{};
23✔
100
    command_request_message.target_system_id = _system_impl.get_system_id();
23✔
101
    command_request_message.target_component_id = item.target_component;
23✔
102

103
    std::string command_name;
23✔
104

105
    switch (item.message_id) {
23✔
106
        case MAVLINK_MSG_ID_AUTOPILOT_VERSION:
2✔
107
            command_request_message.command = MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES;
2✔
108
            command_request_message.params.maybe_param1 = {1.f};
2✔
109
            command_name = "REQUEST_AUTOPILOT_CAPABILITIES";
2✔
110
            break;
2✔
111

112
        case MAVLINK_MSG_ID_CAMERA_INFORMATION:
×
113
            command_request_message.command = MAV_CMD_REQUEST_CAMERA_INFORMATION;
×
114
            command_request_message.params.maybe_param1 = {1.0f};
×
115
            command_name = "REQUEST_CAMERA_INFORMATION";
×
116
            break;
×
117

118
        case MAVLINK_MSG_ID_CAMERA_SETTINGS:
5✔
119
            command_request_message.command = MAV_CMD_REQUEST_CAMERA_SETTINGS;
5✔
120
            command_request_message.params.maybe_param1 = {1.0f};
5✔
121
            command_name = "REQUEST_CAMERA_SETTINGS";
5✔
122

123
            break;
5✔
124

125
        case MAVLINK_MSG_ID_STORAGE_INFORMATION:
9✔
126
            command_request_message.command = MAV_CMD_REQUEST_STORAGE_INFORMATION;
9✔
127
            command_request_message.params.maybe_param1 = {
18✔
128
                static_cast<float>(item.param2)}; // storage ID
18✔
129
            command_request_message.params.maybe_param2 = {1.0f};
9✔
130
            command_name = "REQUEST_STORAGE_INFORMATION";
9✔
131
            break;
9✔
132

133
        case MAVLINK_MSG_ID_CAMERA_CAPTURE_STATUS:
×
134
            command_request_message.command = MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS;
×
135
            command_request_message.params.maybe_param1 = {1.0f};
×
136
            command_name = "REQUEST_CAMERA_CAPTURE_STATUS";
×
137
            break;
×
138

139
        case MAVLINK_MSG_ID_FLIGHT_INFORMATION:
×
140
            command_request_message.command = MAV_CMD_REQUEST_FLIGHT_INFORMATION;
×
141
            command_request_message.params.maybe_param1 = {1.0f};
×
142
            command_name = "REQUEST_FLIGHT_INFORMATION";
×
143
            break;
×
144

145
        case MAVLINK_MSG_ID_VIDEO_STREAM_STATUS:
6✔
146
            command_request_message.command = MAV_CMD_REQUEST_VIDEO_STREAM_STATUS;
6✔
147
            command_request_message.params.maybe_param1 = {
12✔
148
                static_cast<float>(item.param2)}; // stream ID
12✔
149
            command_name = "REQUEST_VIDEO_STREAM_STATUS";
6✔
150
            break;
6✔
151

152
        case MAVLINK_MSG_ID_VIDEO_STREAM_INFORMATION:
1✔
153
            command_request_message.command = MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION;
1✔
154
            command_request_message.params.maybe_param1 = {
2✔
155
                static_cast<float>(item.param2)}; // stream ID
2✔
156
            command_name = "REQUEST_VIDEO_STREAM_INFORMATION";
1✔
157
            break;
1✔
158

159
        case MAVLINK_MSG_ID_CAMERA_IMAGE_CAPTURED:
×
160
            command_request_message.command = MAV_CMD_REQUEST_CAMERA_IMAGE_CAPTURE;
×
161
            command_request_message.params.maybe_param1 = {
×
162
                static_cast<float>(item.param2)}; // sequence number
×
163
            command_name = "REQUEST_CAMERA_IMAGE_CAPTURE";
×
164
            break;
×
165

166
        default:
×
167
            // No alternative command for this message.
168
            return false;
×
169
    }
170

171
    LogWarn() << "Request message " << item.message_id << " again using " << command_name
46✔
172
              << " (retries: " << item.retries << ")";
46✔
173

174
    _command_sender.queue_command_async(
46✔
175
        command_request_message,
176
        [this, message_id = item.message_id](MavlinkCommandSender::Result result, float) {
23✔
177
            if (result != MavlinkCommandSender::Result::InProgress) {
23✔
178
                handle_command_result(message_id, result);
23✔
179
            }
180
        },
23✔
181
        1);
182

183
    return true;
23✔
184
}
23✔
185

186
void MavlinkRequestMessage::handle_any_message(const mavlink_message_t& message)
57✔
187
{
188
    std::unique_lock<std::mutex> lock(_mutex);
57✔
189

190
    for (auto it = _work_items.begin(); it != _work_items.end(); ++it) {
68✔
191
        // Check if we're waiting for this message.
192
        // TODO: check if params are correct.
193
        if (it->message_id != message.msgid && it->target_component == message.compid) {
67✔
194
            continue;
11✔
195
        }
196

197
        _timeout_handler.remove(it->timeout_cookie);
56✔
198
        // We have at least the message which is what we care about most, so we
199
        // tell the user about it and call it a day. If we receive the result
200
        // of the command later, we ignore it, and we fake the result to be successful
201
        // anyway.
202
        auto temp_callback = it->callback;
56✔
203
        // We can now get rid of the entry now.
204
        _work_items.erase(it);
56✔
205
        // We have to clean up later outside this callback, otherwise we lock ourselves out.
206
        _deferred_message_cleanup.push_back(message.msgid);
56✔
207
        lock.unlock();
56✔
208

209
        if (temp_callback) {
56✔
210
            temp_callback(MavlinkCommandSender::Result::Success, message);
1✔
211
        }
212
        return;
56✔
213
    }
56✔
214
}
57✔
215

216
void MavlinkRequestMessage::handle_command_result(
97✔
217
    uint32_t message_id, MavlinkCommandSender::Result result)
218
{
219
    std::unique_lock<std::mutex> lock(_mutex);
97✔
220

221
    for (auto it = _work_items.begin(); it != _work_items.end(); ++it) {
127✔
222
        // Check if we're waiting for this result
223
        if (it->message_id != message_id) {
89✔
224
            continue;
30✔
225
        }
226

227
        switch (result) {
59✔
228
            case MavlinkCommandSender::Result::Success:
23✔
229
                // This is promising, let's hope the message will actually arrive.
230
                // We'll set a timeout in case we need to retry.
231
                it->timeout_cookie = _timeout_handler.add(
46✔
232
                    [this, message_id, target_component = it->target_component]() {
23✔
233
                        handle_timeout(message_id, target_component);
2✔
234
                    },
2✔
235
                    1.0);
236
                return;
23✔
237

238
            case MavlinkCommandSender::Result::Busy:
36✔
239
                // FALLTHROUGH
240
            case MavlinkCommandSender::Result::Denied:
241
                // FALLTHROUGH
242
            case MavlinkCommandSender::Result::Unsupported:
243
                // FALLTHROUGH
244
            case MavlinkCommandSender::Result::Timeout:
245
                // FALLTHROUGH
246
            case MavlinkCommandSender::Result::TemporarilyRejected:
247
                // It looks like we should try again
248
                if (++it->retries > RETRIES) {
36✔
249
                    // We have already retried, let's give up.
250
                    auto temp_callback = it->callback;
5✔
251
                    _message_handler.unregister_one(it->message_id, this);
5✔
252
                    _work_items.erase(it);
5✔
253
                    lock.unlock();
5✔
254
                    if (temp_callback) {
5✔
NEW
255
                        temp_callback(MavlinkCommandSender::Result::Timeout, {});
×
256
                    }
257
                } else {
5✔
258
                    send_request(*it);
31✔
259
                }
260
                return;
36✔
261

NEW
262
            case MavlinkCommandSender::Result::NoSystem:
×
263
                // FALLTHROUGH
264
            case MavlinkCommandSender::Result::ConnectionError:
265
                // FALLTHROUGH
266
            case MavlinkCommandSender::Result::Failed:
267
                // FALLTHROUGH
268
            case MavlinkCommandSender::Result::Cancelled:
269
                // FALLTHROUGH
270
            case MavlinkCommandSender::Result::UnknownError: {
271
                // It looks like this did not work, and we can report the error
272
                // No need to try again.
273
                auto temp_callback = it->callback;
×
274
                _message_handler.unregister_one(it->message_id, this);
×
275
                _work_items.erase(it);
×
276
                lock.unlock();
×
277
                if (temp_callback) {
×
278
                    temp_callback(result, {});
×
279
                }
280
                return;
×
281
            }
×
282

283
            case MavlinkCommandSender::Result::InProgress:
×
284
                // Should not happen, as it is already filtered out.
285
                return;
×
286
        }
287
    }
288
}
97✔
289

290
void MavlinkRequestMessage::handle_timeout(uint32_t message_id, uint8_t target_component)
2✔
291
{
292
    std::unique_lock<std::mutex> lock(_mutex);
2✔
293

294
    for (auto it = _work_items.begin(); it != _work_items.end(); ++it) {
4✔
295
        // Check if we're waiting for this result
296
        if (it->message_id != message_id || it->target_component != target_component) {
2✔
297
            continue;
×
298
        }
299

300
        if (++it->retries > RETRIES) {
2✔
301
            // We have already retried, let's give up.
302
            auto temp_callback = it->callback;
×
303
            _message_handler.unregister_one(it->message_id, this);
×
304
            _work_items.erase(it);
×
305
            lock.unlock();
×
306
            if (temp_callback) {
×
307
                temp_callback(MavlinkCommandSender::Result::Timeout, {});
×
308
            }
309
            return;
×
310
        }
×
311

312
        send_request(*it);
2✔
313
    }
314
}
2✔
315

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