Add group cluster and fix reply handling in NXP backend

pull/10/head
Simon Stürz 2020-11-24 12:45:20 +01:00
parent 66637cc389
commit 0768903b07
9 changed files with 212 additions and 12 deletions

View File

@ -76,8 +76,14 @@ ZigbeeNetworkReply *ZigbeeNetworkNxp::sendRequest(const ZigbeeNetworkRequest &re
{
ZigbeeNetworkReply *reply = createNetworkReply(request);
// Send the request, and keep the reply until transposrt, zigbee trasmission and response arrived
connect(reply, &ZigbeeNetworkReply::finished, this, [this, request](){
m_pendingReplies.remove(request.requestId());
connect(reply, &ZigbeeNetworkReply::finished, this, [this, reply](){
if (!m_pendingReplies.values().contains(reply)) {
qCWarning(dcZigbeeNetwork()) << "Reply finished but not in the pending replies list" << reply;
return;
}
quint8 requestId = m_pendingReplies.key(reply);
m_pendingReplies.remove(requestId);
//qCWarning(dcZigbeeNetwork()) << "#### Removed network reply" << reply << "ID:" << requestId << "Current reply count" << m_pendingReplies.count();
});
// Finish the reply right the way if the network is offline
@ -104,8 +110,8 @@ ZigbeeNetworkReply *ZigbeeNetworkNxp::sendRequest(const ZigbeeNetworkRequest &re
quint8 networkRequestId = interfaceReply->responseData().at(0);
//qCDebug(dcZigbeeNetwork()) << "Request has network SQN" << networkRequestId;
reply->request().setRequestId(networkRequestId);
//qCWarning(dcZigbeeNetwork()) << "#### Insert network reply" << reply << "ID:" << networkRequestId << "Current reply count" << m_pendingReplies.count();
m_pendingReplies.insert(networkRequestId, reply);
// The request has been sent successfully to the device, start the timeout timer now
startWaitingReply(reply);
});
@ -404,6 +410,23 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){
if (state == ZigbeeNode::StateInitialized) {
qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode;
// ZigbeeClusterGroups *groupsCluster = coordinatorNode->getEndpoint(0x01)->inputCluster<ZigbeeClusterGroups>(ZigbeeClusterLibrary::ClusterIdGroups);
// if (!groupsCluster) {
// qCWarning(dcZigbeeNetwork()) << "Failed to get groups cluster from coordinator. The coordinator will not be in default group 0x0000";
// setState(StateRunning);
// setPermitJoining(0);
// return;
// }
// ZigbeeClusterReply *reply = groupsCluster->addGroup(0x0000, "Default");
// connect(reply, &ZigbeeClusterReply::finished, this, [=](){
// if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
// qCWarning(dcZigbeeNetwork()) << "Failed to add coordinator to default group 0x0000. The coordinator will not be in default group 0x0000";
// }
// setState(StateRunning);
// setPermitJoining(0);
// });
setState(StateRunning);
setPermitJoining(0);
return;

View File

@ -17,6 +17,7 @@ SOURCES += \
backends/nxp/zigbeebridgecontrollernxp.cpp \
backends/nxp/zigbeenetworknxp.cpp \
zcl/closures/zigbeeclusterdoorlock.cpp \
zcl/general/zigbeeclustergroups.cpp \
zcl/general/zigbeeclusteridentify.cpp \
zcl/general/zigbeeclusterlevelcontrol.cpp \
zcl/general/zigbeeclusteronoff.cpp \
@ -72,6 +73,7 @@ HEADERS += \
backends/nxp/zigbeebridgecontrollernxp.h \
backends/nxp/zigbeenetworknxp.h \
zcl/closures/zigbeeclusterdoorlock.h \
zcl/general/zigbeeclustergroups.h \
zcl/general/zigbeeclusteridentify.h \
zcl/general/zigbeeclusterlevelcontrol.h \
zcl/general/zigbeeclusteronoff.h \

View File

@ -187,14 +187,14 @@ public:
AlarmMaskGeneralHardwareFault = 0x01,
AlarmMaskGeneralSoftwareFault = 0x02
};
Q_ENUM(AlarmMask)
Q_FLAG(AlarmMask)
Q_DECLARE_FLAGS(AlarmMasks, AlarmMask)
enum DiableLocalConfig {
DiableLocalConfigReset = 0x01,
DiableLocalConfigDeviceConfiguration = 0x02
};
Q_ENUM(DiableLocalConfig)
Q_FLAG(DiableLocalConfig)
Q_DECLARE_FLAGS(DiableLocalConfigs, DiableLocalConfig)
explicit ZigbeeClusterBasic(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
@ -206,7 +206,4 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterBasic::AlarmMasks)
Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterBasic::DiableLocalConfigs)
#endif // ZIGBEECLUSTERBASIC_H

View File

@ -0,0 +1,102 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea-zigbee.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zigbeeclustergroups.h"
#include "loggingcategory.h"
#include <QDataStream>
ZigbeeClusterGroups::ZigbeeClusterGroups(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdGroups, direction, parent)
{
}
ZigbeeClusterReply *ZigbeeClusterGroups::addGroup(quint16 groupId, const QString &groupName)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << groupId << static_cast<quint8>(Zigbee::CharString);
for (int i = 0; i < groupName.length(); i++) {
stream << static_cast<quint8>(groupName.toUtf8().at(i));
}
return executeClusterCommand(ZigbeeClusterGroups::CommandAddGroup, payload);
}
ZigbeeClusterReply *ZigbeeClusterGroups::viewGroup(quint16 groupId)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << groupId;
return executeClusterCommand(ZigbeeClusterGroups::CommandViewGroup, payload);
}
ZigbeeClusterReply *ZigbeeClusterGroups::getGroupMembership(quint8 groupCount, const QList<quint16> &groupList)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << groupCount;
for (int i = 0; i < groupList.length(); i++) {
stream << groupList.at(i);
}
return executeClusterCommand(ZigbeeClusterGroups::CommandGetGroupMembership, payload);
}
ZigbeeClusterReply *ZigbeeClusterGroups::removeGroup(quint16 groupId)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << groupId;
return executeClusterCommand(ZigbeeClusterGroups::CommandRemoveGroup, payload);
}
ZigbeeClusterReply *ZigbeeClusterGroups::removeAllGroups()
{
return executeClusterCommand(ZigbeeClusterGroups::CommandRemoveAllGroups);
}
ZigbeeClusterReply *ZigbeeClusterGroups::addGroupIfIdentifying(quint16 groupId, const QString &groupName)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << groupId << static_cast<quint8>(Zigbee::CharString);
for (int i = 0; i < groupName.length(); i++) {
stream << static_cast<quint8>(groupName.toUtf8().at(i));
}
return executeClusterCommand(ZigbeeClusterGroups::CommandAddGroup, payload);
}
void ZigbeeClusterGroups::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
updateOrAddAttribute(attribute);
}

View File

@ -0,0 +1,72 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea-zigbee.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ZIGBEECLUSTERGROUPS_H
#define ZIGBEECLUSTERGROUPS_H
#include <QObject>
#include "zcl/zigbeecluster.h"
class ZigbeeClusterGroups : public ZigbeeCluster
{
Q_OBJECT
public:
enum Attribute {
// 1 supported, 0 not supported
AttributeNameSupport = 0x0000
};
Q_ENUM(Attribute)
enum Command {
CommandAddGroup = 0x00,
CommandViewGroup = 0x01,
CommandGetGroupMembership = 0x02,
CommandRemoveGroup = 0x03,
CommandRemoveAllGroups = 0x04,
CommandAddGroupIfIdentifying = 0x05
};
Q_ENUM(Command)
explicit ZigbeeClusterGroups(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
ZigbeeClusterReply *addGroup(quint16 groupId, const QString &groupName);
ZigbeeClusterReply *viewGroup(quint16 groupId);
ZigbeeClusterReply *getGroupMembership(quint8 groupCount, const QList<quint16> &groupList);
ZigbeeClusterReply *removeGroup(quint16 groupId);
ZigbeeClusterReply *removeAllGroups();
ZigbeeClusterReply *addGroupIfIdentifying(quint16 groupId, const QString &groupName);
signals:
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
};
#endif // ZIGBEECLUSTERGROUPS_H

View File

@ -611,6 +611,7 @@ void ZigbeeNetwork::setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::Zig
void ZigbeeNetwork::finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error)
{
qCDebug(dcZigbeeNetwork()) << "Finish network reply" << reply << error;
reply->m_error = error;
switch(reply->error()) {
case ZigbeeNetworkReply::ErrorNoError:

View File

@ -505,7 +505,7 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster)
if (m_requestRetry < 3) {
m_requestRetry++;
qCDebug(dcZigbeeNode()) << "Retry to read manufacturer name from" << this << basicCluster << m_requestRetry << "/" << "3 attempts.";
readManufacturerName(basicCluster);
QTimer::singleShot(1000, this, [=](){readManufacturerName(basicCluster);});
} else {
qCWarning(dcZigbeeNode()) << "Failed to read manufacturer name from" << this << basicCluster << "after 3 attempts. Giving up and continue...";
m_requestRetry = 0;
@ -564,7 +564,7 @@ void ZigbeeNode::readModelIdentifier(ZigbeeClusterBasic *basicCluster)
if (m_requestRetry < 3) {
m_requestRetry++;
qCDebug(dcZigbeeNode()) << "Retry to read model identifier from" << this << basicCluster << m_requestRetry << "/" << "3 attempts.";
readModelIdentifier(basicCluster);
QTimer::singleShot(1000, this, [=](){readModelIdentifier(basicCluster);});
} else {
qCWarning(dcZigbeeNode()) << "Failed to read model identifier from" << this << basicCluster << "after 3 attempts. Giving up and continue...";
m_requestRetry = 0;
@ -605,11 +605,11 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster)
if (m_requestRetry < 3) {
m_requestRetry++;
qCDebug(dcZigbeeNode()) << "Retry to read model identifier from" << this << basicCluster << m_requestRetry << "/" << "3 attempts.";
readModelIdentifier(basicCluster);
QTimer::singleShot(1000, this, [=](){readSoftwareBuildId(basicCluster);});
} else {
qCWarning(dcZigbeeNode()) << "Failed to read model identifier from" << this << basicCluster << "after 3 attempts. Giving up and continue...";
m_requestRetry = 0;
readSoftwareBuildId(basicCluster);
setState(StateInitialized);
}
return;
}

View File

@ -175,6 +175,8 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(ZigbeeClusterLibrary::ClusterId
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
case ZigbeeClusterLibrary::ClusterIdLevelControl:
return new ZigbeeClusterLevelControl(m_network, m_node, this, direction, this);
case ZigbeeClusterLibrary::ClusterIdGroups:
return new ZigbeeClusterGroups(m_network, m_node, this, direction, this);
// Measurement
case ZigbeeClusterLibrary::ClusterIdIlluminanceMeasurement:

View File

@ -42,6 +42,7 @@
#include "zcl/general/zigbeeclusteridentify.h"
#include "zcl/general/zigbeeclusterlevelcontrol.h"
#include "zcl/general/zigbeeclusterpowerconfiguration.h"
#include "zcl/general/zigbeeclustergroups.h"
#include "zcl/closures/zigbeeclusterdoorlock.h"