LCOV - code coverage report
Current view: top level - src/cli - loggerfetchcommand.cpp (source / functions) Hit Total Coverage
Project: Dokit Lines: 54 70 77.1 %
Version: Functions: 5 12 41.7 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2022-2024 Paul Colby <git@colby.id.au>
       2             : // SPDX-License-Identifier: LGPL-3.0-or-later
       3             : 
       4             : #include "loggerfetchcommand.h"
       5             : 
       6             : #include <qtpokit/pokitdevice.h>
       7             : 
       8             : #include <QDateTime>
       9             : #include <QJsonDocument>
      10             : #include <QJsonObject>
      11             : 
      12             : #include <iostream>
      13             : 
      14             : // Qt 6.5.0 added new QDateTime::fromSecsSinceEpoch() and fromMSecsSinceEpoch()
      15             : // overloads, then Qt 6.6.0 deprectated some of of the older ones.
      16             : #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
      17             :     #define DOKIT_QT_UTC Qt::UTC
      18             : #else
      19             :     #include <QTimeZone>
      20             :     #define DOKIT_QT_UTC QTimeZone::UTC
      21             : #endif
      22             : 
      23             : /*!
      24             :  * \class LoggerFetchCommand
      25             :  *
      26             :  * The LoggerFetchCommand class implements the `logger` CLI command.
      27             :  */
      28             : 
      29             : /*!
      30             :  * Construct a new LoggerFetchCommand object with \a parent.
      31             :  */
      32        1540 : LoggerFetchCommand::LoggerFetchCommand(QObject * const parent) : DeviceCommand(parent)
      33             : {
      34             : 
      35        1540 : }
      36             : 
      37             : /*!
      38             :  * \copybrief DeviceCommand::getService
      39             :  *
      40             :  * This override returns a pointer to a DataLoggerService object.
      41             :  */
      42           0 : AbstractPokitService * LoggerFetchCommand::getService()
      43             : {
      44             :     Q_ASSERT(device);
      45           0 :     if (!service) {
      46           0 :         service = device->dataLogger();
      47             :         Q_ASSERT(service);
      48           0 :         connect(service, &DataLoggerService::metadataRead, this, &LoggerFetchCommand::metadataRead);
      49           0 :         connect(service, &DataLoggerService::samplesRead, this, &LoggerFetchCommand::outputSamples);
      50             :     }
      51           0 :     return service;
      52             : }
      53             : 
      54             : /*!
      55             :  * \copybrief DeviceCommand::serviceDetailsDiscovered
      56             :  *
      57             :  * This override fetches the current device's status, and outputs it in the selected format.
      58             :  */
      59           0 : void LoggerFetchCommand::serviceDetailsDiscovered()
      60             : {
      61           0 :     DeviceCommand::serviceDetailsDiscovered(); // Just logs consistently.
      62           0 :     qCInfo(lc).noquote() << tr("Fetching logger samples...");
      63           0 :     service->enableMetadataNotifications();
      64           0 :     service->enableReadingNotifications();
      65           0 :     service->fetchSamples();
      66           0 : }
      67             : 
      68             : /*!
      69             :  * Invoked when \a metadata has been received from the data logger.
      70             :  */
      71        1520 : void LoggerFetchCommand::metadataRead(const DataLoggerService::Metadata &data)
      72             : {
      73        1672 :     qCDebug(lc) << "status:"          << (int)(data.status);
      74        1672 :     qCDebug(lc) << "scale:"           << data.scale;
      75        1672 :     qCDebug(lc) << "mode:"            << DataLoggerService::toString(data.mode) << (quint8)data.mode;
      76        1672 :     qCDebug(lc) << "range:"           << service->toString(data.range, data.mode) << data.range;
      77        1672 :     qCDebug(lc) << "updateInterval:"  << (int)data.updateInterval;
      78        1672 :     qCDebug(lc) << "numberOfSamples:" << data.numberOfSamples;
      79        1672 :     qCDebug(lc) << "timestamp:"       << data.timestamp << QDateTime::fromSecsSinceEpoch(data.timestamp, DOKIT_QT_UTC);
      80        1520 :     this->metadata = data;
      81        1520 :     this->samplesToGo = data.numberOfSamples;
      82        1520 :     this->timestamp = (quint64)data.timestamp * (quint64)1000;
      83        3192 :     qCInfo(lc).noquote() << tr("Fetching %Ln logger sample/s...", nullptr, data.numberOfSamples);
      84        1520 : }
      85             : 
      86             : /*!
      87             :  * Outputs logger \a samples in the selected ouput format.
      88             :  */
      89        1800 : void LoggerFetchCommand::outputSamples(const DataLoggerService::Samples &samples)
      90             : {
      91         540 :     QString unit;
      92        1800 :     switch (metadata.mode) {
      93         360 :     case DataLoggerService::Mode::DcVoltage: unit = QLatin1String("Vdc"); break;
      94         360 :     case DataLoggerService::Mode::AcVoltage: unit = QLatin1String("Vac"); break;
      95         360 :     case DataLoggerService::Mode::DcCurrent: unit = QLatin1String("Adc"); break;
      96         360 :     case DataLoggerService::Mode::AcCurrent: unit = QLatin1String("Aac"); break;
      97         468 :     case DataLoggerService::Mode::Temperature: unit = QString::fromUtf8("°C"); break;
      98           0 :     default:
      99           0 :         qCDebug(lc).noquote() << tr(R"(No known unit for mode %1 "%2".)").arg((int)metadata.mode)
     100           0 :             .arg(DataLoggerService::toString(metadata.mode));
     101             :     }
     102        3060 :     const QString range = service->toString(metadata.range, metadata.mode);
     103             : 
     104       10200 :     for (const qint16 &sample: samples) {
     105        8400 :         const QString timeString = (metadata.timestamp == 0) ? QString::number(timestamp)
     106        9072 :             : QDateTime::fromMSecsSinceEpoch(timestamp, DOKIT_QT_UTC).toString(Qt::ISODateWithMs);
     107        8400 :         const float value = sample * metadata.scale;
     108        8400 :         switch (format) {
     109             :         case OutputFormat::Csv:
     110        3200 :             for (; showCsvHeader; showCsvHeader = false) {
     111         520 :                 std::cout << qUtf8Printable(tr("timestamp,value,unit,range\n"));
     112             :             }
     113        6440 :             std::cout << qUtf8Printable(QString::fromLatin1("%1,%2,%3,%4\n")
     114             :                 .arg(timeString).arg(value).arg(unit, range));
     115        2800 :             break;
     116         840 :         case OutputFormat::Json: {
     117             :             QJsonObject object{
     118         840 :                 { QLatin1String("timestamp"), timeString },
     119         840 :                 { QLatin1String("value"),     value },
     120         840 :                 { QLatin1String("unit"),      unit },
     121        5600 :                 { QLatin1String("mode"),      DataLoggerService::toString(metadata.mode) },
     122       22120 :             };
     123        2800 :             if (!range.isEmpty()) {
     124        3248 :                 object.insert(QLatin1String("range"), range);
     125             :             }
     126        5600 :             std::cout << QJsonDocument(object).toJson().toStdString();
     127        2800 :         }   break;
     128        2800 :         case OutputFormat::Text:
     129        6440 :             std::cout << qUtf8Printable(tr("%1 %2 %3\n").arg(timeString).arg(value).arg(unit));
     130        2800 :             break;
     131             :         }
     132        8400 :         timestamp += metadata.updateInterval;
     133        8400 :         --samplesToGo;
     134        5880 :     }
     135        1800 :     if (samplesToGo <= 0) {
     136        4320 :         qCInfo(lc).noquote() << tr("Finished fetching %Ln sample/s (with %L1 remaining).",
     137        2880 :             nullptr, metadata.numberOfSamples).arg(samplesToGo);
     138        1800 :         if (device) disconnect(); // Will exit the application once disconnected.
     139             :     }
     140        6840 : }

Generated by: LCOV version 1.14