1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-30 15:52:12 +01:00

259 lines
8.6 KiB
C++
Raw Normal View History

2013-04-05 23:46:56 +03:00
/**
******************************************************************************
*
* @file telemetrymonitor.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup UAVTalkPlugin UAVTalk Plugin
* @{
* @brief The UAVTalk protocol plugin
*****************************************************************************/
/*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "telemetrymonitor.h"
#include "coreplugin/connectionmanager.h"
#include "coreplugin/icore.h"
/**
* Constructor
*/
TelemetryMonitor::TelemetryMonitor(UAVObjectManager *objMngr, Telemetry *tel) :
objMngr(objMngr),
tel(tel),
gcsStatsObj(GCSTelemetryStats::GetInstance(objMngr)),
flightStatsObj(FlightTelemetryStats::GetInstance(objMngr)),
firmwareIAPObj(FirmwareIAPObj::GetInstance(objMngr)),
statsTimer(new QTimer(this)),
objPending(NULL),
mutex(new QMutex(QMutex::Recursive)),
connectionTimer(new QTime())
2013-04-05 23:46:56 +03:00
{
// Listen for flight stats updates
connect(flightStatsObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(flightStatsUpdated(UAVObject *)));
2013-04-05 23:46:56 +03:00
// Start update timer
connect(statsTimer, SIGNAL(timeout()), this, SLOT(processStatsUpdates()));
statsTimer->start(STATS_CONNECT_PERIOD_MS);
}
TelemetryMonitor::~TelemetryMonitor()
{
2013-04-05 23:46:56 +03:00
// Before saying goodbye, set the GCS connection status to disconnected too:
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
2013-04-05 23:46:56 +03:00
gcsStats.Status = GCSTelemetryStats::STATUS_DISCONNECTED;
// Set data
gcsStatsObj->setData(gcsStats);
}
/**
* Initiate object retrieval, initialize queue with objects to be retrieved.
*/
void TelemetryMonitor::startRetrievingObjects()
{
// Clear object queue
queue.clear();
// Get all objects, add metaobjects, settings and data objects with OnChange update mode to the queue
QList< QList<UAVObject *> > objs = objMngr->getObjects();
for (int n = 0; n < objs.length(); ++n) {
UAVObject *obj = objs[n][0];
UAVMetaObject *mobj = dynamic_cast<UAVMetaObject *>(obj);
UAVDataObject *dobj = dynamic_cast<UAVDataObject *>(obj);
2013-04-05 23:46:56 +03:00
UAVObject::Metadata mdata = obj->getMetadata();
if (mobj != NULL) {
2013-04-05 23:46:56 +03:00
queue.enqueue(obj);
} else if (dobj != NULL) {
if (dobj->isSettings()) {
2013-04-05 23:46:56 +03:00
queue.enqueue(obj);
} else {
if (UAVObject::GetFlightTelemetryUpdateMode(mdata) == UAVObject::UPDATEMODE_ONCHANGE) {
2013-04-05 23:46:56 +03:00
queue.enqueue(obj);
}
}
}
}
// Start retrieving
qDebug() << tr("Starting to retrieve meta and settings objects from the autopilot (%1 objects)")
.arg(queue.length());
2013-04-05 23:46:56 +03:00
retrieveNextObject();
}
/**
* Cancel the object retrieval
*/
void TelemetryMonitor::stopRetrievingObjects()
{
qDebug("Object retrieval has been cancelled");
2013-04-05 23:46:56 +03:00
queue.clear();
}
/**
* Retrieve the next object in the queue
*/
void TelemetryMonitor::retrieveNextObject()
{
// If queue is empty return
if (queue.isEmpty()) {
qDebug("Object retrieval completed");
if (firmwareIAPObj->getBoardType()) {
emit connected();
} else {
connect(firmwareIAPObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(firmwareIAPUpdated(UAVObject *)));
}
2013-04-05 23:46:56 +03:00
return;
}
2013-04-05 23:46:56 +03:00
// Get next object from the queue
UAVObject *obj = queue.dequeue();
// qDebug( tr("Retrieving object: %1").arg(obj->getName()) );
2013-04-05 23:46:56 +03:00
// Connect to object
connect(obj, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool)));
2013-04-05 23:46:56 +03:00
// Request update
obj->requestUpdate();
objPending = obj;
}
/**
* Called by the retrieved object when a transaction is completed.
*/
void TelemetryMonitor::transactionCompleted(UAVObject *obj, bool success)
2013-04-05 23:46:56 +03:00
{
Q_UNUSED(success);
QMutexLocker locker(mutex);
if (obj == objPending) {
// Disconnect from sending object
obj->disconnect(this);
objPending = NULL;
// Process next object if telemetry is still available
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) {
retrieveNextObject();
} else {
stopRetrievingObjects();
}
2013-04-05 23:46:56 +03:00
}
}
/**
* Called each time the flight stats object is updated by the autopilot
*/
void TelemetryMonitor::flightStatsUpdated(UAVObject *obj)
2013-04-05 23:46:56 +03:00
{
Q_UNUSED(obj);
QMutexLocker locker(mutex);
// Force update if not yet connected
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
FlightTelemetryStats::DataFields flightStats = flightStatsObj->getData();
if (gcsStats.Status != GCSTelemetryStats::STATUS_CONNECTED ||
flightStats.Status != FlightTelemetryStats::STATUS_CONNECTED) {
2013-04-05 23:46:56 +03:00
processStatsUpdates();
}
}
/**
* Called each time the firmwareIAP object is updated by the autopilot
*/
void TelemetryMonitor::firmwareIAPUpdated(UAVObject *obj)
{
Q_UNUSED(obj);
QMutexLocker locker(mutex);
if (firmwareIAPObj->getBoardType() != 0) {
emit connected();
}
}
2013-04-05 23:46:56 +03:00
/**
* Called periodically to update the statistics and connection status.
*/
void TelemetryMonitor::processStatsUpdates()
{
QMutexLocker locker(mutex);
// Get telemetry stats
GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
FlightTelemetryStats::DataFields flightStats = flightStatsObj->getData();
Telemetry::TelemetryStats telStats = tel->getStats();
2013-04-05 23:46:56 +03:00
tel->resetStats();
// Update stats object
gcsStats.RxDataRate = (float)telStats.rxBytes / ((float)statsTimer->interval() / 1000.0);
gcsStats.TxDataRate = (float)telStats.txBytes / ((float)statsTimer->interval() / 1000.0);
2013-04-05 23:46:56 +03:00
gcsStats.RxFailures += telStats.rxErrors;
gcsStats.TxFailures += telStats.txErrors;
gcsStats.TxRetries += telStats.txRetries;
2013-04-05 23:46:56 +03:00
// Check for a connection timeout
bool connectionTimeout;
if (telStats.rxObjects > 0) {
2013-04-05 23:46:56 +03:00
connectionTimer->start();
}
if (connectionTimer->elapsed() > CONNECTION_TIMEOUT_MS) {
2013-04-05 23:46:56 +03:00
connectionTimeout = true;
} else {
2013-04-05 23:46:56 +03:00
connectionTimeout = false;
}
// Update connection state
int oldStatus = gcsStats.Status;
if (gcsStats.Status == GCSTelemetryStats::STATUS_DISCONNECTED) {
2013-04-05 23:46:56 +03:00
// Request connection
gcsStats.Status = GCSTelemetryStats::STATUS_HANDSHAKEREQ;
} else if (gcsStats.Status == GCSTelemetryStats::STATUS_HANDSHAKEREQ) {
2013-04-05 23:46:56 +03:00
// Check for connection acknowledge
if (flightStats.Status == FlightTelemetryStats::STATUS_HANDSHAKEACK) {
2013-04-05 23:46:56 +03:00
gcsStats.Status = GCSTelemetryStats::STATUS_CONNECTED;
}
} else if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) {
2013-04-05 23:46:56 +03:00
// Check if the connection is still active and the the autopilot is still connected
if (flightStats.Status == FlightTelemetryStats::STATUS_DISCONNECTED || connectionTimeout) {
2013-04-05 23:46:56 +03:00
gcsStats.Status = GCSTelemetryStats::STATUS_DISCONNECTED;
}
}
emit telemetryUpdated((double) gcsStats.TxDataRate, (double) gcsStats.RxDataRate);
2013-04-05 23:46:56 +03:00
// Set data
gcsStatsObj->setData(gcsStats);
// Force telemetry update if not yet connected
if (gcsStats.Status != GCSTelemetryStats::STATUS_CONNECTED ||
flightStats.Status != FlightTelemetryStats::STATUS_CONNECTED) {
2013-04-05 23:46:56 +03:00
gcsStatsObj->updated();
}
// Act on new connections or disconnections
if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED && gcsStats.Status != oldStatus) {
2013-04-05 23:46:56 +03:00
statsTimer->setInterval(STATS_UPDATE_PERIOD_MS);
qDebug("Connection with the autopilot established");
2013-04-05 23:46:56 +03:00
startRetrievingObjects();
}
if (gcsStats.Status == GCSTelemetryStats::STATUS_DISCONNECTED && gcsStats.Status != oldStatus) {
2013-04-05 23:46:56 +03:00
statsTimer->setInterval(STATS_CONNECT_PERIOD_MS);
qDebug("Connection with the autopilot lost");
qDebug("Trying to connect to the autopilot");
2013-04-05 23:46:56 +03:00
emit disconnected();
}
}