Merge PR #14: deCONZ backend: fix reconnect mechanism and make latest firmware version work

This commit is contained in:
Jenkins nymea 2021-02-14 23:00:18 +01:00
commit ca57f0a720
9 changed files with 395 additions and 251 deletions

View File

@ -67,13 +67,14 @@ public:
CommandApsDataIndication = 0x17, CommandApsDataIndication = 0x17,
CommandGreenPower = 0x19, CommandGreenPower = 0x19,
CommandMacPoll = 0x1C, CommandMacPoll = 0x1C,
CommandSimplifiedBeacon = 0x1F CommandMacBeacon = 0x1F,
CommandUpdateBootloader = 0x21
}; };
Q_ENUM(Command) Q_ENUM(Command)
enum Parameter { enum Parameter {
ParameterMacAddress = 0x01, // R ParameterMacAddress = 0x01, // R
ParameterPanId = 0x05, // R ParameterPanId = 0x05, // RW
ParameterNetworkAddress = 0x07, // R ParameterNetworkAddress = 0x07, // R
ParameterNetworkExtendedPanId = 0x08, // R ParameterNetworkExtendedPanId = 0x08, // R
ParameterNodeType = 0x09, //RW ParameterNodeType = 0x09, //RW
@ -81,12 +82,15 @@ public:
ParameterApsExtendedPanId = 0x0B, //RW ParameterApsExtendedPanId = 0x0B, //RW
ParameterTrustCenterAddress = 0x0E, // RW ParameterTrustCenterAddress = 0x0E, // RW
ParameterSecurityMode = 0x10, // RW ParameterSecurityMode = 0x10, // RW
ParameterNetworkKey = 0x18, //W ParameterPredefinedNwkPanId = 0x15, // RW
ParameterNetworkKey = 0x18, // RW
ParameterLinkKey = 0x19, // RW
ParameterCurrentChannel = 0x1c, // R ParameterCurrentChannel = 0x1c, // R
ParameterPermitJoin = 0x21, // RW ParameterPermitJoin = 0x21, // RW
ParameterProtocolVersion = 0x22, // R ParameterProtocolVersion = 0x22, // R
ParameterNetworkUpdateId = 0x24, // RW ParameterNetworkUpdateId = 0x24, // RW
ParameterWatchdogTtl = 0x26 // RW since protocol version 0x0108 ParameterWatchdogTtl = 0x26, // RW since protocol version 0x0108
ParameterNetworkFrameCounter = 0x27 // RW
}; };
Q_ENUM(Parameter) Q_ENUM(Parameter)

View File

@ -146,6 +146,7 @@ void ZigbeeInterfaceDeconz::onReconnectTimeout()
if (m_serialPort && !m_serialPort->isOpen()) { if (m_serialPort && !m_serialPort->isOpen()) {
if (!m_serialPort->open(QSerialPort::ReadWrite)) { if (!m_serialPort->open(QSerialPort::ReadWrite)) {
setAvailable(false); setAvailable(false);
qCDebug(dcZigbeeInterface()) << "Interface reconnected failed" << m_serialPort->portName() << m_serialPort->baudRate();
m_reconnectTimer->start(); m_reconnectTimer->start();
} else { } else {
qCDebug(dcZigbeeInterface()) << "Interface reconnected successfully on" << m_serialPort->portName() << m_serialPort->baudRate(); qCDebug(dcZigbeeInterface()) << "Interface reconnected successfully on" << m_serialPort->portName() << m_serialPort->baudRate();

View File

@ -67,6 +67,29 @@ Deconz::NetworkState ZigbeeBridgeControllerDeconz::networkState() const
return m_networkState; return m_networkState;
} }
void ZigbeeBridgeControllerDeconz::rebootController()
{
// According to the docs, the watchdog can be used to reboot the device by
// setting the watchdog timeout to a small value and let it timeout
// Reset the timer to prevent interrupting the reboot
m_watchdogTimer->start();
// Write the watchdog to 2 seconds
QByteArray parameterData;
QDataStream stream(&parameterData, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint32>(2);
ZigbeeInterfaceDeconzReply *reply = requestWriteParameter(Deconz::ParameterWatchdogTtl, parameterData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could initiate reboot controller by writing watchdog parameter." << reply->statusCode();
return;
}
qCDebug(dcZigbeeController()) << "Reboot device requested successfully. The controler is about to reboot...";
});
}
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion() ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion()
{ {
@ -76,7 +99,9 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion()
stream << static_cast<quint8>(Deconz::CommandVersion); stream << static_cast<quint8>(Deconz::CommandVersion);
stream << static_cast<quint8>(0); // SQN will be generated right before sending stream << static_cast<quint8>(0); // SQN will be generated right before sending
stream << static_cast<quint8>(0); // Reserverd stream << static_cast<quint8>(0); // Reserverd
stream << static_cast<quint16>(5); // Frame length stream << static_cast<quint16>(9); // Frame length
stream << static_cast<quint16>(0);
stream << static_cast<quint16>(0);
return createReply(Deconz::CommandVersion, "Request controller version", message, this); return createReply(Deconz::CommandVersion, "Request controller version", message, this);
} }
@ -214,9 +239,9 @@ void ZigbeeBridgeControllerDeconz::sendNextRequest()
if (m_currentReply) if (m_currentReply)
return; return;
// // FIXME: If the controler request queue is full, wait until it's free again // // FIXME: If the controler request queue is full, wait until it's free again
// if (!m_apsFreeSlotsAvailable) // if (!m_apsFreeSlotsAvailable)
// return; // return;
// Get the next reply, set the sequence number, send the request data over the interface and start waiting // Get the next reply, set the sequence number, send the request data over the interface and start waiting
m_currentReply = m_replyQueue.dequeue(); m_currentReply = m_replyQueue.dequeue();
@ -282,12 +307,12 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Co
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius) ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{ {
// quint8 sequenceNumber = generateSequenceNumber(); // quint8 sequenceNumber = generateSequenceNumber();
// qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress) // qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress)
// << "SQN:" << sequenceNumber // << "SQN:" << sequenceNumber
// << static_cast<Zigbee::ZigbeeProfile>(profileId) // << static_cast<Zigbee::ZigbeeProfile>(profileId)
// << ZigbeeUtils::convertUint16ToHexString(clusterId) // << ZigbeeUtils::convertUint16ToHexString(clusterId)
// << ZigbeeUtils::convertByteToHexString(sourceEndpoint); // << ZigbeeUtils::convertByteToHexString(sourceEndpoint);
Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes"); Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes");
@ -321,13 +346,13 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius) ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{ {
// quint8 sequenceNumber = generateSequenceNumber(); // quint8 sequenceNumber = generateSequenceNumber();
// qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress) // qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress)
// << "SQN:" << sequenceNumber // << "SQN:" << sequenceNumber
// << ZigbeeUtils::convertByteToHexString(destinationEndpoint) // << ZigbeeUtils::convertByteToHexString(destinationEndpoint)
// << static_cast<Zigbee::ZigbeeProfile>(profileId) // << static_cast<Zigbee::ZigbeeProfile>(profileId)
// << ZigbeeUtils::convertUint16ToHexString(clusterId) // << ZigbeeUtils::convertUint16ToHexString(clusterId)
// << ZigbeeUtils::convertByteToHexString(sourceEndpoint); // << ZigbeeUtils::convertByteToHexString(sourceEndpoint);
Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes"); Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes");
@ -361,12 +386,12 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius) ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius)
{ {
// quint8 sequenceNumber = generateSequenceNumber(); // quint8 sequenceNumber = generateSequenceNumber();
// qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString() // qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString()
// << "SQN:" << sequenceNumber // << "SQN:" << sequenceNumber
// << ZigbeeUtils::convertByteToHexString(destinationEndpoint) // << ZigbeeUtils::convertByteToHexString(destinationEndpoint)
// << profileId << clusterId // << profileId << clusterId
// << ZigbeeUtils::convertByteToHexString(sourceEndpoint); // << ZigbeeUtils::convertByteToHexString(sourceEndpoint);
Q_ASSERT_X(asdu.length() <= 127, "ZigbeeController", "ASDU package length has to be <= 127 bytes"); Q_ASSERT_X(asdu.length() <= 127, "ZigbeeController", "ASDU package length has to be <= 127 bytes");
@ -418,7 +443,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
<< Deconz::ParameterMacAddress << "finished with error" << replyMacAddress->statusCode(); << Deconz::ParameterMacAddress << "finished with error" << replyMacAddress->statusCode();
readNetworkParametersReply->m_statusCode = replyMacAddress->statusCode(); readNetworkParametersReply->m_statusCode = replyMacAddress->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyMacAddress->responseData()); QDataStream stream(replyMacAddress->responseData());
@ -438,7 +463,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPanId->sequenceNumber() << replyPanId->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPanId->sequenceNumber() << replyPanId->command()
<< Deconz::ParameterPanId << "finished with error" << replyPanId->statusCode(); << Deconz::ParameterPanId << "finished with error" << replyPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyPanId->statusCode(); readNetworkParametersReply->m_statusCode = replyPanId->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyPanId->responseData()); QDataStream stream(replyPanId->responseData());
@ -458,7 +483,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyShortAddress->sequenceNumber() << replyShortAddress->command() << Deconz::ParameterNetworkAddress qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyShortAddress->sequenceNumber() << replyShortAddress->command() << Deconz::ParameterNetworkAddress
<< "finished with error" << replyShortAddress->statusCode(); << "finished with error" << replyShortAddress->statusCode();
readNetworkParametersReply->m_statusCode = replyShortAddress->statusCode(); readNetworkParametersReply->m_statusCode = replyShortAddress->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -478,7 +503,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyExtendedPanId->sequenceNumber() << replyExtendedPanId->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyExtendedPanId->sequenceNumber() << replyExtendedPanId->command()
<< Deconz::ParameterNetworkExtendedPanId << "finished with error" << replyExtendedPanId->statusCode(); << Deconz::ParameterNetworkExtendedPanId << "finished with error" << replyExtendedPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyExtendedPanId->statusCode(); readNetworkParametersReply->m_statusCode = replyExtendedPanId->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -498,7 +523,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyNodeType->sequenceNumber() << replyNodeType->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyNodeType->sequenceNumber() << replyNodeType->command()
<< Deconz::ParameterNodeType << "finished with error" << replyNodeType->statusCode(); << Deconz::ParameterNodeType << "finished with error" << replyNodeType->statusCode();
readNetworkParametersReply->m_statusCode = replyNodeType->statusCode(); readNetworkParametersReply->m_statusCode = replyNodeType->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -519,7 +544,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyChannelMask->sequenceNumber() << replyChannelMask->command() << Deconz::ParameterChannelMask qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyChannelMask->sequenceNumber() << replyChannelMask->command() << Deconz::ParameterChannelMask
<< "finished with error" << replyChannelMask->statusCode(); << "finished with error" << replyChannelMask->statusCode();
readNetworkParametersReply->m_statusCode = replyChannelMask->statusCode(); readNetworkParametersReply->m_statusCode = replyChannelMask->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -540,7 +565,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyApsExtendedPanId->sequenceNumber() << replyApsExtendedPanId->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyApsExtendedPanId->sequenceNumber() << replyApsExtendedPanId->command()
<< Deconz::ParameterApsExtendedPanId << "finished with error" << replyApsExtendedPanId->statusCode(); << Deconz::ParameterApsExtendedPanId << "finished with error" << replyApsExtendedPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyApsExtendedPanId->statusCode(); readNetworkParametersReply->m_statusCode = replyApsExtendedPanId->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -561,7 +586,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyTrustCenterAddress->sequenceNumber() << replyTrustCenterAddress->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyTrustCenterAddress->sequenceNumber() << replyTrustCenterAddress->command()
<< Deconz::ParameterTrustCenterAddress << "finished with error" << replyTrustCenterAddress->statusCode(); << Deconz::ParameterTrustCenterAddress << "finished with error" << replyTrustCenterAddress->statusCode();
readNetworkParametersReply->m_statusCode = replyTrustCenterAddress->statusCode(); readNetworkParametersReply->m_statusCode = replyTrustCenterAddress->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -582,7 +607,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replySecurityMode->sequenceNumber() << replySecurityMode->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replySecurityMode->sequenceNumber() << replySecurityMode->command()
<< Deconz::ParameterSecurityMode << "finished with error" << replySecurityMode->statusCode(); << Deconz::ParameterSecurityMode << "finished with error" << replySecurityMode->statusCode();
readNetworkParametersReply->m_statusCode = replySecurityMode->statusCode(); readNetworkParametersReply->m_statusCode = replySecurityMode->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
@ -596,128 +621,158 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters(
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully"; << static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << m_networkConfiguration.securityMode; qCDebug(dcZigbeeController()) << m_networkConfiguration.securityMode;
// Note: reading the network key returns "InavlidParameter". Might be for security reasons which is good!
// Read channel // Read predefined new pan id
ZigbeeInterfaceDeconzReply *replyChannel = requestReadParameter(Deconz::ParameterCurrentChannel); ZigbeeInterfaceDeconzReply *replyPredefinedNwkPanId = requestReadParameter(Deconz::ParameterPredefinedNwkPanId);
connect(replyChannel, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyChannel](){ connect(replyPredefinedNwkPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPredefinedNwkPanId](){
if (replyChannel->statusCode() != Deconz::StatusCodeSuccess) { if (replyPredefinedNwkPanId->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyChannel->sequenceNumber() << replyChannel->command() << Deconz::ParameterCurrentChannel qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPredefinedNwkPanId->sequenceNumber() << replyPredefinedNwkPanId->command()
<< "finished with error" << replyChannel->statusCode(); << Deconz::ParameterSecurityMode << "finished with error" << replyPredefinedNwkPanId->statusCode();
readNetworkParametersReply->m_statusCode = replyChannel->statusCode(); readNetworkParametersReply->m_statusCode = replyPredefinedNwkPanId->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyChannel->responseData()); QDataStream stream(replyPredefinedNwkPanId->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 channel = 0; quint16 payloadLenght = 0; quint8 parameter = 0; quint8 predefinedNwkPanId = 0;
stream >> payloadLenght >> parameter >> channel; stream >> payloadLenght >> parameter >> predefinedNwkPanId;
m_networkConfiguration.currentChannel = channel;
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyChannel->sequenceNumber() << replyChannel->command() << static_cast<Deconz::Parameter>(parameter) m_networkConfiguration.predefinedNetworkPanId = static_cast<bool>(predefinedNwkPanId);
<< "finished successfully"; qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyPredefinedNwkPanId->sequenceNumber() << replyPredefinedNwkPanId->command()
qCDebug(dcZigbeeController()) << "Current channel:" << m_networkConfiguration.currentChannel; << static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << m_networkConfiguration.predefinedNetworkPanId;
// Read permit join status // We don't make use of link key for now
ZigbeeInterfaceDeconzReply *replyPermitJoin = requestReadParameter(Deconz::ParameterPermitJoin);
connect(replyPermitJoin, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPermitJoin](){ // Note: reading the network key returns "InavlidParameter". Might be for security reasons which is good!
if (replyPermitJoin->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPermitJoin->sequenceNumber() << replyPermitJoin->command() // Read channel
<< Deconz::ParameterPermitJoin << "finished with error" << replyPermitJoin->statusCode(); ZigbeeInterfaceDeconzReply *replyChannel = requestReadParameter(Deconz::ParameterCurrentChannel);
readNetworkParametersReply->m_statusCode = replyPermitJoin->statusCode(); connect(replyChannel, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyChannel](){
readNetworkParametersReply->finished(); if (replyChannel->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyChannel->sequenceNumber() << replyChannel->command() << Deconz::ParameterCurrentChannel
<< "finished with error" << replyChannel->statusCode();
readNetworkParametersReply->m_statusCode = replyChannel->statusCode();
emit readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyPermitJoin->responseData()); QDataStream stream(replyChannel->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 payloadLenght = 0; quint8 parameter = 0; quint8 channel = 0;
stream >> payloadLenght >> parameter; stream >> payloadLenght >> parameter >> channel;
//m_networkConfiguration.currentChannel = channel; m_networkConfiguration.currentChannel = channel;
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyPermitJoin->sequenceNumber() << replyPermitJoin->command() << static_cast<Deconz::Parameter>(parameter) qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyChannel->sequenceNumber() << replyChannel->command() << static_cast<Deconz::Parameter>(parameter)
<< "finished successfully" << ZigbeeUtils::convertByteArrayToHexString(replyPermitJoin->responseData()); << "finished successfully";
qCDebug(dcZigbeeController()) << "Current channel:" << m_networkConfiguration.currentChannel;
// Read protocol version // Read permit join status
ZigbeeInterfaceDeconzReply *replyProtocolVersion = requestReadParameter(Deconz::ParameterProtocolVersion); ZigbeeInterfaceDeconzReply *replyPermitJoin = requestReadParameter(Deconz::ParameterPermitJoin);
connect(replyProtocolVersion, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyProtocolVersion](){ connect(replyPermitJoin, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPermitJoin](){
if (replyProtocolVersion->statusCode() != Deconz::StatusCodeSuccess) { if (replyPermitJoin->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyProtocolVersion->sequenceNumber() << replyProtocolVersion->command() qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyPermitJoin->sequenceNumber() << replyPermitJoin->command()
<< Deconz::ParameterProtocolVersion << "finished with error" << replyProtocolVersion->statusCode(); << Deconz::ParameterPermitJoin << "finished with error" << replyPermitJoin->statusCode();
readNetworkParametersReply->m_statusCode = replyProtocolVersion->statusCode(); readNetworkParametersReply->m_statusCode = replyPermitJoin->statusCode();
readNetworkParametersReply->finished(); emit readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyProtocolVersion->responseData()); QDataStream stream(replyPermitJoin->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 protocolVersion = 0; quint16 payloadLenght = 0; quint8 parameter = 0;
stream >> payloadLenght >> parameter >> protocolVersion; stream >> payloadLenght >> parameter;
m_networkConfiguration.protocolVersion = protocolVersion; //m_networkConfiguration.currentChannel = channel;
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyProtocolVersion->sequenceNumber() << replyProtocolVersion->command() qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyPermitJoin->sequenceNumber() << replyPermitJoin->command() << static_cast<Deconz::Parameter>(parameter)
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully"; << "finished successfully" << ZigbeeUtils::convertByteArrayToHexString(replyPermitJoin->responseData());
qCDebug(dcZigbeeController()) << "Protocol version:" << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.protocolVersion);
// Read network updat id
ZigbeeInterfaceDeconzReply *replyNetworkUpdateId = requestReadParameter(Deconz::ParameterNetworkUpdateId); // Read protocol version
connect(replyNetworkUpdateId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyNetworkUpdateId](){ ZigbeeInterfaceDeconzReply *replyProtocolVersion = requestReadParameter(Deconz::ParameterProtocolVersion);
if (replyNetworkUpdateId->statusCode() != Deconz::StatusCodeSuccess) { connect(replyProtocolVersion, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyProtocolVersion](){
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyNetworkUpdateId->sequenceNumber() << replyNetworkUpdateId->command() if (replyProtocolVersion->statusCode() != Deconz::StatusCodeSuccess) {
<< Deconz::ParameterNetworkUpdateId << "finished with error" << replyNetworkUpdateId->statusCode(); qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyProtocolVersion->sequenceNumber() << replyProtocolVersion->command()
readNetworkParametersReply->m_statusCode = replyNetworkUpdateId->statusCode(); << Deconz::ParameterProtocolVersion << "finished with error" << replyProtocolVersion->statusCode();
readNetworkParametersReply->finished(); readNetworkParametersReply->m_statusCode = replyProtocolVersion->statusCode();
emit readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyNetworkUpdateId->responseData()); QDataStream stream(replyProtocolVersion->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 networkUpdateId = 0; quint16 payloadLenght = 0; quint8 parameter = 0; quint16 protocolVersion = 0;
stream >> payloadLenght >> parameter >> networkUpdateId; stream >> payloadLenght >> parameter >> protocolVersion;
m_networkConfiguration.networkUpdateId = networkUpdateId; m_networkConfiguration.protocolVersion = protocolVersion;
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyNetworkUpdateId->sequenceNumber() << replyNetworkUpdateId->command() qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyProtocolVersion->sequenceNumber() << replyProtocolVersion->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully"; << static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "Network update ID:" << m_networkConfiguration.networkUpdateId; qCDebug(dcZigbeeController()) << "Protocol version:" << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.protocolVersion);
// Make sure the watchdog is available for this version // Read network updat id
if (m_networkConfiguration.protocolVersion < 0x0108) { ZigbeeInterfaceDeconzReply *replyNetworkUpdateId = requestReadParameter(Deconz::ParameterNetworkUpdateId);
qCDebug(dcZigbeeController()) << "The watchdog api is available since protocol version 0x0108. The watchdog is not required for this version"; connect(replyNetworkUpdateId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyNetworkUpdateId](){
m_watchdogTimer->stop(); if (replyNetworkUpdateId->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyNetworkUpdateId->sequenceNumber() << replyNetworkUpdateId->command()
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished << Deconz::ParameterNetworkUpdateId << "finished with error" << replyNetworkUpdateId->statusCode();
emit networkConfigurationParameterChanged(m_networkConfiguration); readNetworkParametersReply->m_statusCode = replyNetworkUpdateId->statusCode();
readNetworkParametersReply->m_statusCode = Deconz::StatusCodeSuccess; emit readNetworkParametersReply->finished();
readNetworkParametersReply->finished();
return;
}
// Reset the watchdog in any case
resetControllerWatchdog();
// Read watchdog timeout
ZigbeeInterfaceDeconzReply *replyWatchdogTimeout = requestReadParameter(Deconz::ParameterWatchdogTtl);
connect(replyWatchdogTimeout, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyWatchdogTimeout](){
if (replyWatchdogTimeout->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyWatchdogTimeout->sequenceNumber() << replyWatchdogTimeout->command()
<< Deconz::ParameterWatchdogTtl << "finished with error" << replyWatchdogTimeout->statusCode();
readNetworkParametersReply->m_statusCode = replyWatchdogTimeout->statusCode();
readNetworkParametersReply->finished();
return; return;
} }
QDataStream stream(replyWatchdogTimeout->responseData()); QDataStream stream(replyNetworkUpdateId->responseData());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 parameter = 0; quint32 watchdogTimeout = 0; quint16 payloadLenght = 0; quint8 parameter = 0; quint8 networkUpdateId = 0;
stream >> payloadLenght >> parameter >> watchdogTimeout; stream >> payloadLenght >> parameter >> networkUpdateId;
m_networkConfiguration.watchdogTimeout = watchdogTimeout; m_networkConfiguration.networkUpdateId = networkUpdateId;
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyWatchdogTimeout->sequenceNumber() << replyWatchdogTimeout->command() qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyNetworkUpdateId->sequenceNumber() << replyNetworkUpdateId->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully"; << static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "Watchdog timeout:" << m_networkConfiguration.watchdogTimeout; qCDebug(dcZigbeeController()) << "Network update ID:" << m_networkConfiguration.networkUpdateId;
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished // Make sure the watchdog is available for this version
emit networkConfigurationParameterChanged(m_networkConfiguration); if (m_networkConfiguration.protocolVersion < 0x0108) {
readNetworkParametersReply->m_statusCode = Deconz::StatusCodeSuccess; qCDebug(dcZigbeeController()) << "The watchdog api is available since protocol version 0x0108. The watchdog is not required for this version";
readNetworkParametersReply->finished(); m_watchdogTimer->stop();
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished
emit networkConfigurationParameterChanged(m_networkConfiguration);
readNetworkParametersReply->m_statusCode = Deconz::StatusCodeSuccess;
emit readNetworkParametersReply->finished();
return;
}
// Reset the watchdog in any case
resetControllerWatchdog();
// Read watchdog timeout
ZigbeeInterfaceDeconzReply *replyWatchdogTimeout = requestReadParameter(Deconz::ParameterWatchdogTtl);
connect(replyWatchdogTimeout, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyWatchdogTimeout](){
if (replyWatchdogTimeout->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << "SQN:" << replyWatchdogTimeout->sequenceNumber() << replyWatchdogTimeout->command()
<< Deconz::ParameterWatchdogTtl << "finished with error" << replyWatchdogTimeout->statusCode();
readNetworkParametersReply->m_statusCode = replyWatchdogTimeout->statusCode();
emit readNetworkParametersReply->finished();
return;
}
QDataStream stream(replyWatchdogTimeout->responseData());
stream.setByteOrder(QDataStream::LittleEndian);
quint16 payloadLenght = 0; quint8 parameter = 0; quint32 watchdogTimeout = 0;
stream >> payloadLenght >> parameter >> watchdogTimeout;
m_networkConfiguration.watchdogTimeout = watchdogTimeout;
qCDebug(dcZigbeeController()) << "Request" << "SQN:" << replyWatchdogTimeout->sequenceNumber() << replyWatchdogTimeout->command()
<< static_cast<Deconz::Parameter>(parameter) << "finished successfully";
qCDebug(dcZigbeeController()) << "Watchdog timeout:" << m_networkConfiguration.watchdogTimeout;
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished
emit networkConfigurationParameterChanged(m_networkConfiguration);
readNetworkParametersReply->m_statusCode = Deconz::StatusCodeSuccess;
emit readNetworkParametersReply->finished();
// We ignore the frame counter for now, since we let the firmware take control
});
}); });
}); });
}); });
@ -747,6 +802,11 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi
return state; return state;
} }
void ZigbeeBridgeControllerDeconz::reconnectConrtroller()
{
m_interface->reconnectController();
}
void ZigbeeBridgeControllerDeconz::readDataIndication() void ZigbeeBridgeControllerDeconz::readDataIndication()
{ {
if (m_readIndicationReply) { if (m_readIndicationReply) {
@ -812,7 +872,10 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt
if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) { if (m_apsFreeSlotsAvailable != deviceState.apsDataRequestFreeSlots) {
m_apsFreeSlotsAvailable = deviceState.apsDataRequestFreeSlots; m_apsFreeSlotsAvailable = deviceState.apsDataRequestFreeSlots;
if (!m_apsFreeSlotsAvailable) { if (!m_apsFreeSlotsAvailable) {
qCWarning(dcZigbeeController()) << "The APS request table is full on the device. Cannot send requests until the queue gets processed on the controller."; // Warn only if the network is up
if (m_networkState == Deconz::NetworkStateConnected) {
qCWarning(dcZigbeeController()) << "The APS request table is full on the device. Cannot send requests until the queue gets processed on the controller.";
}
return; return;
} else { } else {
qCDebug(dcZigbeeController()) << "The APS request table is free again. Sending the next request"; qCDebug(dcZigbeeController()) << "The APS request table is free again. Sending the next request";
@ -918,6 +981,18 @@ void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data)
} }
} }
void ZigbeeBridgeControllerDeconz::processMacPoll(const QByteArray &data)
{
qCDebug(dcZigbeeController()) << "MAC Poll command received" << ZigbeeUtils::convertByteArrayToHexString(data);
}
void ZigbeeBridgeControllerDeconz::processMacBeacon(const QByteArray &data)
{
qCDebug(dcZigbeeController()) << "Simplified beacon command received" << ZigbeeUtils::convertByteArrayToHexString(data);
}
void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available) void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available)
{ {
qCDebug(dcZigbeeController()) << "Interface available changed" << available; qCDebug(dcZigbeeController()) << "Interface available changed" << available;
@ -954,7 +1029,7 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
if (m_currentReply && m_currentReply->sequenceNumber() == sequenceNumber && m_currentReply->command() == command) { if (m_currentReply && m_currentReply->sequenceNumber() == sequenceNumber && m_currentReply->command() == command) {
m_currentReply->m_responseData = data; m_currentReply->m_responseData = data;
m_currentReply->m_statusCode = status; m_currentReply->m_statusCode = status;
m_currentReply->finished(); emit m_currentReply->finished();
// Note: the current reply will be cleaned up in the finished slot // Note: the current reply will be cleaned up in the finished slot
return; return;
} }
@ -972,13 +1047,11 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &
break; break;
} }
case Deconz::CommandMacPoll: { case Deconz::CommandMacPoll: {
// FIXME: parse the data and print info processMacPoll(data);
qCDebug(dcZigbeeController()) << "MAC Poll command received" << ZigbeeUtils::convertByteArrayToHexString(data);
break; break;
} }
case Deconz::CommandSimplifiedBeacon: { case Deconz::CommandMacBeacon: {
// FIXME: parse the data and print info processMacBeacon(data);
qCDebug(dcZigbeeController()) << "Simplified beacon command received" << ZigbeeUtils::convertByteArrayToHexString(data);
break; break;
} }
default: default:
@ -1046,7 +1119,8 @@ QDebug operator<<(QDebug debug, const DeconzNetworkConfiguration &configuration)
debug.nospace() << " - Node type:" << configuration.nodeType << "\n"; debug.nospace() << " - Node type:" << configuration.nodeType << "\n";
debug.nospace() << " - IEEE address: " << configuration.ieeeAddress.toString() << "\n"; debug.nospace() << " - IEEE address: " << configuration.ieeeAddress.toString() << "\n";
debug.nospace() << " - NWK address: " << ZigbeeUtils::convertUint16ToHexString(configuration.shortAddress) << "\n"; debug.nospace() << " - NWK address: " << ZigbeeUtils::convertUint16ToHexString(configuration.shortAddress) << "\n";
debug.nospace() << " - PAN ID: " << ZigbeeUtils::convertUint16ToHexString(configuration.panId) << "\n"; debug.nospace() << " - PAN ID: " << ZigbeeUtils::convertUint16ToHexString(configuration.panId) << " (" << configuration.panId << ")\n";
debug.nospace() << " - Use predefined network PAN ID: " << configuration.predefinedNetworkPanId << "\n";
debug.nospace() << " - Extended PAN ID: " << ZigbeeUtils::convertUint64ToHexString(configuration.extendedPanId) << "\n"; debug.nospace() << " - Extended PAN ID: " << ZigbeeUtils::convertUint64ToHexString(configuration.extendedPanId) << "\n";
debug.nospace() << " - APS Extended PAN ID: " << ZigbeeUtils::convertUint64ToHexString(configuration.apsExtendedPanId) << "\n"; debug.nospace() << " - APS Extended PAN ID: " << ZigbeeUtils::convertUint64ToHexString(configuration.apsExtendedPanId) << "\n";
debug.nospace() << " - Trust center IEEE address: " << configuration.trustCenterAddress.toString() << "\n"; debug.nospace() << " - Trust center IEEE address: " << configuration.trustCenterAddress.toString() << "\n";

View File

@ -54,6 +54,7 @@ typedef struct DeconzNetworkConfiguration {
quint64 apsExtendedPanId = 0; // RW quint64 apsExtendedPanId = 0; // RW
ZigbeeAddress trustCenterAddress; // RW ZigbeeAddress trustCenterAddress; // RW
Deconz::SecurityMode securityMode = Deconz::SecurityModeNoMasterButTrustCenterKey; // RW Deconz::SecurityMode securityMode = Deconz::SecurityModeNoMasterButTrustCenterKey; // RW
bool predefinedNetworkPanId; // RW
ZigbeeNetworkKey networkKey; // RW ZigbeeNetworkKey networkKey; // RW
quint8 currentChannel = 0; // R quint8 currentChannel = 0; // R
quint16 protocolVersion = 0; // R quint16 protocolVersion = 0; // R
@ -85,6 +86,8 @@ public:
void setFirmwareVersionString(const QString &firmwareVersion); void setFirmwareVersionString(const QString &firmwareVersion);
Deconz::NetworkState networkState() const; Deconz::NetworkState networkState() const;
void rebootController();
// Controllere requests // Controllere requests
ZigbeeInterfaceDeconzReply *requestVersion(); ZigbeeInterfaceDeconzReply *requestVersion();
@ -135,12 +138,15 @@ private:
// Device state helper // Device state helper
DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag); DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag);
void reconnectConrtroller();
void readDataIndication(); void readDataIndication();
void readDataConfirm(); void readDataConfirm();
void processDeviceState(DeconzDeviceState deviceState); void processDeviceState(DeconzDeviceState deviceState);
void processDataIndication(const QByteArray &data); void processDataIndication(const QByteArray &data);
void processDataConfirm(const QByteArray &data); void processDataConfirm(const QByteArray &data);
void processMacPoll(const QByteArray &data);
void processMacBeacon(const QByteArray &data);
signals: signals:
void networkStateChanged(Deconz::NetworkState networkState); void networkStateChanged(Deconz::NetworkState networkState);

View File

@ -201,7 +201,8 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
case CreateNetworkStateWriteConfiguration: { case CreateNetworkStateWriteConfiguration: {
// - Set coordinator // - Set coordinator
// - Set channel mask // - Set channel mask
// - Set APS extended PANID (zero to reset) // - Set predefined network PANID (0: let the firmware pick, 1: use the defined pan id)
// - Set NWK PANID
// - Set trust center address (coordinator address) // - Set trust center address (coordinator address)
// - Set security mode // - Set security mode
// - Set network key // - Set network key
@ -236,76 +237,95 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully. SQN:" << reply->sequenceNumber(); qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeNetwork()) << "Configure firmware to use predefined network PANID";
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
stream << static_cast<quint64>(extendedPanId());
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
qCDebug(dcZigbeeNetwork()) << "Configure APS extended PANID" << extendedPanId(); stream << static_cast<quint8>(0x01);
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterApsExtendedPanId, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPredefinedNwkPanId, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterApsExtendedPanId << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterPredefinedNwkPanId << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeController()) << "Configured APS extended PANID successfully. SQN:" << reply->sequenceNumber(); qCDebug(dcZigbeeController()) << "Configured firmware to use predefined network PNAID successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeNetwork()) << "Configure network PANID" << panId() << ZigbeeUtils::convertUint16ToHexString(panId());
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
stream << m_controller->networkConfiguration().ieeeAddress.toUInt64(); stream << panId();
qCDebug(dcZigbeeNetwork()) << "Configure trust center address" << m_controller->networkConfiguration().ieeeAddress.toString(); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPanId, paramData);
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterTrustCenterAddress, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterTrustCenterAddress << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterPanId << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeController()) << "Configured trust center address successfully. SQN:" << reply->sequenceNumber(); qCDebug(dcZigbeeController()) << "Configured network PANID successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData; QByteArray paramData;
QDataStream stream(&paramData, QIODevice::WriteOnly); QDataStream stream(&paramData, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian); stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Deconz::SecurityModeNoMasterButTrustCenterKey); stream << m_controller->networkConfiguration().ieeeAddress.toUInt64();
qCDebug(dcZigbeeNetwork()) << "Configure security mode" << Deconz::SecurityModeNoMasterButTrustCenterKey; qCDebug(dcZigbeeNetwork()) << "Configure trust center address" << m_controller->networkConfiguration().ieeeAddress.toString();
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterSecurityMode, paramData); ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterTrustCenterAddress, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterSecurityMode << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterTrustCenterAddress << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
return; return;
} }
qCDebug(dcZigbeeController()) << "Configured security mode successfully. SQN:" << reply->sequenceNumber(); qCDebug(dcZigbeeController()) << "Configured trust center address successfully. SQN:" << reply->sequenceNumber();
QByteArray paramData;
qCDebug(dcZigbeeNetwork()) << "Configure network key" << securityConfiguration().networkKey().toString(); QDataStream stream(&paramData, QIODevice::WriteOnly);
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNetworkKey, securityConfiguration().networkKey().toByteArray()); stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(Deconz::SecurityModeNoMasterButTrustCenterKey);
qCDebug(dcZigbeeNetwork()) << "Configure security mode" << Deconz::SecurityModeNoMasterButTrustCenterKey;
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterSecurityMode, paramData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterNetworkKey << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterSecurityMode << reply->statusCode();
// FIXME: set an appropriate error // FIXME: set an appropriate error
// Note: writing the network key fails all the time... return;
//return;
} else {
qCDebug(dcZigbeeController()) << "Configured network key successfully. SQN:" << reply->sequenceNumber();
} }
// Re-read the configurations qCDebug(dcZigbeeController()) << "Configured security mode successfully. SQN:" << reply->sequenceNumber();
// Read all network parameters
ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters();
qCDebug(dcZigbeeNetwork()) << "Configure network key" << securityConfiguration().networkKey().toString();
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNetworkKey, securityConfiguration().networkKey().toByteArray());
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not write parameter. SQN:" << reply->sequenceNumber() << Deconz::ParameterNetworkKey << reply->statusCode();
// FIXME: set an appropriate error
// Note: writing the network key fails all the time...
//return;
} else {
qCDebug(dcZigbeeController()) << "Configured network key successfully. SQN:" << reply->sequenceNumber();
} }
qCDebug(dcZigbeeController()) << m_controller->networkConfiguration(); // Re-read the configurations
// Read all network parameters
ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode();
}
// Configuration finished, lets start the network qCDebug(dcZigbeeController()) << m_controller->networkConfiguration();
setCreateNetworkState(CreateNetworkStateStartNetwork);
// Configuration finished, lets start the network
setCreateNetworkState(CreateNetworkStateStartNetwork);
});
}); });
}); });
}); });
@ -342,10 +362,15 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully. SQN:" << reply->sequenceNumber(); qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully. SQN:" << reply->sequenceNumber();
qCDebug(dcZigbeeNetwork()) << "Network running with following configuration:";
qCDebug(dcZigbeeNetwork()) << m_controller->networkConfiguration();
setPanId(m_controller->networkConfiguration().panId); setPanId(m_controller->networkConfiguration().panId);
setExtendedPanId(m_controller->networkConfiguration().extendedPanId); setExtendedPanId(m_controller->networkConfiguration().extendedPanId);
setChannel(m_controller->networkConfiguration().currentChannel); setChannel(m_controller->networkConfiguration().currentChannel);
setCreateNetworkState(CreateNetworkStateInitializeCoordinatorNode); setCreateNetworkState(CreateNetworkStateInitializeCoordinatorNode);
}); });
break; break;
@ -392,118 +417,147 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo
void ZigbeeNetworkDeconz::runNetworkInitProcess() void ZigbeeNetworkDeconz::runNetworkInitProcess()
{ {
// - Read the network state (until success)
// - Read the firmware version // - Read the firmware version
// - Read the network configuration parameters // - Read the network configuration parameters
// - Read the network state
// - If network running and we don't have configurations, write them // - If network running and we don't have configurations, write them
// - If network running and configurations match, we are done // - If network running and configurations match, we are done
// Read the firmware version // Read the firmware version
qCDebug(dcZigbeeNetwork()) << "Reading current firmware version..."; qCDebug(dcZigbeeNetwork()) << "Request current device state...";
ZigbeeInterfaceDeconzReply *reply = m_controller->requestVersion(); ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode(); qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode();
m_initRetry++; m_initRetry++;
if (!m_controller->available()) {
m_initRetry = 0;
return;
}
if (m_initRetry < 10) { if (m_initRetry < 10) {
qCDebug(dcZigbeeNetwork()) << "Retry to initialize network" << m_initRetry << "/ 10"; qCDebug(dcZigbeeNetwork()) << "Retry to initialize network" << m_initRetry << "/ 10";
runNetworkInitProcess(); runNetworkInitProcess();
} else { } else {
qCWarning(dcZigbeeNetwork()) << "Failed to read firmware version after 10 attempts. Giving up"; qCWarning(dcZigbeeNetwork()) << "Failed to read device state after 10 attempts. Giving up";
m_controller->disable(); m_controller->reconnectConrtroller();
} }
return; return;
} }
m_initRetry = 0; m_initRetry = 0;
qCDebug(dcZigbeeNetwork()) << "Version request finished successfully" << ZigbeeUtils::convertByteArrayToHexString(reply->responseData());
// Note: version is an uint32 value, little endian, but we can read the individual bytes in reversed order
quint8 majorVersion = static_cast<quint8>(reply->responseData().at(3));
quint8 minorVersion = static_cast<quint8>(reply->responseData().at(2));
Deconz::Platform platform = static_cast<Deconz::Platform>(reply->responseData().at(1));
QString firmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
qCDebug(dcZigbeeNetwork()) << "Firmware version" << firmwareVersion << platform;
// Read all network parameters // Read all network parameters
qCDebug(dcZigbeeNetwork()) << "Start reading controller network parameters..."; qCDebug(dcZigbeeNetwork()) << "Start reading controller network parameters...";
ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters(); ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply, firmwareVersion](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up." << reply->statusCode(); qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up." << reply->statusCode();
// FIXME: set an appropriate error m_initRetry++;
if (m_initRetry < 3) {
qCDebug(dcZigbeeNetwork()) << "Retry to read network parameters" << m_initRetry << "/ 3";
runNetworkInitProcess();
} else {
qCWarning(dcZigbeeNetwork()) << "Failed to read network parameters after 3 attempts. Giving up";
m_controller->reconnectConrtroller();
}
return; return;
} }
qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully."; qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully.";
QString protocolVersion = QString("%1.%2").arg(m_controller->networkConfiguration().protocolVersion >> 8 & 0xFF)
.arg(m_controller->networkConfiguration().protocolVersion & 0xFF);
qCDebug(dcZigbeeNetwork()) << "Controller API protocol version" << ZigbeeUtils::convertUint16ToHexString(m_controller->networkConfiguration().protocolVersion) << protocolVersion;
m_controller->setFirmwareVersionString(QString("%1 - %2").arg(firmwareVersion).arg(protocolVersion));
qCDebug(dcZigbeeNetwork()) << m_controller->networkConfiguration(); qCDebug(dcZigbeeNetwork()) << m_controller->networkConfiguration();
qCDebug(dcZigbeeNetwork()) << "Reading current network state";
ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState(); m_protocolVersion = QString("%1.%2").arg(m_controller->networkConfiguration().protocolVersion >> 8 & 0xFF)
.arg(m_controller->networkConfiguration().protocolVersion & 0xFF);
qCDebug(dcZigbeeNetwork()) << "Controller API protocol version" << ZigbeeUtils::convertUint16ToHexString(m_controller->networkConfiguration().protocolVersion) << m_protocolVersion;
// Try read firmware version (changed with firmware 0x26680700)
qCDebug(dcZigbeeNetwork()) << "Request current firmware version...";
ZigbeeInterfaceDeconzReply *reply = m_controller->requestVersion();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
QString firmwareVersion;
if (reply->statusCode() != Deconz::StatusCodeSuccess) { if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode(); qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode();
// FIXME: set an appropriate error
return;
}
qCDebug(dcZigbeeNetwork()) << "Reading current network state finished successfully." << "SQN:" << reply->sequenceNumber();
QDataStream stream(reply->responseData());
stream.setByteOrder(QDataStream::LittleEndian);
quint8 deviceStateFlag = 0;
stream >> deviceStateFlag;
DeconzDeviceState deviceState = m_controller->parseDeviceStateFlag(deviceStateFlag);
qCDebug(dcZigbeeNetwork()) << deviceState;
// Update the device state in the controller
m_controller->processDeviceState(deviceState);
if (m_createNewNetwork) {
// Set offline
// Write configurations
// Set online
// Read configurations
// Create and initialize coordinator node
// Done. Save network
setCreateNetworkState(CreateNetworkStateStopNetwork);
} else { } else {
// Get the network state and start the network if required qCDebug(dcZigbeeNetwork()) << "Version request finished successfully" << ZigbeeUtils::convertByteArrayToHexString(reply->responseData());
if (m_controller->networkState() == Deconz::NetworkStateConnected) { // Note: version is an uint32 value, little endian, but we can read the individual bytes in reversed order
qCDebug(dcZigbeeNetwork()) << "The network is already running."; quint8 majorVersion = static_cast<quint8>(reply->responseData().at(3));
m_initializing = false; quint8 minorVersion = static_cast<quint8>(reply->responseData().at(2));
setPermitJoiningEnabled(false); Deconz::Platform platform = static_cast<Deconz::Platform>(reply->responseData().at(1));
// Set the permit joining timeout network configuration parameter m_firmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
QByteArray parameterData; qCDebug(dcZigbeeNetwork()) << "Firmware version" << firmwareVersion << platform;
QDataStream stream(&parameterData, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(0);
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPermitJoin, parameterData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode();
// FIXME: set an appropriate error
return;
}
qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode();
setState(StateRunning);
});
} else if (m_controller->networkState() == Deconz::NetworkStateOffline) {
m_initializing = true;
qCDebug(dcZigbeeNetwork()) << "The network is offline. Lets start it";
setCreateNetworkState(CreateNetworkStateStartNetwork);
} else {
// The network is not running yet, lets wait for the state changed
}
} }
if (!m_firmwareVersion.isEmpty()) {
m_controller->setFirmwareVersionString(QString("%1 - %2").arg(m_firmwareVersion).arg(m_protocolVersion));
} else {
m_controller->setFirmwareVersionString(m_protocolVersion);
}
qCDebug(dcZigbeeNetwork()) << "Reading current network state";
ZigbeeInterfaceDeconzReply *reply = m_controller->requestDeviceState();
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Could not read device state during network start up. SQN:" << reply->sequenceNumber() << reply->statusCode();
// FIXME: set an appropriate error
return;
}
qCDebug(dcZigbeeNetwork()) << "Reading current network state finished successfully." << "SQN:" << reply->sequenceNumber();
QDataStream stream(reply->responseData());
stream.setByteOrder(QDataStream::LittleEndian);
quint8 deviceStateFlag = 0;
stream >> deviceStateFlag;
DeconzDeviceState deviceState = m_controller->parseDeviceStateFlag(deviceStateFlag);
qCDebug(dcZigbeeNetwork()) << deviceState;
// Update the device state in the controller
m_controller->processDeviceState(deviceState);
if (m_createNewNetwork) {
// Set offline
// Write configurations
// Set online
// Read configurations
// Create and initialize coordinator node
// Done. Save network
setCreateNetworkState(CreateNetworkStateStopNetwork);
} else {
// Get the network state and start the network if required
if (m_controller->networkState() == Deconz::NetworkStateConnected) {
qCDebug(dcZigbeeNetwork()) << "The network is already running.";
m_initializing = false;
setPermitJoiningEnabled(false);
// Set the permit joining timeout network configuration parameter
QByteArray parameterData;
QDataStream stream(&parameterData, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(0);
ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterPermitJoin, parameterData);
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode();
// FIXME: set an appropriate error
return;
}
qCDebug(dcZigbeeNetwork()) << "Set permit join configuration request finished" << reply->statusCode();
setState(StateRunning);
});
} else if (m_controller->networkState() == Deconz::NetworkStateOffline) {
m_initializing = true;
qCDebug(dcZigbeeNetwork()) << "The network is offline. Lets start it";
setCreateNetworkState(CreateNetworkStateStartNetwork);
} else {
// The network is not running yet, lets wait for the state changed
}
}
});
}); });
}); });
}); });
@ -516,8 +570,8 @@ void ZigbeeNetworkDeconz::startNetworkInternally()
m_createNewNetwork = false; m_createNewNetwork = false;
// Check if we have to create a pan ID and select the channel // Check if we have to create a pan ID and select the channel
if (panId() == 0 || !m_coordinatorNode) { if (panId() == 0 || !m_coordinatorNode) {
qCDebug(dcZigbeeNetwork()) << "Generate new extended PAN ID..."; setPanId(ZigbeeUtils::generateRandomPanId());
setExtendedPanId(ZigbeeUtils::generateRandomPanId()); qCDebug(dcZigbeeNetwork()) << "Generated new extended PAN ID" << panId() << ZigbeeUtils::convertUint16ToHexString(panId());
m_createNewNetwork = true; m_createNewNetwork = true;
} }
@ -566,8 +620,10 @@ void ZigbeeNetworkDeconz::onPollNetworkStateTimeout()
m_controller->processDeviceState(m_controller->parseDeviceStateFlag(deviceStateFlag)); m_controller->processDeviceState(m_controller->parseDeviceStateFlag(deviceStateFlag));
if (m_controller->networkState() == Deconz::NetworkStateOffline) { if (m_controller->networkState() == Deconz::NetworkStateOffline) {
qCDebug(dcZigbeeNetwork()) << "Network stopped successfully for creation"; qCDebug(dcZigbeeNetwork()) << "Network stopped successfully for creation";
// The network is now offline, continue with the state machine // The network is now offline, continue with the state machine in one second (some grace period after network shutdown)
setCreateNetworkState(CreateNetworkStateWriteConfiguration); QTimer::singleShot(1000, this, [=](){
setCreateNetworkState(CreateNetworkStateWriteConfiguration);
});
} else { } else {
// Not offline yet, continue poll // Not offline yet, continue poll
m_pollNetworkStateTimer->start(); m_pollNetworkStateTimer->start();
@ -672,7 +728,8 @@ void ZigbeeNetworkDeconz::stopNetwork()
void ZigbeeNetworkDeconz::reset() void ZigbeeNetworkDeconz::reset()
{ {
// TODO qCDebug(dcZigbeeNetwork()) << "Reboot the controller. The stack will perform a restart.";
m_controller->rebootController();
} }
void ZigbeeNetworkDeconz::factoryResetNetwork() void ZigbeeNetworkDeconz::factoryResetNetwork()

View File

@ -65,6 +65,8 @@ private:
CreateNetworkState m_createState = CreateNetworkStateIdle; CreateNetworkState m_createState = CreateNetworkStateIdle;
bool m_createNewNetwork = false; bool m_createNewNetwork = false;
bool m_initializing = false; bool m_initializing = false;
QString m_protocolVersion;
QString m_firmwareVersion;
QHash<quint8, ZigbeeNetworkReply *> m_pendingReplies; QHash<quint8, ZigbeeNetworkReply *> m_pendingReplies;

View File

@ -290,10 +290,10 @@ QString ZigbeeUtils::profileIdToString(const Zigbee::ZigbeeProfile &profileId)
return profileName; return profileName;
} }
quint64 ZigbeeUtils::generateRandomPanId() quint16 ZigbeeUtils::generateRandomPanId()
{ {
// Note: the PAN ID has to be between 0x0000 and 0x3fff // Note: the PAN ID has to be between 0x0000 and 0x3fff
return static_cast<quint64>(rand() % (0x3fff - 1) + 1); return static_cast<quint16>(rand() % (0x3fff - 1) + 1);
} }
QPointF ZigbeeUtils::convertColorToXY(const QColor &color) QPointF ZigbeeUtils::convertColorToXY(const QColor &color)

View File

@ -69,7 +69,7 @@ public:
static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId); static QString profileIdToString(const Zigbee::ZigbeeProfile &profileId);
// Generate random data // Generate random data
static quint64 generateRandomPanId(); static quint16 generateRandomPanId();
// Color converter // Color converter