diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp index b04fed2..0e3302e 100644 --- a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp @@ -714,11 +714,7 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceState) { - qCDebug(dcZigbeeController()) << "Device state changed notification:" << deviceState.networkState - << "ASPDE-DATA.confirm:" << deviceState.aspDataConfirm - << "ASPDE-DATA.indication:" << deviceState.aspDataIndication - << "configuration changed:" << deviceState.configurationChanged - << "ASPDE-DATA.request free slots:" << deviceState.aspDataRequestFreeSlots; + qCDebug(dcZigbeeController()) << deviceState; if (m_networkState != deviceState.networkState) { qCDebug(dcZigbeeController()) << "Network state changed" << deviceState.networkState; @@ -729,13 +725,15 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt if (m_aspFreeSlotsAvailable != deviceState.aspDataRequestFreeSlots) { m_aspFreeSlotsAvailable = deviceState.aspDataRequestFreeSlots; - // FIXME: if true, send next asp request + // FIXME: if changed to true, send next asp data request } + if (m_networkState != Deconz::NetworkStateConnected) + return; - // Check if we have to fech new data - if (deviceState.aspDataConfirm) { + // Check if we have to read a data indication message + if (deviceState.aspDataIndication) { ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication(); connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ if (reply->statusCode() != Deconz::StatusCodeSuccess) { @@ -744,77 +742,133 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt return; } - // ASP data indication received - QDataStream stream(reply->responseData()); - stream.setByteOrder(QDataStream::LittleEndian); - quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 destinationAddressModeFlag = 0; - quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0; - quint8 sourceAddressModeFlag = 0; quint16 sourceShortAddress = 0; quint64 sourceIeeeAddress = 0; quint8 sourceEndpoint = 0; - quint16 profileId = 0; quint16 clusterId = 0; quint16 asduLength = 0; QByteArray asdu; quint8 reserved = 0; - quint8 lqi = 0; qint8 rssi = 0; - - stream >> payloadLenght >> deviceStateFlag >> destinationAddressModeFlag; - Zigbee::DestinationAddressMode destinationAddressMode = static_cast(destinationAddressModeFlag); - if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) - stream >> destinationShortAddress; - - if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) - stream >> destinationIeeeAddress; - - stream >> destinationEndpoint >> sourceAddressModeFlag; - - Zigbee::SourceAddressMode sourceAddressMode = static_cast(sourceAddressModeFlag); - if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - stream >> sourceShortAddress; - - if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - stream >> sourceIeeeAddress; - - stream >> sourceEndpoint >> profileId >> clusterId >> asduLength; - - // Fill asdu data - for (int i = 0; i < asduLength; i++) { - quint8 byte = 0; - stream >> byte; - asdu.append(static_cast(byte)); - } - - stream >> reserved >> reserved >> lqi >> reserved >> reserved >> reserved >> reserved >> rssi; - - - qCDebug(dcZigbeeController()) << "Data indication received:"; - qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode; - if (destinationAddressMode == Zigbee::DestinationAddressModeGroup) - qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); - - if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) - qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); - - if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) - qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); - - qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); - - qCDebug(dcZigbeeController()) << " Source address mode:" << sourceAddressMode; - if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - qCDebug(dcZigbeeController()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceShortAddress); - - if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) - qCDebug(dcZigbeeController()) << " Source IEEE address:" << ZigbeeAddress(sourceIeeeAddress).toString(); - - - qCDebug(dcZigbeeController()) << " Source endpoint:" << ZigbeeUtils::convertByteToHexString(sourceEndpoint); - qCDebug(dcZigbeeController()) << " Profile:" << static_cast(profileId); - qCDebug(dcZigbeeController()) << " Cluster:" << static_cast(clusterId); - qCDebug(dcZigbeeController()) << " ASDU:" << ZigbeeUtils::convertByteArrayToHexString(asdu); - qCDebug(dcZigbeeController()) << " LQI:" << lqi; - qCDebug(dcZigbeeController()) << " RSSI:" << rssi << "dBm"; - - processDeviceState(parseDeviceStateFlag(deviceStateFlag)); + // ASP data indication received, process the content + qCDebug(dcZigbeeController()) << "Reading data indication finished successfully"; + processDataIndication(reply->responseData()); }); } + // Check if we have a response to read for a request + if (deviceState.aspDataConfirm) { + ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm(); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not read data indication." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + // ASP data indication received, process the content + qCDebug(dcZigbeeController()) << "Reading data confirm finished successfully"; + processDataConfirm(reply->responseData()); + }); + } + +} + +void ZigbeeBridgeControllerDeconz::processDataIndication(const QByteArray &data) +{ + // ASP data indication + QDataStream stream(data); + stream.setByteOrder(QDataStream::LittleEndian); + quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 destinationAddressModeFlag = 0; + quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0; + quint8 sourceAddressModeFlag = 0; quint16 sourceShortAddress = 0; quint64 sourceIeeeAddress = 0; quint8 sourceEndpoint = 0; + quint16 profileId = 0; quint16 clusterId = 0; quint16 asduLength = 0; QByteArray asdu; quint8 reserved = 0; + quint8 lqi = 0; qint8 rssi = 0; + + stream >> payloadLenght >> deviceStateFlag >> destinationAddressModeFlag; + Zigbee::DestinationAddressMode destinationAddressMode = static_cast(destinationAddressModeFlag); + if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + stream >> destinationShortAddress; + + if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + stream >> destinationIeeeAddress; + + stream >> destinationEndpoint >> sourceAddressModeFlag; + + Zigbee::SourceAddressMode sourceAddressMode = static_cast(sourceAddressModeFlag); + if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) + stream >> sourceShortAddress; + + if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) + stream >> sourceIeeeAddress; + + stream >> sourceEndpoint >> profileId >> clusterId >> asduLength; + + // Fill asdu data + for (int i = 0; i < asduLength; i++) { + quint8 byte = 0; + stream >> byte; + asdu.append(static_cast(byte)); + } + + stream >> reserved >> reserved >> lqi >> reserved >> reserved >> reserved >> reserved >> rssi; + + // Print the information for debugging + qCDebug(dcZigbeeController()) << "Data indication received:"; + qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode; + if (destinationAddressMode == Zigbee::DestinationAddressModeGroup) + qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + + if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + + if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); + + qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); + + qCDebug(dcZigbeeController()) << " Source address mode:" << sourceAddressMode; + if (sourceAddressMode == Zigbee::SourceAddressModeShortAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) + qCDebug(dcZigbeeController()) << " Source address:" << ZigbeeUtils::convertUint16ToHexString(sourceShortAddress); + + if (sourceAddressMode == Zigbee::SourceAddressModeIeeeAddress || sourceAddressMode == Zigbee::SourceAddressModeShortAndIeeeAddress) + qCDebug(dcZigbeeController()) << " Source IEEE address:" << ZigbeeAddress(sourceIeeeAddress).toString(); + + + qCDebug(dcZigbeeController()) << " Source endpoint:" << ZigbeeUtils::convertByteToHexString(sourceEndpoint); + qCDebug(dcZigbeeController()) << " Profile:" << static_cast(profileId); + qCDebug(dcZigbeeController()) << " Cluster:" << static_cast(clusterId); + qCDebug(dcZigbeeController()) << " ASDU:" << ZigbeeUtils::convertByteArrayToHexString(asdu); + qCDebug(dcZigbeeController()) << " LQI:" << lqi; + qCDebug(dcZigbeeController()) << " RSSI:" << rssi << "dBm"; + + processDeviceState(parseDeviceStateFlag(deviceStateFlag)); +} + +void ZigbeeBridgeControllerDeconz::processDataConfirm(const QByteArray &data) +{ + QDataStream stream(data); + stream.setByteOrder(QDataStream::LittleEndian); + quint16 payloadLenght = 0; quint8 deviceStateFlag = 0; quint8 requestId = 0; quint8 destinationAddressMode = 0; + quint16 destinationShortAddress = 0; quint64 destinationIeeeAddress = 0; quint8 destinationEndpoint = 0; + quint8 sourceEndpoint = 0; quint8 zigbeeConfirmStatus = 0; + + stream >> payloadLenght >> deviceStateFlag >> requestId >> destinationAddressMode; + if (destinationAddressMode == Zigbee::DestinationAddressModeGroup || destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + stream >> destinationShortAddress; + + if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + stream >> destinationIeeeAddress; + + stream >> destinationEndpoint >> sourceEndpoint >> zigbeeConfirmStatus; + + // Print the information for debugging + qCDebug(dcZigbeeController()) << "Data confirm received: Request" << requestId; + qCDebug(dcZigbeeController()) << " Destination address mode:" << destinationAddressMode; + if (destinationAddressMode == Zigbee::DestinationAddressModeGroup) + qCDebug(dcZigbeeController()) << " Destination address (group):" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + + if (destinationAddressMode == Zigbee::DestinationAddressModeShortAddress) + qCDebug(dcZigbeeController()) << " Destination short address:" << ZigbeeUtils::convertUint16ToHexString(destinationShortAddress); + + if (destinationAddressMode == Zigbee::DestinationAddressModeIeeeAddress) + qCDebug(dcZigbeeController()) << " Destination IEEE address:" << ZigbeeAddress(destinationIeeeAddress).toString(); + + qCDebug(dcZigbeeController()) << " Destination endpoint" << ZigbeeUtils::convertByteToHexString(destinationEndpoint); + qCDebug(dcZigbeeController()) << " Source endpoint" << ZigbeeUtils::convertByteToHexString(sourceEndpoint); + qCDebug(dcZigbeeController()) << " Confirm status" << static_cast(zigbeeConfirmStatus); } void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available) @@ -903,3 +957,28 @@ void ZigbeeBridgeControllerDeconz::disable() { m_interface->disable(); } + +QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState) +{ + debug.nospace() << "DeviceState("; + switch (deviceState.networkState) { + case Deconz::NetworkStateJoining: + debug.nospace() << "Joining, "; + break; + case Deconz::NetworkStateLeaving: + debug.nospace() << "Leaving, "; + break; + case Deconz::NetworkStateOffline: + debug.nospace() << "Offline, "; + break; + case Deconz::NetworkStateConnected: + debug.nospace() << "Connected, "; + break; + } + + debug.nospace() << "Confirm=" << static_cast(deviceState.aspDataConfirm) << ", "; + debug.nospace() << "Indication=" << static_cast(deviceState.aspDataIndication) << ", "; + debug.nospace() << "ConfigChanged=" << static_cast(deviceState.configurationChanged) << ", "; + debug.nospace() << "CanSend=" << deviceState.aspDataRequestFreeSlots << ")"; + return debug.space(); +} diff --git a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h index 5833773..426b70b 100644 --- a/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h +++ b/libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h @@ -70,8 +70,6 @@ typedef struct DeconzDeviceState { bool aspDataRequestFreeSlots = false; } DeconzDeviceState; - - class ZigbeeBridgeControllerDeconz : public ZigbeeBridgeController { Q_OBJECT @@ -93,6 +91,7 @@ public: ZigbeeInterfaceDeconzReply *requestWriteParameter(Deconz::Parameter parameter, const QByteArray &data); ZigbeeInterfaceDeconzReply *requestChangeNetworkState(Deconz::NetworkState networkState); + // Receive data ZigbeeInterfaceDeconzReply *requestReadReceivedDataIndication(Deconz::SourceAddressMode sourceAddressMode = Deconz::SourceAddressModeShortSourceAddress); ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm(); @@ -101,7 +100,6 @@ public: ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, Zigbee::ZigbeeProfile profileId, Zigbee::ClusterId clusterId, quint8 sourceEndpoint, const QByteArray &asdu, quint8 radius = 0); - private: ZigbeeInterfaceDeconz *m_interface = nullptr; quint8 m_sequenceNumber = 0; @@ -126,6 +124,9 @@ private: DeconzDeviceState parseDeviceStateFlag(quint8 deviceStateFlag); void processDeviceState(DeconzDeviceState deviceState); + void processDataIndication(const QByteArray &data); + void processDataConfirm(const QByteArray &data); + signals: void networkStateChanged(Deconz::NetworkState networkState); void networkConfigurationParameterChanged(const DeconzNetworkConfiguration &networkConfiguration); @@ -141,4 +142,7 @@ public slots: void disable(); }; +QDebug operator<<(QDebug debug, const DeconzDeviceState &deviceState); + + #endif // ZIGBEEBRIDGECONTROLLERDECONZ_H diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp index a013b16..45079c1 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp @@ -37,6 +37,11 @@ ZigbeeNetworkDeconz::ZigbeeNetworkDeconz(QObject *parent) : m_controller = new ZigbeeBridgeControllerDeconz(this); //connect(m_controller, &ZigbeeBridgeControllerDeconz::messageReceived, this, &ZigbeeNetworkDeconz::onMessageReceived); connect(m_controller, &ZigbeeBridgeControllerDeconz::availableChanged, this, &ZigbeeNetworkDeconz::onControllerAvailableChanged); + + m_pollNetworkStateTimer = new QTimer(this); + m_pollNetworkStateTimer->setInterval(1000); + m_pollNetworkStateTimer->setSingleShot(false); + connect(m_pollNetworkStateTimer, &QTimer::timeout, this, &ZigbeeNetworkDeconz::onPollNetworkStateTimeout); } ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const @@ -47,11 +52,194 @@ ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const return nullptr; } +void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetworkState state) +{ + if (m_createState == state) + return; + + m_createState = state; + qCDebug(dcZigbeeNetwork()) << "Create network state changed" << m_createState; + + switch (m_createState) { + case CreateNetworkStateIdle: + + break; + case CreateNetworkStateStopNetwork: { + ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateOffline); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not stop network for creating a new one." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + // Start polling the device state, should be Online -> Leaving -> Offline + m_pollNetworkStateTimer->start(); + }); + break; + } + case CreateNetworkStateWriteConfiguration: { + // - Set coordinator + // - Set channel mask + // - Set APS extended PANID (zero to reset) + // - Set trust center address (coordinator address) + // - Set security mode + // - Set network key + + QByteArray paramData; + QDataStream stream(¶mData, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(Deconz::NodeTypeCoordinator); + qCDebug(dcZigbeeNetwork()) << "Configure bridge to" << Deconz::NodeTypeCoordinator; + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterNodeType, paramData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterNodeType << Deconz::NodeTypeCoordinator << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Configured successfully bridge to" << Deconz::NodeTypeCoordinator; + + QByteArray paramData; + QDataStream stream(¶mData, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(channelMask().toUInt32()); + qCDebug(dcZigbeeNetwork()) << "Configure channel mask" << channelMask(); + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterChannelMask, paramData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterChannelMask << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Configured channel mask successfully"; + + QByteArray paramData; + QDataStream stream(¶mData, QIODevice::WriteOnly); + stream << static_cast(0); + stream.setByteOrder(QDataStream::LittleEndian); + qCDebug(dcZigbeeNetwork()) << "Configure APS extended PANID" << 0; + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterApsExtendedPanId, paramData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterApsExtendedPanId << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Configured APS extended PANID successfully"; + + QByteArray paramData; + QDataStream stream(¶mData, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << m_controller->networkConfiguration().ieeeAddress.toUInt64(); + qCDebug(dcZigbeeNetwork()) << "Configure trust center address" << m_controller->networkConfiguration().ieeeAddress.toString(); + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterTrustCenterAddress, paramData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterTrustCenterAddress << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Configured trust center address successfully"; + + QByteArray paramData; + QDataStream stream(¶mData, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(Deconz::SecurityModeNoMasterButTrustCenterKey); + qCDebug(dcZigbeeNetwork()) << "Configure security mode" << Deconz::SecurityModeNoMasterButTrustCenterKey; + ZigbeeInterfaceDeconzReply *reply = m_controller->requestWriteParameter(Deconz::ParameterSecurityMode, paramData); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterSecurityMode << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Configured security mode successfully"; + + + 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](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not write parameter" << Deconz::ParameterNetworkKey << reply->statusCode(); + // FIXME: set an appropriate error + // Note: writing the network key fails all the time... + //return; + } else { + qCDebug(dcZigbeeNetwork()) << "Configured network key successfully"; + } + + // Configuration finished, lets start the network + setCreateNetworkState(CreateNetworkStateStartNetwork); + }); + }); + }); + }); + }); + }); + break; + } + case CreateNetworkStateStartNetwork: { + ZigbeeInterfaceDeconzReply *reply = m_controller->requestChangeNetworkState(Deconz::NetworkStateConnected); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (reply->statusCode() != Deconz::StatusCodeSuccess) { + qCWarning(dcZigbeeController()) << "Could not start network for creating a new one." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + // Start polling the device state, should be Online -> Leaving -> Offline + m_pollNetworkStateTimer->start(); + }); + break; + } + case CreateNetworkStateReadConfiguration: { + // 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." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully."; + + setPanId(m_controller->networkConfiguration().panId); + setExtendedPanId(m_controller->networkConfiguration().extendedPanId); + setChannel(m_controller->networkConfiguration().currentChannel); + + setCreateNetworkState(CreateNetworkStateInitializeCoordinatorNode); + + }); + break; + } + case CreateNetworkStateInitializeCoordinatorNode: { + ZigbeeNodeDeconz *coordinatorNode = qobject_cast(createNode(this)); + coordinatorNode->setShortAddress(m_controller->networkConfiguration().shortAddress); + coordinatorNode->setExtendedAddress(m_controller->networkConfiguration().ieeeAddress); + + // TODO: done when when node initialized + m_coordinatorNode = coordinatorNode; + addNode(coordinatorNode); + + setCreateNetworkState(CreateNetworkStateIdle); + setState(StateRunning); + + //addUnitializedNode(coordinatorNode); + //coordinatorNode->startInitialization(); + } + } +} + ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent) { - //FIXME - Q_UNUSED(parent) - return nullptr; + return new ZigbeeNodeDeconz(m_controller, parent); } void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining) @@ -64,11 +252,13 @@ void ZigbeeNetworkDeconz::startNetworkInternally() { qCDebug(dcZigbeeNetwork()) << "Start network internally"; + m_createNewNetwork = false; + // Check if we have to create a pan ID and select the channel - if (extendedPanId() == 0) { + if (panId() == 0) { m_createNewNetwork = true; - setExtendedPanId(ZigbeeUtils::generateRandomPanId()); - qCDebug(dcZigbeeNetwork()) << "Created new PAN ID:" << extendedPanId(); + //setExtendedPanId(ZigbeeUtils::generateRandomPanId()); + //qCDebug(dcZigbeeNetwork()) << "Created new PAN ID:" << extendedPanId(); } if (securityConfiguration().networkKey().isNull()) { @@ -79,7 +269,7 @@ void ZigbeeNetworkDeconz::startNetworkInternally() } qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().networkKey() << "network link key"; - qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().globalTrustCenterLinkKey() << "global trust center link key"; + qCDebug(dcZigbeeNetwork()) << "Using" << securityConfiguration().globalTrustCenterLinkKey() << "global trust center link key"; // - Read the firmware version @@ -115,8 +305,8 @@ void ZigbeeNetworkDeconz::startNetworkInternally() } qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully."; - QString protocolVersion = QString("%1.%2").arg(m_controller->networkConfiguration().protocolVersion & 0xFF00) - .arg(m_controller->networkConfiguration().protocolVersion & 0x00FF); + QString protocolVersion = QString("%1.%2").arg(m_controller->networkConfiguration().protocolVersion >> 8 & 0xFF) + .arg(m_controller->networkConfiguration().protocolVersion & 0xFF); m_controller->setFirmwareVersionString(QString("%1 - %2").arg(firmwareVersion).arg(protocolVersion)); @@ -137,39 +327,31 @@ void ZigbeeNetworkDeconz::startNetworkInternally() m_controller->processDeviceState(m_controller->parseDeviceStateFlag(deviceStateFlag)); if (m_createNewNetwork) { - // Write the configurations which need to be changed - createNetwork(); - - // Initialize coordinator node - - + 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."; setState(StateRunning); } - - - - } - }); - - - - - - - }); }); } void ZigbeeNetworkDeconz::createNetwork() { + // Set offline + setCreateNetworkState(CreateNetworkStateStopNetwork); + // Write configurations + + // Set online + + // Read configurations + + // Create and initialize coordinator node } void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available) @@ -190,6 +372,76 @@ void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available) } } +void ZigbeeNetworkDeconz::onPollNetworkStateTimeout() +{ + // Stop the timer and make the request + m_pollNetworkStateTimer->stop(); + + switch (m_createState) { + case CreateNetworkStateStopNetwork: { + 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." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; + QDataStream stream(reply->responseData()); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 deviceStateFlag = 0; + stream >> deviceStateFlag; + // Update the device state in the controller + m_controller->processDeviceState(m_controller->parseDeviceStateFlag(deviceStateFlag)); + if (m_controller->networkState() == Deconz::NetworkStateOffline) { + qCDebug(dcZigbeeNetwork()) << "Network stopped successfully for creation"; + // The network is now offline, continue with the state machine + setCreateNetworkState(CreateNetworkStateWriteConfiguration); + } else { + // Not offline yet, continue poll + m_pollNetworkStateTimer->start(); + } + }); + break; + } + case CreateNetworkStateStartNetwork: { + 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." << reply->statusCode(); + // FIXME: set an appropriate error + return; + } + + qCDebug(dcZigbeeNetwork()) << "Read device state finished successfully"; + QDataStream stream(reply->responseData()); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 deviceStateFlag = 0; + stream >> deviceStateFlag; + // Update the device state in the controller + m_controller->processDeviceState(m_controller->parseDeviceStateFlag(deviceStateFlag)); + if (m_controller->networkState() == Deconz::NetworkStateConnected) { + // The network is now online, continue with the state machine + setCreateNetworkState(CreateNetworkStateReadConfiguration); + } else if (m_controller->networkState() == Deconz::NetworkStateOffline) { + qCWarning(dcZigbeeNetwork()) << "Failed to start the network."; + setCreateNetworkState(CreateNetworkStateIdle); + setState(StateOffline); + setError(ErrorZigbeeError); + return; + } else { + // Not offline yet, continue poll + m_pollNetworkStateTimer->start(); + } + }); + break; + } + default: + break; + } +} + void ZigbeeNetworkDeconz::startNetwork() { loadNetwork(); @@ -231,5 +483,9 @@ void ZigbeeNetworkDeconz::reset() void ZigbeeNetworkDeconz::factoryResetNetwork() { - // Wipe settings, and reconfigure network + qCDebug(dcZigbeeNetwork()) << "Factory reset network and forget all information. This cannot be undone."; + clearSettings(); + setState(StateUninitialized); + qCDebug(dcZigbeeNetwork()) << "The factory reset is finished. Start restart with a fresh network."; + startNetwork(); } diff --git a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/deconz/zigbeenetworkdeconz.h index a0bd06e..d980d6e 100644 --- a/libnymea-zigbee/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/deconz/zigbeenetworkdeconz.h @@ -29,7 +29,9 @@ #define ZIGBEENETWORKDECONZ_H #include + #include "zigbeenetwork.h" +#include "zigbeenodedeconz.h" #include "zigbeechannelmask.h" #include "zigbeebridgecontrollerdeconz.h" @@ -37,17 +39,34 @@ class ZigbeeNetworkDeconz : public ZigbeeNetwork { Q_OBJECT public: + enum CreateNetworkState { + CreateNetworkStateIdle, + CreateNetworkStateStopNetwork, + CreateNetworkStateWriteConfiguration, + CreateNetworkStateStartNetwork, + CreateNetworkStateReadConfiguration, + CreateNetworkStateInitializeCoordinatorNode + }; + Q_ENUM(CreateNetworkState) + explicit ZigbeeNetworkDeconz(QObject *parent = nullptr); ZigbeeBridgeController *bridgeController() const override; + + private: ZigbeeBridgeControllerDeconz *m_controller = nullptr; bool m_networkRunning = false; + CreateNetworkState m_createState = CreateNetworkStateIdle; bool m_createNewNetwork = false; + QTimer *m_pollNetworkStateTimer = nullptr; + void setCreateNetworkState(CreateNetworkState state); + protected: ZigbeeNode *createNode(QObject *parent) override; + void setPermitJoiningInternal(bool permitJoining) override; void startNetworkInternally(); @@ -56,6 +75,7 @@ protected: private slots: void onControllerAvailableChanged(bool available); + void onPollNetworkStateTimeout(); public slots: void startNetwork() override; diff --git a/libnymea-zigbee/deconz/zigbeenodedeconz.cpp b/libnymea-zigbee/deconz/zigbeenodedeconz.cpp index 82dc748..8cfad5e 100644 --- a/libnymea-zigbee/deconz/zigbeenodedeconz.cpp +++ b/libnymea-zigbee/deconz/zigbeenodedeconz.cpp @@ -27,8 +27,42 @@ #include "zigbeenodedeconz.h" -ZigbeeNodeDeconz::ZigbeeNodeDeconz(QObject *parent) : - ZigbeeNode(parent) +ZigbeeNodeDeconz::ZigbeeNodeDeconz(ZigbeeBridgeControllerDeconz *controller, QObject *parent) : + ZigbeeNode(parent), + m_controller(controller) { } + +void ZigbeeNodeDeconz::leaveNetworkRequest(bool rejoin, bool removeChildren) +{ + Q_UNUSED(rejoin) + Q_UNUSED(removeChildren) +} + +void ZigbeeNodeDeconz::setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) +{ + Q_UNUSED(report) +} + +void ZigbeeNodeDeconz::startInitialization() +{ + /* Node initialisation steps (sequentially) + * - Node descriptor + * - Power descriptor + * - Active endpoints + * - for each endpoint do: + * - Simple descriptor request + * - for each endpoint + * - read basic cluster + */ + + +} + +ZigbeeNodeEndpoint *ZigbeeNodeDeconz::createNodeEndpoint(quint8 endpointId, QObject *parent) +{ + Q_UNUSED(endpointId) + Q_UNUSED(parent) + return nullptr; +} diff --git a/libnymea-zigbee/deconz/zigbeenodedeconz.h b/libnymea-zigbee/deconz/zigbeenodedeconz.h index ba3479f..f46d2e7 100644 --- a/libnymea-zigbee/deconz/zigbeenodedeconz.h +++ b/libnymea-zigbee/deconz/zigbeenodedeconz.h @@ -32,6 +32,7 @@ #include "zigbee.h" #include "zigbeenode.h" +#include "zigbeebridgecontrollerdeconz.h" class ZigbeeNodeDeconz : public ZigbeeNode { @@ -40,9 +41,21 @@ class ZigbeeNodeDeconz : public ZigbeeNode friend class ZigbeeNetworkDeconz; public: - explicit ZigbeeNodeDeconz(QObject *parent = nullptr); + explicit ZigbeeNodeDeconz(ZigbeeBridgeControllerDeconz *controller, QObject *parent = nullptr); + + void leaveNetworkRequest(bool rejoin = false, bool removeChildren = false) override; + +private: + ZigbeeBridgeControllerDeconz *m_controller = nullptr; + + void setClusterAttributeReport(const ZigbeeClusterAttributeReport &report) override; + +protected: + void startInitialization() override; + ZigbeeNodeEndpoint *createNodeEndpoint(quint8 endpointId, QObject *parent) override; + +private slots: -signals: }; diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index a939ddf..7a64985 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -23,6 +23,8 @@ SOURCES += \ zigbeechannelmask.cpp \ zigbeecluster.cpp \ zigbeeclusterattribute.cpp \ + zigbeedeviceobject.cpp \ + zigbeedeviceprofile.cpp \ zigbeemanufacturer.cpp \ zigbeenetwork.cpp \ zigbeenetworkkey.cpp \ @@ -30,6 +32,7 @@ SOURCES += \ zigbee.cpp \ loggingcategory.cpp \ zigbeenetworkreply.cpp \ + zigbeenetworkrequest.cpp \ zigbeenodeendpoint.cpp \ zigbeesecurityconfiguration.cpp \ zigbeeutils.cpp \ @@ -57,6 +60,8 @@ HEADERS += \ zigbeechannelmask.h \ zigbeecluster.h \ zigbeeclusterattribute.h \ + zigbeedeviceobject.h \ + zigbeedeviceprofile.h \ zigbeemanufacturer.h \ zigbeenetwork.h \ zigbeenetworkkey.h \ @@ -64,6 +69,7 @@ HEADERS += \ zigbee.h \ loggingcategory.h \ zigbeenetworkreply.h \ + zigbeenetworkrequest.h \ zigbeenodeendpoint.h \ zigbeesecurityconfiguration.h \ zigbeeutils.h \ diff --git a/libnymea-zigbee/zigbee.h b/libnymea-zigbee/zigbee.h index e130caf..4174437 100644 --- a/libnymea-zigbee/zigbee.h +++ b/libnymea-zigbee/zigbee.h @@ -41,6 +41,7 @@ class Zigbee public: enum ZigbeeProfile { + ZigbeeProfileDevice = 0x0000, ZigbeeProfileIndustrialPlantMonitoring = 0x0101, ZigbeeProfileHomeAutomation = 0x0104, ZigbeeProfileCommercialBuildingAutomation = 0x0105, diff --git a/libnymea-zigbee/zigbeeaddress.cpp b/libnymea-zigbee/zigbeeaddress.cpp index da96a16..fa72309 100644 --- a/libnymea-zigbee/zigbeeaddress.cpp +++ b/libnymea-zigbee/zigbeeaddress.cpp @@ -111,6 +111,6 @@ bool ZigbeeAddress::operator!=(const ZigbeeAddress &other) const QDebug operator<<(QDebug debug, const ZigbeeAddress &address) { - debug << address.toString(); - return debug; + debug.nospace() << address.toString(); + return debug.space(); } diff --git a/libnymea-zigbee/zigbeeadpu.cpp b/libnymea-zigbee/zigbeeadpu.cpp index ba0ae30..73d4a46 100644 --- a/libnymea-zigbee/zigbeeadpu.cpp +++ b/libnymea-zigbee/zigbeeadpu.cpp @@ -32,25 +32,44 @@ ZigbeeAdpu::ZigbeeAdpu(QObject *parent) : QObject(parent) } -quint8 ZigbeeAdpu::buildFrameControl(ZigbeeAdpu::FrameType frameType, ZigbeeAdpu::DeliveryMode deliveryMode, bool apsAckFormat, bool securitySubField, bool acknowledgementRequest, bool extendedHeaderPresent) +ZigbeeAdpu::FrameControl ZigbeeAdpu::frameControl() const { - quint8 frameControl = 0; - frameControl &= static_cast(frameType); // Bit 0 - 1 - frameControl &= static_cast(deliveryMode); // Bit 2 - 3 - if (apsAckFormat) - frameControl &= static_cast(0x08); // Bit 4 + return m_frameControl; +} - if (securitySubField) - frameControl &= static_cast(0x04); // Bit 5 +void ZigbeeAdpu::setFrameControl(ZigbeeAdpu::FrameControl frameControl) +{ + m_frameControl = frameControl; +} - if (securitySubField) - frameControl &= static_cast(0x04); // Bit 6 +quint8 ZigbeeAdpu::buildFrameControlByte(FrameControl frameControl) +{ + quint8 frameControlByte = 0; + frameControlByte |= static_cast(frameControl.frameType); // Bit 0 - 1 + frameControlByte |= static_cast(frameControl.deliveryMode); // Bit 2 - 3 + if (frameControl.apsAckFormat) + frameControlByte |= static_cast(0x10); // Bit 4 - if (acknowledgementRequest) - frameControl &= static_cast(0x02); // Bit 7 + if (frameControl.security) + frameControlByte |= static_cast(0x20); // Bit 5 - if (extendedHeaderPresent) - frameControl &= static_cast(0x01); // Bit 8 + if (frameControl.acknowledgementRequest) + frameControlByte |= static_cast(0x40); // Bit 6 + if (frameControl.extendedHeader) + frameControlByte |= static_cast(0x80); // Bit 7 + + return frameControlByte; +} + +ZigbeeAdpu::FrameControl ZigbeeAdpu::readFrameControlByte(quint8 frameControlByte) +{ + FrameControl frameControl; + frameControl.frameType = static_cast(frameControlByte | 0x03); + frameControl.deliveryMode = static_cast(frameControlByte | 0x0C); + frameControl.apsAckFormat = frameControlByte | 0x10; + frameControl.security = frameControlByte | 0x20; + frameControl.acknowledgementRequest = frameControlByte | 0x40; + frameControl.extendedHeader = frameControlByte | 0x80; return frameControl; } diff --git a/libnymea-zigbee/zigbeeadpu.h b/libnymea-zigbee/zigbeeadpu.h index 5929502..279bee1 100644 --- a/libnymea-zigbee/zigbeeadpu.h +++ b/libnymea-zigbee/zigbeeadpu.h @@ -30,39 +30,60 @@ #include -typedef struct FrameControl { - -} FrameControl; class ZigbeeAdpu : public QObject { Q_OBJECT public: - // Note: zigbee Pro Specification 2.2.5.1 General APDU Frame Format /* Frame control */ enum FrameType { FrameTypeData = 0x00, - FrameTypeCommand = 0x40, - FrameTypeAck = 0x80, - FrameTypeInterPanAps = 0xC0 + FrameTypeCommand = 0x01, + FrameTypeAck = 0x02, + FrameTypeInterPanAps = 0x03 }; Q_ENUM(FrameType) enum DeliveryMode { DeliveryModeNormalUnicast = 0x00, - DeliveryModeBroadcast = 0x20, - DeliveryModeGroupAddressing = 0x30, + DeliveryModeBroadcast = 0x08, + DeliveryModeGroupAddressing = 0x0C, }; Q_ENUM(DeliveryMode) + typedef struct FrameControl { + FrameType frameType = FrameTypeData; + DeliveryMode deliveryMode = DeliveryModeNormalUnicast; + bool security = false; + bool apsAckFormat = false; + bool acknowledgementRequest = true; + bool extendedHeader = false; + } FrameControl; explicit ZigbeeAdpu(QObject *parent = nullptr); - quint8 buildFrameControl(FrameType frameType, DeliveryMode deliveryMode, bool apsAckFormat, bool securitySubField, bool acknowledgementRequest, bool extendedHeaderPresent); + FrameControl frameControl() const; + void setFrameControl(FrameControl frameControl); + quint8 destinationEndpoint() const; + void setDestinationEndpoint(quint8 destinationEndpoint); + + quint16 groupAddress() const; + void setGroupAddress(quint16 groupAddress); + + quint16 clusterId() const; + void setClusterId(quint16 clusterId); + +private: + FrameControl m_frameControl; + quint8 m_destinationEndpoint; + + + quint8 buildFrameControlByte(FrameControl frameControl); + FrameControl readFrameControlByte(quint8 frameControlByte); signals: }; diff --git a/libnymea-zigbee/zigbeechannelmask.cpp b/libnymea-zigbee/zigbeechannelmask.cpp index 5ea9a07..a70f0d4 100644 --- a/libnymea-zigbee/zigbeechannelmask.cpp +++ b/libnymea-zigbee/zigbeechannelmask.cpp @@ -54,6 +54,60 @@ Zigbee::ZigbeeChannels ZigbeeChannelMask::channels() const return static_cast(m_channelMask); } +QList ZigbeeChannelMask::channelArray() const +{ + QList array; + if (channels().testFlag(Zigbee::ZigbeeChannel11)) + array.append(11); + + if (channels().testFlag(Zigbee::ZigbeeChannel12)) + array.append(12); + + if (channels().testFlag(Zigbee::ZigbeeChannel13)) + array.append(13); + + if (channels().testFlag(Zigbee::ZigbeeChannel14)) + array.append(14); + + if (channels().testFlag(Zigbee::ZigbeeChannel15)) + array.append(15); + + if (channels().testFlag(Zigbee::ZigbeeChannel16)) + array.append(16); + + if (channels().testFlag(Zigbee::ZigbeeChannel17)) + array.append(17); + + if (channels().testFlag(Zigbee::ZigbeeChannel18)) + array.append(18); + + if (channels().testFlag(Zigbee::ZigbeeChannel19)) + array.append(19); + + if (channels().testFlag(Zigbee::ZigbeeChannel20)) + array.append(20); + + if (channels().testFlag(Zigbee::ZigbeeChannel21)) + array.append(21); + + if (channels().testFlag(Zigbee::ZigbeeChannel22)) + array.append(22); + + if (channels().testFlag(Zigbee::ZigbeeChannel23)) + array.append(23); + + if (channels().testFlag(Zigbee::ZigbeeChannel24)) + array.append(24); + + if (channels().testFlag(Zigbee::ZigbeeChannel25)) + array.append(25); + + if (channels().testFlag(Zigbee::ZigbeeChannel26)) + array.append(26); + + return array; +} + bool ZigbeeChannelMask::isSet(Zigbee::ZigbeeChannel channel) const { return channels().testFlag(channel); @@ -90,17 +144,7 @@ bool ZigbeeChannelMask::operator!=(const ZigbeeChannelMask &other) const QDebug operator<<(QDebug debug, const ZigbeeChannelMask &channelMaks) { debug.nospace() << "ChannelMask(" << ZigbeeUtils::convertUint32ToHexString(channelMaks.toUInt32()); - debug.nospace() << ", ["; - for (int i = 11; i <= 25; i++) { - if (channelMaks.isSet(static_cast(i))) { - if (i < 25) { - debug.nospace() << i << ", "; - } else { - debug.nospace() << i; - } - } - } - - debug.nospace() << "])"; + debug.nospace() << ", " << channelMaks.channelArray(); + debug.nospace() << ")"; return debug.space(); } diff --git a/libnymea-zigbee/zigbeechannelmask.h b/libnymea-zigbee/zigbeechannelmask.h index a961fd3..c5d804c 100644 --- a/libnymea-zigbee/zigbeechannelmask.h +++ b/libnymea-zigbee/zigbeechannelmask.h @@ -53,6 +53,8 @@ public: Zigbee::ZigbeeChannels channels() const; + QList channelArray() const; + bool isSet(Zigbee::ZigbeeChannel channel) const; void setChannel(Zigbee::ZigbeeChannel channel); void unsetChannel(Zigbee::ZigbeeChannel channel); diff --git a/libnymea-zigbee/zigbeedeviceobject.cpp b/libnymea-zigbee/zigbeedeviceobject.cpp new file mode 100644 index 0000000..5e4532e --- /dev/null +++ b/libnymea-zigbee/zigbeedeviceobject.cpp @@ -0,0 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeedeviceobject.h" + +ZigbeeDeviceObject::ZigbeeDeviceObject(QObject *parent) : QObject(parent) +{ + +} diff --git a/libnymea-zigbee/zigbeedeviceobject.h b/libnymea-zigbee/zigbeedeviceobject.h new file mode 100644 index 0000000..04fa1dd --- /dev/null +++ b/libnymea-zigbee/zigbeedeviceobject.h @@ -0,0 +1,43 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEEDEVICEOBJECT_H +#define ZIGBEEDEVICEOBJECT_H + +#include + +class ZigbeeDeviceObject : public QObject +{ + Q_OBJECT +public: + explicit ZigbeeDeviceObject(QObject *parent = nullptr); + +signals: + +}; + +#endif // ZIGBEEDEVICEOBJECT_H diff --git a/libnymea-zigbee/zigbeedeviceprofile.cpp b/libnymea-zigbee/zigbeedeviceprofile.cpp new file mode 100644 index 0000000..509a1cc --- /dev/null +++ b/libnymea-zigbee/zigbeedeviceprofile.cpp @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeedeviceprofile.h" diff --git a/libnymea-zigbee/zigbeedeviceprofile.h b/libnymea-zigbee/zigbeedeviceprofile.h new file mode 100644 index 0000000..1c810aa --- /dev/null +++ b/libnymea-zigbee/zigbeedeviceprofile.h @@ -0,0 +1,144 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEEDEVICEPROFILE_H +#define ZIGBEEDEVICEPROFILE_H + +#include + +class ZigbeeDeviceProfile +{ + Q_GADGET + +public: + + enum ZdoCommand { + /* Requests */ + /*Device and service discovery */ + NetworkAddressRequest = 0x0000, + IeeeAddressRequest = 0x0001, + NodeDescriptorRequest = 0x0002, + PowerDescriptorRequest = 0x0003, + SimpleDescriptorRequest = 0x0004, + ActiveEndpointsRequest = 0x0005, + MatchDescriptorsRequest = 0x0006, + ComplexDescriptorRequest = 0x0010, + UserDescriptorRequest = 0x0011, + DiscoveryCacheRequest = 0x0012, + DeviceAnnounce = 0x0013, + UserDescriptorSet = 0x0014, + SystemServerDiscoveryRequest = 0x0015, + DiscoveryStoreRequest = 0x0016, + NodeDescriptorStoreRequest = 0x0017, + PowerDescriptorStoreRequest = 0x0018, + ActiveEndpointStoreRequest = 0x0019, + SimpleDescriptorStoreRequest = 0x001A, + RemoveNodeCacheRequest = 0x001B, + FindNodeCacheRequest = 0x001C, + ExtendedSimpleDescriptorRequest = 0x001D, + ExtendedActiveEndpointRequest = 0x001E, + ParentAnnounceRequest = 0x001F, + + /* Binding */ + EndDeviceBindRequest = 0x0020, + BindRequest = 0x0021, + UnbindRequest = 0x0022, + BindRegisterRequest = 0x0023, + ReplaceDeviceRequest = 0x0024, + StoreBackupBindEntryRequest = 0x0025, + RemoveBackupBindEntryRequest = 0x0026, + BackupBindTableRequest = 0x0027, + RecoverBindTableRequest = 0x0028, + BackupSourceBindRequest = 0x0029, + RecoverSourceBindRequest = 0x002A, + + /* Network management */ + MgmtNetworkDiscoveryRequest = 0x0030, + MgmtLqiRequest = 0x0031, + MgmtRoutingTableRequest = 0x0032, + MgmtBindRequest = 0x0033, + MgmtLeaveRequest = 0x0034, + MgmtDirectJoinRequest = 0x0035, + MgmtPermitJoinRequest = 0x0036, + MgmtCacheRequest = 0x0037, + MgmtNetworkUpdateRequest = 0x0038, + + /* Responses */ + /*Device and service discovery */ + NetworkAddressResponse = 0x8000, + IeeeAddressResponse = 0x8001, + NodeDescriptorResponse = 0x8002, + PowerDescriptorResponse = 0x8003, + SimpleDescriptorResponse = 0x8004, + ActiveEndpointsResponse = 0x8005, + MatchDescriptorsResponse = 0x8006, + ComplexDescriptorResponse = 0x8010, + UserDescriptorResponse = 0x8011, + DiscoveryCacheResponse = 0x8012, + UserDescriptorSetResponse = 0x8014, + SystemServerDiscoveryResponse = 0x8015, + DiscoveryStoreResponse = 0x8016, + NodeDescriptorStoreResponse = 0x8017, + PowerDescriptorStoreResponse = 0x8018, + ActiveEndpointStoreResponse = 0x8019, + SimpleDescriptorStoreResponse = 0x801A, + RemoveNodeCacheResponse = 0x801B, + FindNodeCacheResponse = 0x801C, + ExtendedSimpleDescriptorResponse = 0x801D, + ExtendedActiveEndpointResponse = 0x801E, + ParentAnnounceRespone = 0x801F, + + /* Binding */ + EndDeviceBindResponse = 0x8020, + BindResponse = 0x8021, + UnbindResponse = 0x8022, + BindRegisterResponse = 0x8023, + ReplaceDeviceResponse = 0x8024, + StoreBackupBindEntryResponse = 0x8025, + RemoveBackupBindEntryResponse = 0x8026, + BackupBindTableResponse = 0x8027, + RecoverBindTableResponse = 0x8028, + BackupSourceBindResponse = 0x8029, + RecoverSourceBindResponse = 0x802A, + + /* Network management */ + MgmtNetworkDiscoveryResponse = 0x8030, + MgmtLqiResponse = 0x8031, + MgmtRoutingTableResponse = 0x8032, + MgmtBindResponse = 0x8033, + MgmtLeaveResponse = 0x8034, + MgmtDirectJoinResponse = 0x8035, + MgmtPermitJoinResponse = 0x8036, + MgmtCacheResponse = 0x8037, + MgmtNetworkUpdateResponse = 0x8038 + }; + + + +}; + +#endif // ZIGBEEDEVICEPROFILE_H diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index 2d1a823..57b86ec 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -87,6 +87,20 @@ void ZigbeeNetwork::setSerialBaudrate(qint32 baudrate) emit serialBaudrateChanged(m_serialBaudrate); } +quint16 ZigbeeNetwork::panId() +{ + return m_panId; +} + +void ZigbeeNetwork::setPanId(quint16 panId) +{ + if (m_panId == panId) + return; + + m_panId = panId; + emit panIdChanged(m_panId); +} + quint64 ZigbeeNetwork::extendedPanId() const { return m_extendedPanId; @@ -243,7 +257,7 @@ void ZigbeeNetwork::saveNetwork() qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName; QSettings settings(m_settingsFileName, QSettings::IniFormat, this); settings.beginGroup("Network"); - settings.setValue("panId", extendedPanId()); + settings.setValue("panId", panId()); settings.setValue("channel", channel()); settings.setValue("networkKey", securityConfiguration().networkKey().toString()); settings.setValue("trustCenterLinkKey", securityConfiguration().globalTrustCenterLinkKey().toString()); @@ -260,8 +274,8 @@ void ZigbeeNetwork::loadNetwork() QSettings settings(m_settingsFileName, QSettings::IniFormat, this); settings.beginGroup("Network"); - quint64 extendedPanId = static_cast(settings.value("panId", 0).toULongLong()); - setExtendedPanId(extendedPanId); + quint16 panId = static_cast(settings.value("panId", 0).toUInt()); + setPanId(panId); setChannel(settings.value("channel", 0).toUInt()); ZigbeeNetworkKey netKey(settings.value("networkKey", QString()).toString()); if (netKey.isValid()) @@ -420,6 +434,11 @@ void ZigbeeNetwork::removeNodeFromSettings(ZigbeeNode *node) void ZigbeeNetwork::addNode(ZigbeeNode *node) { qCDebug(dcZigbeeNetwork()) << "Add node" << node; + if (hasNode(node->extendedAddress())) { + qCWarning(dcZigbeeNetwork()) << "Not adding node to the system since already added" << node; + return; + } + addNodeInternally(node); saveNode(node); } diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index da06da5..1fbd959 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -76,6 +76,9 @@ public: void setSerialBaudrate(qint32 baudrate); // Network configurations + quint16 panId(); + void setPanId(quint16 panId); + quint64 extendedPanId() const; void setExtendedPanId(quint64 extendedPanId); @@ -109,6 +112,7 @@ private: qint32 m_serialBaudrate = 115200; // Network configurations + quint16 m_panId = 0; quint64 m_extendedPanId = 0; quint32 m_channel = 0; ZigbeeChannelMask m_channelMask = ZigbeeChannelMask(ZigbeeChannelMask::ChannelConfigurationAllChannels); @@ -151,6 +155,7 @@ signals: void serialPortNameChanged(const QString &serialPortName); void serialBaudrateChanged(qint32 serialBaudrate); + void panIdChanged(quint16 panId); void extendedPanIdChanged(quint64 extendedPanId); void channelChanged(uint channel); void channelMaskChanged(const ZigbeeChannelMask &channelMask); diff --git a/libnymea-zigbee/zigbeenetworkreply.cpp b/libnymea-zigbee/zigbeenetworkreply.cpp index 6fc65f2..7e44b52 100644 --- a/libnymea-zigbee/zigbeenetworkreply.cpp +++ b/libnymea-zigbee/zigbeenetworkreply.cpp @@ -32,12 +32,19 @@ ZigbeeNetworkReply::Error ZigbeeNetworkReply::error() const return m_error; } +ZigbeeNetworkRequest ZigbeeNetworkReply::request() const +{ + return m_request; +} + Zigbee::ZigbeeStatus ZigbeeNetworkReply::zigbeeStatus() const { return m_zigbeeStatus; } -ZigbeeNetworkReply::ZigbeeNetworkReply(QObject *parent) : QObject(parent) +ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent) : + QObject(parent), + m_request(request) { } diff --git a/libnymea-zigbee/zigbeenetworkreply.h b/libnymea-zigbee/zigbeenetworkreply.h index e5edd52..9a7f5f7 100644 --- a/libnymea-zigbee/zigbeenetworkreply.h +++ b/libnymea-zigbee/zigbeenetworkreply.h @@ -31,6 +31,7 @@ #include #include "zigbee.h" +#include "zigbeenetworkrequest.h" class ZigbeeNetworkReply : public QObject { @@ -48,10 +49,13 @@ public: Q_ENUM(Error) Error error() const; + ZigbeeNetworkRequest request() const; Zigbee::ZigbeeStatus zigbeeStatus() const; private: - explicit ZigbeeNetworkReply(QObject *parent = nullptr); + explicit ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObject *parent = nullptr); + ZigbeeNetworkRequest m_request; + bool m_finished = false; Error m_error = ErrorNoError; Zigbee::ZigbeeStatus m_zigbeeStatus = Zigbee::ZigbeeStatusSuccess; diff --git a/libnymea-zigbee/zigbeenetworkrequest.cpp b/libnymea-zigbee/zigbeenetworkrequest.cpp new file mode 100644 index 0000000..3d4cdcb --- /dev/null +++ b/libnymea-zigbee/zigbeenetworkrequest.cpp @@ -0,0 +1,143 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeenetworkrequest.h" + +ZigbeeNetworkRequest::ZigbeeNetworkRequest() +{ + +} + +quint8 ZigbeeNetworkRequest::requestId() const +{ + return m_requestId; +} + +void ZigbeeNetworkRequest::setRequestId(quint8 requestId) +{ + m_requestId = requestId; +} + +Zigbee::DestinationAddressMode ZigbeeNetworkRequest::destinationAddressMode() const +{ + return m_destinationAddressMode; +} + +void ZigbeeNetworkRequest::setDestinationAddressMode(Zigbee::DestinationAddressMode destinationAddressMode) +{ + m_destinationAddressMode = destinationAddressMode; +} + +quint16 ZigbeeNetworkRequest::destinationShortAddress() const +{ + return m_destinationShortAddress; +} + +void ZigbeeNetworkRequest::setDestinationShortAddress(quint16 destinationShortAddress) +{ + m_destinationShortAddress = destinationShortAddress; +} + +ZigbeeAddress ZigbeeNetworkRequest::destinationIeeeAddress() const +{ + return m_destinationIeeeAddress; +} + +void ZigbeeNetworkRequest::setDestinationIeeeAddress(const ZigbeeAddress &destinationIeeeAddress) +{ + m_destinationIeeeAddress = destinationIeeeAddress; +} + +quint8 ZigbeeNetworkRequest::destinationEndpoint() const +{ + return m_destinationEndpoint; +} + +void ZigbeeNetworkRequest::setDestinationEndpoint(quint8 destinationEndpoint) +{ + m_destinationEndpoint = destinationEndpoint; +} + +quint16 ZigbeeNetworkRequest::profileId() const +{ + return m_profileId; +} + +void ZigbeeNetworkRequest::setProfileId(quint16 profileId) +{ + m_profileId = profileId; +} + +quint16 ZigbeeNetworkRequest::clusterId() const +{ + return m_clusterId; +} + +void ZigbeeNetworkRequest::setClusterId(quint16 clusterId) +{ + m_clusterId = clusterId; +} + +quint8 ZigbeeNetworkRequest::sourceEndpoint() const +{ + return m_sourceEndpoint; +} + +void ZigbeeNetworkRequest::setSourceEndpoint(quint8 sourceEndpoint) +{ + m_sourceEndpoint = sourceEndpoint; +} + +QByteArray ZigbeeNetworkRequest::asdu() const +{ + return m_asdu; +} + +void ZigbeeNetworkRequest::setAsdu(const QByteArray &asdu) +{ + m_asdu = asdu; +} + +Zigbee::ZigbeeTxOptions ZigbeeNetworkRequest::txOptions() const +{ + return m_txOptions; +} + +void ZigbeeNetworkRequest::setTxOptions(Zigbee::ZigbeeTxOptions txOptions) +{ + m_txOptions = txOptions; +} + +quint8 ZigbeeNetworkRequest::radius() const +{ + return m_radius; +} + +void ZigbeeNetworkRequest::setRadius(quint8 radius) +{ + m_radius = radius; +} diff --git a/libnymea-zigbee/zigbeenetworkrequest.h b/libnymea-zigbee/zigbeenetworkrequest.h new file mode 100644 index 0000000..831f5ce --- /dev/null +++ b/libnymea-zigbee/zigbeenetworkrequest.h @@ -0,0 +1,88 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEENETWORKREQUEST_H +#define ZIGBEENETWORKREQUEST_H + +#include + +#include "zigbee.h" +#include "zigbeeaddress.h" + +class ZigbeeNetworkRequest +{ +public: + ZigbeeNetworkRequest(); + + quint8 requestId() const; + void setRequestId(quint8 requestId); + + Zigbee::DestinationAddressMode destinationAddressMode() const; + void setDestinationAddressMode(Zigbee::DestinationAddressMode destinationAddressMode); + + quint16 destinationShortAddress() const; + void setDestinationShortAddress(quint16 destinationShortAddress); + + ZigbeeAddress destinationIeeeAddress() const; + void setDestinationIeeeAddress(const ZigbeeAddress &destinationIeeeAddress); + + quint8 destinationEndpoint() const; + void setDestinationEndpoint(quint8 destinationEndpoint); + + quint16 profileId() const; + void setProfileId(quint16 profileId); + + quint16 clusterId() const; + void setClusterId(quint16 clusterId); + + quint8 sourceEndpoint() const; + void setSourceEndpoint(quint8 sourceEndpoint); + + QByteArray asdu() const; + void setAsdu(const QByteArray &asdu); + + Zigbee::ZigbeeTxOptions txOptions() const; + void setTxOptions(Zigbee::ZigbeeTxOptions txOptions); + + quint8 radius() const; + void setRadius(quint8 radius); + +private: + quint8 m_requestId = 0; + Zigbee::DestinationAddressMode m_destinationAddressMode = Zigbee::DestinationAddressModeShortAddress; + quint16 m_destinationShortAddress = 0; + ZigbeeAddress m_destinationIeeeAddress; + quint8 m_destinationEndpoint = 0; + quint16 m_profileId = 0; + quint16 m_clusterId = 0; + quint8 m_sourceEndpoint = 0; + QByteArray m_asdu; + Zigbee::ZigbeeTxOptions m_txOptions = Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission); + quint8 m_radius = 0; +}; + +#endif // ZIGBEENETWORKREQUEST_H diff --git a/libnymea-zigbee/zigbeenodeendpoint.cpp b/libnymea-zigbee/zigbeenodeendpoint.cpp index 9c4d43f..49a8966 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.cpp +++ b/libnymea-zigbee/zigbeenodeendpoint.cpp @@ -155,9 +155,9 @@ void ZigbeeNodeEndpoint::addOutputCluster(ZigbeeCluster *cluster) m_outputClusters.insert(cluster->clusterId(), cluster); } -ZigbeeNetworkReply *ZigbeeNodeEndpoint::createNetworkReply() +ZigbeeNetworkReply *ZigbeeNodeEndpoint::createNetworkReply(const ZigbeeNetworkRequest &request) { - ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(this); + ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this); // Make sure the reply will be deleted connect(reply, &ZigbeeNetworkReply::finished, reply, &ZigbeeNetworkReply::deleteLater); return reply; diff --git a/libnymea-zigbee/zigbeenodeendpoint.h b/libnymea-zigbee/zigbeenodeendpoint.h index dea9207..a289bf6 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.h +++ b/libnymea-zigbee/zigbeenodeendpoint.h @@ -131,7 +131,7 @@ protected: void addOutputCluster(ZigbeeCluster *cluster); // Network reply methods - ZigbeeNetworkReply *createNetworkReply(); + ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest()); void finishNetworkReply(ZigbeeNetworkReply *reply, ZigbeeNetworkReply::Error error = ZigbeeNetworkReply::ErrorNoError, Zigbee::ZigbeeStatus zigbeeStatus = Zigbee::ZigbeeStatusSuccess); signals: diff --git a/libnymea-zigbee/zigbeeutils.cpp b/libnymea-zigbee/zigbeeutils.cpp index df8be0c..8d2f6c0 100644 --- a/libnymea-zigbee/zigbeeutils.cpp +++ b/libnymea-zigbee/zigbeeutils.cpp @@ -173,6 +173,11 @@ QByteArray ZigbeeUtils::convertBitArrayToByteArray(const QBitArray &bitArray) return byteArray; } +bool ZigbeeUtils::checkBitUint8(const quint8 &value, const int &bitNumber) +{ + return value & (1 << bitNumber); +} + bool ZigbeeUtils::checkBitUint16(const quint16 &value, const int &bitNumber) { return value & (1 << bitNumber); diff --git a/libnymea-zigbee/zigbeeutils.h b/libnymea-zigbee/zigbeeutils.h index 29fb23b..bd39d62 100644 --- a/libnymea-zigbee/zigbeeutils.h +++ b/libnymea-zigbee/zigbeeutils.h @@ -38,6 +38,16 @@ #include "zigbee.h" #include "zigbeecluster.h" +template inline TYPE ZigbeeBit(const TYPE & x) +{ + return TYPE(1) << x; +} + +template inline bool ZigbeeIsBitSet(const TYPE & x, const TYPE & y) +{ + return (x & y) != 0; +} + class ZigbeeUtils { Q_GADGET @@ -46,6 +56,7 @@ public: // Data utils QBitArray convertByteArrayToBitArray(const QByteArray &byteArray); QByteArray convertBitArrayToByteArray(const QBitArray &bitArray); + static bool checkBitUint8(const quint8 &value, const int &bitNumber); static bool checkBitUint16(const quint16 &value, const int &bitNumber); static quint16 convertByteArrayToUint16(const QByteArray &data);