// blocks the current thread if a command is pending, then sets the current command as the pending command (note does not apply to all commands) private void WaitAndSetPendingCommand(InsteonDeviceCommands command, byte value) { InsteonDeviceCommands latchedPendingCommand; lock (pendingEvent) { if (pendingCommand == null) { pendingCommand = command; pendingValue = value; pendingRetry = 0; return; } latchedPendingCommand = pendingCommand.Value; } // block current thread if a command is pending Log.WriteLine("Device {0} blocking command {1} for pending command {2}", Address.ToString(), command.ToString(), latchedPendingCommand.ToString()); pendingEvent.Reset(); if (!pendingEvent.WaitOne(Constants.deviceAckTimeout)) // wait at most deviceAckTimeout seconds { ClearPendingCommand(); // break deadlock and warn Log.WriteLine("WARNING: Device {0} unblocking command {1} for pending command {2}", Address.ToString(), command.ToString(), latchedPendingCommand.ToString()); } WaitAndSetPendingCommand(command, value); // try again }
private bool TryCommandInternal(InsteonDeviceCommands command, byte value) { byte[] message = GetStandardMessage(Address, (byte)command, value); Log.WriteLine("Device {0} Command(command:{1}, value:{2:X2})", Address.ToString(), command.ToString(), value); EchoStatus status = network.Messenger.TrySend(message); if (status == EchoStatus.ACK) { ackTimer.Change(Constants.deviceAckTimeout, Timeout.Infinite); // start ACK timeout timer return(true); } else { ClearPendingCommand(); return(false); } }
/// <summary> /// Sends an INSTEON command to the device. /// </summary> /// <remarks> /// This is a non-blocking method that sends an INSTEON message to the target device and returns immediately (as long as another command is not already pending for the device). Only one command can be pending to an INSTEON device at a time. This method will block if a second command is sent while a first command is still pending. /// The <see cref="DeviceStatusChanged">DeviceStatusChanged</see> event will be invoked if the command is successful. /// The <see cref="DeviceCommandTimeout">DeviceCommandTimeout</see> event will be invoked if the device does not respond within the expected timeout period. /// </remarks> /// <param name="command">Specifies the INSTEON device command to be invoked.</param> /// <param name="value">A parameter value required by some commands.</param> public void Command(InsteonDeviceCommands command, byte value) { if (!TryCommand(command, value)) { throw new IOException(string.Format("Failed to send command '{0}' for device '{1}'", command.ToString(), Address.ToString())); } }
// blocks the current thread if a command is pending, then sets the current command as the pending command (note does not apply to all commands) private void WaitAndSetPendingCommand(InsteonDeviceCommands command, byte value) { InsteonDeviceCommands latchedPendingCommand; lock (this.pendingEvent) { if (this.pendingCommand == null) { this.pendingCommand = command; this.pendingValue = value; this.pendingRetry = 0; return; } latchedPendingCommand = this.pendingCommand.Value; } // block current thread if a command is pending Log.WriteLine("Device {0} blocking command {1} for pending command {2}", this.Address.ToString(), command.ToString(), latchedPendingCommand.ToString()); this.pendingEvent.Reset(); if (!this.pendingEvent.WaitOne(Constants.deviceAckTimeout)) // wait at most deviceAckTimeout seconds { this.ClearPendingCommand(); // break deadlock and warn Log.WriteLine("WARNING: Device {0} unblocking command {1} for pending command {2}", this.Address.ToString(), command.ToString(), latchedPendingCommand.ToString()); } this.WaitAndSetPendingCommand(command, value); // try again }
private bool TryCommandInternal(InsteonDeviceCommands command, byte value) { var message = GetStandardMessage(this.Address, (byte)command, value); Log.WriteLine("Device {0} Command(command:{1}, value:{2:X2})", this.Address.ToString(), command.ToString(), value); var status = this.network.Messenger.TrySend(message); if (status == EchoStatus.ACK) { this.ackTimer.Change(Constants.deviceAckTimeout, Timeout.Infinite); // start ACK timeout timer return true; } else { this.ClearPendingCommand(); return false; } }
/// <summary> /// Sends an INSTEON command to the device. /// </summary> /// <remarks> /// This is a non-blocking method that sends an INSTEON message to the target device and returns immediately (as long as another command is not already pending for the device). Only one command can be pending to an INSTEON device at a time. This method will block if a second command is sent while a first command is still pending. /// The <see cref="DeviceStatusChanged">DeviceStatusChanged</see> event will be invoked if the command is successful. /// The <see cref="DeviceCommandTimeout">DeviceCommandTimeout</see> event will be invoked if the device does not respond within the expected timeout period. /// </remarks> /// <param name="command">Specifies the INSTEON device command to be invoked.</param> /// <param name="value">A parameter value required by some commands.</param> public void Command(InsteonDeviceCommands command, byte value) { if (!this.TryCommand(command, value)) throw new IOException(string.Format("Failed to send command '{0}' for device '{1}'", command.ToString(), this.Address.ToString())); }