Commit 10b2b309 authored by Lorenz Meier's avatar Lorenz Meier

MAVLink: Accept existing MAVLink 2 connection and accept link disconnect command.

parent 962eaaaf
...@@ -484,6 +484,12 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes ...@@ -484,6 +484,12 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
if (!_containsLink(link)) { if (!_containsLink(link)) {
_addLink(link); _addLink(link);
// if the minimum supported version of MAVLink is already 2.0
// set our max proto version to it.
if (_mavlink->getCurrentVersion() >= 200) {
_maxProtoVersion = _mavlink->getCurrentVersion();
}
} }
//-- Check link status //-- Check link status
...@@ -513,8 +519,11 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes ...@@ -513,8 +519,11 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
} }
// Mark this vehicle as active // Mark this vehicle as active - but only if the traffic is coming from
_connectionActive(); // the actual vehicle
if (message.sysid == _id) {
_connectionActive();
}
// Give the plugin a change to adjust the message contents // Give the plugin a change to adjust the message contents
if (!_firmwarePlugin->adjustIncomingMavlinkMessage(this, &message)) { if (!_firmwarePlugin->adjustIncomingMavlinkMessage(this, &message)) {
...@@ -569,6 +578,9 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes ...@@ -569,6 +578,9 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
case MAVLINK_MSG_ID_COMMAND_ACK: case MAVLINK_MSG_ID_COMMAND_ACK:
_handleCommandAck(message); _handleCommandAck(message);
break; break;
case MAVLINK_MSG_ID_COMMAND_LONG:
_handleCommandLong(message);
break;
case MAVLINK_MSG_ID_AUTOPILOT_VERSION: case MAVLINK_MSG_ID_AUTOPILOT_VERSION:
_handleAutopilotVersion(link, message); _handleAutopilotVersion(link, message);
break; break;
...@@ -853,7 +865,9 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message) ...@@ -853,7 +865,9 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message)
if (ack.command == MAV_CMD_REQUEST_PROTOCOL_VERSION && ack.result != MAV_RESULT_ACCEPTED) { if (ack.command == MAV_CMD_REQUEST_PROTOCOL_VERSION && ack.result != MAV_RESULT_ACCEPTED) {
// The autopilot does not understand the request and consequently is likely handling only // The autopilot does not understand the request and consequently is likely handling only
// MAVLink 1 // MAVLink 1
_setMaxProtoVersion(100); if (_maxProtoVersion == 0) {
_setMaxProtoVersion(100);
}
} }
if (_mavCommandQueue.count() && ack.command == _mavCommandQueue[0].command) { if (_mavCommandQueue.count() && ack.command == _mavCommandQueue[0].command) {
...@@ -889,6 +903,29 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message) ...@@ -889,6 +903,29 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message)
_sendNextQueuedMavCommand(); _sendNextQueuedMavCommand();
} }
void Vehicle::_handleCommandLong(mavlink_message_t& message)
{
mavlink_command_long_t cmd;
mavlink_msg_command_long_decode(&message, &cmd);
switch (cmd.command) {
// Other component on the same system
// requests that QGC frees up the serial port of the autopilot
case MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
if (cmd.param6 > 0) {
// disconnect the USB link if its a direct connection to a Pixhawk
for (int i = 0; i < _links.length(); i++) {
SerialLink *sl = qobject_cast<SerialLink*>(_links.at(i));
if (sl && sl->getSerialConfig()->usbDirect()) {
qDebug() << "Disconnecting:" << _links.at(i)->getName();
qgcApp()->toolbox()->linkManager()->disconnectLink(_links.at(i));
}
}
}
break;
}
}
void Vehicle::_handleExtendedSysState(mavlink_message_t& message) void Vehicle::_handleExtendedSysState(mavlink_message_t& message)
{ {
mavlink_extended_sys_state_t extendedState; mavlink_extended_sys_state_t extendedState;
...@@ -1076,9 +1113,11 @@ void Vehicle::_handleHeartbeat(mavlink_message_t& message) ...@@ -1076,9 +1113,11 @@ void Vehicle::_handleHeartbeat(mavlink_message_t& message)
void Vehicle::_handleRadioStatus(mavlink_message_t& message) void Vehicle::_handleRadioStatus(mavlink_message_t& message)
{ {
//-- Process telemetry status message //-- Process telemetry status message
mavlink_radio_status_t rstatus; mavlink_radio_status_t rstatus;
mavlink_msg_radio_status_decode(&message, &rstatus); mavlink_msg_radio_status_decode(&message, &rstatus);
int rssi = rstatus.rssi; int rssi = rstatus.rssi;
int remrssi = rstatus.remrssi; int remrssi = rstatus.remrssi;
int lnoise = (int)(int8_t)rstatus.noise; int lnoise = (int)(int8_t)rstatus.noise;
...@@ -1958,9 +1997,15 @@ void Vehicle::_connectionLostTimeout(void) ...@@ -1958,9 +1997,15 @@ void Vehicle::_connectionLostTimeout(void)
if (_connectionLostEnabled && !_connectionLost) { if (_connectionLostEnabled && !_connectionLost) {
_connectionLost = true; _connectionLost = true;
_heardFrom = false; _heardFrom = false;
_maxProtoVersion = 0;
emit connectionLostChanged(true); emit connectionLostChanged(true);
_say(QString("%1 communication lost").arg(_vehicleIdSpeech())); _say(QString("%1 communication lost").arg(_vehicleIdSpeech()));
if (_autoDisconnect) { if (_autoDisconnect) {
// Reset link state
for (int i = 0; i < _links.length(); i++) {
_mavlink->resetMetadataForLink(_links.at(i));
}
disconnectInactiveVehicle(); disconnectInactiveVehicle();
} }
} }
...@@ -1973,6 +2018,12 @@ void Vehicle::_connectionActive(void) ...@@ -1973,6 +2018,12 @@ void Vehicle::_connectionActive(void)
_connectionLost = false; _connectionLost = false;
emit connectionLostChanged(false); emit connectionLostChanged(false);
_say(QString("%1 communication regained").arg(_vehicleIdSpeech())); _say(QString("%1 communication regained").arg(_vehicleIdSpeech()));
// Re-negotiate protocol version for the link
sendMavCommand(MAV_COMP_ID_ALL, // Don't know default component id yet.
MAV_CMD_REQUEST_PROTOCOL_VERSION,
false, // No error shown if fails
1); // Request protocol version
} }
} }
...@@ -2289,8 +2340,11 @@ void Vehicle::_sendMavCommandAgain(void) ...@@ -2289,8 +2340,11 @@ void Vehicle::_sendMavCommandAgain(void)
} }
if (queuedCommand.command == MAV_CMD_REQUEST_PROTOCOL_VERSION) { if (queuedCommand.command == MAV_CMD_REQUEST_PROTOCOL_VERSION) {
// We aren't going to get a response back for the protocol version, so assume v1 is all we can do // We aren't going to get a response back for the protocol version, so assume v1 is all we can do.
_setMaxProtoVersion(100); // If the max protocol version is uninitialized, fall back to v1.
if (_maxProtoVersion == 0) {
_setMaxProtoVersion(100);
}
} }
emit mavCommandResult(_id, queuedCommand.component, queuedCommand.command, MAV_RESULT_FAILED, true /* noResponsefromVehicle */); emit mavCommandResult(_id, queuedCommand.component, queuedCommand.command, MAV_RESULT_FAILED, true /* noResponsefromVehicle */);
......
...@@ -843,6 +843,7 @@ private: ...@@ -843,6 +843,7 @@ private:
void _handleVibration(mavlink_message_t& message); void _handleVibration(mavlink_message_t& message);
void _handleExtendedSysState(mavlink_message_t& message); void _handleExtendedSysState(mavlink_message_t& message);
void _handleCommandAck(mavlink_message_t& message); void _handleCommandAck(mavlink_message_t& message);
void _handleCommandLong(mavlink_message_t& message);
void _handleAutopilotVersion(LinkInterface* link, mavlink_message_t& message); void _handleAutopilotVersion(LinkInterface* link, mavlink_message_t& message);
void _handleProtocolVersion(LinkInterface* link, mavlink_message_t& message); void _handleProtocolVersion(LinkInterface* link, mavlink_message_t& message);
void _handleHilActuatorControls(mavlink_message_t& message); void _handleHilActuatorControls(mavlink_message_t& message);
......
...@@ -191,6 +191,7 @@ void LinkManager::_addLink(LinkInterface* link) ...@@ -191,6 +191,7 @@ void LinkManager::_addLink(LinkInterface* link)
connect(link, &LinkInterface::bytesReceived, _mavlinkProtocol, &MAVLinkProtocol::receiveBytes); connect(link, &LinkInterface::bytesReceived, _mavlinkProtocol, &MAVLinkProtocol::receiveBytes);
_mavlinkProtocol->resetMetadataForLink(link); _mavlinkProtocol->resetMetadataForLink(link);
_mavlinkProtocol->setVersion(_mavlinkProtocol->getCurrentVersion());
connect(link, &LinkInterface::connected, this, &LinkManager::_linkConnected); connect(link, &LinkInterface::connected, this, &LinkManager::_linkConnected);
connect(link, &LinkInterface::disconnected, this, &LinkManager::_linkDisconnected); connect(link, &LinkInterface::disconnected, this, &LinkManager::_linkDisconnected);
......
...@@ -56,6 +56,7 @@ MAVLinkProtocol::MAVLinkProtocol(QGCApplication* app, QGCToolbox* toolbox) ...@@ -56,6 +56,7 @@ MAVLinkProtocol::MAVLinkProtocol(QGCApplication* app, QGCToolbox* toolbox)
, versionMismatchIgnore(false) , versionMismatchIgnore(false)
, systemId(255) , systemId(255)
, _current_version(100) , _current_version(100)
, _radio_version_mismatch_count(0)
, _logSuspendError(false) , _logSuspendError(false)
, _logSuspendReplay(false) , _logSuspendReplay(false)
, _vehicleWasArmed(false) , _vehicleWasArmed(false)
...@@ -152,7 +153,7 @@ void MAVLinkProtocol::storeSettings() ...@@ -152,7 +153,7 @@ void MAVLinkProtocol::storeSettings()
// Parameter interface settings // Parameter interface settings
} }
void MAVLinkProtocol::resetMetadataForLink(const LinkInterface *link) void MAVLinkProtocol::resetMetadataForLink(LinkInterface *link)
{ {
int channel = link->mavlinkChannel(); int channel = link->mavlinkChannel();
totalReceiveCounter[channel] = 0; totalReceiveCounter[channel] = 0;
...@@ -160,6 +161,7 @@ void MAVLinkProtocol::resetMetadataForLink(const LinkInterface *link) ...@@ -160,6 +161,7 @@ void MAVLinkProtocol::resetMetadataForLink(const LinkInterface *link)
totalErrorCounter[channel] = 0; totalErrorCounter[channel] = 0;
currReceiveCounter[channel] = 0; currReceiveCounter[channel] = 0;
currLossCounter[channel] = 0; currLossCounter[channel] = 0;
link->setDecodedFirstMavlinkPacket(false);
} }
/** /**
...@@ -194,9 +196,9 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -194,9 +196,9 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
if (decodeState == 0 && !link->decodedFirstMavlinkPacket()) if (decodeState == 0 && !link->decodedFirstMavlinkPacket())
{ {
nonmavlinkCount++; nonmavlinkCount++;
if (nonmavlinkCount > 2000 && !warnedUserNonMavlink) if (nonmavlinkCount > 500 && !warnedUserNonMavlink)
{ {
//2000 bytes with no mavlink message. Are we connected to a mavlink capable device? // 500 bytes with no mavlink message. Are we connected to a mavlink capable device?
if (!checkedUserNonMavlink) if (!checkedUserNonMavlink)
{ {
link->requestReset(); link->requestReset();
...@@ -217,13 +219,15 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -217,13 +219,15 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
if (decodeState == 1) if (decodeState == 1)
{ {
if (!link->decodedFirstMavlinkPacket()) { if (!link->decodedFirstMavlinkPacket()) {
link->setDecodedFirstMavlinkPacket(true);
mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(mavlinkChannel); mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(mavlinkChannel);
if (!(mavlinkStatus->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) && (mavlinkStatus->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1)) { if (!(mavlinkStatus->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) && (mavlinkStatus->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1)) {
qDebug() << "Switching outbound to mavlink 2.0 due to incoming mavlink 2.0 packet:" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags; qDebug() << "Switching outbound to mavlink 2.0 due to incoming mavlink 2.0 packet:" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags;
mavlinkStatus->flags &= ~MAVLINK_STATUS_FLAG_OUT_MAVLINK1; mavlinkStatus->flags &= ~MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
_current_version = 200;
// Set all links to v2
setVersion(200);
} }
link->setDecodedFirstMavlinkPacket(true);
} }
// Log data // Log data
...@@ -270,6 +274,26 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) ...@@ -270,6 +274,26 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
emit vehicleHeartbeatInfo(link, message.sysid, message.compid, heartbeat.mavlink_version, heartbeat.autopilot, heartbeat.type); emit vehicleHeartbeatInfo(link, message.sysid, message.compid, heartbeat.mavlink_version, heartbeat.autopilot, heartbeat.type);
} }
// Detect if we are talking to an old radio not supporting v2
mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(mavlinkChannel);
if (message.msgid == MAVLINK_MSG_ID_RADIO_STATUS) {
if ((mavlinkStatus->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1)
&& !(mavlinkStatus->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1)) {
_radio_version_mismatch_count++;
}
}
if (_radio_version_mismatch_count == 5) {
// Warn the user if the radio continues to send v1 while the link uses v2
emit protocolStatusMessage(tr("MAVLink Protocol"), tr("Detected radio still using MAVLink v1.0 on a link with MAVLink v2.0 enabled. Please upgrade the radio firmware."));
// Ensure the warning can't get stuck
_radio_version_mismatch_count++;
// Flick link back to v1
qDebug() << "Switching outbound to mavlink 1.0 due to incoming mavlink 1.0 packet:" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags;
mavlinkStatus->flags |= MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
}
// Increase receive counter // Increase receive counter
totalReceiveCounter[mavlinkChannel]++; totalReceiveCounter[mavlinkChannel]++;
currReceiveCounter[mavlinkChannel]++; currReceiveCounter[mavlinkChannel]++;
...@@ -358,6 +382,9 @@ void MAVLinkProtocol::_vehicleCountChanged(void) ...@@ -358,6 +382,9 @@ void MAVLinkProtocol::_vehicleCountChanged(void)
if (count == 0) { if (count == 0) {
// Last vehicle is gone, close out logging // Last vehicle is gone, close out logging
_stopLogging(); _stopLogging();
// Reset protocol version handling
_current_version = 0;
_radio_version_mismatch_count = 0;
} }
} }
......
...@@ -89,7 +89,7 @@ public: ...@@ -89,7 +89,7 @@ public:
/** /**
* Reset the counters for all metadata for this link. * Reset the counters for all metadata for this link.
*/ */
virtual void resetMetadataForLink(const LinkInterface *link); virtual void resetMetadataForLink(LinkInterface *link);
/// Suspend/Restart logging during replay. /// Suspend/Restart logging during replay.
void suspendLogForReplay(bool suspend); void suspendLogForReplay(bool suspend);
...@@ -133,6 +133,7 @@ protected: ...@@ -133,6 +133,7 @@ protected:
bool versionMismatchIgnore; bool versionMismatchIgnore;
int systemId; int systemId;
unsigned _current_version; unsigned _current_version;
unsigned _radio_version_mismatch_count;
signals: signals:
/// Heartbeat received on link /// Heartbeat received on link
......
...@@ -62,7 +62,7 @@ public: ...@@ -62,7 +62,7 @@ public:
* when reconnecting a link. * when reconnecting a link.
* @param link The link to reset metadata for. * @param link The link to reset metadata for.
*/ */
virtual void resetMetadataForLink(const LinkInterface *link) = 0; virtual void resetMetadataForLink(LinkInterface *link) = 0;
public slots: public slots:
virtual void receiveBytes(LinkInterface *link, QByteArray b) = 0; virtual void receiveBytes(LinkInterface *link, QByteArray b) = 0;
......
...@@ -137,6 +137,7 @@ public: ...@@ -137,6 +137,7 @@ public:
void requestReset(); void requestReset();
bool isConnected() const; bool isConnected() const;
qint64 getConnectionSpeed() const; qint64 getConnectionSpeed() const;
SerialConfiguration* getSerialConfig() const { return _serialConfig; }
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of // These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager. // connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment