LCOV - code coverage report
Current view: top level - src/cli - loggerstartcommand.cpp (source / functions) Coverage Total Hit
Project: Dokit Lines: 83.3 % 126 105
Version: Functions: 75.0 % 8 6

            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 "loggerstartcommand.h"
       5              : 
       6              : #include <qtpokit/pokitdevice.h>
       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              :  */
      23         1458 : LoggerStartCommand::LoggerStartCommand(QObject * const parent) : DeviceCommand(parent)
      24         1188 : {
      25              : 
      26         2214 : }
      27              : 
      28         1710 : QStringList LoggerStartCommand::requiredOptions(const QCommandLineParser &parser) const
      29         1980 : {
      30         8370 :     return DeviceCommand::requiredOptions(parser) + QStringList{
      31         1980 :         QLatin1String("mode"),
      32         6255 :     };
      33         2970 : }
      34              : 
      35          836 : QStringList LoggerStartCommand::supportedOptions(const QCommandLineParser &parser) const
      36          968 : {
      37         5588 :     return DeviceCommand::supportedOptions(parser) + QStringList{
      38          968 :         QLatin1String("interval"),
      39          968 :         QLatin1String("range"), // May still be required by processOptions(), depending on the --mode option's value.
      40          968 :         QLatin1String("timestamp"),
      41         4730 :     };
      42         1452 : }
      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              :  */
      50          798 : QStringList LoggerStartCommand::processOptions(const QCommandLineParser &parser)
      51          924 : {
      52         1722 :     QStringList errors = DeviceCommand::processOptions(parser);
      53         1722 :     if (!errors.isEmpty()) {
      54           88 :         return errors;
      55           88 :     }
      56              : 
      57              :     // Parse the (required) mode option.
      58         2280 :     if (const QString mode = parser.value(QLatin1String("mode")).trimmed().toLower();
      59         1634 :         mode.startsWith(QLatin1String("ac v")) || mode.startsWith(QLatin1String("vac"))) {
      60           82 :         settings.mode = DataLoggerService::Mode::AcVoltage;
      61           82 :         minRangeFunc = minVoltageRange;
      62         1548 :     } else if (mode.startsWith(QLatin1String("dc v")) || mode.startsWith(QLatin1String("vdc"))) {
      63         1066 :         settings.mode = DataLoggerService::Mode::DcVoltage;
      64         1066 :         minRangeFunc = minVoltageRange;
      65          782 :     } else if (mode.startsWith(QLatin1String("ac c")) || mode.startsWith(QLatin1String("aac"))) {
      66           82 :         settings.mode = DataLoggerService::Mode::AcCurrent;
      67           82 :         minRangeFunc = minCurrentRange;
      68          344 :     } else if (mode.startsWith(QLatin1String("dc c")) || mode.startsWith(QLatin1String("adc"))) {
      69           82 :         settings.mode = DataLoggerService::Mode::DcCurrent;
      70           82 :         minRangeFunc = minCurrentRange;
      71          246 :     } else if (mode.startsWith(QLatin1String("temp"))) {
      72          164 :         settings.mode = DataLoggerService::Mode::Temperature;
      73          164 :         minRangeFunc = nullptr;
      74           88 :     } else {
      75           82 :         minRangeFunc = nullptr;
      76          120 :         errors.append(tr("Unknown logger mode: %1").arg(parser.value(QLatin1String("mode"))));
      77           44 :         return errors;
      78          481 :     }
      79              : 
      80              :     // Parse the range option.
      81         1476 :     rangeOptionValue = 0;
      82         1746 :     if (parser.isSet(QLatin1String("range"))) {
      83         1394 :         const QString value = parser.value(QLatin1String("range"));
      84         1394 :         switch (settings.mode) {
      85          528 :         case DataLoggerService::Mode::DcVoltage:
      86          572 :         case DataLoggerService::Mode::AcVoltage:
      87         1066 :             rangeOptionValue = parseNumber<std::milli>(value, QLatin1String("V"), 50); // mV.
      88         1066 :             break;
      89           44 :         case DataLoggerService::Mode::DcCurrent:
      90           88 :         case DataLoggerService::Mode::AcCurrent:
      91          164 :             rangeOptionValue = parseNumber<std::milli>(value, QLatin1String("A"), 5); // mA.
      92          164 :             break;
      93          164 :         default:
      94          286 :             qCInfo(lc).noquote() << tr("Ignoring range value: %1").arg(value);
      95          748 :         }
      96         1394 :         if ((minRangeFunc != nullptr) && (rangeOptionValue == 0)) {
      97           97 :             errors.append(tr("Invalid range value: %1").arg(value));
      98           44 :         }
      99         1177 :     } else if (settings.mode != DataLoggerService::Mode::Temperature) {
     100          105 :         errors.append(tr("Missing required option for logger mode '%1': range")
     101          120 :             .arg(parser.value(QLatin1String("mode"))));
     102           44 :     }
     103              : 
     104              :     // Parse the interval option.
     105         1746 :     if (parser.isSet(QLatin1String("interval"))) {
     106          485 :         const QString value = parser.value(QLatin1String("interval"));
     107          410 :         const quint32 interval = parseNumber<std::milli>(value, QLatin1String("s"), 500);
     108          410 :         if (interval == 0) {
     109          194 :             errors.append(tr("Invalid interval value: %1").arg(value));
     110          132 :         } else {
     111          246 :             settings.updateInterval = interval;
     112          132 :         }
     113          335 :     }
     114              : 
     115              :     // Parse the timestamp option.
     116         1476 :     settings.timestamp = (quint32)QDateTime::currentSecsSinceEpoch(); // Note, subject to Y2038 epochalypse.
     117         1746 :     if (parser.isSet(QLatin1String("timestamp"))) {
     118          410 :         const QString value = parser.value(QLatin1String("timestamp"));
     119          410 :         QLocale locale; bool ok;
     120          220 :         static_assert(sizeof(uint) == sizeof(settings.timestamp), "QLocale has no toUint32().");
     121          335 :         const int timestamp = locale.toUInt(value, &ok);
     122          410 :         if (!ok) {
     123          194 :             errors.append(tr("Invalid timestamp value: %1").arg(value));
     124          132 :         } else {
     125          246 :             settings.timestamp = timestamp;
     126          132 :         }
     127          410 :     }
     128          792 :     return errors;
     129          792 : }
     130              : 
     131              : /*!
     132              :  * \copybrief DeviceCommand::getService
     133              :  *
     134              :  * This override returns a pointer to a DataLoggerService object.
     135              :  */
     136            0 : AbstractPokitService * LoggerStartCommand::getService()
     137            0 : {
     138            0 :     Q_ASSERT(device);
     139            0 :     if (!service) {
     140            0 :         service = device->dataLogger();
     141            0 :         Q_ASSERT(service);
     142            0 :         connect(service, &DataLoggerService::settingsWritten,
     143            0 :                 this, &LoggerStartCommand::settingsWritten);
     144            0 :     }
     145            0 :     return service;
     146            0 : }
     147              : 
     148              : /*!
     149              :  * \copybrief DeviceCommand::serviceDetailsDiscovered
     150              :  *
     151              :  * This override fetches the current device's status, and outputs it in the selected format.
     152              :  */
     153            0 : void LoggerStartCommand::serviceDetailsDiscovered()
     154            0 : {
     155            0 :     DeviceCommand::serviceDetailsDiscovered(); // Just logs consistently.
     156            0 :     settings.range = (minRangeFunc == nullptr) ? 0 : minRangeFunc(*service->pokitProduct(), rangeOptionValue);
     157            0 :     const QString range = service->toString(settings.range, settings.mode);
     158            0 :     qCInfo(lc).noquote() << tr("Logging %1, with range %2, every %L3ms.").arg(
     159            0 :         DataLoggerService::toString(settings.mode),
     160            0 :         (range.isNull()) ? QString::fromLatin1("N/A") : range).arg(settings.updateInterval);
     161            0 :     service->setSettings(settings);
     162            0 : }
     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              :  */
     181          114 : void LoggerStartCommand::settingsWritten()
     182          132 : {
     183          270 :     qCDebug(lc).noquote() << tr("Settings written; data logger has started.");
     184          246 :     switch (format) {
     185           82 :     case OutputFormat::Csv:
     186           82 :         std::cout << qUtf8Printable(tr("logger_start_result\nsuccess\n"));
     187           82 :         break;
     188           44 :     case OutputFormat::Json:
     189           93 :         std::cout << qUtf8Printable(QLatin1String("true\n"));
     190           82 :         break;
     191           82 :     case OutputFormat::Text:
     192           82 :         std::cout << qUtf8Printable(tr("Done.\n"));
     193           82 :         break;
     194          132 :     }
     195          246 :     if (device) disconnect(); // Will exit the application once disconnected.
     196          246 : }
        

Generated by: LCOV version 2.0-1