Implement basic initialization of NXP network

This commit is contained in:
Simon Stürz 2020-10-07 14:43:17 +02:00
parent a219fa46ef
commit e00a1ffea0
6 changed files with 156 additions and 28 deletions

View File

@ -10,7 +10,12 @@ public:
enum Command { enum Command {
CommandGetVersion = 0x00, CommandGetVersion = 0x00,
CommandGetControllerState = 0x01, CommandGetControllerState = 0x01,
CommandSoftReset = 0x02 CommandSoftReset = 0x02,
CommandFactoryReset = 0x03,
CommandSetPanId = 0x04,
CommandSetChannelMask = 0x05,
CommandSetSecurityKey = 0x06,
CommandStartNetwork = 0x07
}; };
Q_ENUM(Command) Q_ENUM(Command)
@ -24,7 +29,8 @@ public:
StatusSuccess = 0x00, StatusSuccess = 0x00,
StatusProtocolError = 0x01, StatusProtocolError = 0x01,
StatusUnknownCommand = 0x02, StatusUnknownCommand = 0x02,
StatusInvalidCrc = 0x03 StatusInvalidCrc = 0x03,
StatusStackError = 0x04
}; };
Q_ENUM(Status) Q_ENUM(Status)

View File

@ -163,7 +163,7 @@ void ZigbeeInterfaceNxp::onReadyRead()
// Read each byte until we get END byte, then unescape the package // Read each byte until we get END byte, then unescape the package
for (int i = 0; i < data.length(); i++) { for (int i = 0; i < data.length(); i++) {
quint8 byte = static_cast<quint8>(data.at(i)); quint8 byte = static_cast<quint8>(data.at(i));
qCDebug(dcZigbeeInterfaceTraffic()) << "[in] " << ZigbeeUtils::convertByteToHexString(byte); //qCDebug(dcZigbeeInterfaceTraffic()) << "[in] " << ZigbeeUtils::convertByteToHexString(byte);
if (byte == ProtocolByteEnd) { if (byte == ProtocolByteEnd) {
// If there is no data...continue since it might be a starting END byte // If there is no data...continue since it might be a starting END byte
if (m_dataBuffer.isEmpty()) if (m_dataBuffer.isEmpty())
@ -235,9 +235,9 @@ void ZigbeeInterfaceNxp::sendPackage(const QByteArray &package)
// Send the data // Send the data
qCDebug(dcZigbeeInterfaceTraffic()) << "-->" << ZigbeeUtils::convertByteArrayToHexString(data); qCDebug(dcZigbeeInterfaceTraffic()) << "-->" << ZigbeeUtils::convertByteArrayToHexString(data);
for (int i = 0; i < data.length(); i++) { // for (int i = 0; i < data.length(); i++) {
qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << ZigbeeUtils::convertByteToHexString(data.at(i)); // qCDebug(dcZigbeeInterfaceTraffic()) << "[out]" << ZigbeeUtils::convertByteToHexString(data.at(i));
} // }
if (m_serialPort->write(data) < 0) { if (m_serialPort->write(data) < 0) {
qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data); qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data);

View File

@ -25,10 +25,11 @@ ZigbeeBridgeControllerNxp::ControllerState ZigbeeBridgeControllerNxp::controller
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestVersion() ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestVersion()
{ {
QByteArray message; QByteArray message;
bumpSequenceNumber();
QDataStream stream(&message, QIODevice::WriteOnly); QDataStream stream(&message, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Nxp::CommandGetVersion); stream << static_cast<quint8>(Nxp::CommandGetVersion);
stream << static_cast<quint8>(m_sequenceNumber++); stream << static_cast<quint8>(m_sequenceNumber);
stream << static_cast<quint16>(0); // Frame length stream << static_cast<quint16>(0); // Frame length
return createReply(Nxp::CommandGetVersion, m_sequenceNumber, "Request controller version", message, this); return createReply(Nxp::CommandGetVersion, m_sequenceNumber, "Request controller version", message, this);
@ -37,10 +38,11 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestVersion()
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestControllerState() ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestControllerState()
{ {
QByteArray message; QByteArray message;
bumpSequenceNumber();
QDataStream stream(&message, QIODevice::WriteOnly); QDataStream stream(&message, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Nxp::CommandGetControllerState); stream << static_cast<quint8>(Nxp::CommandGetControllerState);
stream << static_cast<quint8>(m_sequenceNumber++); stream << static_cast<quint8>(m_sequenceNumber);
stream << static_cast<quint16>(0); // Frame length stream << static_cast<quint16>(0); // Frame length
return createReply(Nxp::CommandGetControllerState, m_sequenceNumber, "Request controller state", message, this); return createReply(Nxp::CommandGetControllerState, m_sequenceNumber, "Request controller state", message, this);
@ -49,15 +51,57 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestControllerState()
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestSoftResetController() ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestSoftResetController()
{ {
QByteArray message; QByteArray message;
bumpSequenceNumber();
QDataStream stream(&message, QIODevice::WriteOnly); QDataStream stream(&message, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Nxp::CommandSoftReset); stream << static_cast<quint8>(Nxp::CommandSoftReset);
stream << static_cast<quint8>(m_sequenceNumber++); stream << static_cast<quint8>(m_sequenceNumber);
stream << static_cast<quint16>(0); // Frame length stream << static_cast<quint16>(0); // Frame length
return createReply(Nxp::CommandSoftReset, m_sequenceNumber, "Request soft reset controller", message, this); return createReply(Nxp::CommandSoftReset, m_sequenceNumber, "Request soft reset controller", message, this);
} }
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestFactoryResetController()
{
QByteArray message;
bumpSequenceNumber();
QDataStream stream(&message, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Nxp::CommandFactoryReset);
stream << static_cast<quint8>(m_sequenceNumber);
stream << static_cast<quint16>(0); // Frame length
return createReply(Nxp::CommandFactoryReset, m_sequenceNumber, "Request factory reset controller", message, this);
}
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestSetPanId(quint64 panId)
{
QByteArray message;
bumpSequenceNumber();
QDataStream stream(&message, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Nxp::CommandSetPanId);
stream << static_cast<quint8>(m_sequenceNumber);
stream << static_cast<quint16>(8); // Frame length
stream << panId;
return createReply(Nxp::CommandSetPanId, m_sequenceNumber, "Request set PAN ID", message, this);
}
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestSetChannelMask(quint32 channelMask)
{
QByteArray message;
bumpSequenceNumber();
QDataStream stream(&message, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Nxp::CommandSetChannelMask);
stream << static_cast<quint8>(m_sequenceNumber);
stream << static_cast<quint16>(4); // Frame length
stream << channelMask;
return createReply(Nxp::CommandSetChannelMask, m_sequenceNumber, "Request set channel mask", message, this);
}
ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent) ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent)
{ {
// Create the reply // Create the reply
@ -65,23 +109,32 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::createReply(Nxp::Command com
reply->m_requestName = requestName; reply->m_requestName = requestName;
reply->m_requestData = requestData; reply->m_requestData = requestData;
reply->m_sequenceNumber = sequenceNumber; reply->m_sequenceNumber = sequenceNumber;
// Make sure we clean up on timeout // Make sure we clean up on timeout
connect(reply, &ZigbeeInterfaceNxpReply::timeout, this, [reply](){ connect(reply, &ZigbeeInterfaceNxpReply::timeout, this, [reply](){
qCWarning(dcZigbeeController()) << "Reply timeout" << reply; qCWarning(dcZigbeeController()) << "Reply timeout" << reply;
}); });
// Auto delete the object on finished // Auto delete the object on finished
connect(reply, &ZigbeeInterfaceNxpReply::finished, reply, [reply](){ connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
qCDebug(dcZigbeeController()) << "Interface reply finished" << reply->command() << reply->sequenceNumber() << reply->status();
reply->deleteLater(); reply->deleteLater();
if (m_currentReply == reply) {
m_currentReply = nullptr;
QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection);
}
}); });
m_pendingReplies.insert(sequenceNumber, reply); qCDebug(dcZigbeeController()) << "Enqueue request" << reply->command() << "SQN:" << reply->sequenceNumber();
m_interface->sendPackage(requestData); m_replyQueue.enqueue(reply);
QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection);
return reply; return reply;
} }
void ZigbeeBridgeControllerNxp::bumpSequenceNumber()
{
m_sequenceNumber += 1;
}
void ZigbeeBridgeControllerNxp::onInterfaceAvailableChanged(bool available) void ZigbeeBridgeControllerNxp::onInterfaceAvailableChanged(bool available)
{ {
qCDebug(dcZigbeeController()) << "Interface available changed" << available; qCDebug(dcZigbeeController()) << "Interface available changed" << available;
@ -106,14 +159,14 @@ void ZigbeeBridgeControllerNxp::onInterfacePackageReceived(const QByteArray &pac
} }
Nxp::Notification notification = static_cast<Nxp::Notification>(commandInt); Nxp::Notification notification = static_cast<Nxp::Notification>(commandInt);
//qCDebug(dcZigbeeController()) << "Interface notification received" << notification << "SQN:" << sequenceNumber << ZigbeeUtils::convertByteArrayToHexString(data); qCDebug(dcZigbeeController()) << "Interface notification received" << notification << "SQN:" << sequenceNumber << ZigbeeUtils::convertByteArrayToHexString(data);
switch (notification) { switch (notification) {
case Nxp::NotificationDebugMessage: case Nxp::NotificationDebugMessage:
if (data.isEmpty()) { if (data.isEmpty()) {
qCWarning(dcZigbeeController()) << "Received empty debug log notification"; qCWarning(dcZigbeeController()) << "Received empty debug log notification";
return; return;
} }
qCDebug(dcZigbeeController()) << "DEBUG" << static_cast<Nxp::LogLevel>(data.at(0)) << qUtf8Printable(data.right(data.length() - 1)); qCDebug(dcZigbeeController()) << "*****DEBUG*****" << static_cast<Nxp::LogLevel>(data.at(0)) << Qt::endl << qUtf8Printable(data.right(data.length() - 1));
break; break;
case Nxp::NotificationDeviceStatusChanged: case Nxp::NotificationDeviceStatusChanged:
m_controllerState = static_cast<ControllerState>(data.at(0)); m_controllerState = static_cast<ControllerState>(data.at(0));
@ -135,21 +188,37 @@ void ZigbeeBridgeControllerNxp::onInterfacePackageReceived(const QByteArray &pac
Nxp::Command command = static_cast<Nxp::Command>(commandInt); Nxp::Command command = static_cast<Nxp::Command>(commandInt);
Nxp::Status status = static_cast<Nxp::Status>(statusInt); Nxp::Status status = static_cast<Nxp::Status>(statusInt);
qCDebug(dcZigbeeController()) << "Interface response received" << command << "SQN:" << sequenceNumber << status << ZigbeeUtils::convertByteArrayToHexString(data); qCDebug(dcZigbeeController()) << "Interface response received" << command << "SQN:" << sequenceNumber << status << ZigbeeUtils::convertByteArrayToHexString(data);
if (m_pendingReplies.keys().contains(sequenceNumber)) { if (m_currentReply->sequenceNumber() == sequenceNumber) {
ZigbeeInterfaceNxpReply * reply = m_pendingReplies.take(sequenceNumber); if (m_currentReply->command() == command) {
if (reply->command() == command) { m_currentReply->m_status = status;
reply->m_status = status; m_currentReply->m_responseData = data;
reply->m_responseData = data;
} else { } else {
qCWarning(dcZigbeeController()) << "Received interface response for a pending sequence number but the command does not match the request." << command << reply->command(); qCWarning(dcZigbeeController()) << "Received interface response for a pending sequence number but the command does not match the request." << command << m_currentReply->command();
} }
reply->setFinished(); m_currentReply->setFinished();
} else { } else {
qCWarning(dcZigbeeController()) << "Received a response for a non pending reply. There is no pending reply for command" << command << "SQN:" << sequenceNumber; qCWarning(dcZigbeeController()) << "Received a response for a non pending reply. There is no pending reply for command" << command << "SQN:" << sequenceNumber;
} }
} }
} }
void ZigbeeBridgeControllerNxp::sendNextRequest()
{
// Check if there is a reply request to send
if (m_replyQueue.isEmpty())
return;
// Check if there is currently a running reply
if (m_currentReply)
return;
// Send next message
m_currentReply = m_replyQueue.dequeue();
qCDebug(dcZigbeeController()) << "Send request" << m_currentReply;
m_interface->sendPackage(m_currentReply->requestData());
m_currentReply->m_timer->start();
}
bool ZigbeeBridgeControllerNxp::enable(const QString &serialPort, qint32 baudrate) bool ZigbeeBridgeControllerNxp::enable(const QString &serialPort, qint32 baudrate)
{ {
return m_interface->enable(serialPort, baudrate); return m_interface->enable(serialPort, baudrate);

View File

@ -17,6 +17,9 @@
class ZigbeeBridgeControllerNxp : public ZigbeeBridgeController class ZigbeeBridgeControllerNxp : public ZigbeeBridgeController
{ {
Q_OBJECT Q_OBJECT
friend class ZigbeeNetworkNxp;
public: public:
explicit ZigbeeBridgeControllerNxp(QObject *parent = nullptr); explicit ZigbeeBridgeControllerNxp(QObject *parent = nullptr);
~ZigbeeBridgeControllerNxp() override; ~ZigbeeBridgeControllerNxp() override;
@ -36,6 +39,9 @@ public:
ZigbeeInterfaceNxpReply *requestVersion(); ZigbeeInterfaceNxpReply *requestVersion();
ZigbeeInterfaceNxpReply *requestControllerState(); ZigbeeInterfaceNxpReply *requestControllerState();
ZigbeeInterfaceNxpReply *requestSoftResetController(); ZigbeeInterfaceNxpReply *requestSoftResetController();
ZigbeeInterfaceNxpReply *requestFactoryResetController();
ZigbeeInterfaceNxpReply *requestSetPanId(quint64 panId);
ZigbeeInterfaceNxpReply *requestSetChannelMask(quint32 channelMask);
signals: signals:
void controllerStateChanged(ControllerState controllerState); void controllerStateChanged(ControllerState controllerState);
@ -46,13 +52,18 @@ private:
ControllerState m_controllerState = ControllerStateNotRunning; ControllerState m_controllerState = ControllerStateNotRunning;
quint8 m_sequenceNumber = 0; quint8 m_sequenceNumber = 0;
QHash<quint8, ZigbeeInterfaceNxpReply *> m_pendingReplies; ZigbeeInterfaceNxpReply *m_currentReply = nullptr;
QQueue<ZigbeeInterfaceNxpReply *> m_replyQueue;
ZigbeeInterfaceNxpReply *createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent); ZigbeeInterfaceNxpReply *createReply(Nxp::Command command, quint8 sequenceNumber, const QString &requestName, const QByteArray &requestData, QObject *parent);
void bumpSequenceNumber();
private slots: private slots:
void onInterfaceAvailableChanged(bool available); void onInterfaceAvailableChanged(bool available);
void onInterfacePackageReceived(const QByteArray &package); void onInterfacePackageReceived(const QByteArray &package);
void sendNextRequest();
public slots: public slots:
bool enable(const QString &serialPort, qint32 baudrate); bool enable(const QString &serialPort, qint32 baudrate);
void disable(); void disable();

View File

@ -2,6 +2,8 @@
#include "loggingcategory.h" #include "loggingcategory.h"
#include "zigbeeutils.h" #include "zigbeeutils.h"
#include <QDataStream>
ZigbeeNetworkNxp::ZigbeeNetworkNxp(QObject *parent) : ZigbeeNetworkNxp::ZigbeeNetworkNxp(QObject *parent) :
ZigbeeNetwork(parent) ZigbeeNetwork(parent)
{ {
@ -39,7 +41,7 @@ void ZigbeeNetworkNxp::onControllerAvailableChanged(bool available)
qCDebug(dcZigbeeNetwork()) << "Controller is" << (available ? "now available" : "not available any more"); qCDebug(dcZigbeeNetwork()) << "Controller is" << (available ? "now available" : "not available any more");
if (available) { if (available) {
reset(); reset();
} }
} }
@ -49,8 +51,19 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
case ZigbeeBridgeControllerNxp::ControllerStateRunning: { case ZigbeeBridgeControllerNxp::ControllerStateRunning: {
qCDebug(dcZigbeeNetwork()) << "Request controller version"; qCDebug(dcZigbeeNetwork()) << "Request controller version";
ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion(); ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [reply](){ connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status(); qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status();
QByteArray payload = reply->responseData();
QDataStream stream(&payload, QIODevice::ReadOnly);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 major = 0; quint8 minor = 0; quint8 patch = 0; quint16 sdkVersion = 0;
stream >> major >> minor >> patch >> sdkVersion;
QString versionString = QString ("%1.%2.%3 - %4").arg(major).arg(minor).arg(patch).arg(sdkVersion);
qCDebug(dcZigbeeNetwork()) << "Controller version" << versionString;
m_controller->setFirmwareVersion(versionString);
// We are done here...
}); });
break; break;
@ -62,8 +75,30 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
case ZigbeeBridgeControllerNxp::ControllerStateRunningUninitialized: { case ZigbeeBridgeControllerNxp::ControllerStateRunningUninitialized: {
qCDebug(dcZigbeeNetwork()) << "Request controller version"; qCDebug(dcZigbeeNetwork()) << "Request controller version";
ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion(); ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [reply](){ connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status(); qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status();
QByteArray payload = reply->responseData();
QDataStream stream(&payload, QIODevice::ReadOnly);
stream.setByteOrder(QDataStream::LittleEndian);
quint8 major = 0; quint8 minor = 0; quint8 patch = 0; quint16 sdkVersion = 0;
stream >> major >> minor >> patch >> sdkVersion;
QString versionString = QString ("%1.%2.%3 - %4").arg(major).arg(minor).arg(patch).arg(sdkVersion);
qCDebug(dcZigbeeNetwork()) << "Controller version" << versionString;
m_controller->setFirmwareVersion(versionString);
qCDebug(dcZigbeeNetwork()) << "Set pan id" << ZigbeeUtils::convertUint64ToHexString(extendedPanId()) << extendedPanId();
ZigbeeInterfaceNxpReply *reply = m_controller->requestSetPanId(extendedPanId());
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
qCDebug(dcZigbeeNetwork()) << "Set PAN ID reply finished" << reply->status();
qCDebug(dcZigbeeNetwork()) << "Set channel mask" << channelMask() << ZigbeeUtils::convertUint32ToHexString(channelMask().toUInt32()) << channelMask().toUInt32();
ZigbeeInterfaceNxpReply *reply = m_controller->requestSetChannelMask(channelMask().toUInt32());
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [reply](){
qCDebug(dcZigbeeNetwork()) << "Set channel mask reply finished" << reply->status();
});
});
}); });
break; break;
} }
@ -110,5 +145,8 @@ void ZigbeeNetworkNxp::reset()
void ZigbeeNetworkNxp::factoryResetNetwork() void ZigbeeNetworkNxp::factoryResetNetwork()
{ {
ZigbeeInterfaceNxpReply *reply = m_controller->requestFactoryResetController();
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [](){
qCDebug(dcZigbeeNetwork()) << "Factory reset reply finished";
});
} }

View File

@ -168,6 +168,10 @@ int main(int argc, char *argv[])
network->setSerialPortName(parser.value(serialOption)); network->setSerialPortName(parser.value(serialOption));
network->setSerialBaudrate(baudrate); network->setSerialBaudrate(baudrate);
network->setSettingsFileName("/tmp/zigbee.conf"); network->setSettingsFileName("/tmp/zigbee.conf");
network->setExtendedPanId(5);
ZigbeeChannelMask mask;
mask.setChannel(Zigbee::ZigbeeChannel13);
network->setChannelMask(mask);
network->startNetwork(); network->startNetwork();
//Core core(parser.value(serialOption), baudrate, channel); //Core core(parser.value(serialOption), baudrate, channel);