Line data Source code
1 : // SPDX-FileCopyrightText: 2022-2025 Paul Colby <git@colby.id.au>
2 : // SPDX-License-Identifier: LGPL-3.0-or-later
3 :
4 : #include "statuscommand.h"
5 : #include "../stringliterals_p.h"
6 :
7 : #include <qtpokit/pokitdevice.h>
8 :
9 : #include <QJsonDocument>
10 : #include <QJsonObject>
11 :
12 : #include <iostream>
13 :
14 : DOKIT_USE_STRINGLITERALS
15 :
16 : /*!
17 : * \class StatusCommand
18 : *
19 : * The StatusCommand class implements the `status` CLI command.
20 : */
21 :
22 : /*!
23 : * Construct a new StatusCommand object with \a parent.
24 : */
25 1520 : StatusCommand::StatusCommand(QObject * const parent) : DeviceCommand(parent)
26 464 : {
27 :
28 1584 : }
29 :
30 400 : QStringList StatusCommand::requiredOptions(const QCommandLineParser &parser) const
31 280 : {
32 980 : return DeviceCommand::requiredOptions(parser) + QStringList{
33 935 : };
34 280 : }
35 :
36 160 : QStringList StatusCommand::supportedOptions(const QCommandLineParser &parser) const
37 112 : {
38 272 : return DeviceCommand::supportedOptions(parser);
39 112 : }
40 :
41 : /*!
42 : * \copybrief DeviceCommand::processOptions
43 : *
44 : * This implementation extends DeviceCommand::processOptions to process additional CLI options
45 : * supported (or required) by this command.
46 : */
47 80 : QStringList StatusCommand::processOptions(const QCommandLineParser &parser)
48 56 : {
49 136 : QStringList errors = DeviceCommand::processOptions(parser);
50 56 : if (!errors.isEmpty()) {
51 0 : return errors;
52 0 : }
53 :
54 56 : return errors;
55 56 : }
56 :
57 : /*!
58 : * \copybrief DeviceCommand::getService
59 : *
60 : * This override returns a pointer to a StatusService object.
61 : */
62 0 : AbstractPokitService * StatusCommand::getService()
63 0 : {
64 0 : Q_ASSERT(device);
65 0 : if (!service) {
66 0 : service = device->status();
67 0 : Q_ASSERT(service);
68 0 : }
69 0 : return service;
70 0 : }
71 :
72 : /*!
73 : * \copybrief DeviceCommand::serviceDetailsDiscovered
74 : *
75 : * This override fetches the current device's status, and outputs it in the selected format.
76 : */
77 80 : void StatusCommand::serviceDetailsDiscovered()
78 24 : {
79 104 : DeviceCommand::serviceDetailsDiscovered(); // Just logs consistently.
80 104 : const StatusService::DeviceCharacteristics chrs = service->deviceCharacteristics();
81 104 : if (chrs.firmwareVersion.isNull()) {
82 256 : qCWarning(lc).noquote() << tr("Failed to parse device information");
83 104 : QCoreApplication::exit(EXIT_FAILURE);
84 24 : return;
85 24 : }
86 0 : outputDeviceStatus(chrs);
87 0 : }
88 :
89 : /*!
90 : * Outputs the Pokit device's details, including \a chrs, in the selected format.
91 : */
92 720 : void StatusCommand::outputDeviceStatus(const StatusService::DeviceCharacteristics &chrs)
93 216 : {
94 936 : const QString deviceName = service->deviceName();
95 936 : const StatusService::Status status = service->status();
96 936 : const std::optional<StatusService::TorchStatus> torchStatus = service->torchStatus();
97 936 : const std::optional<StatusService::ButtonStatus> buttonStatus = service->buttonPress();
98 936 : const QString statusLabel = StatusService::toString(status.deviceStatus);
99 936 : const QString batteryLabel = StatusService::toString(status.batteryStatus);
100 936 : const QString switchLabel = status.switchPosition ? StatusService::toString(*status.switchPosition) : QString();
101 936 : const QString chargingLabel = status.chargingStatus ? StatusService::toString(*status.chargingStatus) : QString();
102 936 : const QString torchLabel = (torchStatus) ? StatusService::toString(*torchStatus) : QString();
103 936 : const QString buttonLabel = (buttonStatus) ? StatusService::toString(*buttonStatus) : QString();
104 :
105 936 : switch (format) {
106 312 : case OutputFormat::Csv:
107 441 : std::cout << qUtf8Printable(tr("device_name,device_status,firmware_version,maximum_voltage,"
108 72 : "maximum_current,maximum_resistance,maximum_sampling_rate,"
109 72 : "sampling_buffer_size,capability_mask,mac_address,battery_voltage,"
110 72 : "battery_status,torch_status,button_status,switch_position,charging_status\n"));
111 1368 : std::cout << qUtf8Printable(QString::fromLatin1("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16\n")
112 72 : .arg(escapeCsvField(deviceName),statusLabel.toLower(),chrs.firmwareVersion.toString())
113 72 : .arg(chrs.maximumVoltage).arg(chrs.maximumCurrent).arg(chrs.maximumResistance)
114 72 : .arg(chrs.maximumSamplingRate).arg(chrs.samplingBufferSize).arg(chrs.capabilityMask)
115 72 : .arg(chrs.macAddress.toString()).arg(status.batteryVoltage)
116 72 : .arg(batteryLabel.toLower(), torchLabel.toLower(), buttonLabel.toLower(), switchLabel.toLower(),
117 72 : chargingLabel.toLower()));
118 312 : break;
119 312 : case OutputFormat::Json: {
120 72 : QJsonObject battery{
121 480 : { u"level"_s, status.batteryVoltage },
122 969 : };
123 312 : if (!batteryLabel.isNull()) {
124 633 : battery.insert(u"status"_s, batteryLabel);
125 72 : }
126 72 : QJsonObject object{
127 396 : { u"deviceName"_s, deviceName },
128 1089 : { u"firmwareVersion"_s, QJsonObject{
129 432 : { u"major"_s, chrs.firmwareVersion.majorVersion() },
130 432 : { u"minor"_s, chrs.firmwareVersion.minorVersion() },
131 624 : }},
132 480 : { u"maximumVoltage"_s, chrs.maximumVoltage },
133 480 : { u"maximumCurrent"_s, chrs.maximumCurrent },
134 480 : { u"maximumResistance"_s, chrs.maximumResistance },
135 480 : { u"maximumSamplingRate"_s, chrs.maximumSamplingRate },
136 480 : { u"samplingBufferSize"_s, chrs.samplingBufferSize },
137 480 : { u"capabilityMask"_s, chrs.capabilityMask },
138 552 : { u"macAddress"_s, chrs.macAddress.toString() },
139 1125 : { u"deviceStatus"_s, QJsonObject{
140 543 : { u"code"_s, (quint8)status.deviceStatus },
141 396 : { u"label"_s, statusLabel },
142 624 : }},
143 396 : { u"battery"_s, battery },
144 4449 : };
145 312 : if (torchStatus) {
146 0 : object.insert(u"torchStatus"_s, QJsonObject{
147 0 : { u"code"_s, (quint8)*torchStatus },
148 0 : { u"label"_s, torchLabel },
149 0 : });
150 0 : }
151 312 : if (buttonStatus) {
152 0 : object.insert(u"buttonStatus"_s, QJsonObject{
153 0 : { u"code"_s, (quint8)*buttonStatus },
154 0 : { u"label"_s, buttonLabel },
155 0 : });
156 0 : }
157 312 : if (status.switchPosition) {
158 0 : object.insert(u"switchStatus"_s, QJsonObject{
159 0 : { u"code"_s, (quint8)*status.switchPosition },
160 0 : { u"label"_s, switchLabel },
161 0 : });
162 0 : }
163 312 : if (status.chargingStatus) {
164 0 : object.insert(u"chargingStatus"_s, QJsonObject{
165 0 : { u"code"_s, (quint8)*status.chargingStatus },
166 0 : { u"label"_s, chargingLabel },
167 0 : });
168 0 : }
169 552 : std::cout << QJsonDocument(object).toJson().toStdString();
170 312 : } break;
171 312 : case OutputFormat::Text:
172 681 : std::cout << qUtf8Printable(tr("Device name: %1\n").arg(deviceName));
173 711 : std::cout << qUtf8Printable(tr("Firmware version: %1\n").arg(chrs.firmwareVersion.toString()));
174 570 : std::cout << qUtf8Printable(tr("Maximum voltage: %1\n").arg(chrs.maximumVoltage));
175 570 : std::cout << qUtf8Printable(tr("Maximum current: %1\n").arg(chrs.maximumCurrent));
176 570 : std::cout << qUtf8Printable(tr("Maximum resistance: %1\n").arg(chrs.maximumResistance));
177 570 : std::cout << qUtf8Printable(tr("Maximum sampling rate: %1\n").arg(chrs.maximumSamplingRate));
178 570 : std::cout << qUtf8Printable(tr("Sampling buffer size: %1\n").arg(chrs.samplingBufferSize));
179 570 : std::cout << qUtf8Printable(tr("Capability mask: %1\n").arg(chrs.capabilityMask));
180 711 : std::cout << qUtf8Printable(tr("MAC address: %1\n").arg(chrs.macAddress.toString()));
181 570 : std::cout << qUtf8Printable(tr("Device status: %1 (%2)\n").arg(statusLabel)
182 72 : .arg((quint8)status.deviceStatus));
183 681 : std::cout << qUtf8Printable(tr("Battery voltage: %1\n").arg(status.batteryVoltage));
184 810 : std::cout << qUtf8Printable(tr("Battery status: %1 (%2)\n")
185 72 : .arg(batteryLabel.isNull() ? QString::fromLatin1("N/A") : batteryLabel)
186 72 : .arg((quint8)status.batteryStatus));
187 312 : if (status.switchPosition) {
188 0 : std::cout << qUtf8Printable(tr("Switch position: %1 (%2)\n")
189 0 : .arg(switchLabel).arg((quint8)*status.switchPosition));
190 0 : }
191 312 : if (status.chargingStatus) {
192 0 : std::cout << qUtf8Printable(tr("Charging status: %1 (%2)\n")
193 0 : .arg(chargingLabel).arg((quint8)*status.chargingStatus));
194 0 : }
195 72 : break;
196 216 : }
197 936 : if (device) disconnect(); // Will exit the application once disconnected.
198 3924 : }
|