Ejemplo n.º 1
0
		public void Write(int addr, byte value, int clock)
		{
			UpdateTimers(clock);

			if (addr == 0)
			{
				PartSelect = 1;
				RegisterSelect = value;
				return;
			}
			else if (addr == 2)
			{
				PartSelect = 2;
				RegisterSelect = value;
				return;
			}

			if (PartSelect == 1)
			{
				if (RegisterSelect == 0x24) { WriteTimerA_MSB_24(value, clock); return; }
				if (RegisterSelect == 0x25) { WriteTimerA_LSB_25(value, clock); return; }
				if (RegisterSelect == 0x26) { WriteTimerB_26(value, clock); return; }
				if (RegisterSelect == 0x27) { WriteTimerControl_27(value, clock); } // we process immediately AND enqueue command for port $27. Allows accurate tracking of CH3 special modes.
			}

			// If its not timer related just queue the command write
			var cmd = new QueuedCommand { Part = PartSelect, Register = RegisterSelect, Data = value, Clock = clock - frameStartClock };
			commands.Enqueue(cmd);
		}
Ejemplo n.º 2
0
        /// <summary>
        /// CCDDisplay Plugin device constructor for ISerialComport transport
        /// </summary>
        /// <param name="key"></param>
        /// <param name="name"></param>
        /// <param name="config"></param>
        /// <param name="display">Loaded and initialized instance of CCD Display driver instance</param>
        public ClearOneDSPDevice(string key, string name, ClearOneDSPConfig config, IBasicCommunication comm)
            : base(key, name)
        {
            Debug.Console(0, this, "Constructing new {0} instance", name);

            _config                 = config;
            _commandQueue           = new CrestronQueue(100);
            _responseQueue          = new CrestronQueue <string>();
            _responseParseThread    = new Thread(parseResponse, null, Thread.eThreadStartOptions.Running);
            _commandInProgressTimer = new CTimer((o) => { _commandInProgress = null; }, Timeout.Infinite);

            _devices = new Dictionary <string, ClearOneDSPDeviceInfo>();

            Communication             = comm;
            _portGather               = new CommunicationGather(Communication, "\x0D\x0A");
            _portGather.LineReceived += this.lineReceived;

            if (config.CommunicationMonitorProperties != null)
            {
                CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, config.CommunicationMonitorProperties);
            }
            else
            {
                //#warning Need to deal with this poll string
                CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 30000, 60000, new Action(() =>
                {
                    if (_devices.Count == 0)
                    {
                        _commandQueue.Enqueue("** VER");
                    }
                    //sendLine("** VER");

                    foreach (var controlPoint in LevelControlPoints.Values)
                    {
                        controlPoint.Poll();
                    }
                }));
            }

            LevelControlPoints = new Dictionary <string, ClearOneDSPVolumeControl>();
            foreach (KeyValuePair <string, ClearOneLevelControlBlockConfig> kvp in _config.LevelControlBlocks)
            {
                this.LevelControlPoints.Add(kvp.Key, new ClearOneDSPVolumeControl(kvp.Key, kvp.Value, this));
            }

            CrestronConsole.AddNewConsoleCommand((s) =>
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("Devices:");
                foreach (var kvp in _devices)
                {
                    sb.AppendFormat("\tDevice: {0}\r\n", kvp.Key);
                    sb.AppendFormat("\t\tModel:     {0}\r\n", kvp.Value.DeviceType.ToString());
                    sb.AppendFormat("\t\tId:        {0}\r\n", kvp.Value.DeviceId);
                    sb.AppendFormat("\t\tFirmware:  {0}\r\n", kvp.Value.Version);
                }
                CrestronConsole.ConsoleCommandResponse("{0}", sb.ToString());
            },
                                                 Key + "INFO", "Print Driver Info", ConsoleAccessLevelEnum.AccessOperator);
        }
Ejemplo n.º 3
0
        public static void Enqueue(AppCommands commandType, IEntityBase entity, ExecutionTrigger trigger, object value, ModifyAction modifyAction)
        {
            var command = new QueuedCommand
            {
                CommandType   = commandType,
                Target        = entity.UniqueId,
                Status        = ExecutionStatus.Pending,
                TriggerType   = trigger,
                Value         = value.ToString(),
                ModifyAction  = modifyAction,
                DateCreated   = DateTime.Now,
                DateScheduled = DateTime.Now
            };

            ThreadPool.QueueUserWorkItem(delegate
            {
                ClientState.Current.DataService.Save(command);

                switch (trigger)
                {
                case ExecutionTrigger.Connection:
                    EventBroker.Publish(AppEvents.RequestCommands);
                    break;

                case ExecutionTrigger.Send:
                    EventBroker.Publish(AppEvents.RequestSend);
                    break;

                case ExecutionTrigger.Receive:
                    EventBroker.Publish(AppEvents.RequestReceive);
                    break;
                }
            });
        }
Ejemplo n.º 4
0
		void WriteCommand(QueuedCommand cmd)
		{
			if (cmd.Part == 1)
				Part1_WriteRegister(cmd.Register, cmd.Data);
			else
				Part2_WriteRegister(cmd.Register, cmd.Data);
		}
Ejemplo n.º 5
0
 /// <summary>
 /// Adds a command from a child module to the queue
 /// </summary>
 /// <param name="commandToEnqueue">Command object from child module</param>
 public void EnqueueCommand(QueuedCommand commandToEnqueue)
 {
     _commandQueue.Enqueue(commandToEnqueue);
     Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'.  CommandQueue has '{1}' Elements.", commandToEnqueue.Command, _commandQueue.Count);
     if (!_commandQueueInProgress)
     {
         SendNextQueuedCommand();
     }
 }
Ejemplo n.º 6
0
        public SyncEntityCommand(Entities entities, string key, QueuedCommand inner)
        {
            Values = new Dictionary <string, object> {
                { "wrap_access_token", CloudApi.AccessToken }
            };

            this.key      = key;
            this.entities = entities;
            this.inner    = inner;
        }
Ejemplo n.º 7
0
    public void QueueTauntCommand()
    {
        if (HasFinishedTurn)
        {
            return;
        }
        QueuedCommand com = new QueuedCommand(() => TauntCommand(), 1);

        p_CommandQueue.Enqueue(com);
    }
Ejemplo n.º 8
0
    public void QueueAttackCommand(Limb limb)
    {
        if (HasFinishedTurn)
        {
            return;
        }
        Limb          l   = limb;
        QueuedCommand com = new QueuedCommand(() => AttackCommand(l), 1); // To-Do Read attack data

        p_CommandQueue.Enqueue(com);
    }
Ejemplo n.º 9
0
        static Person GetPerson(QueuedCommand command)
        {
            var    personId = Int64.Parse(command.Target.Substring(1));
            Person person;

            using (VirtualMailBox.Current.Persons.ReaderLock)
                person = VirtualMailBox.Current.Persons.FirstOrDefault(s => s.PersonId == personId);

            if (person == null)
            {
                throw new ApplicationException(String.Format("The given source entity with key {0} was not found", command.Target));
            }

            return(person);
        }
Ejemplo n.º 10
0
        static UserStatus GetUserStatus(QueuedCommand command)
        {
            var        statusId = Int64.Parse(command.Target.Substring(1));
            UserStatus status;

            using (VirtualMailBox.Current.StatusUpdates.ReaderLock)
                status = VirtualMailBox.Current.StatusUpdates.FirstOrDefault(s => s.StatusId == statusId);

            if (status == null)
            {
                throw new ApplicationException(String.Format("The given source entity with key {0} was not found", command.Target));
            }

            return(status);
        }
Ejemplo n.º 11
0
        static Message GetMessage(QueuedCommand command)
        {
            var     messageid = Int64.Parse(command.Target.Substring(1));
            Message message;

            using (VirtualMailBox.Current.Messages.ReaderLock)
                message = VirtualMailBox.Current.Messages.FirstOrDefault(m => m.MessageId == messageid);

            if (message == null)
            {
                throw new ApplicationException(String.Format("The given source entity with key {0} was not found", command.Target));
            }

            return(message);
        }
Ejemplo n.º 12
0
 protected virtual void QueueLogic()
 {
     if (p_CommandQueue.Count <= 0)
     {
         return;
     }
     m_QueueTimer += Time.deltaTime;
     if (m_QueueTimer > m_QueueTrigger)
     {
         QueuedCommand command = p_CommandQueue.Dequeue();
         command.Execute();
         command        = null;
         m_QueueTrigger = 1;// p_CommandQueue.Peek().ExecutionTime;
         m_QueueTimer   = 0;
     }
 }
Ejemplo n.º 13
0
        /// <summary>
        /// Sends the command.
        /// </summary>
        /// <param name="command">command string</param>
        /// <exception cref="System.InvalidOperationException">Not connected</exception>
        protected virtual CommandResult SendCommand(string command)
        {
            if (!Connection.IsOpen)
            {
                throw new InvalidOperationException("Not connected");
            }


            command = PrepareCommand(command);
            Logger?.WriteLine("Queuing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);

            var cmd = new QueuedCommand(command);

            commandQueue.Add(cmd);
            return(cmd.CommandResult);
        }
Ejemplo n.º 14
0
        private void ApplyAudioCommand(QueuedCommand cmd)
        {
            switch (cmd.Register)
            {
            case AudioRegister.AUDC:
                AUD[cmd.Channel].AUDC = cmd.Value;
                break;

            case AudioRegister.AUDF:
                AUD[cmd.Channel].AUDF = cmd.Value;
                break;

            case AudioRegister.AUDV:
                AUD[cmd.Channel].AUDV = cmd.Value;
                break;
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Handles a response message from the DSP
        /// </summary>
        /// <param name="obj"></param>
        private object parseResponse(object obj)
        {
            while (true)
            {
                try
                {
                    string respnose = _responseQueue.Dequeue();
                    Debug.Console(1, this, "Response '{0}' Dequeued. ResponseQueue Size: {1}", respnose, _responseQueue.Count);

                    if (respnose == null)
                    {
                        Debug.Console(2, this, "Exception in parseResponse thread, deque string is empty");
                        return(null);
                    }

                    if (respnose.StartsWith("OK> #", StringComparison.Ordinal) || respnose.StartsWith("> #", StringComparison.Ordinal))
                    {
                        if (_commandInProgress == null)
                        {
                            /// response is not associated with any particular command, iterate through controls
                            parseAll(respnose);
                        }
                        else
                        {
                            _commandInProgressTimer.Stop();
                            if (!_commandInProgress.Control.Parse(respnose))
                            {
                                /// current command owner could not parse response, iterating through all others
                                parseAll(respnose);
                            }
                            _commandInProgress = null;
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.Console(2, this, "Exception in parseResponse thread: '{0}'\n{1}", e.Message, e.StackTrace);
                }

                if (!_commandQueue.IsEmpty && _responseQueue.IsEmpty)
                {
                    sendNextQueuedCommand();
                }
            } // while(true)
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Sends the next queued command to the DSP
        /// </summary>
        void SendNextQueuedCommand()
        {
            //Debug.Console(2, this, "Attempting to send next queued command. CommandQueueInProgress: {0}  Communication isConnected: {1}", CommandQueueInProgress, Communication.IsConnected);

            //if (CommandQueue.IsEmpty)
            //    CommandQueueInProgress = false;

            //Debug.Console(1, this, "CommandQueue has {0} Elements:\n", CommandQueue.Count);

            //foreach (object o in CommandQueue)
            //{
            //    if (o is string)
            //        Debug.Console(1, this, "{0}", o);
            //    else if(o is QueuedCommand)
            //    {
            //        var item = (QueuedCommand)o;
            //        Debug.Console(1, this, "{0}", item.Command);
            //    }
            //}

            //Debug.Console(1, this, "End of CommandQueue");

            if (Communication.IsConnected && !CommandQueue.IsEmpty)
            {
                CommandQueueInProgress = true;

                if (CommandQueue.Peek() is QueuedCommand)
                {
                    QueuedCommand nextCommand = new QueuedCommand();

                    nextCommand = (QueuedCommand)CommandQueue.Peek();

                    SendLine(nextCommand.Command);
                }
                else
                {
                    string nextCommand = (string)CommandQueue.Peek();

                    SendLine(nextCommand);
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Sends the next queued command to the DSP
        /// </summary>
        private void sendNextQueuedCommand()
        {
            if (Communication.IsConnected && !_commandQueue.IsEmpty)
            {
                if (_commandQueue.Peek() is QueuedCommand)
                {
                    _commandInProgress = (QueuedCommand)_commandQueue.Dequeue();
                    Debug.Console(1, this, "Command '{0}' Dequeued. CommandQueue Size: {1}", _commandInProgress.Command, _commandQueue.Count);

                    _commandInProgressTimer.Reset(2000);
                    sendLine(_commandInProgress.Command);
                }
                else
                {
                    string nextCommand = (string)_commandQueue.Dequeue();
                    Debug.Console(1, this, "Command '{0}' Dequeued. CommandQueue Size: {1}", nextCommand, _commandQueue.Count);

                    sendLine(nextCommand);
                }
            }
        }
Ejemplo n.º 18
0
        public static CommandBase CreateCommand(QueuedCommand command)
        {
            switch (command.CommandType)
            {
            case AppCommands.SendMessage:
                return(new SendMessageCommand(GetMessage(command)));

            case AppCommands.SendStatusUpdate:
                return(new SendStatusUpdateCommand(GetUserStatus(command)));

            case AppCommands.SyncMessage:
                return(new SyncEntityCommand(Entities.Messages, GetMessage(command).MessageKey, command));

            case AppCommands.SyncPerson:
                return(new SyncEntityCommand(Entities.Persons, GetPerson(command).PersonKey, command));

            case AppCommands.SyncStatusUpdate:
                return(new SyncEntityCommand(Entities.StatusUpdates, GetUserStatus(command).StatusKey, command));
            }

            throw new ArgumentException(String.Format("Unexpected command type {0}", command.CommandType));
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Sends the next queued command to the DSP
        /// </summary>
        void SendNextQueuedCommand()
        {
            if (Communication.IsConnected && !CommandQueue.IsEmpty)
            {
                CommandQueueInProgress = true;

                if (CommandQueue.Peek() is QueuedCommand)
                {
                    QueuedCommand nextCommand = new QueuedCommand();

                    nextCommand = (QueuedCommand)CommandQueue.Peek();

                    SendLine(nextCommand.Command);
                }
                else
                {
                    string nextCommand = (string)CommandQueue.Peek();

                    SendLine(nextCommand);
                }
            }
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Worker method for sending commands
        /// </summary>
        private async void CommandWorker()
        {
            while (!commandCancellationToken.IsCancellationRequested)
            {
                currentCommand = null;
                if (commandQueue.TryTake(out currentCommand, Timeout.Infinite, commandCancellationToken.Token))
                {
                    Logger?.WriteLine("Writing Command: '" + currentCommand.CommandText.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);

                    if (Connection.IsAsync)
                    {
                        await Connection.WriteAsync(Encoding.ASCII.GetBytes(currentCommand.CommandText));
                    }
                    else
                    {
                        Connection.Write(Encoding.ASCII.GetBytes(currentCommand.CommandText));
                    }
                    //wait for command to finish
                    commandFinishedEvent.WaitOne();
                }
            }
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Adds a command from a child module to the queue
        /// </summary>
        /// <param name="command">Command object from child module</param>
        internal void enqueueCommand(QueuedCommand commandToEnqueue)
        {
            /// check if command already in the queue
            bool commandInQueue = false;

            foreach (var command in _commandQueue)
            {
                string commandText;
                if (command is QueuedCommand)
                {
                    commandText = (command as QueuedCommand).Command;
                }
                else
                {
                    commandText = (string)command;
                }
                if (commandText == commandToEnqueue.Command)
                {
                    commandInQueue = true;
                    break;
                }
            }

            if (commandInQueue)
            {
                Debug.Console(1, this, "Enqueueing command '{0}' is duplicate, skipping. CommandQueue Size: '{1}'", commandToEnqueue.Command, _commandQueue.Count);
            }
            else
            {
                _commandQueue.Enqueue(commandToEnqueue);
            }
            //Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue Size: '{1}'", commandToEnqueue.Command, CommandQueue.Count);

            if (_commandInProgress == null && _responseQueue.IsEmpty)
            {
                sendNextQueuedCommand();
            }
        }
Ejemplo n.º 22
0
		void WriteCommand(QueuedCommand cmd)
		{
			if (cmd.Part == 1)
				Part1_WriteRegister(cmd.Register, cmd.Data);
			else
				Part2_WriteRegister(cmd.Register, cmd.Data);
		}
Ejemplo n.º 23
0
		private void ApplyAudioCommand(QueuedCommand cmd)
		{
			switch (cmd.Register)
			{
				case AudioRegister.AUDC:
					AUD[cmd.Channel].AUDC = cmd.Value;
					break;
				case AudioRegister.AUDF:
					AUD[cmd.Channel].AUDF = cmd.Value;
					break;
				case AudioRegister.AUDV:
					AUD[cmd.Channel].AUDV = cmd.Value;
					break;
			}
		}
Ejemplo n.º 24
0
		public void Write(int addr, byte value, int clock)
		{
			UpdateTimers(clock);

			if (addr == 0)
			{
				PartSelect = 1;
				RegisterSelect = value;
				return;
			}
			else if (addr == 2)
			{
				PartSelect = 2;
				RegisterSelect = value;
				return;
			}

			if (PartSelect == 1)
			{
				if (RegisterSelect == 0x24) { WriteTimerA_MSB_24(value, clock); return; }
				if (RegisterSelect == 0x25) { WriteTimerA_LSB_25(value, clock); return; }
				if (RegisterSelect == 0x26) { WriteTimerB_26(value, clock); return; }
				if (RegisterSelect == 0x27) { WriteTimerControl_27(value, clock); } // we process immediately AND enqueue command for port $27. Allows accurate tracking of CH3 special modes.
			}

			// If its not timer related just queue the command write
			var cmd = new QueuedCommand { Part = PartSelect, Register = RegisterSelect, Data = value, Clock = clock - frameStartClock };
			commands.Enqueue(cmd);
		}
Ejemplo n.º 25
0
        /// <summary>
        /// Handles a response message from the DSP
        /// </summary>
        /// <param name="dev"></param>
        /// <param name="args"></param>
        void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
        {
            if (Debug.Level == 2)
            {
                Debug.Console(2, this, "RX: '{0}'",
                              ShowHexResponse ? ComTextHelper.GetEscapedText(args.Text) : args.Text);
            }

            Debug.Console(1, this, "RX: '{0}'", args.Text);

            try
            {
                if (args.Text.IndexOf("Welcome to the Tesira Text Protocol Server...") > -1)
                {
                    // Indicates a new TTP session

                    SubscribeToAttributes();
                }
                else if (args.Text.IndexOf("publishToken") > -1)
                {
                    // response is from a subscribed attribute

                    string pattern = "! \"publishToken\":[\"](.*)[\"] \"value\":(.*)";

                    Match match = Regex.Match(args.Text, pattern);

                    if (match.Success)
                    {
                        string key;

                        string customName;

                        string value;

                        customName = match.Groups[1].Value;

                        // Finds the key (everything before the '~' character
                        key = customName.Substring(0, customName.IndexOf("~", 0) - 1);

                        value = match.Groups[2].Value;

                        foreach (KeyValuePair <string, TesiraForteLevelControl> controlPoint in LevelControlPoints)
                        {
                            if (customName == controlPoint.Value.LevelCustomName || customName == controlPoint.Value.MuteCustomName)
                            {
                                controlPoint.Value.ParseSubscriptionMessage(customName, value);
                                return;
                            }
                        }
                    }

                    /// same for dialers
                    /// same for switchers
                }
                else if (args.Text.IndexOf("+OK") > -1)
                {
                    if (args.Text == "+OK" || args.Text.IndexOf("list\":") > -1)        // Check for a simple "+OK" only 'ack' repsonse or a list response and ignore
                    {
                        return;
                    }

                    // response is not from a subscribed attribute.  From a get/set/toggle/increment/decrement command

                    if (!CommandQueue.IsEmpty)
                    {
                        if (CommandQueue.Peek() is QueuedCommand)
                        {
                            // Expected response belongs to a child class
                            QueuedCommand tempCommand = (QueuedCommand)CommandQueue.TryToDequeue();
                            //Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);

                            tempCommand.ControlPoint.ParseGetMessage(tempCommand.AttributeCode, args.Text);
                        }
                        else
                        {
                            // Expected response belongs to this class
                            string temp = (string)CommandQueue.TryToDequeue();
                            //Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
                        }

                        if (CommandQueue.IsEmpty)
                        {
                            CommandQueueInProgress = false;
                        }
                        else
                        {
                            SendNextQueuedCommand();
                        }
                    }
                }
                else if (args.Text.IndexOf("-ERR") > -1)
                {
                    // Error response

                    switch (args.Text)
                    {
                    case "-ERR ALREADY_SUBSCRIBED":
                    {
                        ResetSubscriptionTimer();
                        break;
                    }

                    default:
                    {
                        Debug.Console(0, this, "Error From DSP: '{0}'", args.Text);
                        break;
                    }
                    }
                }
            }
            catch (Exception e)
            {
                if (Debug.Level == 2)
                {
                    Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
                }
            }
        }
        protected override void ExecuteCore()
        {
            var commands =
                ClientState.Current.DataService.SelectAllBy <QueuedCommand>(
                    new { TriggerType = trigger.ToString(), Status = ExecutionStatus.Pending.ToString() }).ToList();

            if (commands.Count == 0)
            {
                return;
            }

            Logger.Debug("{0} commands queued with triggger {1}", LogSource.Command, commands.Count, trigger);

            foreach (var command in commands)
            {
                if (DateTime.Now > command.DateScheduled)
                {
                    var cmdObject = CommandFactory.CreateCommand(command);

                    if (cmdObject.CanExecute)
                    {
                        // Lock this task (prevents execution by any other task)
                        command.Status = ExecutionStatus.Submitted;
                        ClientState.Current.DataService.Update(command);

                        var task = new BackgroundActionTask(cmdObject.Execute);

                        // Create new task for command
                        Logger.Debug("Creating task for command {0}", LogSource.Command, command);

                        // Update timestamp on started
                        QueuedCommand command1 = command;

                        task.Started += delegate
                        {
                            Logger.Debug("Command {0} started", LogSource.Command, command1);

                            command1.Status      = ExecutionStatus.Submitted;
                            command1.DateStarted = DateTime.Now;

                            ClientState.Current.DataService.Update(command1);
                        };

                        // Update status on success
                        task.FinishedSuccess += delegate
                        {
                            Logger.Debug("Command {0} finished successfully", LogSource.Command, command1);

                            command1.Status = ExecutionStatus.Success;

                            ClientState.Current.DataService.Update(command1);
                        };

                        // Update status on failure
                        task.FinishedFailure += delegate
                        {
                            Logger.Debug("Command {0} finished with failure", LogSource.Command, command1);

                            command1.Status = (command1.ActualRetries < command1.MaxRetries) ? ExecutionStatus.Pending : ExecutionStatus.Error;
                            command1.ActualRetries++;

                            ClientState.Current.DataService.Update(command1);
                        };

                        task.ExecuteAsync();
                    }
                }
            }
        }
Ejemplo n.º 27
0
 private async ValueTask <T> Queue <T>(QueuedCommand <T> command)
 {
     _queuedCommands.Add(command);
     return(await command.Task);
 }
Ejemplo n.º 28
0
 private XElement CallWebService(string aRequestMethod, string aRequestBody)
 {
     QueuedCommand cmd = new QueuedCommand(aRequestMethod, aRequestBody);
     lock (iCommands)
     {
         iCommands.Add(cmd);
     }
     iCommandSem.Release();
     string resp = cmd.GetResponse();
     return (resp == null? null : XElement.Parse(resp));
 }