You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
6.7 KiB
297 lines
6.7 KiB
/*===================================================================== |
|
|
|
QGroundControl Open Source Ground Control Station |
|
|
|
(c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
|
|
|
This file is part of the QGROUNDCONTROL project |
|
|
|
QGROUNDCONTROL is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
QGROUNDCONTROL is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
======================================================================*/ |
|
|
|
#include <QTimer> |
|
#include <QList> |
|
#include <QDebug> |
|
#include <QMutexLocker> |
|
#include <iostream> |
|
#include "TCPLink.h" |
|
#include "LinkManager.h" |
|
#include "QGC.h" |
|
#include <QHostInfo> |
|
#include <QSignalSpy> |
|
|
|
/// @file |
|
/// @brief TCP link type for SITL support |
|
/// |
|
/// @author Don Gagne <don@thegagnes.com> |
|
|
|
TCPLink::TCPLink(QHostAddress hostAddress, quint16 socketPort) : |
|
_hostAddress(hostAddress), |
|
_port(socketPort), |
|
_socket(NULL), |
|
_socketIsConnected(false) |
|
{ |
|
_linkId = getNextLinkId(); |
|
_resetName(); |
|
|
|
qDebug() << "TCP Created " << _name; |
|
} |
|
|
|
TCPLink::~TCPLink() |
|
{ |
|
disconnect(); |
|
deleteLater(); |
|
} |
|
|
|
void TCPLink::run() |
|
{ |
|
exec(); |
|
} |
|
|
|
void TCPLink::setHostAddress(QHostAddress hostAddress) |
|
{ |
|
bool reconnect = false; |
|
|
|
if (this->isConnected()) { |
|
disconnect(); |
|
reconnect = true; |
|
} |
|
|
|
_hostAddress = hostAddress; |
|
_resetName(); |
|
|
|
if (reconnect) { |
|
connect(); |
|
} |
|
} |
|
|
|
void TCPLink::setHostAddress(const QString& hostAddress) |
|
{ |
|
setHostAddress(QHostAddress(hostAddress)); |
|
} |
|
|
|
void TCPLink::setPort(int port) |
|
{ |
|
bool reconnect = false; |
|
|
|
if (this->isConnected()) { |
|
disconnect(); |
|
reconnect = true; |
|
} |
|
|
|
_port = port; |
|
_resetName(); |
|
|
|
if (reconnect) { |
|
connect(); |
|
} |
|
} |
|
|
|
#ifdef TCPLINK_READWRITE_DEBUG |
|
void TCPLink::_writeDebugBytes(const char *data, qint16 size) |
|
{ |
|
QString bytes; |
|
QString ascii; |
|
for (int i=0; i<size; i++) |
|
{ |
|
unsigned char v = data[i]; |
|
bytes.append(QString().sprintf("%02x ", v)); |
|
if (data[i] > 31 && data[i] < 127) |
|
{ |
|
ascii.append(data[i]); |
|
} |
|
else |
|
{ |
|
ascii.append(219); |
|
} |
|
} |
|
qDebug() << "Sent" << size << "bytes to" << _hostAddress.toString() << ":" << _port << "data:"; |
|
qDebug() << bytes; |
|
qDebug() << "ASCII:" << ascii; |
|
} |
|
#endif |
|
|
|
void TCPLink::writeBytes(const char* data, qint64 size) |
|
{ |
|
#ifdef TCPLINK_READWRITE_DEBUG |
|
_writeDebugBytes(data, size); |
|
#endif |
|
_socket->write(data, size); |
|
|
|
// Log the amount and time written out for future data rate calculations. |
|
QMutexLocker dataRateLocker(&dataRateMutex); |
|
logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, size, QDateTime::currentMSecsSinceEpoch()); |
|
} |
|
|
|
/** |
|
* @brief Read a number of bytes from the interface. |
|
* |
|
* @param data Pointer to the data byte array to write the bytes to |
|
* @param maxLength The maximum number of bytes to write |
|
**/ |
|
void TCPLink::readBytes() |
|
{ |
|
qint64 byteCount = _socket->bytesAvailable(); |
|
|
|
if (byteCount) |
|
{ |
|
QByteArray buffer; |
|
buffer.resize(byteCount); |
|
|
|
_socket->read(buffer.data(), buffer.size()); |
|
|
|
emit bytesReceived(this, buffer); |
|
|
|
// Log the amount and time received for future data rate calculations. |
|
QMutexLocker dataRateLocker(&dataRateMutex); |
|
logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, byteCount, QDateTime::currentMSecsSinceEpoch()); |
|
|
|
#ifdef TCPLINK_READWRITE_DEBUG |
|
writeDebugBytes(buffer.data(), buffer.size()); |
|
#endif |
|
} |
|
} |
|
|
|
/** |
|
* @brief Get the number of bytes to read. |
|
* |
|
* @return The number of bytes to read |
|
**/ |
|
qint64 TCPLink::bytesAvailable() |
|
{ |
|
return _socket->bytesAvailable(); |
|
} |
|
|
|
/** |
|
* @brief Disconnect the connection. |
|
* |
|
* @return True if connection has been disconnected, false if connection couldn't be disconnected. |
|
**/ |
|
bool TCPLink::disconnect() |
|
{ |
|
quit(); |
|
wait(); |
|
|
|
if (_socket) |
|
{ |
|
_socket->disconnectFromHost(); |
|
_socketIsConnected = false; |
|
delete _socket; |
|
_socket = NULL; |
|
|
|
emit disconnected(); |
|
emit connected(false); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* @brief Connect the connection. |
|
* |
|
* @return True if connection has been established, false if connection couldn't be established. |
|
**/ |
|
bool TCPLink::connect() |
|
{ |
|
if (isRunning()) |
|
{ |
|
quit(); |
|
wait(); |
|
} |
|
bool connected = _hardwareConnect(); |
|
if (connected) { |
|
start(HighPriority); |
|
} |
|
return connected; |
|
} |
|
|
|
bool TCPLink::_hardwareConnect(void) |
|
{ |
|
Q_ASSERT(_socket == NULL); |
|
_socket = new QTcpSocket(); |
|
|
|
QSignalSpy errorSpy(_socket, SIGNAL(error(QAbstractSocket::SocketError))); |
|
|
|
_socket->connectToHost(_hostAddress, _port); |
|
|
|
QObject::connect(_socket, SIGNAL(readyRead()), this, SLOT(readBytes())); |
|
QObject::connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_socketError(QAbstractSocket::SocketError))); |
|
|
|
// Give the socket a second to connect to the other side otherwise error out |
|
if (!_socket->waitForConnected(1000)) |
|
{ |
|
// Whether a failed connection emits an error signal or not is platform specific. |
|
// So in cases where it is not emitted, we emit one ourselves. |
|
if (errorSpy.count() == 0) { |
|
emit communicationError(getName(), "Connection failed"); |
|
} |
|
delete _socket; |
|
_socket = NULL; |
|
return false; |
|
} |
|
|
|
_socketIsConnected = true; |
|
emit connected(true); |
|
emit connected(); |
|
|
|
return true; |
|
} |
|
|
|
void TCPLink::_socketError(QAbstractSocket::SocketError socketError) |
|
{ |
|
Q_UNUSED(socketError); |
|
emit communicationError(getName(), "Error on socket: " + _socket->errorString()); |
|
} |
|
|
|
/** |
|
* @brief Check if connection is active. |
|
* |
|
* @return True if link is connected, false otherwise. |
|
**/ |
|
bool TCPLink::isConnected() const |
|
{ |
|
return _socketIsConnected; |
|
} |
|
|
|
int TCPLink::getId() const |
|
{ |
|
return _linkId; |
|
} |
|
|
|
QString TCPLink::getName() const |
|
{ |
|
return _name; |
|
} |
|
|
|
qint64 TCPLink::getConnectionSpeed() const |
|
{ |
|
return 54000000; // 54 Mbit |
|
} |
|
|
|
qint64 TCPLink::getCurrentInDataRate() const |
|
{ |
|
return 0; |
|
} |
|
|
|
qint64 TCPLink::getCurrentOutDataRate() const |
|
{ |
|
return 0; |
|
} |
|
|
|
void TCPLink::_resetName(void) |
|
{ |
|
_name = QString("TCP Link (host:%1 port:%2)").arg(_hostAddress.toString()).arg(_port); |
|
emit nameChanged(_name); |
|
}
|
|
|