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

mavlink / MAVSDK / 7317183253

24 Dec 2023 10:25PM UTC coverage: 36.26% (-0.6%) from 36.89%
7317183253

push

github

web-flow
Merge pull request #2088 from tbago/add_more_camera_function

More camera server functionality

28 of 718 new or added lines in 12 files covered. (3.9%)

20 existing lines in 6 files now uncovered.

10035 of 27675 relevant lines covered (36.26%)

127.93 hits per line

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

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

4
namespace mavsdk {
5

6
template class CallbackList<int32_t>;
7

8
CameraServerImpl::CameraServerImpl(std::shared_ptr<ServerComponent> server_component) :
1✔
9
    ServerPluginImplBase(server_component)
1✔
10
{
11
    _server_component_impl->register_plugin(this);
1✔
12
}
1✔
13

14
CameraServerImpl::~CameraServerImpl()
1✔
15
{
16
    _server_component_impl->unregister_plugin(this);
1✔
17
}
1✔
18

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

137
void CameraServerImpl::deinit()
1✔
138
{
139
    stop_image_capture_interval();
1✔
140
    _server_component_impl->unregister_all_mavlink_command_handlers(this);
1✔
141
}
1✔
142

143
bool CameraServerImpl::parse_version_string(const std::string& version_str)
×
144
{
145
    uint32_t unused;
×
146

147
    return parse_version_string(version_str, unused);
×
148
}
149

150
bool CameraServerImpl::parse_version_string(const std::string& version_str, uint32_t& version)
×
151
{
152
    // empty string means no version
153
    if (version_str.empty()) {
×
154
        version = 0;
×
155

156
        return true;
×
157
    }
158

159
    uint8_t major{}, minor{}, patch{}, dev{};
×
160

161
    auto ret = sscanf(version_str.c_str(), "%hhu.%hhu.%hhu.%hhu", &major, &minor, &patch, &dev);
×
162

163
    if (ret == EOF) {
×
164
        return false;
×
165
    }
166

167
    // pack version according to MAVLINK spec
168
    version = dev << 24 | patch << 16 | minor << 8 | major;
×
169

170
    return true;
×
171
}
172

173
CameraServer::Result CameraServerImpl::set_information(CameraServer::Information information)
×
174
{
175
    if (!parse_version_string(information.firmware_version)) {
×
176
        LogDebug() << "incorrectly formatted firmware version string: "
×
177
                   << information.firmware_version;
×
178
        return CameraServer::Result::WrongArgument;
×
179
    }
180

181
    // TODO: validate information.definition_file_uri
182

183
    _is_information_set = true;
×
184
    _information = information;
×
185

186
    return CameraServer::Result::Success;
×
187
}
188

189
CameraServer::Result
NEW
190
CameraServerImpl::set_video_streaming(CameraServer::VideoStreaming video_streaming)
×
191
{
192
    // TODO: validate uri length
193

NEW
194
    _is_video_streaming_set = true;
×
NEW
195
    _video_streaming = video_streaming;
×
196

NEW
197
    return CameraServer::Result::Success;
×
198
}
199

UNCOV
200
CameraServer::Result CameraServerImpl::set_in_progress(bool in_progress)
×
201
{
202
    _is_image_capture_in_progress = in_progress;
×
203
    return CameraServer::Result::Success;
×
204
}
205

206
CameraServer::TakePhotoHandle
207
CameraServerImpl::subscribe_take_photo(const CameraServer::TakePhotoCallback& callback)
1✔
208
{
209
    return _take_photo_callbacks.subscribe(callback);
1✔
210
}
211

212
void CameraServerImpl::unsubscribe_take_photo(CameraServer::TakePhotoHandle handle)
×
213
{
214
    _take_photo_callbacks.unsubscribe(handle);
×
215
}
×
216

217
CameraServer::Result CameraServerImpl::respond_take_photo(
×
218
    CameraServer::CameraFeedback take_photo_feedback, CameraServer::CaptureInfo capture_info)
219
{
220
    // If capture_info.index == INT32_MIN, it means this was an interval
221
    // capture rather than a single image capture.
222
    if (capture_info.index != INT32_MIN) {
×
223
        // We expect each capture to be the next sequential number.
224
        // If _image_capture_count == 0, we ignore since it means that this is
225
        // the first photo since the plugin was initialized.
226
        if (_image_capture_count != 0 && capture_info.index != _image_capture_count + 1) {
×
227
            LogErr() << "unexpected image index, expecting " << +(_image_capture_count + 1)
×
228
                     << " but was " << +capture_info.index;
×
229
        }
230

231
        _image_capture_count = capture_info.index;
×
232
    }
233

234
    switch (take_photo_feedback) {
×
235
        default:
×
236
            // Fallthrough
237
        case CameraServer::CameraFeedback::Unknown:
238
            return CameraServer::Result::Error;
×
NEW
239
        case CameraServer::CameraFeedback::Ok: {
×
240
            // Check for error above
241
            auto command_ack = _server_component_impl->make_command_ack_message(
×
242
                _last_take_photo_command, MAV_RESULT_ACCEPTED);
×
243
            _server_component_impl->send_command_ack(command_ack);
×
244
            // Only break and send the captured below.
245
            break;
×
246
        }
NEW
247
        case CameraServer::CameraFeedback::Busy: {
×
248
            auto command_ack = _server_component_impl->make_command_ack_message(
×
249
                _last_take_photo_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
250
            _server_component_impl->send_command_ack(command_ack);
×
251
            return CameraServer::Result::Success;
×
252
        }
253

NEW
254
        case CameraServer::CameraFeedback::Failed: {
×
255
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
256
                _last_take_photo_command, MAV_RESULT_FAILED);
×
257
            _server_component_impl->send_command_ack(command_ack);
×
258
            return CameraServer::Result::Success;
×
259
        }
260
    }
261

262
    // REVISIT: Should we cache all CaptureInfo in memory for single image
263
    // captures so that we can respond to requests for lost CAMERA_IMAGE_CAPTURED
264
    // messages without calling back to user code?
265

266
    static const uint8_t camera_id = 0; // deprecated unused field
267

268
    const float attitude_quaternion[] = {
×
269
        capture_info.attitude_quaternion.w,
×
270
        capture_info.attitude_quaternion.x,
×
271
        capture_info.attitude_quaternion.y,
×
272
        capture_info.attitude_quaternion.z,
×
273
    };
×
274

275
    // There needs to be enough data to be copied mavlink internal.
276
    capture_info.file_url.resize(205);
×
277

278
    // TODO: this should be a broadcast message
279
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
280
        mavlink_message_t message{};
×
281
        mavlink_msg_camera_image_captured_pack_chan(
×
282
            mavlink_address.system_id,
×
283
            mavlink_address.component_id,
×
284
            channel,
285
            &message,
286
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
×
287
            capture_info.time_utc_us,
×
288
            camera_id,
289
            static_cast<int32_t>(capture_info.position.latitude_deg * 1e7),
×
290
            static_cast<int32_t>(capture_info.position.longitude_deg * 1e7),
×
291
            static_cast<int32_t>(capture_info.position.absolute_altitude_m * 1e3f),
×
292
            static_cast<int32_t>(capture_info.position.relative_altitude_m * 1e3f),
×
293
            attitude_quaternion,
×
294
            capture_info.index,
295
            capture_info.is_success,
×
296
            capture_info.file_url.c_str());
297
        return message;
×
298
    });
299
    LogDebug() << "sent camera image captured msg - index: " << +capture_info.index;
×
300

301
    return CameraServer::Result::Success;
×
302
}
303

304
CameraServer::StartVideoHandle
NEW
305
CameraServerImpl::subscribe_start_video(const CameraServer::StartVideoCallback& callback)
×
306
{
NEW
307
    return _start_video_callbacks.subscribe(callback);
×
308
}
309

NEW
310
void CameraServerImpl::unsubscribe_start_video(CameraServer::StartVideoHandle handle)
×
311
{
NEW
312
    _start_video_callbacks.unsubscribe(handle);
×
NEW
313
}
×
314

315
CameraServer::Result
NEW
316
CameraServerImpl::respond_start_video(CameraServer::CameraFeedback start_video_feedback)
×
317
{
NEW
318
    switch (start_video_feedback) {
×
NEW
319
        default:
×
320
            // Fallthrough
321
        case CameraServer::CameraFeedback::Unknown:
NEW
322
            return CameraServer::Result::Error;
×
NEW
323
        case CameraServer::CameraFeedback::Ok: {
×
NEW
324
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
325
                _last_start_video_command, MAV_RESULT_ACCEPTED);
×
NEW
326
            _server_component_impl->send_command_ack(command_ack);
×
NEW
327
            break;
×
328
        }
NEW
329
        case CameraServer::CameraFeedback::Busy: {
×
NEW
330
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
331
                _last_start_video_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
332
            _server_component_impl->send_command_ack(command_ack);
×
NEW
333
            return CameraServer::Result::Success;
×
334
        }
NEW
335
        case CameraServer::CameraFeedback::Failed: {
×
NEW
336
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
337
                _last_start_video_command, MAV_RESULT_FAILED);
×
NEW
338
            _server_component_impl->send_command_ack(command_ack);
×
NEW
339
            return CameraServer::Result::Success;
×
340
        }
341
    }
NEW
342
    return CameraServer::Result::Success;
×
343
}
344

345
CameraServer::StopVideoHandle
NEW
346
CameraServerImpl::subscribe_stop_video(const CameraServer::StopVideoCallback& callback)
×
347
{
NEW
348
    return _stop_video_callbacks.subscribe(callback);
×
349
}
350

NEW
351
void CameraServerImpl::unsubscribe_stop_video(CameraServer::StopVideoHandle handle)
×
352
{
NEW
353
    return _stop_video_callbacks.unsubscribe(handle);
×
354
}
355

356
CameraServer::Result
NEW
357
CameraServerImpl::respond_stop_video(CameraServer::CameraFeedback stop_video_feedback)
×
358
{
NEW
359
    switch (stop_video_feedback) {
×
NEW
360
        default:
×
361
            // Fallthrough
362
        case CameraServer::CameraFeedback::Unknown:
NEW
363
            return CameraServer::Result::Error;
×
NEW
364
        case CameraServer::CameraFeedback::Ok: {
×
NEW
365
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
366
                _last_stop_video_command, MAV_RESULT_ACCEPTED);
×
NEW
367
            _server_component_impl->send_command_ack(command_ack);
×
NEW
368
            break;
×
369
        }
NEW
370
        case CameraServer::CameraFeedback::Busy: {
×
NEW
371
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
372
                _last_stop_video_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
373
            _server_component_impl->send_command_ack(command_ack);
×
NEW
374
            return CameraServer::Result::Success;
×
375
        }
NEW
376
        case CameraServer::CameraFeedback::Failed: {
×
NEW
377
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
378
                _last_stop_video_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
379
            _server_component_impl->send_command_ack(command_ack);
×
NEW
380
            return CameraServer::Result::Success;
×
381
        }
382
    }
NEW
383
    return CameraServer::Result::Success;
×
384
}
385

NEW
386
CameraServer::StartVideoStreamingHandle CameraServerImpl::subscribe_start_video_streaming(
×
387
    const CameraServer::StartVideoStreamingCallback& callback)
388
{
NEW
389
    return _start_video_streaming_callbacks.subscribe(callback);
×
390
}
391

NEW
392
void CameraServerImpl::unsubscribe_start_video_streaming(
×
393
    CameraServer::StartVideoStreamingHandle handle)
394
{
NEW
395
    return _start_video_streaming_callbacks.unsubscribe(handle);
×
396
}
397

NEW
398
CameraServer::Result CameraServerImpl::respond_start_video_streaming(
×
399
    CameraServer::CameraFeedback start_video_streaming_feedback)
400
{
NEW
401
    switch (start_video_streaming_feedback) {
×
NEW
402
        default:
×
403
            // Fallthrough
404
        case CameraServer::CameraFeedback::Unknown:
NEW
405
            return CameraServer::Result::Error;
×
NEW
406
        case CameraServer::CameraFeedback::Ok: {
×
NEW
407
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
408
                _last_start_video_streaming_command, MAV_RESULT_ACCEPTED);
×
NEW
409
            _server_component_impl->send_command_ack(command_ack);
×
NEW
410
            break;
×
411
        }
NEW
412
        case CameraServer::CameraFeedback::Busy: {
×
NEW
413
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
414
                _last_start_video_streaming_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
415
            _server_component_impl->send_command_ack(command_ack);
×
NEW
416
            return CameraServer::Result::Success;
×
417
        }
NEW
418
        case CameraServer::CameraFeedback::Failed: {
×
NEW
419
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
420
                _last_start_video_streaming_command, MAV_RESULT_FAILED);
×
NEW
421
            _server_component_impl->send_command_ack(command_ack);
×
NEW
422
            return CameraServer::Result::Success;
×
423
        }
424
    }
NEW
425
    return CameraServer::Result::Success;
×
426
}
427

NEW
428
CameraServer::StopVideoStreamingHandle CameraServerImpl::subscribe_stop_video_streaming(
×
429
    const CameraServer::StopVideoStreamingCallback& callback)
430
{
NEW
431
    return _stop_video_streaming_callbacks.subscribe(callback);
×
432
}
433

NEW
434
void CameraServerImpl::unsubscribe_stop_video_streaming(
×
435
    CameraServer::StopVideoStreamingHandle handle)
436
{
NEW
437
    return _stop_video_streaming_callbacks.unsubscribe(handle);
×
438
}
439

NEW
440
CameraServer::Result CameraServerImpl::respond_stop_video_streaming(
×
441
    CameraServer::CameraFeedback stop_video_streaming_feedback)
442
{
NEW
443
    switch (stop_video_streaming_feedback) {
×
NEW
444
        default:
×
445
            // Fallthrough
446
        case CameraServer::CameraFeedback::Unknown:
NEW
447
            return CameraServer::Result::Error;
×
NEW
448
        case CameraServer::CameraFeedback::Ok: {
×
NEW
449
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
450
                _last_stop_video_streaming_command, MAV_RESULT_ACCEPTED);
×
NEW
451
            _server_component_impl->send_command_ack(command_ack);
×
NEW
452
            break;
×
453
        }
NEW
454
        case CameraServer::CameraFeedback::Busy: {
×
NEW
455
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
456
                _last_stop_video_streaming_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
457
            _server_component_impl->send_command_ack(command_ack);
×
NEW
458
            return CameraServer::Result::Success;
×
459
        }
NEW
460
        case CameraServer::CameraFeedback::Failed: {
×
NEW
461
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
462
                _last_stop_video_streaming_command, MAV_RESULT_FAILED);
×
NEW
463
            _server_component_impl->send_command_ack(command_ack);
×
NEW
464
            return CameraServer::Result::Success;
×
465
        }
466
    }
NEW
467
    return CameraServer::Result::Success;
×
468
}
469

470
CameraServer::SetModeHandle
NEW
471
CameraServerImpl::subscribe_set_mode(const CameraServer::SetModeCallback& callback)
×
472
{
NEW
473
    return _set_mode_callbacks.subscribe(callback);
×
474
}
475

NEW
476
void CameraServerImpl::unsubscribe_set_mode(CameraServer::SetModeHandle handle)
×
477
{
NEW
478
    _set_mode_callbacks.unsubscribe(handle);
×
NEW
479
}
×
480

481
CameraServer::Result
NEW
482
CameraServerImpl::respond_set_mode(CameraServer::CameraFeedback set_mode_feedback)
×
483
{
NEW
484
    switch (set_mode_feedback) {
×
NEW
485
        default:
×
486
            // Fallthrough
487
        case CameraServer::CameraFeedback::Unknown:
NEW
488
            return CameraServer::Result::Error;
×
NEW
489
        case CameraServer::CameraFeedback::Ok: {
×
NEW
490
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
491
                _last_set_mode_command, MAV_RESULT_ACCEPTED);
×
NEW
492
            _server_component_impl->send_command_ack(command_ack);
×
NEW
493
            break;
×
494
        }
NEW
495
        case CameraServer::CameraFeedback::Busy: {
×
NEW
496
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
497
                _last_set_mode_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
498
            _server_component_impl->send_command_ack(command_ack);
×
NEW
499
            return CameraServer::Result::Success;
×
500
        }
NEW
501
        case CameraServer::CameraFeedback::Failed: {
×
NEW
502
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
503
                _last_set_mode_command, MAV_RESULT_FAILED);
×
NEW
504
            _server_component_impl->send_command_ack(command_ack);
×
NEW
505
            return CameraServer::Result::Success;
×
506
        }
507
    }
NEW
508
    return CameraServer::Result::Success;
×
509
}
510

NEW
511
CameraServer::StorageInformationHandle CameraServerImpl::subscribe_storage_information(
×
512
    const CameraServer::StorageInformationCallback& callback)
513
{
NEW
514
    return _storage_information_callbacks.subscribe(callback);
×
515
}
516

NEW
517
void CameraServerImpl::unsubscribe_storage_information(
×
518
    CameraServer::StorageInformationHandle handle)
519
{
NEW
520
    _storage_information_callbacks.unsubscribe(handle);
×
NEW
521
}
×
522

NEW
523
CameraServer::Result CameraServerImpl::respond_storage_information(
×
524
    CameraServer::CameraFeedback storage_information_feedback,
525
    CameraServer::StorageInformation storage_information)
526
{
NEW
527
    switch (storage_information_feedback) {
×
NEW
528
        default:
×
529
            // Fallthrough
530
        case CameraServer::CameraFeedback::Unknown:
NEW
531
            return CameraServer::Result::Error;
×
NEW
532
        case CameraServer::CameraFeedback::Ok: {
×
NEW
533
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
534
                _last_storage_information_command, MAV_RESULT_ACCEPTED);
×
NEW
535
            _server_component_impl->send_command_ack(command_ack);
×
536
            // break and send storage information
NEW
537
            break;
×
538
        }
NEW
539
        case CameraServer::CameraFeedback::Busy: {
×
NEW
540
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
541
                _last_storage_information_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
542
            _server_component_impl->send_command_ack(command_ack);
×
NEW
543
            return CameraServer::Result::Success;
×
544
        }
NEW
545
        case CameraServer::CameraFeedback::Failed: {
×
NEW
546
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
547
                _last_storage_information_command, MAV_RESULT_FAILED);
×
NEW
548
            _server_component_impl->send_command_ack(command_ack);
×
NEW
549
            return CameraServer::Result::Success;
×
550
        }
551
    }
552

NEW
553
    const uint8_t storage_count = 1;
×
554

NEW
555
    const float total_capacity = storage_information.total_storage_mib;
×
NEW
556
    const float used_capacity = storage_information.used_storage_mib;
×
NEW
557
    const float available_capacity = storage_information.available_storage_mib;
×
NEW
558
    const float read_speed = storage_information.read_speed_mib_s;
×
NEW
559
    const float write_speed = storage_information.write_speed_mib_s;
×
560

NEW
561
    auto status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
×
NEW
562
    switch (storage_information.storage_status) {
×
NEW
563
        case CameraServer::StorageInformation::StorageStatus::NotAvailable:
×
NEW
564
            status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
×
NEW
565
            break;
×
NEW
566
        case CameraServer::StorageInformation::StorageStatus::Unformatted:
×
NEW
567
            status = STORAGE_STATUS::STORAGE_STATUS_UNFORMATTED;
×
NEW
568
            break;
×
NEW
569
        case CameraServer::StorageInformation::StorageStatus::Formatted:
×
NEW
570
            status = STORAGE_STATUS::STORAGE_STATUS_READY;
×
NEW
571
            break;
×
NEW
572
        case CameraServer::StorageInformation::StorageStatus::NotSupported:
×
NEW
573
            status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
×
NEW
574
            break;
×
575
    }
576

NEW
577
    auto type = STORAGE_TYPE::STORAGE_TYPE_UNKNOWN;
×
NEW
578
    switch (storage_information.storage_type) {
×
NEW
579
        case CameraServer::StorageInformation::StorageType::UsbStick:
×
NEW
580
            type = STORAGE_TYPE::STORAGE_TYPE_USB_STICK;
×
NEW
581
            break;
×
NEW
582
        case CameraServer::StorageInformation::StorageType::Sd:
×
NEW
583
            type = STORAGE_TYPE::STORAGE_TYPE_SD;
×
NEW
584
            break;
×
NEW
585
        case CameraServer::StorageInformation::StorageType::Microsd:
×
NEW
586
            type = STORAGE_TYPE::STORAGE_TYPE_MICROSD;
×
NEW
587
            break;
×
NEW
588
        case CameraServer::StorageInformation::StorageType::Hd:
×
NEW
589
            type = STORAGE_TYPE::STORAGE_TYPE_HD;
×
NEW
590
            break;
×
NEW
591
        case CameraServer::StorageInformation::StorageType::Other:
×
NEW
592
            type = STORAGE_TYPE::STORAGE_TYPE_OTHER;
×
NEW
593
            break;
×
NEW
594
        default:
×
NEW
595
            break;
×
596
    }
597

NEW
598
    std::string name("");
×
599
    // This needs to be long enough, otherwise the memcpy in mavlink overflows.
NEW
600
    name.resize(32);
×
NEW
601
    const uint8_t storage_usage = 0;
×
602

NEW
603
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
NEW
604
        mavlink_message_t message{};
×
NEW
605
        mavlink_msg_storage_information_pack_chan(
×
NEW
606
            mavlink_address.system_id,
×
NEW
607
            mavlink_address.component_id,
×
608
            channel,
609
            &message,
NEW
610
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
×
NEW
611
            _last_storage_id,
×
612
            storage_count,
NEW
613
            status,
×
NEW
614
            total_capacity,
×
NEW
615
            used_capacity,
×
NEW
616
            available_capacity,
×
NEW
617
            read_speed,
×
NEW
618
            write_speed,
×
NEW
619
            type,
×
NEW
620
            name.data(),
×
621
            storage_usage);
NEW
622
        return message;
×
623
    });
624

NEW
625
    return CameraServer::Result::Success;
×
626
}
627

628
CameraServer::CaptureStatusHandle
NEW
629
CameraServerImpl::subscribe_capture_status(const CameraServer::CaptureStatusCallback& callback)
×
630
{
NEW
631
    return _capture_status_callbacks.subscribe(callback);
×
632
}
633

NEW
634
void CameraServerImpl::unsubscribe_capture_status(CameraServer::CaptureStatusHandle handle)
×
635
{
NEW
636
    _capture_status_callbacks.unsubscribe(handle);
×
NEW
637
}
×
638

NEW
639
CameraServer::Result CameraServerImpl::respond_capture_status(
×
640
    CameraServer::CameraFeedback capture_status_feedback,
641
    CameraServer::CaptureStatus capture_status)
642
{
NEW
643
    switch (capture_status_feedback) {
×
NEW
644
        default:
×
645
            // Fallthrough
646
        case CameraServer::CameraFeedback::Unknown:
NEW
647
            return CameraServer::Result::Error;
×
NEW
648
        case CameraServer::CameraFeedback::Ok: {
×
NEW
649
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
650
                _last_capture_status_command, MAV_RESULT_ACCEPTED);
×
NEW
651
            _server_component_impl->send_command_ack(command_ack);
×
652
            // break and send capture status
NEW
653
            break;
×
654
        }
NEW
655
        case CameraServer::CameraFeedback::Busy: {
×
NEW
656
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
657
                _last_capture_status_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
658
            _server_component_impl->send_command_ack(command_ack);
×
NEW
659
            return CameraServer::Result::Success;
×
660
        }
NEW
661
        case CameraServer::CameraFeedback::Failed: {
×
NEW
662
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
663
                _last_capture_status_command, MAV_RESULT_FAILED);
×
NEW
664
            _server_component_impl->send_command_ack(command_ack);
×
NEW
665
            return CameraServer::Result::Success;
×
666
        }
667
    }
668

NEW
669
    _capture_status = capture_status;
×
670

NEW
671
    send_capture_status();
×
672

NEW
673
    return CameraServer::Result::Success;
×
674
}
675

676
CameraServer::FormatStorageHandle
NEW
677
CameraServerImpl::subscribe_format_storage(const CameraServer::FormatStorageCallback& callback)
×
678
{
NEW
679
    return _format_storage_callbacks.subscribe(callback);
×
680
}
NEW
681
void CameraServerImpl::unsubscribe_format_storage(CameraServer::FormatStorageHandle handle)
×
682
{
NEW
683
    _format_storage_callbacks.unsubscribe(handle);
×
NEW
684
}
×
685

686
CameraServer::Result
NEW
687
CameraServerImpl::respond_format_storage(CameraServer::CameraFeedback format_storage_feedback)
×
688
{
NEW
689
    switch (format_storage_feedback) {
×
NEW
690
        default:
×
691
            // Fallthrough
692
        case CameraServer::CameraFeedback::Unknown:
NEW
693
            return CameraServer::Result::Error;
×
NEW
694
        case CameraServer::CameraFeedback::Ok: {
×
NEW
695
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
696
                _last_format_storage_command, MAV_RESULT_ACCEPTED);
×
NEW
697
            _server_component_impl->send_command_ack(command_ack);
×
NEW
698
            break;
×
699
        }
NEW
700
        case CameraServer::CameraFeedback::Busy: {
×
NEW
701
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
702
                _last_format_storage_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
703
            _server_component_impl->send_command_ack(command_ack);
×
NEW
704
            return CameraServer::Result::Success;
×
705
        }
NEW
706
        case CameraServer::CameraFeedback::Failed: {
×
NEW
707
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
708
                _last_format_storage_command, MAV_RESULT_FAILED);
×
NEW
709
            _server_component_impl->send_command_ack(command_ack);
×
NEW
710
            return CameraServer::Result::Success;
×
711
        }
712
    }
NEW
713
    return CameraServer::Result::Success;
×
714
}
715

716
CameraServer::ResetSettingsHandle
NEW
717
CameraServerImpl::subscribe_reset_settings(const CameraServer::ResetSettingsCallback& callback)
×
718
{
NEW
719
    return _reset_settings_callbacks.subscribe(callback);
×
720
}
721

NEW
722
void CameraServerImpl::unsubscribe_reset_settings(CameraServer::ResetSettingsHandle handle)
×
723
{
NEW
724
    _reset_settings_callbacks.unsubscribe(handle);
×
NEW
725
}
×
726

727
CameraServer::Result
NEW
728
CameraServerImpl::respond_reset_settings(CameraServer::CameraFeedback reset_settings_feedback)
×
729
{
NEW
730
    switch (reset_settings_feedback) {
×
NEW
731
        default:
×
732
            // Fallthrough
733
        case CameraServer::CameraFeedback::Unknown:
NEW
734
            return CameraServer::Result::Error;
×
NEW
735
        case CameraServer::CameraFeedback::Ok: {
×
NEW
736
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
737
                _last_reset_settings_command, MAV_RESULT_ACCEPTED);
×
NEW
738
            _server_component_impl->send_command_ack(command_ack);
×
NEW
739
            break;
×
740
        }
NEW
741
        case CameraServer::CameraFeedback::Busy: {
×
NEW
742
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
743
                _last_reset_settings_command, MAV_RESULT_TEMPORARILY_REJECTED);
×
NEW
744
            _server_component_impl->send_command_ack(command_ack);
×
NEW
745
            return CameraServer::Result::Success;
×
746
        }
NEW
747
        case CameraServer::CameraFeedback::Failed: {
×
NEW
748
            auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
749
                _last_reset_settings_command, MAV_RESULT_FAILED);
×
NEW
750
            _server_component_impl->send_command_ack(command_ack);
×
NEW
751
            return CameraServer::Result::Success;
×
752
        }
753
    }
NEW
754
    return CameraServer::Result::Success;
×
755
}
756

UNCOV
757
void CameraServerImpl::start_image_capture_interval(float interval_s, int32_t count, int32_t index)
×
758
{
759
    // If count == 0, it means capture "forever" until a stop command is received.
760
    auto remaining = std::make_shared<int32_t>(count == 0 ? INT32_MAX : count);
×
761

762
    _server_component_impl->add_call_every(
×
763
        [this, remaining, index]() {
×
764
            LogDebug() << "capture image timer triggered";
×
765

766
            if (!_take_photo_callbacks.empty()) {
×
767
                _take_photo_callbacks(index);
×
768
                (*remaining)--;
×
769
            }
770

771
            if (*remaining == 0) {
×
772
                stop_image_capture_interval();
×
773
            }
774
        },
×
775
        interval_s,
776
        &_image_capture_timer_cookie);
777

778
    _is_image_capture_interval_set = true;
×
779
    _image_capture_timer_interval_s = interval_s;
×
780
}
×
781

782
void CameraServerImpl::stop_image_capture_interval()
1✔
783
{
784
    if (_image_capture_timer_cookie) {
1✔
785
        _server_component_impl->remove_call_every(_image_capture_timer_cookie);
×
786
    }
787

788
    _image_capture_timer_cookie = nullptr;
1✔
789
    _is_image_capture_interval_set = false;
1✔
790
    _image_capture_timer_interval_s = 0;
1✔
791
}
1✔
792

793
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_information_request(
×
794
    const MavlinkCommandReceiver::CommandLong& command)
795
{
NEW
796
    LogWarn() << "Camera info request";
×
UNCOV
797
    auto capabilities = static_cast<bool>(command.params.param1);
×
798

799
    if (!capabilities) {
×
800
        LogDebug() << "early info return";
×
801
        return _server_component_impl->make_command_ack_message(
×
802
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
803
    }
804

805
    if (!_is_information_set) {
×
806
        return _server_component_impl->make_command_ack_message(
×
807
            command, MAV_RESULT::MAV_RESULT_TEMPORARILY_REJECTED);
×
808
    }
809

810
    // ack needs to be sent before camera information message
811
    auto command_ack =
×
812
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
813
    _server_component_impl->send_command_ack(command_ack);
×
814
    LogDebug() << "sent info ack";
×
815

816
    // It is safe to ignore the return value of parse_version_string() here
817
    // since the string was already validated in set_information().
818
    uint32_t firmware_version;
×
819
    parse_version_string(_information.firmware_version, firmware_version);
×
820

821
    // capability flags are determined by subscriptions
822
    uint32_t capability_flags{};
×
823

824
    if (!_take_photo_callbacks.empty()) {
×
825
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_CAPTURE_IMAGE;
×
826
    }
827

NEW
828
    if (!_start_video_callbacks.empty()) {
×
NEW
829
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_CAPTURE_VIDEO;
×
830
    }
831

NEW
832
    if (!_set_mode_callbacks.empty()) {
×
NEW
833
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_MODES;
×
834
    }
835

NEW
836
    if (_is_video_streaming_set) {
×
NEW
837
        capability_flags |= CAMERA_CAP_FLAGS::CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM;
×
838
    }
839

NEW
840
    _information.vendor_name.resize(sizeof(mavlink_camera_information_t::vendor_name));
×
NEW
841
    _information.model_name.resize(sizeof(mavlink_camera_information_t::model_name));
×
NEW
842
    _information.definition_file_uri.resize(
×
843
        sizeof(mavlink_camera_information_t::cam_definition_uri));
844

845
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
846
        mavlink_message_t message{};
×
847
        mavlink_msg_camera_information_pack_chan(
×
848
            mavlink_address.system_id,
×
849
            mavlink_address.component_id,
×
850
            channel,
851
            &message,
852
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
×
853
            reinterpret_cast<const uint8_t*>(_information.vendor_name.c_str()),
×
854
            reinterpret_cast<const uint8_t*>(_information.model_name.c_str()),
×
855
            firmware_version,
×
856
            _information.focal_length_mm,
857
            _information.horizontal_sensor_size_mm,
858
            _information.vertical_sensor_size_mm,
859
            _information.horizontal_resolution_px,
×
860
            _information.vertical_resolution_px,
×
861
            _information.lens_id,
×
862
            capability_flags,
×
863
            _information.definition_file_version,
×
864
            _information.definition_file_uri.c_str(),
865
            0);
UNCOV
866
        return message;
×
867
    });
868
    LogDebug() << "sent info msg";
×
869

870
    // ack was already sent
871
    return std::nullopt;
×
872
}
873

874
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_settings_request(
×
875
    const MavlinkCommandReceiver::CommandLong& command)
876
{
877
    auto settings = static_cast<bool>(command.params.param1);
×
878

879
    if (!settings) {
×
880
        LogDebug() << "early settings return";
×
881
        return _server_component_impl->make_command_ack_message(
×
882
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
883
    }
884

885
    // ack needs to be sent before camera information message
NEW
886
    auto command_ack =
×
887
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
NEW
888
    _server_component_impl->send_command_ack(command_ack);
×
889
    LogDebug() << "sent settings ack";
×
890

891
    // unsupported
892
    const auto mode_id = CAMERA_MODE::CAMERA_MODE_IMAGE;
×
893
    const float zoom_level = 0;
×
894
    const float focus_level = 0;
×
895

896
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
897
        mavlink_message_t message{};
×
898
        mavlink_msg_camera_settings_pack_chan(
×
899
            mavlink_address.system_id,
×
900
            mavlink_address.component_id,
×
901
            channel,
902
            &message,
903
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
×
904
            mode_id,
905
            zoom_level,
×
906
            focus_level);
×
907
        return message;
×
908
    });
909
    LogDebug() << "sent settings msg";
×
910

911
    // ack was already sent
912
    return std::nullopt;
×
913
}
914

915
std::optional<mavlink_command_ack_t> CameraServerImpl::process_storage_information_request(
×
916
    const MavlinkCommandReceiver::CommandLong& command)
917
{
918
    auto storage_id = static_cast<uint8_t>(command.params.param1);
×
919
    auto information = static_cast<bool>(command.params.param2);
×
920

921
    if (!information) {
×
922
        LogDebug() << "early storage return";
×
923
        return _server_component_impl->make_command_ack_message(
×
924
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
925
    }
926

NEW
927
    if (_storage_information_callbacks.empty()) {
×
NEW
928
        LogDebug()
×
NEW
929
            << "Get storage information requested with no set storage information subscriber";
×
NEW
930
        return _server_component_impl->make_command_ack_message(
×
NEW
931
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
932
    }
933

934
    // ack needs to be sent before storage information message
935
    auto command_ack =
×
936
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
937
    _server_component_impl->send_command_ack(command_ack);
×
938

939
    // TODO may need support multi storage id
NEW
940
    _last_storage_id = storage_id;
×
941

NEW
942
    _last_storage_information_command = command;
×
NEW
943
    _storage_information_callbacks(storage_id);
×
944

945
    // unsupported
946
    const uint8_t storage_count = 0;
×
947
    const auto status = STORAGE_STATUS::STORAGE_STATUS_NOT_SUPPORTED;
×
948
    const float total_capacity = 0;
×
949
    const float used_capacity = 0;
×
950
    const float available_capacity = 0;
×
951
    const float read_speed = 0;
×
952
    const float write_speed = 0;
×
953
    const uint8_t type = STORAGE_TYPE::STORAGE_TYPE_UNKNOWN;
×
954
    std::string name("");
×
955
    // This needs to be long enough, otherwise the memcpy in mavlink overflows.
956
    name.resize(32);
×
957
    const uint8_t storage_usage = 0;
×
958

959
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
960
        mavlink_message_t message{};
×
961
        mavlink_msg_storage_information_pack_chan(
×
962
            mavlink_address.system_id,
×
963
            mavlink_address.component_id,
×
964
            channel,
965
            &message,
966
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
×
967
            storage_id,
×
968
            storage_count,
969
            status,
970
            total_capacity,
×
971
            used_capacity,
×
972
            available_capacity,
×
973
            read_speed,
×
974
            write_speed,
×
975
            type,
976
            name.data(),
×
977
            storage_usage);
978

979
        return message;
×
980
    });
981

982
    LogDebug() << "sent storage msg";
×
983

984
    // ack was already sent
985
    return std::nullopt;
×
986
}
987

988
std::optional<mavlink_command_ack_t>
989
CameraServerImpl::process_storage_format(const MavlinkCommandReceiver::CommandLong& command)
×
990
{
991
    auto storage_id = static_cast<uint8_t>(command.params.param1);
×
992
    auto format = static_cast<bool>(command.params.param2);
×
993
    auto reset_image_log = static_cast<bool>(command.params.param3);
×
994

995
    UNUSED(format);
×
996
    UNUSED(reset_image_log);
×
NEW
997
    if (_format_storage_callbacks.empty()) {
×
NEW
998
        LogDebug() << "process storage format requested with no storage format subscriber";
×
NEW
999
        return _server_component_impl->make_command_ack_message(
×
NEW
1000
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1001
    }
1002

NEW
1003
    _last_format_storage_command = command;
×
NEW
1004
    _format_storage_callbacks(storage_id);
×
1005

NEW
1006
    return std::nullopt;
×
1007
}
1008

1009
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_capture_status_request(
×
1010
    const MavlinkCommandReceiver::CommandLong& command)
1011
{
1012
    auto capture_status = static_cast<bool>(command.params.param1);
×
1013

1014
    if (!capture_status) {
×
1015
        return _server_component_impl->make_command_ack_message(
×
1016
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1017
    }
1018

NEW
1019
    if (_capture_status_callbacks.empty()) {
×
NEW
1020
        LogDebug() << "process camera capture status requested with no capture status subscriber";
×
NEW
1021
        return _server_component_impl->make_command_ack_message(
×
NEW
1022
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1023
    }
1024

1025
    // ack needs to be sent before camera capture status message
1026
    auto command_ack =
×
1027
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1028
    _server_component_impl->send_command_ack(command_ack);
×
1029

NEW
1030
    _last_capture_status_command = command;
×
1031

1032
    // may not need param for now ,just use zero
NEW
1033
    _capture_status_callbacks(0);
×
1034

NEW
1035
    send_capture_status();
×
1036

1037
    // ack was already sent
NEW
1038
    return std::nullopt;
×
1039
}
1040

NEW
1041
void CameraServerImpl::send_capture_status()
×
1042
{
NEW
1043
    uint8_t image_status{};
×
NEW
1044
    if (_capture_status.image_status ==
×
NEW
1045
            CameraServer::CaptureStatus::ImageStatus::CaptureInProgress ||
×
NEW
1046
        _capture_status.image_status ==
×
1047
            CameraServer::CaptureStatus::ImageStatus::IntervalInProgress) {
UNCOV
1048
        image_status |= StatusFlags::IN_PROGRESS;
×
1049
    }
1050

NEW
1051
    if (_capture_status.image_status == CameraServer::CaptureStatus::ImageStatus::IntervalIdle ||
×
NEW
1052
        _capture_status.image_status ==
×
NEW
1053
            CameraServer::CaptureStatus::ImageStatus::IntervalInProgress ||
×
NEW
1054
        _is_image_capture_interval_set) {
×
UNCOV
1055
        image_status |= StatusFlags::INTERVAL_SET;
×
1056
    }
1057

NEW
1058
    uint8_t video_status = 0;
×
NEW
1059
    if (_capture_status.video_status == CameraServer::CaptureStatus::VideoStatus::Idle) {
×
NEW
1060
        video_status = 0;
×
NEW
1061
    } else if (
×
NEW
1062
        _capture_status.video_status ==
×
1063
        CameraServer::CaptureStatus::VideoStatus::CaptureInProgress) {
NEW
1064
        video_status = 1;
×
1065
    }
1066

NEW
1067
    const uint32_t recording_time_ms =
×
NEW
1068
        static_cast<uint32_t>(static_cast<double>(_capture_status.recording_time_s) * 1e3);
×
NEW
1069
    const float available_capacity = _capture_status.available_capacity_mib;
×
1070

1071
    _server_component_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
1072
        mavlink_message_t message{};
×
1073
        mavlink_msg_camera_capture_status_pack_chan(
×
1074
            mavlink_address.system_id,
×
1075
            mavlink_address.component_id,
×
1076
            channel,
1077
            &message,
1078
            static_cast<uint32_t>(_server_component_impl->get_time().elapsed_s() * 1e3),
×
1079
            image_status,
×
UNCOV
1080
            video_status,
×
1081
            _image_capture_timer_interval_s,
UNCOV
1082
            recording_time_ms,
×
1083
            available_capacity,
×
1084
            _image_capture_count);
1085
        return message;
×
1086
    });
UNCOV
1087
}
×
1088

1089
std::optional<mavlink_command_ack_t>
1090
CameraServerImpl::process_reset_camera_settings(const MavlinkCommandReceiver::CommandLong& command)
×
1091
{
1092
    auto reset = static_cast<bool>(command.params.param1);
×
1093

1094
    UNUSED(reset);
×
1095

NEW
1096
    if (_reset_settings_callbacks.empty()) {
×
NEW
1097
        LogDebug() << "reset camera settings requested with no camera settings subscriber";
×
NEW
1098
        return _server_component_impl->make_command_ack_message(
×
NEW
1099
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1100
    }
1101

NEW
1102
    _last_reset_settings_command = command;
×
NEW
1103
    _reset_settings_callbacks(0);
×
1104

NEW
1105
    return std::nullopt;
×
1106
}
1107

1108
std::optional<mavlink_command_ack_t>
1109
CameraServerImpl::process_set_camera_mode(const MavlinkCommandReceiver::CommandLong& command)
×
1110
{
1111
    auto camera_mode = static_cast<CAMERA_MODE>(command.params.param2);
×
1112

NEW
1113
    if (_set_mode_callbacks.empty()) {
×
NEW
1114
        LogDebug() << "Set mode requested with no set mode subscriber";
×
NEW
1115
        return _server_component_impl->make_command_ack_message(
×
NEW
1116
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1117
    }
1118

1119
    // convert camera mode enum type
NEW
1120
    CameraServer::Mode convert_camera_mode = CameraServer::Mode::Unknown;
×
NEW
1121
    if (camera_mode == CAMERA_MODE_IMAGE) {
×
NEW
1122
        convert_camera_mode = CameraServer::Mode::Photo;
×
NEW
1123
    } else if (camera_mode == CAMERA_MODE_VIDEO) {
×
NEW
1124
        convert_camera_mode = CameraServer::Mode::Video;
×
1125
    }
1126

NEW
1127
    if (convert_camera_mode == CameraServer::Mode::Unknown) {
×
NEW
1128
        return _server_component_impl->make_command_ack_message(
×
NEW
1129
            command, MAV_RESULT::MAV_RESULT_DENIED);
×
1130
    }
1131

NEW
1132
    _last_set_mode_command = command;
×
NEW
1133
    _set_mode_callbacks(convert_camera_mode);
×
1134

NEW
1135
    return std::nullopt;
×
1136
}
1137

1138
std::optional<mavlink_command_ack_t>
1139
CameraServerImpl::process_set_camera_zoom(const MavlinkCommandReceiver::CommandLong& command)
×
1140
{
1141
    auto zoom_type = static_cast<CAMERA_ZOOM_TYPE>(command.params.param1);
×
1142
    auto zoom_value = command.params.param2;
×
1143

1144
    UNUSED(zoom_type);
×
1145
    UNUSED(zoom_value);
×
1146

1147
    LogDebug() << "unsupported set camera zoom request";
×
1148

1149
    return _server_component_impl->make_command_ack_message(
×
1150
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1151
}
1152

1153
std::optional<mavlink_command_ack_t>
1154
CameraServerImpl::process_set_camera_focus(const MavlinkCommandReceiver::CommandLong& command)
×
1155
{
1156
    auto focus_type = static_cast<SET_FOCUS_TYPE>(command.params.param1);
×
1157
    auto focus_value = command.params.param2;
×
1158

1159
    UNUSED(focus_type);
×
1160
    UNUSED(focus_value);
×
1161

1162
    LogDebug() << "unsupported set camera focus request";
×
1163

1164
    return _server_component_impl->make_command_ack_message(
×
1165
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1166
}
1167

1168
std::optional<mavlink_command_ack_t>
1169
CameraServerImpl::process_set_storage_usage(const MavlinkCommandReceiver::CommandLong& command)
×
1170
{
1171
    auto storage_id = static_cast<uint8_t>(command.params.param1);
×
1172
    auto usage = static_cast<STORAGE_USAGE_FLAG>(command.params.param2);
×
1173

1174
    UNUSED(storage_id);
×
1175
    UNUSED(usage);
×
1176

1177
    LogDebug() << "unsupported set storage usage request";
×
1178

1179
    return _server_component_impl->make_command_ack_message(
×
1180
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1181
}
1182

1183
std::optional<mavlink_command_ack_t>
1184
CameraServerImpl::process_image_start_capture(const MavlinkCommandReceiver::CommandLong& command)
×
1185
{
1186
    auto interval_s = command.params.param2;
×
1187
    auto total_images = static_cast<int32_t>(command.params.param3);
×
1188
    auto seq_number = static_cast<int32_t>(command.params.param4);
×
1189

1190
    LogDebug() << "received image start capture request - interval: " << +interval_s
×
1191
               << " total: " << +total_images << " index: " << +seq_number;
×
1192

1193
    // TODO: validate parameters and return MAV_RESULT_DENIED not valid
1194

1195
    stop_image_capture_interval();
×
1196

1197
    if (_take_photo_callbacks.empty()) {
×
1198
        LogDebug() << "image capture requested with no take photo subscriber";
×
1199
        return _server_component_impl->make_command_ack_message(
×
1200
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1201
    }
1202

1203
    // single image capture
1204
    if (total_images == 1) {
×
1205
        // MAV_RESULT_ACCEPTED must be sent before CAMERA_IMAGE_CAPTURED
1206
        auto command_ack = _server_component_impl->make_command_ack_message(
×
1207
            command, MAV_RESULT::MAV_RESULT_IN_PROGRESS);
×
1208
        _server_component_impl->send_command_ack(command_ack);
×
1209

1210
        _last_take_photo_command = command;
×
1211

UNCOV
1212
        _take_photo_callbacks(seq_number);
×
1213

1214
        return std::nullopt;
×
1215
    }
1216

1217
    start_image_capture_interval(interval_s, total_images, seq_number);
×
1218

1219
    return _server_component_impl->make_command_ack_message(
×
1220
        command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1221
}
1222

1223
std::optional<mavlink_command_ack_t>
1224
CameraServerImpl::process_image_stop_capture(const MavlinkCommandReceiver::CommandLong& command)
×
1225
{
1226
    LogDebug() << "received image stop capture request";
×
1227

1228
    // REVISIT: should we return something other that MAV_RESULT_ACCEPTED if
1229
    // there is not currently a capture interval active?
1230
    stop_image_capture_interval();
×
1231

1232
    return _server_component_impl->make_command_ack_message(
×
1233
        command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
1234
}
1235

1236
std::optional<mavlink_command_ack_t> CameraServerImpl::process_camera_image_capture_request(
×
1237
    const MavlinkCommandReceiver::CommandLong& command)
1238
{
1239
    auto seq_number = static_cast<uint32_t>(command.params.param1);
×
1240

1241
    UNUSED(seq_number);
×
1242

1243
    LogDebug() << "unsupported image capture request";
×
1244

1245
    return _server_component_impl->make_command_ack_message(
×
1246
        command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1247
}
1248

1249
std::optional<mavlink_command_ack_t>
1250
CameraServerImpl::process_video_start_capture(const MavlinkCommandReceiver::CommandLong& command)
×
1251
{
1252
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1253
    auto status_frequency = command.params.param2;
×
1254

1255
    UNUSED(status_frequency);
×
1256

NEW
1257
    if (_start_video_callbacks.empty()) {
×
NEW
1258
        LogDebug() << "video start capture requested with no video start capture subscriber";
×
NEW
1259
        return _server_component_impl->make_command_ack_message(
×
NEW
1260
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1261
    }
1262

NEW
1263
    _last_start_video_command = command;
×
NEW
1264
    _start_video_callbacks(stream_id);
×
1265

NEW
1266
    return std::nullopt;
×
1267
}
1268

1269
std::optional<mavlink_command_ack_t>
1270
CameraServerImpl::process_video_stop_capture(const MavlinkCommandReceiver::CommandLong& command)
×
1271
{
1272
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1273

NEW
1274
    if (_stop_video_callbacks.empty()) {
×
NEW
1275
        LogDebug() << "video stop capture requested with no video stop capture subscriber";
×
NEW
1276
        return _server_component_impl->make_command_ack_message(
×
NEW
1277
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1278
    }
1279

NEW
1280
    _last_stop_video_command = command;
×
NEW
1281
    _stop_video_callbacks(stream_id);
×
1282

NEW
1283
    return std::nullopt;
×
1284
}
1285

1286
std::optional<mavlink_command_ack_t>
1287
CameraServerImpl::process_video_start_streaming(const MavlinkCommandReceiver::CommandLong& command)
×
1288
{
1289
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1290

NEW
1291
    if (_start_video_streaming_callbacks.empty()) {
×
NEW
1292
        LogDebug() << "video start streaming requested with no video start streaming subscriber";
×
NEW
1293
        return _server_component_impl->make_command_ack_message(
×
NEW
1294
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1295
    }
1296

NEW
1297
    _last_start_video_streaming_command = command;
×
NEW
1298
    _start_video_streaming_callbacks(stream_id);
×
1299

NEW
1300
    return std::nullopt;
×
1301
}
1302

1303
std::optional<mavlink_command_ack_t>
1304
CameraServerImpl::process_video_stop_streaming(const MavlinkCommandReceiver::CommandLong& command)
×
1305
{
1306
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1307

NEW
1308
    if (_stop_video_streaming_callbacks.empty()) {
×
NEW
1309
        LogDebug() << "video stop streaming requested with no video stop streaming subscriber";
×
NEW
1310
        return _server_component_impl->make_command_ack_message(
×
NEW
1311
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1312
    }
1313

NEW
1314
    _last_stop_video_streaming_command = command;
×
NEW
1315
    _stop_video_streaming_callbacks(stream_id);
×
1316

NEW
1317
    return std::nullopt;
×
1318
}
1319

1320
std::optional<mavlink_command_ack_t> CameraServerImpl::process_video_stream_information_request(
×
1321
    const MavlinkCommandReceiver::CommandLong& command)
1322
{
1323
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1324

1325
    UNUSED(stream_id);
×
1326

NEW
1327
    if (_is_video_streaming_set) {
×
NEW
1328
        auto command_ack = _server_component_impl->make_command_ack_message(
×
NEW
1329
            command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
NEW
1330
        _server_component_impl->send_command_ack(command_ack);
×
NEW
1331
        LogDebug() << "sent video streaming ack";
×
1332

NEW
1333
        const char name[32] = "";
×
1334

NEW
1335
        _video_streaming.rtsp_uri.resize(sizeof(mavlink_video_stream_information_t::uri));
×
1336

NEW
1337
        mavlink_message_t msg{};
×
NEW
1338
        mavlink_msg_video_stream_information_pack(
×
NEW
1339
            _server_component_impl->get_own_system_id(),
×
NEW
1340
            _server_component_impl->get_own_component_id(),
×
1341
            &msg,
1342
            0, // Stream id
1343
            0, // Count
1344
            VIDEO_STREAM_TYPE_RTSP,
1345
            VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1346
            0, // famerate
1347
            0, // resolution horizontal
1348
            0, // resolution vertical
1349
            0, // bitrate
1350
            0, // rotation
1351
            0, // horizontal field of view
1352
            name,
1353
            _video_streaming.rtsp_uri.c_str());
1354

NEW
1355
        _server_component_impl->send_message(msg);
×
1356

1357
        // Ack already sent.
NEW
1358
        return std::nullopt;
×
1359

1360
    } else {
NEW
1361
        return _server_component_impl->make_command_ack_message(
×
NEW
1362
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1363
    }
1364
}
1365

1366
std::optional<mavlink_command_ack_t> CameraServerImpl::process_video_stream_status_request(
×
1367
    const MavlinkCommandReceiver::CommandLong& command)
1368
{
1369
    auto stream_id = static_cast<uint8_t>(command.params.param1);
×
1370

1371
    UNUSED(stream_id);
×
1372

NEW
1373
    if (!_is_video_streaming_set) {
×
NEW
1374
        return _server_component_impl->make_command_ack_message(
×
NEW
1375
            command, MAV_RESULT::MAV_RESULT_UNSUPPORTED);
×
1376
    }
1377

NEW
1378
    auto command_ack =
×
NEW
1379
        _server_component_impl->make_command_ack_message(command, MAV_RESULT::MAV_RESULT_ACCEPTED);
×
NEW
1380
    _server_component_impl->send_command_ack(command_ack);
×
NEW
1381
    LogDebug() << "sent video streaming ack";
×
1382

NEW
1383
    mavlink_message_t msg{};
×
NEW
1384
    mavlink_msg_video_stream_status_pack(
×
NEW
1385
        _server_component_impl->get_own_system_id(),
×
NEW
1386
        _server_component_impl->get_own_component_id(),
×
1387
        &msg,
1388
        0, // Stream id
1389
        VIDEO_STREAM_STATUS_FLAGS_RUNNING,
1390
        0, // framerate
1391
        0, // resolution horizontal
1392
        0, // resolution vertical
1393
        0, // bitrate
1394
        0, // rotation
1395
        0 // horizontal field of view
1396
    );
NEW
1397
    _server_component_impl->send_message(msg);
×
1398

1399
    // ack was already sent
NEW
1400
    return std::nullopt;
×
1401
}
1402

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