machines/firmware/legacy/arduino-libraries/Arduino-CmdMessenger/extras/CSharp/CommandMessenger/Queue/SendCommandQueue.cs

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();
}
}
}