private async Task <IXBeeResponse> SendCommandAsync(IXBeeCommand command, CancellationToken cancellationToken) { IXBeeListener xbeeListener = new XBeeListener(); AddTransactionListener(xbeeListener); lock (_frameIdLock) { xbeeListener.OurFrameId = Interlocked.Increment(ref _frameId); command.SetFrameId(xbeeListener.OurFrameId); Interlocked.CompareExchange(ref _frameId, 1, 256); } // Send the transaction QueueFrame(command); while (!_mainCancellationToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested && !xbeeListener.Complete) { // wait until transaction is complete await Task.Delay(5); } RemoveTransactionListener(xbeeListener); return(xbeeListener.CompletionResponse); }
/// <summary> /// Sends a XBee request to the NCP without waiting for the response. /// </summary> /// <param name="command">Request <see cref="IXBeeCommand"/> to send.</param> /// <returns></returns> public async Task <IXBeeResponse> SendRequestAsync(IXBeeCommand command) { IXBeeListener xbeeListener = new XBeeListener(); await _taskFactory.StartNew(() => { AddTransactionListener(xbeeListener); lock (_frameIdLock) { xbeeListener.OurFrameId = Interlocked.Increment(ref _frameId); command.SetFrameId(xbeeListener.OurFrameId); Interlocked.CompareExchange(ref _frameId, 1, 256); } // Send the transaction QueueFrame(command); lock (xbeeListener) { while (!xbeeListener.Complete) { // wait until transaction is complete } } RemoveTransactionListener(xbeeListener); }); return(xbeeListener.CompletionResponse); }
/// <summary> /// Add a XBee command frame to the send queue.The sendQueue is a FIFO queue. /// This method queues a <see cref="IXBeeCommand"/> /// frame without waiting for a response. /// </summary> private void QueueFrame(IXBeeCommand request) { _sendQueue.Enqueue(request); Log.Verbose($"TX XBEE queue: {_sendQueue.Count}: {request}"); SendNextFrame(); }
/// <summary> /// Cancel the transaction and send the next frame from the queue. /// We don't try and retry as this might cause other unwanted issues. /// </summary> private void TimeoutCallback(object state) { StopTimer(); Log.Debug("XBEE Timer: Timeout"); lock (_commandLock) { if (_sentCommand != null) { _sentCommand = null; SendNextFrame(); } } }
private void SendNextFrame() { // Are we already processing a command? if (_sentCommand != null) { Log.Debug($"TX XBEE Frame outstanding: {_sentCommand}"); return; } bool isFrameDequeuedSuccsess = _sendQueue.TryDequeue(out IXBeeCommand nextFrame); if (!isFrameDequeuedSuccsess) { Log.Verbose("XBEE TX: Nothing to send"); // Nothing to send StopTimer(); return; } Log.Debug($"TX XBEE: {nextFrame}"); // Remember the command we're processing _sentCommand = nextFrame; // Send the data List <byte> bytes = new List <byte>(); bytes.Add(XBEE_FLAG); StringBuilder builder = new StringBuilder(); int[] frames = nextFrame.Serialize(); foreach (int sendByte in frames) { builder.Append(string.Format(" 0x{0:X2}", sendByte)); if (_escapeCodes.Contains((byte)sendByte)) { bytes.Add(XBEE_ESCAPE); bytes.Add((byte)(sendByte ^ XBEE_XOR)); } else { bytes.Add((byte)sendByte); } } Log.Verbose($"TX XBEE Data:{builder.ToString()}"); _serialPort.Write(bytes.ToArray()); // Start the timeout Log.Verbose("XBEE Timer: Start"); _timeoutTimer.Change(_commandTimeout, Timeout.Infinite); }
/// <summary> /// Sends a XBee request to the dongle and waits for the response.The response is correlated with the request /// and the response data is returned as a <see cref="IXBeeEvent"/>. /// </summary> /// <param name="command">Request <see cref="IXBeeCommand"/> to send</param> /// <returns>Response <see cref="IXBeeResponse"/> the response, or null if there was a timeout</returns> public IXBeeResponse SendRequest(IXBeeCommand command) { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = cancellationTokenSource.Token; Task <IXBeeResponse> sendCommandTask = SendCommandAsync(command, cancellationToken); bool taskResult = sendCommandTask.Wait(_transactionTimeout); if (taskResult) { return(sendCommandTask.Result); } else { Log.Debug($"XBee interrupted in SendRequest {command}"); cancellationTokenSource.Cancel(); return(null); } }
/// <summary> /// Construct which sets input stream where the packet is read from the and /// handler which further processes the received packet. /// </summary> /// <param name="serialPort">The serial port.</param> public void Start(IZigBeePort serialPort) { Interlocked.Exchange(ref _frameId, 1); _serialPort = serialPort; _timeoutTimer = new Timer(new TimerCallback(TimeoutCallback)); // TODO af: find the equivalent in C# --> maybe ThreadPool-Class is the right one //timeoutScheduler = Executors.newSingleThreadScheduledExecutor(); // Clear anything in the receive buffer before we start EmptyRxBuffer(); // TODO af: find a more elegant way to solve this --> maybe async/await // This might be resolved with a TaskCompletionSource // See the refactored while loop in ZigBeeTransaction.cs line 84 _parserThread = _taskFactory.StartNew(() => { Log.Debug("XBeeFrameHandler task started."); while (!_closeHandler) { try { lock (_commandLock) { if (_sentCommand == null) { SendNextFrame(); } } // Get a packet from the serial port int[] responseData = GetPacket(); if (responseData == null) { lock (_commandLock) { _sentCommand = null; } continue; } StringBuilder builder = new StringBuilder(); foreach (int value in responseData) { builder.Append(string.Format(" 0x{0:X2}", value.ToString())); } Log.Verbose($"RX XBEE Data: {builder}"); // Use the Event Factory to get an event IXBeeEvent xBeeEvent = XBeeEventFactory.GetXBeeFrame(responseData); if (xBeeEvent != null) { NotifyEventReceived(xBeeEvent); } // Use the Response Factory to get a response IXBeeResponse response = XBeeResponseFactory.GetXBeeFrame(responseData); if (response != null && NotifyResponseReceived(response)) { lock (_commandLock) { _sentCommand = null; } } } catch (Exception ex) { Log.Error(ex, "XBeeFrameHandler exception {Exception}", ex.Message); } } Log.Debug("XBeeFrameHandler thread exited."); }); }
/// <summary> /// Sends a XBee request to the NCP without waiting for the response. /// </summary> /// <param name="command">Request <see cref="IXBeeCommand"/> to send.</param> /// <returns></returns> public Task <IXBeeResponse> SendRequestAsync(IXBeeCommand command) { return(_taskFactory.StartNew(() => SendRequest(command))); }