QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
VehicleCameraControl.cc
Go to the documentation of this file.
2#include "QGCCameraIO.h"
3#include "AppMessages.h"
4#include "QGCFormat.h"
5#include "SettingsManager.h"
6#include "AppSettings.h"
7#include "VideoManager.h"
8#include "QGCCameraManager.h"
9#include "FTPManager.h"
10#include "QGCCompression.h"
11#include "QGCCorePlugin.h"
12#include "AppMessages.h"
13#include "QGCFormat.h"
14#include "Vehicle.h"
15#include "VehicleLinkManager.h"
16#include "LinkInterface.h"
17#include "MAVLinkProtocol.h"
18#include "QGCVideoStreamInfo.h"
19#include "MissionCommandTree.h"
20
21#include <QtNetwork/QNetworkAccessManager>
22#include <QtCore/QDir>
23
24#include <algorithm>
25#include <QtCore/QSettings>
26#include <QtXml/QDomDocument>
27#include <QtXml/QDomNodeList>
28#include <QtQml/QQmlEngine>
29#include <QtNetwork/QNetworkReply>
30
31#include "QGCNetworkHelper.h"
32#include "QGCLoggingCategory.h"
33
34QGC_LOGGING_CATEGORY(VehicleCameraControlLog, "Camera.VehicleCameraControl")
35QGC_LOGGING_CATEGORY(VehicleCameraControlVerboseLog, "Camera.VehicleCameraControl.Verbose")
36
37QGCCameraOptionExclusion::QGCCameraOptionExclusion(QObject* parent, QString param_, QString value_, QStringList exclusions_)
38 : QObject(parent)
39 , param(param_)
40 , value(value_)
41 , exclusions(exclusions_)
42{
43}
44
45QGCCameraOptionRange::QGCCameraOptionRange(QObject* parent, QString param_, QString value_, QString targetParam_, QString condition_, QStringList optNames_, QStringList optValues_)
46 : QObject(parent)
47 , param(param_)
48 , value(value_)
49 , targetParam(targetParam_)
50 , condition(condition_)
51 , optNames(optNames_)
52 , optValues(optValues_)
53{
54}
55
56static bool read_attribute(QDomNode& node, const char* tagName, bool& target)
57{
58 QDomNamedNodeMap attrs = node.attributes();
59 if(!attrs.count()) {
60 return false;
61 }
62 QDomNode subNode = attrs.namedItem(tagName);
63 if(subNode.isNull()) {
64 return false;
65 }
66 target = subNode.nodeValue() != "0";
67 return true;
68}
69
70static bool read_attribute(QDomNode& node, const char* tagName, int& target)
71{
72 QDomNamedNodeMap attrs = node.attributes();
73 if(!attrs.count()) {
74 return false;
75 }
76 QDomNode subNode = attrs.namedItem(tagName);
77 if(subNode.isNull()) {
78 return false;
79 }
80 target = subNode.nodeValue().toInt();
81 return true;
82}
83
84static bool read_attribute(QDomNode& node, const char* tagName, QString& target)
85{
86 QDomNamedNodeMap attrs = node.attributes();
87 if(!attrs.count()) {
88 return false;
89 }
90 QDomNode subNode = attrs.namedItem(tagName);
91 if(subNode.isNull()) {
92 return false;
93 }
94 target = subNode.nodeValue();
95 return true;
96}
97
98static bool read_value(QDomNode& element, const char* tagName, QString& target)
99{
100 QDomElement de = element.firstChildElement(tagName);
101 if(de.isNull()) {
102 return false;
103 }
104 target = de.text();
105 return true;
106}
107
108VehicleCameraControl::VehicleCameraControl(const mavlink_camera_information_t *info, Vehicle* vehicle, int compID, QObject* parent)
109 : MavlinkCameraControlInterface(vehicle, parent)
110 , _compID(compID)
111{
112 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
113
114 memcpy(&_mavlinkCameraInfo, info, sizeof(mavlink_camera_information_t));
115
116 _vendor = QString(reinterpret_cast<const char*>(info->vendor_name));
117 _modelName = QString(reinterpret_cast<const char*>(info->model_name));
118 _cacheFile = QString::asprintf("%s/%s_%s_%03d.xml",
119 SettingsManager::instance()->appSettings()->parameterSavePath().toStdString().c_str(),
120 _vendor.toStdString().c_str(),
121 _modelName.toStdString().c_str(),
122 static_cast<int>(_mavlinkCameraInfo.cam_definition_version));
123
125
126 if(info->cam_definition_uri[0] != 0) {
127 //-- Process camera definition file
128 _handleDefinitionFile(info->cam_definition_uri);
129 } else {
131 }
132
133 QSettings settings;
134 _photoCaptureMode = static_cast<PhotoCaptureMode>(settings.value(kPhotoMode, static_cast<int>(PHOTO_CAPTURE_SINGLE)).toInt());
135 _photoLapse = settings.value(kPhotoLapse, 1.0).toDouble();
136 _photoLapseCount = settings.value(kPhotoLapseCount, 0).toInt();
137 _thermalOpacity = settings.value(kThermalOpacity, 85.0).toDouble();
138 _thermalMode = static_cast<ThermalViewMode>(settings.value(kThermalMode, static_cast<uint32_t>(THERMAL_BLEND)).toUInt());
139
140 _videoRecordTimeUpdateTimer.setSingleShot(false);
141 _videoRecordTimeUpdateTimer.setInterval(333);
143
144 // Cameras are not required to broadcast CAMERA_SETTINGS when zoom/focus changes,
145 // so re-request it after an accepted zoom/focus command to keep zoom level and
146 // FOV current. The delay also coalesces bursts of zoom/focus commands into a
147 // single request.
148 constexpr int kCameraSettingsRefreshDelayMsecs = 1000;
149 _cameraSettingsRefreshTimer.setSingleShot(true);
150 _cameraSettingsRefreshTimer.setInterval(kCameraSettingsRefreshDelayMsecs);
151 connect(&_cameraSettingsRefreshTimer, &QTimer::timeout, this, [this]() {
152 _cameraSettingsRetries = 0; // Start a fresh request/retry cycle
154 });
155
156 //-- Tracking capabilities
157 _hasTrackingRectCapability = _mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_HAS_TRACKING_RECTANGLE;
158 _hasTrackingPointCapability = _mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_HAS_TRACKING_POINT;
159
160 qCDebug(VehicleCameraControlLog) << "Camera Info:";
161 qCDebug(VehicleCameraControlLog) << " vendor:" << vendor();
162 qCDebug(VehicleCameraControlLog) << " model:" << modelName();
163 qCDebug(VehicleCameraControlLog) << " version:" << version();
164 qCDebug(VehicleCameraControlLog) << " firmware:" << firmwareVersion();
165 qCDebug(VehicleCameraControlLog) << " focal length:" << focalLength();
166 qCDebug(VehicleCameraControlLog) << " sensor size:" << sensorSize();
167 qCDebug(VehicleCameraControlLog) << " resolution:" << resolution();
168 qCDebug(VehicleCameraControlLog) << " captures video:" << capturesVideo();
169 qCDebug(VehicleCameraControlLog) << " captures photos:" << capturesPhotos();
170 qCDebug(VehicleCameraControlLog) << " has modes:" << hasModes();
171 qCDebug(VehicleCameraControlLog) << " has zoom:" << hasZoom();
172 qCDebug(VehicleCameraControlLog) << " has focus:" << hasFocus();
173 qCDebug(VehicleCameraControlLog) << " has tracking:" << hasTracking();
174 qCDebug(VehicleCameraControlLog) << " has video stream:" << hasVideoStream();
175 qCDebug(VehicleCameraControlLog) << " photos in video mode:" << photosInVideoMode();
176 qCDebug(VehicleCameraControlLog) << " video in photo mode:" << videoInPhotoMode();
177}
178
180{
181 // Stop all timers to prevent them from firing during or after destruction
182 _captureStatusTimer.stop();
184 _streamInfoTimer.stop();
185 _streamStatusTimer.stop();
188 _storageInfoTimer.stop();
189
190 delete _netManager;
191 _netManager = nullptr;
192}
193
195{
196 qCDebug(VehicleCameraControlLog) << "_initWhenReady()";
197 if(isBasic()) {
198 qCDebug(VehicleCameraControlLog) << "Basic, MAVLink only messages, no parameters.";
199 //-- Basic cameras have no parameters
200 _paramComplete = true;
201 emit parametersReady();
202 } else {
204 }
205
206 QTimer::singleShot(500, this, &VehicleCameraControl::_requestCameraSettings);
207 connect(&_cameraSettingsTimer, &QTimer::timeout, this, &VehicleCameraControl::_cameraSettingsTimeout);
208
209 QTimer::singleShot(1000, this, &VehicleCameraControl::_checkForVideoStreams);
210
212
213 connect(&_captureStatusTimer, &QTimer::timeout, this, &VehicleCameraControl::_requestCaptureStatus);
214 _captureStatusTimer.setSingleShot(true);
215 _captureStatusTimer.start(1500);
216
217 connect(&_storageInfoTimer, &QTimer::timeout, this, &VehicleCameraControl::_storageInfoTimeout);
218 QTimer::singleShot(2000, this, &VehicleCameraControl::_requestStorageInfo);
219
227
228 emit infoChanged();
229
230 delete _netManager;
231 _netManager = nullptr;
232}
233
235{
236 // Even if the camera itself does not report video capture capability
237 // we can always save locally from a video stream, or use onboard recording
238 // if the camera reports video capture capability.
239 return _mavlinkCameraInfo.flags & (CAMERA_CAP_FLAGS_CAPTURE_VIDEO | CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM);
240}
241
243{
244 // If we have a video stream we can always screen grab from it,
245 //even if the camera itself does not report still capture capability.
246 return _mavlinkCameraInfo.flags & (CAMERA_CAP_FLAGS_CAPTURE_IMAGE | CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM);
247}
248
250{
253 } else if (_photoCaptureStatus() != PHOTO_CAPTURE_IDLE) {
256 // The ui is not set up to support recording video while in photo/survey mode, even if the camera technically supports it.
258 } else if (_mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM || _mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_CAPTURE_VIDEO) {
260 }
261
263}
264
266{
271 } else if (_photoCaptureStatus() == PHOTO_CAPTURE_IDLE) {
272 // We can always do at least a screen grab from the video stream, even if camera doesn't report still capture capability
273 if (_mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM || _mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_CAPTURE_IMAGE) {
275 }
276 }
277
279}
280
282{
283 if (_mavlinkCameraInfo.firmware_version == 0) {
284 return {};
285 }
286 int major = (_mavlinkCameraInfo.firmware_version) & 0xFF;
287 int minor = (_mavlinkCameraInfo.firmware_version >> 8) & 0xFF;
288 int patch = (_mavlinkCameraInfo.firmware_version >> 16) & 0xFF;
289 int dev = (_mavlinkCameraInfo.firmware_version >> 24) & 0xFF;
290 if (dev != 0) {
291 return QString::asprintf("%d.%d.%d.%d", major, minor, patch, dev);
292 }
293 return QString::asprintf("%d.%d.%d", major, minor, patch);
294}
295
297{
298 return QTime(0, 0).addMSecs(static_cast<int>(recordTime())).toString("hh:mm:ss");
299}
300
302{
303 return QGC::bigSizeMBToString(static_cast<quint64>(_storageFree));
304}
305
307{
308 if(_batteryRemaining >= 0) {
309 return QGC::numberToString(static_cast<quint64>(_batteryRemaining)) + " %";
310 }
311 return "";
312}
313
315{
316 if (_resetting) {
317 return;
318 }
319 if (!hasModes()) {
320 qCWarning(VehicleCameraControlLog) << "Camera does not support modes";
321 return;
322 }
323
324 qCDebug(VehicleCameraControlLog) << "Camera set to video mode";
326}
327
329{
330 if (_resetting) {
331 return;
332 }
333 if (!hasModes()) {
334 qCWarning(VehicleCameraControlLog) << "Camera does not support modes";
335 return;
336 }
337
338 qCDebug(VehicleCameraControlLog) << "Camera set to photo mode";
340}
341
343{
344 if (_resetting) {
345 return;
346 }
347 if (!hasModes()) {
348 qCWarning(VehicleCameraControlLog) << "Camera does not support modes";
349 return;
350 }
352 qCWarning(VehicleCameraControlLog) << "Invalid camera mode" << cameraMode;
353 return;
354 }
355 if (_cameraMode == cameraMode) {
356 return;
357 }
358
359 qCDebug(VehicleCameraControlLog) << "Camera mode set to" << cameraModeToStr(cameraMode);
360
361 //-- Does it have a mode parameter?
362 Fact* pMode = mode();
363 if(pMode) {
364 pMode->setRawValue(cameraMode);
366 } else {
367 //-- Use MAVLink Command
369 _compID, // Target component
370 MAV_CMD_SET_CAMERA_MODE, // Command id
371 true, // ShowError
372 0, // Reserved (Set to 0)
373 cameraMode); // Camera mode (0: photo, 1: video)
375 }
376}
377
379{
380 if(!_resetting) {
382 QSettings settings;
383 settings.setValue(kPhotoMode, static_cast<int>(mode));
385 }
386}
387
389{
390 _photoLapse = interval;
391 QSettings settings;
392 settings.setValue(kPhotoLapse, interval);
393 emit photoLapseChanged();
394}
395
397{
398 _photoLapseCount = count;
399 QSettings settings;
400 settings.setValue(kPhotoLapseCount, count);
402}
403
405{
406 if(_cameraMode != mode) {
408 emit cameraModeChanged();
409 //-- Update stream status
410 _streamStatusTimer.start(1000);
411 }
412}
413
424
426{
427 if(_resetting) {
428 return false;
429 }
430
432 return stopVideoRecording();
433 } else {
434 return startVideoRecording();
435 }
436
437 return false;
438}
439
441{
442 if (_resetting) {
443 return false;
444 }
446 qCWarning(VehicleCameraControlLog) << "Take photo denied - photo capture is disabled";
447 return false;
448 }
450 qCWarning(VehicleCameraControlLog) << "Take photo denied - already capturing";
451 return false;
452 }
453
454 qCDebug(VehicleCameraControlLog) << "takePhoto()";
455
456 const bool canUseMavlinkImageCapture =
457 (_mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_CAPTURE_IMAGE) &&
459
460 if (canUseMavlinkImageCapture) {
461 const bool timelapse = _photoCaptureMode == PHOTO_CAPTURE_TIMELAPSE;
463 _compID,
464 MAV_CMD_IMAGE_START_CAPTURE,
465 true, // ShowError
466 0, // All cameras
467 static_cast<float>(timelapse ? _photoLapse : 0), // Duration between two consecutive pictures (in seconds--ignored if single image)
468 timelapse ? _photoLapseCount : 1); // Number of images to capture total - 0 for unlimited capture
469 // Interval state must be visible immediately so the shutter can stop the sequence before the camera reports status
472 return true;
473 } else {
477 QTimer::singleShot(500, this, [this]() {
479 });
480 return true;
481 } else {
482 QGC::showAppMessage(tr("Timelapse photo capture is not supported on cameras without still capture capability"));
483 }
484 }
485
486 return false;
487}
488
490{
491 if (_resetting) {
492 return false;
493 }
495 qCWarning(VehicleCameraControlLog) << "Stop taking photos requested - not currently capturing multiple photos";
496 return false;
497 }
498
499 qCDebug(VehicleCameraControlLog) << "Camera stop taking photos";
500
501 // Interval capture is only supported directly by cameras
503 _compID, // Target component
504 MAV_CMD_IMAGE_STOP_CAPTURE,
505 true, // ShowError
506 0); // All cameras
509
510 return true;
511}
512
514{
515 if (_resetting) {
516 return false;
517 }
519 qCWarning(VehicleCameraControlLog) << "Start video denied - already recording";
520 return false;
521 }
523 qCWarning(VehicleCameraControlLog) << "Start video denied - video capture is disabled";
524 return false;
525 }
526
527 bool useMavlinkCommand = _mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_CAPTURE_VIDEO;
528
529 qCDebug(VehicleCameraControlLog) << "Start video recording:" << (useMavlinkCommand ? "MAVLink command" : "VideoManager");
530
531 if (useMavlinkCommand) {
533 _compID, // Target component
534 MAV_CMD_VIDEO_START_CAPTURE,
535 true, // Show error on failure
536 0, // All streams
537 0, // CAMERA_CAPTURE_STATUS streaming frequency
538 0); // All cameras
539 } else {
541 }
542
543 return true;
544}
545
547{
548 if (_resetting) {
549 return false;
550 }
552 qCWarning(VehicleCameraControlLog) << "Stop video recording requested - already idle";
553 return true;
554 }
555
556 bool useMavlinkCommand = _mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_CAPTURE_VIDEO;
557
558 qCDebug(VehicleCameraControlLog) << "Camera stop video recording" << (useMavlinkCommand ? "MAVLink command" : "VideoManager");
559
560 if (useMavlinkCommand) {
562 _compID, // Target component
563 MAV_CMD_VIDEO_STOP_CAPTURE,
564 true, // Show error on failure
565 0, // All streams
566 0); // All cameras
567 } else {
569 }
570
571 return true;
572}
573
575{
576 QSettings settings;
577 settings.setValue(kThermalMode, static_cast<uint32_t>(mode));
579 emit thermalModeChanged();
580}
581
583{
584 if(val < 0.0) val = 0.0;
585 if(val > 100.0) val = 100.0;
586 if(fabs(_thermalOpacity - val) > 0.1) {
587 _thermalOpacity = val;
588 QSettings settings;
589 settings.setValue(kThermalOpacity, val);
591 }
592}
593
595{
596 qCDebug(VehicleCameraControlLog) << "Camera set zoom level to" << level;
597 if(hasZoom()) {
598 //-- Limit
599 level = std::min(std::max(level, 0.0), 100.0);
600 if(_vehicle) {
602 _compID, // Target component
603 MAV_CMD_SET_CAMERA_ZOOM, // Command id
604 false, // ShowError
605 ZOOM_TYPE_RANGE, // Zoom type
606 static_cast<float>(level)); // Level
607 }
608 }
609}
610
612{
613 qCDebug(VehicleCameraControlLog) << "Camera set focus level to" << level;
614 if(hasFocus()) {
615 //-- Limit
616 level = std::min(std::max(level, 0.0), 100.0);
617 if(_vehicle) {
619 _compID, // Target component
620 MAV_CMD_SET_CAMERA_FOCUS, // Command id
621 false, // ShowError
622 FOCUS_TYPE_RANGE, // Focus type
623 static_cast<float>(level)); // Level
624 }
625 }
626}
627
629{
630 if(!_resetting) {
631 qCDebug(VehicleCameraControlLog) << "resetSettings()";
632 _resetting = true;
634 _compID, // Target component
635 MAV_CMD_RESET_CAMERA_SETTINGS, // Command id
636 true, // ShowError
637 1); // Do Reset
638 }
639}
640
642{
643 if(!_resetting) {
644 qCDebug(VehicleCameraControlLog) << "formatCard()";
645 if(_vehicle) {
647 _compID, // Target component
648 MAV_CMD_STORAGE_FORMAT, // Command id
649 true, // ShowError
650 id, // Storage ID (1 for first, 2 for second, etc.)
651 1); // Do Format
652 }
653 }
654}
655
657{
658 qCDebug(VehicleCameraControlLog) << "Camera step zoom" << direction;
659 if(_vehicle && hasZoom()) {
661 _compID, // Target component
662 MAV_CMD_SET_CAMERA_ZOOM, // Command id
663 false, // ShowError
664 ZOOM_TYPE_STEP, // Zoom type
665 direction); // Direction (-1 wide, 1 tele)
666 }
667}
668
670{
671 qCDebug(VehicleCameraControlLog) << "Camera start zoom" << direction;
672 if(_vehicle && hasZoom()) {
674 _compID, // Target component
675 MAV_CMD_SET_CAMERA_ZOOM, // Command id
676 false, // ShowError
677 ZOOM_TYPE_CONTINUOUS, // Zoom type
678 direction); // Direction (-1 wide, 1 tele)
679 }
680}
681
683{
684 qCDebug(VehicleCameraControlLog) << "Camera stop zoom";
685 if(_vehicle && hasZoom()) {
687 _compID, // Target component
688 MAV_CMD_SET_CAMERA_ZOOM, // Command id
689 false, // ShowError
690 ZOOM_TYPE_CONTINUOUS, // Zoom type
691 0); // Direction (-1 wide, 1 tele)
692 }
693}
694
696{
697 qCDebug(VehicleCameraControlLog) << "Camera step focus" << direction;
698 if(_vehicle && hasFocus()) {
700 _compID, // Target component
701 MAV_CMD_SET_CAMERA_FOCUS, // Command id
702 false, // ShowError
703 FOCUS_TYPE_STEP, // Focus type
704 direction); // Direction (-1 in, 1 out)
705 }
706}
707
709{
710 qCDebug(VehicleCameraControlLog) << "Camera start focus" << direction;
711 if(_vehicle && hasFocus()) {
713 _compID, // Target component
714 MAV_CMD_SET_CAMERA_FOCUS, // Command id
715 false, // ShowError
716 FOCUS_TYPE_CONTINUOUS, // Focus type
717 direction); // Direction (-1 in, 1 out)
718 }
719}
720
722{
723 qCDebug(VehicleCameraControlLog) << "Camera stop focus";
724 if(_vehicle && hasFocus()) {
726 _compID, // Target component
727 MAV_CMD_SET_CAMERA_FOCUS, // Command id
728 false, // ShowError
729 FOCUS_TYPE_CONTINUOUS, // Focus type
730 0); // Direction (-1 in, 1 out)
731 }
732}
733
735{
736 qCDebug(VehicleCameraControlLog) << "Camera request capture status - retries:" << _cameraCaptureStatusRetries;
737
738 if(_cameraCaptureStatusRetries++ % 2 == 0) {
739 qCDebug(VehicleCameraControlLog) << " Sending REQUEST_MESSAGE:MAVLINK_MSG_ID_CAMERA_CAPTURE_STATUS";
741 _compID, // target component
742 MAV_CMD_REQUEST_MESSAGE, // command id
743 false, // showError
744 MAVLINK_MSG_ID_CAMERA_CAPTURE_STATUS); // msgid
745 } else {
746 qCDebug(VehicleCameraControlLog) << " Sending MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS (legacy)";
748 _compID, // target component
749 MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS, // command id
750 false, // showError
751 1); // Do Request
752 }
753}
754
756{
757 _updateActiveList();
758 _updateRanges(pFact);
759}
760
761void VehicleCameraControl::_mavCommandResult(int vehicleId, int component, int command, int result, int failureCode)
762{
763 Q_UNUSED(failureCode);
764
765 //-- Is this ours?
766 if (_vehicle->id() != vehicleId || compID() != component) {
767 return;
768 }
769 if (result == MAV_RESULT_IN_PROGRESS) {
770 //-- Do Nothing
771 qCDebug(VehicleCameraControlLog) << "In progress response for" << command;
772 } else if(result == MAV_RESULT_ACCEPTED) {
773 switch(command) {
774 case MAV_CMD_RESET_CAMERA_SETTINGS:
775 _resetting = false;
776 if(isBasic()) {
778 } else {
779 QTimer::singleShot(500, this, &VehicleCameraControl::_requestAllParameters);
780 QTimer::singleShot(2500, this, &VehicleCameraControl::_requestCameraSettings);
781 }
782 break;
783 case MAV_CMD_VIDEO_START_CAPTURE:
785 _captureStatusTimer.start(1000);
786 break;
787 case MAV_CMD_VIDEO_STOP_CAPTURE:
789 _captureStatusTimer.start(1000);
790 break;
791 case MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS:
793 break;
794 case MAV_CMD_REQUEST_STORAGE_INFORMATION:
796 break;
797 case MAV_CMD_IMAGE_START_CAPTURE:
798 _captureStatusTimer.start(1000);
799 break;
800 case MAV_CMD_SET_CAMERA_ZOOM:
801 case MAV_CMD_SET_CAMERA_FOCUS:
803 break;
804 }
805 } else {
806 QString commandStr = MissionCommandTree::instance()->rawName(static_cast<MAV_CMD>(command));
807 if ((result == MAV_RESULT_TEMPORARILY_REJECTED) || (result == MAV_RESULT_FAILED)) {
808 if (result == MAV_RESULT_TEMPORARILY_REJECTED) {
809 qCDebug(VehicleCameraControlLog) << "Command temporarily rejected (MAV_RESULT_TEMPORARILY_REJECTED) for" << commandStr;
810 } else {
811 qCDebug(VehicleCameraControlLog) << "Command failed (MAV_RESULT_FAILED) for" << commandStr;
812 }
813 switch(command) {
814 case MAV_CMD_RESET_CAMERA_SETTINGS:
815 _resetting = false;
816 qCDebug(VehicleCameraControlLog) << "Failed to reset camera settings";
817 break;
818 case MAV_CMD_IMAGE_START_CAPTURE:
819 case MAV_CMD_IMAGE_STOP_CAPTURE:
820 if(++_captureInfoRetries <= 5) {
821 _captureStatusTimer.start(1000);
822 } else {
823 qCDebug(VehicleCameraControlLog) << "Giving up start/stop image capture";
825 }
826 break;
827 case MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS:
828 if(++_cameraCaptureStatusRetries <= 5) {
829 _captureStatusTimer.start(1000);
830 } else {
831 qCDebug(VehicleCameraControlLog) << "Giving up requesting capture status";
832 }
833 break;
834 case MAV_CMD_REQUEST_STORAGE_INFORMATION:
835 if(++_storageInfoRetries <= 5) {
836 QTimer::singleShot(1000, this, &VehicleCameraControl::_requestStorageInfo);
837 } else {
838 qCDebug(VehicleCameraControlLog) << "Giving up requesting storage status";
839 }
840 break;
841 }
842 } else {
843 qCDebug(VehicleCameraControlLog) << "Bad response for" << commandStr << QGCMAVLink::mavResultToString(result);
844 }
845 }
846}
847
849{
850 if(_videoCaptureStatusValue != captureStatus) {
851 _videoCaptureStatusValue = captureStatus;
853 if(captureStatus == VIDEO_CAPTURE_STATUS_RUNNING) {
854 _recordTime = 0;
855 _recTime = QTime::currentTime();
857 } else {
859 _recordTime = 0;
860 emit recordTimeChanged();
861 }
862 }
863}
864
866{
867 _recordTime = static_cast<uint32_t>(_recTime.msecsTo(QTime::currentTime()));
868 emit recordTimeChanged();
869}
870
872{
873 // Only track time here when not using MAVLink video capture (to avoid double-tracking)
875 return;
876 }
877
878 if (recording) {
879 _recordTime = 0;
880 _recTime = QTime::currentTime();
882 } else {
884 _recordTime = 0;
885 emit recordTimeChanged();
886 }
887}
888
890{
891 if(_photoCaptureStatusValue != captureStatus) {
892 qCDebug(VehicleCameraControlLog) << "Set Photo Status:" << captureStatus;
893 _photoCaptureStatusValue = captureStatus;
895 }
896}
897
898bool VehicleCameraControl::_loadCameraDefinitionFile(QByteArray& bytes)
899{
900 QByteArray originalData(bytes);
901 //-- Handle localization
902 if(!_handleLocalization(bytes)) {
903 return false;
904 }
905
906 QDomDocument doc;
907 const QDomDocument::ParseResult result = doc.setContent(bytes, QDomDocument::ParseOption::Default);
908 if (!result) {
909 qCCritical(VehicleCameraControlLog) << "Unable to parse camera definition file on line:" << result.errorLine;
910 qCCritical(VehicleCameraControlLog) << result.errorMessage;
911 return false;
912 }
913 //-- Load camera constants
914 QDomNodeList defElements = doc.elementsByTagName(kDefnition);
915 if(!defElements.size() || !_loadConstants(defElements)) {
916 qCWarning(VehicleCameraControlLog) << "Unable to load camera constants from camera definition";
917 return false;
918 }
919 //-- Load camera parameters
920 QDomNodeList paramElements = doc.elementsByTagName(kParameters);
921 if(!paramElements.size()) {
922 qCDebug(VehicleCameraControlLog) << "No parameters to load from camera";
923 return false;
924 }
925 if(!_loadSettings(paramElements)) {
926 qCWarning(VehicleCameraControlLog) << "Unable to load camera parameters from camera definition";
927 return false;
928 }
929 //-- If this is new, cache it
930 if(!_cached) {
931 qCDebug(VehicleCameraControlLog) << "Saving camera definition file" << _cacheFile;
932 QFile file(_cacheFile);
933 if (!file.open(QIODevice::WriteOnly)) {
934 qWarning() << QString("Could not save cache file %1. Error: %2").arg(_cacheFile).arg(file.errorString());
935 } else {
936 file.write(originalData);
937 }
938 }
939 return true;
940}
941
942bool VehicleCameraControl::_loadConstants(const QDomNodeList nodeList)
943{
944 QDomNode node = nodeList.item(0);
945 if(!read_attribute(node, kVersion, _version)) {
946 return false;
947 }
948 if(!read_value(node, kModel, _modelName)) {
949 return false;
950 }
951 if(!read_value(node, kVendor, _vendor)) {
952 return false;
953 }
954 return true;
955}
956
957bool VehicleCameraControl::_loadSettings(const QDomNodeList nodeList)
958{
959 QDomNode node = nodeList.item(0);
960 QDomElement elem = node.toElement();
961 QDomNodeList parameters = elem.elementsByTagName(kParameter);
962 //-- Pre-process settings (maintain order and skip non-controls)
963 for(int i = 0; i < parameters.size(); i++) {
964 QDomNode parameterNode = parameters.item(i);
965 QString name;
966 if(read_attribute(parameterNode, kName, name)) {
967 bool control = true;
968 read_attribute(parameterNode, kControl, control);
969 if(control) {
970 _settings << name;
971 }
972 } else {
973 qCritical() << "Parameter entry missing parameter name";
974 return false;
975 }
976 }
977 //-- Load parameters
978 for(int i = 0; i < parameters.size(); i++) {
979 QDomNode parameterNode = parameters.item(i);
980 QString factName;
981 read_attribute(parameterNode, kName, factName);
982 QString type;
983 if(!read_attribute(parameterNode, kType, type)) {
984 qCritical() << QString("Parameter %1 missing parameter type").arg(factName);
985 return false;
986 }
987 //-- Does it have a control?
988 bool control = true;
989 read_attribute(parameterNode, kControl, control);
990 //-- Is it read only?
991 bool readOnly = false;
992 read_attribute(parameterNode, kReadOnly, readOnly);
993 //-- Is it write only?
994 bool writeOnly = false;
995 read_attribute(parameterNode, kWriteOnly, writeOnly);
996 //-- It can't be both
997 if(readOnly && writeOnly) {
998 qCritical() << QString("Parameter %1 cannot be both read only and write only").arg(factName);
999 }
1000 //-- Param type
1001 bool unknownType;
1002 FactMetaData::ValueType_t factType = FactMetaData::stringToType(type, unknownType);
1003 if (unknownType) {
1004 qCritical() << QString("Unknown type for parameter %1").arg(factName);
1005 return false;
1006 }
1007 //-- By definition, custom types do not have control
1008 if(factType == FactMetaData::valueTypeCustom) {
1009 control = false;
1010 }
1011 //-- Description
1012 QString description;
1013 if(!read_value(parameterNode, kDescription, description)) {
1014 qCritical() << QString("Parameter %1 missing parameter description").arg(factName);
1015 return false;
1016 }
1017 //-- Check for updates
1018 QStringList updates = _loadUpdates(parameterNode);
1019 if(updates.size()) {
1020 qCDebug(VehicleCameraControlVerboseLog) << "Parameter" << factName << "requires updates for:" << updates;
1021 _requestUpdates[factName] = updates;
1022 }
1023 //-- Build metadata
1024 FactMetaData* metaData = new FactMetaData(factType, factName, this);
1025 QQmlEngine::setObjectOwnership(metaData, QQmlEngine::CppOwnership);
1026 metaData->setShortDescription(description);
1027 metaData->setLongDescription(description);
1028 metaData->setHasControl(control);
1029 metaData->setReadOnly(readOnly);
1030 metaData->setWriteOnly(writeOnly);
1031 //-- Options (enums)
1032 QDomElement optionElem = parameterNode.toElement();
1033 QDomNodeList optionsRoot = optionElem.elementsByTagName(kOptions);
1034 if(optionsRoot.size()) {
1035 //-- Iterate options
1036 QDomNode optionsNode = optionsRoot.item(0);
1037 QDomElement optionsElem = optionsNode.toElement();
1038 QDomNodeList options = optionsElem.elementsByTagName(kOption);
1039 for(int optionIndex = 0; optionIndex < options.size(); optionIndex++) {
1040 QDomNode option = options.item(optionIndex);
1041 QString optName;
1042 QString optValue;
1043 QVariant optVariant;
1044 if(!_loadNameValue(option, factName, metaData, optName, optValue, optVariant)) {
1045 delete metaData;
1046 return false;
1047 }
1048 metaData->addEnumInfo(optName, optVariant);
1049 _originalOptNames[factName] << optName;
1050 _originalOptValues[factName] << optVariant;
1051 //-- Check for exclusions
1052 QStringList exclusions = _loadExclusions(option);
1053 if(exclusions.size()) {
1054 qCDebug(VehicleCameraControlVerboseLog) << "New exclusions:" << factName << optValue << exclusions;
1055 QGCCameraOptionExclusion* pExc = new QGCCameraOptionExclusion(this, factName, optValue, exclusions);
1056 QQmlEngine::setObjectOwnership(pExc, QQmlEngine::CppOwnership);
1057 _valueExclusions.append(pExc);
1058 }
1059 //-- Check for range rules
1060 if(!_loadRanges(option, factName, optValue)) {
1061 delete metaData;
1062 return false;
1063 }
1064 }
1065 }
1066 QString defaultValue;
1067 if(read_attribute(parameterNode, kDefault, defaultValue)) {
1068 QVariant defaultVariant;
1069 QString errorString;
1070 if (metaData->convertAndValidateRaw(defaultValue, false, defaultVariant, errorString)) {
1071 metaData->setRawDefaultValue(defaultVariant);
1072 } else {
1073 qWarning() << "Invalid default value for" << factName
1074 << " type:" << metaData->type()
1075 << " value:" << defaultValue
1076 << " error:" << errorString;
1077 }
1078 }
1079 //-- Set metadata and Fact
1080 if (_nameToFactMetaDataMap.contains(factName)) {
1081 qWarning() << QStringLiteral("Duplicate fact name:") << factName;
1082 delete metaData;
1083 } else {
1084 {
1085 //-- Check for Min Value
1086 QString attr;
1087 if(read_attribute(parameterNode, kMin, attr)) {
1088 QVariant typedValue;
1089 QString errorString;
1090 if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) {
1091 metaData->setRawMin(typedValue);
1092 } else {
1093 qWarning() << "Invalid min value for" << factName
1094 << " type:" << metaData->type()
1095 << " value:" << attr
1096 << " error:" << errorString;
1097 }
1098 }
1099 }
1100 {
1101 //-- Check for Max Value
1102 QString attr;
1103 if(read_attribute(parameterNode, kMax, attr)) {
1104 QVariant typedValue;
1105 QString errorString;
1106 if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) {
1107 metaData->setRawMax(typedValue);
1108 } else {
1109 qWarning() << "Invalid max value for" << factName
1110 << " type:" << metaData->type()
1111 << " value:" << attr
1112 << " error:" << errorString;
1113 }
1114 }
1115 }
1116 {
1117 //-- Check for Step Value
1118 QString attr;
1119 if(read_attribute(parameterNode, kStep, attr)) {
1120 QVariant typedValue;
1121 QString errorString;
1122 if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) {
1123 metaData->setRawIncrement(typedValue.toDouble());
1124 } else {
1125 qWarning() << "Invalid step value for" << factName
1126 << " type:" << metaData->type()
1127 << " value:" << attr
1128 << " error:" << errorString;
1129 }
1130 }
1131 }
1132 {
1133 //-- Check for Decimal Places
1134 QString attr;
1135 if(read_attribute(parameterNode, kDecimalPlaces, attr)) {
1136 QVariant typedValue;
1137 QString errorString;
1138 if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) {
1139 metaData->setDecimalPlaces(typedValue.toInt());
1140 } else {
1141 qWarning() << "Invalid decimal places value for" << factName
1142 << " type:" << metaData->type()
1143 << " value:" << attr
1144 << " error:" << errorString;
1145 }
1146 }
1147 }
1148 {
1149 //-- Check for Units
1150 QString attr;
1151 if(read_attribute(parameterNode, kUnit, attr)) {
1152 metaData->setRawUnits(attr);
1153 }
1154 }
1155 qCDebug(VehicleCameraControlLog) << "New parameter:" << factName << (readOnly ? "ReadOnly" : "Writable") << (writeOnly ? "WriteOnly" : "Readable");
1156 _nameToFactMetaDataMap[factName] = metaData;
1157 Fact* pFact = new Fact(_compID, factName, factType, this);
1158 QQmlEngine::setObjectOwnership(pFact, QQmlEngine::CppOwnership);
1159 pFact->setMetaData(metaData);
1160 pFact->containerSetRawValue(metaData->rawDefaultValue());
1161 QGCCameraParamIO* pIO = new QGCCameraParamIO(this, pFact, _vehicle);
1162 QQmlEngine::setObjectOwnership(pIO, QQmlEngine::CppOwnership);
1163 _paramIO[factName] = pIO;
1164 _addFact(pFact, factName);
1165 }
1166 }
1167 if(_nameToFactMetaDataMap.size() > 0) {
1168 _addFactGroup(this, "camera");
1169 _processRanges();
1171 emit activeSettingsChanged();
1172 return true;
1173 }
1174 return false;
1175}
1176
1177bool VehicleCameraControl::_handleLocalization(QByteArray& bytes)
1178{
1179 QDomDocument doc;
1180 const QDomDocument::ParseResult result = doc.setContent(bytes, QDomDocument::ParseOption::Default);
1181 if (!result) {
1182 qCritical() << "Unable to parse camera definition file on line:" << result.errorLine;
1183 qCritical() << result.errorMessage;
1184 return false;
1185 }
1186 //-- Find out where we are
1187 QLocale locale = QLocale::system();
1188#if defined (Q_OS_MACOS)
1189 locale = QLocale(locale.name());
1190#endif
1191 QString localeName = locale.name().toLower().replace("-", "_");
1192 qCDebug(VehicleCameraControlLog) << "Current locale:" << localeName;
1193 if(localeName == "en_us") {
1194 // Nothing to do
1195 return true;
1196 }
1197 QDomNodeList locRoot = doc.elementsByTagName(kLocalization);
1198 if(!locRoot.size()) {
1199 // Nothing to do
1200 return true;
1201 }
1202 //-- Iterate locales
1203 QDomNode node = locRoot.item(0);
1204 QDomElement elem = node.toElement();
1205 QDomNodeList locales = elem.elementsByTagName(kLocale);
1206 for(int i = 0; i < locales.size(); i++) {
1207 QDomNode localeNode = locales.item(i);
1208 QString name;
1209 if(!read_attribute(localeNode, kName, name)) {
1210 qWarning() << "Localization entry is missing its name attribute";
1211 continue;
1212 }
1213 // If we found a direct match, deal with it now
1214 if(localeName == name.toLower().replace("-", "_")) {
1215 return _replaceLocaleStrings(localeNode, bytes);
1216 }
1217 }
1218 //-- No direct match. Pick first matching language (if any)
1219 localeName = localeName.left(3);
1220 for(int i = 0; i < locales.size(); i++) {
1221 QDomNode localeNode = locales.item(i);
1222 QString name;
1223 read_attribute(localeNode, kName, name);
1224 if(name.toLower().startsWith(localeName)) {
1225 return _replaceLocaleStrings(localeNode, bytes);
1226 }
1227 }
1228 //-- Could not find a language to use
1229 qWarning() << "No match for" << QLocale::system().name() << "in camera definition file";
1230 //-- Just use default, en_US
1231 return true;
1232}
1233
1234bool VehicleCameraControl::_replaceLocaleStrings(const QDomNode node, QByteArray& bytes)
1235{
1236 QDomElement stringElem = node.toElement();
1237 QDomNodeList strings = stringElem.elementsByTagName(kStrings);
1238 for(int i = 0; i < strings.size(); i++) {
1239 QDomNode stringNode = strings.item(i);
1240 QString original;
1241 QString translated;
1242 if(read_attribute(stringNode, kOriginal, original)) {
1243 if(read_attribute(stringNode, kTranslated, translated)) {
1244 QString o; o = "\"" + original + "\"";
1245 QString t; t = "\"" + translated + "\"";
1246 bytes.replace(o.toUtf8(), t.toUtf8());
1247 o = ">" + original + "<";
1248 t = ">" + translated + "<";
1249 bytes.replace(o.toUtf8(), t.toUtf8());
1250 }
1251 }
1252 }
1253 return true;
1254}
1255
1257{
1258 //-- Reset receive list
1259 for(const QString& paramName: _paramIO.keys()) {
1260 if(_paramIO[paramName]) {
1261 _paramIO[paramName]->setParamRequest();
1262 } else {
1263 qCritical() << "QGCParamIO is NULL" << paramName;
1264 }
1265 }
1267 if (sharedLink) {
1269 mavlink_msg_param_ext_request_list_pack_chan(
1270 static_cast<uint8_t>(MAVLinkProtocol::instance()->getSystemId()),
1271 static_cast<uint8_t>(MAVLinkProtocol::getComponentId()),
1272 sharedLink->mavlinkChannel(),
1273 &msg,
1274 static_cast<uint8_t>(_vehicle->id()),
1275 static_cast<uint8_t>(compID()));
1276 _vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
1277 }
1278 qCDebug(VehicleCameraControlVerboseLog) << "Request all parameters";
1279}
1280
1281QString VehicleCameraControl::_getParamName(const char* param_id)
1282{
1283 // This will null terminate the name string
1284 char parameterNameWithNull[MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN + 1] = {};
1285 (void) strncpy(parameterNameWithNull, param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN);
1286 const QString parameterName(parameterNameWithNull);
1287 return parameterName;
1288}
1289
1291{
1292 QString paramName = _getParamName(paramExtAck.param_id);
1293 qCDebug(VehicleCameraControlLog).noquote() << "Received PARAM_EXT_ACK:"
1294 << "\n\tParam name:" << paramName
1295 << "\n\tResult:" << static_cast<int>(paramExtAck.param_result)
1296 << "\n\tType:" << static_cast<int>(paramExtAck.param_type);
1297
1298 if(!_paramIO.contains(paramName)) {
1299 qCWarning(VehicleCameraControlLog) << "Received PARAM_EXT_ACK for unknown param:" << paramName;
1300 return;
1301 }
1302 if(_paramIO[paramName]) {
1303 _paramIO[paramName]->handleParamAck(paramExtAck);
1304 } else {
1305 qCritical() << "QGCParamIO is NULL" << paramName;
1306 }
1307}
1308
1310{
1311 QString paramName = _getParamName(paramExtValue.param_id);
1312 qCDebug(VehicleCameraControlLog).noquote() << "Received PARAM_EXT_VALUE:"
1313 << "\n\tParam name:" << paramName
1314 << "\n\tType:" << static_cast<int>(paramExtValue.param_type)
1315 << "\n\tIndex:" << static_cast<int>(paramExtValue.param_index)
1316 << "\n\tCount:" << static_cast<int>(paramExtValue.param_count);
1317
1318 if(!_paramIO.contains(paramName)) {
1319 qCWarning(VehicleCameraControlLog) << "Received PARAM_EXT_VALUE for unknown param:" << paramName;
1320 return;
1321 }
1322 if(_paramIO[paramName]) {
1323 _paramIO[paramName]->handleParamValue(paramExtValue);
1324 } else {
1325 qCritical() << "QGCParamIO is NULL" << paramName;
1326 }
1327}
1328
1329void VehicleCameraControl::_updateActiveList()
1330{
1331 //-- Clear out excluded parameters based on exclusion rules
1332 QStringList exclusionList;
1334 Fact* pFact = getFact(param->param);
1335 if(pFact) {
1336 QString option = pFact->rawValueString();
1337 if(param->value == option) {
1338 exclusionList << param->exclusions;
1339 }
1340 }
1341 }
1342 QStringList active;
1343 for(QString key: _settings) {
1344 if(!exclusionList.contains(key)) {
1345 active.append(key);
1346 }
1347 }
1348 if(active != _activeSettings) {
1349 qCDebug(VehicleCameraControlVerboseLog) << "Excluding" << exclusionList;
1350 _activeSettings = active;
1351 emit activeSettingsChanged();
1352 //-- Force validity of "Facts" based on active set
1353 if(_paramComplete) {
1354 emit parametersReady();
1355 }
1356 }
1357}
1358
1359bool VehicleCameraControl::_processConditionTest(const QString conditionTest)
1360{
1361 enum {
1362 TEST_NONE,
1363 TEST_EQUAL,
1364 TEST_NOT_EQUAL,
1365 TEST_GREATER,
1366 TEST_SMALLER
1367 };
1368 qCDebug(VehicleCameraControlVerboseLog) << "_processConditionTest(" << conditionTest << ")";
1369 int op = TEST_NONE;
1370 QStringList test;
1371
1372 auto split = [&conditionTest](const QString& sep ) {
1373 return conditionTest.split(sep, Qt::SkipEmptyParts);
1374 };
1375
1376 if(conditionTest.contains("!=")) {
1377 test = split("!=");
1378 op = TEST_NOT_EQUAL;
1379 } else if(conditionTest.contains("=")) {
1380 test = split("=");
1381 op = TEST_EQUAL;
1382 } else if(conditionTest.contains(">")) {
1383 test = split(">");
1384 op = TEST_GREATER;
1385 } else if(conditionTest.contains("<")) {
1386 test = split("<");
1387 op = TEST_SMALLER;
1388 }
1389 if(test.size() == 2) {
1390 Fact* pFact = getFact(test[0]);
1391 if(pFact) {
1392 switch(op) {
1393 case TEST_EQUAL:
1394 return pFact->rawValueString() == test[1];
1395 case TEST_NOT_EQUAL:
1396 return pFact->rawValueString() != test[1];
1397 case TEST_GREATER:
1398 return pFact->rawValueString() > test[1];
1399 case TEST_SMALLER:
1400 return pFact->rawValueString() < test[1];
1401 case TEST_NONE:
1402 break;
1403 }
1404 } else {
1405 qWarning() << "Invalid condition parameter:" << test[0] << "in" << conditionTest;
1406 return false;
1407 }
1408 }
1409 qWarning() << "Invalid condition" << conditionTest;
1410 return false;
1411}
1412
1413bool VehicleCameraControl::_processCondition(const QString condition)
1414{
1415 qCDebug(VehicleCameraControlVerboseLog) << "_processCondition(" << condition << ")";
1416 bool result = true;
1417 bool andOp = true;
1418 if(!condition.isEmpty()) {
1419 QStringList scond = condition.split(" ", Qt::SkipEmptyParts);
1420 while(scond.size()) {
1421 QString test = scond.first();
1422 scond.removeFirst();
1423 if(andOp) {
1424 result = result && _processConditionTest(test);
1425 } else {
1426 result = result || _processConditionTest(test);
1427 }
1428 if(!scond.size()) {
1429 return result;
1430 }
1431 andOp = scond.first().toUpper() == "AND";
1432 scond.removeFirst();
1433 }
1434 }
1435 return result;
1436}
1437
1438void VehicleCameraControl::_updateRanges(Fact* pFact)
1439{
1440 QMap<Fact*, QGCCameraOptionRange*> rangesSet;
1441 QMap<Fact*, QString> rangesReset;
1442 QStringList changedList;
1443 QStringList resetList;
1444 QStringList updates;
1445 //-- Iterate range sets looking for limited ranges
1446 for(QGCCameraOptionRange* pRange: _optionRanges) {
1447 //-- If this fact or one of its conditions is part of this range set
1448 if(!changedList.contains(pRange->targetParam) && (pRange->param == pFact->name() || pRange->condition.contains(pFact->name()))) {
1449 Fact* pRFact = getFact(pRange->param); //-- This parameter
1450 Fact* pTFact = getFact(pRange->targetParam); //-- The target parameter (the one its range is to change)
1451 if(pRFact && pTFact) {
1452 //qCDebug(VehicleCameraControlVerboseLog) << "Check new set of options for" << pTFact->name();
1453 QString option = pRFact->rawValueString(); //-- This parameter value
1454 //-- If this value (and condition) triggers a change in the target range
1455 //qCDebug(VehicleCameraControlVerboseLog) << "Range value:" << pRange->value << "Current value:" << option << "Condition:" << pRange->condition;
1456 if(pRange->value == option && _processCondition(pRange->condition)) {
1457 if(pTFact->enumStrings() != pRange->optNames) {
1458 //-- Set limited range set
1459 rangesSet[pTFact] = pRange;
1460 }
1461 changedList << pRange->targetParam;
1462 }
1463 }
1464 }
1465 }
1466 //-- Iterate range sets again looking for resets
1467 for(QGCCameraOptionRange* pRange: _optionRanges) {
1468 if(!changedList.contains(pRange->targetParam) && (pRange->param == pFact->name() || pRange->condition.contains(pFact->name()))) {
1469 Fact* pTFact = getFact(pRange->targetParam); //-- The target parameter (the one its range is to change)
1470 if(!resetList.contains(pRange->targetParam)) {
1471 if(pTFact->enumStrings() != _originalOptNames[pRange->targetParam]) {
1472 //-- Restore full option set
1473 rangesReset[pTFact] = pRange->targetParam;
1474 }
1475 resetList << pRange->targetParam;
1476 }
1477 }
1478 }
1479 //-- Update limited range set
1480 for (Fact* f: rangesSet.keys()) {
1481 f->setEnumInfo(rangesSet[f]->optNames, rangesSet[f]->optVariants);
1482 if(!updates.contains(f->name())) {
1483 emit f->enumsChanged();
1484 qCDebug(VehicleCameraControlVerboseLog) << "Limited set of options for:" << f->name() << rangesSet[f]->optNames;;
1485 updates << f->name();
1486 }
1487 }
1488 //-- Restore full range set
1489 for (Fact* f: rangesReset.keys()) {
1490 f->setEnumInfo(_originalOptNames[rangesReset[f]], _originalOptValues[rangesReset[f]]);
1491 if(!updates.contains(f->name())) {
1492 emit f->enumsChanged();
1493 qCDebug(VehicleCameraControlVerboseLog) << "Restore full set of options for:" << f->name() << _originalOptNames[f->name()];
1494 updates << f->name();
1495 }
1496 }
1497 //-- Parameter update requests
1498 if(_requestUpdates.contains(pFact->name())) {
1499 for(const QString& param: _requestUpdates[pFact->name()]) {
1500 if(!_updatesToRequest.contains(param)) {
1501 _updatesToRequest << param;
1502 }
1503 }
1504 }
1505 if(_updatesToRequest.size()) {
1506 QTimer::singleShot(500, this, &VehicleCameraControl::_requestParamUpdates);
1507 }
1508}
1509
1511{
1512 for(const QString& param: _updatesToRequest) {
1513 _paramIO[param]->paramRequest();
1514 }
1515 _updatesToRequest.clear();
1516}
1517
1519{
1520 qCDebug(VehicleCameraControlLog) << "_requestCameraSettings() - retries:" << _cameraSettingsRetries << "timer active:" << _cameraSettingsTimer.isActive();
1521 if(_vehicle) {
1522 // Use REQUEST_MESSAGE instead of deprecated REQUEST_CAMERA_SETTINGS
1523 // first time and every other time after that.
1524
1525 if(_cameraSettingsRetries % 2 == 0) {
1526 qCDebug(VehicleCameraControlLog) << " Sending REQUEST_MESSAGE:MAVLINK_MSG_ID_CAMERA_SETTINGS";
1528 _compID, // target component
1529 MAV_CMD_REQUEST_MESSAGE, // command id
1530 false, // showError
1531 MAVLINK_MSG_ID_CAMERA_SETTINGS); // msgid
1532 } else {
1533 qCDebug(VehicleCameraControlLog) << " Sending MAV_CMD_REQUEST_CAMERA_SETTINGS (legacy)";
1535 _compID, // Target component
1536 MAV_CMD_REQUEST_CAMERA_SETTINGS, // command id
1537 false, // showError
1538 1); // Do Request
1539 }
1540 if(_cameraSettingsTimer.isActive()) {
1541 qCDebug(VehicleCameraControlLog) << "_requestCameraSettings() - RESTARTING already active timer";
1542 } else {
1543 qCDebug(VehicleCameraControlLog) << "_requestCameraSettings() - starting timer";
1544 }
1545 _cameraSettingsTimer.start(1000); // Wait up to a second for it
1546 }
1547
1548}
1549
1551{
1552 qCDebug(VehicleCameraControlLog) << "_requestStorageInfo() - retries:" << _storageInfoRetries << "timer active:" << _storageInfoTimer.isActive();
1553 if(_vehicle) {
1554 // Use REQUEST_MESSAGE instead of deprecated REQUEST_STORAGE_INFORMATION
1555 // first time and every other time after that.
1556 if(_storageInfoRetries % 2 == 0) {
1557 qCDebug(VehicleCameraControlLog) << " Sending REQUEST_MESSAGE:MAVLINK_MSG_ID_STORAGE_INFORMATION";
1559 _compID, // target component
1560 MAV_CMD_REQUEST_MESSAGE, // command id
1561 false, // showError
1562 MAVLINK_MSG_ID_STORAGE_INFORMATION, // msgid
1563 0); // storage ID
1564 } else {
1565 qCDebug(VehicleCameraControlLog) << " Sending MAV_CMD_REQUEST_STORAGE_INFORMATION (legacy)";
1567 _compID, // Target component
1568 MAV_CMD_REQUEST_STORAGE_INFORMATION, // command id
1569 false, // showError
1570 0, // Storage ID (0 for all, 1 for first, 2 for second, etc.)
1571 1); // Do Request
1572 }
1573 qCDebug(VehicleCameraControlLog) << "_requestStorageInfo() - starting timer";
1574 _storageInfoTimer.start(1000); // Wait up to a second for it
1575 }
1576}
1577
1579{
1580 qCDebug(VehicleCameraControlLog).noquote() << "Received CAMERA_SETTINGS - stopping timer, resetting retries:"
1581 << "\n\tMode:" << settings.mode_id
1582 << "\n\tZoom level:" << settings.zoomLevel
1583 << "\n\tFocus level:" << settings.focusLevel;
1584
1585 _cameraSettingsTimer.stop();
1587
1588 _setCameraMode(static_cast<CameraMode>(settings.mode_id));
1589 qreal z = static_cast<qreal>(settings.zoomLevel);
1590 qreal f = static_cast<qreal>(settings.focusLevel);
1591 if(std::isfinite(z) && z != _zoomLevel) {
1592 _zoomLevel = z;
1593 emit zoomLevelChanged();
1594 }
1595 if(std::isfinite(f) && f != _focusLevel) {
1596 _focusLevel = f;
1597 emit focusLevelChanged();
1598 }
1599}
1600
1602{
1603 qCDebug(VehicleCameraControlLog) << "Received STORAGE_INFORMATION - stopping timer, resetting retries:"
1604 << "\n\tStorage id:" << storageInformation.storage_id
1605 << "\n\tStorage count:" << storageInformation.storage_count
1606 << "\n\tStatus:"<< storageStatusToStr(storageInformation.status)
1607 << "\n\tTotal capacity:" << storageInformation.total_capacity
1608 << "\n\tUsed capacity:" << storageInformation.used_capacity
1609 << "\n\tAvailable capacity:" << storageInformation.available_capacity;
1610
1611 _storageInfoTimer.stop();
1613
1614 if(storageInformation.status == STORAGE_STATUS_READY) {
1615 uint32_t t = static_cast<uint32_t>(storageInformation.total_capacity);
1616 if(_storageTotal != t) {
1617 _storageTotal = t;
1618 emit storageTotalChanged();
1619 }
1620 uint32_t a = static_cast<uint32_t>(storageInformation.available_capacity);
1621 if(_storageFree != a) {
1622 _storageFree = a;
1623 emit storageFreeChanged();
1624 }
1625 }
1626 if(_storageStatus != static_cast<StorageStatus>(storageInformation.status)) {
1627 _storageStatus = static_cast<StorageStatus>(storageInformation.status);
1628 emit storageStatusChanged();
1629 }
1630}
1631
1633{
1634 qCDebug(VehicleCameraControlLog).noquote() << "Received BATTERY_STATUS:"
1635 << "\n\tBattery remaining (%):" << bs.battery_remaining;
1636
1637 if(bs.battery_remaining >= 0 && _batteryRemaining != static_cast<int>(bs.battery_remaining)) {
1638 _batteryRemaining = static_cast<int>(bs.battery_remaining);
1640 }
1641}
1642
1644{
1645 qCDebug(VehicleCameraControlLog).noquote() << "Received CAMERA_CAPTURE_STATUS - stopping timer, resetting retries:"
1646 << "\n\tImage status:" << captureImageStatusToStr(cameraCaptureStatus.image_status)
1647 << "\n\tVideo status:" << captureVideoStatusToStr(cameraCaptureStatus.video_status)
1648 << "\n\tInterval:" << cameraCaptureStatus.image_interval
1649 << "\n\tRecording time (ms):" << cameraCaptureStatus.recording_time_ms
1650 << "\n\tCapacity:" << cameraCaptureStatus.available_capacity;
1651
1652 _captureStatusTimer.stop();
1654
1655 //-- Disk Free Space
1656 uint32_t a = static_cast<uint32_t>(cameraCaptureStatus.available_capacity);
1657 if(_storageFree != a) {
1658 _storageFree = a;
1659 emit storageFreeChanged();
1660 }
1661 //-- Do we have recording time?
1662 if(cameraCaptureStatus.recording_time_ms) {
1663 // Resync our _recTime timer to the time info received from the camera component
1664 _recordTime = cameraCaptureStatus.recording_time_ms;
1665 _recTime = _recTime.addMSecs(_recTime.msecsTo(QTime::currentTime()) - static_cast<int>(cameraCaptureStatus.recording_time_ms));
1666 emit recordTimeChanged();
1667 }
1668 //-- Video/Image Capture Status
1669 uint8_t vs = cameraCaptureStatus.video_status < static_cast<uint8_t>(VIDEO_CAPTURE_STATUS_LAST) ? cameraCaptureStatus.video_status : static_cast<uint8_t>(VIDEO_CAPTURE_STATUS_UNDEFINED);
1670 uint8_t ps = cameraCaptureStatus.image_status < static_cast<uint8_t>(PHOTO_CAPTURE_LAST) ? cameraCaptureStatus.image_status : static_cast<uint8_t>(PHOTO_CAPTURE_STATUS_UNDEFINED);
1673 //-- Keep asking for it once in a while when recording
1675 _captureStatusTimer.start(5000);
1676 //-- Same while a single image capture is busy
1678 _captureStatusTimer.start(1000);
1679 //-- Interval capture can run for hours; poll at the video cadence
1681 _captureStatusTimer.start(5000);
1682 }
1683}
1684
1686{
1687 qCDebug(VehicleCameraControlLog).noquote() << "Received VIDEO_STREAM_INFORMATION:"
1688 << "\n\tStream ID:" << videoStreamInformation.stream_id
1689 << "\n\tStream count:" << videoStreamInformation.count
1690 << "\n\tType:" << static_cast<int>(videoStreamInformation.type)
1691 << "\n\tFlags:" << Qt::hex << Qt::showbase << videoStreamInformation.flags << Qt::dec << Qt::noshowbase
1692 << "\n\tBitrate (bits/s):" << videoStreamInformation.bitrate
1693 << "\n\tFramerate (fps):" << videoStreamInformation.framerate
1694 << "\n\tResolution:" << videoStreamInformation.resolution_h << "x" << videoStreamInformation.resolution_v
1695 << "\n\tRotation (deg):" << videoStreamInformation.rotation
1696 << "\n\tHFOV (deg):" << videoStreamInformation.hfov
1697 << "\n\tURI:" << videoStreamInformation.uri;
1698
1699 _expectedCount = videoStreamInformation.count;
1700 if(!_findStream(videoStreamInformation.stream_id, false)) {
1701 qCDebug(VehicleCameraControlLog) << "Create stream handler for stream ID:" << videoStreamInformation.stream_id;
1702 QGCVideoStreamInfo* pStream = new QGCVideoStreamInfo(videoStreamInformation, this);
1703 QQmlEngine::setObjectOwnership(pStream, QQmlEngine::CppOwnership);
1704 _streams.append(pStream);
1705 //-- Thermal is handled separately and not listed
1706 if(!pStream->isThermal()) {
1707 _streamLabels.append(pStream->name());
1708 emit streamsChanged();
1709 emit streamLabelsChanged();
1710 } else {
1711 emit thermalStreamChanged();
1712 }
1713 }
1714 //-- Check for missing count
1715 if(_streams.count() < _expectedCount) {
1716 _streamInfoTimer.start(1000);
1717 } else if (_streamInfoTimer.isActive()) {
1718 //-- Done
1719 qCDebug(VehicleCameraControlLog) << "All stream handlers done";
1720 _streamInfoTimer.stop();
1722 emit autoStreamChanged();
1724 }
1725}
1726
1728{
1729 qCDebug(VehicleCameraControlLog) << "Received VIDEO_STREAM_STATUS - stopping timer, resetting retries:"
1730 << "\n\tStream ID:" << videoStreamStatus.stream_id
1731 << "\n\tFlags:" << Qt::hex << Qt::showbase << videoStreamStatus.flags << Qt::dec << Qt::noshowbase
1732 << "\n\tBitrate (bits/s):" << videoStreamStatus.bitrate
1733 << "\n\tFramerate (fps):" << videoStreamStatus.framerate
1734 << "\n\tResolution: " << videoStreamStatus.resolution_h << "x" << videoStreamStatus.resolution_v
1735 << "\n\tRotation (deg):" << videoStreamStatus.rotation
1736 << "\n\tHFOV (deg):" << videoStreamStatus.hfov;
1737
1738 _streamStatusTimer.stop();
1740
1741 QGCVideoStreamInfo* pInfo = _findStream(videoStreamStatus.stream_id);
1742 if(pInfo) {
1743 pInfo->update(videoStreamStatus);
1744 }
1745}
1746
1748{
1749 qCDebug(VehicleCameraControlLog).noquote() << "Received CAMERA_TRACKING_IMAGE_STATUS:"
1750 << "\n\tTracking status:" << static_cast<int>(trackingImageStatus.tracking_status)
1751 << "\n\tTracking mode:" << static_cast<int>(trackingImageStatus.tracking_mode)
1752 << "\n\tPoint:" << trackingImageStatus.point_x << "," << trackingImageStatus.point_y
1753 << "\n\tRectangle:" << trackingImageStatus.rec_top_x << "," << trackingImageStatus.rec_top_y
1754 << " -> " << trackingImageStatus.rec_bottom_x << "," << trackingImageStatus.rec_bottom_y
1755 << "\n\tRadius:" << trackingImageStatus.radius;
1756
1757 _trackingImageStatus = trackingImageStatus;
1758
1759 const bool active = ((_trackingImageStatus.tracking_status & CAMERA_TRACKING_STATUS_FLAGS_ACTIVE) != 0) && trackingEnabled();
1760 const bool isPoint = active && (_trackingImageStatus.tracking_mode == CAMERA_TRACKING_MODE_POINT);
1761
1762 if (!active) {
1763 qCDebug(VehicleCameraControlLog) << "Tracking off";
1764 _trackingImageRect = {};
1767 } else if (isPoint) {
1768 const QPointF point(std::clamp(static_cast<qreal>(_trackingImageStatus.point_x), 0.0, 1.0),
1769 std::clamp(static_cast<qreal>(_trackingImageStatus.point_y), 0.0, 1.0));
1770 qreal radius = static_cast<qreal>(_trackingImageStatus.radius);
1771 if (qIsNaN(radius) || radius <= 0) {
1772 radius = 0.05;
1773 } else {
1774 radius = std::clamp(radius, 0.0, 1.0);
1775 }
1776 qCDebug(VehicleCameraControlLog) << "Tracking Point [" << point << "] radius:" << radius;
1777 _trackingImageRect = {};
1778 if (_trackingImagePoint != point) {
1779 _trackingImagePoint = point;
1781 }
1782 if (!qFuzzyCompare(_trackingImageRadius, radius)) {
1783 _trackingImageRadius = radius;
1785 }
1786 } else {
1787 // Rectangle tracking
1788 const QRectF rect = QRectF(QPointF(std::clamp(static_cast<qreal>(_trackingImageStatus.rec_top_x), 0.0, 1.0),
1789 std::clamp(static_cast<qreal>(_trackingImageStatus.rec_top_y), 0.0, 1.0)),
1790 QPointF(std::clamp(static_cast<qreal>(_trackingImageStatus.rec_bottom_x), 0.0, 1.0),
1791 std::clamp(static_cast<qreal>(_trackingImageStatus.rec_bottom_y), 0.0, 1.0))).normalized();
1792 qCDebug(VehicleCameraControlLog) << "Tracking Rect [" << rect << "]";
1795 if (_trackingImageRect != rect) {
1796 _trackingImageRect = rect;
1798 }
1799 }
1800
1801 if (_trackingImageIsActive != active) {
1802 _trackingImageIsActive = active;
1804 }
1805 if (_trackingImageIsPoint != isPoint) {
1806 _trackingImageIsPoint = isPoint;
1808 }
1809}
1810
1812{
1813 if (stream != _currentStream && stream >= 0 && stream < _streamLabels.count()) {
1815 if(pInfo) {
1816 qCDebug(VehicleCameraControlLog)
1817 << "Stopping stream:" << QGCNetworkHelper::redactedUrlForLogging(pInfo->uri());
1818 //-- Stop current stream
1820 _compID, // Target component
1821 MAV_CMD_VIDEO_STOP_STREAMING, // Command id
1822 false, // ShowError
1823 pInfo->streamID()); // Stream ID
1824 }
1825 _currentStream = stream;
1826 pInfo = currentStreamInstance();
1827 if(pInfo) {
1828 //-- Start new stream
1829 qCDebug(VehicleCameraControlLog)
1830 << "Starting stream:" << QGCNetworkHelper::redactedUrlForLogging(pInfo->uri());
1832 _compID, // Target component
1833 MAV_CMD_VIDEO_START_STREAMING, // Command id
1834 false, // ShowError
1835 pInfo->streamID()); // Stream ID
1836 //-- Update stream status
1837 _requestStreamStatus(static_cast<uint8_t>(pInfo->streamID()));
1838 }
1839 emit currentStreamChanged();
1841 }
1842}
1843
1845{
1847 if(pInfo) {
1848 //-- Stop current stream
1850 _compID, // Target component
1851 MAV_CMD_VIDEO_STOP_STREAMING, // Command id
1852 false, // ShowError
1853 pInfo->streamID()); // Stream ID
1854 }
1855}
1856
1858{
1860 if(pInfo) {
1861 //-- Start new stream
1863 _compID, // Target component
1864 MAV_CMD_VIDEO_START_STREAMING, // Command id
1865 false, // ShowError
1866 pInfo->streamID()); // Stream ID
1867 }
1868}
1869
1871{
1872 if(hasVideoStream()) {
1873 return _streams.count() > 0;
1874 }
1875 return false;
1876}
1877
1880{
1881 if(_currentStream < _streamLabels.count() && _streamLabels.count()) {
1883 return pStream;
1884 }
1885 return nullptr;
1886}
1887
1890{
1891 //-- For now, it will return the first thermal listed (if any)
1892 for(int i = 0; i < _streams.count(); i++) {
1893 if(_streams[i]) {
1894 QGCVideoStreamInfo* pStream = qobject_cast<QGCVideoStreamInfo*>(_streams[i]);
1895 if(pStream) {
1896 if(pStream->isThermal()) {
1897 return pStream;
1898 }
1899 }
1900 }
1901 }
1902 return nullptr;
1903}
1904
1906{
1907 qCDebug(VehicleCameraControlLog) << "_requestStreamInfo() - stream:" << streamID << "retries:" << _videoStreamInfoRetries;
1908 // By default, try to use new REQUEST_MESSAGE command instead of
1909 // deprecated MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION.
1910 if (_videoStreamInfoRetries % 2 == 0) {
1911 qCDebug(VehicleCameraControlLog) << " Sending REQUEST_MESSAGE:MAVLINK_MSG_ID_VIDEO_STREAM_INFORMATION";
1913 _compID, // target component
1914 MAV_CMD_REQUEST_MESSAGE, // command id
1915 false, // showError
1916 MAVLINK_MSG_ID_VIDEO_STREAM_INFORMATION, // msgid
1917 streamID); // stream ID
1918 } else {
1919 qCDebug(VehicleCameraControlLog) << " Sending MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION (legacy)";
1921 _compID, // Target component
1922 MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION, // Command id
1923 false, // ShowError
1924 streamID); // Stream ID
1925 }
1926 _streamInfoTimer.start(1000); // Wait up to a second for it
1927}
1928
1930{
1931 qCDebug(VehicleCameraControlLog) << "_requestStreamStatus() - stream:" << streamID << "retries:" << _videoStreamStatusRetries;
1932 // By default, try to use new REQUEST_MESSAGE command instead of
1933 // deprecated MAV_CMD_REQUEST_VIDEO_STREAM_STATUS.
1934 if (_videoStreamStatusRetries % 2 == 0) {
1935 qCDebug(VehicleCameraControlLog) << " Sending REQUEST_MESSAGE:MAVLINK_MSG_ID_VIDEO_STREAM_STATUS";
1937 _compID, // target component
1938 MAV_CMD_REQUEST_MESSAGE, // command id
1939 false, // showError
1940 MAVLINK_MSG_ID_VIDEO_STREAM_STATUS, // msgid
1941 streamID); // stream id
1942 } else {
1943 qCDebug(VehicleCameraControlLog) << " Sending MAV_CMD_REQUEST_VIDEO_STREAM_STATUS (legacy)";
1945 _compID, // Target component
1946 MAV_CMD_REQUEST_VIDEO_STREAM_STATUS, // Command id
1947 false, // ShowError
1948 streamID); // Stream ID
1949 }
1950 _streamStatusTimer.start(1000); // Wait up to a second for it
1951}
1952
1955{
1956 for(int i = 0; i < _streams.count(); i++) {
1957 if(_streams[i]) {
1958 QGCVideoStreamInfo* pStream = qobject_cast<QGCVideoStreamInfo*>(_streams[i]);
1959 if(pStream) {
1960 if(pStream->streamID() == id) {
1961 return pStream;
1962 }
1963 } else {
1964 qCritical() << "Null QGCVideoStreamInfo instance";
1965 }
1966 }
1967 }
1968 if(report) {
1969 qWarning() << "Stream id not found:" << id;
1970 }
1971 return nullptr;
1972}
1973
1976{
1977 for(int i = 0; i < _streams.count(); i++) {
1978 if(_streams[i]) {
1979 QGCVideoStreamInfo* pStream = qobject_cast<QGCVideoStreamInfo*>(_streams[i]);
1980 if(pStream) {
1981 if(pStream->name() == name) {
1982 return pStream;
1983 }
1984 }
1985 }
1986 }
1987 return nullptr;
1988}
1989
1991{
1993 int count = _expectedCount * 6;
1994 if(_videoStreamInfoRetries > count) {
1995 qCWarning(VehicleCameraControlLog) << "Giving up requesting video stream info";
1996 _streamInfoTimer.stop();
1997 //-- If we have at least one stream, work with what we have.
1998 if(_streams.count()) {
1999 emit autoStreamChanged();
2001 }
2002 return;
2003 }
2004 for(uint8_t i = 0; i < _expectedCount; i++) {
2005 //-- Stream ID starts at 1
2006 if(!_findStream(i+1, false)) {
2007 _requestStreamInfo(i+1);
2008 return;
2009 }
2010 }
2011}
2012
2014{
2017 qCWarning(VehicleCameraControlLog) << "Giving up requesting video stream status";
2018 _streamStatusTimer.stop();
2019 return;
2020 }
2022 if(pStream) {
2023 _requestStreamStatus(static_cast<uint8_t>(pStream->streamID()));
2024 }
2025}
2026
2028{
2030 qCDebug(VehicleCameraControlLog) << "_cameraSettingsTimeout() - retries now:" << _cameraSettingsRetries;
2031 if(_cameraSettingsRetries > 5) {
2032 qCWarning(VehicleCameraControlLog) << "Giving up requesting camera settings after" << _cameraSettingsRetries << "retries";
2033 _cameraSettingsTimer.stop();
2034 return;
2035 }
2036 qCDebug(VehicleCameraControlLog) << "_cameraSettingsTimeout() - calling _requestCameraSettings()";
2038}
2039
2041{
2043 qCDebug(VehicleCameraControlLog) << "_storageInfoTimeout() - retries now:" << _storageInfoRetries;
2044 if(_storageInfoRetries > 5) {
2045 qCWarning(VehicleCameraControlLog) << "Giving up requesting storage info after" << _storageInfoRetries << "retries";
2046 _storageInfoTimer.stop();
2047 return;
2048 }
2049 qCDebug(VehicleCameraControlLog) << "_storageInfoTimeout() - calling _requestStorageInfo()";
2051}
2052
2053QStringList
2054VehicleCameraControl::_loadExclusions(QDomNode option)
2055{
2056 QStringList exclusionList;
2057 QDomElement optionElem = option.toElement();
2058 QDomNodeList excRoot = optionElem.elementsByTagName(kExclusions);
2059 if(excRoot.size()) {
2060 //-- Iterate exclusions
2061 QDomNode node = excRoot.item(0);
2062 QDomElement elem = node.toElement();
2063 QDomNodeList exclusions = elem.elementsByTagName(kExclusion);
2064 for(int i = 0; i < exclusions.size(); i++) {
2065 QString exclude = exclusions.item(i).toElement().text();
2066 if(!exclude.isEmpty()) {
2067 exclusionList << exclude;
2068 }
2069 }
2070 }
2071 return exclusionList;
2072}
2073
2074QStringList
2075VehicleCameraControl::_loadUpdates(QDomNode option)
2076{
2077 QStringList updateList;
2078 QDomElement optionElem = option.toElement();
2079 QDomNodeList updateRoot = optionElem.elementsByTagName(kUpdates);
2080 if(updateRoot.size()) {
2081 //-- Iterate updates
2082 QDomNode node = updateRoot.item(0);
2083 QDomElement elem = node.toElement();
2084 QDomNodeList updates = elem.elementsByTagName(kUpdate);
2085 for(int i = 0; i < updates.size(); i++) {
2086 QString update = updates.item(i).toElement().text();
2087 if(!update.isEmpty()) {
2088 updateList << update;
2089 }
2090 }
2091 }
2092 return updateList;
2093}
2094
2095bool VehicleCameraControl::_loadRanges(QDomNode option, const QString factName, QString paramValue)
2096{
2097 QDomElement optionElem = option.toElement();
2098 QDomNodeList rangeRoot = optionElem.elementsByTagName(kParameterranges);
2099 if(rangeRoot.size()) {
2100 QDomNode node = rangeRoot.item(0);
2101 QDomElement elem = node.toElement();
2102 QDomNodeList parameterRanges = elem.elementsByTagName(kParameterrange);
2103 //-- Iterate parameter ranges
2104 for(int i = 0; i < parameterRanges.size(); i++) {
2105 QString param;
2106 QString condition;
2107 QDomNode paramRange = parameterRanges.item(i);
2108 if(!read_attribute(paramRange, kParameter, param)) {
2109 qCritical() << QString("Malformed option range for parameter %1").arg(factName);
2110 return false;
2111 }
2112 read_attribute(paramRange, kCondition, condition);
2113 QDomElement pelem = paramRange.toElement();
2114 QDomNodeList rangeOptions = pelem.elementsByTagName(kRoption);
2115 QStringList optNames;
2116 QStringList optValues;
2117 //-- Iterate options
2118 for(int rangeOptionIndex = 0; rangeOptionIndex < rangeOptions.size(); rangeOptionIndex++) {
2119 QString optName;
2120 QString optValue;
2121 QDomNode roption = rangeOptions.item(rangeOptionIndex);
2122 if(!read_attribute(roption, kName, optName)) {
2123 qCritical() << QString("Malformed roption for parameter %1").arg(factName);
2124 return false;
2125 }
2126 if(!read_attribute(roption, kValue, optValue)) {
2127 qCritical() << QString("Malformed rvalue for parameter %1").arg(factName);
2128 return false;
2129 }
2130 optNames << optName;
2131 optValues << optValue;
2132 }
2133 if(optNames.size()) {
2134 QGCCameraOptionRange* pRange = new QGCCameraOptionRange(this, factName, paramValue, param, condition, optNames, optValues);
2135 _optionRanges.append(pRange);
2136 qCDebug(VehicleCameraControlVerboseLog) << "New range limit:" << factName << paramValue << param << condition << optNames << optValues;
2137 }
2138 }
2139 }
2140 return true;
2141}
2142
2143void VehicleCameraControl::_processRanges()
2144{
2145 //-- After all parameter are loaded, process parameter ranges
2146 for(QGCCameraOptionRange* pRange: _optionRanges) {
2147 Fact* pRFact = getFact(pRange->targetParam);
2148 if(pRFact) {
2149 for(int i = 0; i < pRange->optNames.size(); i++) {
2150 QVariant optVariant;
2151 QString errorString;
2152 if (!pRFact->metaData()->convertAndValidateRaw(pRange->optValues[i], false, optVariant, errorString)) {
2153 qWarning() << "Invalid roption value, name:" << pRange->targetParam
2154 << " type:" << pRFact->metaData()->type()
2155 << " value:" << pRange->optValues[i]
2156 << " error:" << errorString;
2157 } else {
2158 pRange->optVariants << optVariant;
2159 }
2160 }
2161 }
2162 }
2163}
2164
2165bool VehicleCameraControl::_loadNameValue(QDomNode option, const QString factName, FactMetaData* metaData, QString& optName, QString& optValue, QVariant& optVariant)
2166{
2167 if(!read_attribute(option, kName, optName)) {
2168 qCritical() << QString("Malformed option for parameter %1").arg(factName);
2169 return false;
2170 }
2171 if(!read_attribute(option, kValue, optValue)) {
2172 qCritical() << QString("Malformed value for parameter %1").arg(factName);
2173 return false;
2174 }
2175 QString errorString;
2176 if (!metaData->convertAndValidateRaw(optValue, false, optVariant, errorString)) {
2177 qWarning() << "Invalid option value, name:" << factName
2178 << " type:" << metaData->type()
2179 << " value:" << optValue
2180 << " error:" << errorString;
2181 }
2182 return true;
2183}
2184
2185void VehicleCameraControl::_handleDefinitionFile(const QString &url)
2186{
2187 //-- First check and see if we have it cached
2188 QFile xmlFile(_cacheFile);
2189
2190 QString ftpPrefix(QStringLiteral("%1://").arg(FTPManager::mavlinkFTPScheme));
2191 if (!xmlFile.exists() && url.startsWith(ftpPrefix, Qt::CaseInsensitive)) {
2192 qCDebug(VehicleCameraControlLog) << "No camera definition file cached, attempt ftp download";
2193 int ver = static_cast<int>(_mavlinkCameraInfo.cam_definition_version);
2194 QString ext = "";
2195 if (url.endsWith(".lzma", Qt::CaseInsensitive)) { ext = ".lzma"; }
2196 if (url.endsWith(".xz", Qt::CaseInsensitive)) { ext = ".xz"; }
2197 QString fileName = QString::asprintf("%s_%s_%03d.xml%s",
2198 _vendor.toStdString().c_str(),
2199 _modelName.toStdString().c_str(),
2200 ver,
2201 ext.toStdString().c_str());
2202 connect(_vehicle->ftpManager(), &FTPManager::downloadComplete, this, &VehicleCameraControl::_ftpDownloadComplete);
2204 SettingsManager::instance()->appSettings()->parameterSavePath().toStdString().c_str(),
2205 fileName);
2206 return;
2207 }
2208
2209 if (!xmlFile.exists()) {
2210 qCDebug(VehicleCameraControlLog) << "No camera definition file cached, attempt http download";
2211 _httpRequest(url);
2212 return;
2213 }
2214 if (!xmlFile.open(QIODevice::ReadOnly)) {
2215 qWarning() << "Could not read cached camera definition file:" << _cacheFile;
2216 _httpRequest(url);
2217 return;
2218 }
2219 QByteArray bytes = xmlFile.readAll();
2220 QDomDocument doc;
2221 const QDomDocument::ParseResult result = doc.setContent(bytes, QDomDocument::ParseOption::Default);
2222 if (!result) {
2223 qWarning() << "Could not parse cached camera definition file:" << _cacheFile;
2224 _httpRequest(url);
2225 return;
2226 }
2227 //-- We have it
2228 qCDebug(VehicleCameraControlLog) << "Using cached camera definition file:" << _cacheFile;
2229 _cached = true;
2230 emit dataReady(bytes);
2231}
2232
2233void VehicleCameraControl::_httpRequest(const QString &url)
2234{
2235 qCDebug(VehicleCameraControlLog) << "Request camera definition:" << url;
2236 if(!_netManager) {
2237 _netManager = new QNetworkAccessManager(this);
2238 }
2240 QNetworkRequest request(QUrl::fromUserInput(url));
2241 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
2242 QSslConfiguration conf = request.sslConfiguration();
2243 conf.setPeerVerifyMode(QSslSocket::VerifyNone);
2244 request.setSslConfiguration(conf);
2245 QNetworkReply* reply = _netManager->get(request);
2246 connect(reply, &QNetworkReply::finished, this, &VehicleCameraControl::_downloadFinished);
2247}
2248
2250{
2251 QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
2252 if(!reply) {
2253 return;
2254 }
2255 int err = reply->error();
2256 int http_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
2257 QByteArray data = reply->readAll();
2258 if(err == QNetworkReply::NoError && http_code == 200) {
2259 data.append("\n");
2260 } else {
2261 data.clear();
2262 qWarning() << QString("Camera Definition (%1) download error: %2 status: %3").arg(
2263 reply->url().toDisplayString(),
2264 reply->errorString(),
2265 reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()
2266 );
2267 }
2268 emit dataReady(data);
2269 //reply->deleteLater();
2270}
2271
2272void VehicleCameraControl::_ftpDownloadComplete(const QString& fileName, const QString& errorMsg)
2273{
2274 qCDebug(VehicleCameraControlLog) << "FTP Download completed: " << fileName << ", " << errorMsg;
2275
2276 disconnect(_vehicle->ftpManager(), &FTPManager::downloadComplete, this, &VehicleCameraControl::_ftpDownloadComplete);
2277
2278 QString outputFileName = QGCCompression::decompressIfNeeded(fileName);
2279 if (outputFileName.isEmpty()) {
2280 qCWarning(VehicleCameraControlLog) << "Inflate of compressed xml failed" << fileName;
2281 }
2282
2283 QFile xmlFile(outputFileName);
2284
2285 if (!xmlFile.exists()) {
2286 qCDebug(VehicleCameraControlLog) << "No camera definition file present after ftp download completed";
2287 return;
2288 }
2289 if (!xmlFile.open(QIODevice::ReadOnly)) {
2290 qWarning() << "Could not read downloaded camera definition file: " << fileName;
2291 return;
2292 }
2293
2294 _cached = true;
2295 QByteArray bytes = xmlFile.readAll();
2296 emit dataReady(bytes);
2297}
2298
2300{
2301 if(data.size()) {
2302 qCDebug(VehicleCameraControlLog) << "Parsing camera definition";
2303 _loadCameraDefinitionFile(data);
2304 } else {
2305 qCDebug(VehicleCameraControlLog) << "No camera definition received, trying to search on our own...";
2306 QFile definitionFile;
2307 if(QGCCorePlugin::instance()->getOfflineCameraDefinitionFile(_modelName, definitionFile)) {
2308 qCDebug(VehicleCameraControlLog) << "Found offline definition file for: " << _modelName << ", loading: " << definitionFile.fileName();
2309 if (definitionFile.open(QIODevice::ReadOnly)) {
2310 QByteArray newData = definitionFile.readAll();
2311 _loadCameraDefinitionFile(newData);
2312 } else {
2313 qCDebug(VehicleCameraControlLog) << "error opening offline definition file for: " << _modelName;
2314 }
2315 } else {
2316 qCDebug(VehicleCameraControlLog) << "No offline camera definition file found";
2317 }
2318 }
2320}
2321
2323{
2324 for(const QString& param: _paramIO.keys()) {
2325 if(!_paramIO[param]->paramDone()) {
2326 return;
2327 }
2328 }
2329 //-- All parameters loaded (or timed out)
2330 _paramComplete = true;
2331 emit parametersReady();
2332}
2333
2335{
2336 if(_mavlinkCameraInfo.flags & CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM) {
2337 connect(&_streamInfoTimer, &QTimer::timeout, this, &VehicleCameraControl::_streamInfoTimeout);
2338 _streamInfoTimer.setSingleShot(false);
2339 connect(&_streamStatusTimer, &QTimer::timeout, this, &VehicleCameraControl::_streamStatusTimeout);
2340 _streamStatusTimer.setSingleShot(true);
2341 //-- Request all streams
2343 _streamInfoTimer.start(2000);
2344 }
2345}
2346
2347bool VehicleCameraControl::incomingParameter(Fact* pFact, QVariant& newValue)
2348{
2349 Q_UNUSED(pFact);
2350 Q_UNUSED(newValue);
2351 return true;
2352}
2353
2354bool VehicleCameraControl::validateParameter(Fact* pFact, QVariant& newValue)
2355{
2356 Q_UNUSED(pFact);
2357 Q_UNUSED(newValue);
2358 return true;
2359}
2360
2361QStringList
2363{
2364 qCDebug(VehicleCameraControlLog) << "Active:" << _activeSettings;
2365 return _activeSettings;
2366}
2367
2368Fact*
2373
2374Fact*
2376{
2377 return (_paramComplete && _activeSettings.contains(kCAM_EV)) ? getFact(kCAM_EV) : nullptr;
2378}
2379
2380Fact*
2382{
2383 return (_paramComplete && _activeSettings.contains(kCAM_ISO)) ? getFact(kCAM_ISO) : nullptr;
2384}
2385
2386Fact*
2391
2392Fact*
2397
2398Fact*
2400{
2401 return (_paramComplete && _activeSettings.contains(kCAM_WBMODE)) ? getFact(kCAM_WBMODE) : nullptr;
2402}
2403
2404Fact*
2409
2411{
2412 if (_trackingEnabled == set) {
2413 return;
2414 }
2415 _trackingEnabled = set;
2416 if (!set) {
2417 stopTracking();
2418 }
2420}
2421
2423{
2425 qCCritical(VehicleCameraControlLog) << "startTrackingRect called but camera does not have rectangle tracking capability";
2426 return;
2427 }
2428
2429 qCDebug(VehicleCameraControlLog) << "Start Tracking (Rectangle: ["
2430 << static_cast<float>(rec.x()) << ", "
2431 << static_cast<float>(rec.y()) << "] - ["
2432 << static_cast<float>(rec.x() + rec.width()) << ", "
2433 << static_cast<float>(rec.y() + rec.height()) << "]";
2434
2436 MAV_CMD_CAMERA_TRACK_RECTANGLE,
2437 true,
2438 static_cast<float>(rec.x()),
2439 static_cast<float>(rec.y()),
2440 static_cast<float>(rec.x() + rec.width()),
2441 static_cast<float>(rec.y() + rec.height()));
2442
2444}
2445
2446void VehicleCameraControl::startTrackingPoint(QPointF point, double radius)
2447{
2449 qCCritical(VehicleCameraControlLog) << "startTrackingPoint called but camera does not have point tracking capability";
2450 return;
2451 }
2452
2453 qCDebug(VehicleCameraControlLog) << "Start Tracking (Point: ["
2454 << static_cast<float>(point.x()) << ", "
2455 << static_cast<float>(point.y()) << "], Radius: "
2456 << static_cast<float>(radius);
2457
2459 MAV_CMD_CAMERA_TRACK_POINT,
2460 true,
2461 static_cast<float>(point.x()),
2462 static_cast<float>(point.y()),
2463 static_cast<float>(radius));
2464
2466}
2467
2469{
2470 qCDebug(VehicleCameraControlLog) << "Stop Tracking";
2471
2472 //-- Stop Tracking
2474 MAV_CMD_CAMERA_STOP_TRACKING,
2475 true);
2476
2477 //-- Stop Sending Tracking Status
2479 MAV_CMD_SET_MESSAGE_INTERVAL,
2480 true,
2481 MAVLINK_MSG_ID_CAMERA_TRACKING_IMAGE_STATUS,
2482 -1);
2483
2484 // reset tracking state
2485 _trackingImageRect = {};
2489 _trackingImageIsActive = false;
2491 }
2493 _trackingImageIsPoint = false;
2495 }
2496}
2497
2499{
2501 MAV_CMD_SET_MESSAGE_INTERVAL,
2502 true,
2503 MAVLINK_MSG_ID_CAMERA_TRACKING_IMAGE_STATUS,
2504 500000); // Interval (us)
2505}
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
QString errorString
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
struct __mavlink_video_stream_information_t mavlink_video_stream_information_t
struct __mavlink_storage_information_t mavlink_storage_information_t
struct __mavlink_param_ext_value_t mavlink_param_ext_value_t
struct __mavlink_param_ext_ack_t mavlink_param_ext_ack_t
struct __mavlink_camera_information_t mavlink_camera_information_t
struct __mavlink_camera_settings_t mavlink_camera_settings_t
struct __mavlink_video_stream_status_t mavlink_video_stream_status_t
struct __mavlink_camera_tracking_image_status_t mavlink_camera_tracking_image_status_t
struct __mavlink_battery_status_t mavlink_battery_status_t
struct __mavlink_camera_capture_status_t mavlink_camera_capture_status_t
std::array< MsgOutKey, 4 > keys
Definition UBXPlan.cc:13
static bool read_value(QDomNode &element, const char *tagName, QString &target)
static bool read_attribute(QDomNode &node, const char *tagName, bool &target)
static constexpr const char * mavlinkFTPScheme
Definition FTPManager.h:77
void downloadComplete(const QString &file, const QString &errorMsg)
bool download(uint8_t fromCompId, const QString &fromURI, const QString &toDir, const QString &fileName="", bool checksize=true)
Definition FTPManager.cc:32
QMap< QString, FactMetaData * > _nameToFactMetaDataMap
Definition FactGroup.h:71
Q_INVOKABLE Fact * getFact(const QString &name) const
Definition FactGroup.cc:72
void _addFactGroup(FactGroup *factGroup, const QString &name)
Definition FactGroup.cc:133
Q_INVOKABLE bool factExists(const QString &name) const
@ return true: if the fact exists in the group
Definition FactGroup.cc:49
void _addFact(Fact *fact, const QString &name)
Definition FactGroup.cc:116
Holds the meta data associated with a Fact.
void setRawUnits(const QString &rawUnits)
void setDecimalPlaces(int decimalPlaces)
void setHasControl(bool bValue)
void setShortDescription(const QString &shortDescription)
void setLongDescription(const QString &longDescription)
void setRawMin(const QVariant &rawMin)
bool convertAndValidateRaw(const QVariant &rawValue, bool convertOnly, QVariant &typedValue, QString &errorString) const
void setWriteOnly(bool bValue)
void setRawDefaultValue(const QVariant &rawDefaultValue)
void setRawMax(const QVariant &rawMax)
void setRawIncrement(double increment)
void addEnumInfo(const QString &name, const QVariant &value)
Used to add new values to the enum lists after the meta data has been loaded.
QVariant rawDefaultValue() const
ValueType_t type() const
static ValueType_t stringToType(const QString &typeString, bool &unknownType)
void setReadOnly(bool bValue)
A Fact is used to hold a single value within the system.
Definition Fact.h:15
void setMetaData(FactMetaData *metaData, bool setDefaultFromMetaData=false)
Definition Fact.cc:742
void containerSetRawValue(const QVariant &value)
Value coming from Vehicle. This does NOT send a _containerRawValueChanged signal.
Definition Fact.cc:199
FactMetaData * metaData()
Definition Fact.h:172
void setRawValue(const QVariant &value)
Definition Fact.cc:135
QString rawValueString() const
Definition Fact.cc:484
QStringList enumStrings() const
Definition Fact.cc:294
QString name() const
Definition Fact.h:124
static int getComponentId()
static MAVLinkProtocol * instance()
Abstract base class for all camera controls: real and simulated.
PhotoCaptureStatus _photoCaptureStatus() const
QString captureImageStatusToStr(uint8_t image_status)
VideoCaptureStatus _videoCaptureStatus() const
QString captureVideoStatusToStr(uint8_t video_status)
void dataReady(const QByteArray &data)
static MissionCommandTree * instance()
QString rawName(MAV_CMD command) const
Returns the raw name for the specified command.
Camera option exclusions.
Camera option ranges.
QGCCameraOptionRange(QObject *parent, QString param_, QString value_, QString targetParam_, QString condition_, QStringList optNames_, QStringList optValues_)
Camera parameter handler.
Definition QGCCameraIO.h:14
static QGCCorePlugin * instance()
Encapsulates the contents of a VIDEO_STREAM_INFORMATION message.
quint8 streamID() const
bool update(const mavlink_video_stream_status_t &info)
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
int count() const override final
static SettingsManager * instance()
MAVLink Camera API controller - connected to a real mavlink v2 camera.
void handleParamExtValue(const mavlink_param_ext_value_t &paramExtValue) override
static constexpr const char * kCAM_ISO
void setPhotoLapse(qreal interval) override
static constexpr const char * kRoption
QSize resolution() const override
bool incomingParameter(Fact *pFact, QVariant &newValue) override
Allow controller to modify or invalidate incoming parameter.
QString storageFreeStr() const override
bool capturesPhotos() const override
Q_INVOKABLE void startZoom(int direction) override
static constexpr const char * kName
void setTrackingEnabled(bool set) override
QStringList activeSettings() const override
QList< QGCCameraOptionRange * > _optionRanges
static constexpr const char * kType
static constexpr const char * kModel
void setCameraMode(CameraMode cameraMode) override
Q_INVOKABLE void startTrackingRect(QRectF rec) override
Q_INVOKABLE void startTrackingPoint(QPointF point, double radius) override
bool validateParameter(Fact *pFact, QVariant &newValue) override
Allow controller to modify or invalidate parameter change.
mavlink_camera_tracking_image_status_t _trackingImageStatus
QGCVideoStreamInfo * thermalStreamInstance() override
static constexpr const char * kDescription
QString recordTimeStr() const override
Q_INVOKABLE void formatCard(int id=1) override
bool hasVideoStream() const override
virtual void _onVideoManagerRecordingChanged(bool recording)
int compID() const override
static constexpr const char * kUpdate
void setPhotoCaptureMode(PhotoCaptureMode mode) override
QmlObjectListModel _streams
CapturePhotosState capturePhotosState() const override
Q_INVOKABLE void toggleCameraMode() override
void setFocusLevel(qreal level) override
Q_INVOKABLE void stepFocus(int direction) override
Q_INVOKABLE void stepZoom(int direction) override
static constexpr const char * kDecimalPlaces
static constexpr const char * kOptions
bool hasTracking() const override
Q_INVOKABLE bool toggleVideoRecording() override
virtual void _dataReady(QByteArray data)
Q_INVOKABLE bool takePhoto() override
static constexpr const char * kControl
static constexpr const char * kVersion
void setZoomLevel(qreal level) override
void handleVideoStreamInformation(const mavlink_video_stream_information_t &videoStreamInformation) override
QString vendor() const override
bool capturesVideo() const override
static constexpr const char * kWriteOnly
QString batteryRemainingStr() const override
VehicleCameraControl(const mavlink_camera_information_t *info, Vehicle *vehicle, int compID, QObject *parent=nullptr)
static constexpr const char * kCAM_EXPMODE
virtual void _cameraSettingsTimeout()
static constexpr const char * kPhotoLapse
void handleCameraCaptureStatus(const mavlink_camera_capture_status_t &cameraCaptureStatus) override
static constexpr const char * kCAM_APERTURE
static constexpr const char * kTranslated
Q_INVOKABLE void startFocus(int direction) override
bool autoStream() const override
static constexpr const char * kParameterranges
void setThermalOpacity(double val) override
void handleBatteryStatus(const mavlink_battery_status_t &bs) override
static constexpr const char * kUnit
Q_INVOKABLE void stopFocus() override
static constexpr const char * kDefnition
static constexpr const char * kVendor
static constexpr const char * kOriginal
void setPhotoLapseCount(int count) override
QList< QGCCameraOptionExclusion * > _valueExclusions
QSizeF sensorSize() const override
Q_INVOKABLE void setCameraModePhoto() override
static constexpr const char * kCAM_SHUTTERSPD
virtual void _requestTrackingStatus()
static constexpr const char * kDefault
static constexpr const char * kMin
qreal focalLength() const override
virtual void _setCameraMode(CameraMode mode)
virtual void _requestStreamInfo(uint8_t streamID)
Q_INVOKABLE bool stopVideoRecording() override
void factChanged(Fact *pFact) override
Notify controller a parameter has changed.
void handleVideoStreamStatus(const mavlink_video_stream_status_t &videoStreamStatus) override
QMap< QString, QGCCameraParamIO * > _paramIO
static constexpr const char * kPhotoLapseCount
static constexpr const char * kExclusions
static constexpr const char * kLocale
int version() const override
static constexpr const char * kCondition
static constexpr const char * kThermalMode
bool hasFocus() const override
Q_INVOKABLE void stopStream() override
static constexpr const char * kMax
QString firmwareVersion() const override
virtual void _mavCommandResult(int vehicleId, int component, int command, int result, int failureCode)
static constexpr const char * kStep
Q_INVOKABLE void resetSettings() override
virtual void _requestStreamStatus(uint8_t streamID)
Q_INVOKABLE bool startVideoRecording() override
Q_INVOKABLE void setCameraModeVideo() override
void handleParamExtAck(const mavlink_param_ext_ack_t &paramExtAck) override
static constexpr const char * kOption
void handleTrackingImageStatus(const mavlink_camera_tracking_image_status_t &trackingImageStatus) override
static constexpr const char * kExclusion
void setThermalMode(ThermalViewMode mode) override
static constexpr const char * kStrings
QMap< QString, QVariantList > _originalOptValues
QMap< QString, QStringList > _originalOptNames
static constexpr const char * kPhotoMode
static constexpr const char * kReadOnly
virtual void _requestCaptureStatus()
void handleStorageInformation(const mavlink_storage_information_t &storageInformation) override
bool hasModes() const override
bool trackingEnabled() const override
static constexpr const char * kParameter
static constexpr const char * kValue
virtual QGCVideoStreamInfo * _findStream(uint8_t streamID, bool report=true)
CaptureVideoState captureVideoState() const override
static constexpr const char * kUpdates
void handleCameraSettings(const mavlink_camera_settings_t &settings) override
QMap< QString, QStringList > _requestUpdates
Q_INVOKABLE void stopTracking() override
static constexpr const char * kParameterrange
static constexpr const char * kParameters
Q_INVOKABLE void resumeStream() override
bool photosInVideoMode() const override
quint32 recordTime() const override
virtual void _requestCameraSettings()
static constexpr const char * kCAM_EV
bool isBasic() const override
bool hasZoom() const override
Q_INVOKABLE bool stopTakePhoto() override
void setCurrentStream(int stream) override
QNetworkAccessManager * _netManager
bool videoInPhotoMode() const override
Q_INVOKABLE void stopZoom() override
static constexpr const char * kLocalization
QString modelName() const override
virtual void _setPhotoCaptureStatus(PhotoCaptureStatus captureStatus)
static constexpr const char * kCAM_WBMODE
QGCVideoStreamInfo * currentStreamInstance() override
virtual void _setVideoCaptureStatus(VideoCaptureStatus captureStatus)
mavlink_camera_information_t _mavlinkCameraInfo
static constexpr const char * kCAM_MODE
static constexpr const char * kThermalOpacity
WeakLinkInterfacePtr primaryLink() const
QGCCameraManager * cameraManager()
Definition Vehicle.h:1312
void sendMavCommand(int compId, MAV_CMD command, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
Definition Vehicle.cc:2173
VehicleLinkManager * vehicleLinkManager()
Definition Vehicle.h:597
int id() const
Definition Vehicle.h:443
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
Definition Vehicle.cc:1401
FTPManager * ftpManager()
Definition Vehicle.h:598
void mavCommandResult(int vehicleId, int targetComponent, int command, int ackResult, int failureCode)
Q_INVOKABLE void stopRecording()
Q_INVOKABLE void startRecording(const QString &videoFile=QString())
static VideoManager * instance()
void recordingChanged(bool recording)
Q_INVOKABLE void grabImage(const QString &imageFile=QString())
QString decompressIfNeeded(const QString &filePath, const QString &outputPath, bool removeOriginal)
void configureProxy(QNetworkAccessManager *manager)
Set up default proxy configuration on a network manager.
QString redactedUrlForLogging(const QUrl &url)
QString numberToString(quint64 number)
Decimal integer (e.g. "1,234,567").
Definition QGCFormat.cc:15
QString bigSizeMBToString(quint64 sizeMB)
MB-scaled size, output in MB/GB/TB. Input is in MB.
Definition QGCFormat.cc:38
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Definition AppMessages.cc:9