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

mavlink / MAVSDK / 29547914454

17 Jul 2026 01:37AM UTC coverage: 50.413%. First build
29547914454

Pull #2936

github

web-flow
Merge 46af30374 into 23fd28534
Pull Request #2936: Backport various bugfixes to v3

162 of 257 new or added lines in 24 files covered. (63.04%)

19304 of 38292 relevant lines covered (50.41%)

668.85 hits per line

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

37.72
/src/mavsdk/plugins/camera_server/camera_server_impl.cpp
1
#include "camera_server_impl.h"
2
#include "callback_list.tpp"
3
#include "mavsdk_export.h"
4

5
namespace mavsdk {
6

7
template class MAVSDK_TEMPL_INST CallbackList<int32_t>;
8
template class MAVSDK_TEMPL_INST CallbackList<CameraServer::TrackPoint>;
9
template class MAVSDK_TEMPL_INST CallbackList<CameraServer::TrackRectangle>;
10

11
CameraServerImpl::CameraServerImpl(std::shared_ptr<ServerComponent> server_component) :
11✔
12
    ServerPluginImplBase(server_component)
11✔
13
{
14
    _server_component_impl->register_plugin(this);
11✔
15
}
11✔
16

17
CameraServerImpl::~CameraServerImpl()
22✔
18
{
19
    stop_sending_tracking_status();
11✔
20
    _server_component_impl->unregister_plugin(this);
11✔
21
}
22✔
22

23
void CameraServerImpl::init()
11✔
24
{
25
    _server_component_impl->register_mavlink_command_handler(
11✔
26
        MAV_CMD_REQUEST_MESSAGE,
27
        [this](const MavlinkCommandReceiver::CommandLong& command) {
121✔
28
            return process_request_message(command);
121✔
29
        },
30
        this);
31
    _server_component_impl->register_mavlink_command_handler(
11✔
32
        MAV_CMD_REQUEST_CAMERA_INFORMATION,
33
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
34
            return process_camera_information_request(command);
×
35
        },
36
        this);
37
    _server_component_impl->register_mavlink_command_handler(
11✔
38
        MAV_CMD_REQUEST_CAMERA_SETTINGS,
39
        [this](const MavlinkCommandReceiver::CommandLong& command) {
11✔
40
            return process_camera_settings_request(command);
11✔
41
        },
42
        this);
43
    _server_component_impl->register_mavlink_command_handler(
11✔
44
        MAV_CMD_REQUEST_STORAGE_INFORMATION,
45
        [this](const MavlinkCommandReceiver::CommandLong& command) {
20✔
46
            return process_storage_information_request(command);
20✔
47
        },
48
        this);
49
    _server_component_impl->register_mavlink_command_handler(
11✔
50
        MAV_CMD_STORAGE_FORMAT,
51
        [this](const MavlinkCommandReceiver::CommandLong& command) {
1✔
52
            return process_storage_format(command);
1✔
53
        },
54
        this);
55
    _server_component_impl->register_mavlink_command_handler(
11✔
56
        MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS,
57
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
58
            return process_camera_capture_status_request(command);
×
59
        },
60
        this);
61
    _server_component_impl->register_mavlink_command_handler(
11✔
62
        MAV_CMD_RESET_CAMERA_SETTINGS,
63
        [this](const MavlinkCommandReceiver::CommandLong& command) {
1✔
64
            return process_reset_camera_settings(command);
1✔
65
        },
66
        this);
67
    _server_component_impl->register_mavlink_command_handler(
11✔
68
        MAV_CMD_SET_CAMERA_MODE,
69
        [this](const MavlinkCommandReceiver::CommandLong& command) {
2✔
70
            return process_set_camera_mode(command);
2✔
71
        },
72
        this);
73
    _server_component_impl->register_mavlink_command_handler(
11✔
74
        MAV_CMD_SET_CAMERA_ZOOM,
75
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
76
            return process_set_camera_zoom(command);
×
77
        },
78
        this);
79
    _server_component_impl->register_mavlink_command_handler(
11✔
80
        MAV_CMD_SET_CAMERA_FOCUS,
81
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
82
            return process_set_camera_focus(command);
×
83
        },
84
        this);
85
    _server_component_impl->register_mavlink_command_handler(
11✔
86
        MAV_CMD_SET_STORAGE_USAGE,
87
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
88
            return process_set_storage_usage(command);
×
89
        },
90
        this);
91
    _server_component_impl->register_mavlink_command_handler(
11✔
92
        MAV_CMD_IMAGE_START_CAPTURE,
93
        [this](const MavlinkCommandReceiver::CommandLong& command) {
2✔
94
            return process_image_start_capture(command);
2✔
95
        },
96
        this);
97
    _server_component_impl->register_mavlink_command_handler(
11✔
98
        MAV_CMD_IMAGE_STOP_CAPTURE,
99
        [this](const MavlinkCommandReceiver::CommandLong& command) {
1✔
100
            return process_image_stop_capture(command);
1✔
101
        },
102
        this);
103
    _server_component_impl->register_mavlink_command_handler(
11✔
104
        MAV_CMD_REQUEST_CAMERA_IMAGE_CAPTURE,
105
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
106
            return process_camera_image_capture_request(command);
×
107
        },
108
        this);
109
    _server_component_impl->register_mavlink_command_handler(
11✔
110
        MAV_CMD_VIDEO_START_CAPTURE,
111
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
112
            return process_video_start_capture(command);
×
113
        },
114
        this);
115
    _server_component_impl->register_mavlink_command_handler(
11✔
116
        MAV_CMD_VIDEO_STOP_CAPTURE,
117
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
118
            return process_video_stop_capture(command);
×
119
        },
120
        this);
121
    _server_component_impl->register_mavlink_command_handler(
11✔
122
        MAV_CMD_VIDEO_START_STREAMING,
123
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
124
            return process_video_start_streaming(command);
×
125
        },
126
        this);
127
    _server_component_impl->register_mavlink_command_handler(
11✔
128
        MAV_CMD_VIDEO_STOP_STREAMING,
129
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
130
            return process_video_stop_streaming(command);
×
131
        },
132
        this);
133
    _server_component_impl->register_mavlink_command_handler(
11✔
134
        MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION,
135
        [this](const MavlinkCommandReceiver::CommandLong& command) {
19✔
136
            return process_video_stream_information_request(command);
19✔
137
        },
138
        this);
139
    _server_component_impl->register_mavlink_command_handler(
11✔
140
        MAV_CMD_REQUEST_VIDEO_STREAM_STATUS,
141
        [this](const MavlinkCommandReceiver::CommandLong& command) {
21✔
142
            return process_video_stream_status_request(command);
21✔
143
        },
144
        this);
145
    _server_component_impl->register_mavlink_command_handler(
11✔
146
        MAV_CMD_CAMERA_TRACK_POINT,
147
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
148
            return process_track_point_command(command);
×
149
        },
150
        this);
151

152
    _server_component_impl->register_mavlink_command_handler(
11✔
153
        MAV_CMD_CAMERA_TRACK_RECTANGLE,
154
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
155
            return process_track_rectangle_command(command);
×
156
        },
157
        this);
158

159
    _server_component_impl->register_mavlink_command_handler(
11✔
160
        MAV_CMD_CAMERA_STOP_TRACKING,
161
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
162
            return process_track_off_command(command);
×
163
        },
164
        this);
165
    _server_component_impl->register_mavlink_command_handler(
11✔
166
        MAV_CMD_SET_MESSAGE_INTERVAL,
167
        [this](const MavlinkCommandReceiver::CommandLong& command) {
×
168
            return process_set_message_interval(command);
×
169
        },
170
        this);
171
}
11✔
172

173
void CameraServerImpl::deinit()
11✔
174
{
175
    stop_image_capture_interval();
11✔
176
    stop_sending_capture_status();
11✔
177
    _server_component_impl->unregister_all_mavlink_command_handlers(this);
11✔
178

179
    std::lock_guard lg(_mutex);
11✔
180
    _take_photo_callbacks.clear();
11✔
181
    _start_video_callbacks.clear();
11✔
182
    _stop_video_callbacks.clear();
11✔
183
    _start_video_streaming_callbacks.clear();
11✔
184
    _stop_video_streaming_callbacks.clear();
11✔
185
    _set_mode_callbacks.clear();
11✔
186
    _storage_information_callbacks.clear();
11✔
187
    _capture_status_callbacks.clear();
11✔
188
    _format_storage_callbacks.clear();
11✔
189
    _reset_settings_callbacks.clear();
11✔
190
    _tracking_point_callbacks.clear();
11✔
191
    _tracking_rectangle_callbacks.clear();
11✔
192
    _tracking_off_callbacks.clear();
11✔
193
    _zoom_in_start_callbacks.clear();
11✔
194
    _zoom_out_start_callbacks.clear();
11✔
195
    _zoom_stop_callbacks.clear();
11✔
196
    _zoom_range_callbacks.clear();
11✔
197
}
11✔
198

199
bool CameraServerImpl::is_command_sender_ok(const MavlinkCommandReceiver::CommandLong& command)
×
200
{
201
    if (command.target_system_id != 0 &&
×
202
        command.target_system_id != _server_component_impl->get_own_system_id()) {
×
203
        return false;
×
204
    } else {
205
        return true;
×
206
    }
207
}
208

209
void CameraServerImpl::set_tracking_point_status(CameraServer::TrackPoint tracked_point)
×
210
{
211
    std::lock_guard<std::mutex> lg{_mutex};
×
212
    _tracking_mode = TrackingMode::POINT;
×
213
    _tracked_point = tracked_point;
×
214
}
×
215

216
void CameraServerImpl::set_tracking_rectangle_status(CameraServer::TrackRectangle tracked_rectangle)
×
217
{
218
    std::lock_guard<std::mutex> lg{_mutex};
×
219
    _tracking_mode = TrackingMode::RECTANGLE;
×
220
    _tracked_rectangle = tracked_rectangle;
×
221
}
×
222

223
void CameraServerImpl::set_tracking_off_status()
×
224
{
225
    std::lock_guard<std::mutex> lg{_mutex};
×
226
    _tracking_mode = TrackingMode::NONE;
×
227
}
×
228

229
bool CameraServerImpl::parse_version_string(const std::string& version_str)
11✔
230
{
231
    uint32_t unused;
232

233
    return parse_version_string(version_str, unused);
11✔
234
}
235

236
bool CameraServerImpl::parse_version_string(const std::string& version_str, uint32_t& version)
22✔
237
{
238
    // empty string means no version
239
    if (version_str.empty()) {
22✔
240
        version = 0;
×
241

242
        return true;
×
243
    }
244

245
    uint8_t major{}, minor{}, patch{}, dev{};
22✔
246

247
    auto ret = sscanf(version_str.c_str(), "%hhu.%hhu.%hhu.%hhu", &major, &minor, &patch, &dev);
22✔
248

249
    if (ret == EOF) {
22✔
250
        return false;
×
251
    }
252

253
    // pack version according to MAVLINK spec
254
    version = dev << 24 | patch << 16 | minor << 8 | major;
22✔
255

256
    return true;
22✔
257
}
258

259
CameraServer::Result CameraServerImpl::set_information(CameraServer::Information information)
11✔
260
{
261
    if (!parse_version_string(information.firmware_version)) {
11✔
262
        LogDebug() << "incorrectly formatted firmware version string: "
×
263
                   << information.firmware_version;
×
264
        return CameraServer::Result::WrongArgument;
×
265
    }
266

267
    std::lock_guard<std::mutex> lg{_mutex};
11✔
268

269
    // TODO: validate information.definition_file_uri
270

271
    _is_information_set = true;
11✔
272
    _information = information;
11✔
273

274
    return CameraServer::Result::Success;
11✔
275
}
11✔
276

277
CameraServer::Result
278
CameraServerImpl::set_video_streaming(CameraServer::VideoStreaming video_streaming)
1✔
279
{
280
    // TODO: validate uri length
281

282
    std::lock_guard<std::mutex> lg{_mutex};
1✔
283

284
    _is_video_streaming_set = true;
1✔
285
    _video_streaming = video_streaming;
1✔
286

287
    return CameraServer::Result::Success;
2✔
288
}
1✔
289

290
CameraServer::Result CameraServerImpl::set_in_progress(bool in_progress)
×
291
{
292
    _is_image_capture_in_progress = in_progress;
×
293

294
    send_capture_status();
×
295
    return CameraServer::Result::Success;
×
296
}
297

298
CameraServer::TakePhotoHandle
299
CameraServerImpl::subscribe_take_photo(const CameraServer::TakePhotoCallback& callback)
2✔
300
{
301
    std::lock_guard<std::mutex> lg{_mutex};
2✔
302
    return _take_photo_callbacks.subscribe(callback);
2✔
303
}
2✔
304

305
void CameraServerImpl::unsubscribe_take_photo(CameraServer::TakePhotoHandle handle)
×
306
{
307
    std::lock_guard<std::mutex> lg{_mutex};
×
308
    _take_photo_callbacks.unsubscribe(handle);
×
309
}
×
310

311
CameraServer::Result CameraServerImpl::respond_take_photo(
4✔
312
    CameraServer::CameraFeedback take_photo_feedback, CameraServer::CaptureInfo capture_info)
313
{
314
    bool should_send_capture_status = false;
4✔
315

316
    {
317
        std::lock_guard<std::mutex> lg{_mutex};
4✔
318

319
        // If capture_info.index == INT32_MIN, it means this was an interval
320
        // capture rather than a single image capture.
321
        if (capture_info.index != INT32_MIN) {
4✔
322
            // We expect each capture to be the next sequential number.
323
            // If _image_capture_count == 0, we ignore since it means that this is
324
            // the first photo since the plugin was initialized.
325
            if (_image_capture_count != 0 && capture_info.index != _image_capture_count + 1) {
4✔
326
                LogErr() << "unexpected image index, expecting " << +(_image_capture_count + 1)
×
327
                         << " but was " << +capture_info.index;
×
328
            }
329

330
            _image_capture_count = capture_info.index;
4✔
331
        }
332

333
        // Log the command details to help debug
334
        LogDebug() << "Responding to take photo command: " << "target_system_id: "
4✔
335
                   << static_cast<int>(_last_take_photo_command.target_system_id)
4✔
336
                   << ", target_component_id: "
4✔
337
                   << static_cast<int>(_last_take_photo_command.target_component_id)
8✔
338
                   << ", command: " << _last_take_photo_command.command;
4✔
339

340
        switch (take_photo_feedback) {
4✔
341
            default:
×
342
                // Fallthrough
343
            case CameraServer::CameraFeedback::Unknown:
344
                return CameraServer::Result::Error;
×
345
            case CameraServer::CameraFeedback::Ok: {
4✔
346
                // Check for error above
347
                auto command_ack = _server_component_impl->make_command_ack_message(
4✔
348
                    _last_take_photo_command, MAV_RESULT_ACCEPTED);
4✔
349
                _server_component_impl->send_command_ack(command_ack);
4✔
350
                should_send_capture_status = true;
4✔
351
                // Only break and send the captured below.
352
                break;
4✔
353
            }
354
            case CameraServer::CameraFeedback::Busy: {
×
355
                auto command_ack = _server_component_impl->make_command_ack_message(
×
356
                    _last_take_photo_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
357
                _server_component_impl->send_command_ack(command_ack);
×
358
                return CameraServer::Result::Success;
×
359
            }
360

361
            case CameraServer::CameraFeedback::Failed: {
×
362
                auto command_ack = _server_component_impl->make_command_ack_message(
×
363
                    _last_take_photo_command, MAV_RESULT_FAILED);
×
364
                _server_component_impl->send_command_ack(command_ack);
×
365
                return CameraServer::Result::Success;
×
366
            }
367
        }
368

369
        // REVISIT: Should we cache all CaptureInfo in memory for single image
370
        // captures so that we can respond to requests for lost CAMERA_IMAGE_CAPTURED
371
        // messages without calling back to user code?
372

373
        static const uint8_t camera_id = 0; // deprecated unused field
374

375
        const float attitude_quaternion[] = {
376
            capture_info.attitude_quaternion.w,
4✔
377
            capture_info.attitude_quaternion.x,
4✔
378
            capture_info.attitude_quaternion.y,
4✔
379
            capture_info.attitude_quaternion.z,
4✔
380
        };
4✔
381

382
        // There needs to be enough data to be copied mavlink internal.
383
        capture_info.file_url.resize(205);
4✔
384

385
        // TODO: this should be a broadcast message
386
        _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
4✔
387
            mavlink_message_t message{};
4✔
388
            mavlink_msg_camera_image_captured_pack_chan(
12✔
389
                mavlink_address.system_id,
4✔
390
                mavlink_address.component_id,
4✔
391
                channel,
392
                &message,
393
                static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
4✔
394
                capture_info.time_utc_us,
4✔
395
                camera_id,
396
                static_cast<int32_t>(capture_info.position.latitude_deg * 1e7),
4✔
397
                static_cast<int32_t>(capture_info.position.longitude_deg * 1e7),
4✔
398
                static_cast<int32_t>(capture_info.position.absolute_altitude_m * 1e3f),
4✔
399
                static_cast<int32_t>(capture_info.position.relative_altitude_m * 1e3f),
4✔
400
                attitude_quaternion,
4✔
401
                capture_info.index,
402
                capture_info.is_success,
4✔
403
                capture_info.file_url.c_str());
404
            return message;
4✔
405
        });
406
        LogDebug() << "sent camera image captured msg - index: " << +capture_info.index;
4✔
407

408
    } // Release mutex
4✔
409

410
    if (should_send_capture_status) {
4✔
411
        send_capture_status();
4✔
412
    }
413

414
    return CameraServer::Result::Success;
4✔
415
}
416

417
CameraServer::StartVideoHandle
418
CameraServerImpl::subscribe_start_video(const CameraServer::StartVideoCallback& callback)
×
419
{
420
    std::lock_guard<std::mutex> lg{_mutex};
×
421
    return _start_video_callbacks.subscribe(callback);
×
422
}
×
423

424
void CameraServerImpl::unsubscribe_start_video(CameraServer::StartVideoHandle handle)
×
425
{
426
    std::lock_guard<std::mutex> lg{_mutex};
×
427
    _start_video_callbacks.unsubscribe(handle);
×
428
}
×
429

430
CameraServer::Result
431
CameraServerImpl::respond_start_video(CameraServer::CameraFeedback start_video_feedback)
×
432
{
433
    bool should_send_capture_status = false;
×
434

435
    {
436
        std::lock_guard<std::mutex> lg{_mutex};
×
437

438
        switch (start_video_feedback) {
×
439
            default:
×
440
                // Fallthrough
441
            case CameraServer::CameraFeedback::Unknown:
442
                return CameraServer::Result::Error;
×
443
            case CameraServer::CameraFeedback::Ok: {
×
444
                auto command_ack = _server_component_impl->make_command_ack_message(
×
445
                    _last_start_video_command, MAV_RESULT_ACCEPTED);
×
446
                _server_component_impl->send_command_ack(command_ack);
×
447
                _capture_status.video_status =
×
448
                    CameraServer::CaptureStatus::VideoStatus::CaptureInProgress;
449
                should_send_capture_status = true;
×
450
                break;
×
451
            }
452
            case CameraServer::CameraFeedback::Busy: {
×
453
                auto command_ack = _server_component_impl->make_command_ack_message(
×
454
                    _last_start_video_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
455
                _server_component_impl->send_command_ack(command_ack);
×
456
                return CameraServer::Result::Success;
×
457
            }
458
            case CameraServer::CameraFeedback::Failed: {
×
459
                auto command_ack = _server_component_impl->make_command_ack_message(
×
460
                    _last_start_video_command, MAV_RESULT_FAILED);
×
461
                _server_component_impl->send_command_ack(command_ack);
×
462
                return CameraServer::Result::Success;
×
463
            }
464
        }
465
    } // Release mutex
×
466

467
    if (should_send_capture_status) {
×
468
        send_capture_status();
×
469
    }
470

471
    return CameraServer::Result::Success;
×
472
}
473

474
CameraServer::StopVideoHandle
475
CameraServerImpl::subscribe_stop_video(const CameraServer::StopVideoCallback& callback)
×
476
{
477
    std::lock_guard<std::mutex> lg{_mutex};
×
478
    return _stop_video_callbacks.subscribe(callback);
×
479
}
×
480

481
void CameraServerImpl::unsubscribe_stop_video(CameraServer::StopVideoHandle handle)
×
482
{
483
    std::lock_guard<std::mutex> lg{_mutex};
×
484
    return _stop_video_callbacks.unsubscribe(handle);
×
485
}
×
486

487
CameraServer::Result
488
CameraServerImpl::respond_stop_video(CameraServer::CameraFeedback stop_video_feedback)
×
489
{
490
    bool should_send_capture_status = false;
×
491

492
    {
493
        std::lock_guard<std::mutex> lg{_mutex};
×
494

495
        switch (stop_video_feedback) {
×
496
            default:
×
497
                // Fallthrough
498
            case CameraServer::CameraFeedback::Unknown:
499
                return CameraServer::Result::Error;
×
500
            case CameraServer::CameraFeedback::Ok: {
×
501
                auto command_ack = _server_component_impl->make_command_ack_message(
×
502
                    _last_stop_video_command, MAV_RESULT_ACCEPTED);
×
503
                _server_component_impl->send_command_ack(command_ack);
×
504
                _capture_status.video_status = CameraServer::CaptureStatus::VideoStatus::Idle;
×
505
                should_send_capture_status = true;
×
506
                break;
×
507
            }
508
            case CameraServer::CameraFeedback::Busy: {
×
509
                auto command_ack = _server_component_impl->make_command_ack_message(
×
510
                    _last_stop_video_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
511
                _server_component_impl->send_command_ack(command_ack);
×
512
                return CameraServer::Result::Success;
×
513
            }
514
            case CameraServer::CameraFeedback::Failed: {
×
515
                auto command_ack = _server_component_impl->make_command_ack_message(
×
516
                    _last_stop_video_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
517
                _server_component_impl->send_command_ack(command_ack);
×
518
                return CameraServer::Result::Success;
×
519
            }
520
        }
521
    } // Release mutex
×
522

523
    if (should_send_capture_status) {
×
524
        send_capture_status();
×
525
    }
526

527
    return CameraServer::Result::Success;
×
528
}
529

530
CameraServer::StartVideoStreamingHandle CameraServerImpl::subscribe_start_video_streaming(
×
531
    const CameraServer::StartVideoStreamingCallback& callback)
532
{
533
    std::lock_guard<std::mutex> lg{_mutex};
×
534
    return _start_video_streaming_callbacks.subscribe(callback);
×
535
}
×
536

537
void CameraServerImpl::unsubscribe_start_video_streaming(
×
538
    CameraServer::StartVideoStreamingHandle handle)
539
{
540
    std::lock_guard<std::mutex> lg{_mutex};
×
541
    return _start_video_streaming_callbacks.unsubscribe(handle);
×
542
}
×
543

544
CameraServer::Result CameraServerImpl::respond_start_video_streaming(
×
545
    CameraServer::CameraFeedback start_video_streaming_feedback)
546
{
547
    std::lock_guard<std::mutex> lg{_mutex};
×
548

549
    switch (start_video_streaming_feedback) {
×
550
        default:
×
551
            // Fallthrough
552
        case CameraServer::CameraFeedback::Unknown:
553
            return CameraServer::Result::Error;
×
554
        case CameraServer::CameraFeedback::Ok: {
×
555
            auto command_ack = _server_component_impl->make_command_ack_message(
×
556
                _last_start_video_streaming_command, MAV_RESULT_ACCEPTED);
×
557
            _server_component_impl->send_command_ack(command_ack);
×
558
            return CameraServer::Result::Success;
×
559
        }
560
        case CameraServer::CameraFeedback::Busy: {
×
561
            auto command_ack = _server_component_impl->make_command_ack_message(
×
562
                _last_start_video_streaming_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
563
            _server_component_impl->send_command_ack(command_ack);
×
564
            return CameraServer::Result::Success;
×
565
        }
566
        case CameraServer::CameraFeedback::Failed: {
×
567
            auto command_ack = _server_component_impl->make_command_ack_message(
×
568
                _last_start_video_streaming_command, MAV_RESULT_FAILED);
×
569
            _server_component_impl->send_command_ack(command_ack);
×
570
            return CameraServer::Result::Success;
×
571
        }
572
    }
573
}
×
574

575
CameraServer::StopVideoStreamingHandle CameraServerImpl::subscribe_stop_video_streaming(
×
576
    const CameraServer::StopVideoStreamingCallback& callback)
577
{
578
    std::lock_guard<std::mutex> lg{_mutex};
×
579
    return _stop_video_streaming_callbacks.subscribe(callback);
×
580
}
×
581

582
void CameraServerImpl::unsubscribe_stop_video_streaming(
×
583
    CameraServer::StopVideoStreamingHandle handle)
584
{
585
    std::lock_guard<std::mutex> lg{_mutex};
×
586
    return _stop_video_streaming_callbacks.unsubscribe(handle);
×
587
}
×
588

589
CameraServer::Result CameraServerImpl::respond_stop_video_streaming(
×
590
    CameraServer::CameraFeedback stop_video_streaming_feedback)
591
{
592
    std::lock_guard<std::mutex> lg{_mutex};
×
593

594
    switch (stop_video_streaming_feedback) {
×
595
        default:
×
596
            // Fallthrough
597
        case CameraServer::CameraFeedback::Unknown:
598
            return CameraServer::Result::Error;
×
599
        case CameraServer::CameraFeedback::Ok: {
×
600
            auto command_ack = _server_component_impl->make_command_ack_message(
×
601
                _last_stop_video_streaming_command, MAV_RESULT_ACCEPTED);
×
602
            _server_component_impl->send_command_ack(command_ack);
×
603
            return CameraServer::Result::Success;
×
604
        }
605
        case CameraServer::CameraFeedback::Busy: {
×
606
            auto command_ack = _server_component_impl->make_command_ack_message(
×
607
                _last_stop_video_streaming_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
608
            _server_component_impl->send_command_ack(command_ack);
×
609
            return CameraServer::Result::Success;
×
610
        }
611
        case CameraServer::CameraFeedback::Failed: {
×
612
            auto command_ack = _server_component_impl->make_command_ack_message(
×
613
                _last_stop_video_streaming_command, MAV_RESULT_FAILED);
×
614
            _server_component_impl->send_command_ack(command_ack);
×
615
            return CameraServer::Result::Success;
×
616
        }
617
    }
618
}
×
619

620
CameraServer::SetModeHandle
621
CameraServerImpl::subscribe_set_mode(const CameraServer::SetModeCallback& callback)
2✔
622
{
623
    std::lock_guard<std::mutex> lg{_mutex};
2✔
624
    return _set_mode_callbacks.subscribe(callback);
2✔
625
}
2✔
626

627
void CameraServerImpl::unsubscribe_set_mode(CameraServer::SetModeHandle handle)
1✔
628
{
629
    std::lock_guard<std::mutex> lg{_mutex};
1✔
630
    _set_mode_callbacks.unsubscribe(handle);
1✔
631
}
1✔
632

633
CameraServer::Result
634
CameraServerImpl::respond_set_mode(CameraServer::CameraFeedback set_mode_feedback)
2✔
635
{
636
    std::lock_guard<std::mutex> lg{_mutex};
2✔
637

638
    switch (set_mode_feedback) {
2✔
639
        default:
×
640
            // Fallthrough
641
        case CameraServer::CameraFeedback::Unknown:
642
            return CameraServer::Result::Error;
×
643
        case CameraServer::CameraFeedback::Ok: {
2✔
644
            auto command_ack = _server_component_impl->make_command_ack_message(
2✔
645
                _last_set_mode_command, MAV_RESULT_ACCEPTED);
2✔
646
            _server_component_impl->send_command_ack(command_ack);
2✔
647
            return CameraServer::Result::Success;
2✔
648
        }
649
        case CameraServer::CameraFeedback::Busy: {
×
650
            auto command_ack = _server_component_impl->make_command_ack_message(
×
651
                _last_set_mode_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
652
            _server_component_impl->send_command_ack(command_ack);
×
653
            return CameraServer::Result::Success;
×
654
        }
655
        case CameraServer::CameraFeedback::Failed: {
×
656
            auto command_ack = _server_component_impl->make_command_ack_message(
×
657
                _last_set_mode_command, MAV_RESULT_FAILED);
×
658
            _server_component_impl->send_command_ack(command_ack);
×
659
            return CameraServer::Result::Success;
×
660
        }
661
    }
662
}
2✔
663

664
CameraServer::StorageInformationHandle CameraServerImpl::subscribe_storage_information(
1✔
665
    const CameraServer::StorageInformationCallback& callback)
666
{
667
    std::lock_guard<std::mutex> lg{_mutex};
1✔
668
    return _storage_information_callbacks.subscribe(callback);
1✔
669
}
1✔
670

671
void CameraServerImpl::unsubscribe_storage_information(
×
672
    CameraServer::StorageInformationHandle handle)
673
{
674
    std::lock_guard<std::mutex> lg{_mutex};
×
675
    _storage_information_callbacks.unsubscribe(handle);
×
676
}
×
677

678
CameraServer::Result CameraServerImpl::respond_storage_information(
2✔
679
    CameraServer::CameraFeedback storage_information_feedback,
680
    CameraServer::StorageInformation storage_information)
681
{
682
    std::lock_guard<std::mutex> lg{_mutex};
2✔
683

684
    switch (storage_information_feedback) {
2✔
685
        default:
×
686
            // Fallthrough
687
        case CameraServer::CameraFeedback::Unknown:
688
            return CameraServer::Result::Error;
×
689
        case CameraServer::CameraFeedback::Ok: {
2✔
690
            auto command_ack = _server_component_impl->make_command_ack_message(
2✔
691
                _last_storage_information_command, MAV_RESULT_ACCEPTED);
2✔
692
            _server_component_impl->send_command_ack(command_ack);
2✔
693
            // break and send storage information
694
            break;
2✔
695
        }
696
        case CameraServer::CameraFeedback::Busy: {
×
697
            auto command_ack = _server_component_impl->make_command_ack_message(
×
698
                _last_storage_information_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
699
            _server_component_impl->send_command_ack(command_ack);
×
700
            return CameraServer::Result::Success;
×
701
        }
702
        case CameraServer::CameraFeedback::Failed: {
×
703
            auto command_ack = _server_component_impl->make_command_ack_message(
×
704
                _last_storage_information_command, MAV_RESULT_FAILED);
×
705
            _server_component_impl->send_command_ack(command_ack);
×
706
            return CameraServer::Result::Success;
×
707
        }
708
    }
709

710
    const uint8_t storage_count = 1;
2✔
711

712
    const float total_capacity = storage_information.total_storage_mib;
2✔
713
    const float used_capacity = storage_information.used_storage_mib;
2✔
714
    const float available_capacity = storage_information.available_storage_mib;
2✔
715
    const float read_speed = storage_information.read_speed_mib_s;
2✔
716
    const float write_speed = storage_information.write_speed_mib_s;
2✔
717

718
    auto status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
2✔
719
    switch (storage_information.storage_status) {
2✔
720
        case CameraServer::StorageInformation::StorageStatus::NotAvailable:
×
721
            status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
×
722
            break;
×
723
        case CameraServer::StorageInformation::StorageStatus::Unformatted:
×
724
            status = STORAGE_STATUS::STORAGE_STATUS_UNFORMATTED;
×
725
            break;
×
726
        case CameraServer::StorageInformation::StorageStatus::Formatted:
2✔
727
            status = STORAGE_STATUS::STORAGE_STATUS_READY;
2✔
728
            break;
2✔
729
        case CameraServer::StorageInformation::StorageStatus::NotSupported:
×
730
            status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
×
731
            break;
×
732
    }
733

734
    auto type = STORAGE_TYPE::STORAGE_TYPE_UNKNOWN;
2✔
735
    switch (storage_information.storage_type) {
2✔
736
        case CameraServer::StorageInformation::StorageType::UsbStick:
×
737
            type = STORAGE_TYPE::STORAGE_TYPE_USB_STICK;
×
738
            break;
×
739
        case CameraServer::StorageInformation::StorageType::Sd:
×
740
            type = STORAGE_TYPE::STORAGE_TYPE_SD;
×
741
            break;
×
742
        case CameraServer::StorageInformation::StorageType::Microsd:
×
743
            type = STORAGE_TYPE::STORAGE_TYPE_MICROSD;
×
744
            break;
×
745
        case CameraServer::StorageInformation::StorageType::Hd:
×
746
            type = STORAGE_TYPE::STORAGE_TYPE_HD;
×
747
            break;
×
748
        case CameraServer::StorageInformation::StorageType::Other:
×
749
            type = STORAGE_TYPE::STORAGE_TYPE_OTHER;
×
750
            break;
×
751
        default:
2✔
752
            break;
2✔
753
    }
754

755
    std::string name("");
2✔
756
    // This needs to be long enough, otherwise the memcpy in mavlink overflows.
757
    name.resize(32);
2✔
758
    const uint8_t storage_usage = 0;
2✔
759

760
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
2✔
761
        mavlink_message_t message{};
2✔
762
        mavlink_msg_storage_information_pack_chan(
4✔
763
            mavlink_address.system_id,
2✔
764
            mavlink_address.component_id,
2✔
765
            channel,
766
            &message,
767
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
2✔
768
            _last_storage_id,
2✔
769
            storage_count,
770
            status,
2✔
771
            total_capacity,
2✔
772
            used_capacity,
2✔
773
            available_capacity,
2✔
774
            read_speed,
2✔
775
            write_speed,
2✔
776
            type,
2✔
777
            name.data(),
2✔
778
            storage_usage);
779
        return message;
2✔
780
    });
781

782
    return CameraServer::Result::Success;
2✔
783
}
2✔
784

785
CameraServer::CaptureStatusHandle
786
CameraServerImpl::subscribe_capture_status(const CameraServer::CaptureStatusCallback& callback)
×
787
{
788
    CameraServer::CaptureStatusHandle handle;
×
789
    bool should_start_timer = false;
×
790

791
    {
792
        std::lock_guard<std::mutex> lg{_mutex};
×
793
        should_start_timer = _capture_status_callbacks.empty();
×
794
        handle = _capture_status_callbacks.subscribe(callback);
×
795
    }
×
796

797
    if (should_start_timer) {
×
798
        start_sending_capture_status();
×
799
    }
800

801
    return handle;
×
802
}
803

804
void CameraServerImpl::unsubscribe_capture_status(CameraServer::CaptureStatusHandle handle)
×
805
{
806
    bool should_stop_timer = false;
×
807

808
    {
809
        std::lock_guard<std::mutex> lg{_mutex};
×
810
        _capture_status_callbacks.unsubscribe(handle);
×
811
        should_stop_timer = _capture_status_callbacks.empty();
×
812
    }
×
813

814
    if (should_stop_timer) {
×
815
        stop_sending_capture_status();
×
816
    }
817
}
×
818

819
CameraServer::Result CameraServerImpl::respond_capture_status(
×
820
    CameraServer::CameraFeedback capture_status_feedback,
821
    CameraServer::CaptureStatus capture_status)
822
{
823
    {
824
        std::lock_guard<std::mutex> lg{_mutex};
×
825

826
        switch (capture_status_feedback) {
×
827
            default:
×
828
                // Fallthrough
829
            case CameraServer::CameraFeedback::Unknown:
830
                return CameraServer::Result::Error;
×
831
            case CameraServer::CameraFeedback::Ok: {
×
832
                auto command_ack = _server_component_impl->make_command_ack_message(
×
833
                    _last_capture_status_command, MAV_RESULT_ACCEPTED);
×
834
                _server_component_impl->send_command_ack(command_ack);
×
835
                // break and send capture status
836
                break;
×
837
            }
838
            case CameraServer::CameraFeedback::Busy: {
×
839
                auto command_ack = _server_component_impl->make_command_ack_message(
×
840
                    _last_capture_status_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
841
                _server_component_impl->send_command_ack(command_ack);
×
842
                return CameraServer::Result::Success;
×
843
            }
844
            case CameraServer::CameraFeedback::Failed: {
×
845
                auto command_ack = _server_component_impl->make_command_ack_message(
×
846
                    _last_capture_status_command, MAV_RESULT_FAILED);
×
847
                _server_component_impl->send_command_ack(command_ack);
×
848
                return CameraServer::Result::Success;
×
849
            }
850
        }
851

852
        _capture_status = capture_status;
×
853
    }
×
854

855
    send_capture_status();
×
856

857
    return CameraServer::Result::Success;
×
858
}
859

860
CameraServer::FormatStorageHandle
861
CameraServerImpl::subscribe_format_storage(const CameraServer::FormatStorageCallback& callback)
1✔
862
{
863
    std::lock_guard<std::mutex> lg{_mutex};
1✔
864
    return _format_storage_callbacks.subscribe(callback);
1✔
865
}
1✔
866
void CameraServerImpl::unsubscribe_format_storage(CameraServer::FormatStorageHandle handle)
1✔
867
{
868
    std::lock_guard<std::mutex> lg{_mutex};
1✔
869
    _format_storage_callbacks.unsubscribe(handle);
1✔
870
}
1✔
871

872
CameraServer::Result
873
CameraServerImpl::respond_format_storage(CameraServer::CameraFeedback format_storage_feedback)
1✔
874
{
875
    std::lock_guard<std::mutex> lg{_mutex};
1✔
876

877
    switch (format_storage_feedback) {
1✔
878
        default:
×
879
            // Fallthrough
880
        case CameraServer::CameraFeedback::Unknown:
881
            return CameraServer::Result::Error;
×
882
        case CameraServer::CameraFeedback::Ok: {
1✔
883
            auto command_ack = _server_component_impl->make_command_ack_message(
1✔
884
                _last_format_storage_command, MAV_RESULT_ACCEPTED);
1✔
885
            _server_component_impl->send_command_ack(command_ack);
1✔
886
            return CameraServer::Result::Success;
1✔
887
        }
888
        case CameraServer::CameraFeedback::Busy: {
×
889
            auto command_ack = _server_component_impl->make_command_ack_message(
×
890
                _last_format_storage_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
891
            _server_component_impl->send_command_ack(command_ack);
×
892
            return CameraServer::Result::Success;
×
893
        }
894
        case CameraServer::CameraFeedback::Failed: {
×
895
            auto command_ack = _server_component_impl->make_command_ack_message(
×
896
                _last_format_storage_command, MAV_RESULT_FAILED);
×
897
            _server_component_impl->send_command_ack(command_ack);
×
898
            return CameraServer::Result::Success;
×
899
        }
900
    }
901
}
1✔
902

903
CameraServer::ResetSettingsHandle
904
CameraServerImpl::subscribe_reset_settings(const CameraServer::ResetSettingsCallback& callback)
1✔
905
{
906
    std::lock_guard<std::mutex> lg{_mutex};
1✔
907
    return _reset_settings_callbacks.subscribe(callback);
1✔
908
}
1✔
909

910
void CameraServerImpl::unsubscribe_reset_settings(CameraServer::ResetSettingsHandle handle)
×
911
{
912
    std::lock_guard<std::mutex> lg{_mutex};
×
913
    _reset_settings_callbacks.unsubscribe(handle);
×
914
}
×
915

916
CameraServer::Result
917
CameraServerImpl::respond_reset_settings(CameraServer::CameraFeedback reset_settings_feedback)
1✔
918
{
919
    std::lock_guard<std::mutex> lg{_mutex};
1✔
920

921
    switch (reset_settings_feedback) {
1✔
922
        default:
×
923
            // Fallthrough
924
        case CameraServer::CameraFeedback::Unknown:
925
            return CameraServer::Result::Error;
×
926
        case CameraServer::CameraFeedback::Ok: {
1✔
927
            auto command_ack = _server_component_impl->make_command_ack_message(
1✔
928
                _last_reset_settings_command, MAV_RESULT_ACCEPTED);
1✔
929
            _server_component_impl->send_command_ack(command_ack);
1✔
930
            return CameraServer::Result::Success;
1✔
931
        }
932
        case CameraServer::CameraFeedback::Busy: {
×
933
            auto command_ack = _server_component_impl->make_command_ack_message(
×
934
                _last_reset_settings_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
935
            _server_component_impl->send_command_ack(command_ack);
×
936
            return CameraServer::Result::Success;
×
937
        }
938
        case CameraServer::CameraFeedback::Failed: {
×
939
            auto command_ack = _server_component_impl->make_command_ack_message(
×
940
                _last_reset_settings_command, MAV_RESULT_FAILED);
×
941
            _server_component_impl->send_command_ack(command_ack);
×
942
            return CameraServer::Result::Success;
×
943
        }
944
    }
945
}
1✔
946

947
CameraServer::TrackingPointCommandHandle CameraServerImpl::subscribe_tracking_point_command(
×
948
    const CameraServer::TrackingPointCommandCallback& callback)
949
{
950
    std::lock_guard<std::mutex> lg{_mutex};
×
951
    return _tracking_point_callbacks.subscribe(callback);
×
952
}
×
953

954
void CameraServerImpl::unsubscribe_tracking_point_command(
×
955
    CameraServer::TrackingPointCommandHandle handle)
956
{
957
    std::lock_guard<std::mutex> lg{_mutex};
×
958
    _tracking_point_callbacks.unsubscribe(handle);
×
959
}
×
960

961
CameraServer::Result CameraServerImpl::respond_tracking_point_command(
×
962
    CameraServer::CameraFeedback tracking_point_feedback)
963
{
964
    std::lock_guard<std::mutex> lg{_mutex};
×
965

966
    switch (tracking_point_feedback) {
×
967
        default:
×
968
            // Fallthrough
969
        case CameraServer::CameraFeedback::Unknown:
970
            return CameraServer::Result::Error;
×
971
        case CameraServer::CameraFeedback::Ok: {
×
972
            auto command_ack = _server_component_impl->make_command_ack_message(
×
973
                _last_track_point_command, MAV_RESULT_ACCEPTED);
×
974
            _server_component_impl->send_command_ack(command_ack);
×
975
            break;
×
976
        }
977
        case CameraServer::CameraFeedback::Busy: {
×
978
            auto command_ack = _server_component_impl->make_command_ack_message(
×
979
                _last_track_point_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
980
            _server_component_impl->send_command_ack(command_ack);
×
981
            return CameraServer::Result::Success;
×
982
        }
983
        case CameraServer::CameraFeedback::Failed: {
×
984
            auto command_ack = _server_component_impl->make_command_ack_message(
×
985
                _last_track_point_command, MAV_RESULT_FAILED);
×
986
            _server_component_impl->send_command_ack(command_ack);
×
987
            return CameraServer::Result::Success;
×
988
        }
989
    }
990
    return CameraServer::Result::Success;
×
991
}
×
992

993
CameraServer::TrackingRectangleCommandHandle CameraServerImpl::subscribe_tracking_rectangle_command(
×
994
    const CameraServer::TrackingRectangleCommandCallback& callback)
995
{
996
    std::lock_guard<std::mutex> lg{_mutex};
×
997
    return _tracking_rectangle_callbacks.subscribe(callback);
×
998
}
×
999

1000
void CameraServerImpl::unsubscribe_tracking_rectangle_command(
×
1001
    CameraServer::TrackingRectangleCommandHandle handle)
1002
{
1003
    std::lock_guard<std::mutex> lg{_mutex};
×
1004
    _tracking_rectangle_callbacks.unsubscribe(handle);
×
1005
}
×
1006

1007
CameraServer::Result CameraServerImpl::respond_tracking_rectangle_command(
×
1008
    CameraServer::CameraFeedback tracking_rectangle_feedback)
1009
{
1010
    std::lock_guard<std::mutex> lg{_mutex};
×
1011

1012
    switch (tracking_rectangle_feedback) {
×
1013
        default:
×
1014
            // Fallthrough
1015
        case CameraServer::CameraFeedback::Unknown:
1016
            return CameraServer::Result::Error;
×
1017
        case CameraServer::CameraFeedback::Ok: {
×
1018
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1019
                _last_track_rectangle_command, MAV_RESULT_ACCEPTED);
×
1020
            _server_component_impl->send_command_ack(command_ack);
×
1021
            break;
×
1022
        }
1023
        case CameraServer::CameraFeedback::Busy: {
×
1024
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1025
                _last_track_rectangle_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
1026
            _server_component_impl->send_command_ack(command_ack);
×
1027
            return CameraServer::Result::Success;
×
1028
        }
1029
        case CameraServer::CameraFeedback::Failed: {
×
1030
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1031
                _last_track_rectangle_command, MAV_RESULT_FAILED);
×
1032
            _server_component_impl->send_command_ack(command_ack);
×
1033
            return CameraServer::Result::Success;
×
1034
        }
1035
    }
1036
    return CameraServer::Result::Success;
×
1037
}
×
1038

1039
CameraServer::TrackingOffCommandHandle CameraServerImpl::subscribe_tracking_off_command(
×
1040
    const CameraServer::TrackingOffCommandCallback& callback)
1041
{
1042
    std::lock_guard<std::mutex> lg{_mutex};
×
1043
    return _tracking_off_callbacks.subscribe(callback);
×
1044
}
×
1045

1046
void CameraServerImpl::unsubscribe_tracking_off_command(
×
1047
    CameraServer::TrackingOffCommandHandle handle)
1048
{
1049
    std::lock_guard<std::mutex> lg{_mutex};
×
1050
    _tracking_off_callbacks.unsubscribe(handle);
×
1051
}
×
1052

1053
CameraServer::Result
1054
CameraServerImpl::respond_tracking_off_command(CameraServer::CameraFeedback tracking_off_feedback)
×
1055
{
1056
    std::lock_guard<std::mutex> lg{_mutex};
×
1057

1058
    switch (tracking_off_feedback) {
×
1059
        default:
×
1060
            // Fallthrough
1061
        case CameraServer::CameraFeedback::Unknown:
1062
            return CameraServer::Result::Error;
×
1063
        case CameraServer::CameraFeedback::Ok: {
×
1064
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1065
                _last_tracking_off_command, MAV_RESULT_ACCEPTED);
×
1066
            _server_component_impl->send_command_ack(command_ack);
×
1067
            break;
×
1068
        }
1069
        case CameraServer::CameraFeedback::Busy: {
×
1070
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1071
                _last_tracking_off_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
1072
            _server_component_impl->send_command_ack(command_ack);
×
1073
            return CameraServer::Result::Success;
×
1074
        }
1075
        case CameraServer::CameraFeedback::Failed: {
×
1076
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1077
                _last_tracking_off_command, MAV_RESULT_FAILED);
×
1078
            _server_component_impl->send_command_ack(command_ack);
×
1079
            return CameraServer::Result::Success;
×
1080
        }
1081
    }
1082
    return CameraServer::Result::Success;
×
1083
}
×
1084

1085
void CameraServerImpl::start_image_capture_interval(float interval_s, int32_t count, int32_t index)
1✔
1086
{
1087
    // If count == 0, it means capture "forever" until a stop command is received.
1088
    auto remaining = std::make_shared<int32_t>(count == 0 ? INT32_MAX : count);
1✔
1089

1090
    _last_interval_index = index;
1✔
1091
    _image_capture_timer_cookie = _server_component_impl->add_call_every(
1✔
1092
        [this, remaining]() {
12✔
1093
            LogDebug() << "capture image timer triggered";
3✔
1094

1095
            if (!_take_photo_callbacks.empty()) {
3✔
1096
                _take_photo_callbacks.queue(_last_interval_index++, [this](const auto& func) {
3✔
1097
                    _server_component_impl->call_user_callback(func);
3✔
1098
                });
3✔
1099
                (*remaining)--;
3✔
1100
            }
1101

1102
            if (*remaining == 0) {
3✔
1103
                stop_image_capture_interval();
×
1104
            }
1105
        },
3✔
1106
        interval_s);
1107
    _is_image_capture_interval_set = true;
1✔
1108
    _image_capture_timer_interval_s = interval_s;
1✔
1109
}
1✔
1110

1111
void CameraServerImpl::stop_image_capture_interval()
14✔
1112
{
1113
    _server_component_impl->remove_call_every(_image_capture_timer_cookie);
14✔
1114

1115
    std::lock_guard<std::mutex> lg{_mutex};
14✔
1116
    _is_image_capture_interval_set = false;
14✔
1117
    _image_capture_timer_interval_s = 0;
14✔
1118
}
14✔
1119

1120
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_information_request(
×
1121
    const MavlinkCommandReceiver::CommandLong& command)
1122
{
1123
    LogDebug() << "Camera info request";
×
1124

1125
    if (static_cast<int>(command.params.param1) == 0) {
×
1126
        return _server_component_impl->make_command_ack_message(
×
1127
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1128
    }
1129

1130
    return send_camera_information(command);
×
1131
}
1132

1133
std::optional<mavlink_command_ack_t>
1134
CameraServerImpl::process_request_message(const MavlinkCommandReceiver::CommandLong& command)
121✔
1135
{
1136
    switch (static_cast<int>(command.params.param1)) {
121✔
1137
        case MAVLINK_MSG_ID_CAMERA_INFORMATION:
11✔
1138
            return send_camera_information(command);
11✔
1139

1140
        case MAVLINK_MSG_ID_CAMERA_CAPTURE_STATUS:
11✔
1141
            send_capture_status();
11✔
1142
            return _server_component_impl->make_command_ack_message(
11✔
1143
                command, MAV_RESULT::MAV_RESULT_ACCEPTED);
11✔
1144

1145
        default:
99✔
1146
            LogWarn() << "Got unknown request message!";
99✔
1147
            return _server_component_impl->make_command_ack_message(
99✔
1148
                command, MAV_RESULT::MAV_RESULT_DENIED);
99✔
1149
    }
1150
}
1151

1152
std::optional<mavlink_command_ack_t>
1153
CameraServerImpl::send_camera_information(const MavlinkCommandReceiver::CommandLong& command)
11✔
1154
{
1155
    std::lock_guard<std::mutex> lg{_mutex};
11✔
1156

1157
    if (!_is_information_set) {
11✔
1158
        return _server_component_impl->make_command_ack_message(
×
1159
            command, MAV_RESULT::MAV_RESULT_TEMPORARILY_REJECTED);
×
1160
    }
1161

1162
    // ack needs to be sent before camera information message
1163
    auto command_ack =
1164
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
11✔
1165
    _server_component_impl->send_command_ack(command_ack);
11✔
1166

1167
    // It is safe to ignore the return value of parse_version_string() here
1168
    // since the string was already validated in set_information().
1169
    uint32_t firmware_version;
1170
    parse_version_string(_information.firmware_version, firmware_version);
11✔
1171

1172
    // capability flags are determined by subscriptions
1173
    uint32_t capability_flags{};
11✔
1174

1175
    if (!_take_photo_callbacks.empty()) {
11✔
1176
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_CAPTURE_IMAGE;
2✔
1177
    }
1178

1179
    if (!_start_video_callbacks.empty()) {
11✔
1180
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_CAPTURE_VIDEO;
×
1181
    }
1182

1183
    if (!_set_mode_callbacks.empty()) {
11✔
1184
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_MODES;
2✔
1185
    }
1186

1187
    if (_information.image_in_video_mode_supported) {
11✔
1188
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_CAN_CAPTURE_IMAGE_IN_VIDEO_MODE;
×
1189
    }
1190

1191
    if (_information.video_in_image_mode_supported) {
11✔
1192
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_CAN_CAPTURE_VIDEO_IN_IMAGE_MODE;
×
1193
    }
1194

1195
    if (_is_video_streaming_set) {
11✔
1196
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM;
1✔
1197
    }
1198

1199
    if (!_tracking_point_callbacks.empty()) {
11✔
1200
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_TRACKING_POINT;
×
1201
    }
1202

1203
    if (!_tracking_rectangle_callbacks.empty()) {
11✔
1204
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_TRACKING_RECTANGLE;
×
1205
    }
1206

1207
    if (!_zoom_range_callbacks.empty() || !_zoom_in_start_callbacks.empty() ||
22✔
1208
        !_zoom_out_start_callbacks.empty()) {
11✔
1209
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_BASIC_ZOOM;
×
1210
    }
1211

1212
    _information.vendor_name.resize(sizeof(mavlink_camera_information_t::vendor_name));
11✔
1213
    _information.model_name.resize(sizeof(mavlink_camera_information_t::model_name));
11✔
1214
    _information.definition_file_uri.resize(
11✔
1215
        sizeof(mavlink_camera_information_t::cam_definition_uri));
1216

1217
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
11✔
1218
        mavlink_message_t message{};
11✔
1219
        mavlink_msg_camera_information_pack_chan(
33✔
1220
            mavlink_address.system_id,
11✔
1221
            mavlink_address.component_id,
11✔
1222
            channel,
1223
            &message,
1224
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
22✔
1225
            reinterpret_cast<const uint8_t*>(_information.vendor_name.c_str()),
11✔
1226
            reinterpret_cast<const uint8_t*>(_information.model_name.c_str()),
11✔
1227
            firmware_version,
11✔
1228
            _information.focal_length_mm,
1229
            _information.horizontal_sensor_size_mm,
1230
            _information.vertical_sensor_size_mm,
1231
            _information.horizontal_resolution_px,
11✔
1232
            _information.vertical_resolution_px,
11✔
1233
            _information.lens_id,
11✔
1234
            capability_flags,
11✔
1235
            _information.definition_file_version,
11✔
1236
            _information.definition_file_uri.c_str(),
1237
            0,
1238
            0);
1239
        return message;
11✔
1240
    });
1241

1242
    return std::nullopt;
11✔
1243
}
11✔
1244

1245
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_settings_request(
11✔
1246
    const MavlinkCommandReceiver::CommandLong& command)
1247
{
1248
    auto settings = static_cast<bool>(command.params.param1);
11✔
1249

1250
    if (!settings) {
11✔
1251
        return _server_component_impl->make_command_ack_message(
×
1252
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1253
    }
1254

1255
    // ack needs to be sent before camera information message
1256
    auto command_ack =
1257
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
11✔
1258
    _server_component_impl->send_command_ack(command_ack);
11✔
1259
    LogDebug() << "sent settings ack";
11✔
1260

1261
    // unsupported
1262
    const auto mode_id = CAMERA_MODE::CAMERA_MODE_IMAGE;
11✔
1263
    const float zoom_level = 0;
11✔
1264
    const float focus_level = 0;
11✔
1265

1266
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
11✔
1267
        mavlink_message_t message{};
11✔
1268
        mavlink_msg_camera_settings_pack_chan(
22✔
1269
            mavlink_address.system_id,
11✔
1270
            mavlink_address.component_id,
11✔
1271
            channel,
1272
            &message,
1273
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
11✔
1274
            mode_id,
1275
            zoom_level,
11✔
1276
            focus_level,
11✔
1277
            0);
1278
        return message;
11✔
1279
    });
1280
    LogDebug() << "sent settings msg";
11✔
1281

1282
    // ack was already sent
1283
    return std::nullopt;
11✔
1284
}
1285

1286
std::optional<mavlink_command_ack_t> CameraServerImpl::process_storage_information_request(
20✔
1287
    const MavlinkCommandReceiver::CommandLong& command)
1288
{
1289
    auto storage_id = static_cast<uint8_t>(command.params.param1);
20✔
1290
    auto information = static_cast<bool>(command.params.param2);
20✔
1291

1292
    if (!information) {
20✔
1293
        return _server_component_impl->make_command_ack_message(
×
1294
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1295
    }
1296

1297
    std::lock_guard<std::mutex> lg{_mutex};
20✔
1298

1299
    if (_storage_information_callbacks.empty()) {
20✔
1300
        LogDebug()
36✔
1301
            << "Get storage information requested with no set storage information subscriber";
18✔
1302
        return _server_component_impl->make_command_ack_message(
18✔
1303
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
18✔
1304
    }
1305

1306
    // TODO may need support multi storage id
1307
    _last_storage_id = storage_id;
2✔
1308

1309
    _last_storage_information_command = command;
2✔
1310

1311
    _storage_information_callbacks.queue(
2✔
1312
        storage_id, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
2✔
1313

1314
    // ack will be sent later in respond_storage_information
1315
    return std::nullopt;
2✔
1316
}
20✔
1317

1318
std::optional<mavlink_command_ack_t>
1319
CameraServerImpl::process_storage_format(const MavlinkCommandReceiver::CommandLong& command)
1✔
1320
{
1321
    auto storage_id = static_cast<uint8_t>(command.params.param1);
1✔
1322
    auto format = static_cast<bool>(command.params.param2);
1✔
1323
    auto reset_image_log = static_cast<bool>(command.params.param3);
1✔
1324

1325
    UNUSED(format);
1✔
1326
    UNUSED(reset_image_log);
1✔
1327

1328
    std::lock_guard<std::mutex> lg{_mutex};
1✔
1329

1330
    if (_format_storage_callbacks.empty()) {
1✔
1331
        LogDebug() << "process storage format requested with no storage format subscriber";
×
1332
        return _server_component_impl->make_command_ack_message(
×
1333
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1334
    }
1335

1336
    _last_format_storage_command = command;
1✔
1337

1338
    _format_storage_callbacks.queue(
1✔
1339
        storage_id, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
1✔
1340

1341
    return std::nullopt;
1✔
1342
}
1✔
1343

1344
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_capture_status_request(
×
1345
    const MavlinkCommandReceiver::CommandLong& command)
1346
{
1347
    auto capture_status = static_cast<bool>(command.params.param1);
×
1348

1349
    if (!capture_status) {
×
1350
        return _server_component_impl->make_command_ack_message(
×
1351
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1352
    }
1353

1354
    std::lock_guard<std::mutex> lg{_mutex};
×
1355
    if (_capture_status_callbacks.empty()) {
×
1356
        LogDebug() << "process camera capture status requested with no capture status subscriber";
×
1357
        return _server_component_impl->make_command_ack_message(
×
1358
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1359
    }
1360

1361
    _last_capture_status_command = command;
×
1362

1363
    // may not need param for now ,just use zero
1364
    _capture_status_callbacks.queue(
×
1365
        0, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
×
1366

1367
    // ack was already sent
1368
    return std::nullopt;
×
1369
}
×
1370

1371
void CameraServerImpl::send_capture_status()
15✔
1372
{
1373
    uint8_t image_status{};
15✔
1374
    uint8_t video_status{};
15✔
1375
    uint32_t recording_time_ms{};
15✔
1376
    float available_capacity{};
15✔
1377
    float image_capture_timer_interval_s{};
15✔
1378
    int32_t image_capture_count{};
15✔
1379

1380
    {
1381
        std::lock_guard<std::mutex> lg{_mutex};
15✔
1382

1383
        if (_capture_status.image_status ==
15✔
1384
                CameraServer::CaptureStatus::ImageStatus::CaptureInProgress ||
15✔
1385
            _capture_status.image_status ==
15✔
1386
                CameraServer::CaptureStatus::ImageStatus::IntervalInProgress) {
NEW
1387
            image_status |= StatusFlags::IN_PROGRESS;
×
1388
        }
1389

1390
        if (_capture_status.image_status ==
15✔
1391
                CameraServer::CaptureStatus::ImageStatus::IntervalIdle ||
15✔
1392
            _capture_status.image_status ==
15✔
1393
                CameraServer::CaptureStatus::ImageStatus::IntervalInProgress ||
15✔
1394
            _is_image_capture_interval_set) {
15✔
1395
            image_status |= StatusFlags::INTERVAL_SET;
3✔
1396
        }
1397

1398
        if (_capture_status.video_status == CameraServer::CaptureStatus::VideoStatus::Idle) {
15✔
1399
            video_status = 0;
15✔
NEW
1400
        } else if (
×
NEW
1401
            _capture_status.video_status ==
×
1402
            CameraServer::CaptureStatus::VideoStatus::CaptureInProgress) {
NEW
1403
            video_status = 1;
×
1404
        }
1405

1406
        recording_time_ms =
15✔
1407
            static_cast<uint32_t>(static_cast<double>(_capture_status.recording_time_s) * 1e3);
15✔
1408
        available_capacity = _capture_status.available_capacity_mib;
15✔
1409
        image_capture_timer_interval_s = _image_capture_timer_interval_s;
15✔
1410
        image_capture_count = _image_capture_count;
15✔
1411
    }
15✔
1412

1413
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
15✔
1414
        mavlink_message_t message{};
15✔
1415
        mavlink_msg_camera_capture_status_pack_chan(
30✔
1416
            mavlink_address.system_id,
15✔
1417
            mavlink_address.component_id,
15✔
1418
            channel,
1419
            &message,
1420
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
15✔
1421
            image_status,
15✔
1422
            video_status,
15✔
1423
            image_capture_timer_interval_s,
15✔
1424
            recording_time_ms,
15✔
1425
            available_capacity,
15✔
1426
            image_capture_count,
15✔
1427
            0);
1428
        return message;
15✔
1429
    });
1430
}
15✔
1431

1432
std::optional<mavlink_command_ack_t>
1433
CameraServerImpl::process_reset_camera_settings(const MavlinkCommandReceiver::CommandLong& command)
1✔
1434
{
1435
    auto reset = static_cast<bool>(command.params.param1);
1✔
1436

1437
    UNUSED(reset);
1✔
1438

1439
    std::lock_guard<std::mutex> lg{_mutex};
1✔
1440

1441
    if (_reset_settings_callbacks.empty()) {
1✔
1442
        LogDebug() << "reset camera settings requested with no camera settings subscriber";
×
1443
        return _server_component_impl->make_command_ack_message(
×
1444
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1445
    }
1446

1447
    _last_reset_settings_command = command;
1✔
1448
    _reset_settings_callbacks.queue(
1✔
1449
        0, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
1✔
1450

1451
    return std::nullopt;
1✔
1452
}
1✔
1453

1454
std::optional<mavlink_command_ack_t>
1455
CameraServerImpl::process_set_camera_mode(const MavlinkCommandReceiver::CommandLong& command)
2✔
1456
{
1457
    auto camera_mode = static_cast<CAMERA_MODE>(command.params.param2);
2✔
1458

1459
    std::lock_guard<std::mutex> lg{_mutex};
2✔
1460

1461
    if (_set_mode_callbacks.empty()) {
2✔
1462
        LogDebug() << "Set mode requested with no set mode subscriber";
×
1463
        return _server_component_impl->make_command_ack_message(
×
1464
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1465
    }
1466

1467
    // convert camera mode enum type
1468
    CameraServer::Mode convert_camera_mode = CameraServer::Mode::Unknown;
2✔
1469
    if (camera_mode == CAMERA_MODE_IMAGE) {
2✔
1470
        convert_camera_mode = CameraServer::Mode::Photo;
1✔
1471
    } else if (camera_mode == CAMERA_MODE_VIDEO) {
1✔
1472
        convert_camera_mode = CameraServer::Mode::Video;
1✔
1473
    }
1474

1475
    if (convert_camera_mode == CameraServer::Mode::Unknown) {
2✔
1476
        return _server_component_impl->make_command_ack_message(
×
1477
            command, MAV_RESULT::MAV_RESULT_DENIED);
×
1478
    }
1479

1480
    _last_set_mode_command = command;
2✔
1481

1482
    _set_mode_callbacks.queue(convert_camera_mode, [this](const auto& func) {
2✔
1483
        _server_component_impl->call_user_callback(func);
2✔
1484
    });
2✔
1485

1486
    return std::nullopt;
2✔
1487
}
2✔
1488

1489
std::optional<mavlink_command_ack_t>
1490
CameraServerImpl::process_set_camera_zoom(const MavlinkCommandReceiver::CommandLong& command)
×
1491
{
1492
    auto zoom_type = static_cast<CAMERA_ZOOM_TYPE>(command.params.param1);
×
1493
    auto zoom_value = command.params.param2;
×
1494

1495
    std::lock_guard<std::mutex> lg{_mutex};
×
1496

1497
    if (_zoom_in_start_callbacks.empty() && _zoom_out_start_callbacks.empty() &&
×
1498
        _zoom_stop_callbacks.empty() && _zoom_range_callbacks.empty()) {
×
1499
        LogWarn() << "No camera zoom is supported";
×
1500
        return _server_component_impl->make_command_ack_message(
×
1501
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1502
    }
1503

1504
    auto unsupported = [&]() {
×
1505
        LogWarn() << "unsupported set camera zoom type (" << (int)zoom_type << ") request";
×
1506
    };
×
1507

1508
    switch (zoom_type) {
×
1509
        case ZOOM_TYPE_CONTINUOUS:
×
1510
            if (zoom_value == -1.f) {
×
1511
                if (_zoom_out_start_callbacks.empty()) {
×
1512
                    unsupported();
×
1513
                    return _server_component_impl->make_command_ack_message(
×
1514
                        command, MAV_RESULT::MAV_RESULT_DENIED);
×
1515
                } else {
1516
                    _last_zoom_out_start_command = command;
×
1517
                    int dummy = 0;
×
1518
                    _zoom_out_start_callbacks.queue(dummy, [this](const auto& func) {
×
1519
                        _server_component_impl->call_user_callback(func);
×
1520
                    });
×
1521
                }
1522
            } else if (zoom_value == 1.f) {
×
1523
                if (_zoom_in_start_callbacks.empty()) {
×
1524
                    unsupported();
×
1525
                    return _server_component_impl->make_command_ack_message(
×
1526
                        command, MAV_RESULT::MAV_RESULT_DENIED);
×
1527
                } else {
1528
                    _last_zoom_in_start_command = command;
×
1529
                    int dummy = 0;
×
1530
                    _zoom_in_start_callbacks.queue(dummy, [this](const auto& func) {
×
1531
                        _server_component_impl->call_user_callback(func);
×
1532
                    });
×
1533
                }
1534
            } else if (zoom_value == 0.f) {
×
1535
                if (_zoom_stop_callbacks.empty()) {
×
1536
                    unsupported();
×
1537
                    return _server_component_impl->make_command_ack_message(
×
1538
                        command, MAV_RESULT::MAV_RESULT_DENIED);
×
1539
                } else {
1540
                    _last_zoom_stop_command = command;
×
1541
                    int dummy = 0;
×
1542
                    _zoom_stop_callbacks.queue(dummy, [this](const auto& func) {
×
1543
                        _server_component_impl->call_user_callback(func);
×
1544
                    });
×
1545
                }
1546
            } else {
1547
                LogWarn() << "Invalid zoom value";
×
1548
                return _server_component_impl->make_command_ack_message(
×
1549
                    command, MAV_RESULT::MAV_RESULT_DENIED);
×
1550
            }
1551
            break;
×
1552
        case ZOOM_TYPE_RANGE:
×
1553
            if (_zoom_range_callbacks.empty()) {
×
1554
                unsupported();
×
1555
                return _server_component_impl->make_command_ack_message(
×
1556
                    command, MAV_RESULT::MAV_RESULT_DENIED);
×
1557

1558
            } else {
1559
                _last_zoom_range_command = command;
×
1560
                _zoom_range_callbacks.queue(zoom_value, [this](const auto& func) {
×
1561
                    _server_component_impl->call_user_callback(func);
×
1562
                });
×
1563
            }
1564
            break;
×
1565
        case ZOOM_TYPE_STEP:
×
1566
        // Fallthrough
1567
        case ZOOM_TYPE_FOCAL_LENGTH:
1568
        // Fallthrough
1569
        case ZOOM_TYPE_HORIZONTAL_FOV:
1570
        // Fallthrough
1571
        default:
1572
            unsupported();
×
1573
            return _server_component_impl->make_command_ack_message(
×
1574
                command, MAV_RESULT::MAV_RESULT_DENIED);
×
1575
            break;
1576
    }
1577

1578
    // For any success so far, we don't ack yet, but later when the respond function is called.
1579
    return std::nullopt;
×
1580
}
×
1581

1582
std::optional<mavlink_command_ack_t>
1583
CameraServerImpl::process_set_camera_focus(const MavlinkCommandReceiver::CommandLong& command)
×
1584
{
1585
    auto focus_type = static_cast<SET_FOCUS_TYPE>(command.params.param1);
×
1586
    auto focus_value = command.params.param2;
×
1587

1588
    UNUSED(focus_type);
×
1589
    UNUSED(focus_value);
×
1590

1591
    LogDebug() << "unsupported set camera focus request";
×
1592

1593
    return _server_component_impl->make_command_ack_message(
×
1594
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1595
}
1596

1597
std::optional<mavlink_command_ack_t>
1598
CameraServerImpl::process_set_storage_usage(const MavlinkCommandReceiver::CommandLong& command)
×
1599
{
1600
    auto storage_id = static_cast<uint8_t>(command.params.param1);
×
1601
    auto usage = static_cast<STORAGE_USAGE_FLAG>(command.params.param2);
×
1602

1603
    UNUSED(storage_id);
×
1604
    UNUSED(usage);
×
1605

1606
    LogDebug() << "unsupported set storage usage request";
×
1607

1608
    return _server_component_impl->make_command_ack_message(
×
1609
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1610
}
1611

1612
std::optional<mavlink_command_ack_t>
1613
CameraServerImpl::process_image_start_capture(const MavlinkCommandReceiver::CommandLong& command)
2✔
1614
{
1615
    auto interval_s = command.params.param2;
2✔
1616
    auto total_images = static_cast<int32_t>(command.params.param3);
2✔
1617
    auto seq_number = static_cast<int32_t>(command.params.param4);
2✔
1618

1619
    LogDebug() << "received image start capture request - interval: " << +interval_s
2✔
1620
               << " total: " << +total_images << " index: " << +seq_number;
2✔
1621

1622
    // TODO: validate parameters and return MAV_RESULT_DENIED not valid
1623

1624
    stop_image_capture_interval();
2✔
1625

1626
    std::lock_guard<std::mutex> lg{_mutex};
2✔
1627

1628
    if (_take_photo_callbacks.empty()) {
2✔
1629
        LogDebug() << "image capture requested with no take photo subscriber";
×
1630
        return _server_component_impl->make_command_ack_message(
×
1631
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1632
    }
1633

1634
    // single image capture
1635
    if (total_images == 1) {
2✔
1636
        // MAV_RESULT_ACCEPTED must be sent before CAMERA_IMAGE_CAPTURED
1637
        auto command_ack = _server_component_impl->make_command_ack_message(
1✔
1638
            command, MAV_RESULT::MAV_RESULT_IN_PROGRESS);
1639
        _server_component_impl->send_command_ack(command_ack);
1✔
1640

1641
        _last_take_photo_command = command;
1✔
1642

1643
        _take_photo_callbacks.queue(seq_number, [this](const auto& func) {
1✔
1644
            _server_component_impl->call_user_callback(func);
1✔
1645
        });
1✔
1646

1647
        return std::nullopt;
1✔
1648
    }
1649

1650
    start_image_capture_interval(interval_s, total_images, seq_number);
1✔
1651

1652
    return _server_component_impl->make_command_ack_message(
1✔
1653
        command, MAV_RESULT::MAV_RESULT_ACCEPTED);
1✔
1654
}
2✔
1655

1656
std::optional<mavlink_command_ack_t>
1657
CameraServerImpl::process_image_stop_capture(const MavlinkCommandReceiver::CommandLong& command)
1✔
1658
{
1659
    LogDebug() << "received image stop capture request";
1✔
1660

1661
    // REVISIT: should we return something other that MAV_RESULT_ACCEPTED if
1662
    // there is not currently a capture interval active?
1663
    stop_image_capture_interval();
1✔
1664

1665
    return _server_component_impl->make_command_ack_message(
1✔
1666
        command, MAV_RESULT::MAV_RESULT_ACCEPTED);
1✔
1667
}
1668

1669
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_image_capture_request(
×
1670
    const MavlinkCommandReceiver::CommandLong& command)
1671
{
1672
    auto seq_number = static_cast<uint32_t>(command.params.param1);
×
1673

1674
    UNUSED(seq_number);
×
1675

1676
    LogDebug() << "unsupported image capture request";
×
1677

1678
    return _server_component_impl->make_command_ack_message(
×
1679
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1680
}
1681

1682
std::optional<mavlink_command_ack_t>
1683
CameraServerImpl::process_video_start_capture(const MavlinkCommandReceiver::CommandLong& command)
×
1684
{
1685
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1686
    auto status_frequency = command.params.param2;
×
1687

1688
    UNUSED(status_frequency);
×
1689

1690
    std::lock_guard<std::mutex> lg{_mutex};
×
1691

1692
    if (_start_video_callbacks.empty()) {
×
1693
        LogDebug() << "video start capture requested with no video start capture subscriber";
×
1694
        return _server_component_impl->make_command_ack_message(
×
1695
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1696
    }
1697

1698
    _last_start_video_command = command;
×
1699
    _start_video_callbacks.queue(
×
1700
        stream_id, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
×
1701

1702
    return std::nullopt;
×
1703
}
×
1704

1705
std::optional<mavlink_command_ack_t>
1706
CameraServerImpl::process_video_stop_capture(const MavlinkCommandReceiver::CommandLong& command)
×
1707
{
1708
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1709

1710
    std::lock_guard<std::mutex> lg{_mutex};
×
1711

1712
    if (_stop_video_callbacks.empty()) {
×
1713
        LogDebug() << "video stop capture requested with no video stop capture subscriber";
×
1714
        return _server_component_impl->make_command_ack_message(
×
1715
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1716
    }
1717

1718
    _last_stop_video_command = command;
×
1719
    _stop_video_callbacks.queue(
×
1720
        stream_id, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
×
1721

1722
    return std::nullopt;
×
1723
}
×
1724

1725
std::optional<mavlink_command_ack_t>
1726
CameraServerImpl::process_video_start_streaming(const MavlinkCommandReceiver::CommandLong& command)
×
1727
{
1728
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1729

1730
    std::lock_guard<std::mutex> lg{_mutex};
×
1731

1732
    if (_start_video_streaming_callbacks.empty()) {
×
1733
        LogDebug() << "video start streaming requested with no video start streaming subscriber";
×
1734
        return _server_component_impl->make_command_ack_message(
×
1735
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1736
    }
1737

1738
    _last_start_video_streaming_command = command;
×
1739
    _start_video_streaming_callbacks.queue(
×
1740
        stream_id, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
×
1741

1742
    return std::nullopt;
×
1743
}
×
1744

1745
std::optional<mavlink_command_ack_t>
1746
CameraServerImpl::process_video_stop_streaming(const MavlinkCommandReceiver::CommandLong& command)
×
1747
{
1748
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1749

1750
    std::lock_guard<std::mutex> lg{_mutex};
×
1751

1752
    if (_stop_video_streaming_callbacks.empty()) {
×
1753
        LogDebug() << "video stop streaming requested with no video stop streaming subscriber";
×
1754
        return _server_component_impl->make_command_ack_message(
×
1755
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1756
    }
1757

1758
    _last_stop_video_streaming_command = command;
×
1759
    _stop_video_streaming_callbacks.queue(
×
1760
        stream_id, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
×
1761

1762
    return std::nullopt;
×
1763
}
×
1764

1765
std::optional<mavlink_command_ack_t> CameraServerImpl::process_video_stream_information_request(
19✔
1766
    const MavlinkCommandReceiver::CommandLong& command)
1767
{
1768
    auto stream_id = static_cast<uint8_t>(command.params.param1);
19✔
1769

1770
    UNUSED(stream_id);
19✔
1771

1772
    std::lock_guard<std::mutex> lg{_mutex};
19✔
1773

1774
    if (_is_video_streaming_set) {
19✔
1775
        auto command_ack = _server_component_impl->make_command_ack_message(
1✔
1776
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
1777
        _server_component_impl->send_command_ack(command_ack);
1✔
1778
        LogDebug() << "sent video streaming ack";
1✔
1779

1780
        const char name[32] = "";
1✔
1781

1782
        _video_streaming.rtsp_uri.resize(sizeof(mavlink_video_stream_information_t::uri));
1✔
1783

1784
        _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
1✔
1785
            mavlink_message_t msg{};
1✔
1786
            mavlink_msg_video_stream_information_pack_chan(
2✔
1787
                mavlink_address.system_id,
1✔
1788
                mavlink_address.component_id,
1✔
1789
                channel,
1790
                &msg,
1791
                0, // Stream id
1792
                0, // Count
1793
                VIDEO_STREAM_TYPE_RTSP,
1794
                VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1795
                0, // famerate
1796
                0, // resolution horizontal
1797
                0, // resolution vertical
1798
                0, // bitrate
1799
                0, // rotation
1800
                0, // horizontal field of view
1801
                name,
1✔
1802
                _video_streaming.rtsp_uri.c_str(),
1✔
1803
                0,
1804
                0);
1805
            return msg;
1✔
1806
        });
1807

1808
        // Ack already sent.
1809
        return std::nullopt;
1✔
1810

1811
    } else {
1812
        return _server_component_impl->make_command_ack_message(
18✔
1813
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
18✔
1814
    }
1815
}
19✔
1816

1817
std::optional<mavlink_command_ack_t> CameraServerImpl::process_video_stream_status_request(
21✔
1818
    const MavlinkCommandReceiver::CommandLong& command)
1819
{
1820
    auto stream_id = static_cast<uint8_t>(command.params.param1);
21✔
1821

1822
    UNUSED(stream_id);
21✔
1823

1824
    std::lock_guard<std::mutex> lg{_mutex};
21✔
1825

1826
    if (!_is_video_streaming_set) {
21✔
1827
        return _server_component_impl->make_command_ack_message(
20✔
1828
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
20✔
1829
    }
1830

1831
    auto command_ack =
1832
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
1✔
1833
    _server_component_impl->send_command_ack(command_ack);
1✔
1834
    LogDebug() << "sent video streaming ack";
1✔
1835

1836
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
1✔
1837
        mavlink_message_t msg{};
1✔
1838
        mavlink_msg_video_stream_status_pack_chan(
1✔
1839
            mavlink_address.system_id,
1✔
1840
            mavlink_address.component_id,
1✔
1841
            channel,
1842
            &msg,
1843
            0, // Stream id
1844
            VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1845
            0, // framerate
1846
            0, // resolution horizontal
1847
            0, // resolution vertical
1848
            0, // bitrate
1849
            0, // rotation
1850
            0, // horizontal field of view
1851
            0);
1852
        return msg;
1✔
1853
    });
1854

1855
    // ack was already sent
1856
    return std::nullopt;
1✔
1857
}
21✔
1858

1859
CameraServer::ZoomInStartHandle
1860
CameraServerImpl::subscribe_zoom_in_start(const CameraServer::ZoomInStartCallback& callback)
×
1861
{
1862
    std::lock_guard<std::mutex> lg{_mutex};
×
1863
    return _zoom_in_start_callbacks.subscribe(callback);
×
1864
}
×
1865

1866
void CameraServerImpl::unsubscribe_zoom_in_start(CameraServer::ZoomInStartHandle handle)
×
1867
{
1868
    std::lock_guard<std::mutex> lg{_mutex};
×
1869
    _zoom_in_start_callbacks.unsubscribe(handle);
×
1870
}
×
1871

1872
CameraServer::Result
1873
CameraServerImpl::respond_zoom_in_start(CameraServer::CameraFeedback zoom_in_start_feedback)
×
1874
{
1875
    std::lock_guard<std::mutex> lg{_mutex};
×
1876

1877
    switch (zoom_in_start_feedback) {
×
1878
        default:
×
1879
            // Fallthrough
1880
        case CameraServer::CameraFeedback::Unknown:
1881
            return CameraServer::Result::Error;
×
1882
        case CameraServer::CameraFeedback::Ok: {
×
1883
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1884
                _last_zoom_in_start_command, MAV_RESULT_ACCEPTED);
×
1885
            _server_component_impl->send_command_ack(command_ack);
×
1886
            return CameraServer::Result::Success;
×
1887
        }
1888
        case CameraServer::CameraFeedback::Busy: {
×
1889
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1890
                _last_zoom_in_start_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
1891
            _server_component_impl->send_command_ack(command_ack);
×
1892
            return CameraServer::Result::Success;
×
1893
        }
1894
        case CameraServer::CameraFeedback::Failed: {
×
1895
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1896
                _last_zoom_in_start_command, MAV_RESULT_FAILED);
×
1897
            _server_component_impl->send_command_ack(command_ack);
×
1898
            return CameraServer::Result::Success;
×
1899
        }
1900
    }
1901
}
×
1902

1903
CameraServer::ZoomOutStartHandle
1904
CameraServerImpl::subscribe_zoom_out_start(const CameraServer::ZoomOutStartCallback& callback)
×
1905
{
1906
    std::lock_guard<std::mutex> lg{_mutex};
×
1907
    return _zoom_out_start_callbacks.subscribe(callback);
×
1908
}
×
1909

1910
void CameraServerImpl::unsubscribe_zoom_out_start(CameraServer::ZoomOutStartHandle handle)
×
1911
{
1912
    std::lock_guard<std::mutex> lg{_mutex};
×
1913
    _zoom_out_start_callbacks.unsubscribe(handle);
×
1914
}
×
1915

1916
CameraServer::Result
1917
CameraServerImpl::respond_zoom_out_start(CameraServer::CameraFeedback zoom_out_start_feedback)
×
1918
{
1919
    std::lock_guard<std::mutex> lg{_mutex};
×
1920

1921
    switch (zoom_out_start_feedback) {
×
1922
        default:
×
1923
            // Fallthrough
1924
        case CameraServer::CameraFeedback::Unknown:
1925
            return CameraServer::Result::Error;
×
1926
        case CameraServer::CameraFeedback::Ok: {
×
1927
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1928
                _last_zoom_out_start_command, MAV_RESULT_ACCEPTED);
×
1929
            _server_component_impl->send_command_ack(command_ack);
×
1930
            return CameraServer::Result::Success;
×
1931
        }
1932
        case CameraServer::CameraFeedback::Busy: {
×
1933
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1934
                _last_zoom_out_start_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
1935
            _server_component_impl->send_command_ack(command_ack);
×
1936
            return CameraServer::Result::Success;
×
1937
        }
1938
        case CameraServer::CameraFeedback::Failed: {
×
1939
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1940
                _last_zoom_out_start_command, MAV_RESULT_FAILED);
×
1941
            _server_component_impl->send_command_ack(command_ack);
×
1942
            return CameraServer::Result::Success;
×
1943
        }
1944
    }
1945
}
×
1946

1947
CameraServer::ZoomStopHandle
1948
CameraServerImpl::subscribe_zoom_stop(const CameraServer::ZoomStopCallback& callback)
×
1949
{
1950
    std::lock_guard<std::mutex> lg{_mutex};
×
1951
    return _zoom_stop_callbacks.subscribe(callback);
×
1952
}
×
1953

1954
void CameraServerImpl::unsubscribe_zoom_stop(CameraServer::ZoomStopHandle handle)
×
1955
{
1956
    std::lock_guard<std::mutex> lg{_mutex};
×
1957
    _zoom_stop_callbacks.unsubscribe(handle);
×
1958
}
×
1959

1960
CameraServer::Result
1961
CameraServerImpl::respond_zoom_stop(CameraServer::CameraFeedback zoom_stop_feedback)
×
1962
{
1963
    std::lock_guard<std::mutex> lg{_mutex};
×
1964

1965
    switch (zoom_stop_feedback) {
×
1966
        default:
×
1967
            // Fallthrough
1968
        case CameraServer::CameraFeedback::Unknown:
1969
            return CameraServer::Result::Error;
×
1970
        case CameraServer::CameraFeedback::Ok: {
×
1971
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1972
                _last_zoom_stop_command, MAV_RESULT_ACCEPTED);
×
1973
            _server_component_impl->send_command_ack(command_ack);
×
1974
            return CameraServer::Result::Success;
×
1975
        }
1976
        case CameraServer::CameraFeedback::Busy: {
×
1977
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1978
                _last_zoom_stop_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
1979
            _server_component_impl->send_command_ack(command_ack);
×
1980
            return CameraServer::Result::Success;
×
1981
        }
1982
        case CameraServer::CameraFeedback::Failed: {
×
1983
            auto command_ack = _server_component_impl->make_command_ack_message(
×
1984
                _last_zoom_stop_command, MAV_RESULT_FAILED);
×
1985
            _server_component_impl->send_command_ack(command_ack);
×
1986
            return CameraServer::Result::Success;
×
1987
        }
1988
    }
1989
}
×
1990

1991
CameraServer::ZoomRangeHandle
1992
CameraServerImpl::subscribe_zoom_range(const CameraServer::ZoomRangeCallback& callback)
×
1993
{
1994
    std::lock_guard<std::mutex> lg{_mutex};
×
1995
    return _zoom_range_callbacks.subscribe(callback);
×
1996
}
×
1997

1998
void CameraServerImpl::unsubscribe_zoom_range(CameraServer::ZoomRangeHandle handle)
×
1999
{
2000
    std::lock_guard<std::mutex> lg{_mutex};
×
2001
    _zoom_range_callbacks.unsubscribe(handle);
×
2002
}
×
2003

2004
CameraServer::Result
2005
CameraServerImpl::respond_zoom_range(CameraServer::CameraFeedback zoom_range_feedback)
×
2006
{
2007
    std::lock_guard<std::mutex> lg{_mutex};
×
2008

2009
    switch (zoom_range_feedback) {
×
2010
        case CameraServer::CameraFeedback::Ok: {
×
2011
            auto command_ack = _server_component_impl->make_command_ack_message(
×
2012
                _last_zoom_range_command, MAV_RESULT_ACCEPTED);
×
2013
            _server_component_impl->send_command_ack(command_ack);
×
2014
            return CameraServer::Result::Success;
×
2015
        }
2016
        case CameraServer::CameraFeedback::Busy: {
×
2017
            auto command_ack = _server_component_impl->make_command_ack_message(
×
2018
                _last_zoom_range_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
2019
            _server_component_impl->send_command_ack(command_ack);
×
2020
            return CameraServer::Result::Success;
×
2021
        }
2022
        case CameraServer::CameraFeedback::Failed: {
×
2023
            auto command_ack = _server_component_impl->make_command_ack_message(
×
2024
                _last_zoom_range_command, MAV_RESULT_FAILED);
×
2025
            _server_component_impl->send_command_ack(command_ack);
×
2026
            return CameraServer::Result::Success;
×
2027
        }
2028
        case CameraServer::CameraFeedback::Unknown:
×
2029
            // Fallthrough
2030
        default:
2031
            return CameraServer::Result::Error;
×
2032
    }
2033
}
×
2034

2035
std::optional<mavlink_command_ack_t>
2036
CameraServerImpl::process_track_point_command(const MavlinkCommandReceiver::CommandLong& command)
×
2037
{
2038
    if (!is_command_sender_ok(command)) {
×
2039
        LogWarn() << "Incoming track point command is for target sysid "
×
2040
                  << int(command.target_system_id) << " instead of "
×
2041
                  << int(_server_component_impl->get_own_system_id());
×
2042
        return std::nullopt;
×
2043
    }
2044

2045
    std::lock_guard<std::mutex> lg{_mutex};
×
2046

2047
    if (_tracking_point_callbacks.empty()) {
×
2048
        LogDebug() << "Track point requested with no user callback provided";
×
2049
        return _server_component_impl->make_command_ack_message(
×
2050
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
2051
    }
2052

2053
    CameraServer::TrackPoint track_point{
2054
        command.params.param1, command.params.param2, command.params.param3};
×
2055

2056
    _last_track_point_command = command;
×
2057
    _tracking_point_callbacks.queue(track_point, [this](const auto& func) {
×
2058
        _server_component_impl->call_user_callback(func);
×
2059
    });
×
2060
    // We don't send an ack but leave that to the user.
2061
    return std::nullopt;
×
2062
}
×
2063

2064
std::optional<mavlink_command_ack_t> CameraServerImpl::process_track_rectangle_command(
×
2065
    const MavlinkCommandReceiver::CommandLong& command)
2066
{
2067
    if (!is_command_sender_ok(command)) {
×
2068
        LogWarn() << "Incoming track rectangle command is for target sysid "
×
2069
                  << int(command.target_system_id) << " instead of "
×
2070
                  << int(_server_component_impl->get_own_system_id());
×
2071
        return std::nullopt;
×
2072
    }
2073

2074
    std::lock_guard<std::mutex> lg{_mutex};
×
2075

2076
    if (_tracking_rectangle_callbacks.empty()) {
×
2077
        LogDebug() << "Track rectangle requested with no user callback provided";
×
2078
        return _server_component_impl->make_command_ack_message(
×
2079
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
2080
    }
2081

2082
    CameraServer::TrackRectangle track_rectangle{
2083
        command.params.param1, command.params.param2, command.params.param3, command.params.param4};
×
2084

2085
    _last_track_rectangle_command = command;
×
2086
    _tracking_rectangle_callbacks.queue(track_rectangle, [this](const auto& func) {
×
2087
        _server_component_impl->call_user_callback(func);
×
2088
    });
×
2089
    // We don't send an ack but leave that to the user.
2090
    return std::nullopt;
×
2091
}
×
2092

2093
std::optional<mavlink_command_ack_t>
2094
CameraServerImpl::process_track_off_command(const MavlinkCommandReceiver::CommandLong& command)
×
2095
{
2096
    if (!is_command_sender_ok(command)) {
×
2097
        LogWarn() << "Incoming track off command is for target sysid "
×
2098
                  << int(command.target_system_id) << " instead of "
×
2099
                  << int(_server_component_impl->get_own_system_id());
×
2100
        return std::nullopt;
×
2101
    }
2102

2103
    std::lock_guard<std::mutex> lg{_mutex};
×
2104

2105
    if (_tracking_off_callbacks.empty()) {
×
2106
        LogDebug() << "Tracking off requested with no user callback provided";
×
2107
        return _server_component_impl->make_command_ack_message(
×
2108
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
2109
    }
2110

2111
    _last_tracking_off_command = command;
×
2112
    _tracking_off_callbacks.queue(
×
2113
        0, [this](const auto& func) { _server_component_impl->call_user_callback(func); });
×
2114
    // We don't send an ack but leave that to the user.
2115
    return std::nullopt;
×
2116
}
×
2117

2118
std::optional<mavlink_command_ack_t>
2119
CameraServerImpl::process_set_message_interval(const MavlinkCommandReceiver::CommandLong& command)
×
2120
{
2121
    if (!is_command_sender_ok(command)) {
×
2122
        LogWarn() << "Incoming track off command is for target sysid "
×
2123
                  << int(command.target_system_id) << " instead of "
×
2124
                  << int(_server_component_impl->get_own_system_id());
×
2125
        return std::nullopt;
×
2126
    }
2127

2128
    auto message_id = static_cast<uint32_t>(command.params.param1);
×
2129
    auto interval_us = static_cast<int32_t>(command.params.param2);
×
2130
    UNUSED(message_id);
×
2131

2132
    // Interval value of -1 means to disable sending messages
2133
    if (interval_us < 0) {
×
2134
        stop_sending_tracking_status();
×
2135
    } else {
2136
        start_sending_tracking_status(interval_us);
×
2137
    }
2138

2139
    // Always send the "Accepted" result
2140
    return _server_component_impl->make_command_ack_message(
×
2141
        command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
2142
}
2143

2144
void CameraServerImpl::send_tracking_status_with_interval(uint32_t interval_us)
×
2145
{
2146
    while (true) {
2147
        std::this_thread::sleep_for(std::chrono::microseconds{interval_us});
×
2148
        {
2149
            std::scoped_lock lg{_mutex};
×
2150
            if (!_sending_tracking_status) {
×
2151
                return;
×
2152
            }
2153
        }
×
NEW
2154
        TrackingMode tracking_mode{};
×
NEW
2155
        CameraServer::TrackPoint tracked_point{};
×
NEW
2156
        CameraServer::TrackRectangle tracked_rectangle{};
×
2157
        {
NEW
2158
            std::lock_guard<std::mutex> lg{_mutex};
×
NEW
2159
            tracking_mode = _tracking_mode;
×
NEW
2160
            tracked_point = _tracked_point;
×
NEW
2161
            tracked_rectangle = _tracked_rectangle;
×
NEW
2162
        }
×
2163

2164
        _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
2165
            mavlink_message_t message;
2166

2167
            // The message is filled based on current tracking mode
NEW
2168
            switch (tracking_mode) {
×
2169
                default:
×
2170
                    // Fallthrough
2171
                case TrackingMode::NONE:
2172

2173
                    mavlink_msg_camera_tracking_image_status_pack_chan(
×
2174
                        mavlink_address.system_id,
×
2175
                        mavlink_address.component_id,
×
2176
                        channel,
2177
                        &message,
2178
                        CAMERA_TRACKING_STATUS_FLAGS_IDLE,
2179
                        CAMERA_TRACKING_MODE_NONE,
2180
                        0, // used to be CAMERA_TRACKING_TARGET_DATA_NONE
2181
                        0.0f,
2182
                        0.0f,
2183
                        0.0f,
2184
                        0.0f,
2185
                        0.0f,
2186
                        0.0f,
2187
                        0.0f,
2188
                        0);
2189
                    break;
×
2190
                case TrackingMode::POINT:
×
2191

2192
                    mavlink_msg_camera_tracking_image_status_pack_chan(
×
2193
                        mavlink_address.system_id,
×
2194
                        mavlink_address.component_id,
×
2195
                        channel,
2196
                        &message,
2197
                        CAMERA_TRACKING_STATUS_FLAGS_ACTIVE,
2198
                        CAMERA_TRACKING_MODE_POINT,
2199
                        CAMERA_TRACKING_TARGET_DATA_IN_STATUS,
NEW
2200
                        tracked_point.point_x,
×
2201
                        tracked_point.point_y,
2202
                        tracked_point.radius,
2203
                        0.0f,
2204
                        0.0f,
2205
                        0.0f,
2206
                        0.0f,
2207
                        0);
2208
                    break;
×
2209

2210
                case TrackingMode::RECTANGLE:
×
2211

2212
                    mavlink_msg_camera_tracking_image_status_pack_chan(
×
2213
                        mavlink_address.system_id,
×
2214
                        mavlink_address.component_id,
×
2215
                        channel,
2216
                        &message,
2217
                        CAMERA_TRACKING_STATUS_FLAGS_ACTIVE,
2218
                        CAMERA_TRACKING_MODE_RECTANGLE,
2219
                        CAMERA_TRACKING_TARGET_DATA_IN_STATUS,
2220
                        0.0f,
2221
                        0.0f,
2222
                        0.0f,
NEW
2223
                        tracked_rectangle.top_left_corner_x,
×
2224
                        tracked_rectangle.top_left_corner_y,
2225
                        tracked_rectangle.bottom_right_corner_x,
2226
                        tracked_rectangle.bottom_right_corner_y,
2227
                        0);
2228
                    break;
×
2229
            }
2230
            return message;
×
2231
        });
2232
    }
×
2233
}
2234

2235
void CameraServerImpl::start_sending_tracking_status(uint32_t interval_ms)
×
2236
{
2237
    // Stop sending status with the old interval
2238
    stop_sending_tracking_status();
×
2239

2240
    std::lock_guard<std::mutex> lg{_mutex};
×
2241
    _sending_tracking_status = true;
×
2242
    _tracking_status_sending_thread =
2243
        std::thread{&CameraServerImpl::send_tracking_status_with_interval, this, interval_ms};
×
2244
}
×
2245

2246
void CameraServerImpl::stop_sending_tracking_status()
11✔
2247
{
2248
    // Firstly, ask the other thread to stop sending the status
2249
    {
2250
        std::scoped_lock lg{_mutex};
11✔
2251
        _sending_tracking_status = false;
11✔
2252
    }
11✔
2253
    // If the thread was active, wait for it to finish
2254
    if (_tracking_status_sending_thread.joinable()) {
11✔
2255
        _tracking_status_sending_thread.join();
×
2256
    }
2257
}
11✔
2258

2259
void CameraServerImpl::start_sending_capture_status()
×
2260
{
2261
    _capture_status_timer_cookie = _server_component_impl->add_call_every(
×
2262
        [this]() { send_capture_status(); }, CAPTURE_STATUS_INTERVAL_S);
×
2263
}
×
2264

2265
void CameraServerImpl::stop_sending_capture_status()
11✔
2266
{
2267
    _server_component_impl->remove_call_every(_capture_status_timer_cookie);
11✔
2268
}
11✔
2269

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