public void CommandReceived(ZigBeeCommand command) { // We are only interested in READ ATTRIBUTE commands if (!(command is ReadAttributesCommand)) { return; } ReadAttributesCommand readCommand = (ReadAttributesCommand)command; if (readCommand.ClusterId != ZclBasicCluster.CLUSTER_ID && readCommand.CommandDirection != ZclCommandDirection.SERVER_TO_CLIENT) { return; } List <ReadAttributeStatusRecord> attributeRecords = new List <ReadAttributeStatusRecord>(); foreach (ushort attributeId in readCommand.Identifiers) { attributeRecords.Add(GetAttributeRecord(attributeId)); } ReadAttributesResponse readResponse = new ReadAttributesResponse(); readResponse.Records = attributeRecords; readResponse.DestinationAddress = readCommand.SourceAddress; readResponse.CommandDirection = ZclCommandDirection.CLIENT_TO_SERVER; readResponse.TransactionId = command.TransactionId; _networkManager.SendCommand(readResponse); }
public void CommandReceived(ZigBeeCommand command) { // If we have local servers matching the request, then we need to respond if (command is MatchDescriptorRequest matchRequest) { Log.Debug("{ExtPanId}: ClusterMatcher received request {Match}", _networkManager.ZigBeeExtendedPanId, matchRequest); if (matchRequest.ProfileId != 0x104) { // TODO: Do we need to restrict the profile? Remove this check? return; } // We want to match any of our local servers (ie our input clusters) with any // requested clusters in the requests cluster list if (matchRequest.InClusterList.Intersect(_clusters).Count() == 0 && matchRequest.OutClusterList.Intersect(_clusters).Count() == 0) { Log.Debug("{ExtPanId}: ClusterMatcher no match", _networkManager.ZigBeeExtendedPanId); return; } MatchDescriptorResponse matchResponse = new MatchDescriptorResponse(); matchResponse.Status = ZdoStatus.SUCCESS; List <ushort> matchList = new List <ushort>(); matchList.Add(1); matchResponse.MatchList = matchList; matchResponse.DestinationAddress = command.SourceAddress; matchResponse.NwkAddrOfInterest = matchRequest.NwkAddrOfInterest; Log.Debug("{ExtPanId}: ClusterMatcher sending match {Response}", _networkManager.ZigBeeExtendedPanId, matchResponse); _networkManager.SendCommand(matchResponse); } }
/// <summary> /// Sends ZigBeeCommand command and uses the ZigBeeTransactionMatcher to match the response. /// The task will be timed out if there is no response. /// /// @param command the ZigBeeCommand /// @param responseMatcher the ZigBeeTransactionMatcher /// </summary> public async Task <CommandResult> SendTransaction(ZigBeeCommand command, IZigBeeTransactionMatcher responseMatcher) { _command = command; _responseMatcher = responseMatcher; _timeout = DateTime.Now.AddMilliseconds(DEFAULT_TIMEOUT_MILLISECONDS); lock (_command) { _networkManager.AddCommandListener(this); int transactionId = _networkManager.SendCommand(command); if (command is ZclCommand cmd) { cmd.TransactionId = (byte)transactionId; } } return(await Task.Run(() => { while (true) { if (DateTime.Now < _timeout) { if (_result != null) { return _result; } } else { _logger.Debug("Transaction timeout: {Command}", _command); lock (_command) { _networkManager.RemoveCommandListener(this); return new CommandResult(); } } } })); }
public void CommandReceived(ZigBeeCommand command) { // If we have local servers matching the request, then we need to respond if (command is MatchDescriptorRequest matchRequest) { Log.Debug("{ExtPanId}: ClusterMatcher received request {Match}", _networkManager.ZigBeeExtendedPanId, matchRequest); if (matchRequest.ProfileId != _profileId) { Log.Debug("{ExtPanId}: ClusterMatcher no match to profileId", _networkManager.ZigBeeExtendedPanId); return; } if (matchRequest.NwkAddrOfInterest != _networkManager.LocalNwkAddress && !ZigBeeBroadcastDestination.IsBroadcast(matchRequest.NwkAddrOfInterest)) { Log.Debug("{ExtPanId}: ClusterMatcher no match to local address", _networkManager.ZigBeeExtendedPanId); return; } // We want to match any of our local servers (ie our input clusters) with any // requested clusters in the requests cluster list if (matchRequest.InClusterList.Intersect(_serverClusters).Count() == 0 && matchRequest.OutClusterList.Intersect(_clientClusters).Count() == 0) { Log.Debug("{ExtPanId}: ClusterMatcher no match", _networkManager.ZigBeeExtendedPanId); return; } MatchDescriptorResponse matchResponse = new MatchDescriptorResponse(); matchResponse.Status = ZdoStatus.SUCCESS; List <byte> matchList = new List <byte>(); matchList.Add(_localEndpointId); matchResponse.MatchList = matchList; matchResponse.NwkAddrOfInterest = _networkManager.LocalNwkAddress; matchResponse.TransactionId = matchRequest.TransactionId; matchResponse.DestinationAddress = command.SourceAddress; Log.Debug("{ExtPanId}: ClusterMatcher sending match {Response}", _networkManager.ZigBeeExtendedPanId, matchResponse); _networkManager.SendCommand(matchResponse); } }
/// <summary> /// Sends ZigBeeCommand command and uses the ZigBeeTransactionMatcher to match the response. /// The task will be timed out if there is no response. /// /// <param name="command">the ZigBeeCommand</param> /// <param name="responseMatcher">the ZigBeeTransactionMatcher</param> /// </summary> public async Task <CommandResult> SendTransaction(ZigBeeCommand command, IZigBeeTransactionMatcher responseMatcher) { CommandResult commandResult; lock (_objLock) { _command = command; _responseMatcher = responseMatcher; _networkManager.AddCommandListener(this); int transactionId = _networkManager.SendCommand(command); if (command is ZclCommand cmd) { cmd.TransactionId = (byte)transactionId; } //Without RunContinuationsAsynchronously, calling SetResult can block the calling thread, because the continuation is run synchronously //see https://stackoverflow.com/a/37492081 _sendTransactionTask = new TaskCompletionSource <CommandResult>(TaskCreationOptions.RunContinuationsAsynchronously); } var t = _sendTransactionTask.Task; var cancel = new CancellationTokenSource(); var timeoutTask = Task.Delay(Timeout, cancel.Token); if (t == await Task.WhenAny(t, timeoutTask).ConfigureAwait(false)) { cancel.Cancel(); //Cancel the timeout task commandResult = t.Result; } else { /* Timeout */ Log.Debug("Transaction timeout: {Command}", _command); commandResult = new CommandResult(); } _networkManager.RemoveCommandListener(this); return(commandResult); }
/// <summary> /// Sends ZigBeeCommand command and uses the ZigBeeTransactionMatcher to match the response. /// The task will be timed out if there is no response. /// /// <param name="command">the ZigBeeCommand</param> /// <param name="responseMatcher">the ZigBeeTransactionMatcher</param> /// </summary> public async Task <CommandResult> SendTransaction(ZigBeeCommand command, IZigBeeTransactionMatcher responseMatcher) { _command = command; _responseMatcher = responseMatcher; _timeout = DateTime.Now.AddMilliseconds(DEFAULT_TIMEOUT_MILLISECONDS); _networkManager.AddCommandListener(this); int transactionId = _networkManager.SendCommand(command); if (command is ZclCommand cmd) { cmd.TransactionId = (byte)transactionId; } _sendTransactionTask = new TaskCompletionSource <CommandResult>(); var t = _sendTransactionTask.Task; var timeoutTask = Task.Delay(DEFAULT_TIMEOUT_MILLISECONDS); var cancel = new CancellationTokenSource(); if (t == await Task.WhenAny(t, timeoutTask).ConfigureAwait(false)) { cancel.Cancel(); //Cancel the timeout task _networkManager.RemoveCommandListener(this); return(t.Result); } else { /* Timeout */ Log.Debug("Transaction timeout: {Command}", _command); _networkManager.RemoveCommandListener(this); return(new CommandResult()); } /* !!! OLD CODE WITHOUT COMPLETION SOURCE - DO NOT DELET IT YET !!! * * return await Task.Run(() => * { * while (true) * { * if (DateTime.Now < _timeout) * { * if (_result != null) * { * return _result; * } * } * else * { * Log.Debug("Transaction timeout: {Command}", _command); * lock (_command) * { * _networkManager.RemoveCommandListener(this); * return new CommandResult(); * } * } * } * }); * */ }