mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-03-01 18:29:16 +01:00
OP-1122 OP-1125 made GCS telemetry and uavtalk a bit more robust (more error case handling)
minor cleanup and code reorganization some preparatory work to read from IODevice from its own thread
This commit is contained in:
parent
4f9231e247
commit
612e66367a
@ -230,11 +230,6 @@ void Telemetry::transactionCompleted(UAVObject *obj, bool success)
|
|||||||
// Lookup the transaction in the transaction map.
|
// Lookup the transaction in the transaction map.
|
||||||
ObjectTransactionInfo *transInfo = findTransaction(obj);
|
ObjectTransactionInfo *transInfo = findTransaction(obj);
|
||||||
if (transInfo) {
|
if (transInfo) {
|
||||||
// Remove this transaction as it's complete.
|
|
||||||
transInfo->timer->stop();
|
|
||||||
closeTransaction(transInfo);
|
|
||||||
delete transInfo;
|
|
||||||
// Send signal
|
|
||||||
if (success) {
|
if (success) {
|
||||||
#ifdef VERBOSE_TELEMETRY
|
#ifdef VERBOSE_TELEMETRY
|
||||||
qDebug() << "Telemetry - transaction successful for object" << obj->toStringBrief();
|
qDebug() << "Telemetry - transaction successful for object" << obj->toStringBrief();
|
||||||
@ -242,7 +237,13 @@ void Telemetry::transactionCompleted(UAVObject *obj, bool success)
|
|||||||
} else {
|
} else {
|
||||||
qWarning() << "Telemetry - !!! transaction failed for object" << obj->toStringBrief();
|
qWarning() << "Telemetry - !!! transaction failed for object" << obj->toStringBrief();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove this transaction as it's complete.
|
||||||
|
closeTransaction(transInfo);
|
||||||
|
|
||||||
|
// Send signal
|
||||||
obj->emitTransactionCompleted(success);
|
obj->emitTransactionCompleted(success);
|
||||||
|
|
||||||
// Process new object updates from queue
|
// Process new object updates from queue
|
||||||
processObjectQueue();
|
processObjectQueue();
|
||||||
} else {
|
} else {
|
||||||
@ -255,30 +256,33 @@ void Telemetry::transactionCompleted(UAVObject *obj, bool success)
|
|||||||
*/
|
*/
|
||||||
void Telemetry::transactionTimeout(ObjectTransactionInfo *transInfo)
|
void Telemetry::transactionTimeout(ObjectTransactionInfo *transInfo)
|
||||||
{
|
{
|
||||||
transInfo->timer->stop();
|
|
||||||
// Check if more retries are pending
|
// Check if more retries are pending
|
||||||
if (transInfo->retriesRemaining > 0) {
|
if (transInfo->retriesRemaining > 0) {
|
||||||
#ifdef VERBOSE_TELEMETRY
|
#ifdef VERBOSE_TELEMETRY
|
||||||
qDebug().nospace() << "Telemetry - transaction timed out for object " << transInfo->obj->toStringBrief() << ", retrying...";
|
qDebug().nospace() << "Telemetry - transaction timed out for object " << transInfo->obj->toStringBrief() << ", retrying...";
|
||||||
#endif
|
#endif
|
||||||
--transInfo->retriesRemaining;
|
|
||||||
processObjectTransaction(transInfo);
|
|
||||||
++txRetries;
|
++txRetries;
|
||||||
|
--transInfo->retriesRemaining;
|
||||||
|
|
||||||
|
// Retry the transaction
|
||||||
|
processObjectTransaction(transInfo);
|
||||||
} else {
|
} else {
|
||||||
// Stop the timer.
|
qWarning().nospace() << "Telemetry - !!! transaction timed out for object " << transInfo->obj->toStringBrief();
|
||||||
transInfo->timer->stop();
|
|
||||||
|
++txErrors;
|
||||||
|
|
||||||
// Terminate transaction
|
// Terminate transaction
|
||||||
utalk->cancelTransaction(transInfo->obj);
|
utalk->cancelTransaction(transInfo->obj);
|
||||||
// Send signal
|
|
||||||
qWarning().nospace() << "Telemetry - !!! transaction timed out for object " << transInfo->obj->toStringBrief();
|
|
||||||
transInfo->obj->emitTransactionCompleted(false);
|
|
||||||
// Remove this transaction as it's complete.
|
// Remove this transaction as it's complete.
|
||||||
// FIXME : also remove transaction from UAVTalk transaction map
|
UAVObject *obj = transInfo->obj;
|
||||||
closeTransaction(transInfo);
|
closeTransaction(transInfo);
|
||||||
delete transInfo;
|
|
||||||
|
// Send signal
|
||||||
|
obj->emitTransactionCompleted(false);
|
||||||
|
|
||||||
// Process new object updates from queue
|
// Process new object updates from queue
|
||||||
processObjectQueue();
|
processObjectQueue();
|
||||||
++txErrors;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,24 +292,33 @@ void Telemetry::transactionTimeout(ObjectTransactionInfo *transInfo)
|
|||||||
void Telemetry::processObjectTransaction(ObjectTransactionInfo *transInfo)
|
void Telemetry::processObjectTransaction(ObjectTransactionInfo *transInfo)
|
||||||
{
|
{
|
||||||
// Initiate transaction
|
// Initiate transaction
|
||||||
|
bool sent = false;
|
||||||
if (transInfo->objRequest) {
|
if (transInfo->objRequest) {
|
||||||
#ifdef VERBOSE_TELEMETRY
|
#ifdef VERBOSE_TELEMETRY
|
||||||
qDebug().nospace() << "Telemetry - sending object request for " << transInfo->obj->toStringBrief() << ", " << (transInfo->allInstances ? "all" : "single") << " " << (transInfo->acked ? "acked" : "");
|
qDebug().nospace() << "Telemetry - sending request for object " << transInfo->obj->toStringBrief() << ", " << (transInfo->allInstances ? "all" : "single") << " " << (transInfo->acked ? "acked" : "");
|
||||||
#endif
|
#endif
|
||||||
utalk->sendObjectRequest(transInfo->obj, transInfo->allInstances);
|
sent = utalk->sendObjectRequest(transInfo->obj, transInfo->allInstances);
|
||||||
} else {
|
} else {
|
||||||
#ifdef VERBOSE_TELEMETRY
|
#ifdef VERBOSE_TELEMETRY
|
||||||
qDebug().nospace() << "Telemetry - sending object " << transInfo->obj->toStringBrief() << ", " << (transInfo->allInstances ? "all" : "single") << " " << (transInfo->acked ? "acked" : "");
|
qDebug().nospace() << "Telemetry - sending object " << transInfo->obj->toStringBrief() << ", " << (transInfo->allInstances ? "all" : "single") << " " << (transInfo->acked ? "acked" : "");
|
||||||
#endif
|
#endif
|
||||||
utalk->sendObject(transInfo->obj, transInfo->acked, transInfo->allInstances);
|
sent = utalk->sendObject(transInfo->obj, transInfo->acked, transInfo->allInstances);
|
||||||
}
|
}
|
||||||
// Start timer if a response is expected
|
// Check if a response is needed now or will arrive asynchronously
|
||||||
if (transInfo->objRequest || transInfo->acked) {
|
if (transInfo->objRequest || transInfo->acked) {
|
||||||
transInfo->timer->start(REQ_TIMEOUT_MS);
|
if (sent) {
|
||||||
} else {
|
// Start timer if a response is expected
|
||||||
// Otherwise, remove this transaction as it's complete.
|
transInfo->timer->start(REQ_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// message was not sent, the transaction will not complete and will timeout
|
||||||
|
// there is no need to wait to close the transaction and notify of completion failure
|
||||||
|
//transactionCompleted(transInfo->obj, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// not transacted, so just close the transaction with no notification of completion
|
||||||
closeTransaction(transInfo);
|
closeTransaction(transInfo);
|
||||||
delete transInfo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +393,7 @@ void Telemetry::processObjectQueue()
|
|||||||
// TODO make the above logic a reality...
|
// TODO make the above logic a reality...
|
||||||
if (findTransaction(objInfo.obj)) {
|
if (findTransaction(objInfo.obj)) {
|
||||||
qWarning() << "Telemetry - !!! Making request for a object " << objInfo.obj->toStringBrief() << " for which a request is already in progress";
|
qWarning() << "Telemetry - !!! Making request for a object " << objInfo.obj->toStringBrief() << " for which a request is already in progress";
|
||||||
objInfo.obj->emitTransactionCompleted(false);
|
//objInfo.obj->emitTransactionCompleted(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UAVObject::Metadata metadata = objInfo.obj->getMetadata();
|
UAVObject::Metadata metadata = objInfo.obj->getMetadata();
|
||||||
@ -599,6 +612,7 @@ void Telemetry::closeTransaction(ObjectTransactionInfo *trans)
|
|||||||
// Keep the map even if it is empty
|
// Keep the map even if it is empty
|
||||||
// There are at most 100 different object IDs...
|
// There are at most 100 different object IDs...
|
||||||
}
|
}
|
||||||
|
delete trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Telemetry::closeAllTransactions()
|
void Telemetry::closeAllTransactions()
|
||||||
@ -626,7 +640,7 @@ ObjectTransactionInfo::ObjectTransactionInfo(QObject *parent) : QObject(parent)
|
|||||||
telem = 0;
|
telem = 0;
|
||||||
// Setup transaction timer
|
// Setup transaction timer
|
||||||
timer = new QTimer(this);
|
timer = new QTimer(this);
|
||||||
timer->stop();
|
timer->setSingleShot(true);
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,7 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/threadmanager.h>
|
#include <coreplugin/threadmanager.h>
|
||||||
|
|
||||||
TelemetryManager::TelemetryManager() :
|
TelemetryManager::TelemetryManager() : autopilotConnected(false)
|
||||||
autopilotConnected(false)
|
|
||||||
{
|
{
|
||||||
moveToThread(Core::ICore::instance()->threadManager()->getRealTimeThread());
|
moveToThread(Core::ICore::instance()->threadManager()->getRealTimeThread());
|
||||||
// Get UAVObjectManager instance
|
// Get UAVObjectManager instance
|
||||||
@ -44,7 +43,8 @@ TelemetryManager::TelemetryManager() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
TelemetryManager::~TelemetryManager()
|
TelemetryManager::~TelemetryManager()
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool TelemetryManager::isConnected()
|
bool TelemetryManager::isConnected()
|
||||||
{
|
{
|
||||||
@ -62,6 +62,29 @@ void TelemetryManager::onStart()
|
|||||||
utalk = new UAVTalk(device, objMngr);
|
utalk = new UAVTalk(device, objMngr);
|
||||||
telemetry = new Telemetry(utalk, objMngr);
|
telemetry = new Telemetry(utalk, objMngr);
|
||||||
telemetryMon = new TelemetryMonitor(objMngr, telemetry);
|
telemetryMon = new TelemetryMonitor(objMngr, telemetry);
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
// UAVTalk must be thread safe and for that:
|
||||||
|
// 1- all public methods must lock a mutex
|
||||||
|
// 2- the reader thread must lock that mutex too
|
||||||
|
// The reader thread locks the mutex once a packet is read and decoded.
|
||||||
|
// It is assumed that the UAVObjectManager is thread safe
|
||||||
|
|
||||||
|
// Create the reader and move it to the reader thread
|
||||||
|
IODeviceReader *reader = new IODeviceReader(utalk);
|
||||||
|
reader->moveToThread(&readerThread);
|
||||||
|
// The reader will be deleted (later) when the thread finishes
|
||||||
|
connect(&readerThread, &QThread::finished, reader, &QObject::deleteLater);
|
||||||
|
// Connect IO device to reader
|
||||||
|
connect(device, SIGNAL(readyRead()), reader, SLOT(read()));
|
||||||
|
// start the reader thread
|
||||||
|
readerThread.start();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Connect IO device to reader
|
||||||
|
connect(device, SIGNAL(readyRead()), utalk, SLOT(processInputStream()));
|
||||||
|
}
|
||||||
|
|
||||||
connect(telemetryMon, SIGNAL(connected()), this, SLOT(onConnect()));
|
connect(telemetryMon, SIGNAL(connected()), this, SLOT(onConnect()));
|
||||||
connect(telemetryMon, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
|
connect(telemetryMon, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
|
||||||
}
|
}
|
||||||
@ -70,6 +93,11 @@ void TelemetryManager::onStart()
|
|||||||
void TelemetryManager::stop()
|
void TelemetryManager::stop()
|
||||||
{
|
{
|
||||||
emit myStop();
|
emit myStop();
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
readerThread.quit();
|
||||||
|
readerThread.wait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TelemetryManager::onStop()
|
void TelemetryManager::onStop()
|
||||||
@ -92,3 +120,13 @@ void TelemetryManager::onDisconnect()
|
|||||||
autopilotConnected = false;
|
autopilotConnected = false;
|
||||||
emit disconnected();
|
emit disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IODeviceReader::IODeviceReader(UAVTalk *uavTalk) : uavTalk(uavTalk)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IODeviceReader::read()
|
||||||
|
{
|
||||||
|
uavTalk->processInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,20 @@ private:
|
|||||||
TelemetryMonitor *telemetryMon;
|
TelemetryMonitor *telemetryMon;
|
||||||
QIODevice *device;
|
QIODevice *device;
|
||||||
bool autopilotConnected;
|
bool autopilotConnected;
|
||||||
|
QThread readerThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class IODeviceReader : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
IODeviceReader(UAVTalk *uavTalk);
|
||||||
|
|
||||||
|
UAVTalk *uavTalk;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void read();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TELEMETRYMANAGER_H
|
#endif // TELEMETRYMANAGER_H
|
||||||
|
@ -25,11 +25,13 @@
|
|||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "uavtalk.h"
|
#include "uavtalk.h"
|
||||||
#include <QtEndian>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <coreplugin/generalsettings.h>
|
#include <coreplugin/generalsettings.h>
|
||||||
|
|
||||||
|
#include <QtEndian>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QEventLoop>
|
||||||
|
|
||||||
// #define UAVTALK_DEBUG
|
// #define UAVTALK_DEBUG
|
||||||
#ifdef UAVTALK_DEBUG
|
#ifdef UAVTALK_DEBUG
|
||||||
#define UAVTALK_QXTLOG_DEBUG(args ...)
|
#define UAVTALK_QXTLOG_DEBUG(args ...)
|
||||||
@ -64,20 +66,13 @@ const quint8 UAVTalk::crc_table[256] = {
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
UAVTalk::UAVTalk(QIODevice *iodev, UAVObjectManager *objMngr)
|
UAVTalk::UAVTalk(QIODevice *iodev, UAVObjectManager *objMngr) : io(iodev), objMngr(objMngr), mutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
io = iodev;
|
|
||||||
|
|
||||||
this->objMngr = objMngr;
|
|
||||||
|
|
||||||
rxState = STATE_SYNC;
|
rxState = STATE_SYNC;
|
||||||
rxPacketLength = 0;
|
rxPacketLength = 0;
|
||||||
|
|
||||||
mutex = new QMutex(QMutex::Recursive);
|
|
||||||
|
|
||||||
memset(&stats, 0, sizeof(ComStats));
|
memset(&stats, 0, sizeof(ComStats));
|
||||||
|
|
||||||
connect(io, SIGNAL(readyRead()), this, SLOT(processInputStream()));
|
|
||||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||||
Core::Internal::GeneralSettings *settings = pm->getObject<Core::Internal::GeneralSettings>();
|
Core::Internal::GeneralSettings *settings = pm->getObject<Core::Internal::GeneralSettings>();
|
||||||
useUDPMirror = settings->useUDPMirror();
|
useUDPMirror = settings->useUDPMirror();
|
||||||
@ -94,9 +89,9 @@ UAVTalk::UAVTalk(QIODevice *iodev, UAVObjectManager *objMngr)
|
|||||||
|
|
||||||
UAVTalk::~UAVTalk()
|
UAVTalk::~UAVTalk()
|
||||||
{
|
{
|
||||||
// According to Qt, it is not necessary to disconnect upon
|
// According to Qt, it is not necessary to disconnect upon object deletion.
|
||||||
// object deletion.
|
// disconnect(io, SIGNAL(readyRead()), worker, SLOT(processInputStream()));
|
||||||
// disconnect(io, SIGNAL(readyRead()), this, SLOT(processInputStream()));
|
|
||||||
closeAllTransactions();
|
closeAllTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +101,7 @@ UAVTalk::~UAVTalk()
|
|||||||
*/
|
*/
|
||||||
void UAVTalk::resetStats()
|
void UAVTalk::resetStats()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(mutex);
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
memset(&stats, 0, sizeof(ComStats));
|
memset(&stats, 0, sizeof(ComStats));
|
||||||
}
|
}
|
||||||
@ -116,26 +111,11 @@ void UAVTalk::resetStats()
|
|||||||
*/
|
*/
|
||||||
UAVTalk::ComStats UAVTalk::getStats()
|
UAVTalk::ComStats UAVTalk::getStats()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(mutex);
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called each time there are data in the input buffer
|
|
||||||
*/
|
|
||||||
void UAVTalk::processInputStream()
|
|
||||||
{
|
|
||||||
quint8 tmp;
|
|
||||||
|
|
||||||
if (io && io->isReadable()) {
|
|
||||||
while (io->bytesAvailable() > 0) {
|
|
||||||
io->read((char *)&tmp, 1);
|
|
||||||
processInputByte(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UAVTalk::dummyUDPRead()
|
void UAVTalk::dummyUDPRead()
|
||||||
{
|
{
|
||||||
QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender());
|
QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender());
|
||||||
@ -147,6 +127,35 @@ void UAVTalk::dummyUDPRead()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the specified object through the telemetry link.
|
||||||
|
* \param[in] obj Object to send
|
||||||
|
* \param[in] acked Selects if an ack is required
|
||||||
|
* \param[in] allInstances If set true then all instances will be updated
|
||||||
|
* \return Success (true), Failure (false)
|
||||||
|
*/
|
||||||
|
bool UAVTalk::sendObject(UAVObject *obj, bool acked, bool allInstances)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
|
quint16 instId = 0;
|
||||||
|
|
||||||
|
if (allInstances) {
|
||||||
|
instId = ALL_INSTANCES;
|
||||||
|
}
|
||||||
|
else if (obj) {
|
||||||
|
instId = obj->getInstID();
|
||||||
|
}
|
||||||
|
bool success = false;
|
||||||
|
if (acked) {
|
||||||
|
success = objectTransaction(TYPE_OBJ_ACK, obj->getObjID(), instId, obj);
|
||||||
|
} else {
|
||||||
|
success = objectTransaction(TYPE_OBJ, obj->getObjID(), instId, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request an update for the specified object, on success the object data would have been
|
* Request an update for the specified object, on success the object data would have been
|
||||||
* updated by the GCS.
|
* updated by the GCS.
|
||||||
@ -156,7 +165,7 @@ void UAVTalk::dummyUDPRead()
|
|||||||
*/
|
*/
|
||||||
bool UAVTalk::sendObjectRequest(UAVObject *obj, bool allInstances)
|
bool UAVTalk::sendObjectRequest(UAVObject *obj, bool allInstances)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(mutex);
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
quint16 instId = 0;
|
quint16 instId = 0;
|
||||||
|
|
||||||
@ -169,38 +178,12 @@ bool UAVTalk::sendObjectRequest(UAVObject *obj, bool allInstances)
|
|||||||
return objectTransaction(TYPE_OBJ_REQ, obj->getObjID(), instId, obj);
|
return objectTransaction(TYPE_OBJ_REQ, obj->getObjID(), instId, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the specified object through the telemetry link.
|
|
||||||
* \param[in] obj Object to send
|
|
||||||
* \param[in] acked Selects if an ack is required
|
|
||||||
* \param[in] allInstances If set true then all instances will be updated
|
|
||||||
* \return Success (true), Failure (false)
|
|
||||||
*/
|
|
||||||
bool UAVTalk::sendObject(UAVObject *obj, bool acked, bool allInstances)
|
|
||||||
{
|
|
||||||
QMutexLocker locker(mutex);
|
|
||||||
|
|
||||||
quint16 instId = 0;
|
|
||||||
|
|
||||||
if (allInstances) {
|
|
||||||
instId = ALL_INSTANCES;
|
|
||||||
}
|
|
||||||
else if (obj) {
|
|
||||||
instId = obj->getInstID();
|
|
||||||
}
|
|
||||||
if (acked) {
|
|
||||||
return objectTransaction(TYPE_OBJ_ACK, obj->getObjID(), instId, obj);
|
|
||||||
} else {
|
|
||||||
return objectTransaction(TYPE_OBJ, obj->getObjID(), instId, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel a pending transaction
|
* Cancel a pending transaction
|
||||||
*/
|
*/
|
||||||
void UAVTalk::cancelTransaction(UAVObject *obj)
|
void UAVTalk::cancelTransaction(UAVObject *obj)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(mutex);
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
if (io.isNull()) {
|
if (io.isNull()) {
|
||||||
return;
|
return;
|
||||||
@ -240,6 +223,21 @@ bool UAVTalk::objectTransaction(quint8 type, quint32 objId, quint16 instId, UAVO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called each time there are data in the input buffer
|
||||||
|
*/
|
||||||
|
void UAVTalk::processInputStream()
|
||||||
|
{
|
||||||
|
quint8 tmp;
|
||||||
|
|
||||||
|
if (io && io->isReadable()) {
|
||||||
|
while (io->bytesAvailable() > 0) {
|
||||||
|
io->read((char *)&tmp, 1);
|
||||||
|
processInputByte(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process an byte from the telemetry stream.
|
* Process an byte from the telemetry stream.
|
||||||
* \param[in] rxbyte Received byte
|
* \param[in] rxbyte Received byte
|
||||||
@ -446,18 +444,18 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex->lock();
|
mutex.lock();
|
||||||
|
|
||||||
receiveObject(rxType, rxObjId, rxInstId, rxBuffer, rxLength);
|
receiveObject(rxType, rxObjId, rxInstId, rxBuffer, rxLength);
|
||||||
|
|
||||||
if (useUDPMirror) {
|
|
||||||
udpSocketTx->writeDatagram(rxDataArray, QHostAddress::LocalHost, udpSocketRx->localPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
stats.rxObjectBytes += rxLength;
|
stats.rxObjectBytes += rxLength;
|
||||||
stats.rxObjects++;
|
stats.rxObjects++;
|
||||||
|
|
||||||
mutex->unlock();
|
mutex.unlock();
|
||||||
|
|
||||||
|
if (useUDPMirror) {
|
||||||
|
udpSocketTx->writeDatagram(rxDataArray, QHostAddress::LocalHost, udpSocketRx->localPort());
|
||||||
|
}
|
||||||
|
|
||||||
rxState = STATE_SYNC;
|
rxState = STATE_SYNC;
|
||||||
UAVTALK_QXTLOG_DEBUG("UAVTalk: CSum->Sync (OK)");
|
UAVTALK_QXTLOG_DEBUG("UAVTalk: CSum->Sync (OK)");
|
||||||
@ -661,7 +659,17 @@ void UAVTalk::updateAck(quint8 type, quint32 objId, quint16 instId, UAVObject *o
|
|||||||
}
|
}
|
||||||
Transaction *trans = findTransaction(objId, instId);
|
Transaction *trans = findTransaction(objId, instId);
|
||||||
if (trans && trans->respType == type) {
|
if (trans && trans->respType == type) {
|
||||||
if (trans->respInstId != ALL_INSTANCES || instId == 0) {
|
if (trans->respInstId == ALL_INSTANCES) {
|
||||||
|
if (instId == 0) {
|
||||||
|
// last instance received, complete transaction
|
||||||
|
closeTransaction(trans);
|
||||||
|
emit transactionCompleted(obj, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO extend timeout?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
closeTransaction(trans);
|
closeTransaction(trans);
|
||||||
emit transactionCompleted(obj, true);
|
emit transactionCompleted(obj, true);
|
||||||
}
|
}
|
||||||
@ -705,14 +713,27 @@ bool UAVTalk::transmitObject(quint8 type, quint32 objId, quint16 instId, UAVObje
|
|||||||
// Process message type
|
// Process message type
|
||||||
if (type == TYPE_OBJ || type == TYPE_OBJ_ACK) {
|
if (type == TYPE_OBJ || type == TYPE_OBJ_ACK) {
|
||||||
if (allInstances) {
|
if (allInstances) {
|
||||||
// Get number of instances
|
|
||||||
quint32 numInst = objMngr->getNumInstances(objId);
|
|
||||||
// Send all instances in reverse order
|
// Send all instances in reverse order
|
||||||
// This allows the receiver to detect when the last object has been received (i.e. when instance 0 is received)
|
// This allows the receiver to detect when the last object has been received (i.e. when instance 0 is received)
|
||||||
|
quint32 numInst = objMngr->getNumInstances(objId);
|
||||||
for (quint32 n = 0; n < numInst; ++n) {
|
for (quint32 n = 0; n < numInst; ++n) {
|
||||||
quint32 i = numInst - n - 1;
|
quint32 i = numInst - n - 1;
|
||||||
|
|
||||||
UAVObject *o = objMngr->getObject(objId, i);
|
UAVObject *o = objMngr->getObject(objId, i);
|
||||||
transmitSingleObject(type, objId, i, o);
|
if (!transmitSingleObject(type, objId, i, o)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
// yield
|
||||||
|
mutex.unlock();
|
||||||
|
// going back to the event loop is necessary to allow timeout events to be fired
|
||||||
|
// but don't allow user events as the event can cause the main thread to reenter UAVTalk
|
||||||
|
// the timer event suffers from the same issue but this case is handled
|
||||||
|
//QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 10);
|
||||||
|
QThread::msleep(1);
|
||||||
|
mutex.lock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,19 +27,22 @@
|
|||||||
#ifndef UAVTALK_H
|
#ifndef UAVTALK_H
|
||||||
#define UAVTALK_H
|
#define UAVTALK_H
|
||||||
|
|
||||||
|
#include "uavobjectmanager.h"
|
||||||
|
#include "uavtalk_global.h"
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QSemaphore>
|
#include <QThread>
|
||||||
#include "uavobjectmanager.h"
|
|
||||||
#include "uavtalk_global.h"
|
|
||||||
#include <QtNetwork/QUdpSocket>
|
#include <QtNetwork/QUdpSocket>
|
||||||
|
|
||||||
class UAVTALK_EXPORT UAVTalk : public QObject {
|
class UAVTALK_EXPORT UAVTalk : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class IODeviceReader;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const quint16 ALL_INSTANCES = 0xFFFF;
|
static const quint16 ALL_INSTANCES = 0xFFFF;
|
||||||
|
|
||||||
@ -56,17 +59,19 @@ public:
|
|||||||
|
|
||||||
UAVTalk(QIODevice *iodev, UAVObjectManager *objMngr);
|
UAVTalk(QIODevice *iodev, UAVObjectManager *objMngr);
|
||||||
~UAVTalk();
|
~UAVTalk();
|
||||||
|
|
||||||
|
ComStats getStats();
|
||||||
|
void resetStats();
|
||||||
|
|
||||||
bool sendObject(UAVObject *obj, bool acked, bool allInstances);
|
bool sendObject(UAVObject *obj, bool acked, bool allInstances);
|
||||||
bool sendObjectRequest(UAVObject *obj, bool allInstances);
|
bool sendObjectRequest(UAVObject *obj, bool allInstances);
|
||||||
void cancelTransaction(UAVObject *obj);
|
void cancelTransaction(UAVObject *obj);
|
||||||
ComStats getStats();
|
|
||||||
void resetStats();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void transactionCompleted(UAVObject *obj, bool success);
|
void transactionCompleted(UAVObject *obj, bool success);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void processInputStream(void);
|
void processInputStream();
|
||||||
void dummyUDPRead();
|
void dummyUDPRead();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -106,7 +111,7 @@ private:
|
|||||||
// Variables
|
// Variables
|
||||||
QPointer<QIODevice> io;
|
QPointer<QIODevice> io;
|
||||||
UAVObjectManager *objMngr;
|
UAVObjectManager *objMngr;
|
||||||
QMutex *mutex;
|
QMutex mutex;
|
||||||
QMap<quint32, QMap<quint32, Transaction *> *> transMap;
|
QMap<quint32, QMap<quint32, Transaction *> *> transMap;
|
||||||
quint8 rxBuffer[MAX_PACKET_LENGTH];
|
quint8 rxBuffer[MAX_PACKET_LENGTH];
|
||||||
quint8 txBuffer[MAX_PACKET_LENGTH];
|
quint8 txBuffer[MAX_PACKET_LENGTH];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user