Add more node data and improve serial parsing

This commit is contained in:
Simon Stürz 2018-01-17 16:39:06 +01:00
parent bbc9cb0ba1
commit 0255dfd792
9 changed files with 855 additions and 153 deletions

View File

@ -46,6 +46,10 @@ public:
MessageTypeAuthenticateDeviceResponse = 0x8028,
MessageTypeOutOfBandCommisioningDataRequest = 0x0029,
MessageTypeOutOfBandCommisioningDataResponse = 0x8029,
MessageTypeUserDescriptorSet = 0x002B,
MessageTypeUserDescriptorNotify = 0x802B,
MessageTypeUserDescriptorRequest = 0x002C,
MessageTypeUserDescriptorResponse = 0x802C,
MessageTypeReset = 0x0011,
MessageTypeErasePersistentData = 0x0012,
@ -56,6 +60,8 @@ public:
MessageTypeBindResponse = 0x8030,
MessageTypeUnbind = 0x0031,
MessageTypeUnbindResponse = 0x8031,
MessageTypeComplexDescriptorRequest = 0x0034,
MessageTypeComplexDescriptorResponse = 0x8034,
MessageTypeNetworkAdressRequest = 0x0040,
MessageTypeNetworkAdressResponse = 0x8040,
@ -400,6 +406,25 @@ public:
};
Q_ENUM(DataType)
enum Manufacturer {
// RF4CE
PanasonicRF4CE = 0x0001,
SonyRF4CE = 0x0002,
SamsungRF4CE = 0x0003,
PhilipsRF4CE = 0x0004,
FreescaleRF4CE = 0x0005,
OkiSemiRF4CE = 0x0006,
TiRF4CE = 0x0007,
// Manufacturer Codes for non RF4CE devices
Cirronet = 0x1000,
Chipcon = 0x1001,
Ember = 0x1003,
};
Q_ENUM(Manufacturer)
///* Manufacturer Codes */
///* Codes less than 0x1000 were issued for RF4CE */
//#define ZBEE_MFG_CODE_PANASONIC_RF4CE 0x0001
@ -412,7 +437,7 @@ public:
///* Manufacturer Codes for non RF4CE devices */
//#define ZBEE_MFG_CODE_CIRRONET 0x1000
//#define ZBEE_MFG_CODE_CHIPCON 0x1001
//#define ZBEE_MFG_CODE_CHIPCON
//#define ZBEE_MFG_CODE_EMBER 0x1002
//#define ZBEE_MFG_CODE_NTS 0x1003
//#define ZBEE_MFG_CODE_FREESCALE 0x1004

View File

@ -7,7 +7,8 @@
#include <QSettings>
ZigbeeNetworkManager::ZigbeeNetworkManager(const int &channel, const QString &serialPort, QObject *parent) :
ZigbeeNode(new ZigbeeBridgeController(serialPort, parent), parent)
ZigbeeNode(new ZigbeeBridgeController(serialPort, parent), parent),
m_serialPort(serialPort)
{
connect(controller(), &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived);
@ -20,7 +21,8 @@ ZigbeeNetworkManager::ZigbeeNetworkManager(const int &channel, const QString &se
QSettings settings;
settings.beginGroup("Network");
m_extendedPanId = static_cast<quint64>(settings.value("panId", 0).toUInt());
m_extendedPanId = static_cast<quint64>(settings.value("panId", 0).toLongLong());
qCDebug(dcZigbee()) << "Loading saved pan id" << m_extendedPanId;
if (m_extendedPanId == 0) {
m_extendedPanId = generateRandomPanId();
settings.setValue("panId", m_extendedPanId);
@ -39,24 +41,19 @@ ZigbeeNetworkManager::ZigbeeNetworkManager(const int &channel, const QString &se
qCDebug(dcZigbee()) << "Using channel" << channel << "for the zigbee network.";
}
// // Call init methods
// erasePersistentData();
// //resetController();
// getVersion();
// setExtendedPanId(m_extendedPanId);
// setChannelMask(channelMask);
// setDeviceType(NodeTypeCoordinator);
// startNetwork();
loadNetwork();
resetController();
getVersion();
init();
}
bool ZigbeeNetworkManager::isAvailable() const
{
if (m_controller){
return m_controller->available();
}
// //startScan();
// //getPermitJoiningStatus();
// enableWhitelist();
// permitJoining();
// //getPermitJoiningStatus();
// //startScan();
// initiateTouchLink();
return false;
}
QString ZigbeeNetworkManager::controllerVersion() const
@ -64,6 +61,11 @@ QString ZigbeeNetworkManager::controllerVersion() const
return m_controllerVersion;
}
QString ZigbeeNetworkManager::serialPort() const
{
return m_serialPort;
}
QList<ZigbeeNode *> ZigbeeNetworkManager::nodeList() const
{
return m_nodeList;
@ -102,28 +104,8 @@ void ZigbeeNetworkManager::parseNetworkFormed(const QByteArray &data)
networkStatusString = "unknown";
}
// Parse short network address
quint16 shortAddress = data.at(1);
shortAddress <<= 8;
shortAddress |= data.at(2);
// Parse extended network address
quint64 extendedAddress = data.at(3);
extendedAddress <<= 8;
extendedAddress |= data.at(4);
extendedAddress <<= 8;
extendedAddress |= data.at(5);
extendedAddress <<= 8;
extendedAddress |= data.at(6);
extendedAddress <<= 8;
extendedAddress |= data.at(7);
extendedAddress <<= 8;
extendedAddress |= data.at(8);
extendedAddress <<= 8;
extendedAddress |= data.at(9);
extendedAddress <<= 8;
extendedAddress |= data.at(10);
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(data.mid(1, 2));
quint64 extendedAddress = ZigbeeUtils::convertByteArrayToUint64(data.mid(3, 8));
// Parse network channel
quint8 channel = static_cast<quint8>(data.at(11));
@ -219,7 +201,7 @@ void ZigbeeNetworkManager::setExtendedPanId(const quint64 &panId)
stream << panId;
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetExtendetPanId, data));
request.setDescription("Set extended PAN ID " + QString::number(panId) + " " + ZigbeeUtils::convertUint64ToHexString(panId));
request.setDescription("Set extended PAN id " + QString::number(panId) + " " + ZigbeeUtils::convertUint64ToHexString(panId));
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetExtendedPanIdFinished);
@ -227,6 +209,10 @@ void ZigbeeNetworkManager::setExtendedPanId(const quint64 &panId)
void ZigbeeNetworkManager::setChannelMask(const quint32 &channelMask)
{
// Note: 10 < value < 27 -> using sinle channel value
// 0x07fff800 select from all channels 11 - 26
// 0x2108800 primary zigbee light link channels 11, 15, 20, 25
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << channelMask;
@ -285,12 +271,13 @@ void ZigbeeNetworkManager::startScan()
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onStartScanFinished);
}
void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 advertisingIntervall)
void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 advertisingIntervall, bool tcSignificance)
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << targetAddress;
stream << advertisingIntervall;
stream << static_cast<quint8>(tcSignificance);
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePermitJoiningRequest, data));
request.setDescription("Permit joining request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress) + " for " + QString::number(advertisingIntervall) + "[s]");
@ -299,6 +286,23 @@ void ZigbeeNetworkManager::permitJoining(quint16 targetAddress, const quint8 adv
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onPermitJoiningFinished);
}
void ZigbeeNetworkManager::requestLinkQuality()
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << shortAddress();
stream << static_cast<quint8>(0);
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse);
request.setDescription("Request link quality request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress()));
request.setTimoutIntervall(5000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestLinkQualityFinished);
}
void ZigbeeNetworkManager::getPermitJoiningStatus()
{
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeGetPermitJoining));
@ -337,25 +341,40 @@ void ZigbeeNetworkManager::touchLinkFactoryReset()
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onTouchLinkFactoryResetFinished);
}
void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile)
void ZigbeeNetworkManager::networkAddressRequest(quint16 targetAddress, quint64 extendedAddress)
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << targetAddress;
stream << extendedAddress;
stream << static_cast<quint8>(1);
stream << static_cast<quint8>(0);
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNetworkAdressRequest, data));
request.setDescription("Network address request on " + ZigbeeUtils::convertUint16ToHexString(targetAddress));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNetworkAdressResponse);
request.setTimoutIntervall(1000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onNetworkAddressRequestFinished);
}
void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile)
{
// TargetAddress profile InputClusterCount InputClusterList OutputClusterCount OutputClusterList
Q_UNUSED(profile)
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << shortAddress;
stream << static_cast<quint16>(profile);
// TODO: check what this does
// // Input clusters
// stream << static_cast<quint8>(7);
// stream << static_cast<quint16>(Zigbee::ClusterIdBasic);
// stream << static_cast<quint16>(Zigbee::ClusterIdIdentify);
// stream << static_cast<quint16>(Zigbee::ClusterIdGroups);
// stream << static_cast<quint16>(Zigbee::ClusterIdScenes);
// stream << static_cast<quint16>(Zigbee::ClusterIdOnOff);
// stream << static_cast<quint16>(Zigbee::ClusterIdLevelControl);
// stream << static_cast<quint16>(Zigbee::ClusterIdColorControl);
stream << static_cast<quint16>(0xFFFF);
stream << static_cast<quint8>(0);
stream << static_cast<quint16>(0);
stream << static_cast<quint8>(0);
stream << static_cast<quint16>(0);
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeMatchDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeMatchDescriptorResponse);
@ -366,6 +385,50 @@ void ZigbeeNetworkManager::requestMatchDescriptor(const quint16 &shortAddress, c
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onRequestMatchDescriptorFinished);
}
void ZigbeeNetworkManager::setInitialSecurity(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key)
{
// Note: calls ZPS_vAplSecSetInitialSecurityState
// Key state:
// ZPS_ZDO_PRECONFIGURED_LINK_KEY = 3
// This key will be used to encrypt the network key. This is the master or manufacturer key
// ZPS_ZDO_ZLL_LINK_KEY = 4
// This key will be generated by the trust center.
// Key Type:
// ZPS_APS_UNIQUE_LINK_KEY =
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << keyState;
stream << keySequence;
stream << keyType;
stream << QByteArray::fromHex(key.toUtf8());
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSetSecurity, data));
request.setDescription("Set security configuration");
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onSetSecurityFinished);
}
void ZigbeeNetworkManager::authenticateDevice(const ZigbeeAddress &ieeeAddress)
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << ieeeAddress.toUInt64();
stream << QByteArray::fromHex("5A6967426565416C6C69616E63653039");
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeAuthenticateDeviceRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeAuthenticateDeviceResponse);
request.setDescription(QString("Authenticate device %1").arg(ieeeAddress.toString()));
request.setTimoutIntervall(5000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onAuthenticateDeviceFinished);
}
void ZigbeeNetworkManager::onResetControllerFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
@ -409,15 +472,9 @@ void ZigbeeNetworkManager::onGetVersionFinished()
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
// Parse major version
quint16 majorVersion = reply->additionalMessage().data().at(0);
majorVersion <<= 8;
majorVersion |= reply->additionalMessage().data().at(1);
// Parse minor version
quint16 minorVersion = reply->additionalMessage().data().at(2);
minorVersion <<= 8;
minorVersion |= reply->additionalMessage().data().at(3);
// Parse version
quint16 majorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(0, 2));
quint16 minorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(2, 2));
m_controllerVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
qCDebug(dcZigbee()) << "Version:" << m_controllerVersion;
@ -540,6 +597,83 @@ void ZigbeeNetworkManager::onRequestMatchDescriptorFinished()
qCDebug(dcZigbeeController()) << reply->additionalMessage();
}
void ZigbeeNetworkManager::onSetSecurityFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onNetworkAddressRequestFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
quint8 statusCode = static_cast<quint8>(reply->additionalMessage().data().at(1));
quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(2, 8));
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(10, 2));
quint8 deviceCount = static_cast<quint8>(reply->additionalMessage().data().at(12));
quint8 startIndex = static_cast<quint8>(reply->additionalMessage().data().at(13));
qCDebug(dcZigbee()) << "Network address response:";
qCDebug(dcZigbee()) << " SQN:" << sequenceNumber;
qCDebug(dcZigbee()) << " Status:" << statusCode;
qCDebug(dcZigbee()) << " Address:" << shortAddress << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbee()) << " Deice count:" << deviceCount;
qCDebug(dcZigbee()) << " Start index:" << startIndex;
}
void ZigbeeNetworkManager::onAuthenticateDeviceFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint64 gatewayIeeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(0, 8));
QString encryptedKey = reply->additionalMessage().data().mid(8, 16).toHex();
QByteArray mic = reply->additionalMessage().data().mid(24, 4);
quint64 initiatorIeeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(28, 8));
quint8 activeKeySequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(36));
quint8 channel = static_cast<quint8>(reply->additionalMessage().data().at(37));
quint16 shortPan = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(38, 2));
quint64 extendedPanId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(40, 8));
qCDebug(dcZigbee()) << "Authentication response:";
qCDebug(dcZigbee()) << " Gateways address:" << ZigbeeAddress(gatewayIeeeAddress);
qCDebug(dcZigbee()) << " Key:" << encryptedKey;
qCDebug(dcZigbee()) << " MIC:" << mic.toHex();
qCDebug(dcZigbee()) << " Initiator address:" << ZigbeeAddress(initiatorIeeeAddress);
qCDebug(dcZigbee()) << " Active key sequence number:" << activeKeySequenceNumber;
qCDebug(dcZigbee()) << " Channel:" << channel;
qCDebug(dcZigbee()) << " Short PAN ID:" << ZigbeeUtils::convertUint16ToHexString(shortPan);
qCDebug(dcZigbee()) << " Extended PAN ID:" << extendedPanId << ZigbeeUtils::convertUint64ToHexString(extendedPanId);
}
void ZigbeeNetworkManager::onEnableWhitelistFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
@ -579,6 +713,68 @@ void ZigbeeNetworkManager::onTouchLinkFactoryResetFinished()
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNetworkManager::onRequestLinkQualityFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
quint8 statusCode = static_cast<quint8>(reply->additionalMessage().data().at(1));
quint8 neighborTableEntries = static_cast<quint8>(reply->additionalMessage().data().at(2));
quint8 neighborTableListCount = static_cast<quint8>(reply->additionalMessage().data().at(3));
quint8 startIndex = static_cast<quint8>(reply->additionalMessage().data().at(4));
qCDebug(dcZigbee()) << "LQI response:";
qCDebug(dcZigbee()) << " SQN:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(statusCode);
qCDebug(dcZigbee()) << " Neighbor table entries:" << neighborTableEntries;
qCDebug(dcZigbee()) << " Neighbor table list count:" << neighborTableListCount;
qCDebug(dcZigbee()) << " Start index:" << startIndex;
int offset = 5;
// Note: according to docs, if the table has no neigbors the list will be empty
if (neighborTableEntries == 0) {
qCDebug(dcZigbee()) << " There are no neigbors";
return;
}
for (int i = startIndex; i < neighborTableListCount; i++) {
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(offset, 2));
quint64 panId = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(offset + 2, 8));
quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(reply->additionalMessage().data().mid(offset + 10, 8));
quint8 depth = static_cast<quint8>(reply->additionalMessage().data().at(offset + 18));
quint8 linkQuality = static_cast<quint8>(reply->additionalMessage().data().at(offset + 19));
quint8 bitMap = static_cast<quint8>(reply->additionalMessage().data().at(offset + 20));
offset += 21;
qCDebug(dcZigbee()) << " Neighbor:" << i;
qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbee()) << " PAN id:" << panId;
qCDebug(dcZigbee()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbee()) << " Depth:" << depth;
qCDebug(dcZigbee()) << " Link quality:" << linkQuality;
qCDebug(dcZigbee()) << " BitMap:" << ZigbeeUtils::convertByteToHexString(bitMap);
foreach (ZigbeeNode *node, m_nodeList) {
if (node->extendedAddress() == ZigbeeAddress(ieeeAddress)) {
node->setShortAddress(shortAddress);
}
}
}
}
void ZigbeeNetworkManager::processLoggingMessage(const ZigbeeInterfaceMessage &message)
{
quint8 logLevel = static_cast<quint8>(message.data().at(0));
@ -658,10 +854,10 @@ void ZigbeeNetworkManager::processNodeClusterList(const ZigbeeInterfaceMessage &
QByteArray clusterListData = message.data().right(message.data().count() - 3);
for (int i = 0; i < clusterListData.count(); i+=2) {
for (int i = 0; i < clusterListData.count(); i += 2) {
quint16 clusterId = clusterListData.at(i);
clusterId <<= 8;
clusterId |= clusterListData .at(i+1);
clusterId |= clusterListData .at(i + 1);
qCDebug(dcZigbeeController()) << " Cluster ID:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
}
@ -671,14 +867,8 @@ void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage
{
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
quint16 profileId = static_cast<quint8>(message.data().at(1));
profileId <<= 8;
profileId |= static_cast<quint8>(message.data().at(2));
quint16 clusterId = static_cast<quint8>(message.data().at(3));
clusterId <<= 8;
clusterId |= static_cast<quint8>(message.data().at(4));
quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2));
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2));
qCDebug(dcZigbeeController()) << "Node attribute list received:";
qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint;
@ -687,11 +877,8 @@ void ZigbeeNetworkManager::processNodeAttributeList(const ZigbeeInterfaceMessage
QByteArray attributeListData = message.data().right(message.data().count() - 5);
for (int i = 0; i < attributeListData.count(); i+=2) {
quint16 attribute = attributeListData.at(i);
attribute <<= 8;
attribute |= attributeListData .at(i+1);
for (int i = 0; i < attributeListData.count(); i += 2) {
quint16 attribute = ZigbeeUtils::convertByteArrayToUint16(attributeListData.mid(i, 2));
qCDebug(dcZigbeeController()) << " Attribute:" << ZigbeeUtils::convertUint16ToHexString(attribute);
}
}
@ -700,13 +887,8 @@ void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage
{
quint8 sourceEndpoint = static_cast<quint8>(message.data().at(0));
quint16 profileId = static_cast<quint8>(message.data().at(1));
profileId <<= 8;
profileId |= static_cast<quint8>(message.data().at(2));
quint16 clusterId = static_cast<quint8>(message.data().at(3));
clusterId <<= 8;
clusterId |= static_cast<quint8>(message.data().at(4));
quint16 profileId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2));
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(3, 2));
qCDebug(dcZigbeeController()) << "Node command list received:";
qCDebug(dcZigbeeController()) << " Souce endpoint:" << sourceEndpoint;
@ -723,27 +905,10 @@ void ZigbeeNetworkManager::processNodeCommandIdList(const ZigbeeInterfaceMessage
void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &message)
{
quint16 shortAddress = message.data().at(0);
shortAddress <<= 8;
shortAddress |= message.data().at(1);
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2));
quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(message.data().mid(2, 8));
quint64 ieeeAddress = message.data().at(2);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(3);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(4);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(5);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(6);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(7);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(8);
ieeeAddress <<= 8;
ieeeAddress |= message.data().at(9);
quint8 macCapability = message.data().at(10);
quint8 macCapability = static_cast<quint8>(message.data().at(10));
qCDebug(dcZigbee()) << "Device announced:";
qCDebug(dcZigbee()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
@ -764,28 +929,14 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message)
{
quint8 sequenceNumber = static_cast<quint8>(message.data().at(0));
quint16 sourceAddress = message.data().at(1);
sourceAddress <<= 8;
sourceAddress |= message.data().at(2);
quint16 sourceAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(1, 2));
quint8 endPoint = static_cast<quint8>(message.data().at(3));
quint16 clusterId = message.data().at(4);
clusterId <<= 8;
clusterId |= message.data().at(5);
quint16 attributeId = message.data().at(6);
attributeId <<= 8;
attributeId |= message.data().at(7);
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(4, 2));
quint16 attributeId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(6, 2));
quint8 attributStatus = static_cast<quint8>(message.data().at(8));
quint8 attributDataType = static_cast<quint8>(message.data().at(9));
quint16 attributeSize = message.data().at(10);
attributeSize <<= 8;
attributeSize |= message.data().at(11);
quint16 attributeSize = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(10, 2));
QByteArray data = message.data().mid(12);
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
@ -805,7 +956,7 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
qCDebug(dcZigbee()) << " Data(converted)" << QString::fromUtf8(data);
break;
case Zigbee::Bool:
qCDebug(dcZigbee()) << " Data(converted)" << QVariant(data.toInt()).toBool();
qCDebug(dcZigbee()) << " Data(converted)" << QVariant(data).toBool();
break;
default:
break;
@ -817,17 +968,37 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message)
{
quint16 shortAddress = message.data().at(0);
shortAddress <<= 8;
shortAddress |= message.data().at(1);
quint8 rejoining = message.data().at(2);
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2));
quint8 rejoining = static_cast<quint8>(message.data().at(2));
qCDebug(dcZigbee()) << "Node leaving:" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << rejoining;
// TODO: remove node
}
void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessage &message)
{
if (message.data().isEmpty())
return;
quint8 status = static_cast<quint8>(message.data().at(0));
switch (status) {
case 0:
qCDebug(dcZigbee()) << "Restart provisioned: start up";
break;
case 2:
qCDebug(dcZigbee()) << "Restart provisioned: NFN start";
break;
case 6:
qCDebug(dcZigbee()) << "Restart provisioned: running";
break;
default:
qCDebug(dcZigbee()) << "Restart provisioned: unknown";
break;
}
}
void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message)
{
switch (message.messageType()) {
@ -855,6 +1026,12 @@ void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &messa
case Zigbee::MessageTypeLeaveIndication:
processLeaveIndication(message);
break;
case Zigbee::MessageTypeNetworkJoinedFormed:
parseNetworkFormed(message.data());
break;
case Zigbee::MessageTypeRestartProvisioned:
processRestartProvisioned(message);
break;
default:
qCDebug(dcZigbeeController()) << "Message received:" << message;
break;

View File

@ -13,9 +13,13 @@ class ZigbeeNetworkManager : public ZigbeeNode
public:
explicit ZigbeeNetworkManager(const int &channel = 0, const QString &serialPort = "/dev/ttyS0", QObject *parent = nullptr);
bool isAvailable() const;
QString controllerVersion() const;
QString serialPort() const;
QList<ZigbeeNode *> nodeList() const;
quint64 extendedPanId() const;
bool networkRunning() const;
// Controller methods
@ -24,12 +28,14 @@ public:
void sendDataManagerAvailableResponse();
void getVersion();
void setExtendedPanId(const quint64 &panId);
void setChannelMask(const quint32 &channelMask);
void setChannelMask(const quint32 &channelMask = 0x07fff800);
void setDeviceType(const NodeType &deviceType);
void startNetwork();
void startScan();
void permitJoining(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 254);
void permitJoining(quint16 targetAddress = 0xfffc, const quint8 advertisingIntervall = 180, bool tcSignificance = false);
void requestLinkQuality();
void getPermitJoiningStatus();
void enableWhitelist();
@ -37,10 +43,17 @@ public:
void initiateTouchLink();
void touchLinkFactoryReset();
void networkAddressRequest(quint16 targetAddress, quint64 extendedAddress);
void requestMatchDescriptor(const quint16 &shortAddress, const Zigbee::ZigbeeProfile &profile);
void setInitialSecurity(quint8 keyState, quint8 keySequence, quint8 keyType, const QString &key);
void authenticateDevice(const ZigbeeAddress &ieeeAddress);
private:
ZigbeeBridgeController *m_controller = nullptr;
QString m_serialPort;
QString m_controllerVersion;
quint64 m_extendedPanId = 0;
@ -76,8 +89,12 @@ private slots:
void onInitiateTouchLinkFinished();
void onTouchLinkFactoryResetFinished();
void onRequestLinkQualityFinished();
void onRequestMatchDescriptorFinished();
void onSetSecurityFinished();
void onNetworkAddressRequestFinished();
void onAuthenticateDeviceFinished();
// Process controller notifications/messages
void processLoggingMessage(const ZigbeeInterfaceMessage &message);
@ -88,6 +105,7 @@ private slots:
void processDeviceAnnounce(const ZigbeeInterfaceMessage &message);
void processAttributeReport(const ZigbeeInterfaceMessage &message);
void processLeaveIndication(const ZigbeeInterfaceMessage &message);
void processRestartProvisioned(const ZigbeeInterfaceMessage &message);
};
#endif // ZIGBEEMANAGER_H

View File

@ -14,11 +14,56 @@ ZigbeeAddress ZigbeeNode::extendedAddress() const
return m_extendedAddress;
}
int ZigbeeNode::endPoint() const
{
return m_endPoint;
}
ZigbeeNode::NodeType ZigbeeNode::nodeType() const
{
return m_nodeType;
}
ZigbeeNode::FrequencyBand ZigbeeNode::frequencyBand() const
{
return m_frequencyBand;
}
ZigbeeNode::Relationship ZigbeeNode::relationShip() const
{
return m_relationShip;
}
Zigbee::ZigbeeProfile ZigbeeNode::profile() const
{
return m_profile;
}
quint16 ZigbeeNode::manufacturerCode() const
{
return m_manufacturerCode;
}
ZigbeeNode::PowerMode ZigbeeNode::powerMode() const
{
return m_powerMode;
}
ZigbeeNode::PowerSource ZigbeeNode::powerSource() const
{
return m_powerSource;
}
QList<ZigbeeNode::PowerSource> ZigbeeNode::availablePowerSources() const
{
return m_availablePowerSources;
}
ZigbeeNode::PowerLevel ZigbeeNode::powerLevel() const
{
return m_powerLevel;
}
void ZigbeeNode::init()
{
requestNodeDescription();
@ -26,6 +71,40 @@ void ZigbeeNode::init()
requestPowerDescriptor();
}
void ZigbeeNode::identify()
{
// QByteArray data;
// QDataStream stream(&data, QIODevice::WriteOnly);
// stream << m_shortAddress;
// stream << static_cast<quint8>(0);
// ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeManagementLqiRequest, data));
// request.setExpectedAdditionalMessageType(Zigbee::MessageTypeManagementLqiResponse);
// request.setDescription("Node link quality request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
// request.setTimoutIntervall(10000);
// ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
// connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestLinkQuality);
}
void ZigbeeNode::toggle(int addressMode)
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << static_cast<quint8>(addressMode); // adress mode
stream << m_shortAddress;
stream << static_cast<quint8>(1); // source endpoint
stream << static_cast<quint8>(1); // destination endpoint
stream << static_cast<quint8>(2); // command toggle
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeCluserOnOff, data));
request.setDescription("Toggle request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onToggleFinished);
}
void ZigbeeNode::requestNodeDescription()
{
QByteArray data;
@ -35,7 +114,7 @@ void ZigbeeNode::requestNodeDescription()
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse);
request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
request.setTimoutIntervall(10000);
request.setTimoutIntervall(5000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestNodeDescriptionFinished);
@ -51,7 +130,7 @@ void ZigbeeNode::requestSimpleNodeDescription()
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSimpleDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeSimpleDescriptorResponse);
request.setDescription("Simple node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
request.setTimoutIntervall(10000);
request.setTimoutIntervall(5000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestSimpleNodeDescriptionFinished);
@ -66,12 +145,28 @@ void ZigbeeNode::requestPowerDescriptor()
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypePowerDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypePowerDescriptorResponse);
request.setDescription("Node power descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
request.setTimoutIntervall(10000);
request.setTimoutIntervall(5000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestPowerDescriptorFinished);
}
void ZigbeeNode::requestUserDescriptor()
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << m_shortAddress;
stream << static_cast<quint16>(0);
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeUserDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeUserDescriptorResponse);
request.setDescription("Node user descriptor request for " + ZigbeeUtils::convertUint16ToHexString(m_shortAddress));
request.setTimoutIntervall(5000);
ZigbeeInterfaceReply *reply = controller()->sendRequest(request);
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNode::onRequestUserDescriptorFinished);
}
ZigbeeNode::ZigbeeNode(ZigbeeBridgeController *controller, QObject *parent) :
QObject(parent),
m_controller(controller)
@ -137,20 +232,86 @@ void ZigbeeNode::onRequestNodeDescriptionFinished()
bitField <<= 8;
bitField |= reply->additionalMessage().data().at(16);
// TODO: find node for short address and set data
// Set node data
m_manufacturerCode = manufacturerCode;
m_maximalRxSize = maximalRxSize;
m_maximalTxSize = maximalTxSize;
// Parse server mask
m_isPrimaryTrustCenter = ((serverMask >> 0) & 0x0001);
m_isBackupTrustCenter = ((serverMask >> 1) & 0x0001);
m_isPrimaryBindingCache = ((serverMask >> 2) & 0x0001);
m_isBackupBindingCache = ((serverMask >> 3) & 0x0001);
m_isPrimaryDiscoveryCache = ((serverMask >> 4) & 0x0001);
m_isBackupDiscoveryCache = ((serverMask >> 5) & 0x0001);
m_isNetworkManager = ((serverMask >> 6) & 0x0001);
// Parse desciptor flag
bool extendedActiveEndpointListAvailable = ((descriptorFlag >> 0) & 0x01);
bool extendedSimpleDescriptorListAvailable = ((descriptorFlag >> 1) & 0x01);
// Parse MAC capabilities
m_receiverOnWhenIdle = ((macFlags >> 3) & 0x01);
m_securityCapability = ((macFlags >> 6) & 0x01);
// Parse bit field
bool isCoordinator = ((bitField >> 0) & 0x0001);
bool isRouter = ((bitField >> 1) & 0x0001);
bool isEndDevice = ((bitField >> 2) & 0x0001);
bool complexDescriptorAvailable = ((bitField >> 3) & 0x0001);
bool userDescriptorAvailable = ((bitField >> 4) & 0x0001);
if (isCoordinator && !isRouter && !isEndDevice) {
m_nodeType = NodeTypeCoordinator;
} else if (!isCoordinator && isRouter && !isEndDevice) {
m_nodeType = NodeTypeRouter;
} else if (!isCoordinator && !isRouter && isEndDevice) {
m_nodeType = NodeTypeEndDevice;
} else {
if (m_isNetworkManager) {
m_nodeType = NodeTypeCoordinator;
} else {
m_nodeType = NodeTypeEndDevice;
}
}
// Note: Frequency always 2,4 GHz
qCDebug(dcZigbee()) << "Node descriptor:";
qCDebug(dcZigbee()) << " Node type:" << m_nodeType;
qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
qCDebug(dcZigbee()) << " Short address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbee()) << " Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode);
qCDebug(dcZigbee()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(maximalRxSize);
qCDebug(dcZigbee()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(maximalTxSize);
qCDebug(dcZigbee()) << " Server makk:" << ZigbeeUtils::convertUint16ToHexString(serverMask);
qCDebug(dcZigbee()) << " Maximum Rx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximalRxSize);
qCDebug(dcZigbee()) << " Maximum Tx size:" << ZigbeeUtils::convertUint16ToHexString(m_maximalTxSize);
qCDebug(dcZigbee()) << " Server mask:" << ZigbeeUtils::convertUint16ToHexString(serverMask);
qCDebug(dcZigbee()) << " Primary Trust center:" << m_isPrimaryTrustCenter;
qCDebug(dcZigbee()) << " Backup Trust center:" << m_isBackupTrustCenter;
qCDebug(dcZigbee()) << " Primary Binding cache:" << m_isPrimaryBindingCache;
qCDebug(dcZigbee()) << " Backup Binding cache:" << m_isBackupBindingCache;
qCDebug(dcZigbee()) << " Primary Discovery cache:" << m_isPrimaryDiscoveryCache;
qCDebug(dcZigbee()) << " Backup Discovery cache:" << m_isBackupDiscoveryCache;
qCDebug(dcZigbee()) << " Network Manager:" << m_isNetworkManager;
qCDebug(dcZigbee()) << " Descriptor flag:" << ZigbeeUtils::convertByteToHexString(descriptorFlag);
qCDebug(dcZigbee()) << " Extended active endpoint list available:" << extendedActiveEndpointListAvailable;
qCDebug(dcZigbee()) << " Extended simple descriptor list available:" << extendedSimpleDescriptorListAvailable;
qCDebug(dcZigbee()) << " MAC flags:" << ZigbeeUtils::convertByteToHexString(macFlags);
qCDebug(dcZigbee()) << " Receiver on when idle:" << m_receiverOnWhenIdle;
qCDebug(dcZigbee()) << " Security capability:" << m_securityCapability;
qCDebug(dcZigbee()) << " Maximum buffer size:" << ZigbeeUtils::convertByteToHexString(maxBufferSize);
qCDebug(dcZigbee()) << " Bit field:" << ZigbeeUtils::convertUint16ToHexString(bitField);
qCDebug(dcZigbee()) << " Is coordinator:" << isCoordinator;
qCDebug(dcZigbee()) << " Is router:" << isRouter;
qCDebug(dcZigbee()) << " Is end device:" << isEndDevice;
qCDebug(dcZigbee()) << " Complex desciptor available:" << complexDescriptorAvailable;
qCDebug(dcZigbee()) << " User desciptor available:" << userDescriptorAvailable;
if (userDescriptorAvailable) {
requestUserDescriptor();
}
}
void ZigbeeNode::onRequestSimpleNodeDescriptionFinished()
@ -174,6 +335,12 @@ void ZigbeeNode::onRequestSimpleNodeDescriptionFinished()
nwkAddress |= reply->additionalMessage().data().at(3);
quint8 length = static_cast<quint8>(reply->additionalMessage().data().at(4));
if (length == 0) {
qCWarning(dcZigbee()) << "Length 0";
return;
}
quint8 endPoint = static_cast<quint8>(reply->additionalMessage().data().at(5));
quint16 profileId = reply->additionalMessage().data().at(6);
@ -248,14 +415,128 @@ void ZigbeeNode::onRequestPowerDescriptorFinished()
bitField <<= 8;
bitField |= reply->additionalMessage().data().at(3);
// Bit 0 - 3 Power mode
// 0000: Receiver configured according to “Receiver on when idle” MAC flag in the Node Descriptor
// 0001: Receiver switched on periodically
// 0010: Receiver switched on when stimulated, e.g. by pressing a button
if (!ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
m_powerMode = PowerModeAlwaysOn;
} else if (ZigbeeUtils::checkBitUint16(bitField, 0) && !ZigbeeUtils::checkBitUint16(bitField, 1)) {
m_powerMode = PowerModeOnPeriodically;
} else if (!ZigbeeUtils::checkBitUint16(bitField, 0) && ZigbeeUtils::checkBitUint16(bitField, 1)) {
m_powerMode = PowerModeOnWhenStimulated;
}
// Bit 4 - 7 Available power sources
// Bit 0: Permanent mains supply
// Bit 1: Rechargeable battery
// Bit 2: Disposable battery
// Bit 4: Reserved
if (ZigbeeUtils::checkBitUint16(bitField, 4)) {
m_availablePowerSources.append(PowerSourcePermanentMainSupply);
} else if (ZigbeeUtils::checkBitUint16(bitField, 5)) {
m_availablePowerSources.append(PowerSourceRecharchableBattery);
} else if (ZigbeeUtils::checkBitUint16(bitField, 6)) {
m_availablePowerSources.append(PowerSourceDisposableBattery);
}
// Bit 8 - 11 Active source: according to the same schema as available power sources
if (ZigbeeUtils::checkBitUint16(bitField, 8)) {
m_powerSource = PowerSourcePermanentMainSupply;
} else if (ZigbeeUtils::checkBitUint16(bitField, 9)) {
m_powerSource = PowerSourceRecharchableBattery;
} else if (ZigbeeUtils::checkBitUint16(bitField, 10)) {
m_powerSource = PowerSourceDisposableBattery;
}
// Bit 12 - 15: Battery level if available
// 0000: Critically low
// 0100: Approximately 33%
// 1000: Approximately 66%
// 1100: Approximately 100% (near fully charged)
if (!ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelCriticalLow;
} else if (ZigbeeUtils::checkBitUint16(bitField, 14) && !ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelLow;
} else if (!ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelOk;
} else if (ZigbeeUtils::checkBitUint16(bitField, 14) && ZigbeeUtils::checkBitUint16(bitField, 15)) {
m_powerLevel = PowerLevelFull;
}
qCDebug(dcZigbee()) << "Node power descriptor:";
qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
qCDebug(dcZigbee()) << " Bitfiled:" << ZigbeeUtils::convertUint16ToHexString(bitField);
qCDebug(dcZigbee()) << " Power mode:" << m_powerMode;
qCDebug(dcZigbee()) << " Available power sources:";
foreach (const PowerSource &source, m_availablePowerSources) {
qCDebug(dcZigbee()) << " " << source;
}
qCDebug(dcZigbee()) << " Power source:" << m_powerSource;
qCDebug(dcZigbee()) << " Power level:" << m_powerLevel;
}
void ZigbeeNode::onRequestUserDescriptorFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
qCDebug(dcZigbeeController()) << reply->additionalMessage();
quint8 sequenceNumber = static_cast<quint8>(reply->additionalMessage().data().at(0));
quint8 status = static_cast<quint8>(reply->additionalMessage().data().at(1));
quint16 nwkAddress = reply->additionalMessage().data().at(2);
nwkAddress <<= 8;
nwkAddress |= reply->additionalMessage().data().at(3);
quint8 length = static_cast<quint8>(reply->additionalMessage().data().at(4));
QByteArray data;
if (length > 0) {
data = reply->additionalMessage().data().mid(5, length);
}
qCDebug(dcZigbee()) << "User descriptor:";
qCDebug(dcZigbee()) << " Sequence number:" << ZigbeeUtils::convertByteToHexString(sequenceNumber);
qCDebug(dcZigbee()) << " Status:" << ZigbeeUtils::convertByteToHexString(status);
qCDebug(dcZigbee()) << " Attribute address:" << ZigbeeUtils::convertUint16ToHexString(nwkAddress);
qCDebug(dcZigbee()) << " Lenght:" << ZigbeeUtils::convertByteToHexString(length);
qCDebug(dcZigbee()) << " Data:" << data;
}
void ZigbeeNode::onToggleFinished()
{
ZigbeeInterfaceReply *reply = static_cast<ZigbeeInterfaceReply *>(sender());
reply->deleteLater();
if (reply->status() != ZigbeeInterfaceReply::Success) {
qCWarning(dcZigbeeController()) << "Could not" << reply->request().description() << reply->status() << reply->statusErrorMessage();
return;
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
}
void ZigbeeNode::onIdentifyFinished()
{
}
QDebug operator<<(QDebug debug, ZigbeeNode *node)
{
debug.nospace().noquote() << "Node(" << node->shortAddress() << ", " << node->extendedAddress().toString() << ") ";
debug.nospace().noquote() << "Node(" << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) << " | " << node->extendedAddress().toString() << ") ";
debug.nospace().noquote() << " " << ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) << " | " << node->extendedAddress().toString() << ") ";
return debug;
}

View File

@ -30,28 +30,97 @@ public:
};
Q_ENUM(FrequencyBand)
enum Relationship {
Parent,
Child,
Sibling
};
Q_ENUM(Relationship)
enum PowerMode {
PowerModeAlwaysOn,
PowerModeOnPeriodically,
PowerModeOnWhenStimulated
};
Q_ENUM(PowerMode)
enum PowerSource {
PowerSourcePermanentMainSupply,
PowerSourceRecharchableBattery,
PowerSourceDisposableBattery
};
Q_ENUM(PowerSource)
enum PowerLevel {
PowerLevelCriticalLow,
PowerLevelLow,
PowerLevelOk,
PowerLevelFull
};
Q_ENUM(PowerLevel)
quint16 shortAddress() const;
ZigbeeAddress extendedAddress() const;
int endPoint() const;
// Information from node descriptor
NodeType nodeType() const;
FrequencyBand frequencyBand() const;
Relationship relationShip() const;
Zigbee::ZigbeeProfile profile() const;
quint16 manufacturerCode() const;
bool canBeCoordinator() const;
PowerMode powerMode() const;
PowerSource powerSource() const;
QList<PowerSource> availablePowerSources() const;
PowerLevel powerLevel() const;
// Node specific zigbee commands
void init();
void identify();
void toggle(int addressMode);
private:
ZigbeeBridgeController *m_controller;
quint16 m_shortAddress = 0;
ZigbeeAddress m_extendedAddress;
NodeType m_nodeType;
int m_endPoint = 0;
NodeType m_nodeType = NodeTypeRouter;
FrequencyBand m_frequencyBand = FrequencyBand2400Mhz;
Relationship m_relationShip = Parent;
Zigbee::ZigbeeProfile m_profile;
quint16 m_manufacturerCode = 0;
quint16 m_maximalRxSize = 0;
quint16 m_maximalTxSize = 0;
bool m_isPrimaryTrustCenter = false;
bool m_isBackupTrustCenter = false;
bool m_isPrimaryBindingCache = false;
bool m_isBackupBindingCache = false;
bool m_isPrimaryDiscoveryCache = false;
bool m_isBackupDiscoveryCache = false;
bool m_isNetworkManager = false;
// Power information
PowerMode m_powerMode;
PowerSource m_powerSource;
QList<PowerSource> m_availablePowerSources;
PowerLevel m_powerLevel;
// Mac capabilities
bool m_receiverOnWhenIdle = false;
bool m_securityCapability = false;
void requestNodeDescription();
void requestSimpleNodeDescription();
void requestPowerDescriptor();
void requestUserDescriptor();
void saveToSettings();
protected:
ZigbeeNode(ZigbeeBridgeController *controller, QObject *parent = nullptr);
@ -67,7 +136,9 @@ private slots:
void onRequestNodeDescriptionFinished();
void onRequestSimpleNodeDescriptionFinished();
void onRequestPowerDescriptorFinished();
void onRequestUserDescriptorFinished();
void onToggleFinished();
void onIdentifyFinished();
public slots:

View File

@ -27,6 +27,43 @@ QByteArray ZigbeeUtils::convertBitArrayToByteArray(const QBitArray &bitArray)
return byteArray;
}
bool ZigbeeUtils::checkBitUint16(const quint16 &value, const int &bitNumber)
{
return value & (1 << bitNumber);
}
quint16 ZigbeeUtils::convertByteArrayToUint16(const QByteArray &data)
{
Q_ASSERT_X(data.count() == 2, "converting data", "Invalid byte array size for converting to quint16");
quint16 value = static_cast<quint8>(data.at(0));
value <<= 8;
value |= static_cast<quint8>(data.at(1));
return value;
}
quint64 ZigbeeUtils::convertByteArrayToUint64(const QByteArray &data)
{
Q_ASSERT_X(data.count() == 8, "converting data", "Invalid byte array size for converting to quint64");
quint64 value = static_cast<quint8>(data.at(0));
value <<= 8;
value |= static_cast<quint8>(data.at(1));
value <<= 8;
value |= static_cast<quint8>(data.at(2));
value <<= 8;
value |= static_cast<quint8>(data.at(3));
value <<= 8;
value |= static_cast<quint8>(data.at(4));
value <<= 8;
value |= static_cast<quint8>(data.at(5));
value <<= 8;
value |= static_cast<quint8>(data.at(6));
value <<= 8;
value |= static_cast<quint8>(data.at(7));
return value;
}
QString ZigbeeUtils::convertByteToHexString(const quint8 &byte)
{
QString hexString(QStringLiteral("0x%1"));
@ -39,7 +76,7 @@ QString ZigbeeUtils::convertByteArrayToHexString(const QByteArray &byteArray)
QString hexString;
for (int i = 0; i < byteArray.count(); i++) {
hexString.append(convertByteToHexString((quint8)byteArray.at(i)));
if (i != byteArray.count() -1) {
if (i != byteArray.count() - 1) {
hexString.append(" ");
}
}

View File

@ -16,6 +16,10 @@ public:
// Data utils
QBitArray convertByteArrayToBitArray(const QByteArray &byteArray);
QByteArray convertBitArrayToByteArray(const QBitArray &bitArray);
static bool checkBitUint16(const quint16 &value, const int &bitNumber);
static quint16 convertByteArrayToUint16(const QByteArray &data);
static quint64 convertByteArrayToUint64(const QByteArray &data);
// Debug utils
static QString convertByteToHexString(const quint8 &byte);

View File

@ -1,11 +1,16 @@
#include "core.h"
#include "loggingcategory.h"
#include "QCoreApplication"
#include "zigbeeutils.h"
#include <QCoreApplication>
Core::Core(const QString &serialPort, const int &channel, QObject *parent) :
QObject(parent),
m_serialPort(serialPort)
{
m_channelMask = 0;
m_channelMask |= 1 << (channel);
m_manager = new ZigbeeNetworkManager(channel, m_serialPort, this);
// Set commands
@ -20,11 +25,18 @@ Core::Core(const QString &serialPort, const int &channel, QObject *parent) :
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("network-info", "Print all information of the zigbee network."));
m_commands.append(TerminalCommand("list-nodes", "List all nodes and information of the current network"));
m_commands.append(TerminalCommand("permit-join", "Permit nodes to join the network"));
m_commands.append(TerminalCommand("touch-link", "Initiate touch link pairing"));
m_commands.append(TerminalCommand("reset-touchlink", "Touch link factory reset"));
m_commands.append(TerminalCommand("whitelist", "Enable the white list joining"));
m_commands.append(TerminalCommand("address-request", "Request network address on host node"));
m_commands.append(TerminalCommand("matchdescriptor", "Request match descriptors"));
m_commands.append(TerminalCommand("init-node", "Request simple descriptors"));
m_commands.append(TerminalCommand("lqi", "Request link quality"));
m_commands.append(TerminalCommand("toggle", "Request to toggle"));
m_commands.append(TerminalCommand("authenticate", "Authenticate device with given IEEE address"));
TerminalCommander::instance()->setCommands(m_commands);
TerminalCommander::instance()->start();
@ -33,6 +45,17 @@ Core::Core(const QString &serialPort, const int &channel, QObject *parent) :
connect(TerminalCommander::instance(), &TerminalCommander::finished, QCoreApplication::instance(), &QCoreApplication::quit);
}
ZigbeeNode *Core::findNode(const QString &shortAddressString)
{
foreach (ZigbeeNode *node, m_manager->nodeList()) {
if (ZigbeeUtils::convertUint16ToHexString(node->shortAddress()) == shortAddressString) {
return node;
}
}
return nullptr;
}
void Core::onCommandReceived(const QStringList &tokens)
{
TerminalCommand command;
@ -68,30 +91,93 @@ void Core::onCommandReceived(const QStringList &tokens)
m_manager->erasePersistentData();
m_manager->getVersion();
m_manager->setExtendedPanId(m_manager->extendedPanId());
m_manager->setChannelMask(0);
m_manager->setChannelMask(0x2108800);
m_manager->setDeviceType(nodeType);
// Note: this is the leaked philips ZLL master key
m_manager->setInitialSecurity(3, 0, 1, "9F5595F10257C8A469CBF42BC93FEE31");
m_manager->setInitialSecurity(4, 0, 1, "5A6967426565416C6C69616E63653039");
} else if (command.command() == "start") {
m_manager->startNetwork();
} else if (command.command() == "version") {
m_manager->getVersion();
} else if (command.command() == "network-info") {
qCDebug(dcZigbee()).nospace().noquote() << "Network controller: " << m_manager->serialPort() << ", Bridge version: " << m_manager->controllerVersion();
} else if (command.command() == "scan") {
m_manager->startScan();
} else if (command.command() == "reset") {
m_manager->resetController();
} else if (command.command() == "permit-join") {
m_manager->permitJoining();
m_manager->permitJoining(0xfffc, 180, true);
} else if (command.command() == "touch-link") {
m_manager->initiateTouchLink();
} else if (command.command() == "touch-link-reset") {
} else if (command.command() == "reset-touchlink") {
m_manager->touchLinkFactoryReset();
} else if (command.command() == "enable-whitelist") {
} else if (command.command() == "whitelist") {
m_manager->enableWhitelist();
} else if (command.command() == "address-request") {
if (tokens.count() == 1) {
m_manager->networkAddressRequest(0, m_manager->extendedAddress().toUInt64());
return;
}
ZigbeeNode *node = findNode(tokens.at(1));
if (!node) {
qCWarning(dcZigbee()) << "Could not find node with short address tokens.at(1)";
return;
}
m_manager->networkAddressRequest(node->shortAddress(), node->extendedAddress().toUInt64());
} else if (command.command() == "toggle") {
if (tokens.count() < 3) {
qCWarning(dcZigbee()) << "Please specify also the node short address and adressMode";
return;
}
ZigbeeNode *node = findNode(tokens.at(1));
if (!node) {
qCWarning(dcZigbee()) << "Could not find node with short address tokens.at(1)";
return;
}
int addressMode = QString(tokens.at(2)).toInt();
node->toggle(addressMode);
} else if (command.command() == "lqi") {
m_manager->requestLinkQuality();
} else if (command.command() == "init-node") {
if (tokens.count() == 1) {
qCWarning(dcZigbee()) << "Please specify also the node short address";
return;
}
ZigbeeNode *node = findNode(tokens.at(1));
if (!node) {
qCWarning(dcZigbee()) << "Could not find node with short address tokens.at(1)";
return;
}
node->init();
} else if (command.command() == "matchdescriptor") {
m_manager->requestMatchDescriptor(0x9004, Zigbee::ZigbeeProfileLightLink);
//m_manager->requestMatchDescriptor(0xFFFD, Zigbee::ZigbeeProfileLightLink);
} else if (command.command() == "authenticate") {
if (tokens.count() == 1) {
qCWarning(dcZigbee()) << "Please specify also the node short address";
return;
}
m_manager->authenticateDevice(ZigbeeAddress(tokens.at(1)));
} else if (command.command() == "list-nodes") {
qCDebug(dcZigbee()) << "--> Host:" << m_manager;
foreach (ZigbeeNode *node, m_manager->nodeList()) {
qCDebug(dcZigbee()) << "-->" << node;
qCDebug(dcZigbee()) << " -->" << node;
}
}

View File

@ -21,6 +21,9 @@ private:
ZigbeeNetworkManager *m_manager = nullptr;
QList<TerminalCommand> m_commands;
QString m_serialPort;
quint32 m_channelMask = 0;
ZigbeeNode *findNode(const QString &shortAddressString);
signals: