Add basic commander capabilities

pull/2/head
Simon Stürz 2017-12-28 13:17:23 +01:00
parent ef1837f105
commit 2631c821ec
10 changed files with 257 additions and 45 deletions

2
debian/control vendored
View File

@ -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

View File

@ -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";

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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:

View File

@ -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");

View File

@ -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 &parameters)
{
m_mandatorysParameters = parameters;
}
QStringList TerminalCommand::optionalParameters() const
{
return m_optionalParameters;
}
void TerminalCommand::setOptionalParameters(const QStringList &parameters)
{
m_optionalParameters = parameters;
}
bool TerminalCommand::isValid()
{
return !m_command.isEmpty() && !m_description.isEmpty();
}

View File

@ -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 &parameters);
QStringList optionalParameters() const;
void setOptionalParameters(const QStringList &parameters);
bool isValid();
private:
QString m_command;
QString m_description;
QStringList m_mandatorysParameters;
QStringList m_optionalParameters;
public slots:
};
#endif // TERMINALCOMMAND_H
#endif // TERMINALCOMMAND_H

View File

@ -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);
}

View File

@ -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);