Dokit
Internal development documentation
Loading...
Searching...
No Matches
loggerfetchcommand.cpp
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
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 */
36
37/*!
38 * \copybrief DeviceCommand::getService
39 *
40 * This override returns a pointer to a DataLoggerService object.
41 */
53
54/*!
55 * \copybrief DeviceCommand::serviceDetailsDiscovered
56 *
57 * This override fetches the current device's status, and outputs it in the selected format.
58 */
60{
61 DeviceCommand::serviceDetailsDiscovered(); // Just logs consistently.
62 qCInfo(lc).noquote() << tr("Fetching logger samples...");
66}
67
68/*!
69 * Invoked when \a metadata has been received from the data logger.
70 */
72{
73 qCDebug(lc) << "status:" << (int)(data.status);
74 qCDebug(lc) << "scale:" << data.scale;
75 qCDebug(lc) << "mode:" << DataLoggerService::toString(data.mode) << (quint8)data.mode;
76 qCDebug(lc) << "range:" << service->toString(data.range, data.mode) << data.range;
77 qCDebug(lc) << "updateInterval:" << (int)data.updateInterval;
78 qCDebug(lc) << "numberOfSamples:" << data.numberOfSamples;
79 qCDebug(lc) << "timestamp:" << data.timestamp << QDateTime::fromSecsSinceEpoch(data.timestamp, DOKIT_QT_UTC);
80 this->metadata = data;
81 this->samplesToGo = data.numberOfSamples;
82 this->timestamp = (quint64)data.timestamp * (quint64)1000;
83 qCInfo(lc).noquote() << tr("Fetching %Ln logger sample/s...", nullptr, data.numberOfSamples);
84}
85
86/*!
87 * Outputs logger \a samples in the selected ouput format.
88 */
90{
91 QString unit;
92 switch (metadata.mode) {
93 case DataLoggerService::Mode::DcVoltage: unit = QLatin1String("Vdc"); break;
94 case DataLoggerService::Mode::AcVoltage: unit = QLatin1String("Vac"); break;
95 case DataLoggerService::Mode::DcCurrent: unit = QLatin1String("Adc"); break;
96 case DataLoggerService::Mode::AcCurrent: unit = QLatin1String("Aac"); break;
98 default:
99 qCDebug(lc).noquote() << tr(R"(No known unit for mode %1 "%2".)").arg((int)metadata.mode)
101 }
103
104 for (const qint16 &sample: samples) {
105 const QString timeString = (metadata.timestamp == 0) ? QString::number(timestamp)
107 const float value = sample * metadata.scale;
108 switch (format) {
110 for (; showCsvHeader; showCsvHeader = false) {
111 std::cout << qUtf8Printable(tr("timestamp,value,unit,range\n"));
112 }
113 std::cout << qUtf8Printable(QString::fromLatin1("%1,%2,%3,%4\n")
114 .arg(timeString).arg(value).arg(unit, range));
115 break;
116 case OutputFormat::Json: {
117 QJsonObject object{
118 { QLatin1String("timestamp"), timeString },
119 { QLatin1String("value"), value },
120 { QLatin1String("unit"), unit },
122 };
123 if (!range.isEmpty()) {
124 object.insert(QLatin1String("range"), range);
125 }
126 std::cout << QJsonDocument(object).toJson().toStdString();
127 } break;
129 std::cout << qUtf8Printable(tr("%1 %2 %3\n").arg(timeString).arg(value).arg(unit));
130 break;
131 }
133 --samplesToGo;
134 }
135 if (samplesToGo <= 0) {
136 qCInfo(lc).noquote() << tr("Finished fetching %Ln sample/s (with %L1 remaining).",
138 if (device) disconnect(); // Will exit the application once disconnected.
139 }
140}
OutputFormat format
Selected output format.
@ Text
Plain unstructured text.
@ Csv
RFC 4180 compliant CSV text.
@ Json
RFC 8259 compliant JSON text.
The AbstractPokitService class provides a common base for Pokit services classes.
bool enableMetadataNotifications()
Enables client-side notifications of Data Logger metadata changes.
bool enableReadingNotifications()
Enables client-side notifications of Data Logger readings.
void metadataRead(const DataLoggerService::Metadata &meta)
This signal is emitted when the Metadata characteristic has been read successfully.
static QString toString(const Mode &mode)
Returns mode as a user-friendly string.
bool fetchSamples()
Start the data logger.
void samplesRead(const DataLoggerService::Samples &samples)
This signal is emitted when the Reading characteristic has been notified.
@ DcVoltage
Measure DC voltage.
@ AcCurrent
Measure AC current.
@ AcVoltage
Measure AC voltage.
@ Temperature
Measure temperature.
@ DcCurrent
Measure DC current.
The AbstractCommand class extends AbstractCommand to add a PokitDevice instance.
PokitDevice * device
Pokit Bluetooth device (if any) this command interracts with.
virtual void serviceDetailsDiscovered()
Handles service detail discovery events.
void disconnect(int exitCode=EXIT_SUCCESS)
Disconnects the underlying Pokit device, and sets exitCode to be return to the OS once the disconnect...
qint32 samplesToGo
Number of samples we're still expecting to receive.
DataLoggerService::Metadata metadata
Most recent data logging metadata.
DataLoggerService * service
Bluetooth service this command interracts with.
bool showCsvHeader
Whether or not to show a header as the first line of CSV output.
void outputSamples(const DataLoggerService::Samples &samples)
Outputs logger samples in the selected ouput format.
AbstractPokitService * getService() override
Returns a Pokit service object for the derived command class.
LoggerFetchCommand(QObject *const parent=nullptr)
Construct a new LoggerFetchCommand object with parent.
void serviceDetailsDiscovered() override
Handles service detail discovery events.
quint64 timestamp
Current sample's epoch milliseconds timestamp.
void metadataRead(const DataLoggerService::Metadata &data)
Invoked when metadata has been received from the data logger.
DataLoggerService * dataLogger()
Returns a pointer to a DataLoggerService instance that uses this device's controller for access.
Declares the PokitDevice class.
std::string toStdString() const const
QDateTime fromMSecsSinceEpoch(qint64 msecs)
QDateTime fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds)
QString toString(Qt::DateFormat format) const const
QByteArray toJson() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString tr(const char *sourceText, const char *disambiguation, int n)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
QString fromUtf8(const char *str, int size)
QString & insert(int position, QChar ch)
bool isEmpty() const const
QString number(int n, int base)
ISODateWithMs
Attributes included in the Metadata characterstic.
quint16 numberOfSamples
Number of samples acquired (1 to 6192).
quint32 timestamp
Timestamp stored at the beginning of the logging session.
float scale
Scale to apply to read samples.
LoggerStatus status
Current data logger status.
quint32 updateInterval
Current logging interval in milliseconds.
Mode mode
Current operation mode.