LCOV - code coverage report
Current view: top level - src/cli - loggerfetchcommand.cpp (source / functions) Coverage Total Hit
Project: Dokit Lines: 69.1 % 97 67
Version: Functions: 66.7 % 6 4

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

Generated by: LCOV version 2.4-0