目录
前言
本篇介绍Camera文件夹下的内容,该文件夹下又三个类文件,分别是QGCCameraManager,QGCCameraIO,QGCCameraControl,按照命名可以理解这个三个类是对项目中的相机进行管理的,分别是QGCCameraManager管理camera实例,camera实例的逻辑在QGCCameraControl中编写,io功能在QGCCameraIO中编写。下面我们分别对这三个类的内容进行分析。
一.QGCCameraManager
该类主要用于管理相机设备实例,主要操作包含,控制相机的更换,手柄的更换,视频流的更换,相机信息的获取,心跳机制的管理,以及相机所有功能如截图,录像,存储等。
代码和注释如下
/*!
* @file
* @brief Camera Controller
* @author Gus Grubba <[email protected]>
*
*/
/// @file
/// @brief MAVLink Camera API. Camera Manager.
/// @author Gus Grubba <[email protected]>
#pragma once
#include "QGCApplication.h"
#include <QLoggingCategory>
#include "QmlObjectListModel.h"
#include "QGCCameraControl.h"
#include <QObject>
#include <QTimer>
//为相机管理建立日志类
Q_DECLARE_LOGGING_CATEGORY(CameraManagerLog)
class Joystick;
//-----------------------------------------------------------------------------
/// Camera Manager
class QGCCameraManager : public QObject
{
Q_OBJECT
public:
QGCCameraManager(Vehicle* vehicle);
virtual ~QGCCameraManager();
//相机列表
Q_PROPERTY(QmlObjectListModel* cameras READ cameras NOTIFY camerasChanged)
//相机标签列表
Q_PROPERTY(QStringList cameraLabels READ cameraLabels NOTIFY cameraLabelsChanged)
//当前相机实例
Q_PROPERTY(QGCCameraControl* currentCameraInstance READ currentCameraInstance NOTIFY currentCameraChanged)
//当前相机
Q_PROPERTY(int currentCamera READ currentCamera WRITE setCurrentCamera NOTIFY currentCameraChanged)
//-- Return a list of cameras provided by this vehicle 返回由该设备提供的摄像机列表
virtual QmlObjectListModel* cameras () { return &_cameras; }
//-- Camera names to show the user (for selection) 显示给用户的相机名称(供选择)
virtual QStringList cameraLabels () { return _cameraLabels; }
//-- Current selected camera 当前选择的相机
virtual int currentCamera () { return _currentCamera; }
virtual QGCCameraControl* currentCameraInstance();
//-- Set current camera
virtual void setCurrentCamera (int sel);
//-- Current stream 当前的流
virtual QGCVideoStreamInfo* currentStreamInstance();
//-- Current thermal stream
virtual QGCVideoStreamInfo* thermalStreamInstance();
signals:
void camerasChanged ();
void cameraLabelsChanged ();
void currentCameraChanged ();
void streamChanged ();
protected slots:
virtual void _vehicleReady (bool ready); //设备准备
virtual void _mavlinkMessageReceived (const mavlink_message_t& message); //mavlink消息收到
virtual void _activeJoystickChanged (Joystick* joystick); //激活的手柄更改
virtual void _stepZoom (int direction); //缩放步骤
virtual void _startZoom (int direction); //开始缩放
virtual void _stopZoom (); //结束缩放
virtual void _stepCamera (int direction); //
virtual void _stepStream (int direction);
virtual void _cameraTimeout (); //相机超时
virtual void _triggerCamera (); //触发相机
virtual void _startVideoRecording (); //开始视频录制
virtual void _stopVideoRecording (); //结束视频录制
virtual void _toggleVideoRecording (); //
protected:
virtual QGCCameraControl* _findCamera (int id); //找到相机
virtual void _requestCameraInfo (int compID); //请求相机信息
virtual void _handleHeartbeat (const mavlink_message_t& message); //处理心跳
virtual void _handleCameraInfo (const mavlink_message_t& message); //处理相机信息
virtual void _handleStorageInfo (const mavlink_message_t& message); //处理存储信息
virtual void _handleCameraSettings (const mavlink_message_t& message); //处理相机设置
virtual void _handleParamAck (const mavlink_message_t& message); //处理参数应答
virtual void _handleParamValue (const mavlink_message_t& message); //处理参数值
virtual void _handleCaptureStatus (const mavlink_message_t& message); //处理截图状态
virtual void _handleVideoStreamInfo (const mavlink_message_t& message); //处理视频流信息
virtual void _handleVideoStreamStatus(const mavlink_message_t& message); //处理视频流状态
virtual void _handleBatteryStatus (const mavlink_message_t& message); //处理电池状态
protected:
//内置类
class CameraStruct : public QObject {
public:
CameraStruct(QObject* parent, uint8_t compID_);
QElapsedTimer lastHeartbeat; //上一次心跳时间
bool infoReceived = false; //信息是否接收到
bool gaveUp = false; //放弃
int tryCount = 0; //尝试次数
uint8_t compID = 0; //comid
};
Vehicle* _vehicle = nullptr; //设备指针
Joystick* _activeJoystick = nullptr; //手柄
bool _vehicleReadyState = false; //设备准备状态
int _currentTask = 0; //当前任务
QmlObjectListModel _cameras; //相机列表
QStringList _cameraLabels; //相机名称列表
int _currentCamera = 0; //当前相机
QElapsedTimer _lastZoomChange;
QElapsedTimer _lastCameraChange;
QTimer _cameraTimer; //相机计时器
QMap<QString, CameraStruct*> _cameraInfoRequest; //相机信息请求
};
cc文件如下
/*!
* @file
* @brief Camera Controller
* @author Gus Grubba <[email protected]>
*
*/
#include "QGCApplication.h"
#include "QGCCameraManager.h"
#include "JoystickManager.h"
QGC_LOGGING_CATEGORY(CameraManagerLog, "CameraManagerLog")
//-----------------------------------------------------------------------------
// CameraStruct 构造
QGCCameraManager::CameraStruct::CameraStruct(QObject* parent, uint8_t compID_)
: QObject(parent)
, compID(compID_)
{
}
//-----------------------------------------------------------------------------
//QGCCameraManager构造
QGCCameraManager::QGCCameraManager(Vehicle *vehicle)
: _vehicle(vehicle)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qCDebug(CameraManagerLog) << "QGCCameraManager Created";
//绑定槽函数
connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::parameterReadyVehicleAvailableChanged, this, &QGCCameraManager::_vehicleReady);
connect(_vehicle, &Vehicle::mavlinkMessageReceived, this, &QGCCameraManager::_mavlinkMessageReceived);
//相机超时
connect(&_cameraTimer, &QTimer::timeout, this, &QGCCameraManager::_cameraTimeout);
_cameraTimer.setSingleShot(false);
//计时器开启
_lastZoomChange.start();
_lastCameraChange.start();
_cameraTimer.start(500);
}
//-----------------------------------------------------------------------------
QGCCameraManager::~QGCCameraManager()
{
}
//-----------------------------------------------------------------------------
// 更新当前相机
void
QGCCameraManager::setCurrentCamera(int sel)
{
if(sel != _currentCamera && sel >= 0 && sel < _cameras.count()) {
_currentCamera = sel;
emit currentCameraChanged();
emit streamChanged();
}
}
//-----------------------------------------------------------------------------
//设备就绪
void
QGCCameraManager::_vehicleReady(bool ready)
{
qCDebug(CameraManagerLog) << "_vehicleReady(" << ready << ")";
if(ready) {
if(qgcApp()->toolbox()->multiVehicleManager()->activeVehicle() == _vehicle) {
_vehicleReadyState = true;
//获取到手柄实例
JoystickManager *pJoyMgr = qgcApp()->toolbox()->joystickManager();
_activeJoystickChanged(pJoyMgr->activeJoystick());
connect(pJoyMgr, &JoystickManager::activeJoystickChanged, this, &QGCCameraManager::_activeJoystickChanged);
}
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_mavlinkMessageReceived(const mavlink_message_t& message)
{
//-- Only pay attention to camera components, as identified by their compId
// 只注意相机组件,由它们的compId识别 组件id 对应typedef enum MAV_COMPONENT
if(message.sysid == _vehicle->id() && (message.compid >= MAV_COMP_ID_CAMERA && message.compid <= MAV_COMP_ID_CAMERA6)) {
//根据mavlink消息的不同状态执行指令
switch (message.msgid) {
case MAVLINK_MSG_ID_CAMERA_CAPTURE_STATUS:
_handleCaptureStatus(message);
break;
case MAVLINK_MSG_ID_STORAGE_INFORMATION:
_handleStorageInfo(message);
break;
case MAVLINK_MSG_ID_HEARTBEAT:
_handleHeartbeat(message);
break;
case MAVLINK_MSG_ID_CAMERA_INFORMATION:
_handleCameraInfo(message);
break;
case MAVLINK_MSG_ID_CAMERA_SETTINGS:
_handleCameraSettings(message);
break;
case MAVLINK_MSG_ID_PARAM_EXT_ACK:
_handleParamAck(message);
break;
case MAVLINK_MSG_ID_PARAM_EXT_VALUE:
_handleParamValue(message);
break;
case MAVLINK_MSG_ID_VIDEO_STREAM_INFORMATION:
_handleVideoStreamInfo(message);
break;
case MAVLINK_MSG_ID_VIDEO_STREAM_STATUS:
_handleVideoStreamStatus(message);
break;
case MAVLINK_MSG_ID_BATTERY_STATUS:
_handleBatteryStatus(message);
break;
}
}
}
//-----------------------------------------------------------------------------
//处理心跳
void
QGCCameraManager::_handleHeartbeat(const mavlink_message_t &message)
{
mavlink_heartbeat_t heartbeat;
mavlink_msg_heartbeat_decode(&message, &heartbeat);
//-- First time hearing from this one? 第一次收到这个camera的心跳
QString sCompID = QString::number(message.compid);
if(!_cameraInfoRequest.contains(sCompID)) {
//不包含就添加
qCDebug(CameraManagerLog) << "Hearbeat from " << message.compid;
CameraStruct* pInfo = new CameraStruct(this, message.compid);
pInfo->lastHeartbeat.start();
_cameraInfoRequest[sCompID] = pInfo;
//-- Request camera info 请求相机信息
_requestCameraInfo(message.compid);
} else {
if(_cameraInfoRequest[sCompID]) {
CameraStruct* pInfo = _cameraInfoRequest[sCompID];
//-- Check if we have indeed received the camera info 检查我们是否确实收到了相机信息
if(pInfo->infoReceived) {
//-- We have it. Just update the heartbeat timeout 我们拥有它。只需更新心跳超时
pInfo->lastHeartbeat.start();
} else {
//-- Try again. Maybe.
if(pInfo->lastHeartbeat.elapsed() > 2000) {
//如果超时了并且次数超过3次了 就放弃这个相机了
if(pInfo->tryCount > 3) {
if(!pInfo->gaveUp) {
pInfo->gaveUp = true;
qWarning() << "Giving up requesting camera info from" << _vehicle->id() << message.compid;
}
} else {
pInfo->tryCount++;
//-- Request camera info again.
// 否则继续请求相机信息
_requestCameraInfo(message.compid);
}
}
}
} else {
qWarning() << "_cameraInfoRequest[" << sCompID << "] is null";
}
}
}
//-----------------------------------------------------------------------------
//获取当前相机实例
QGCCameraControl*
QGCCameraManager::currentCameraInstance()
{
if(_currentCamera < _cameras.count() && _cameras.count()) {
QGCCameraControl* pCamera = qobject_cast<QGCCameraControl*>(_cameras[_currentCamera]);
return pCamera;
}
return nullptr;
}
//-----------------------------------------------------------------------------
//获取当前流实例
QGCVideoStreamInfo*
QGCCameraManager::currentStreamInstance()
{
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
QGCVideoStreamInfo* pInfo = pCamera->currentStreamInstance();
return pInfo;
}
return nullptr;
}
//-----------------------------------------------------------------------------
QGCVideoStreamInfo*
QGCCameraManager::thermalStreamInstance()
{
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
QGCVideoStreamInfo* pInfo = pCamera->thermalStreamInstance();
return pInfo;
}
return nullptr;
}
//-----------------------------------------------------------------------------
//查找相机
QGCCameraControl*
QGCCameraManager::_findCamera(int id)
{
for(int i = 0; i < _cameras.count(); i++) {
if(_cameras[i]) {
QGCCameraControl* pCamera = qobject_cast<QGCCameraControl*>(_cameras[i]);
if(pCamera) {
if(pCamera->compID() == id) {
return pCamera;
}
} else {
qCritical() << "Null QGCCameraControl instance";
}
}
}
//qWarning() << "Camera component id not found:" << id;
return nullptr;
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_handleCameraInfo(const mavlink_message_t& message)
{
//-- Have we requested it?
//是否之前已经请求过相机信息
QString sCompID = QString::number(message.compid);
//如果还没有请求过
if(_cameraInfoRequest.contains(sCompID) && !_cameraInfoRequest[sCompID]->infoReceived) {
//-- Flag it as done 标识为true
_cameraInfoRequest[sCompID]->infoReceived = true;
//将mavlink数据解码成相机信息
mavlink_camera_information_t info;
mavlink_msg_camera_information_decode(&message, &info);
qCDebug(CameraManagerLog) << "_handleCameraInfo:" << reinterpret_cast<const char*>(info.model_name) << reinterpret_cast<const char*>(info.vendor_name) << "Comp ID:" << message.compid;
//创建相机实例
QGCCameraControl* pCamera = _vehicle->firmwarePlugin()->createCameraControl(&info, _vehicle, message.compid, this);
if(pCamera) {
//指定pCamera对象所有权是c++
QQmlEngine::setObjectOwnership(pCamera, QQmlEngine::CppOwnership);
_cameras.append(pCamera);
_cameraLabels << pCamera->modelName();
//触发信号
emit camerasChanged();
emit cameraLabelsChanged();
}
}
}
//-----------------------------------------------------------------------------
//相机超时
void
QGCCameraManager::_cameraTimeout()
{
//-- Iterate cameras
foreach(QString sCompID, _cameraInfoRequest.keys()) {
if(_cameraInfoRequest[sCompID]) {
CameraStruct* pInfo = _cameraInfoRequest[sCompID];
//-- Have we received a camera info message?
if(pInfo->infoReceived) {
//-- Has the camera stopped talking to us?
//超时
if(pInfo->lastHeartbeat.elapsed() > 5000) {
//-- Camera is gone. Remove it.
//清除
bool autoStream = false;
QGCCameraControl* pCamera = _findCamera(pInfo->compID);
if(pCamera) {
qWarning() << "Camera" << pCamera->modelName() << "stopped transmitting. Removing from list.";
int idx = _cameraLabels.indexOf(pCamera->modelName());
if(idx >= 0) {
_cameraLabels.removeAt(idx);
}
idx = _cameras.indexOf(pCamera);
if(idx >= 0) {
_cameras.removeAt(idx);
}
autoStream = pCamera->autoStream();
pCamera->deleteLater();
delete pInfo;
}
_cameraInfoRequest.remove(sCompID);
emit cameraLabelsChanged();
//-- If we have another camera, switch current camera.
if(_cameras.count()) {
setCurrentCamera(0);
} else {
//-- We're out of cameras
emit camerasChanged();
if(autoStream) {
emit streamChanged();
}
}
//-- Exit loop.
return;
}
}
}
}
}
//-----------------------------------------------------------------------------
//处理截屏事件
void
QGCCameraManager::_handleCaptureStatus(const mavlink_message_t &message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_camera_capture_status_t cap;
mavlink_msg_camera_capture_status_decode(&message, &cap);
pCamera->handleCaptureStatus(cap);
}
}
//-----------------------------------------------------------------------------
//处理存储信息
void
QGCCameraManager::_handleStorageInfo(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_storage_information_t st;
mavlink_msg_storage_information_decode(&message, &st);
pCamera->handleStorageInfo(st);
}
}
//-----------------------------------------------------------------------------
//处理相机设置
void
QGCCameraManager::_handleCameraSettings(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_camera_settings_t settings;
mavlink_msg_camera_settings_decode(&message, &settings);
pCamera->handleSettings(settings);
}
}
//-----------------------------------------------------------------------------
//处理相机参数应答
void
QGCCameraManager::_handleParamAck(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_param_ext_ack_t ack;
mavlink_msg_param_ext_ack_decode(&message, &ack);
pCamera->handleParamAck(ack);
}
}
//-----------------------------------------------------------------------------
//处理相机参数值
void
QGCCameraManager::_handleParamValue(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_param_ext_value_t value;
mavlink_msg_param_ext_value_decode(&message, &value);
pCamera->handleParamValue(value);
}
}
//-----------------------------------------------------------------------------
//处理相机视频流
void
QGCCameraManager::_handleVideoStreamInfo(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_video_stream_information_t streamInfo;
mavlink_msg_video_stream_information_decode(&message, &streamInfo);
pCamera->handleVideoInfo(&streamInfo);
}
}
//-----------------------------------------------------------------------------
//处理相机视频流状态
void
QGCCameraManager::_handleVideoStreamStatus(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_video_stream_status_t streamStatus;
mavlink_msg_video_stream_status_decode(&message, &streamStatus);
pCamera->handleVideoStatus(&streamStatus);
}
}
//-----------------------------------------------------------------------------
//处理电池状态
void
QGCCameraManager::_handleBatteryStatus(const mavlink_message_t& message)
{
QGCCameraControl* pCamera = _findCamera(message.compid);
if(pCamera) {
mavlink_battery_status_t batteryStatus;
mavlink_msg_battery_status_decode(&message, &batteryStatus);
pCamera->handleBatteryStatus(batteryStatus);
}
}
//-----------------------------------------------------------------------------
//请求相机信息
void
QGCCameraManager::_requestCameraInfo(int compID)
{
qCDebug(CameraManagerLog) << "_requestCameraInfo(" << compID << ")";
if(_vehicle) {
//发送mavlink请求
_vehicle->sendMavCommand(
compID, // target component
MAV_CMD_REQUEST_CAMERA_INFORMATION, // command id
false, // showError
1); // Do Request
}
}
//----------------------------------------------------------------------------------------
//激活手柄发生改变
void
QGCCameraManager::_activeJoystickChanged(Joystick* joystick)
{
qCDebug(CameraManagerLog) << "Joystick changed";
if(_activeJoystick) {
disconnect(_activeJoystick, &Joystick::stepZoom, this, &QGCCameraManager::_stepZoom);
disconnect(_activeJoystick, &Joystick::startContinuousZoom, this, &QGCCameraManager::_startZoom);
disconnect(_activeJoystick, &Joystick::stopContinuousZoom, this, &QGCCameraManager::_stopZoom);
disconnect(_activeJoystick, &Joystick::stepCamera, this, &QGCCameraManager::_stepCamera);
disconnect(_activeJoystick, &Joystick::stepStream, this, &QGCCameraManager::_stepStream);
disconnect(_activeJoystick, &Joystick::triggerCamera, this, &QGCCameraManager::_triggerCamera);
disconnect(_activeJoystick, &Joystick::startVideoRecord, this, &QGCCameraManager::_startVideoRecording);
disconnect(_activeJoystick, &Joystick::stopVideoRecord, this, &QGCCameraManager::_stopVideoRecording);
disconnect(_activeJoystick, &Joystick::toggleVideoRecord, this, &QGCCameraManager::_toggleVideoRecording);
}
_activeJoystick = joystick;
if(_activeJoystick) {
connect(_activeJoystick, &Joystick::stepZoom, this, &QGCCameraManager::_stepZoom);
connect(_activeJoystick, &Joystick::startContinuousZoom, this, &QGCCameraManager::_startZoom);
connect(_activeJoystick, &Joystick::stopContinuousZoom, this, &QGCCameraManager::_stopZoom);
connect(_activeJoystick, &Joystick::stepCamera, this, &QGCCameraManager::_stepCamera);
connect(_activeJoystick, &Joystick::stepStream, this, &QGCCameraManager::_stepStream);
connect(_activeJoystick, &Joystick::triggerCamera, this, &QGCCameraManager::_triggerCamera);
connect(_activeJoystick, &Joystick::startVideoRecord, this, &QGCCameraManager::_startVideoRecording);
connect(_activeJoystick, &Joystick::stopVideoRecord, this, &QGCCameraManager::_stopVideoRecording);
connect(_activeJoystick, &Joystick::toggleVideoRecord, this, &QGCCameraManager::_toggleVideoRecording);
}
}
//-----------------------------------------------------------------------------
//触发相机拍照
void
QGCCameraManager::_triggerCamera()
{
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->takePhoto();
}
}
//-----------------------------------------------------------------------------
//开始视频录像
void
QGCCameraManager::_startVideoRecording()
{
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->startVideo();
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_stopVideoRecording()
{
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->stopVideo();
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_toggleVideoRecording()
{
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->toggleVideo();
}
}
//-----------------------------------------------------------------------------
//聚焦
void
QGCCameraManager::_stepZoom(int direction)
{
if(_lastZoomChange.elapsed() > 40) {
_lastZoomChange.start();
qCDebug(CameraManagerLog) << "Step Camera Zoom" << direction;
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->stepZoom(direction);
}
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_startZoom(int direction)
{
qCDebug(CameraManagerLog) << "Start Camera Zoom" << direction;
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->startZoom(direction);
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_stopZoom()
{
qCDebug(CameraManagerLog) << "Stop Camera Zoom";
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
pCamera->stopZoom();
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_stepCamera(int direction)
{
if(_lastCameraChange.elapsed() > 1000) {
_lastCameraChange.start();
qCDebug(CameraManagerLog) << "Step Camera" << direction;
int c = _currentCamera + direction;
if(c < 0) c = _cameras.count() - 1;
if(c >= _cameras.count()) c = 0;
setCurrentCamera(c);
}
}
//-----------------------------------------------------------------------------
void
QGCCameraManager::_stepStream(int direction)
{
if(_lastCameraChange.elapsed() > 1000) {
_lastCameraChange.start();
QGCCameraControl* pCamera = currentCameraInstance();
if(pCamera) {
qCDebug(CameraManagerLog) << "Step Camera Stream" << direction;
int c = pCamera->currentStream() + direction;
if(c < 0) c = pCamera->streams()->count() - 1;
if(c >= pCamera->streams()->count()) c = 0;
pCamera->setCurrentStream(c);
}
}
}
二.QGCCameraIO
该类主要处理相机的参数请求,参数应答,写参数,保存参数写入状态,和一些计时器用来设置写入重试和参数请求次数。
/*!
* @file
* @brief Camera Controller
* @author Gus Grubba <[email protected]>
*
*/
/// @file
/// @brief MAVLink Camera API. Camera parameter handler.
/// @author Gus Grubba <[email protected]>
#pragma once
#include "QGCApplication.h"
#include <QLoggingCategory>
class QGCCameraControl;
Q_DECLARE_LOGGING_CATEGORY(CameraIOLog)
Q_DECLARE_LOGGING_CATEGORY(CameraIOLogVerbose)
//mavlink包
MAVPACKED(
typedef struct {
union {
float param_float;
double param_double;
int64_t param_int64;
uint64_t param_uint64;
int32_t param_int32;
uint32_t param_uint32;
int16_t param_int16;
uint16_t param_uint16;
int8_t param_int8;
uint8_t param_uint8;
uint8_t bytes[MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_VALUE_LEN];
};
uint8_t type;
}) param_ext_union_t;
//-----------------------------------------------------------------------------
/// Camera parameter handler.
/// 相机参数处理器
class QGCCameraParamIO : public QObject
{
public:
QGCCameraParamIO(QGCCameraControl* control, Fact* fact, Vehicle* vehicle);
void handleParamAck (const mavlink_param_ext_ack_t& ack); //处理相机参数应答
void handleParamValue (const mavlink_param_ext_value_t& value); //处理相机参数值
void setParamRequest (); //设置参数请求
bool paramDone () const { return _done; } //参数是否完成
void paramRequest (bool reset = true); //参数请求
void sendParameter (bool updateUI = false); //发送参数
QStringList optNames; //选项名
QVariantList optVariants; //选项值
private slots:
void _paramWriteTimeout (); //参数写入超时
void _paramRequestTimeout (); //参数请求超时
void _factChanged (QVariant value);
void _containerRawValueChanged (const QVariant value);
private:
void _sendParameter (); //发送参数
QVariant _valueFromMessage (const char* value, uint8_t param_type); //从消息中提取值
private:
QGCCameraControl* _control;
Fact* _fact;
Vehicle* _vehicle;
int _sentRetries; //发送尝试次数
int _requestRetries; //请求尝试次数
bool _paramRequestReceived; //参数请求是否收到
QTimer _paramWriteTimer; //写参数计时器
QTimer _paramRequestTimer; //请求参数计时器
bool _done; //完成状态
bool _updateOnSet;
MAV_PARAM_EXT_TYPE _mavParamType; //mavlink参数类型
MAVLinkProtocol* _pMavlink; //mavlink实例
bool _forceUIUpdate; //是否强制ui重绘
};
/*!
* @file
* @brief Camera Controller
* @author Gus Grubba <[email protected]>
*
*/
#include "QGCCameraControl.h"
#include "QGCCameraIO.h"
QGC_LOGGING_CATEGORY(CameraIOLog, "CameraIOLog")
QGC_LOGGING_CATEGORY(CameraIOLogVerbose, "CameraIOLogVerbose")
//-----------------------------------------------------------------------------
//QGCCameraParamIO构造
QGCCameraParamIO::QGCCameraParamIO(QGCCameraControl *control, Fact* fact, Vehicle *vehicle)
: QObject(control)
, _control(control)
, _fact(fact)
, _vehicle(vehicle)
, _sentRetries(0)
, _requestRetries(0)
, _done(false)
, _updateOnSet(false)
, _forceUIUpdate(false)
{
//初始化变量
//实例交给C++
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
//设置定时器单次执行延时3s
_paramWriteTimer.setSingleShot(true);
_paramWriteTimer.setInterval(3000);
_paramRequestTimer.setSingleShot(true);
_paramRequestTimer.setInterval(3500);
if(_fact->writeOnly()) {
//-- Write mode is always "done" as it won't ever read
_done = true;
} else {
connect(&_paramRequestTimer, &QTimer::timeout, this, &QGCCameraParamIO::_paramRequestTimeout);
}
//绑定函数
connect(&_paramWriteTimer, &QTimer::timeout, this, &QGCCameraParamIO::_paramWriteTimeout);
connect(_fact, &Fact::rawValueChanged, this, &QGCCameraParamIO::_factChanged);
connect(_fact, &Fact::_containerRawValueChanged, this, &QGCCameraParamIO::_containerRawValueChanged);
_pMavlink = qgcApp()->toolbox()->mavlinkProtocol();
//-- TODO: Even though we don't use anything larger than 32-bit, this should
// probably be updated.
//尽管我们没有使用超过32位的数据,但这可能需要更新。
switch (_fact->type()) {
case FactMetaData::valueTypeUint8:
case FactMetaData::valueTypeBool:
_mavParamType = MAV_PARAM_EXT_TYPE_UINT8;
break;
case FactMetaData::valueTypeInt8:
_mavParamType = MAV_PARAM_EXT_TYPE_INT8;
break;
case FactMetaData::valueTypeUint16:
_mavParamType = MAV_PARAM_EXT_TYPE_UINT16;
break;
case FactMetaData::valueTypeInt16:
_mavParamType = MAV_PARAM_EXT_TYPE_INT16;
break;
case FactMetaData::valueTypeUint32:
_mavParamType = MAV_PARAM_EXT_TYPE_UINT32;
break;
case FactMetaData::valueTypeUint64:
_mavParamType = MAV_PARAM_EXT_TYPE_UINT64;
break;
case FactMetaData::valueTypeInt64:
_mavParamType = MAV_PARAM_EXT_TYPE_INT64;
break;
case FactMetaData::valueTypeFloat:
_mavParamType = MAV_PARAM_EXT_TYPE_REAL32;
break;
case FactMetaData::valueTypeDouble:
_mavParamType = MAV_PARAM_EXT_TYPE_REAL64;
break;
//-- String and custom are the same for now
case FactMetaData::valueTypeString:
case FactMetaData::valueTypeCustom:
_mavParamType = MAV_PARAM_EXT_TYPE_CUSTOM;
break;
default:
qWarning() << "Unsupported fact type" << _fact->type() << "for" << _fact->name();
case FactMetaData::valueTypeInt32:
_mavParamType = MAV_PARAM_EXT_TYPE_INT32;
break;
}
}
//-----------------------------------------------------------------------------
void
QGCCameraParamIO::setParamRequest()
{
if(!_fact->writeOnly()) {
_paramRequestReceived = false;
_requestRetries = 0;
_paramRequestTimer.start();
}
}
//-----------------------------------------------------------------------------
void
QGCCameraParamIO::_factChanged(QVariant value)
{
if(!_forceUIUpdate) {
Q_UNUSED(value);
qCDebug(CameraIOLog) << "UI Fact" << _fact->name() << "changed to" << value;
_control->factChanged(_fact);
}
}
//-----------------------------------------------------------------------------
void
QGCCameraParamIO::_containerRawValueChanged(const QVariant value)
{
if(!_fact->readOnly()) {
Q_UNUSED(value);
qCDebug(CameraIOLog) << "Update Fact from camera" << _fact->name();
_sentRetries = 0;
_sendParameter();
}
}
//-----------------------------------------------------------------------------
void
QGCCameraParamIO::sendParameter(bool updateUI)
{
qCDebug(CameraIOLog) << "Send Fact" << _fact->name();
_sentRetries = 0;
_updateOnSet = updateUI;
_sendParameter();
}
//-----------------------------------------------------------------------------
//发送参数
void
QGCCameraParamIO::_sendParameter()
{
//获取mavlink实例
WeakLinkInterfacePtr weakLink = _vehicle->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
//如果有效
SharedLinkInterfacePtr sharedLink = weakLink.lock();
//构造mavlink_param_ext_set_t
mavlink_param_ext_set_t p;
//初始化mavlink_param_ext_set_t
memset(&p, 0, sizeof(mavlink_param_ext_set_t));
//
param_ext_union_t union_value;
mavlink_message_t msg;
//得到factType
FactMetaData::ValueType_t factType = _fact->type();
p.param_type = _mavParamType;
//根据type进行不同type的赋值操作
switch (factType) {
case FactMetaData::valueTypeUint8:
case FactMetaData::valueTypeBool:
union_value.param_uint8 = static_cast<uint8_t>(_fact->rawValue().toUInt());
break;
case FactMetaData::valueTypeInt8:
union_value.param_int8 = static_cast<int8_t>(_fact->rawValue().toInt());
break;
case FactMetaData::valueTypeUint16:
union_value.param_uint16 = static_cast<uint16_t>(_fact->rawValue().toUInt());
break;
case FactMetaData::valueTypeInt16:
union_value.param_int16 = static_cast<int16_t>(_fact->rawValue().toInt());
break;
case FactMetaData::valueTypeUint32:
union_value.param_uint32 = static_cast<uint32_t>(_fact->rawValue().toUInt());
break;
case FactMetaData::valueTypeInt64:
union_value.param_int64 = static_cast<int64_t>(_fact->rawValue().toLongLong());
break;
case FactMetaData::valueTypeUint64:
union_value.param_uint64 = static_cast<uint64_t>(_fact->rawValue().toULongLong());
break;
case FactMetaData::valueTypeFloat:
union_value.param_float = _fact->rawValue().toFloat();
break;
case FactMetaData::valueTypeDouble:
union_value.param_double = _fact->rawValue().toDouble();
break;
//-- String and custom are the same for now
case FactMetaData::valueTypeString:
case FactMetaData::valueTypeCustom:
{
//如果是自定类型转为byte数组
QByteArray custom = _fact->rawValue().toByteArray();
memcpy(union_value.bytes, custom.data(), static_cast<size_t>(std::max(custom.size(), MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_VALUE_LEN)));
}
break;
default:
qCritical() << "Unsupported fact type" << factType << "for" << _fact->name();
case FactMetaData::valueTypeInt32:
union_value.param_int32 = static_cast<int32_t>(_fact->rawValue().toInt());
break;
}
//将union_value的值复制到p.param_value
memcpy(&p.param_value[0], &union_value.bytes[0], MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_VALUE_LEN);
p.target_system = static_cast<uint8_t>(_vehicle->id());
p.target_component = static_cast<uint8_t>(_control->compID());
strncpy(p.param_id, _fact->name().toStdString().c_str(), MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_ID_LEN);
//发送mavlink消息
mavlink_msg_param_ext_set_encode_chan(
static_cast<uint8_t>(_pMavlink->getSystemId()),
static_cast<uint8_t>(_pMavlink->getComponentId()),
sharedLink->mavlinkChannel(),
&msg,
&p);
_vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
_paramWriteTimer.start();
}
//-----------------------------------------------------------------------------
//写参数的定时器到时函数
void
QGCCameraParamIO::_paramWriteTimeout()
{
if(++_sentRetries > 3) {
qCWarning(CameraIOLog) << "No response for param set:" << _fact->name();
_updateOnSet = false;
} else {
//-- Send it again
qCDebug(CameraIOLog) << "Param set retry:" << _fact->name() << _sentRetries;
_sendParameter();
_paramWriteTimer.start();
}
}
//-----------------------------------------------------------------------------
//处理参数响应
void
QGCCameraParamIO::handleParamAck(const mavlink_param_ext_ack_t& ack)
{
//关闭写入参数定时器
_paramWriteTimer.stop();
//如果参数结果是sccept(接受)
if(ack.param_result == PARAM_ACK_ACCEPTED) {
//根绝type和value获取数据
QVariant val = _valueFromMessage(ack.param_value, ack.param_type);
//如果当前的fact的值与该值不等
if(_fact->rawValue() != val) {
//获取是否包含
_fact->_containerSetRawValue(val);
if(_updateOnSet) {
_updateOnSet = false;
_control->factChanged(_fact);
}
}
} else if(ack.param_result == PARAM_ACK_IN_PROGRESS) {
//-- Wait a bit longer for this one 正在处理中
qCDebug(CameraIOLogVerbose) << "Param set in progress:" << _fact->name();
_paramWriteTimer.start();
} else {
if(ack.param_result == PARAM_ACK_FAILED) {
if(++_sentRetries < 3) {
//-- Try again
qCWarning(CameraIOLog) << "Param set failed:" << _fact->name() << _sentRetries;
_paramWriteTimer.start();
}
return;
} else if(ack.param_result == PARAM_ACK_VALUE_UNSUPPORTED) {
//参数设置不支持
qCWarning(CameraIOLog) << "Param set unsuported:" << _fact->name();
}
//-- If UI changed and value was not set, restore UI
QVariant val = _valueFromMessage(ack.param_value, ack.param_type);
if(_fact->rawValue() != val) {
if(_control->validateParameter(_fact, val)) {
_fact->_containerSetRawValue(val);
}
}
}
}
//-----------------------------------------------------------------------------
//处理参数值
void
QGCCameraParamIO::handleParamValue(const mavlink_param_ext_value_t& value)
{
//请求计时器停止
_paramRequestTimer.stop();
QVariant newValue = _valueFromMessage(value.param_value, value.param_type);
if(_control->incomingParameter(_fact, newValue)) {
_fact->_containerSetRawValue(newValue);
}
_paramRequestReceived = true;
if(_forceUIUpdate) {
emit _fact->rawValueChanged(_fact->rawValue());
emit _fact->valueChanged(_fact->rawValue());
_forceUIUpdate = false;
}
if(!_done) {
_done = true;
_control->_paramDone();
}
qCDebug(CameraIOLog) << QString("handleParamValue() %1 %2").arg(_fact->name()).arg(_fact->rawValueString());
}
//-----------------------------------------------------------------------------
QVariant
QGCCameraParamIO::_valueFromMessage(const char* value, uint8_t param_type)
{
QVariant var;
param_ext_union_t u;
memcpy(u.bytes, value, MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_VALUE_LEN);
switch (param_type) {
case MAV_PARAM_EXT_TYPE_REAL32:
var = QVariant(u.param_float);
break;
case MAV_PARAM_EXT_TYPE_UINT8:
var = QVariant(u.param_uint8);
break;
case MAV_PARAM_EXT_TYPE_INT8:
var = QVariant(u.param_int8);
break;
case MAV_PARAM_EXT_TYPE_UINT16:
var = QVariant(u.param_uint16);
break;
case MAV_PARAM_EXT_TYPE_INT16:
var = QVariant(u.param_int16);
break;
case MAV_PARAM_EXT_TYPE_UINT32:
var = QVariant(u.param_uint32);
break;
case MAV_PARAM_EXT_TYPE_INT32:
var = QVariant(u.param_int32);
break;
case MAV_PARAM_EXT_TYPE_UINT64:
var = QVariant(static_cast<qulonglong>(u.param_uint64));
break;
case MAV_PARAM_EXT_TYPE_INT64:
var = QVariant(static_cast<qulonglong>(u.param_int64));
break;
case MAV_PARAM_EXT_TYPE_CUSTOM:
var = QVariant(QByteArray(value, MAVLINK_MSG_PARAM_EXT_SET_FIELD_PARAM_VALUE_LEN));
break;
default:
var = QVariant(0);
qCritical() << "Invalid param_type used for camera setting:" << param_type;
}
return var;
}
//-----------------------------------------------------------------------------
void
QGCCameraParamIO::_paramRequestTimeout()
{
if(++_requestRetries > 3) {
qCWarning(CameraIOLog) << "No response for param request:" << _fact->name();
if(!_done) {
_done = true;
_control->_paramDone();
}
} else {
//-- Request it again
qCDebug(CameraIOLog) << "Param request retry:" << _fact->name();
paramRequest(false);
_paramRequestTimer.start();
}
}
//-----------------------------------------------------------------------------
void
QGCCameraParamIO::paramRequest(bool reset)
{
//-- If it's write only, we don't request it.
if(_fact->writeOnly()) {
if(!_done) {
_done = true;
_control->_paramDone();
}
return;
}
if(reset) {
_requestRetries = 0;
_forceUIUpdate = true;
}
qCDebug(CameraIOLog) << "Request parameter:" << _fact->name();
WeakLinkInterfacePtr weakLink = _vehicle->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
SharedLinkInterfacePtr sharedLink = weakLink.lock();
char param_id[MAVLINK_MSG_PARAM_EXT_REQUEST_READ_FIELD_PARAM_ID_LEN + 1];
memset(param_id, 0, sizeof(param_id));
strncpy(param_id, _fact->name().toStdString().c_str(), MAVLINK_MSG_PARAM_EXT_REQUEST_READ_FIELD_PARAM_ID_LEN);
mavlink_message_t msg;
mavlink_msg_param_ext_request_read_pack_chan(
static_cast<uint8_t>(_pMavlink->getSystemId()),
static_cast<uint8_t>(_pMavlink->getComponentId()),
sharedLink->mavlinkChannel(),
&msg,
static_cast<uint8_t>(_vehicle->id()),
static_cast<uint8_t>(_control->compID()),
param_id,
-1);
_vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
}
_paramRequestTimer.start();
}
三.QGCCameraControl
这个类的中文件中还定义了其他几个类分别是视频流类,主要处理相机的mavlink的一些操作,代码太多,并且没有需要特别指出的地方所以,这里不贴出了。