4#include "calibratecommand.h"
6#include "flashledcommand.h"
7#include "infocommand.h"
8#include "loggerfetchcommand.h"
9#include "loggerstartcommand.h"
10#include "loggerstopcommand.h"
11#include "metercommand.h"
12#include "scancommand.h"
13#include "setnamecommand.h"
14#include "settorchcommand.h"
15#include "statuscommand.h"
17#include <QCommandLineParser>
18#include <QCoreApplication>
20#include <QLoggingCategory>
27#elif defined(Q_OS_WIN)
31static Q_LOGGING_CATEGORY(lc,
"dokit.cli.main", QtInfoMsg);
33inline bool haveConsole()
35 #if defined(Q_OS_UNIX)
36 return isatty(STDERR_FILENO);
37 #elif defined(Q_OS_WIN)
38 return GetConsoleWindow();
47 QString messagePattern = QStringLiteral(
"%{if-category}%{category}: %{endif}%{message}");
49 if (parser.
isSet(QStringLiteral(
"debug"))) {
50 #ifdef QT_MESSAGELOGCONTEXT
52 messagePattern.
prepend(QStringLiteral(
"%{function} "));
54 messagePattern.
prepend(QStringLiteral(
"%{time process} %{threadid} %{type} "));
58 const QString color = parser.
value(QStringLiteral(
"color"));
59 if ((color == QStringLiteral(
"yes")) || (color == QStringLiteral(
"auto") && haveConsole())) {
60 messagePattern.
prepend(QStringLiteral(
61 "%{if-debug}\x1b[37m%{endif}"
62 "%{if-info}\x1b[32m%{endif}"
63 "%{if-warning}\x1b[35m%{endif}"
64 "%{if-critical}\x1b[31m%{endif}"
65 "%{if-fatal}\x1b[31;1m%{endif}"));
66 messagePattern.
append(QStringLiteral(
"\x1b[0m"));
69 qSetMessagePattern(messagePattern);
88void showCliError(
const QString &errorText)
93 std::cerr << qUtf8Printable(message);
96Command getCliCommand(
const QStringList &posArguments)
101 if (posArguments.
size() > 1) {
103 .arg(posArguments.
join(QStringLiteral(
", "))));
104 ::exit(EXIT_FAILURE);
108 { QStringLiteral(
"info"), Command::Info },
109 { QStringLiteral(
"status"), Command::Status },
110 { QStringLiteral(
"meter"), Command::Meter },
111 { QStringLiteral(
"dso"), Command::DSO },
112 { QStringLiteral(
"logger-start"), Command::LoggerStart },
113 { QStringLiteral(
"logger-stop"), Command::LoggerStop },
114 { QStringLiteral(
"logger-fetch"), Command::LoggerFetch },
115 { QStringLiteral(
"scan"), Command::Scan },
116 { QStringLiteral(
"set-name"), Command::SetName },
117 { QStringLiteral(
"set-torch"), Command::SetTorch },
118 { QStringLiteral(
"flash-led"), Command::FlashLed },
119 { QStringLiteral(
"calibrate"), Command::Calibrate },
121 const Command command = supportedCommands.
value(posArguments.
first().toLower(), Command::None);
122 if (command == Command::None) {
124 ::exit(EXIT_FAILURE);
133 { QStringLiteral(
"color"),
135 "are: yes, no and auto. The default is auto."),
136 QStringLiteral(
"yes|no|auto"), QStringLiteral(
"auto")},
137 {{QStringLiteral(
"debug")},
139 {{QStringLiteral(
"d"), QStringLiteral(
"device")},
141 "Set the name, hardware address or macOS UUID of Pokit device to use. If not specified, "
142 "the first discovered Pokit device will be used."),
147 {{QStringLiteral(
"interval")},
149 "logger modes. Suffixes such as 's' and 'ms' (for seconds and milliseconds) may be used. "
150 "If no suffix is present, the units will be inferred from the magnitide of the given "
151 "interval. If the option itself is not specified, a sensible default will be chosen "
152 "according to the selected command."),
154 {{QStringLiteral(
"mode")},
156 "meter, dso, and logger commands, the supported modes are: AC Voltage, DC Voltage, AC Current, "
157 "DC Current, Resistance, Diode, Continuity, and Temperature. All are case insensitive. "
158 "Only the first four options are available for dso and logger commands; the rest are "
159 "available in meter mode only. Temperature is also available for logger commands, but "
160 "requires firmware v1.5 or later for Pokit devices to support it. For the set-torch command "
161 "supported modes are On and Off."),
163 {{QStringLiteral(
"new-name")},
166 {{QStringLiteral(
"output")},
168 "formats are: CSV, JSON and Text. All are case insenstitve. The default is Text."),
171 {{QStringLiteral(
"range")},
173 "devices support specific ranges, such as 0 to 300mV. Specify the desired upper limit, "
174 "and the best range will be selected, or use 'auto' to enable the Pokit device's auto-"
175 "range feature. The default is 'auto'."),
177 {{QStringLiteral(
"samples")},
180 {{QStringLiteral(
"temperature")},
183 {{QStringLiteral(
"timeout")},
185 "Suffixes such as 's' and 'ms' (for seconds and milliseconds) may be used. "
186 "If no suffix is present, the units will be inferred from the magnitide of the given "
187 "interval. The default behaviour is no timeout."),
189 {{QStringLiteral(
"timestamp")},
191 "data logging. Default to 'now'."),
193 {{QStringLiteral(
"trigger-level")},
196 {{QStringLiteral(
"trigger-mode")},
198 "modes are: free, rising and falling. The default is free."),
206 QStringLiteral(
" "));
209 QStringLiteral(
" "));
212 QStringLiteral(
" "));
215 QStringLiteral(
" "));
218 QStringLiteral(
" "));
221 QStringLiteral(
" "));
224 QStringLiteral(
" "));
227 QStringLiteral(
" "));
230 QStringLiteral(
" "));
233 QStringLiteral(
" "));
236 QStringLiteral(
" "));
239 QStringLiteral(
" "));
242 parser.
parse(appArguments);
243 configureLogging(parser);
247 if (command != Command::None) {
252 if (parser.
isSet(QStringLiteral(
"help"))) {
253 const QString commandString = (command == Command::None) ? QStringLiteral(
"<command>")
255 std::cout << qUtf8Printable(parser.
helpText()
256 .
replace(QStringLiteral(
"[options]"), commandString + QStringLiteral(
" [options]"))
257 .replace(QStringLiteral(
"Arguments:"), QStringLiteral(
"Command:"))
259 ::exit(EXIT_SUCCESS);
272 "Missing argument: <command>\nSee --help for usage information."));
275 case Command::DSO:
return new DsoCommand(parent);
277 case Command::Info:
return new InfoCommand(parent);
282 case Command::Scan:
return new ScanCommand(parent);
291int main(
int argc,
char *argv[])
297 #ifdef PROJECT_PRE_RELEASE
298 "-" PROJECT_PRE_RELEASE
300 #ifdef PROJECT_BUILD_ID
307 if (appTranslator.
load(
QLocale(), QStringLiteral(
"cli"), QStringLiteral(
"/"), QStringLiteral(
":/i18n"))) {
310 if (libTranslator.
load(
QLocale(), QStringLiteral(
"lib"), QStringLiteral(
"/"), QStringLiteral(
":/i18n"))) {
317 const Command commandType = parseCommandLine(appArguments, parser);
319 qCDebug(lc).noquote() <<
"Qt" << qVersion() <<
"(runtime) [" QT_VERSION_STR
" compile-time]";
320#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
321 qCDebug(lc).noquote() <<
"App translations:" <<
322 (appTranslator.
filePath().
isEmpty() ? QStringLiteral(
"<none>") : appTranslator.filePath());
323 qCDebug(lc).noquote() <<
"Library translations:" <<
324 (libTranslator.
filePath().
isEmpty() ? QStringLiteral(
"<none>") : libTranslator.filePath());
326 qCDebug(lc).noquote() <<
"App translations:" << (!appTranslator.
isEmpty());
327 qCDebug(lc).noquote() <<
"Lib translations:" << (!libTranslator.
isEmpty());
332 if (command ==
nullptr) {
336 for (
const QString &error: cliErrors) {
The AbstractCommand class provides a consistent base for the classes that implement CLI commands.
virtual bool start()=0
Begins the functionality of this command, and returns true if begun successfully, false otherwise.
virtual QStringList processOptions(const QCommandLineParser &parser)
Processes the relevant options from the command line parser.
The CalibrateCommand class implements the calibrate CLI command.
The DsoCommand class implements the dso CLI command.
The FlashLedCommand class implements the flash-led CLI command.
The InfoCommand class implements the info CLI command.
The LoggerFetchCommand class implements the logger CLI command.
The LoggerStartCommand class implements the logger CLI command.
The LoggerStopCommand class implements the logger stop CLI command.
The MeterCommand class implements the meter CLI command.
The ScanCommand class implements the scan CLI command, by scanning for nearby Pokit Bluetooth devices...
The SetNameCommand class implements the set-name CLI command.
The SetTorchCommand class implements the set-torch CLI command.
The StatusCommand class implements the status CLI command.
QCommandLineOption addHelpOption()
bool addOptions(const QList< QCommandLineOption > &options)
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
QCommandLineOption addVersionOption()
void clearPositionalArguments()
QString helpText() const const
bool isSet(const QString &name) const const
bool parse(const QStringList &arguments)
QStringList positionalArguments() const const
void process(const QStringList &arguments)
QString value(const QString &optionName) const const
void setApplicationVersion(const QString &version)
bool installTranslator(QTranslator *translationFile)
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
const T & constFirst() const const
bool isEmpty() const const
void setFilterRules(const QString &rules)
const T value(const Key &key, const T &defaultValue) const const
QString & append(QChar ch)
QString fromLatin1(const char *str, int size)
bool isEmpty() const const
QString & prepend(QChar ch)
QString & replace(int position, int n, QChar after)
QString join(const QString &separator) const const
QString filePath() const const
virtual bool isEmpty() const const
bool load(const QString &filename, const QString &directory, const QString &search_delimiters, const QString &suffix)