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 4032 : #define DOKIT_QT_UTC Qt::UTC
18 : #else
19 : #include <QTimeZone>
20 1344 : #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 4158 : LoggerFetchCommand::LoggerFetchCommand(QObject * const parent) : DeviceCommand(parent)
33 1288 : {
34 :
35 4214 : }
36 :
37 : /*!
38 : * \copybrief DeviceCommand::getService
39 : *
40 : * This override returns a pointer to a DataLoggerService object.
41 : */
42 0 : AbstractPokitService * LoggerFetchCommand::getService()
43 0 : {
44 0 : Q_ASSERT(device);
45 0 : if (!service) {
46 0 : service = device->dataLogger();
47 0 : Q_ASSERT(service);
48 0 : connect(service, &DataLoggerService::metadataRead, this, &LoggerFetchCommand::metadataRead);
49 0 : connect(service, &DataLoggerService::samplesRead, this, &LoggerFetchCommand::outputSamples);
50 0 : }
51 0 : return service;
52 0 : }
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 0 : {
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 2888 : void LoggerFetchCommand::metadataRead(const DataLoggerService::Metadata &data)
72 1244 : {
73 4740 : qCDebug(lc) << "status:" << (int)(data.status);
74 4740 : qCDebug(lc) << "scale:" << data.scale;
75 4740 : qCDebug(lc) << "mode:" << DataLoggerService::toString(data.mode) << (quint8)data.mode;
76 4740 : qCDebug(lc) << "range:" << service->toString(data.range, data.mode) << data.range;
77 4740 : qCDebug(lc) << "updateInterval:" << (int)data.updateInterval;
78 4740 : qCDebug(lc) << "numberOfSamples:" << data.numberOfSamples;
79 4740 : qCDebug(lc) << "timestamp:" << data.timestamp << QDateTime::fromSecsSinceEpoch(data.timestamp, DOKIT_QT_UTC);
80 4132 : this->metadata = data;
81 4132 : this->samplesToGo = data.numberOfSamples;
82 4132 : this->timestamp = (quint64)data.timestamp * (quint64)1000;
83 7628 : qCInfo(lc).noquote() << tr("Fetching %Ln logger sample/s...", nullptr, data.numberOfSamples);
84 4132 : }
85 :
86 : /*!
87 : * Outputs logger \a samples in the selected ouput format.
88 : */
89 3420 : void LoggerFetchCommand::outputSamples(const DataLoggerService::Samples &samples)
90 1440 : {
91 2790 : QString unit;
92 4860 : switch (metadata.mode) {
93 972 : case DataLoggerService::Mode::DcVoltage: unit = QLatin1String("Vdc"); break;
94 972 : case DataLoggerService::Mode::AcVoltage: unit = QLatin1String("Vac"); break;
95 972 : case DataLoggerService::Mode::DcCurrent: unit = QLatin1String("Adc"); break;
96 972 : case DataLoggerService::Mode::AcCurrent: unit = QLatin1String("Aac"); break;
97 1242 : 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 1440 : }
102 6930 : const QString range = service->toString(metadata.range, metadata.mode);
103 :
104 26100 : for (const qint16 &sample: samples) {
105 22680 : const QString timeString = (metadata.timestamp == 0) ? QString::number(timestamp)
106 22680 : : QDateTime::fromMSecsSinceEpoch(timestamp, DOKIT_QT_UTC).toString(Qt::ISODateWithMs);
107 22680 : const float value = sample * metadata.scale;
108 22680 : switch (format) {
109 2240 : case OutputFormat::Csv:
110 8640 : for (; showCsvHeader; showCsvHeader = false) {
111 1380 : std::cout << qUtf8Printable(tr("timestamp,value,unit,range\n"));
112 320 : }
113 14980 : std::cout << qUtf8Printable(QString::fromLatin1("%1,%2,%3,%4\n")
114 2240 : .arg(timeString).arg(value).arg(unit, range));
115 7560 : break;
116 7560 : case OutputFormat::Json: {
117 2240 : QJsonObject object{
118 4340 : { QLatin1String("timestamp"), timeString },
119 4340 : { QLatin1String("value"), value },
120 4340 : { QLatin1String("unit"), unit },
121 10780 : { QLatin1String("mode"), DataLoggerService::toString(metadata.mode) },
122 37240 : };
123 7560 : if (!range.isEmpty()) {
124 8064 : object.insert(QLatin1String("range"), range);
125 1792 : }
126 12880 : std::cout << QJsonDocument(object).toJson().toStdString();
127 7560 : } break;
128 7560 : case OutputFormat::Text:
129 14980 : std::cout << qUtf8Printable(tr("%1 %2 %3\n").arg(timeString).arg(value).arg(unit));
130 7560 : break;
131 6720 : }
132 22680 : timestamp += metadata.updateInterval;
133 22680 : --samplesToGo;
134 16380 : }
135 4860 : if (samplesToGo <= 0) {
136 11070 : qCInfo(lc).noquote() << tr("Finished fetching %Ln sample/s (with %L1 remaining).",
137 8280 : nullptr, metadata.numberOfSamples).arg(samplesToGo);
138 4860 : if (device) disconnect(); // Will exit the application once disconnected.
139 1440 : }
140 28380 : }
|