dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
telemetry.cpp
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  *
31  * Additional note on redistribution: The copyright and license notices above
32  * must be maintained in each individual source file that is a derivative work
33  * of this source file; otherwise redistribution is prohibited.
34  */
35 
36 #include "telemetry.h"
37 #include "hwtaulink.h"
38 #include "objectpersistence.h"
39 #include <QTime>
40 #include <QtGlobal>
41 #include <stdlib.h>
42 #include <QDebug>
43 
44 #ifdef TELEMETRY_DEBUG
45 #define TELEMETRY_QXTLOG_DEBUG(...) qDebug() << (__VA_ARGS__)
46 #else // TELEMETRY_DEBUG
47 #define TELEMETRY_QXTLOG_DEBUG(...)
48 #endif // TELEMETRY_DEBUG
49 
54 {
55 public:
56  TransactionKey(quint32 objId, quint32 instId, bool req)
57  {
58  this->objId = objId;
59  this->instId = instId;
60  this->req = req;
61  }
62 
64  {
65  this->objId = obj->getObjID();
66  this->instId = obj->getInstID();
67  this->req = req;
68  }
69 
70  // See if this is an equivalent transaction key
71  bool operator==(const TransactionKey &rhs) const
72  {
73  return (rhs.objId == objId && rhs.instId == instId && rhs.req == req);
74  }
75 
76  bool operator<(const TransactionKey &rhs) const
77  {
78  return objId < rhs.objId || (objId == rhs.objId && instId < rhs.instId)
79  || (objId == rhs.objId && instId == rhs.instId && req != rhs.req);
80  }
81 
82  quint32 objId;
83  quint32 instId;
84  bool req;
85 };
86 
91 {
92  this->utalk = utalk;
93  this->objMngr = objMngr;
94  // Process all objects in the list
95  QVector<QVector<UAVObject *>> objs = objMngr->getObjectsVector();
96  const int objSize = objs.size();
97  for (int objidx = 0; objidx < objSize; ++objidx) {
98  registerObject(objs[objidx][0]); // we only need to register one instance per object type
99  }
100  // Listen to new object creations
101  connect(objMngr, &UAVObjectManager::newObject, this, &Telemetry::newObject);
102  connect(objMngr, &UAVObjectManager::newInstance, this, &Telemetry::newInstance);
103  // Listen to transaction completions
104  connect(utalk, &UAVTalk::ackReceived, this, &Telemetry::transactionSuccess);
105  connect(utalk, &UAVTalk::nackReceived, this, &Telemetry::transactionFailure);
106  // Get GCS stats object
107  gcsStatsObj = GCSTelemetryStats::GetInstance(objMngr);
108  // Setup and start the periodic timer
109  timeToNextUpdateMs = 0;
110  updateTimer = new QTimer(this);
111  connect(updateTimer, &QTimer::timeout, this, &Telemetry::processPeriodicUpdates);
112  updateTimer->start(1000);
113  // Setup and start the stats timer
114  txErrors = 0;
115  txRetries = 0;
116 }
117 
119 {
120  for (QMap<TransactionKey, ObjectTransactionInfo *>::iterator itr = transMap.begin();
121  itr != transMap.end(); ++itr) {
122  delete itr.value();
123  }
124 }
125 
129 void Telemetry::registerObject(UAVObject *obj)
130 {
131  // Setup object for periodic updates
132  addObject(obj);
133 
134  // Setup object for telemetry updates
135  updateObject(obj, EV_NONE);
136 }
137 
141 void Telemetry::addObject(UAVObject *obj)
142 {
143  // Check if object type is already in the list
144  const QVector<ObjectTimeInfo>::iterator iterEnd = objList.end();
145  for (QVector<ObjectTimeInfo>::const_iterator iter = objList.constBegin(); iter != iterEnd;
146  ++iter) {
147  if (iter->obj->getObjID() == obj->getObjID()) {
148  // Object type (not instance!) is already in the list, do nothing
149  return;
150  }
151  }
152 
153  // If this point is reached, then the object type is new, let's add it
154  ObjectTimeInfo timeInfo;
155  timeInfo.obj = obj;
156  timeInfo.timeToNextUpdateMs = 0;
157  timeInfo.updatePeriodMs = 0;
158  objList.append(timeInfo);
159 }
160 
164 void Telemetry::setUpdatePeriod(UAVObject *obj, qint32 periodMs)
165 {
166  // Find object type (not instance!) and update its period
167  const quint32 objID = obj->getObjID();
168 
169  const QVector<ObjectTimeInfo>::iterator iterEnd = objList.end();
170  for (QVector<ObjectTimeInfo>::iterator iter = objList.begin(); iter != iterEnd; ++iter) {
171  if (iter->obj->getObjID() == objID) {
172  iter->updatePeriodMs = periodMs;
173  iter->timeToNextUpdateMs = quint32((float)periodMs * (float)qrand()
174  / (float)RAND_MAX); // avoid bunching of updates
175  }
176  }
177 }
178 
182 void Telemetry::connectToObjectInstances(UAVObject *obj, quint32 eventMask)
183 {
184  QVector<UAVObject *> objs = objMngr->getObjectInstancesVector(obj->getObjID());
185  int objsSize = objs.size();
186  for (int n = 0; n < objsSize; ++n) {
187  // Disconnect all
188  objs[n]->disconnect(this);
189  // Connect only the selected events
190  if ((eventMask & EV_UNPACKED) != 0) {
191  connect(objs[n], &UAVObject::objectUnpacked, this, &Telemetry::objectUnpacked);
192  }
193  if ((eventMask & EV_UPDATED) != 0) {
194  connect(objs[n], &UAVObject::objectUpdatedAuto, this, &Telemetry::objectUpdatedAuto);
195  }
196  if ((eventMask & EV_UPDATED_MANUAL) != 0) {
197  connect(objs[n], &UAVObject::objectUpdatedManual, this,
198  &Telemetry::objectUpdatedManual);
199  }
200  if ((eventMask & EV_UPDATED_PERIODIC) != 0) {
201  connect(objs[n], &UAVObject::objectUpdatedPeriodic, this,
202  &Telemetry::objectUpdatedPeriodic);
203  }
204  if ((eventMask & EV_UPDATE_REQ) != 0) {
205  connect(objs[n], &UAVObject::updateRequested, this, &Telemetry::updateRequested);
206  connect(objs[n], &UAVObject::updateAllInstancesRequested, this,
207  &Telemetry::updateAllInstancesRequested);
208  }
209  }
210 }
211 
221 void Telemetry::updateObject(UAVObject *obj, quint32 eventType)
222 {
223  // Get metadata
224  UAVObject::Metadata metadata = obj->getMetadata();
226 
227  // Setup object depending on update mode
228  qint32 eventMask;
229  if (updateMode == UAVObject::UPDATEMODE_PERIODIC) {
230  // Set update period
231  setUpdatePeriod(obj, metadata.gcsTelemetryUpdatePeriod);
232  // Connect signals for all instances
233  eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ | EV_UPDATED_PERIODIC;
234  eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
235  connectToObjectInstances(obj, eventMask);
236  } else if (updateMode == UAVObject::UPDATEMODE_ONCHANGE) {
237  // Set update period
238  setUpdatePeriod(obj, 0);
239  // Connect signals for all instances
240  eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
241  eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
242  connectToObjectInstances(obj, eventMask);
243  } else if (updateMode == UAVObject::UPDATEMODE_THROTTLED) {
244  // If we received a periodic update, we can change back to update on change
245  if ((eventType == EV_UPDATED_PERIODIC) || (eventType == EV_NONE)) {
246  // Set update period
247  if (eventType == EV_NONE)
248  setUpdatePeriod(obj, metadata.gcsTelemetryUpdatePeriod);
249  // Connect signals for all instances
250  eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ | EV_UPDATED_PERIODIC;
251  } else {
252  // Otherwise, we just received an object update, so switch to periodic for the timeout
253  // period to prevent more updates
254  // Connect signals for all instances
255  eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ;
256  }
257  eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
258  connectToObjectInstances(obj, eventMask);
259  } else if (updateMode == UAVObject::UPDATEMODE_MANUAL) {
260  // Set update period
261  setUpdatePeriod(obj, 0);
262  // Connect signals for all instances
263  eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ;
264  eventMask |= EV_UNPACKED; // we also need to act on remote updates (unpack events)
265  connectToObjectInstances(obj, eventMask);
266  }
267 }
268 
274 void Telemetry::transactionSuccess(UAVObject *obj)
275 {
276  if (updateTransactionMap(obj, false)) {
277  TELEMETRY_QXTLOG_DEBUG(
278  QString("[telemetry.cpp] Transaction succeeded:%0 Instance:%1")
279  .arg(obj->getName()
280  + QString(QString(" 0x") + QString::number(obj->getObjID(), 16).toUpper()))
281  .arg(obj->getInstID()));
282  obj->emitTransactionCompleted(true);
283  obj->emitTransactionCompleted(true, false);
284  } else {
285  TELEMETRY_QXTLOG_DEBUG(
286  QString("[telemetry.cpp] Received an ACK we were not expecting object:%0")
287  .arg(obj->getName()));
288  }
289  // Process new object updates from queue
290  processObjectQueue();
291 }
292 
300 void Telemetry::transactionFailure(UAVObject *obj)
301 {
302  bool nacked = false;
303  if (sender() == this->utalk)
304  nacked = true;
305  // Here we need to check for true or false as a NAK can occur for OBJ_REQ or an
306  // object set
307  if (updateTransactionMap(obj, true) || updateTransactionMap(obj, false)) {
308  TELEMETRY_QXTLOG_DEBUG(
309  QString("[telemetry.cpp] Transaction failed:%0 Instance:%1")
310  .arg(obj->getName()
311  + QString(QString(" 0x") + QString::number(obj->getObjID(), 16).toUpper()))
312  .arg(obj->getInstID()));
313  obj->emitTransactionCompleted(false);
314  obj->emitTransactionCompleted(false, nacked);
315  } else {
316  TELEMETRY_QXTLOG_DEBUG(
317  QString("[telemetry.cpp] Received a NACK we were not expecting for object %0")
318  .arg(obj->getName()));
319  }
320  // Process new object updates from queue
321  processObjectQueue();
322 }
323 
329 void Telemetry::transactionRequestCompleted(UAVObject *obj)
330 {
331  if (updateTransactionMap(obj, true)) {
332  TELEMETRY_QXTLOG_DEBUG(
333  QString("[telemetry.cpp] Transaction succeeded:%0 Instance:%1")
334  .arg(obj->getName()
335  + QString(QString(" 0x") + QString::number(obj->getObjID(), 16).toUpper()))
336  .arg(obj->getInstID()));
337  obj->emitTransactionCompleted(true);
338  obj->emitTransactionCompleted(true, false);
339  } else {
340  TELEMETRY_QXTLOG_DEBUG(
341  QString("[telemetry.cpp] Received a ACK we were not expecting for object %0")
342  .arg(obj->getName()));
343  }
344  // Process new object updates from queue
345  processObjectQueue();
346 }
347 
357 bool Telemetry::updateTransactionMap(UAVObject *obj, bool request)
358 {
359  TransactionKey key(obj, request);
360  QMap<TransactionKey, ObjectTransactionInfo *>::iterator itr = transMap.find(key);
361  if (itr != transMap.end()) {
362  ObjectTransactionInfo *transInfo = itr.value();
363  // Remove this transaction as it is complete.
364  transInfo->timer->stop();
365  transMap.remove(key);
366  delete transInfo;
367  return true;
368  }
369  return false;
370 }
371 
376 {
377  transInfo->timer->stop();
378  // Check if more retries are pending
379  if (transInfo->retriesRemaining > 0) {
380  --transInfo->retriesRemaining;
381  qInfo() << QString("[telemetry.cpp] Transaction timeout:%0 Instance:%1 Retrying remaining=%3")
382  .arg(transInfo->obj->getName()
383  + QString(QString(" 0x")
384  + QString::number(transInfo->obj->getObjID(), 16).toUpper()))
385  .arg(transInfo->obj->getInstID())
386  .arg(transInfo->retriesRemaining);
387  processObjectTransaction(transInfo);
388  ++txRetries;
389  } else {
390  qInfo() << QString("[telemetry.cpp] Transaction timeout:%0 Instance:%1 no more retries. FAILED "
391  "TRANSACT")
392  .arg(transInfo->obj->getName()
393  + QString(QString(" 0x")
394  + QString::number(transInfo->obj->getObjID(), 16).toUpper()))
395  .arg(transInfo->obj->getInstID());
396  transInfo->timer->stop();
397  transactionFailure(transInfo->obj);
398  ++txErrors;
399  }
400 }
401 
402 /* This is synchronous, so we use a primitive callback mechanism
403  * instead of signal/slot. Can have a future async variant if
404  * necessary
405  */
406 QByteArray *Telemetry::downloadFile(quint32 fileId, quint32 maxSize,
407  std::function<void(quint32)>progressCb)
408 {
409  quint32 curOffset = 0;
410 
411  QByteArray *result = new QByteArray();
412 
413  quint32 sizeGuess = 32 * 1024;
414 
415  if (maxSize < sizeGuess) {
416  sizeGuess = maxSize;
417  }
418 
419  result->reserve(maxSize);
420 
421  bool newReqNeeded = false;
422  bool completed = false;
423  int inactivityCount = 0;
424  int failCount = 0;
425 
426  QEventLoop loop;
427  QTimer timeStep;
428 
429  timeStep.setSingleShot(false);
430  timeStep.start(150);
431 
432  connect(&timeStep, &QTimer::timeout, &loop, &QEventLoop::quit);
433 
434  connect(utalk, &UAVTalk::fileDataReceived, &loop,
435  [&](quint32 recvFileId, quint32 offset, quint8 *data, quint32 dataLen,
436  bool eof, bool lastInSeq) {
437  if (recvFileId != fileId) {
438  return;
439  }
440 
441  if (offset != curOffset) {
442  if (lastInSeq) {
443  newReqNeeded = true;
444  loop.exit();
445  }
446 
447  return;
448  }
449 
450  result->append((const char *) data, dataLen);
451 
452  curOffset += dataLen;
453 
454  if (eof) {
455  completed = true;
456  loop.exit();
457  } else if (lastInSeq) {
458  newReqNeeded = true;
459  loop.exit();
460  }
461 
462  inactivityCount = 0;
463  failCount = 0;
464 
465  if (progressCb) {
466  progressCb(curOffset);
467  }
468  }
469  );
470 
471  while (curOffset < maxSize && (!completed)) {
472  utalk->requestFile(fileId, curOffset);
473 
474  newReqNeeded = false;
475  inactivityCount = 0;
476 
477  do {
478  if ((inactivityCount++) > 10) {
479  qDebug() << "Retrying file transfer because of inactivity";
480  failCount++;
481  break;
482  }
483 
484  loop.exec();
485 
486  } while (curOffset < maxSize && (!completed) && (!newReqNeeded));
487 
488  if (failCount > 5) {
489  qDebug() << "Aborting file transfer";
490  delete result;
491  return NULL;
492  }
493  }
494 
495  return result;
496 }
497 
501 void Telemetry::processObjectTransaction(ObjectTransactionInfo *transInfo)
502 {
503 
504  // Initiate transaction
505  if (transInfo->objRequest) { // We are requesting an object from the remote end
506  utalk->sendObjectRequest(transInfo->obj, transInfo->allInstances);
507  } else { // We are sending an object to the remote end
508  utalk->sendObject(transInfo->obj, transInfo->acked, transInfo->allInstances);
509  }
510  // Start timer if a response is expected
511  if (transInfo->objRequest || transInfo->acked) {
512  transInfo->timer->start(REQ_TIMEOUT_MS);
513  } else {
514  // Stop tracking this transaction, since we're not expecting a response:
515  transMap.remove(TransactionKey(transInfo->obj, transInfo->objRequest));
516  delete transInfo;
517  }
518 }
519 
524 void Telemetry::processObjectUpdates(UAVObject *obj, EventMask event, bool allInstances,
525  bool priority)
526 {
527  // Push event into queue
528  ObjectQueueInfo objInfo;
529  objInfo.obj = obj;
530  objInfo.event = event;
531  objInfo.allInstances = allInstances;
532  if (priority) {
533  if (objPriorityQueue.length() < MAX_QUEUE_SIZE) {
534  objPriorityQueue.enqueue(objInfo);
535  } else {
536  ++txErrors;
537  obj->emitTransactionCompleted(false);
538  obj->emitTransactionCompleted(false, false);
539  qWarning() << QString(tr("Telemetry: priority event queue is full, event lost (%1)")
540  .arg(obj->getName()));
541  }
542  } else {
543  if (objQueue.length() < MAX_QUEUE_SIZE) {
544  objQueue.enqueue(objInfo);
545  } else {
546  ++txErrors;
547  obj->emitTransactionCompleted(false, false);
548  obj->emitTransactionCompleted(false);
549  qWarning() << QString(tr("Telemetry: event queue is full, event lost (%1)")
550  .arg(obj->getName()));
551  }
552  }
553  // Process the transaction queue
554  processObjectQueue();
555 }
556 
560 void Telemetry::processObjectQueue()
561 {
562  if (objQueue.length() > 1) {
563  TELEMETRY_QXTLOG_DEBUG(
564  "[telemetry.cpp] **************** Object Queue above 1 in backlog ****************");
565  }
566  // Get object information from queue (first the priority and then the regular queue)
567  ObjectQueueInfo objInfo;
568  if (!objPriorityQueue.isEmpty()) {
569  objInfo = objPriorityQueue.dequeue();
570  } else if (!objQueue.isEmpty()) {
571  objInfo = objQueue.dequeue();
572  } else {
573  return;
574  }
575 
576  // Check if a connection has been established, only process
577  // GCSTelemetryStats updates (used to establish the connection)
578  GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData();
579  if (gcsStats.Status != GCSTelemetryStats::STATUS_CONNECTED) {
580  objQueue.clear();
581  if (objInfo.obj->getObjID() != GCSTelemetryStats::OBJID) {
582  objInfo.obj->emitTransactionCompleted(false);
583  objInfo.obj->emitTransactionCompleted(false, false);
584  return;
585  }
586  }
587 
588  // Setup transaction (skip if unpack event)
589  UAVObject::Metadata metadata = objInfo.obj->getMetadata();
591  if ((objInfo.event != EV_UNPACKED) && ((objInfo.event != EV_UPDATED_PERIODIC)
592  || (updateMode != UAVObject::UPDATEMODE_THROTTLED))) {
593  // We are either going to send an object, or are requesting one:
594  if (transMap.contains(TransactionKey(objInfo.obj, objInfo.event == EV_UPDATE_REQ))) {
595  TELEMETRY_QXTLOG_DEBUG(QString("[telemetry.cpp] Warning: Got request for %0 for which "
596  "a request is already in progress. Not doing it")
597  .arg(objInfo.obj->getName()));
598  // We will not re-request it, then, we should wait for a timeout or success...
599  } else {
600  UAVObject::Metadata metadata = objInfo.obj->getMetadata();
601  ObjectTransactionInfo *transInfo = new ObjectTransactionInfo(this);
602  transInfo->obj = objInfo.obj;
603  transInfo->allInstances = objInfo.allInstances;
604  transInfo->retriesRemaining = MAX_RETRIES;
605  transInfo->acked = UAVObject::GetGcsTelemetryAcked(metadata);
606  if (objInfo.event == EV_UPDATED || objInfo.event == EV_UPDATED_MANUAL
607  || objInfo.event == EV_UPDATED_PERIODIC) {
608  transInfo->objRequest = false;
609  } else if (objInfo.event == EV_UPDATE_REQ) {
610  transInfo->objRequest = true;
611  }
612  transInfo->telem = this;
613  // Insert the transaction into the transaction map.
614  TransactionKey key(objInfo.obj, transInfo->objRequest);
615  transMap.insert(key, transInfo);
616  processObjectTransaction(transInfo);
617  }
618  }
619 
620  // If this is a metaobject then make necessary telemetry updates
621  // to the connections of this object to Telemetry (this) :
622  UAVMetaObject *metaobj = dynamic_cast<UAVMetaObject *>(objInfo.obj);
623  if (metaobj != NULL) {
624  updateObject(metaobj->getParentObject(), EV_NONE);
625  } else if (updateMode != UAVObject::UPDATEMODE_THROTTLED) {
626  updateObject(objInfo.obj, objInfo.event);
627  }
628 
629  // We received an "unpacked" event, check whether
630  // this is for an object we were expecting
631  if (objInfo.event == EV_UNPACKED) {
632  // TODO: Check here this is for a OBJ_REQ
633  if (transMap.contains(TransactionKey(objInfo.obj, true))) {
634  TELEMETRY_QXTLOG_DEBUG(
635  QString("[telemetry.cpp] EV_UNPACKED %0 Instance:%1")
636  .arg(objInfo.obj->getName()
637  + QString(QString("0x")
638  + QString::number(objInfo.obj->getObjID(), 16).toUpper()))
639  .arg(objInfo.obj->getInstID()));
640  transactionRequestCompleted(objInfo.obj);
641  } else {
642  processObjectQueue();
643  }
644  }
645 }
646 
650 void Telemetry::processPeriodicUpdates()
651 {
652  // Stop timer
653  updateTimer->stop();
654 
655  // Iterate through each object and update its timer, if zero then transmit object.
656  // Also calculate smallest delay to next update (will be used for setting timeToNextUpdateMs)
657  qint32 minDelay = MAX_UPDATE_PERIOD_MS;
658  qint32 elapsedMs = 0;
659  QTime time;
660  qint32 offset;
661 
662  const QVector<ObjectTimeInfo>::iterator objInfoEnd = objList.end();
663  for (QVector<ObjectTimeInfo>::iterator objinfo = objList.begin(); objinfo != objInfoEnd;
664  ++objinfo) {
665  // If object is configured for periodic updates
666  // FixMe: This is an inefficient process as it depends on polling. It would be better to
667  // have
668  // this functionality be driven through timers.
669  if (objinfo->updatePeriodMs > 0) {
670  objinfo->timeToNextUpdateMs -= timeToNextUpdateMs;
671  // Check if time for the next update
672  if (objinfo->timeToNextUpdateMs <= 0) {
673  // Reset timer
674  offset = (-objinfo->timeToNextUpdateMs) % objinfo->updatePeriodMs;
675  objinfo->timeToNextUpdateMs = objinfo->updatePeriodMs - offset;
676  // Send object
677  time.start();
678  processObjectUpdates(objinfo->obj, EV_UPDATED_PERIODIC, true, false);
679  elapsedMs = time.elapsed();
680  // Update timeToNextUpdateMs with the elapsed delay of sending the object;
681  timeToNextUpdateMs += elapsedMs;
682  }
683  // Update minimum delay
684  if (objinfo->timeToNextUpdateMs < minDelay) {
685  minDelay = objinfo->timeToNextUpdateMs;
686  }
687  }
688  }
689 
690  // Check if delay for the next update is too short
691  if (minDelay < MIN_UPDATE_PERIOD_MS) {
692  minDelay = MIN_UPDATE_PERIOD_MS;
693  }
694 
695  // Done
696  timeToNextUpdateMs = minDelay;
697 
698  // Restart timer
699  updateTimer->start(timeToNextUpdateMs);
700 }
701 
703 {
704  // Get UAVTalk stats
705  UAVTalk::ComStats utalkStats = utalk->getStats();
706 
707  // Update stats
708  TelemetryStats stats;
709  stats.txBytes = utalkStats.txBytes;
710  stats.rxBytes = utalkStats.rxBytes;
711  stats.txObjectBytes = utalkStats.txObjectBytes;
712  stats.rxObjectBytes = utalkStats.rxObjectBytes;
713  stats.rxObjects = utalkStats.rxObjects;
714  stats.txObjects = utalkStats.txObjects;
715  stats.txErrors = utalkStats.txErrors + txErrors;
716  stats.rxErrors = utalkStats.rxErrors;
717  stats.txRetries = txRetries;
718 
719  txErrors = 0;
720  txRetries = 0;
721 
722  // Done
723  return stats;
724 }
725 
726 void Telemetry::objectUpdatedAuto(UAVObject *obj)
727 {
728  processObjectUpdates(obj, EV_UPDATED, false, true);
729 }
730 
731 void Telemetry::objectUpdatedManual(UAVObject *obj)
732 {
733  processObjectUpdates(obj, EV_UPDATED_MANUAL, false, true);
734 }
735 
736 void Telemetry::objectUpdatedPeriodic(UAVObject *obj)
737 {
738  processObjectUpdates(obj, EV_UPDATED_PERIODIC, false, true);
739 }
740 
741 void Telemetry::objectUnpacked(UAVObject *obj)
742 {
743  processObjectUpdates(obj, EV_UNPACKED, false, true);
744 }
745 
746 void Telemetry::updateRequested(UAVObject *obj)
747 {
748  processObjectUpdates(obj, EV_UPDATE_REQ, false, true);
749 }
750 
751 void Telemetry::updateAllInstancesRequested(UAVObject *obj)
752 {
753  processObjectUpdates(obj, EV_UPDATE_REQ, true, true);
754 }
755 
756 void Telemetry::newObject(UAVObject *obj)
757 {
758  registerObject(obj);
759 }
760 
761 void Telemetry::newInstance(UAVObject *obj)
762 {
763  registerObject(obj);
764 }
765 
767  : QObject(parent)
768 {
769  obj = nullptr;
770  allInstances = false;
771  objRequest = false;
772  retriesRemaining = 0;
773  acked = false;
774  telem = nullptr;
775  // Setup transaction timer
776  timer = new QTimer(this);
777  timer->stop();
778  connect(timer, &QTimer::timeout, this, &ObjectTransactionInfo::timeout);
779 }
780 
782 {
783  telem = nullptr;
784  timer->stop();
785  timer->deleteLater();
786 }
787 
788 void ObjectTransactionInfo::timeout()
789 {
790  if (!telem.isNull())
791  telem->transactionTimeout(this);
792 }
QVector< UAVObject * > getObjectInstancesVector(const QString &name)
iter
Definition: OPPlots.m:115
void emitTransactionCompleted(bool success)
Definition: uavobject.cpp:327
QPointer< class Telemetry > telem
Definition: telemetry.h:60
function[]
void objectUpdatedPeriodic(UAVObject *obj)
objectUpdatedPeriodic: not used anywhere ?
quint32 objId
Definition: telemetry.cpp:82
void objectUpdatedAuto(UAVObject *obj)
objectUpdatedAuto: triggered on "setData" only (Object data updated by changing the data structure) ...
QVector< QVector< UAVObject * > > getObjectsVector()
UAVObject * getParentObject()
void newInstance(UAVObject *obj)
quint32 txObjectBytes
Definition: uavtalk.h:55
void objectUnpacked(UAVObject *obj)
objectUnpacked: triggered whenever an object is unpacked (i.e. arrives from the telemetry link) ...
static UpdateMode GetGcsTelemetryUpdateMode(const Metadata &meta)
Definition: uavobject.cpp:479
quint32 txBytes
Definition: uavtalk.h:53
bool operator<(const TransactionKey &rhs) const
Definition: telemetry.cpp:76
quint32 rxErrors
Definition: uavtalk.h:60
bool sendObject(UAVObject *obj, bool acked, bool allInstances)
Definition: uavtalk.cpp:155
bool operator==(const TransactionKey &rhs) const
Definition: telemetry.cpp:71
ComStats getStats()
Definition: uavtalk.cpp:97
quint32 getInstID()
Definition: uavobject.cpp:115
DataFields data
QByteArray * downloadFile(quint32 fileId, quint32 maxSize, std::function< void(quint32)>progressCb=nullptr)
Definition: telemetry.cpp:406
virtual Metadata getMetadata()=0
quint32 txObjects
Definition: uavtalk.h:58
quint32 rxBytes
Definition: uavtalk.h:54
void fileDataReceived(quint32 fileId, quint32 offset, quint8 *data, quint32 dataLen, bool eof, bool lastInSeq)
Eccentricity n
Definition: OPPlots.m:137
quint32 rxObjectBytes
Definition: uavtalk.h:56
ObjectTransactionInfo(QObject *parent)
Definition: telemetry.cpp:766
UAVObject * obj
Definition: telemetry.h:55
quint32 getObjID()
Definition: uavobject.cpp:107
void updateRequested(UAVObject *obj)
updateRequested
TransactionKey(UAVObject *obj, bool req)
Definition: telemetry.cpp:63
void ackReceived(UAVObject *obj)
void updateAllInstancesRequested(UAVObject *obj)
updateAllInstancesRequested
quint32 instId
Definition: telemetry.cpp:83
quint32 rxObjects
Definition: uavtalk.h:57
QString getName()
Definition: uavobject.cpp:131
void transactionTimeout(ObjectTransactionInfo *info)
Definition: telemetry.cpp:375
TransactionKey(quint32 objId, quint32 instId, bool req)
Definition: telemetry.cpp:56
bool requestFile(quint32 fileId, quint32 offset)
Definition: uavtalk.cpp:610
TelemetryStats getStats()
Definition: telemetry.cpp:702
The TransactionKey class A key for the QMap to track transactions.
Definition: telemetry.cpp:53
void objectUpdatedManual(UAVObject *obj)
objectUpdatedManual: triggered only from the "updated" slot in uavobject The telemetry manager listen...
quint32 txErrors
Definition: uavtalk.h:59
Telemetry(UAVTalk *utalk, UAVObjectManager *objMngr)
Definition: telemetry.cpp:90
static quint8 GetGcsTelemetryAcked(const Metadata &meta)
Definition: uavobject.cpp:437
bool sendObjectRequest(UAVObject *obj, bool allInstances)
Definition: uavtalk.cpp:143
void nackReceived(UAVObject *obj)
void newObject(UAVObject *obj)