Add basic commander capabilities
parent
ef1837f105
commit
2631c821ec
|
|
@ -12,7 +12,7 @@ Build-Depends: debhelper (>= 9.0.0),
|
|||
qtbase5-dev,
|
||||
qtbase5-dev-tools,
|
||||
libqt5serialport5-dev,
|
||||
libncurses5-dev
|
||||
libreadline-dev
|
||||
|
||||
Package: zigbee-cli
|
||||
Architecture: any
|
||||
|
|
|
|||
|
|
@ -69,6 +69,11 @@ QList<ZigbeeNode *> ZigbeeNetworkManager::nodeList() const
|
|||
return m_nodeList;
|
||||
}
|
||||
|
||||
bool ZigbeeNetworkManager::networkRunning() const
|
||||
{
|
||||
return m_networkRunning;
|
||||
}
|
||||
|
||||
void ZigbeeNetworkManager::reset()
|
||||
{
|
||||
qCCritical(dcZigbee()) << "Reset networkmanager: TODO: needs to be implementet";
|
||||
|
|
|
|||
|
|
@ -19,13 +19,18 @@ public:
|
|||
|
||||
void reset();
|
||||
|
||||
|
||||
bool networkRunning() const;
|
||||
|
||||
private:
|
||||
ZigbeeBridgeController *m_controller = nullptr;
|
||||
QString m_controllerVersion;
|
||||
quint64 m_extendedPanId;
|
||||
quint64 m_extendedPanId = 0;
|
||||
|
||||
QList<ZigbeeNode *> m_nodeList;
|
||||
|
||||
bool m_networkRunning = false;
|
||||
|
||||
quint64 generateRandomPanId();
|
||||
|
||||
// Controller methods
|
||||
|
|
@ -48,6 +53,7 @@ private:
|
|||
void requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile);
|
||||
|
||||
signals:
|
||||
void runningChanged(const bool &running);
|
||||
|
||||
private slots:
|
||||
void onMessageReceived(const ZigbeeInterfaceMessage &message);
|
||||
|
|
@ -72,7 +78,6 @@ private slots:
|
|||
|
||||
void onRequestMatchDescriptorFinished();
|
||||
|
||||
|
||||
// Process controller notifications/messages
|
||||
void processLoggingMessage(const ZigbeeInterfaceMessage &message);
|
||||
void processFactoryNewRestart(const ZigbeeInterfaceMessage &message);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
#include "core.h"
|
||||
#include "terminalcommander.h"
|
||||
#include "loggingcategory.h"
|
||||
#include "QCoreApplication"
|
||||
|
||||
Core::Core(const int &channel, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_manager = new ZigbeeNetworkManager(channel, "/dev/ttyS0", this);
|
||||
|
||||
TerminalCommander::instance();
|
||||
|
||||
// Set commands
|
||||
m_commands.append(TerminalCommand("run", "Run the zigbee controller in a normal non interactive mode."));
|
||||
m_commands.append(TerminalCommand("start", "Start the zigbee network"));
|
||||
m_commands.append(TerminalCommand("stop", "Stop the zigbee network"));
|
||||
m_commands.append(TerminalCommand("reset", "Reset the zigbee controller"));
|
||||
m_commands.append(TerminalCommand("scan", "Start scanning for zigbee networks"));
|
||||
m_commands.append(TerminalCommand("version", "Print the version of the zigbee controll bridge firmware"));
|
||||
m_commands.append(TerminalCommand("permit-join", "Permit nodes to join the network"));
|
||||
|
||||
TerminalCommander::instance()->setCommands(m_commands);
|
||||
|
||||
TerminalCommander::instance()->start();
|
||||
|
||||
|
|
@ -18,9 +25,10 @@ Core::Core(const int &channel, QObject *parent) :
|
|||
m_testTimer->setSingleShot(false);
|
||||
|
||||
connect(m_testTimer, &QTimer::timeout, this, &Core::onTimeout);
|
||||
m_testTimer->start();
|
||||
//m_testTimer->start();
|
||||
|
||||
connect(TerminalCommander::instance(), &TerminalCommander::commandReceived, this, &Core::onCommandReceived);
|
||||
connect(TerminalCommander::instance(), &TerminalCommander::finished, QCoreApplication::instance(), &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
void Core::onTimeout()
|
||||
|
|
@ -30,6 +38,26 @@ void Core::onTimeout()
|
|||
|
||||
void Core::onCommandReceived(const QStringList &tokens)
|
||||
{
|
||||
qCDebug(dcZigbee()) << "Command received:" << tokens;
|
||||
TerminalCommand command;
|
||||
foreach (const TerminalCommand &terminalCommand, m_commands) {
|
||||
if (tokens.first() == terminalCommand.command()) {
|
||||
command = terminalCommand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!command.isValid()) {
|
||||
qCWarning(dcZigbee()) << "Unknown command" << tokens;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Process command
|
||||
qCDebug(dcZigbee()) << "Executing" << tokens.join(" ");
|
||||
|
||||
if (command.command() == "start") {
|
||||
m_manager->startNetwork();
|
||||
} else if (command.command() == "version") {
|
||||
m_manager->getVersion();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <readline/readline.h>
|
||||
|
||||
#include "terminalcommander.h"
|
||||
#include "zigbeenetworkmanager.h"
|
||||
|
||||
class Core : public QObject
|
||||
|
|
@ -17,8 +18,10 @@ public:
|
|||
explicit Core(const int &channel, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
ZigbeeNetworkManager *m_manager;
|
||||
QTimer *m_testTimer;
|
||||
ZigbeeNetworkManager *m_manager = nullptr;
|
||||
QTimer *m_testTimer = nullptr;
|
||||
|
||||
QList<TerminalCommand> m_commands;
|
||||
|
||||
signals:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,18 +4,60 @@
|
|||
#include <QDateTime>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <initializer_list>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
#include "core.h"
|
||||
#include "zigbeecommander.h"
|
||||
#include "loggingcategory.h"
|
||||
#include "terminalcommander.h"
|
||||
|
||||
static const char *const normal = "\033[0m";
|
||||
static const char *const warning = "\e[33m";
|
||||
static const char *const error = "\e[31m";
|
||||
|
||||
static QHash<QString, bool> s_loggingFilters;
|
||||
|
||||
//static bool s_aboutToShutdown = false;
|
||||
|
||||
//static void catchUnixSignals(const std::vector<int>& quitSignals, const std::vector<int>& ignoreSignals = std::vector<int>()) {
|
||||
// auto handler = [](int sig) -> void {
|
||||
// switch (sig) {
|
||||
// case SIGQUIT:
|
||||
// qCDebug(dcZigbee()) << "Cought SIGQUIT quit signal...";
|
||||
// break;
|
||||
// case SIGINT:
|
||||
// qCDebug(dcZigbee()) << "Cought SIGINT quit signal...";
|
||||
// break;
|
||||
// case SIGTERM:
|
||||
// qCDebug(dcZigbee()) << "Cought SIGTERM quit signal...";
|
||||
// break;
|
||||
// case SIGHUP:
|
||||
// qCDebug(dcZigbee()) << "Cought SIGHUP quit signal...";
|
||||
// break;
|
||||
// case SIGSEGV: {
|
||||
// qCDebug(dcZigbee()) << "Cought SIGSEGV signal. Segmentation fault!";
|
||||
// exit(1);
|
||||
// }
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (s_aboutToShutdown) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// s_aboutToShutdown = true;
|
||||
// TerminalCommander::instance()->destroy();
|
||||
// TerminalCommander::instance()->quit();
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// // all these signals will be ignored.
|
||||
// for (int sig : ignoreSignals)
|
||||
// signal(sig, SIG_IGN);
|
||||
|
||||
// for (int sig : quitSignals)
|
||||
// signal(sig, handler);
|
||||
//}
|
||||
|
||||
static void loggingCategoryFilter(QLoggingCategory *category)
|
||||
{
|
||||
// If this is a known category
|
||||
|
|
@ -59,6 +101,9 @@ int main(int argc, char *argv[])
|
|||
qInstallMessageHandler(consoleLogHandler);
|
||||
|
||||
QCoreApplication application(argc, argv);
|
||||
|
||||
//catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGSEGV});
|
||||
|
||||
application.setOrganizationName("guh");
|
||||
application.setApplicationName("qt-zigbee");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,58 @@
|
|||
#include "terminalcommand.h"
|
||||
|
||||
TerminalCommand::TerminalCommand(QObject *parent) : QObject(parent)
|
||||
TerminalCommand::TerminalCommand()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TerminalCommand::TerminalCommand(const QString &command, const QString &description) :
|
||||
m_command(command),
|
||||
m_description(description)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString TerminalCommand::command() const
|
||||
{
|
||||
return m_command;
|
||||
}
|
||||
|
||||
void TerminalCommand::setCommand(const QString &command)
|
||||
{
|
||||
m_command = command;
|
||||
}
|
||||
|
||||
QString TerminalCommand::description() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
void TerminalCommand::setDescription(const QString &description)
|
||||
{
|
||||
m_description = description;
|
||||
}
|
||||
|
||||
QStringList TerminalCommand::mandatoryParameters() const
|
||||
{
|
||||
return m_mandatorysParameters;
|
||||
}
|
||||
|
||||
void TerminalCommand::setMandatoryParameters(const QStringList ¶meters)
|
||||
{
|
||||
m_mandatorysParameters = parameters;
|
||||
}
|
||||
|
||||
QStringList TerminalCommand::optionalParameters() const
|
||||
{
|
||||
return m_optionalParameters;
|
||||
}
|
||||
|
||||
void TerminalCommand::setOptionalParameters(const QStringList ¶meters)
|
||||
{
|
||||
m_optionalParameters = parameters;
|
||||
}
|
||||
|
||||
bool TerminalCommand::isValid()
|
||||
{
|
||||
return !m_command.isEmpty() && !m_description.isEmpty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,35 @@
|
|||
#ifndef TERMINALCOMMAND_H
|
||||
#define TERMINALCOMMAND_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class TerminalCommand : public QObject
|
||||
class TerminalCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TerminalCommand(QObject *parent = nullptr);
|
||||
explicit TerminalCommand();
|
||||
explicit TerminalCommand(const QString &command, const QString &description);
|
||||
|
||||
signals:
|
||||
QString command() const;
|
||||
void setCommand(const QString &command);
|
||||
|
||||
QString description() const;
|
||||
void setDescription(const QString &description);
|
||||
|
||||
QStringList mandatoryParameters() const;
|
||||
void setMandatoryParameters(const QStringList ¶meters);
|
||||
|
||||
QStringList optionalParameters() const;
|
||||
void setOptionalParameters(const QStringList ¶meters);
|
||||
|
||||
bool isValid();
|
||||
|
||||
private:
|
||||
QString m_command;
|
||||
QString m_description;
|
||||
QStringList m_mandatorysParameters;
|
||||
QStringList m_optionalParameters;
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // TERMINALCOMMAND_H
|
||||
#endif // TERMINALCOMMAND_H
|
||||
|
|
|
|||
|
|
@ -16,25 +16,34 @@ TerminalCommander *TerminalCommander::instance()
|
|||
return s_instance;
|
||||
}
|
||||
|
||||
QStringList TerminalCommander::commands() const
|
||||
void TerminalCommander::destroy()
|
||||
{
|
||||
qCDebug(dcZigbee()) << "Shut down terminal commander. Have a nice day.b";
|
||||
stopProcess();
|
||||
}
|
||||
|
||||
QList<TerminalCommand> TerminalCommander::commands() const
|
||||
{
|
||||
return m_commands;
|
||||
}
|
||||
|
||||
void TerminalCommander::setCommands(QList<TerminalCommand> commands)
|
||||
{
|
||||
m_commands.append(commands);
|
||||
}
|
||||
|
||||
TerminalCommander::TerminalCommander(QObject *parent) :
|
||||
QThread(parent)
|
||||
{
|
||||
m_commands.append("start");
|
||||
m_commands.append("stop");
|
||||
m_commands.append("explode");
|
||||
// Native terminal commands
|
||||
m_commands.append(TerminalCommand("exit", "Exit this application"));
|
||||
m_commands.append(TerminalCommand("quit", "Quit this application"));
|
||||
m_commands.append(TerminalCommand("help", "Print this help message"));
|
||||
}
|
||||
|
||||
TerminalCommander::~TerminalCommander()
|
||||
{
|
||||
mutex.lock();
|
||||
m_abort = true;
|
||||
mutex.unlock();
|
||||
|
||||
destroy();
|
||||
wait();
|
||||
}
|
||||
|
||||
|
|
@ -45,9 +54,8 @@ void TerminalCommander::printToTerminal(const QString &message)
|
|||
|
||||
void TerminalCommander::stopProcess()
|
||||
{
|
||||
mutex.lock();
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_abort = true;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void TerminalCommander::run()
|
||||
|
|
@ -57,24 +65,51 @@ void TerminalCommander::run()
|
|||
|
||||
rl_set_prompt(QString("%1[zigbee]%2 ").arg(terminalColorBoldGray).arg(terminalColorNormal).toStdString().data());
|
||||
rl_redisplay();
|
||||
|
||||
rl_bind_key('\t',rl_complete);
|
||||
|
||||
rl_clear_signals();
|
||||
rl_catch_signals = 1;
|
||||
|
||||
while (true) {
|
||||
char *buffer = readline(QString("%1[zigbee]%2 ").arg(terminalColorBoldGray).arg(terminalColorNormal).toStdString().data());
|
||||
rl_bind_key('\t',rl_complete);
|
||||
if (buffer) {
|
||||
if (!QString(buffer).isEmpty()) {
|
||||
QStringList tokens = QString(buffer).split(" ");
|
||||
emit commandReceived(tokens);
|
||||
add_history(buffer);
|
||||
free(buffer);
|
||||
|
||||
// Check quit
|
||||
if (tokens.count() == 1 && (tokens.first() == "quit" || tokens.first() == "exit")) {
|
||||
qDebug() << "";
|
||||
rl_on_new_line();
|
||||
rl_replace_line("", 0);
|
||||
rl_redisplay();
|
||||
qCDebug(dcZigbee()) << "Terminal thread stopped";
|
||||
free(buffer);
|
||||
stopProcess();
|
||||
return;
|
||||
|
||||
} else if (tokens.count() == 1 && (tokens.first() == "?" || tokens.first() == "help")) {
|
||||
printHelpMessage();
|
||||
add_history(buffer);
|
||||
free(buffer);
|
||||
} else {
|
||||
emit commandReceived(tokens);
|
||||
add_history(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_abort)
|
||||
return;
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (m_abort) {
|
||||
qDebug() << "";
|
||||
rl_on_new_line();
|
||||
rl_replace_line("", 0);
|
||||
rl_redisplay();
|
||||
qCDebug(dcZigbee()) << "Terminal thread stopped";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
msleep(10);
|
||||
}
|
||||
|
|
@ -107,7 +142,21 @@ void TerminalCommander::rl_printf(const char *fmt, ...)
|
|||
rl_redisplay();
|
||||
free(saved_line);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalCommander::signalHandler(int status)
|
||||
{
|
||||
Q_UNUSED(status)
|
||||
qCDebug(dcZigbee()) << "Terminal thread stopped";
|
||||
TerminalCommander::instance()->stopProcess();
|
||||
}
|
||||
|
||||
void TerminalCommander::printHelpMessage()
|
||||
{
|
||||
for (int i = 0; i < m_commands.count(); i++) {
|
||||
QString command = QString("\t%1 %2").arg(m_commands.at(i).command(), -20).arg(m_commands.at(i).description());
|
||||
rl_printf("%s\n",command.toStdString().data());
|
||||
}
|
||||
}
|
||||
|
||||
char **commandCompletion(const char *text, int start, int end)
|
||||
|
|
@ -135,7 +184,7 @@ char *commandCompletionGenerator(const char *text, int state)
|
|||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (list_index < TerminalCommander::instance()->commands().count() && (name = TerminalCommander::instance()->commands().at(list_index).toStdString().data())) {
|
||||
while (list_index < TerminalCommander::instance()->commands().count() && (name = TerminalCommander::instance()->commands().at(list_index).command().toStdString().data())) {
|
||||
list_index++;
|
||||
if (strncmp (name, text, len) == 0) return strdup (name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include "terminalcommand.h"
|
||||
|
||||
static const char *const terminalColorNormal = "\033[0m";
|
||||
static const char *const terminalColorYellow = "\x1B[0;93m";
|
||||
static const char *const terminalColorRed = "\x1B[0;91m";
|
||||
|
|
@ -24,21 +26,26 @@ class TerminalCommander : public QThread
|
|||
Q_OBJECT
|
||||
public:
|
||||
static TerminalCommander* instance();
|
||||
void destroy();
|
||||
|
||||
QList<TerminalCommand> commands() const;
|
||||
void setCommands(QList<TerminalCommand> commands);
|
||||
|
||||
QStringList commands() const;
|
||||
void printToTerminal(const QString &message);
|
||||
|
||||
private:
|
||||
explicit TerminalCommander(QObject *parent = nullptr);
|
||||
~TerminalCommander();
|
||||
|
||||
bool m_abort = false;
|
||||
QMutex mutex;
|
||||
QList<TerminalCommand> m_commands;
|
||||
|
||||
QStringList m_commands;
|
||||
QMutex m_mutex;
|
||||
bool m_abort = false;
|
||||
|
||||
static void rl_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
static void signalHandler(int status);
|
||||
|
||||
void printHelpMessage();
|
||||
|
||||
signals:
|
||||
void commandReceived(const QStringList &tokens);
|
||||
|
|
|
|||
Loading…
Reference in New Issue