Newer
Older
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
dogmaphobic
committed
#include "QGCLoggingCategory.h"
#include <QTimer>
#include <QDebug>
#include <QFile>
#include <string.h>
// FIXME: Hack to work around clean headers
#include "FirmwarePlugin/PX4/px4_custom_mode.h"
QGC_LOGGING_CATEGORY(MockLinkLog, "MockLinkLog")
QGC_LOGGING_CATEGORY(MockLinkVerboseLog, "MockLinkVerboseLog")
/// @file
/// @brief Mock implementation of a Link.
///
/// @author Don Gagne <don@thegagnes.com>
// Vehicle position is set close to default Gazebo vehicle location. This allows for multi-vehicle
// testing of a gazebo vehicle and a mocklink vehicle
#if 1
double MockLink::_defaultVehicleLatitude = 47.397;
double MockLink::_defaultVehicleLongitude = 8.5455;
double MockLink::_defaultVehicleAltitude = 488.056;
#else
double MockLink::_defaultVehicleLatitude = 47.6333022928789;
double MockLink::_defaultVehicleLongitude = -122.08833157994995;
double MockLink::_defaultVehicleAltitude = 19.0;
#endif
int MockLink::_nextVehicleSystemId = 128;
const char* MockLink::_failParam = "COM_FLTMODE6";
const char* MockConfiguration::_firmwareTypeKey = "FirmwareType";
const char* MockConfiguration::_vehicleTypeKey = "VehicleType";
const char* MockConfiguration::_sendStatusTextKey = "SendStatusText";
const char* MockConfiguration::_highLatencyKey = "HighLatency";
const char* MockConfiguration::_failureModeKey = "FailureMode";
MockLink::MockLink(SharedLinkConfigurationPointer& config)
: LinkInterface (config)
, _missionItemHandler (this, qgcApp()->toolbox()->mavlinkProtocol())
, _name ("MockLink")
, _connected (false)
, _mavlinkChannel (0)
, _vehicleSystemId (_nextVehicleSystemId++)
, _vehicleComponentId (MAV_COMP_ID_AUTOPILOT1)
, _inNSH (false)
, _mavlinkStarted (true)
, _mavBaseMode (MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_CUSTOM_MODE_ENABLED)
, _mavState (MAV_STATE_STANDBY)
, _firmwareType (MAV_AUTOPILOT_PX4)
, _vehicleType (MAV_TYPE_QUADROTOR)
, _vehicleLatitude (_defaultVehicleLatitude + ((_vehicleSystemId - 128) * 0.0001)) // Slight offset for each vehicle
, _vehicleLongitude (_defaultVehicleLongitude + ((_vehicleSystemId - 128) * 0.0001))
, _vehicleAltitude (_defaultVehicleAltitude)
, _sendStatusText (false)
, _apmSendHomePositionOnEmptyList (false)
, _failureMode (MockConfiguration::FailNone)
, _sendHomePositionDelayCount (10) // No home position for 4 seconds
, _sendGPSPositionDelayCount (100) // No gps lock for 5 seconds
, _currentParamRequestListParamIndex (-1)
, _logDownloadCurrentOffset (0)
, _logDownloadBytesRemaining (0)
MockConfiguration* mockConfig = qobject_cast<MockConfiguration*>(_config.data());
_firmwareType = mockConfig->firmwareType();
_vehicleType = mockConfig->vehicleType();
_sendStatusText = mockConfig->sendStatusText();
_failureMode = mockConfig->failureMode();
union px4_custom_mode px4_cm;
px4_cm.data = 0;
px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL;
_mavCustomMode = px4_cm.data;
_fileServer = new MockLinkFileServer(_vehicleSystemId, _vehicleComponentId, this);
Q_CHECK_PTR(_fileServer);
_adsbVehicleCoordinate = QGeoCoordinate(_vehicleLatitude, _vehicleLongitude).atDistanceAndAzimuth(1000, _adsbAngle);
_adsbVehicleCoordinate.setAltitude(100);
if (!_logDownloadFilename.isEmpty()) {
QFile::remove(_logDownloadFilename);
}
bool MockLink::_connect(void)
if (!_connected) {
_connected = true;
_mavlinkChannel = qgcApp()->toolbox()->linkManager()->_reserveMavlinkChannel();
if (_mavlinkChannel == 0) {
qWarning() << "No mavlink channels available";
return false;
}
// MockLinks use Mavlink 2.0
mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(_mavlinkChannel);
mavlinkStatus->flags &= ~MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
dogmaphobic
committed
if (_mavlinkChannel != 0) {
qgcApp()->toolbox()->linkManager()->_freeMavlinkChannel(_mavlinkChannel);
}
QTimer timer1HzTasks;
QTimer timer10HzTasks;
QTimer timer500HzTasks;
dogmaphobic
committed
QObject::connect(&timer1HzTasks, &QTimer::timeout, this, &MockLink::_run1HzTasks);
QObject::connect(&timer10HzTasks, &QTimer::timeout, this, &MockLink::_run10HzTasks);
QObject::connect(&timer500HzTasks, &QTimer::timeout, this, &MockLink::_run500HzTasks);
dogmaphobic
committed
timer1HzTasks.start(1000);
timer10HzTasks.start(100);
timer500HzTasks.start(2);
dogmaphobic
committed
dogmaphobic
committed
QObject::disconnect(&timer1HzTasks, &QTimer::timeout, this, &MockLink::_run1HzTasks);
QObject::disconnect(&timer10HzTasks, &QTimer::timeout, this, &MockLink::_run10HzTasks);
QObject::disconnect(&timer500HzTasks, &QTimer::timeout, this, &MockLink::_run500HzTasks);
}
void MockLink::_run1HzTasks(void)
{
if (_mavlinkStarted && _connected) {
if (_highLatency) {
_sendHighLatency2();
_sendADSBVehicles();
if (!qgcApp()->runningUnitTests()) {
// Sending RC Channels during unit test breaks RC tests which does it's own RC simulation
_sendRCChannels();
}
if (_sendHomePositionDelayCount > 0) {
// We delay home position for better testing
_sendHomePositionDelayCount--;
} else {
_sendHomePosition();
}
if (_sendStatusText) {
_sendStatusText = false;
_sendStatusTextMessages();
}
}
}
void MockLink::_run10HzTasks(void)
{
if (_mavlinkStarted && _connected) {
if (_sendGPSPositionDelayCount > 0) {
// We delay gps position for better testing
_sendGPSPositionDelayCount--;
} else {
_sendGpsRawInt();
}
if (_mavlinkStarted && _connected) {
}
}
void MockLink::_loadParams(void)
{
QFile paramFile;
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
if (_vehicleType == MAV_TYPE_FIXED_WING) {
paramFile.setFileName(":/FirmwarePlugin/APM/Plane.OfflineEditing.params");
} else if (_vehicleType == MAV_TYPE_SUBMARINE ) {
paramFile.setFileName(":/MockLink/APMArduSubMockLink.params");
} else if (_vehicleType == MAV_TYPE_GROUND_ROVER ) {
paramFile.setFileName(":/FirmwarePlugin/APM/Rover.OfflineEditing.params");
paramFile.setFileName(":/FirmwarePlugin/APM/Copter.OfflineEditing.params");
paramFile.setFileName(":/MockLink/PX4MockLink.params");
dogmaphobic
committed
bool success = paramFile.open(QFile::ReadOnly);
Q_UNUSED(success);
Q_ASSERT(success);
dogmaphobic
committed
dogmaphobic
committed
while (!paramStream.atEnd()) {
QString line = paramStream.readLine();
dogmaphobic
committed
if (line.startsWith("#")) {
continue;
}
dogmaphobic
committed
QStringList paramData = line.split("\t");
Q_ASSERT(paramData.count() == 5);
dogmaphobic
committed
QString paramName = paramData.at(2);
QString valStr = paramData.at(3);
uint paramType = paramData.at(4).toUInt();
dogmaphobic
committed
case MAV_PARAM_TYPE_REAL32:
paramValue = QVariant(valStr.toFloat());
break;
case MAV_PARAM_TYPE_UINT32:
paramValue = QVariant(valStr.toUInt());
break;
case MAV_PARAM_TYPE_INT32:
paramValue = QVariant(valStr.toInt());
break;
case MAV_PARAM_TYPE_UINT16:
paramValue = QVariant((quint16)valStr.toUInt());
break;
case MAV_PARAM_TYPE_INT16:
paramValue = QVariant((qint16)valStr.toInt());
break;
case MAV_PARAM_TYPE_UINT8:
paramValue = QVariant((quint8)valStr.toUInt());
break;
case MAV_PARAM_TYPE_INT8:
paramValue = QVariant((qint8)valStr.toUInt());
break;
default:
qCritical() << "Unknown type" << paramType;
paramValue = QVariant(valStr.toInt());
break;
dogmaphobic
committed
qCDebug(MockLinkVerboseLog) << "Loading param" << paramName << paramValue;
dogmaphobic
committed
_mapParamName2Value[compId][paramName] = paramValue;
_mapParamName2MavParamType[compId][paramName] = static_cast<MAV_PARAM_TYPE>(paramType);
}
}
void MockLink::_sendHeartBeat(void)
{
mavlink_message_t msg;
mavlink_msg_heartbeat_pack_chan(_vehicleSystemId,
_vehicleComponentId,
&msg,
_vehicleType, // MAV_TYPE
_firmwareType, // MAV_AUTOPILOT
_mavBaseMode, // MAV_MODE
_mavCustomMode, // custom mode
_mavState); // MAV_STATE
void MockLink::_sendHighLatency2(void)
{
mavlink_message_t msg;
union px4_custom_mode px4_cm;
px4_cm.data = _mavCustomMode;
qDebug() << "Sending" << _mavCustomMode;
mavlink_msg_high_latency2_pack_chan(_vehicleSystemId,
_vehicleComponentId,
_mavlinkChannel,
&msg,
0, // timestamp
_vehicleType, // MAV_TYPE
_firmwareType, // MAV_AUTOPILOT
px4_cm.custom_mode_hl, // custom_mode
(int32_t)(_vehicleLatitude * 1E7),
(int32_t)(_vehicleLongitude * 1E7),
(int16_t)_vehicleAltitude,
(int16_t)_vehicleAltitude, // target_altitude,
0, // heading
0, // target_heading
0, // target_distance
0, // throttle
0, // airspeed
0, // airspeed_sp
0, // groundspeed
0, // windspeed,
0, // wind_heading
UINT8_MAX, // eph not known
UINT8_MAX, // epv not known
0, // temperature_air
0, // climb_rate
-1, // battery, do not use?
0, // wp_num
0, // failure_flags
0, 0, 0); // custom0, custom1, custom2
respondWithMavlinkMessage(msg);
}
void MockLink::_sendSysStatus(void)
{
if(_batteryRemaining > 50) {
_batteryRemaining = static_cast<int8_t>(100 - (_runningTime.elapsed() / 1000));
}
mavlink_message_t msg;
mavlink_msg_sys_status_pack_chan(
_vehicleSystemId,
_vehicleComponentId,
static_cast<uint8_t>(_mavlinkChannel),
&msg,
0, // onboard_control_sensors_present
0, // onboard_control_sensors_enabled
0, // onboard_control_sensors_health
250, // load
4200 * 4, // voltage_battery
8000, // current_battery
_batteryRemaining, // battery_remaining
0,0,0,0,0,0);
respondWithMavlinkMessage(msg);
}
void MockLink::_sendVibration(void)
{
mavlink_message_t msg;
mavlink_msg_vibration_pack_chan(_vehicleSystemId,
_vehicleComponentId,
&msg,
0, // time_usec
50.5, // vibration_x,
10.5, // vibration_y,
60.0, // vibration_z,
1, // clipping_0
2, // clipping_0
3); // clipping_0
void MockLink::respondWithMavlinkMessage(const mavlink_message_t& msg)
{
uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
int cBuffer = mavlink_msg_to_send_buffer(buffer, &msg);
QByteArray bytes((char *)buffer, cBuffer);
emit bytesReceived(this, bytes);
}
/// @brief Called when QGC wants to write bytes to the MAV
void MockLink::_writeBytes(const QByteArray bytes)
{
if (_inNSH) {
_handleIncomingNSHBytes(bytes.constData(), bytes.count());
} else {
if (bytes.startsWith(QByteArray("\r\r\r"))) {
_inNSH = true;
_handleIncomingNSHBytes(&bytes.constData()[3], bytes.count() - 3);
}
dogmaphobic
committed
_handleIncomingMavlinkBytes((uint8_t *)bytes.constData(), bytes.count());
}
}
/// @brief Handle incoming bytes which are meant to be interpreted by the NuttX shell
void MockLink::_handleIncomingNSHBytes(const char* bytes, int cBytes)
{
Q_UNUSED(cBytes);
dogmaphobic
committed
// Drop back out of NSH
if (cBytes == 4 && bytes[0] == '\r' && bytes[1] == '\r' && bytes[2] == '\r') {
_inNSH = false;
return;
}
if (cBytes > 0) {
qDebug() << "NSH:" << (const char*)bytes;
dogmaphobic
committed
#if 0
// MockLink not quite ready to handle this correctly yet
if (strncmp(bytes, "sh /etc/init.d/rc.usb\n", cBytes) == 0) {
// This is the mavlink start command
_mavlinkStarted = true;
}
}
}
/// @brief Handle incoming bytes which are meant to be handled by the mavlink protocol
void MockLink::_handleIncomingMavlinkBytes(const uint8_t* bytes, int cBytes)
{
mavlink_message_t msg;
mavlink_status_t comm;
dogmaphobic
committed
if (!mavlink_parse_char(_mavlinkChannel, bytes[i], &msg, &comm)) {
if (_missionItemHandler.handleMessage(msg)) {
dogmaphobic
committed
case MAVLINK_MSG_ID_HEARTBEAT:
_handleHeartBeat(msg);
break;
dogmaphobic
committed
case MAVLINK_MSG_ID_PARAM_REQUEST_LIST:
_handleParamRequestList(msg);
break;
dogmaphobic
committed
case MAVLINK_MSG_ID_SET_MODE:
_handleSetMode(msg);
break;
dogmaphobic
committed
case MAVLINK_MSG_ID_PARAM_SET:
_handleParamSet(msg);
break;
dogmaphobic
committed
case MAVLINK_MSG_ID_PARAM_REQUEST_READ:
_handleParamRequestRead(msg);
break;
case MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL:
_handleFTP(msg);
break;
case MAVLINK_MSG_ID_COMMAND_LONG:
_handleCommandLong(msg);
break;
dogmaphobic
committed
case MAVLINK_MSG_ID_MANUAL_CONTROL:
_handleManualControl(msg);
break;
case MAVLINK_MSG_ID_LOG_REQUEST_LIST:
_handleLogRequestList(msg);
break;
case MAVLINK_MSG_ID_LOG_REQUEST_DATA:
_handleLogRequestData(msg);
break;
}
}
}
void MockLink::_handleHeartBeat(const mavlink_message_t& msg)
{
Q_UNUSED(msg);
qCDebug(MockLinkLog) << "Heartbeat";
}
void MockLink::_handleSetMode(const mavlink_message_t& msg)
{
mavlink_set_mode_t request;
mavlink_msg_set_mode_decode(&msg, &request);
dogmaphobic
committed
Q_ASSERT(request.target_system == _vehicleSystemId);
dogmaphobic
committed
_mavBaseMode = request.base_mode;
_mavCustomMode = request.custom_mode;
}
void MockLink::_handleManualControl(const mavlink_message_t& msg)
{
mavlink_manual_control_t manualControl;
mavlink_msg_manual_control_decode(&msg, &manualControl);
qCDebug(MockLinkLog) << "MANUAL_CONTROL" << manualControl.x << manualControl.y << manualControl.z << manualControl.r;
void MockLink::_setParamFloatUnionIntoMap(int componentId, const QString& paramName, float paramFloat)
{
mavlink_param_union_t valueUnion;
dogmaphobic
committed
Q_ASSERT(_mapParamName2Value.contains(componentId));
Q_ASSERT(_mapParamName2Value[componentId].contains(paramName));
dogmaphobic
committed
valueUnion.param_float = paramFloat;
dogmaphobic
committed
MAV_PARAM_TYPE paramType = _mapParamName2MavParamType[componentId][paramName];
dogmaphobic
committed
dogmaphobic
committed
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
case MAV_PARAM_TYPE_REAL32:
paramVariant = QVariant::fromValue(valueUnion.param_float);
break;
case MAV_PARAM_TYPE_UINT32:
paramVariant = QVariant::fromValue(valueUnion.param_uint32);
break;
case MAV_PARAM_TYPE_INT32:
paramVariant = QVariant::fromValue(valueUnion.param_int32);
break;
case MAV_PARAM_TYPE_UINT16:
paramVariant = QVariant::fromValue(valueUnion.param_uint16);
break;
case MAV_PARAM_TYPE_INT16:
paramVariant = QVariant::fromValue(valueUnion.param_int16);
break;
case MAV_PARAM_TYPE_UINT8:
paramVariant = QVariant::fromValue(valueUnion.param_uint8);
break;
case MAV_PARAM_TYPE_INT8:
paramVariant = QVariant::fromValue(valueUnion.param_int8);
break;
default:
qCritical() << "Invalid parameter type" << paramType;
paramVariant = QVariant::fromValue(valueUnion.param_int32);
break;
dogmaphobic
committed
qCDebug(MockLinkLog) << "_setParamFloatUnionIntoMap" << paramName << paramVariant;
_mapParamName2Value[componentId][paramName] = paramVariant;
/// Convert from a parameter variant to the float value from mavlink_param_union_t
float MockLink::_floatUnionForParam(int componentId, const QString& paramName)
mavlink_param_union_t valueUnion;
dogmaphobic
committed
Q_ASSERT(_mapParamName2Value.contains(componentId));
Q_ASSERT(_mapParamName2Value[componentId].contains(paramName));
dogmaphobic
committed
MAV_PARAM_TYPE paramType = _mapParamName2MavParamType[componentId][paramName];
QVariant paramVar = _mapParamName2Value[componentId][paramName];
dogmaphobic
committed
valueUnion.param_float = paramVar.toFloat();
dogmaphobic
committed
case MAV_PARAM_TYPE_UINT32:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = paramVar.toUInt();
} else {
valueUnion.param_uint32 = paramVar.toUInt();
}
break;
dogmaphobic
committed
case MAV_PARAM_TYPE_INT32:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = paramVar.toInt();
} else {
valueUnion.param_int32 = paramVar.toInt();
}
break;
dogmaphobic
committed
case MAV_PARAM_TYPE_UINT16:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = paramVar.toUInt();
} else {
valueUnion.param_uint16 = paramVar.toUInt();
}
break;
dogmaphobic
committed
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
case MAV_PARAM_TYPE_INT16:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = paramVar.toInt();
} else {
valueUnion.param_int16 = paramVar.toInt();
}
break;
case MAV_PARAM_TYPE_UINT8:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = paramVar.toUInt();
} else {
valueUnion.param_uint8 = paramVar.toUInt();
}
break;
case MAV_PARAM_TYPE_INT8:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = (unsigned char)paramVar.toChar().toLatin1();
} else {
valueUnion.param_int8 = (unsigned char)paramVar.toChar().toLatin1();
}
break;
default:
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
valueUnion.param_float = paramVar.toInt();
} else {
valueUnion.param_int32 = paramVar.toInt();
}
qCritical() << "Invalid parameter type" << paramType;
dogmaphobic
committed
return valueUnion.param_float;
}
void MockLink::_handleParamRequestList(const mavlink_message_t& msg)
{
if (_failureMode == MockConfiguration::FailParamNoReponseToRequestList) {
return;
}
dogmaphobic
committed
mavlink_msg_param_request_list_decode(&msg, &request);
dogmaphobic
committed
Q_ASSERT(request.target_system == _vehicleSystemId);
Q_ASSERT(request.target_component == MAV_COMP_ID_ALL);
// Start the worker routine
_currentParamRequestListComponentIndex = 0;
_currentParamRequestListParamIndex = 0;
}
/// Sends the next parameter to the vehicle
void MockLink::_paramRequestListWorker(void)
{
if (_currentParamRequestListComponentIndex == -1) {
// Initial request complete
return;
}
int componentId = _mapParamName2Value.keys()[_currentParamRequestListComponentIndex];
int cParameters = _mapParamName2Value[componentId].count();
QString paramName = _mapParamName2Value[componentId].keys()[_currentParamRequestListParamIndex];
if ((_failureMode == MockConfiguration::FailMissingParamOnInitialReqest || _failureMode == MockConfiguration::FailMissingParamOnAllRequests) && paramName == _failParam) {
qCDebug(MockLinkLog) << "Skipping param send:" << paramName;
} else {
char paramId[MAVLINK_MSG_ID_PARAM_VALUE_LEN];
mavlink_message_t responseMsg;
Q_ASSERT(_mapParamName2Value[componentId].contains(paramName));
MAV_PARAM_TYPE paramType = _mapParamName2MavParamType[componentId][paramName];
Q_ASSERT(paramName.length() <= MAVLINK_MSG_ID_PARAM_VALUE_LEN);
strncpy(paramId, paramName.toLocal8Bit().constData(), MAVLINK_MSG_ID_PARAM_VALUE_LEN);
qCDebug(MockLinkLog) << "Sending msg_param_value" << componentId << paramId << paramType << _mapParamName2Value[componentId][paramId];
mavlink_msg_param_value_pack_chan(_vehicleSystemId,
componentId, // component id
&responseMsg, // Outgoing message
paramId, // Parameter name
_floatUnionForParam(componentId, paramName), // Parameter value
paramType, // MAV_PARAM_TYPE
cParameters, // Total number of parameters
_currentParamRequestListParamIndex); // Index of this parameter
// Move to next param index
if (++_currentParamRequestListParamIndex >= cParameters) {
// We've sent the last parameter for this component, move to next component
if (++_currentParamRequestListComponentIndex >= _mapParamName2Value.keys().count()) {
// We've finished sending the last parameter for the last component, request is complete
_currentParamRequestListComponentIndex = -1;
} else {
_currentParamRequestListParamIndex = 0;
}
}
void MockLink::_handleParamSet(const mavlink_message_t& msg)
{
mavlink_param_set_t request;
mavlink_msg_param_set_decode(&msg, &request);
dogmaphobic
committed
Q_ASSERT(request.target_system == _vehicleSystemId);
int componentId = request.target_component;
// Param may not be null terminated if exactly fits
char paramId[MAVLINK_MSG_PARAM_SET_FIELD_PARAM_ID_LEN + 1];
strncpy(paramId, request.param_id, MAVLINK_MSG_PARAM_SET_FIELD_PARAM_ID_LEN);
dogmaphobic
committed
qCDebug(MockLinkLog) << "_handleParamSet" << componentId << paramId << request.param_type;
Q_ASSERT(_mapParamName2Value.contains(componentId));
Q_ASSERT(_mapParamName2Value[componentId].contains(paramId));
Q_ASSERT(request.param_type == _mapParamName2MavParamType[componentId][paramId]);
dogmaphobic
committed
_setParamFloatUnionIntoMap(componentId, paramId, request.param_value);
dogmaphobic
committed
// Respond with a param_value to ack
mavlink_message_t responseMsg;
mavlink_msg_param_value_pack_chan(_vehicleSystemId,
componentId, // component id
&responseMsg, // Outgoing message
paramId, // Parameter name
request.param_value, // Send same value back
request.param_type, // Send same type back
_mapParamName2Value[componentId].count(), // Total number of parameters
_mapParamName2Value[componentId].keys().indexOf(paramId)); // Index of this parameter
}
void MockLink::_handleParamRequestRead(const mavlink_message_t& msg)
{
mavlink_message_t responseMsg;
mavlink_param_request_read_t request;
mavlink_msg_param_request_read_decode(&msg, &request);
const QString paramName(QString::fromLocal8Bit(request.param_id, strnlen(request.param_id, MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN)));
int componentId = request.target_component;
// special case for magic _HASH_CHECK value
if (request.target_component == MAV_COMP_ID_ALL && paramName == "_HASH_CHECK") {
mavlink_param_union_t valueUnion;
valueUnion.type = MAV_PARAM_TYPE_UINT32;
valueUnion.param_uint32 = 0;
// Special case of magic hash check value
mavlink_msg_param_value_pack_chan(_vehicleSystemId,
componentId,
&responseMsg,
request.param_id,
valueUnion.param_float,
MAV_PARAM_TYPE_UINT32,
0,
-1);
respondWithMavlinkMessage(responseMsg);
return;
}
Q_ASSERT(_mapParamName2Value.contains(componentId));
dogmaphobic
committed
char paramId[MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN + 1];
paramId[0] = 0;
dogmaphobic
committed
Q_ASSERT(request.target_system == _vehicleSystemId);
dogmaphobic
committed
if (request.param_index == -1) {
// Request is by param name. Param may not be null terminated if exactly fits
strncpy(paramId, request.param_id, MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN);
dogmaphobic
committed
Q_ASSERT(request.param_index >= 0 && request.param_index < _mapParamName2Value[componentId].count());
dogmaphobic
committed
QString key = _mapParamName2Value[componentId].keys().at(request.param_index);
Q_ASSERT(key.length() <= MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN);
strcpy(paramId, key.toLocal8Bit().constData());
Q_ASSERT(_mapParamName2Value[componentId].contains(paramId));
dogmaphobic
committed
if (_failureMode == MockConfiguration::FailMissingParamOnAllRequests && strcmp(paramId, _failParam) == 0) {
qCDebug(MockLinkLog) << "Ignoring request read for " << _failParam;
// Fail to send this param no matter what
return;
}
mavlink_msg_param_value_pack_chan(_vehicleSystemId,
componentId, // component id
&responseMsg, // Outgoing message
paramId, // Parameter name
_floatUnionForParam(componentId, paramId), // Parameter value
_mapParamName2Value[componentId].count(), // Total number of parameters
_mapParamName2Value[componentId].keys().indexOf(paramId)); // Index of this parameter
void MockLink::emitRemoteControlChannelRawChanged(int channel, uint16_t raw)
{
uint16_t chanRaw[18];
for (int i=0; i<18; i++) {
chanRaw[i] = UINT16_MAX;
}
chanRaw[channel] = raw;
mavlink_msg_rc_channels_pack_chan(_vehicleSystemId,
_vehicleComponentId,
&responseMsg, // Outgoing message
0, // time since boot, ignored
18, // channel count
chanRaw[0], // channel raw value
chanRaw[1], // channel raw value
chanRaw[2], // channel raw value
chanRaw[3], // channel raw value
chanRaw[4], // channel raw value
chanRaw[5], // channel raw value
chanRaw[6], // channel raw value
chanRaw[7], // channel raw value
chanRaw[8], // channel raw value
chanRaw[9], // channel raw value
chanRaw[10], // channel raw value
chanRaw[11], // channel raw value
chanRaw[12], // channel raw value
chanRaw[13], // channel raw value
chanRaw[14], // channel raw value
chanRaw[15], // channel raw value
chanRaw[16], // channel raw value
chanRaw[17], // channel raw value
0); // rss
respondWithMavlinkMessage(responseMsg);
}
void MockLink::_handleFTP(const mavlink_message_t& msg)
{
Q_ASSERT(_fileServer);
_fileServer->handleFTPMessage(msg);
void MockLink::_handleCommandLong(const mavlink_message_t& msg)
{
static bool firstCmdUser3 = true;
static bool firstCmdUser4 = true;
uint8_t commandResult = MAV_RESULT_UNSUPPORTED;
mavlink_msg_command_long_decode(&msg, &request);
switch (request.command) {
case MAV_CMD_COMPONENT_ARM_DISARM:
if (request.param1 == 0.0f) {
_mavBaseMode &= ~MAV_MODE_FLAG_SAFETY_ARMED;
} else {
_mavBaseMode |= MAV_MODE_FLAG_SAFETY_ARMED;
}
break;
case MAV_CMD_PREFLIGHT_CALIBRATION:
_handlePreFlightCalibration(request);
commandResult = MAV_RESULT_ACCEPTED;
break;
case MAV_CMD_PREFLIGHT_STORAGE:
commandResult = MAV_RESULT_ACCEPTED;
break;
case MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES:
commandResult = MAV_RESULT_ACCEPTED;
_respondWithAutopilotVersion();
break;
case MAV_CMD_USER_1:
// Test command which always returns MAV_RESULT_ACCEPTED
commandResult = MAV_RESULT_ACCEPTED;
break;
case MAV_CMD_USER_2:
// Test command which always returns MAV_RESULT_FAILED
commandResult = MAV_RESULT_FAILED;
break;
case MAV_CMD_USER_3:
// Test command which returns MAV_RESULT_ACCEPTED on second attempt
if (firstCmdUser3) {
} else {
firstCmdUser3 = true;
commandResult = MAV_RESULT_ACCEPTED;
}
break;
case MAV_CMD_USER_4:
// Test command which returns MAV_RESULT_FAILED on second attempt
if (firstCmdUser4) {
} else {
firstCmdUser4 = true;
commandResult = MAV_RESULT_FAILED;
}
break;
case MAV_CMD_USER_5:
// No response
return;
break;
mavlink_msg_command_ack_pack_chan(_vehicleSystemId,
_vehicleComponentId,
0, // progress
0, // result_param2
0, // target_system
0); // target_component
void MockLink::_respondWithAutopilotVersion(void)
{
mavlink_message_t msg;
uint8_t customVersion[8] = { };
uint32_t flightVersion = 0;
Gus Grubba
committed
#if !defined(NO_ARDUPILOT_DIALECT)
if (_firmwareType == MAV_AUTOPILOT_ARDUPILOTMEGA) {
if (_vehicleType == MAV_TYPE_FIXED_WING) {
flightVersion |= 9 << (8*2);
} else if (_vehicleType == MAV_TYPE_SUBMARINE ) {
flightVersion |= 5 << (8*2);
} else if (_vehicleType == MAV_TYPE_GROUND_ROVER ) {
flightVersion |= 5 << (8*2);
} else {
flightVersion |= 6 << (8*2);
}
flightVersion |= 3 << (8*3); // Major
flightVersion |= 0 << (8*1); // Patch
flightVersion |= FIRMWARE_VERSION_TYPE_DEV << (8*0);
} else if (_firmwareType == MAV_AUTOPILOT_PX4) {
Gus Grubba
committed
#endif
flightVersion |= 1 << (8*3);
flightVersion |= 4 << (8*2);
flightVersion |= 1 << (8*1);
flightVersion |= FIRMWARE_VERSION_TYPE_DEV << (8*0);
Gus Grubba
committed
#if !defined(NO_ARDUPILOT_DIALECT)
Gus Grubba
committed
#endif
mavlink_msg_autopilot_version_pack_chan(_vehicleSystemId,
_vehicleComponentId,