183 lines
7.2 KiB
C#
183 lines
7.2 KiB
C#
#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
|
|
{
|
|
/// <summary> Queue of received commands. </summary>
|
|
public class SendCommandQueue : CommandQueue
|
|
{
|
|
public event EventHandler<CommandEventArgs> NewLineSent;
|
|
|
|
private readonly CommunicationManager _communicationManager;
|
|
private readonly int _sendBufferMaxLength = 62;
|
|
private string _sendBuffer = string.Empty;
|
|
private int _commandCount;
|
|
|
|
public uint MaxQueueLength { get; set; }
|
|
|
|
/// <summary> send command queue constructor. </summary>
|
|
/// <param name="communicationManager">The communication manager instance</param>
|
|
/// <param name="sendBufferMaxLength">Length of the send buffer</param>
|
|
public SendCommandQueue(CommunicationManager communicationManager, int sendBufferMaxLength)
|
|
{
|
|
MaxQueueLength = 5000;
|
|
|
|
_communicationManager = communicationManager;
|
|
_sendBufferMaxLength = sendBufferMaxLength;
|
|
}
|
|
|
|
protected override bool ProcessQueue()
|
|
{
|
|
SendCommandsFromQueue();
|
|
lock (Queue) return !IsEmpty;
|
|
}
|
|
|
|
/// <summary> Sends the commands from queue. All commands will be combined until either
|
|
/// the SendBufferMaxLength has been reached or if a command requires an acknowledge
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary> Sends a float command from the queue. </summary>
|
|
/// <param name="commandStrategy"> The command strategy to send. </param>
|
|
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);
|
|
}
|
|
|
|
/// <summary> Adds a commandStrategy to the commands string. </summary>
|
|
/// <param name="commandStrategy"> The command strategy to add. </param>
|
|
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"; }
|
|
}
|
|
}
|
|
|
|
/// <summary> Sends a command. Note that the command is put at the front of the queue </summary>
|
|
/// <param name="sendCommand"> The command to sent. </param>
|
|
public void SendCommand(SendCommand sendCommand)
|
|
{
|
|
// Add command to front of queue
|
|
QueueCommand(new TopCommandStrategy(sendCommand));
|
|
}
|
|
|
|
/// <summary> Queue the send command. </summary>
|
|
/// <param name="sendCommand"> The command to sent. </param>
|
|
public void QueueCommand(SendCommand sendCommand)
|
|
{
|
|
QueueCommand(new CommandStrategy(sendCommand));
|
|
}
|
|
|
|
/// <summary> Queue the send command wrapped in a command strategy. </summary>
|
|
/// <param name="commandStrategy"> The command strategy. </param>
|
|
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();
|
|
}
|
|
}
|
|
}
|