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 : }