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

mavlink / MAVSDK / 11944365474

21 Nov 2024 12:43AM UTC coverage: 43.566% (+4.9%) from 38.691%
11944365474

Pull #2386

github

web-flow
Merge 2f8c5b774 into c963c5161
Pull Request #2386: camera: support multiple cameras within one instance

1352 of 2024 new or added lines in 47 files covered. (66.8%)

55 existing lines in 9 files now uncovered.

13857 of 31807 relevant lines covered (43.57%)

291.5 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(
75✔
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);
75✔
28

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

35
    // Respond with 'Busy' if already in progress.
36
    for (auto& item : _work_items) {
140✔
37
        if (item.message_id == message_id && item.param2 == param2) {
65✔
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});
75✔
48

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

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

59
void MavlinkRequestMessage::send_request(WorkItem& item)
134✔
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) {
134✔
64
        if (!try_sending_request_using_old_command(item)) {
37✔
65
            send_request_using_new_command(item);
×
66
        }
67
    } else {
68
        send_request_using_new_command(item);
97✔
69
    }
70
}
134✔
71

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

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

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

103
    std::string command_name;
37✔
104

105
    switch (item.message_id) {
37✔
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:
7✔
119
            command_request_message.command = MAV_CMD_REQUEST_CAMERA_SETTINGS;
7✔
120
            command_request_message.params.maybe_param1 = {1.0f};
7✔
121
            command_name = "REQUEST_CAMERA_SETTINGS";
7✔
122

123
            break;
7✔
124

125
        case MAVLINK_MSG_ID_STORAGE_INFORMATION:
13✔
126
            command_request_message.command = MAV_CMD_REQUEST_STORAGE_INFORMATION;
13✔
127
            command_request_message.params.maybe_param1 = {
26✔
128
                static_cast<float>(item.param2)}; // storage ID
26✔
129
            command_request_message.params.maybe_param2 = {1.0f};
13✔
130
            command_name = "REQUEST_STORAGE_INFORMATION";
13✔
131
            break;
13✔
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:
10✔
146
            command_request_message.command = MAV_CMD_REQUEST_VIDEO_STREAM_STATUS;
10✔
147
            command_request_message.params.maybe_param1 = {
20✔
148
                static_cast<float>(item.param2)}; // stream ID
20✔
149
            command_name = "REQUEST_VIDEO_STREAM_STATUS";
10✔
150
            break;
10✔
151

152
        case MAVLINK_MSG_ID_VIDEO_STREAM_INFORMATION:
5✔
153
            command_request_message.command = MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION;
5✔
154
            command_request_message.params.maybe_param1 = {
10✔
155
                static_cast<float>(item.param2)}; // stream ID
10✔
156
            command_name = "REQUEST_VIDEO_STREAM_INFORMATION";
5✔
157
            break;
5✔
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
74✔
172
              << " (retries: " << item.retries << ")";
74✔
173

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

183
    return true;
37✔
184
}
37✔
185

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

190
    for (auto it = _work_items.begin(); it != _work_items.end(); ++it) {
82✔
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) {
81✔
194
            continue;
21✔
195
        }
196

197
        _timeout_handler.remove(it->timeout_cookie);
60✔
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;
60✔
203
        // We can now get rid of the entry now.
204
        _work_items.erase(it);
60✔
205
        // We have to clean up later outside this callback, otherwise we lock ourselves out.
206
        _deferred_message_cleanup.push_back(message.msgid);
60✔
207
        lock.unlock();
60✔
208

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

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

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

227
        switch (result) {
91✔
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:
68✔
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) {
68✔
249
                    // We have already retried, let's give up.
250
                    auto temp_callback = it->callback;
11✔
251
                    _message_handler.unregister_one(it->message_id, this);
11✔
252
                    _work_items.erase(it);
11✔
253
                    lock.unlock();
11✔
254
                    if (temp_callback) {
11✔
NEW
255
                        temp_callback(MavlinkCommandSender::Result::Timeout, {});
×
256
                    }
257
                } else {
11✔
258
                    send_request(*it);
57✔
259
                }
260
                return;
68✔
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
}
133✔
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