Dokit
Internal development documentation
Loading...
Searching...
No Matches
loggerstartcommand.cpp
1// SPDX-FileCopyrightText: 2022-2024 Paul Colby <git@colby.id.au>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#include "loggerstartcommand.h"
5
7
8#include <QDateTime>
9#include <QJsonDocument>
10#include <QJsonObject>
11
12#include <iostream>
13
14/*!
15 * \class LoggerStartCommand
16 *
17 * The LoggerStartCommand class implements the `logger` CLI command.
18 */
19
20/*!
21 * Construct a new LoggerStartCommand object with \a parent.
22 */
27
34
36{
38 QLatin1String("interval"),
39 QLatin1String("range"), // May still be required by processOptions(), depending on the --mode option's value.
40 QLatin1String("timestamp"),
41 };
42}
43
44/*!
45 * \copybrief DeviceCommand::processOptions
46 *
47 * This implementation extends DeviceCommand::processOptions to process additional CLI options
48 * supported (or required) by this command.
49 */
51{
53 if (!errors.isEmpty()) {
54 return errors;
55 }
56
57 // Parse the (required) mode option.
58 const QString mode = parser.value(QLatin1String("mode")).trimmed().toLower();
59 if (mode.startsWith(QLatin1String("ac v")) || mode.startsWith(QLatin1String("vac"))) {
62 } else if (mode.startsWith(QLatin1String("dc v")) || mode.startsWith(QLatin1String("vdc"))) {
65 } else if (mode.startsWith(QLatin1String("ac c")) || mode.startsWith(QLatin1String("aac"))) {
68 } else if (mode.startsWith(QLatin1String("dc c")) || mode.startsWith(QLatin1String("adc"))) {
71 } else if (mode.startsWith(QLatin1String("temp"))) {
73 minRangeFunc = nullptr;
74 } else {
75 minRangeFunc = nullptr;
76 errors.append(tr("Unknown logger mode: %1").arg(parser.value(QLatin1String("mode"))));
77 return errors;
78 }
79
80 // Parse the range option.
82 if (parser.isSet(QLatin1String("range"))) {
83 const QString value = parser.value(QLatin1String("range"));
84 switch (settings.mode) {
87 rangeOptionValue = parseNumber<std::milli>(value, QLatin1String("V"), 50); // mV.
88 break;
91 rangeOptionValue = parseNumber<std::milli>(value, QLatin1String("A"), 5); // mA.
92 break;
93 default:
94 qCInfo(lc).noquote() << tr("Ignoring range value: %1").arg(value);
95 }
96 if ((minRangeFunc != nullptr) && (rangeOptionValue == 0)) {
97 errors.append(tr("Invalid range value: %1").arg(value));
98 }
100 errors.append(tr("Missing required option for logger mode '%1': range")
101 .arg(parser.value(QLatin1String("mode"))));
102 }
103
104 // Parse the interval option.
105 if (parser.isSet(QLatin1String("interval"))) {
106 const QString value = parser.value(QLatin1String("interval"));
107 const quint32 interval = parseNumber<std::milli>(value, QLatin1String("s"), 500);
108 if (interval == 0) {
109 errors.append(tr("Invalid interval value: %1").arg(value));
110 } else {
111 settings.updateInterval = interval;
112 }
113 }
114
115 // Parse the timestamp option.
116 settings.timestamp = (quint32)QDateTime::currentSecsSinceEpoch(); // Note, subject to Y2038 epochalypse.
117 if (parser.isSet(QLatin1String("timestamp"))) {
118 const QString value = parser.value(QLatin1String("timestamp"));
119 QLocale locale; bool ok;
120 static_assert(sizeof(uint) == sizeof(settings.timestamp), "QLocale has no toUint32().");
121 const int timestamp = locale.toUInt(value, &ok);
122 if (!ok) {
123 errors.append(tr("Invalid timestamp value: %1").arg(value));
124 } else {
125 settings.timestamp = timestamp;
126 }
127 }
128 return errors;
129}
130
131/*!
132 * \copybrief DeviceCommand::getService
133 *
134 * This override returns a pointer to a DataLoggerService object.
135 */
147
148/*!
149 * \copybrief DeviceCommand::serviceDetailsDiscovered
150 *
151 * This override fetches the current device's status, and outputs it in the selected format.
152 */
154{
155 DeviceCommand::serviceDetailsDiscovered(); // Just logs consistently.
158 qCInfo(lc).noquote() << tr("Logging %1, with range %2, every %L3ms.").arg(
160 (range.isNull()) ? QString::fromLatin1("N/A") : range).arg(settings.updateInterval);
162}
163
164/*!
165 * \var LoggerStartCommand::minRangeFunc
166 *
167 * Pointer to function for converting #rangeOptionValue to a Pokit device's range enumerator. This function pointer
168 * is assigned during the command line parsing, but is not invoked until after the device's services are discovere,
169 * because prior to that discovery, we don't know which product (Meter vs Pro vs Clamp, etc) we're talking to and thus
170 * which enumerator list to be using.
171 *
172 * If the current mode does not support ranges (eg diode, and continuity modes), then this member will be \c nullptr.
173 *
174 * \see processOptions
175 * \see serviceDetailsDiscovered
176 */
177
178/*!
179 * Invoked when the data logger settings have been written.
180 */
182{
183 qCDebug(lc).noquote() << tr("Settings written; data logger has started.");
184 switch (format) {
186 std::cout << qUtf8Printable(tr("logger_start_result\nsuccess\n"));
187 break;
189 std::cout << qUtf8Printable(QLatin1String("true\n"));
190 break;
192 std::cout << qUtf8Printable(tr("Done.\n"));
193 break;
194 }
195 if (device) disconnect(); // Will exit the application once disconnected.
196}
virtual QStringList supportedOptions(const QCommandLineParser &parser) const
Returns a list of CLI option names supported by this command.
OutputFormat format
Selected output format.
@ Text
Plain unstructured text.
@ Csv
RFC 4180 compliant CSV text.
@ Json
RFC 8259 compliant JSON text.
virtual QStringList processOptions(const QCommandLineParser &parser)
Processes the relevant options from the command line parser.
virtual QStringList requiredOptions(const QCommandLineParser &parser) const
Returns a list of CLI option names required by this command.
The AbstractPokitService class provides a common base for Pokit services classes.
std::optional< PokitProduct > pokitProduct() const
Returns the Pokit product this service is attached to.
bool setSettings(const Settings &settings)
Configures the Pokit device's data logger mode.
static QString toString(const Mode &mode)
Returns mode as a user-friendly string.
@ DcVoltage
Measure DC voltage.
@ AcCurrent
Measure AC current.
@ AcVoltage
Measure AC voltage.
@ Temperature
Measure temperature.
@ DcCurrent
Measure DC current.
void settingsWritten()
This signal is emitted when the Settings characteristic has been written successfully.
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.
static quint8 minVoltageRange(const PokitProduct product, const quint32 maxValue)
t Returns the product's lowest voltage range that can measure at least up to maxValue (mV),...
static quint8 minCurrentRange(const PokitProduct product, const quint32 maxValue)
Returns the product's lowest current range that can measure at least up to maxValue (µA),...
void disconnect(int exitCode=EXIT_SUCCESS)
Disconnects the underlying Pokit device, and sets exitCode to be return to the OS once the disconnect...
QStringList requiredOptions(const QCommandLineParser &parser) const override
Returns a list of CLI option names required by this command.
quint8(* minRangeFunc)(const PokitProduct product, const quint32 maxValue)
Pointer to function for converting rangeOptionValue to a Pokit device's range enumerator.
AbstractPokitService * getService() override
Returns a Pokit service object for the derived command class.
QStringList processOptions(const QCommandLineParser &parser) override
Processes the relevant options from the command line parser.
DataLoggerService::Settings settings
Settings for the Pokit device's data logger mode.
quint32 rangeOptionValue
The parsed value of range option.
void settingsWritten()
Invoked when the data logger settings have been written.
void serviceDetailsDiscovered() override
Handles service detail discovery events.
QStringList supportedOptions(const QCommandLineParser &parser) const override
Returns a list of CLI option names supported by this command.
LoggerStartCommand(QObject *const parent=nullptr)
Construct a new LoggerStartCommand object with parent.
DataLoggerService * service
Bluetooth service this command interracts with.
DataLoggerService * dataLogger()
Returns a pointer to a DataLoggerService instance that uses this device's controller for access.
Declares the PokitDevice class.
bool isSet(const QString &name) const const
QString value(const QString &optionName) const const
qint64 currentSecsSinceEpoch()
void append(const T &value)
bool isEmpty() const const
uint toUInt(const QString &s, bool *ok) 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)
bool isNull() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString toLower() const const
QString trimmed() const const
quint32 timestamp
Custom timestamp for start time in retrieved metadata.
Mode mode
Desired operation mode.
quint32 updateInterval
Desired update interval in milliseconds.