Fix initialization error due to timeout issue and improve debugging

This commit is contained in:
Simon Stürz 2020-12-02 12:03:44 +01:00
parent 4e8254fcb9
commit 1eed81562a
9 changed files with 90 additions and 43 deletions

View File

@ -68,7 +68,8 @@ public:
StatusProtocolError = 0x01, StatusProtocolError = 0x01,
StatusUnknownCommand = 0x02, StatusUnknownCommand = 0x02,
StatusInvalidCrc = 0x03, StatusInvalidCrc = 0x03,
StatusStackError = 0x04 StatusStackError = 0x04,
StatusTimeout = 0xff
}; };
Q_ENUM(Status) Q_ENUM(Status)

View File

@ -98,6 +98,8 @@ void ZigbeeInterfaceNxpReply::setFinished()
void ZigbeeInterfaceNxpReply::onTimeout() void ZigbeeInterfaceNxpReply::onTimeout()
{ {
m_timeout = true; m_timeout = true;
m_status = Nxp::StatusTimeout;
emit timeout(); emit timeout();
emit finished(); emit finished();
} }

View File

@ -71,7 +71,7 @@ private:
QByteArray m_requestData; QByteArray m_requestData;
// Response content // Response content
Nxp::Status m_status = Nxp::StatusUnknownCommand; // FIXME Nxp::Status m_status = Nxp::StatusUnknownCommand;
QByteArray m_responseData; QByteArray m_responseData;
void setFinished(); void setFinished();

View File

@ -94,6 +94,7 @@ ZigbeeNetworkReply *ZigbeeNetworkNxp::sendRequest(const ZigbeeNetworkRequest &re
// Enqueu reply and send next one if we have enouth capacity // Enqueu reply and send next one if we have enouth capacity
m_replyQueue.enqueue(reply); m_replyQueue.enqueue(reply);
qCDebug(dcZigbeeNetwork()) << "=== Pending replies count (enqueued)" << m_replyQueue.count();
sendNextReply(); sendNextReply();
return reply; return reply;
@ -181,6 +182,8 @@ void ZigbeeNetworkNxp::sendNextReply()
ZigbeeNetworkReply *reply = m_replyQueue.dequeue(); ZigbeeNetworkReply *reply = m_replyQueue.dequeue();
qCDebug(dcZigbeeNetwork()) << "=== Pending replies count (dequeued)" << m_replyQueue.count();
ZigbeeInterfaceNxpReply *interfaceReply = m_controller->requestSendRequest(reply->request()); ZigbeeInterfaceNxpReply *interfaceReply = m_controller->requestSendRequest(reply->request());
connect(interfaceReply, &ZigbeeInterfaceNxpReply::finished, reply, [this, reply, interfaceReply](){ connect(interfaceReply, &ZigbeeInterfaceNxpReply::finished, reply, [this, reply, interfaceReply](){
if (interfaceReply->status() != Nxp::StatusSuccess) { if (interfaceReply->status() != Nxp::StatusSuccess) {
@ -246,7 +249,6 @@ ZigbeeNetworkReply *ZigbeeNetworkNxp::requestSetPermitJoin(quint16 shortAddress,
bool ZigbeeNetworkNxp::processVersionReply(ZigbeeInterfaceNxpReply *reply) bool ZigbeeNetworkNxp::processVersionReply(ZigbeeInterfaceNxpReply *reply)
{ {
qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status(); qCDebug(dcZigbeeNetwork()) << "Version reply finished" << reply->status();
if (reply->timendOut()) { if (reply->timendOut()) {
m_reconnectCounter++; m_reconnectCounter++;
if (m_reconnectCounter >= 3) { if (m_reconnectCounter >= 3) {
@ -271,7 +273,9 @@ bool ZigbeeNetworkNxp::processVersionReply(ZigbeeInterfaceNxpReply *reply)
qCWarning(dcZigbeeNetwork()) << "Failed to read firmware version. Retry" << m_reconnectCounter << "/ 3"; qCWarning(dcZigbeeNetwork()) << "Failed to read firmware version. Retry" << m_reconnectCounter << "/ 3";
ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion(); ZigbeeInterfaceNxpReply *reply = m_controller->requestVersion();
connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){ connect(reply, &ZigbeeInterfaceNxpReply::finished, this, [this, reply](){
processVersionReply(reply); if (processVersionReply(reply)) {
m_controller->refreshControllerState();
}
}); });
return false; return false;
@ -436,22 +440,25 @@ void ZigbeeNetworkNxp::onControllerStateChanged(ZigbeeBridgeControllerNxp::Contr
connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){ connect(coordinatorNode, &ZigbeeNode::stateChanged, this, [this, coordinatorNode](ZigbeeNode::State state){
if (state == ZigbeeNode::StateInitialized) { if (state == ZigbeeNode::StateInitialized) {
qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode; qCDebug(dcZigbeeNetwork()) << "Coordinator initialized successfully." << coordinatorNode;
// ZigbeeClusterGroups *groupsCluster = coordinatorNode->getEndpoint(0x01)->inputCluster<ZigbeeClusterGroups>(ZigbeeClusterLibrary::ClusterIdGroups); /* Note: this currently has been hardcoded into the firmware. TODO: implement appropriate method for binding coordinator to group
// if (!groupsCluster) {
// qCWarning(dcZigbeeNetwork()) << "Failed to get groups cluster from coordinator. The coordinator will not be in default group 0x0000";
// setState(StateRunning);
// setPermitJoining(0);
// return;
// }
// ZigbeeClusterReply *reply = groupsCluster->addGroup(0x0000, "Default"); ZigbeeClusterGroups *groupsCluster = coordinatorNode->getEndpoint(0x01)->inputCluster<ZigbeeClusterGroups>(ZigbeeClusterLibrary::ClusterIdGroups);
// connect(reply, &ZigbeeClusterReply::finished, this, [=](){ if (!groupsCluster) {
// if (reply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeeNetwork()) << "Failed to get groups cluster from coordinator. The coordinator will not be in default group 0x0000";
// qCWarning(dcZigbeeNetwork()) << "Failed to add coordinator to default group 0x0000. The coordinator will not be in default group 0x0000"; setState(StateRunning);
// } setPermitJoining(0);
// setState(StateRunning); return;
// setPermitJoining(0); }
// });
ZigbeeClusterReply *reply = groupsCluster->addGroup(0x0000, "Default");
connect(reply, &ZigbeeClusterReply::finished, this, [=](){
if (reply->error() != ZigbeeClusterReply::ErrorNoError) {
qCWarning(dcZigbeeNetwork()) << "Failed to add coordinator to default group 0x0000. The coordinator will not be in default group 0x0000";
}
setState(StateRunning);
setPermitJoining(0);
});
*/
setState(StateRunning); setState(StateRunning);
setPermitJoining(0); setPermitJoining(0);
@ -613,8 +620,10 @@ void ZigbeeNetworkNxp::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress iee
setNodeReachable(node, true); setNodeReachable(node, true);
return; return;
} else { } else {
qCDebug(dcZigbeeNetwork()) << "Already known device announced with different network address. Removing node and reinitialize..."; qCWarning(dcZigbeeNetwork()) << "Already known device announced with different network address. FIXME: update the network address or reinitialize node...";
removeNode(node);
//removeNode(node);
} }
} }

View File

@ -211,9 +211,10 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestSimpleDescriptor(quint8 endp
return zdoReply; return zdoReply;
} }
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindShortAddress(quint8 sourceEndpointId, quint16 clusterId, quint16 destinationAddress) ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindGroupAddress(quint8 sourceEndpointId, quint16 clusterId, quint16 destinationAddress)
{ {
qCDebug(dcZigbeeDeviceObject()) << "Request bind short address from" << m_node << "endpoint" << clusterId << "to" << destinationAddress; qCDebug(dcZigbeeDeviceObject()) << "Request bind group address from" << m_node << "endpoint" << ZigbeeUtils::convertByteToHexString(sourceEndpointId)
<< static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId) << "to group" << ZigbeeUtils::convertUint16ToHexString(destinationAddress);
// Build APS request // Build APS request
ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::BindRequest); ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::BindRequest);
@ -260,7 +261,9 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindShortAddress(quint8 sour
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindIeeeAddress(quint8 sourceEndpointId, quint16 clusterId, const ZigbeeAddress &destinationIeeeAddress, quint8 destinationEndpointId) ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindIeeeAddress(quint8 sourceEndpointId, quint16 clusterId, const ZigbeeAddress &destinationIeeeAddress, quint8 destinationEndpointId)
{ {
qCDebug(dcZigbeeDeviceObject()) << "Request bind ieee address from" << m_node << "endpoint" << clusterId << "to" << destinationIeeeAddress.toString() << destinationEndpointId; qCDebug(dcZigbeeDeviceObject()) << "Request bind IEEE address from" << m_node << "endpoint" << ZigbeeUtils::convertByteToHexString(sourceEndpointId)
<< static_cast<ZigbeeClusterLibrary::ClusterId>(clusterId) << "to" << destinationIeeeAddress.toString() << "endpoint"
<< ZigbeeUtils::convertByteToHexString(destinationEndpointId);
// Build APS request // Build APS request
ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::BindRequest); ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::BindRequest);
@ -358,6 +361,49 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestUnbind(const ZigbeeDevicePro
return zdoReply; return zdoReply;
} }
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindRegister(const ZigbeeAddress &ieeeAddress)
{
qCDebug(dcZigbeeDeviceObject()) << "Request bind register" << m_node << ieeeAddress.toString();
// Build APS request
ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::BindRegisterRequest);
// Generate a new transaction sequence number for this device object
quint8 transactionSequenceNumber = m_transactionSequenceNumber++;
// Build ZDO frame
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << transactionSequenceNumber;
stream << ieeeAddress.toUInt64();
// Set the ZDO frame as APS request payload
request.setAsdu(asdu);
// Create the device object reply and wait for the response indication
ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber);
// Send the request, on finished read the confirm information
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){
if (!verifyNetworkError(zdoReply, networkReply)) {
finishZdoReply(zdoReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zdoReply->isComplete()) {
finishZdoReply(zdoReply);
return;
}
// We received the confirmation but not yet the indication
});
return zdoReply;
}
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLeaveNetwork(bool rejoin, bool removeChildren) ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLeaveNetwork(bool rejoin, bool removeChildren)
{ {
qCDebug(dcZigbeeDeviceObject()) << "Request management leave network from" << m_node << "rejoin" << rejoin << "remove children" << removeChildren; qCDebug(dcZigbeeDeviceObject()) << "Request management leave network from" << m_node << "rejoin" << rejoin << "remove children" << removeChildren;
@ -442,17 +488,6 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLqi(quint8 startIndex)
// Now check if the expected indication response received already // Now check if the expected indication response received already
if (zdoReply->isComplete()) { if (zdoReply->isComplete()) {
qCDebug(dcZigbeeDeviceObject()) << "Successfully received response for" << static_cast<ZigbeeDeviceProfile::ZdoCommand>(networkReply->request().clusterId()); qCDebug(dcZigbeeDeviceObject()) << "Successfully received response for" << static_cast<ZigbeeDeviceProfile::ZdoCommand>(networkReply->request().clusterId());
// TODO: pars child table
// QByteArray response = zdoReply->responseAdpu().payload;
// QDataStream stream(&response, QIODevice::ReadOnly);
// stream.setByteOrder(QDataStream::LittleEndian);
// quint8 statusValue; quint8 tableEntries; quint8 startIndex;
// ZigbeeDeviceProfile::Status status;
finishZdoReply(zdoReply); finishZdoReply(zdoReply);
return; return;
} }

View File

@ -50,10 +50,10 @@ public:
// TODO: implement other device and service discovery methods // TODO: implement other device and service discovery methods
// End device binding // End device binding
ZigbeeDeviceObjectReply *requestBindShortAddress(quint8 sourceEndpointId, quint16 clusterId, quint16 destinationAddress); ZigbeeDeviceObjectReply *requestBindGroupAddress(quint8 sourceEndpointId, quint16 clusterId, quint16 destinationAddress);
ZigbeeDeviceObjectReply *requestBindIeeeAddress(quint8 sourceEndpointId, quint16 clusterId, const ZigbeeAddress &destinationIeeeAddress, quint8 destinationEndpointId); ZigbeeDeviceObjectReply *requestBindIeeeAddress(quint8 sourceEndpointId, quint16 clusterId, const ZigbeeAddress &destinationIeeeAddress, quint8 destinationEndpointId);
ZigbeeDeviceObjectReply *requestUnbind(const ZigbeeDeviceProfile::BindingTableListRecord &bindingRecord); ZigbeeDeviceObjectReply *requestUnbind(const ZigbeeDeviceProfile::BindingTableListRecord &bindingRecord);
ZigbeeDeviceObjectReply *requestBindRegister(const ZigbeeAddress &ieeeAddress);
// Management request // Management request
ZigbeeDeviceObjectReply *requestMgmtLeaveNetwork(bool rejoin = false, bool removeChildren = false); ZigbeeDeviceObjectReply *requestMgmtLeaveNetwork(bool rejoin = false, bool removeChildren = false);

View File

@ -197,7 +197,7 @@ ZigbeeDeviceProfile::Adpu ZigbeeDeviceProfile::parseAdpu(const QByteArray &adpu)
QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu) QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::Adpu &deviceAdpu)
{ {
debug.nospace() << "DeviceAdpu(SQN: " << deviceAdpu.transactionSequenceNumber << ", "; debug.nospace() << "DeviceProfileAdpu(SQN: " << deviceAdpu.transactionSequenceNumber << ", ";
debug.nospace() << deviceAdpu.status << ", "; debug.nospace() << deviceAdpu.status << ", ";
debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", "; debug.nospace() << ZigbeeUtils::convertUint16ToHexString(deviceAdpu.addressOfInterest) << ", ";
debug.nospace() << "Payload: " << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")"; debug.nospace() << "Payload: " << ZigbeeUtils::convertByteArrayToHexString(deviceAdpu.payload) << ")";
@ -210,12 +210,12 @@ QDebug operator<<(QDebug debug, const ZigbeeDeviceProfile::NodeDescriptor &nodeD
debug.nospace() << " Complex descriptor available: " << nodeDescriptor.complexDescriptorAvailable << "\n"; debug.nospace() << " Complex descriptor available: " << nodeDescriptor.complexDescriptorAvailable << "\n";
debug.nospace() << " User descriptor available: " << nodeDescriptor.userDescriptorAvailable << "\n"; debug.nospace() << " User descriptor available: " << nodeDescriptor.userDescriptorAvailable << "\n";
debug.nospace() << " " << nodeDescriptor.frequencyBand << "\n"; debug.nospace() << " " << nodeDescriptor.frequencyBand << "\n";
debug.nospace() << " " << nodeDescriptor.macCapabilities; debug.nospace() << " " << nodeDescriptor.macCapabilities << "\n";
debug.nospace() << " Manufacturer code: " << ZigbeeUtils::convertUint16ToHexString(nodeDescriptor.manufacturerCode) << "(" << nodeDescriptor.manufacturerCode << ")" << "\n"; debug.nospace() << " Manufacturer code: " << ZigbeeUtils::convertUint16ToHexString(nodeDescriptor.manufacturerCode) << "(" << nodeDescriptor.manufacturerCode << ")" << "\n";
debug.nospace() << " Maximum buffer size: " << nodeDescriptor.maximumBufferSize << "\n"; debug.nospace() << " Maximum buffer size: " << nodeDescriptor.maximumBufferSize << "\n";
debug.nospace() << " Maximum RX size: " << nodeDescriptor.maximumRxSize << "\n"; debug.nospace() << " Maximum RX size: " << nodeDescriptor.maximumRxSize << "\n";
debug.nospace() << " Maximum TX size: " << nodeDescriptor.maximumTxSize << "\n"; debug.nospace() << " Maximum TX size: " << nodeDescriptor.maximumTxSize << "\n";
debug.nospace() << " " << nodeDescriptor.serverMask; debug.nospace() << " " << nodeDescriptor.serverMask << "\n";
debug.nospace() << " " << nodeDescriptor.descriptorCapabilities; debug.nospace() << " " << nodeDescriptor.descriptorCapabilities;
return debug; return debug;
} }

View File

@ -292,7 +292,6 @@ public:
static MacCapabilities parseMacCapabilities(quint8 macCapabilitiesFlag); static MacCapabilities parseMacCapabilities(quint8 macCapabilitiesFlag);
static ServerMask parseServerMask(quint16 serverMaskFlag); static ServerMask parseServerMask(quint16 serverMaskFlag);
static DescriptorCapabilities parseDescriptorCapabilities(quint8 descriptorCapabilitiesFlag); static DescriptorCapabilities parseDescriptorCapabilities(quint8 descriptorCapabilitiesFlag);
static PowerDescriptor parsePowerDescriptor(quint16 powerDescriptorFlag); static PowerDescriptor parsePowerDescriptor(quint16 powerDescriptorFlag);
}; };

View File

@ -691,8 +691,9 @@ void ZigbeeNetwork::evaluateNodeReachableStates()
// Note: sleeping devices should send some message within 6 hours, // Note: sleeping devices should send some message within 6 hours,
// otherwise the device might not be reachable any more // otherwise the device might not be reachable any more
int msSinceLastSeen = node->lastSeen().msecsTo(QDateTime::currentDateTimeUtc()); int msSinceLastSeen = node->lastSeen().msecsTo(QDateTime::currentDateTimeUtc());
qCDebug(dcZigbeeNetwork()) << node << "last seen" << QTime::fromMSecsSinceStartOfDay(msSinceLastSeen).toString(); qCDebug(dcZigbeeNetwork()) << node << "has been seen the last time" << QTime::fromMSecsSinceStartOfDay(msSinceLastSeen).toString() << "ago.";
if (msSinceLastSeen < 1000*60*60*6) { // 6 Hours = 6 * 60 * 60 * 1000 = 21600000 ms
if (msSinceLastSeen < 21600000) {
setNodeReachable(node, true); setNodeReachable(node, true);
} else { } else {
setNodeReachable(node, false); setNodeReachable(node, false);