Commit 76677481 authored by Don Gagne's avatar Don Gagne

Reference counting for LinkInterface, LinkConfiguration

Prevent shutdown ordering crashes
parent 5040e3d9
......@@ -641,6 +641,7 @@ SOURCES += \
src/VehicleSetup/JoystickConfigController.cc \
src/audio/QGCAudioWorker.cpp \
src/comm/LinkConfiguration.cc \
src/comm/LinkInterface.cc \
src/comm/LinkManager.cc \
src/comm/MAVLinkProtocol.cc \
src/comm/QGCMAVLink.cc \
......
......@@ -155,8 +155,8 @@ void QGroundControlQmlGlobal::stopAllMockLinks(void)
#ifdef QT_DEBUG
LinkManager* linkManager = qgcApp()->toolbox()->linkManager();
for (int i=0; i<linkManager->links()->count(); i++) {
LinkInterface* link = linkManager->links()->value<LinkInterface*>(i);
for (int i=0; i<linkManager->links().count(); i++) {
LinkInterface* link = linkManager->links()[i];
MockLink* mockLink = qobject_cast<MockLink*>(link);
if (mockLink) {
......
......@@ -306,9 +306,9 @@ void MultiVehicleManager::setGcsHeartbeatEnabled(bool gcsHeartBeatEnabled)
void MultiVehicleManager::_sendGCSHeartbeat(void)
{
// Send a heartbeat out on each link
QmlObjectListModel* links = _toolbox->linkManager()->links();
for (int i=0; i<links->count(); i++) {
LinkInterface* link = links->value<LinkInterface*>(i);
LinkManager* linkMgr = _toolbox->linkManager();
for (int i=0; i<linkMgr->links().count(); i++) {
LinkInterface* link = linkMgr->links()[i];
if (link->isConnected()) {
mavlink_message_t message;
mavlink_msg_heartbeat_pack_chan(_mavlinkProtocol->getSystemId(),
......
......@@ -926,8 +926,9 @@ bool Vehicle::_containsLink(LinkInterface* link)
void Vehicle::_addLink(LinkInterface* link)
{
if (!_containsLink(link)) {
_links += link;
qCDebug(VehicleLog) << "_addLink:" << QString("%1").arg((ulong)link, 0, 16);
_links += link;
_updatePriorityLink();
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkInactive, this, &Vehicle::_linkInactiveOrDeleted);
connect(qgcApp()->toolbox()->linkManager(), &LinkManager::linkDeleted, this, &Vehicle::_linkInactiveOrDeleted);
}
......@@ -938,6 +939,7 @@ void Vehicle::_linkInactiveOrDeleted(LinkInterface* link)
qCDebug(VehicleLog) << "_linkInactiveOrDeleted linkCount" << _links.count();
_links.removeOne(link);
_updatePriorityLink();
if (_links.count() == 0 && !_allLinksInactiveSent) {
qCDebug(VehicleLog) << "All links inactive";
......@@ -983,26 +985,42 @@ void Vehicle::_sendMessageOnLink(LinkInterface* link, mavlink_message_t message)
emit messagesSentChanged();
}
/// @return Direct usb connection link to board if one, NULL if none
LinkInterface* Vehicle::priorityLink(void)
void Vehicle::_updatePriorityLink(void)
{
#ifndef NO_SERIAL_LINK
foreach (LinkInterface* link, _links) {
LinkInterface* newPriorityLink = NULL;
// Note that this routine specificallty does not clear _priorityLink when there are no links remaining.
// By doing this we hold a reference on the last link as the Vehicle shuts down. Thus preventing shutdown
// ordering NULL pointer crashes where priorityLink() is still called during shutdown sequence.
for (int i=0; i<_links.count(); i++) {
LinkInterface* link = _links[i];
if (link->isConnected()) {
SerialLink* pSerialLink = qobject_cast<SerialLink*>(link);
if (pSerialLink) {
LinkConfiguration* pLinkConfig = pSerialLink->getLinkConfiguration();
if (pLinkConfig) {
SerialConfiguration* pSerialConfig = qobject_cast<SerialConfiguration*>(pLinkConfig);
LinkConfiguration* config = pSerialLink->getLinkConfiguration();
if (config) {
SerialConfiguration* pSerialConfig = qobject_cast<SerialConfiguration*>(config);
if (pSerialConfig && pSerialConfig->usbDirect()) {
return link;
if (_priorityLink.data() != link) {
newPriorityLink = link;
break;
}
return;
}
}
}
}
}
if (!newPriorityLink && !_priorityLink.data() && _links.count()) {
newPriorityLink = _links[0];
}
if (newPriorityLink) {
_priorityLink = qgcApp()->toolbox()->linkManager()->sharedLinkInterfacePointerForLink(newPriorityLink);
}
#endif
return _links.count() ? _links[0] : NULL;
}
void Vehicle::setLatitude(double latitude)
......
......@@ -416,8 +416,9 @@ public:
MAV_TYPE vehicleType(void) const { return _vehicleType; }
Q_INVOKABLE QString vehicleTypeName(void) const;
/// Returns the highest quality link available to the Vehicle
LinkInterface* priorityLink(void);
/// Returns the highest quality link available to the Vehicle. If you need to hold a refernce to this link use
/// LinkManager::sharedLinkInterfaceForGet to get QSharedPointer for link.
LinkInterface* priorityLink(void) { return _priorityLink.data(); }
/// Sends a message to the specified link
/// @return true: message sent, false: Link no longer connected
......@@ -720,6 +721,7 @@ private:
void _handleMavlinkLoggingDataAcked(mavlink_message_t& message);
void _ackMavlinkLogData(uint16_t sequence);
void _sendNextQueuedMavCommand(void);
void _updatePriorityLink(void);
private:
int _id; ///< Mavlink system id
......@@ -851,6 +853,8 @@ private:
static const int _lowBatteryAnnounceRepeatMSecs; // Amount of time in between each low battery announcement
QElapsedTimer _lowBatteryAnnounceTimer;
SharedLinkInterfacePointer _priorityLink; // We always keep a reference to the priority link to manage shutdown ordering
// FactGroup facts
Fact _rollFact;
......
......@@ -7,7 +7,6 @@
*
****************************************************************************/
#ifndef LINKCONFIGURATION_H
#define LINKCONFIGURATION_H
......@@ -37,7 +36,7 @@ public:
// Property accessors
const QString name(void) { return _name; }
QString name(void) const { return _name; }
LinkInterface* link(void) { return _link; }
void setName(const QString name);
......@@ -190,4 +189,6 @@ private:
bool _autoConnect; ///< This connection is started automatically at boot
};
typedef QSharedPointer<LinkConfiguration> SharedLinkConfigurationPointer;
#endif // LINKCONFIGURATION_H
/****************************************************************************
*
* (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.
*
****************************************************************************/
#include "LinkInterface.h"
#include "QGCApplication.h"
/// mavlink channel to use for this link, as used by mavlink_parse_char. The mavlink channel is only
/// set into the link when it is added to LinkManager
uint8_t LinkInterface::mavlinkChannel(void) const
{
if (!_mavlinkChannelSet) {
qWarning() << "Call to LinkInterface::mavlinkChannel with _mavlinkChannelSet == false";
}
return _mavlinkChannel;
}
// Links are only created by LinkManager so constructor is not public
LinkInterface::LinkInterface(SharedLinkConfigurationPointer& config)
: QThread(0)
, _config(config)
, _mavlinkChannelSet(false)
, _active(false)
, _enableRateCollection(false)
{
_config->setLink(this);
// Initialize everything for the data rate calculation buffers.
_inDataIndex = 0;
_outDataIndex = 0;
// Initialize our data rate buffers.
memset(_inDataWriteAmounts, 0, sizeof(_inDataWriteAmounts));
memset(_inDataWriteTimes, 0, sizeof(_inDataWriteTimes));
memset(_outDataWriteAmounts,0, sizeof(_outDataWriteAmounts));
memset(_outDataWriteTimes, 0, sizeof(_outDataWriteTimes));
QObject::connect(this, &LinkInterface::_invokeWriteBytes, this, &LinkInterface::_writeBytes);
qRegisterMetaType<LinkInterface*>("LinkInterface*");
}
/// This function logs the send times and amounts of datas for input. Data is used for calculating
/// the transmission rate.
/// @param byteCount Number of bytes received
/// @param time Time in ms send occurred
void LinkInterface::_logInputDataRate(quint64 byteCount, qint64 time) {
if(_enableRateCollection)
_logDataRateToBuffer(_inDataWriteAmounts, _inDataWriteTimes, &_inDataIndex, byteCount, time);
}
/// This function logs the send times and amounts of datas for output. Data is used for calculating
/// the transmission rate.
/// @param byteCount Number of bytes sent
/// @param time Time in ms receive occurred
void LinkInterface::_logOutputDataRate(quint64 byteCount, qint64 time) {
if(_enableRateCollection)
_logDataRateToBuffer(_outDataWriteAmounts, _outDataWriteTimes, &_outDataIndex, byteCount, time);
}
/**
* @brief logDataRateToBuffer Stores transmission times/amounts for statistics
*
* This function logs the send times and amounts of datas to the given circular buffers.
* This data is used for calculating the transmission rate.
*
* @param bytesBuffer[out] The buffer to write the bytes value into.
* @param timeBuffer[out] The buffer to write the time value into
* @param writeIndex[out] The write index used for this buffer.
* @param bytes The amount of bytes transmit.
* @param time The time (in ms) this transmission occurred.
*/
void LinkInterface::_logDataRateToBuffer(quint64 *bytesBuffer, qint64 *timeBuffer, int *writeIndex, quint64 bytes, qint64 time)
{
QMutexLocker dataRateLocker(&_dataRateMutex);
int i = *writeIndex;
// Now write into the buffer, if there's no room, we just overwrite the first data point.
bytesBuffer[i] = bytes;
timeBuffer[i] = time;
// Increment and wrap the write index
++i;
if (i == _dataRateBufferSize)
{
i = 0;
}
*writeIndex = i;
}
/**
* @brief getCurrentDataRate Get the current data rate given a data rate buffer.
*
* This function attempts to use the times and number of bytes transmit into a current data rate
* estimation. Since it needs to use timestamps to get the timeperiods over when the data was sent,
* this is effectively a global data rate over the last _dataRateBufferSize - 1 data points. Also note
* that data points older than NOW - dataRateCurrentTimespan are ignored.
*
* @param index The first valid sample in the data rate buffer. Refers to the oldest time sample.
* @param dataWriteTimes The time, in ms since epoch, that each data sample took place.
* @param dataWriteAmounts The amount of data (in bits) that was transferred.
* @return The bits per second of data transferrence of the interface over the last [-statsCurrentTimespan, 0] timespan.
*/
qint64 LinkInterface::_getCurrentDataRate(int index, const qint64 dataWriteTimes[], const quint64 dataWriteAmounts[]) const
{
const qint64 now = QDateTime::currentMSecsSinceEpoch();
// Limit the time we calculate to the recent past
const qint64 cutoff = now - _dataRateCurrentTimespan;
// Grab the mutex for working with the stats variables
QMutexLocker dataRateLocker(&_dataRateMutex);
// Now iterate through the buffer of all received data packets adding up all values
// within now and our cutof.
qint64 totalBytes = 0;
qint64 totalTime = 0;
qint64 lastTime = 0;
int size = _dataRateBufferSize;
while (size-- > 0)
{
// If this data is within our cutoff time, include it in our calculations.
// This also accounts for when the buffer is empty and filled with 0-times.
if (dataWriteTimes[index] > cutoff && lastTime > 0) {
// Track the total time, using the previous time as our timeperiod.
totalTime += dataWriteTimes[index] - lastTime;
totalBytes += dataWriteAmounts[index];
}
// Track the last time sample for doing timespan calculations
lastTime = dataWriteTimes[index];
// Increment and wrap the index if necessary.
if (++index == _dataRateBufferSize)
{
index = 0;
}
}
// Return the final calculated value in bits / s, converted from bytes/ms.
qint64 dataRate = (totalTime != 0)?(qint64)((float)totalBytes * 8.0f / ((float)totalTime / 1000.0f)):0;
// Finally return our calculated data rate.
return dataRate;
}
/// Sets the mavlink channel to use for this link
void LinkInterface::_setMavlinkChannel(uint8_t channel)
{
Q_ASSERT(!_mavlinkChannelSet);
_mavlinkChannelSet = true;
_mavlinkChannel = channel;
}
......@@ -19,9 +19,9 @@
#include <QDebug>
#include "QGCMAVLink.h"
#include "LinkConfiguration.h"
class LinkManager;
class LinkConfiguration;
/**
* The link interface defines the interface for all links used to communicate
......@@ -35,18 +35,16 @@ class LinkInterface : public QThread
// Only LinkManager is allowed to create/delete or _connect/_disconnect a link
friend class LinkManager;
public:
public:
~LinkInterface() { _config->setLink(NULL); }
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
// Property accessors
bool active(void) { return _active; }
void setActive(bool active) { _active = active; emit activeChanged(active); }
bool active(void) { return _active; }
void setActive(bool active) { _active = active; emit activeChanged(active); }
/**
* @brief Get link configuration
* @return A pointer to the instance of LinkConfiguration
**/
virtual LinkConfiguration* getLinkConfiguration() = 0;
LinkConfiguration* getLinkConfiguration(void) { return _config.data(); }
/* Connection management */
......@@ -116,13 +114,7 @@ public:
/// mavlink channel to use for this link, as used by mavlink_parse_char. The mavlink channel is only
/// set into the link when it is added to LinkManager
uint8_t mavlinkChannel(void) const
{
if (!_mavlinkChannelSet) {
qWarning() << "Call to LinkInterface::mavlinkChannel with _mavlinkChannelSet == false";
}
return _mavlinkChannel;
}
uint8_t mavlinkChannel(void) const;
// 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.
......@@ -192,43 +184,21 @@ signals:
protected:
// Links are only created by LinkManager so constructor is not public
LinkInterface() :
QThread(0)
, _mavlinkChannelSet(false)
, _active(false)
, _enableRateCollection(false)
{
// Initialize everything for the data rate calculation buffers.
_inDataIndex = 0;
_outDataIndex = 0;
// Initialize our data rate buffers.
memset(_inDataWriteAmounts, 0, sizeof(_inDataWriteAmounts));
memset(_inDataWriteTimes, 0, sizeof(_inDataWriteTimes));
memset(_outDataWriteAmounts,0, sizeof(_outDataWriteAmounts));
memset(_outDataWriteTimes, 0, sizeof(_outDataWriteTimes));
QObject::connect(this, &LinkInterface::_invokeWriteBytes, this, &LinkInterface::_writeBytes);
qRegisterMetaType<LinkInterface*>("LinkInterface*");
}
LinkInterface(SharedLinkConfigurationPointer& config);
/// This function logs the send times and amounts of datas for input. Data is used for calculating
/// the transmission rate.
/// @param byteCount Number of bytes received
/// @param time Time in ms send occurred
void _logInputDataRate(quint64 byteCount, qint64 time) {
if(_enableRateCollection)
_logDataRateToBuffer(_inDataWriteAmounts, _inDataWriteTimes, &_inDataIndex, byteCount, time);
}
void _logInputDataRate(quint64 byteCount, qint64 time);
/// This function logs the send times and amounts of datas for output. Data is used for calculating
/// the transmission rate.
/// @param byteCount Number of bytes sent
/// @param time Time in ms receive occurred
void _logOutputDataRate(quint64 byteCount, qint64 time) {
if(_enableRateCollection)
_logDataRateToBuffer(_outDataWriteAmounts, _outDataWriteTimes, &_outDataIndex, byteCount, time);
}
void _logOutputDataRate(quint64 byteCount, qint64 time);
SharedLinkConfigurationPointer _config;
private:
/**
......@@ -243,24 +213,7 @@ private:
* @param bytes The amount of bytes transmit.
* @param time The time (in ms) this transmission occurred.
*/
void _logDataRateToBuffer(quint64 *bytesBuffer, qint64 *timeBuffer, int *writeIndex, quint64 bytes, qint64 time)
{
QMutexLocker dataRateLocker(&_dataRateMutex);
int i = *writeIndex;
// Now write into the buffer, if there's no room, we just overwrite the first data point.
bytesBuffer[i] = bytes;
timeBuffer[i] = time;
// Increment and wrap the write index
++i;
if (i == _dataRateBufferSize)
{
i = 0;
}
*writeIndex = i;
}
void _logDataRateToBuffer(quint64 *bytesBuffer, qint64 *timeBuffer, int *writeIndex, quint64 bytes, qint64 time);
/**
* @brief getCurrentDataRate Get the current data rate given a data rate buffer.
......@@ -275,48 +228,7 @@ private:
* @param dataWriteAmounts The amount of data (in bits) that was transferred.
* @return The bits per second of data transferrence of the interface over the last [-statsCurrentTimespan, 0] timespan.
*/
qint64 _getCurrentDataRate(int index, const qint64 dataWriteTimes[], const quint64 dataWriteAmounts[]) const
{
const qint64 now = QDateTime::currentMSecsSinceEpoch();
// Limit the time we calculate to the recent past
const qint64 cutoff = now - _dataRateCurrentTimespan;
// Grab the mutex for working with the stats variables
QMutexLocker dataRateLocker(&_dataRateMutex);
// Now iterate through the buffer of all received data packets adding up all values
// within now and our cutof.
qint64 totalBytes = 0;
qint64 totalTime = 0;
qint64 lastTime = 0;
int size = _dataRateBufferSize;
while (size-- > 0)
{
// If this data is within our cutoff time, include it in our calculations.
// This also accounts for when the buffer is empty and filled with 0-times.
if (dataWriteTimes[index] > cutoff && lastTime > 0) {
// Track the total time, using the previous time as our timeperiod.
totalTime += dataWriteTimes[index] - lastTime;
totalBytes += dataWriteAmounts[index];
}
// Track the last time sample for doing timespan calculations
lastTime = dataWriteTimes[index];
// Increment and wrap the index if necessary.
if (++index == _dataRateBufferSize)
{
index = 0;
}
}
// Return the final calculated value in bits / s, converted from bytes/ms.
qint64 dataRate = (totalTime != 0)?(qint64)((float)totalBytes * 8.0f / ((float)totalTime / 1000.0f)):0;
// Finally return our calculated data rate.
return dataRate;
}
qint64 _getCurrentDataRate(int index, const qint64 dataWriteTimes[], const quint64 dataWriteAmounts[]) const;
/**
* @brief Connect this interface logically
......@@ -328,7 +240,7 @@ private:
virtual void _disconnect(void) = 0;
/// Sets the mavlink channel to use for this link
void _setMavlinkChannel(uint8_t channel) { Q_ASSERT(!_mavlinkChannelSet); _mavlinkChannelSet = true; _mavlinkChannel = channel; }
void _setMavlinkChannel(uint8_t channel);
bool _mavlinkChannelSet; ///< true: _mavlinkChannel has been set
uint8_t _mavlinkChannel; ///< mavlink channel to use for this link, as used by mavlink_parse_char
......@@ -355,6 +267,6 @@ private:
bool _enableRateCollection;
};
typedef QSharedPointer<LinkInterface> SharedLinkInterface;
typedef QSharedPointer<LinkInterface> SharedLinkInterfacePointer;
#endif // _LINKINTERFACE_H_
This diff is collapsed.
......@@ -67,19 +67,12 @@ public:
Q_PROPERTY(bool autoconnectPX4Flow READ autoconnectPX4Flow WRITE setAutoconnectPX4Flow NOTIFY autoconnectPX4FlowChanged)
Q_PROPERTY(bool autoconnectRTKGPS READ autoconnectRTKGPS WRITE setAutoconnectRTKGPS NOTIFY autoconnectRTKGPSChanged)
Q_PROPERTY(bool autoconnectLibrePilot READ autoconnectLibrePilot WRITE setAutoconnectLibrePilot NOTIFY autoconnectLibrePilotChanged)
Q_PROPERTY(bool isBluetoothAvailable READ isBluetoothAvailable CONSTANT)
/// LinkInterface Accessor
Q_PROPERTY(QmlObjectListModel* links READ links CONSTANT)
/// LinkConfiguration Accessor
Q_PROPERTY(QmlObjectListModel* linkConfigurations READ linkConfigurations NOTIFY linkConfigurationsChanged)
/// List of comm type strings
Q_PROPERTY(QStringList linkTypeStrings READ linkTypeStrings CONSTANT)
/// List of supported baud rates for serial links
Q_PROPERTY(QStringList serialBaudRates READ serialBaudRates CONSTANT)
/// List of comm ports display names
Q_PROPERTY(bool isBluetoothAvailable READ isBluetoothAvailable CONSTANT)
Q_PROPERTY(QmlObjectListModel* linkConfigurations READ _qmlLinkConfigurations NOTIFY linkConfigurationsChanged)
Q_PROPERTY(QStringList linkTypeStrings READ linkTypeStrings CONSTANT)
Q_PROPERTY(QStringList serialBaudRates READ serialBaudRates CONSTANT)
Q_PROPERTY(QStringList serialPortStrings READ serialPortStrings NOTIFY commPortStringsChanged)
/// List of comm ports
Q_PROPERTY(QStringList serialPorts READ serialPorts NOTIFY commPortsChanged)
// Create/Edit Link Configuration
......@@ -100,12 +93,11 @@ public:
bool autoconnectLibrePilot (void) { return _autoconnectLibrePilot; }
bool isBluetoothAvailable (void);
QmlObjectListModel* links (void) { return &_links; }
QmlObjectListModel* linkConfigurations (void) { return &_linkConfigurations; }
QStringList linkTypeStrings (void) const;
QStringList serialBaudRates (void);
QStringList serialPortStrings (void);
QStringList serialPorts (void);
QList<LinkInterface*> links (void);
QStringList linkTypeStrings (void) const;
QStringList serialBaudRates (void);
QStringList serialPortStrings (void);
QStringList serialPorts (void);
void setAutoconnectUDP (bool autoconnect);
void setAutoconnectPixhawk (bool autoconnect);
......@@ -132,7 +124,7 @@ public:
/// Creates, connects (and adds) a link based on the given configuration instance.
/// Link takes ownership of config.
Q_INVOKABLE LinkInterface* createConnectedLink(LinkConfiguration* config);
Q_INVOKABLE LinkInterface* createConnectedLink(SharedLinkConfigurationPointer& config);
/// Creates, connects (and adds) a link based on the given configuration name.
LinkInterface* createConnectedLink(const QString& name);
......@@ -165,6 +157,17 @@ public:
// Override from QGCTool
virtual void setToolbox(QGCToolbox *toolbox);
/// @return This mavlink channel is never assigned to a vehicle.
uint8_t reservedMavlinkChannel(void) { return 0; }
/// If you are going to hold a reference to a LinkInterface* in your object you must reference count it
/// by using this method to get access to the shared pointer.
SharedLinkInterfacePointer sharedLinkInterfacePointerForLink(LinkInterface* link);
bool containsLink(LinkInterface* link);
SharedLinkConfigurationPointer addConfiguration(LinkConfiguration* config);
signals:
void autoconnectUDPChanged (bool autoconnect);
void autoconnectPixhawkChanged (bool autoconnect);
......@@ -204,11 +207,13 @@ private slots:
#endif
private:
QmlObjectListModel* _qmlLinkConfigurations (void) { return &_qmlConfigurations; }
bool _connectionsSuspendedMsg(void);
void _updateAutoConnectLinks(void);
void _updateSerialPorts();
void _fixUnnamed(LinkConfiguration* config);
bool _setAutoconnectWorker(bool& currentAutoconnect, bool newAutoconnect, const char* autoconnectKey);
void _removeConfiguration(LinkConfiguration* config);
#ifndef NO_SERIAL_LINK
SerialConfiguration* _autoconnectConfigurationsContainsPort(const QString& portName);
......@@ -223,9 +228,11 @@ private:
MAVLinkProtocol* _mavlinkProtocol;
QmlObjectListModel _links;
QmlObjectListModel _linkConfigurations;
QmlObjectListModel _autoconnectConfigurations;
QList<SharedLinkInterfacePointer> _sharedLinks;
QList<SharedLinkConfigurationPointer> _sharedConfigurations;
QList<SharedLinkConfigurationPointer> _sharedAutoconnectConfigurations;
QmlObjectListModel _qmlConfigurations;
QMap<QString, int> _autoconnectWaitList; ///< key: QGCSerialPortInfo.systemLocation, value: wait count
QStringList _commPortList;
......
......@@ -64,12 +64,13 @@ QString LogReplayLinkConfiguration::logFilenameShort(void)
return fi.fileName();
}
LogReplayLink::LogReplayLink(LogReplayLinkConfiguration* config) :
_connected(false),
_replayAccelerationFactor(1.0f)
LogReplayLink::LogReplayLink(SharedLinkConfigurationPointer& config)
: LinkInterface(config)
, _logReplayConfig(qobject_cast<LogReplayLinkConfiguration*>(config.data()))
, _connected(false)
, _replayAccelerationFactor(1.0f)
{
Q_ASSERT(config);
_config = config;
Q_ASSERT(_logReplayConfig);
_readTickTimer.moveToThread(this);
......@@ -184,7 +185,7 @@ quint64 LogReplayLink::_seekToNextMavlinkMessage(mavlink_message_t* nextMsg)
bool LogReplayLink::_loadLogFile(void)
{
QString errorMsg;
QString logFilename = _config->logFilename();
QString logFilename = _logReplayConfig->logFilename();
QFileInfo logFileInfo;
int logDurationSecondsTotal;
......
......@@ -57,8 +57,6 @@ class LogReplayLink : public LinkInterface
friend class LinkManager;
public:
virtual LinkConfiguration* getLinkConfiguration() { return _config; }
/// @return true: log is currently playing, false: log playback is paused
bool isPlaying(void) { return _readTickTimer.isActive(); }
......@@ -111,7 +109,7 @@ private slots:
private:
// Links are only created/destroyed by LinkManager so constructor/destructor is not public
LogReplayLink(LogReplayLinkConfiguration* config);
LogReplayLink(SharedLinkConfigurationPointer& config);
~LogReplayLink();
void _replayError(const QString& errorMsg);
......@@ -129,7 +127,7 @@ private:
// Virtuals from QThread
virtual void run(void);
LogReplayLinkConfiguration* _config;
LogReplayLinkConfiguration* _logReplayConfig;
bool _connected;
QTimer _readTickTimer; ///< Timer which signals a read of next log record
......
......@@ -159,7 +159,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
// Since receiveBytes signals cross threads we can end up with signals in the queue
// that come through after the link is disconnected. For these we just drop the data
// since the link is closed.
if (!_linkMgr->links()->contains(link)) {
if (!_linkMgr->containsLink(link)) {
return;
}
......
......@@ -44,8 +44,9 @@ const char* MockConfiguration::_vehicleTypeKey = "VehicleType";
const char* MockConfiguration::_sendStatusTextKey = "SendStatusText";
const char* MockConfiguration::_failureModeKey = "FailureMode";
MockLink::MockLink(MockConfiguration* config)
: _missionItemHandler(this, qgcApp()->toolbox()->mavlinkProtocol())
MockLink::MockLink(SharedLinkConfigurationPointer& config)
: LinkInterface(config)
, _missionItemHandler(this, qgcApp()->toolbox()->mavlinkProtocol())
, _name("MockLink")
, _connected(false)
, _vehicleSystemId(_nextVehicleSystemId++)
......@@ -67,14 +68,11 @@ MockLink::MockLink(MockConfiguration* config)
, _logDownloadCurrentOffset(0)
, _logDownloadBytesRemaining(0)
{
_config = config;
if (_config) {
_firmwareType = config->firmwareType();
_vehicleType = config->vehicleType();
_sendStatusText = config->sendStatusText();
_failureMode = config->failureMode();
_config->setLink(this);
}
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;
......@@ -1041,12 +1039,12 @@ void MockConfiguration::updateSettings()
MockLink* MockLink::_startMockLink(MockConfiguration* mockConfig)
{
LinkManager* linkManager = qgcApp()->toolbox()->linkManager();
LinkManager* linkMgr = qgcApp()->toolbox()->linkManager();
mockConfig->setDynamic(true);
linkManager->linkConfigurations()->append(mockConfig);
SharedLinkConfigurationPointer config = linkMgr->addConfiguration(mockConfig);
return qobject_cast<MockLink*>(linkManager->createConnectedLink(mockConfig));
return qobject_cast<MockLink*>(linkMgr->createConnectedLink(config));
}
MockLink* MockLink::startPX4MockLink(bool sendStatusText, MockConfiguration::FailureMode_t failureMode)
......
......@@ -90,8 +90,7 @@ class MockLink : public LinkInterface
Q_OBJECT
public:
// LinkConfiguration is optional for MockLink
MockLink(MockConfiguration* config = NULL);
MockLink(SharedLinkConfigurationPointer& config);
~MockLink(void);
// MockLink methods
......@@ -126,8 +125,6 @@ public:
bool connect(void);
bool disconnect(void);
LinkConfiguration* getLinkConfiguration() { return _config; }
/// Sets a failure mode for unit testing
/// @param failureMode Type of failure to simulate
void setMissionItemFailureMode(MockLinkMissionItemHandler::FailureMode_t failureMode);
......@@ -216,7 +213,6 @@ private:
uint32_t _mavCustomMode;
uint8_t _mavState;
MockConfiguration* _config;
MAV_AUTOPILOT _firmwareType;
MAV_TYPE _vehicleType;
......
......@@ -30,19 +30,19 @@ QGC_LOGGING_CATEGORY(SerialLinkLog, "SerialLinkLog")
static QStringList kSupportedBaudRates;
SerialLink::SerialLink(SerialConfiguration* config)
SerialLink::SerialLink(SharedLinkConfigurationPointer& config)
: LinkInterface(config)
, _port(NULL)
, _bytesRead(0)
, _stopp(false)
, _reqReset(false)
, _serialConfig(qobject_cast<SerialConfiguration*>(config.data()))
{
_bytesRead = 0;
_port = Q_NULLPTR;
_stopp = false;
_reqReset = false;
Q_ASSERT(config != NULL);
_config = config;
_config->setLink(this);
qCDebug(SerialLinkLog) << "Create SerialLink " << config->portName() << config->baud() << config->flowControl()
<< config->parity() << config->dataBits() << config->stopBits();
qCDebug(SerialLinkLog) << "portName: " << config->portName();
Q_ASSERT(_serialConfig);
qCDebug(SerialLinkLog) << "Create SerialLink " << _serialConfig->portName() << _serialConfig->baud() << _serialConfig->flowControl()
<< _serialConfig->parity() << _serialConfig->dataBits() << _serialConfig->stopBits();
qCDebug(SerialLinkLog) << "portName: " << _serialConfig->portName();
}
void SerialLink::requestReset()
......@@ -53,10 +53,10 @@ void SerialLink::requestReset()
SerialLink::~SerialLink()
{
// Disconnect link from configuration
_config->setLink(NULL);
_disconnect();
if(_port) delete _port;
if (_port) {
delete _port;
}
_port = NULL;
}
......@@ -70,7 +70,7 @@ bool SerialLink::_isBootloader()
{
qCDebug(SerialLinkLog) << "PortName : " << info.portName() << "Description : " << info.description();
qCDebug(SerialLinkLog) << "Manufacturer: " << info.manufacturer();
if (info.portName().trimmed() == _config->portName() &&
if (info.portName().trimmed() == _serialConfig->portName() &&
(info.description().toLower().contains("bootloader") ||
info.description().toLower().contains("px4 bl") ||
info.description().toLower().contains("px4 fmu v1.6"))) {
......@@ -159,7 +159,7 @@ bool SerialLink::_hardwareConnect(QSerialPort::SerialPortError& error, QString&
_port = NULL;
}
qCDebug(SerialLinkLog) << "SerialLink: hardwareConnect to " << _config->portName();
qCDebug(SerialLinkLog) << "SerialLink: hardwareConnect to " << _serialConfig->portName();
// If we are in the Pixhawk bootloader code wait for it to timeout
if (_isBootloader()) {
......@@ -181,7 +181,7 @@ bool SerialLink::_hardwareConnect(QSerialPort::SerialPortError& error, QString&
}
}
_port = new QSerialPort(_config->portName());
_port = new QSerialPort(_serialConfig->portName());
QObject::connect(_port, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error),
this, &SerialLink::linkError);
......@@ -219,17 +219,17 @@ bool SerialLink::_hardwareConnect(QSerialPort::SerialPortError& error, QString&
_port->setDataTerminalReady(true);
qCDebug(SerialLinkLog) << "Configuring port";
_port->setBaudRate (_config->baud());
_port->setDataBits (static_cast<QSerialPort::DataBits> (_config->dataBits()));
_port->setFlowControl (static_cast<QSerialPort::FlowControl> (_config->flowControl()));
_port->setStopBits (static_cast<QSerialPort::StopBits> (_config->stopBits()));
_port->setParity (static_cast<QSerialPort::Parity> (_config->parity()));
_port->setBaudRate (_serialConfig->baud());
_port->setDataBits (static_cast<QSerialPort::DataBits> (_serialConfig->dataBits()));
_port->setFlowControl (static_cast<QSerialPort::FlowControl> (_serialConfig->flowControl()));
_port->setStopBits (static_cast<QSerialPort::StopBits> (_serialConfig->stopBits()));
_port->setParity (static_cast<QSerialPort::Parity> (_serialConfig->parity()));
emit communicationUpdate(getName(), "Opened port!");
emit connected();
qCDebug(SerialLinkLog) << "Connection SeriaLink: " << "with settings" << _config->portName()
<< _config->baud() << _config->dataBits() << _config->parity() << _config->stopBits();
qCDebug(SerialLinkLog) << "Connection SeriaLink: " << "with settings" << _serialConfig->portName()
<< _serialConfig->baud() << _serialConfig->dataBits() << _serialConfig->parity() << _serialConfig->stopBits();
return true; // successful connection
}
......@@ -281,7 +281,7 @@ bool SerialLink::isConnected() const
QString SerialLink::getName() const
{
return _config->portName();
return _serialConfig->portName();
}
/**
......@@ -294,7 +294,7 @@ qint64 SerialLink::getConnectionSpeed() const
if (_port) {
baudRate = _port->baudRate();
} else {
baudRate = _config->baud();
baudRate = _serialConfig->baud();
}
qint64 dataRate;
switch (baudRate)
......@@ -334,11 +334,11 @@ qint64 SerialLink::getConnectionSpeed() const
void SerialLink::_resetConfiguration()
{
if (_port) {
_port->setBaudRate (_config->baud());
_port->setDataBits (static_cast<QSerialPort::DataBits> (_config->dataBits()));
_port->setFlowControl (static_cast<QSerialPort::FlowControl> (_config->flowControl()));
_port->setStopBits (static_cast<QSerialPort::StopBits> (_config->stopBits()));
_port->setParity (static_cast<QSerialPort::Parity> (_config->parity()));
_port->setBaudRate (_serialConfig->baud());
_port->setDataBits (static_cast<QSerialPort::DataBits> (_serialConfig->dataBits()));
_port->setFlowControl (static_cast<QSerialPort::FlowControl> (_serialConfig->flowControl()));
_port->setStopBits (static_cast<QSerialPort::StopBits> (_serialConfig->stopBits()));
_port->setParity (static_cast<QSerialPort::Parity> (_serialConfig->parity()));
}
}
......@@ -349,11 +349,6 @@ void SerialLink::_emitLinkError(const QString& errorMsg)
emit communicationError(tr("Link Error"), msg.arg(getName()).arg(errorMsg));
}
LinkConfiguration* SerialLink::getLinkConfiguration()
{
return _config;
}
//--------------------------------------------------------------------------
//-- SerialConfiguration
......
......@@ -133,7 +133,6 @@ class SerialLink : public LinkInterface
public:
// LinkInterface
LinkConfiguration* getLinkConfiguration();
QString getName() const;
void requestReset();
bool isConnected() const;
......@@ -168,7 +167,7 @@ private slots:
private:
// Links are only created/destroyed by LinkManager so constructor/destructor is not public
SerialLink(SerialConfiguration* config);
SerialLink(SharedLinkConfigurationPointer& config);
~SerialLink();
// From LinkInterface
......@@ -186,7 +185,7 @@ private:
volatile bool _reqReset;
QMutex _stoppMutex; // Mutex for accessing _stopp
QByteArray _transmitBuffer; // An internal buffer for receiving data from member functions and actually transmitting them via the serial port.
SerialConfiguration* _config;
SerialConfiguration* _serialConfig;
signals:
void aboutToCloseFlag();
......
......@@ -24,16 +24,14 @@
///
/// @author Don Gagne <don@thegagnes.com>
TCPLink::TCPLink(TCPConfiguration *config)
: _config(config)
TCPLink::TCPLink(SharedLinkConfigurationPointer& config)
: LinkInterface(config)
, _tcpConfig(qobject_cast<TCPConfiguration*>(config.data()))
, _socket(NULL)
, _socketIsConnected(false)
{
Q_ASSERT(_config != NULL);
// We're doing it wrong - because the Qt folks got the API wrong:
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
Q_ASSERT(_tcpConfig);
moveToThread(this);
//qDebug() << "TCP Created " << _config->name();
}
TCPLink::~TCPLink()
......@@ -69,7 +67,7 @@ void TCPLink::_writeDebugBytes(const QByteArray data)
ascii.append(219);
}
}
qDebug() << "Sent" << size << "bytes to" << _config->address().toString() << ":" << _config->port() << "data:";
qDebug() << "Sent" << size << "bytes to" << _tcpConfig->address().toString() << ":" << _tcpConfig->port() << "data:";
qDebug() << bytes;
qDebug() << "ASCII:" << ascii;
}
......@@ -148,7 +146,7 @@ bool TCPLink::_hardwareConnect()
_socket = new QTcpSocket();
QSignalSpy errorSpy(_socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error));
_socket->connectToHost(_config->address(), _config->port());
_socket->connectToHost(_tcpConfig->address(), _tcpConfig->port());
QObject::connect(_socket, &QTcpSocket::readyRead, this, &TCPLink::readBytes);
QObject::connect(_socket,static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error),
......@@ -189,7 +187,7 @@ bool TCPLink::isConnected() const
QString TCPLink::getName() const
{
return _config->name();
return _tcpConfig->name();
}
qint64 TCPLink::getConnectionSpeed() const
......
......@@ -121,7 +121,6 @@ class TCPLink : public LinkInterface
public:
QTcpSocket* getSocket(void) { return _socket; }
virtual LinkConfiguration* getLinkConfiguration() { return _config; }
void signalBytesWritten(void);
......@@ -160,7 +159,7 @@ protected:
private:
// Links are only created/destroyed by LinkManager so constructor/destructor is not public
TCPLink(TCPConfiguration* config);
TCPLink(SharedLinkConfigurationPointer& config);
~TCPLink();
// From LinkInterface
......@@ -174,7 +173,7 @@ private:
void _writeDebugBytes(const QByteArray data);
#endif
TCPConfiguration* _config;
TCPConfiguration* _tcpConfig;
QTcpSocket* _socket;
bool _socketIsConnected;
......
......@@ -65,27 +65,22 @@ static QString get_ip_address(const QString& address)
return QString("");
}
UDPLink::UDPLink(UDPConfiguration* config)
: _socket(NULL)
, _connectState(false)
#if defined(QGC_ZEROCONF_ENABLED)
UDPLink::UDPLink(SharedLinkConfigurationPointer& config)
: LinkInterface(config)
#if defined(QGC_ZEROCONF_ENABLED)
, _dnssServiceRef(NULL)
#endif
#endif
, _running(false)
, _socket(NULL)
, _udpConfig(qobject_cast<UDPConfiguration*>(config.data()))
, _connectState(false)
{
Q_ASSERT(config != NULL);
_config = config;
_config->setLink(this);
// We're doing it wrong - because the Qt folks got the API wrong:
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
Q_ASSERT(_udpConfig);
moveToThread(this);
}
UDPLink::~UDPLink()
{
// Disconnect link from configuration
_config->setLink(NULL);
_disconnect();
// Tell the thread to exit
_running = false;
......@@ -121,17 +116,17 @@ void UDPLink::_restartConnection()
QString UDPLink::getName() const
{
return _config->name();
return _udpConfig->name();
}
void UDPLink::addHost(const QString& host)
{
_config->addHost(host);
_udpConfig->addHost(host);
}
void UDPLink::removeHost(const QString& host)
{
_config->removeHost(host);
_udpConfig->removeHost(host);
}
void UDPLink::_writeBytes(const QByteArray data)
......@@ -143,7 +138,7 @@ void UDPLink::_writeBytes(const QByteArray data)
// Send to all connected systems
QString host;
int port;
if(_config->firstHost(host, port)) {
if(_udpConfig->firstHost(host, port)) {
do {
QHostAddress currentHost(host);
if(_socket->writeDatagram(data, currentHost, (quint16)port) < 0) {
......@@ -162,10 +157,10 @@ void UDPLink::_writeBytes(const QByteArray data)
// unit sent by UDP.
_logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch());
}
} while (_config->nextHost(host, port));
} while (_udpConfig->nextHost(host, port));
//-- Remove hosts that are no longer there
foreach (const QString& ghost, goneHosts) {
_config->removeHost(ghost);
_udpConfig->removeHost(ghost);
}
}
}
......@@ -194,7 +189,7 @@ void UDPLink::readBytes()
// added to the list and will start receiving datagrams from here. Even a port scanner
// would trigger this.
// Add host to broadcast list if not yet present, or update its port
_config->addHost(sender.toString(), (int)senderPort);
_udpConfig->addHost(sender.toString(), (int)senderPort);
}
//-- Send whatever is left
if(databuffer.size()) {
......@@ -248,7 +243,7 @@ bool UDPLink::_hardwareConnect()
QHostAddress host = QHostAddress::AnyIPv4;
_socket = new QUdpSocket();
_socket->setProxy(QNetworkProxy::NoProxy);
_connectState = _socket->bind(host, _config->localPort(), QAbstractSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
_connectState = _socket->bind(host, _udpConfig->localPort(), QAbstractSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
if (_connectState) {
//-- Make sure we have a large enough IO buffers
#ifdef __mobile__
......@@ -258,7 +253,7 @@ bool UDPLink::_hardwareConnect()
_socket->setSocketOption(QAbstractSocket::SendBufferSizeSocketOption, 256 * 1024);
_socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 512 * 1024);
#endif
_registerZeroconf(_config->localPort(), kZeroconfRegistration);
_registerZeroconf(_udpConfig->localPort(), kZeroconfRegistration);
QObject::connect(_socket, &QUdpSocket::readyRead, this, &UDPLink::readBytes);
emit connected();
} else {
......
......@@ -177,10 +177,7 @@ public:
bool connect(void);
bool disconnect(void);
LinkConfiguration* getLinkConfiguration() { return _config; }
public slots:
/*! @brief Add a new host to broadcast messages to */
void addHost (const QString& host);
/*! @brief Remove a host from broadcasting messages to */
......@@ -189,23 +186,11 @@ public slots:
void readBytes();
private slots:
/*!
* @brief Write a number of bytes to the interface.
*
* @param data Pointer to the data byte array
* @param size The size of the bytes array
**/
void _writeBytes(const QByteArray data);
protected:
QUdpSocket* _socket;
UDPConfiguration* _config;
bool _connectState;
private:
// Links are only created/destroyed by LinkManager so constructor/destructor is not public
UDPLink(UDPConfiguration* config);
UDPLink(SharedLinkConfigurationPointer& config);
~UDPLink();
// From LinkInterface
......@@ -223,6 +208,9 @@ private:
#endif
bool _running;
QUdpSocket* _socket;
UDPConfiguration* _udpConfig;
bool _connectState;
};
#endif // UDPLINK_H
......@@ -57,29 +57,29 @@ void LinkManagerTest::cleanup(void)
void LinkManagerTest::_add_test(void)
{
Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_linkMgr->links().count() == 0);
_connectMockLink();
QCOMPARE(_linkMgr->links()->count(), 1);
QCOMPARE(_linkMgr->links()->value<MockLink*>(0), _mockLink);
QCOMPARE(_linkMgr->links().count(), 1);
QCOMPARE(_linkMgr->links().at(0), _mockLink);
}
void LinkManagerTest::_delete_test(void)
{
Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_linkMgr->links().count() == 0);
_connectMockLink();
_disconnectMockLink();
QCOMPARE(_linkMgr->links()->count(), 0);
QCOMPARE(_linkMgr->links().count(), 0);
}
void LinkManagerTest::_addSignals_test(void)
{
Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_linkMgr->links().count() == 0);
Q_ASSERT(_multiSpy->checkNoSignals() == true);
_connectMockLink();
......@@ -99,7 +99,7 @@ void LinkManagerTest::_addSignals_test(void)
void LinkManagerTest::_deleteSignals_test(void)
{
Q_ASSERT(_linkMgr);
Q_ASSERT(_linkMgr->links()->count() == 0);
Q_ASSERT(_linkMgr->links().count() == 0);
Q_ASSERT(_multiSpy->checkNoSignals() == true);
_connectMockLink();
......
......@@ -17,8 +17,7 @@
#include "TCPLoopBackServer.h"
TCPLinkTest::TCPLinkTest(void)
: _config(NULL)
, _link(NULL)
: _link(NULL)
, _multiSpy(NULL)
{
......@@ -31,13 +30,12 @@ void TCPLinkTest::init(void)
Q_ASSERT(_link == nullptr);
Q_ASSERT(_multiSpy == nullptr);
Q_ASSERT(_config == nullptr);
_config = new TCPConfiguration("MockTCP");
_config->setAddress(QHostAddress::LocalHost);
_config->setPort(5760);
_link = new TCPLink(_config);
Q_ASSERT(_link != NULL);
TCPConfiguration* tcpConfig = new TCPConfiguration("MockTCP");
tcpConfig->setAddress(QHostAddress::LocalHost);
tcpConfig->setPort(5760);
_sharedConfig = SharedLinkConfigurationPointer(tcpConfig);
_link = new TCPLink(_sharedConfig);
_rgSignals[bytesReceivedSignalIndex] = SIGNAL(bytesReceived(LinkInterface*, QByteArray));
_rgSignals[connectedSignalIndex] = SIGNAL(connected(void));
......@@ -55,7 +53,6 @@ void TCPLinkTest::cleanup(void)
{
Q_ASSERT(_multiSpy);
Q_ASSERT(_link);
Q_ASSERT(_config);
delete _multiSpy;
_multiSpy = nullptr;
......@@ -63,15 +60,13 @@ void TCPLinkTest::cleanup(void)
delete _link;
_link = nullptr;
delete _config;
_config = nullptr;
_sharedConfig.clear();
UnitTest::cleanup();
}
void TCPLinkTest::_connectFail_test(void)
{
Q_ASSERT(_config);
Q_ASSERT(_link);
Q_ASSERT(_multiSpy);
Q_ASSERT(_multiSpy->checkNoSignals() == true);
......@@ -110,7 +105,8 @@ void TCPLinkTest::_connectSucceed_test(void)
Q_ASSERT(_multiSpy->checkNoSignals() == true);
// Start the server side
TCPLoopBackServer* server = new TCPLoopBackServer(_config->address(), _config->port());
TCPConfiguration* tcpConfig = qobject_cast<TCPConfiguration*>(_sharedConfig.data());
TCPLoopBackServer* server = new TCPLoopBackServer(tcpConfig->address(), tcpConfig->port());
Q_CHECK_PTR(server);
// Connect to the server
......
......@@ -60,11 +60,11 @@ private:
//deleteLinkSignalMask = 1 << deleteLinkSignalIndex,
};
TCPConfiguration* _config;
TCPLink* _link;
MultiSignalSpy* _multiSpy;
static const size_t _cSignals = maxSignalIndex;
const char* _rgSignals[_cSignals];
SharedLinkConfigurationPointer _sharedConfig;
TCPLink* _link;
MultiSignalSpy* _multiSpy;
static const size_t _cSignals = maxSignalIndex;
const char* _rgSignals[_cSignals];
};
#endif
......@@ -85,7 +85,10 @@ void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void)
linkConfig->setLogFilename(logFilename);
linkConfig->setName(linkConfig->logFilenameShort());
_ui->logFileNameLabel->setText(linkConfig->logFilenameShort());
_replayLink = (LogReplayLink*)qgcApp()->toolbox()->linkManager()->createConnectedLink(linkConfig);
LinkManager* linkMgr = qgcApp()->toolbox()->linkManager();
SharedLinkConfigurationPointer sharedConfig = linkMgr->addConfiguration(linkConfig);
_replayLink = (LogReplayLink*)qgcApp()->toolbox()->linkManager()->createConnectedLink(sharedConfig);
connect(_replayLink, &LogReplayLink::logFileStats, this, &QGCMAVLinkLogPlayer::_logFileStats);
connect(_replayLink, &LogReplayLink::playbackStarted, this, &QGCMAVLinkLogPlayer::_playbackStarted);
......
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