#region CmdMessenger - MIT - (c) 2013 Thijs Elenbaas. /* CmdMessenger - library that provides command based messaging Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Copyright 2013 - Thijs Elenbaas */ #endregion using System; using System.Threading; namespace CommandMessenger.Queue { /// Queue of received commands. public class SendCommandQueue : CommandQueue { public event EventHandler NewLineSent; private readonly CommunicationManager _communicationManager; private readonly int _sendBufferMaxLength = 62; private string _sendBuffer = string.Empty; private int _commandCount; public uint MaxQueueLength { get; set; } /// send command queue constructor. /// The communication manager instance /// Length of the send buffer public SendCommandQueue(CommunicationManager communicationManager, int sendBufferMaxLength) { MaxQueueLength = 5000; _communicationManager = communicationManager; _sendBufferMaxLength = sendBufferMaxLength; } protected override bool ProcessQueue() { SendCommandsFromQueue(); lock (Queue) return !IsEmpty; } /// Sends the commands from queue. All commands will be combined until either /// the SendBufferMaxLength has been reached or if a command requires an acknowledge /// private void SendCommandsFromQueue() { _commandCount = 0; _sendBuffer = string.Empty; CommandStrategy eventCommandStrategy = null; // while maximum buffer string is not reached, and command in queue while (_sendBuffer.Length < _sendBufferMaxLength && Queue.Count > 0) { lock (Queue) { var commandStrategy = !IsEmpty ? Queue.Peek() : null; if (commandStrategy != null) { if (commandStrategy.Command != null) { var sendCommand = (SendCommand)commandStrategy.Command; if (sendCommand.ReqAc) { if (_commandCount > 0) { break; } SendSingleCommandFromQueue(commandStrategy); } else { eventCommandStrategy = commandStrategy; AddToCommandString(commandStrategy); } } } } // event callback outside lock for performance if (eventCommandStrategy != null) { if (NewLineSent != null) NewLineSent(this, new CommandEventArgs(eventCommandStrategy.Command)); eventCommandStrategy = null; } } // Now check if a command string has been filled if (_sendBuffer.Length > 0) { _communicationManager.ExecuteSendString(_sendBuffer, SendQueue.InFrontQueue); } } /// Sends a float command from the queue. /// The command strategy to send. private void SendSingleCommandFromQueue(CommandStrategy commandStrategy) { // Dequeue lock (Queue) { commandStrategy.DeQueue(); // Process all generic dequeue strategies foreach (var generalStrategy in GeneralStrategies) { generalStrategy.OnDequeue(); } } // Send command if (commandStrategy.Command != null) _communicationManager.ExecuteSendCommand((SendCommand)commandStrategy.Command, SendQueue.InFrontQueue); } /// Adds a commandStrategy to the commands string. /// The command strategy to add. private void AddToCommandString(CommandStrategy commandStrategy) { // Dequeue lock (Queue) { commandStrategy.DeQueue(); // Process all generic dequeue strategies foreach (var generalStrategy in GeneralStrategies) { generalStrategy.OnDequeue(); } } // Add command if (commandStrategy.Command != null) { _commandCount++; _sendBuffer += commandStrategy.Command.CommandString(); if (_communicationManager.PrintLfCr) { _sendBuffer += "\r\n"; } } } /// Sends a command. Note that the command is put at the front of the queue /// The command to sent. public void SendCommand(SendCommand sendCommand) { // Add command to front of queue QueueCommand(new TopCommandStrategy(sendCommand)); } /// Queue the send command. /// The command to sent. public void QueueCommand(SendCommand sendCommand) { QueueCommand(new CommandStrategy(sendCommand)); } /// Queue the send command wrapped in a command strategy. /// The command strategy. public override void QueueCommand(CommandStrategy commandStrategy) { while (Queue.Count > MaxQueueLength) { Thread.Yield(); } lock (Queue) { // Process commandStrategy enqueue associated with command commandStrategy.CommandQueue = Queue; commandStrategy.Command.CommunicationManager = _communicationManager; ((SendCommand)commandStrategy.Command).InitArguments(); commandStrategy.Enqueue(); // Process all generic enqueue strategies foreach (var generalStrategy in GeneralStrategies) { generalStrategy.OnEnqueue(); } } SignalWorker(); } } }