示例#1
0
        private static bool StandardMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length < offset + 10)
            {
                return(false);
            }

            var messageId  = data[offset];
            var properties = new Dictionary <PropertyKey, int>();

            GetAddressProperty(PropertyKey.FromAddress, data, offset + 1, out count, properties);
            GetMessageFlagProperty(data, offset, out count, properties);
            if (properties[PropertyKey.MessageFlagsBroadcast] == 0)
            {
                GetAddressProperty(PropertyKey.ToAddress, data, offset + 4, out count, properties);
            }
            properties[PropertyKey.Cmd1] = data[offset + 8];
            properties[PropertyKey.Cmd2] = data[offset + 9];
            count = 10;

            var messageType = GetMessageType(data, offset, properties);

            message = new InsteonMessage(messageId, messageType, properties);
            return(true);
        }
示例#2
0
        private static bool ExtendedMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length < offset + 23)
            {
                return(false);
            }

            StandardMessage(data, offset, out count, out message);
            message.Properties[PropertyKey.Data1]  = data[offset + 10];
            message.Properties[PropertyKey.Data2]  = data[offset + 11];
            message.Properties[PropertyKey.Data3]  = data[offset + 12];
            message.Properties[PropertyKey.Data4]  = data[offset + 13];
            message.Properties[PropertyKey.Data5]  = data[offset + 14];
            message.Properties[PropertyKey.Data6]  = data[offset + 15];
            message.Properties[PropertyKey.Data7]  = data[offset + 16];
            message.Properties[PropertyKey.Data8]  = data[offset + 17];
            message.Properties[PropertyKey.Data9]  = data[offset + 18];
            message.Properties[PropertyKey.Data10] = data[offset + 19];
            message.Properties[PropertyKey.Data11] = data[offset + 20];
            message.Properties[PropertyKey.Data12] = data[offset + 21];
            message.Properties[PropertyKey.Data13] = data[offset + 22];
            message.Properties[PropertyKey.Data14] = data[offset + 23];
            count = 23;
            return(true);
        }
示例#3
0
 private static bool ButtonEvent(byte[] data, int offset, out int count, out InsteonMessage message)
 {
     //todo: something to actually process this.
     count   = 0;
     message = null;
     return(false);
 }
        internal override void OnMessage(InsteonMessage message)
        {
            var cmd2 = (byte)message.Properties[PropertyKey.Cmd2];

            if (message.MessageType == InsteonMessageType.OnCleanup)
            {
                if (cmd2 == 0x01)
                {
                    logger.InfoFormat("Dry State detected in device {0}", Address.ToString());
                    OnDeviceStatusChanged(InsteonDeviceStatus.DryDetected);
                }
                else if (cmd2 == 0x02)
                {
                    logger.InfoFormat("Wet State detect in device {0}", Address.ToString());
                    OnDeviceStatusChanged(InsteonDeviceStatus.WetDetected);
                }
                else if (cmd2 == 0x04)
                {
                    logger.InfoFormat("Heartbeat from device {0}", Address.ToString());
                    LastHeartbeat = DateTime.Now;
                    OnDeviceStatusChanged(InsteonDeviceStatus.Heartbeat);
                }
            }
            else
            {
                base.OnMessage(message);
            }
        }
        private static bool ExtendedMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length < offset + 23)
            {
                return false;
            }

            StandardMessage(data, offset, out count, out message);
            message.Properties[PropertyKey.Data1] = data[offset + 10];
            message.Properties[PropertyKey.Data2] = data[offset + 11];
            message.Properties[PropertyKey.Data3] = data[offset + 12];
            message.Properties[PropertyKey.Data4] = data[offset + 13];
            message.Properties[PropertyKey.Data5] = data[offset + 14];
            message.Properties[PropertyKey.Data6] = data[offset + 15];
            message.Properties[PropertyKey.Data7] = data[offset + 16];
            message.Properties[PropertyKey.Data8] = data[offset + 17];
            message.Properties[PropertyKey.Data9] = data[offset + 18];
            message.Properties[PropertyKey.Data10] = data[offset + 19];
            message.Properties[PropertyKey.Data11] = data[offset + 20];
            message.Properties[PropertyKey.Data12] = data[offset + 21];
            message.Properties[PropertyKey.Data13] = data[offset + 22];
            message.Properties[PropertyKey.Data14] = data[offset + 23];
            count = 23;
            return true;
        }
示例#6
0
        public EchoStatus TrySendEchoCommand(byte[] message, bool retryOnNak, int echoLength, out Dictionary <PropertyKey, int> properties)
        {
            echoMessage = null;

            echoCommand = true;
            EchoStatus status = TrySend(message, retryOnNak, echoLength);

            echoCommand = false;

            properties  = echoMessage?.Properties;
            echoMessage = null;
            return(status);
        }
示例#7
0
        private void OnMessage(InsteonMessage message)
        {
            if (message.Properties.ContainsKey(PropertyKey.FromAddress))
            {
                int address = message.Properties[PropertyKey.FromAddress];
                if (network.Devices.ContainsKey(address))
                {
                    logger.DebugFormat("Device {0} received message {1}", InsteonAddress.Format(address), message.ToString());
                    InsteonDevice device = network.Devices.Find(address);
                    device.OnMessage(message);
                }
                else if (message.MessageType == InsteonMessageType.SetButtonPressed)
                {
                    // don't warn about SetButtonPressed message from unknown devices, because it may be from a device about to be added
                }
                else if (network.AutoAdd)
                {
                    logger.DebugFormat("Unknown device {0} received message {1}, adding device", InsteonAddress.Format(address), message.ToString());

                    //note: due to how messages are handled and how devices cannot receive new messages while pending sends (I think) we should only add on certain message types.
                    // right now I've only tested devices where we get broadcast messages. Thus, we wait until the last message received.
                    if (message.MessageType == InsteonMessageType.SuccessBroadcast)
                    {
                        InsteonIdentity?id;

                        // TODO: probably shouldn't be in a while loop. Need a better way to address this
                        while (!network.Controller.TryGetLinkIdentity(new InsteonAddress(address), out id))
                        {
                            if (id != null)
                            {
                                InsteonDevice device = network.Devices.Add(new InsteonAddress(address), id.Value);
                                device.OnMessage(message);
                            }
                        }
                    }
                }
                else
                {
                    logger.WarnFormat("Unknown device {0} received message {1}. Could be Identification process.", InsteonAddress.Format(address), message.ToString());
                }
            }
            else
            {
                logger.DebugFormat("Controller received message {0}", message.ToString());
                network.Controller.OnMessage(message);
            }
        }
示例#8
0
        private bool IsDuplicateMessage(InsteonMessage message)
        {
            lock (duplicates)
            {
                // determine if message key matches an entry in the list
                if (duplicates.Any(item => message.Key == item.Key))
                {
                    return(true);
                }

                // create a new duplicte entry
                Timer timer = new Timer(DuplicateMessageTimerCallback, message.Key, 0, 1000);
                duplicates.Add(message.Key, timer);

                return(false);
            }
        }
        private bool IsDuplicateMessage(InsteonMessage message)
        {
            lock (duplicates)
            {
                // determine if message key matches an entry in the list
                if (duplicates.Any(item => message.Key == item.Key))
                {
                    return true;
                }

                // create a new duplicte entry
                Timer timer = new Timer(DuplicateMessageTimerCallback, message.Key, 0, 1000);
                duplicates.Add(message.Key, timer);

                return false;
            }
        }
        private static bool DeviceLinkCleanupMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length <= offset + 8)
            {
                return false;
            }

            var messageId = data[offset];
            var properties = new Dictionary<PropertyKey, int>();

            properties[PropertyKey.LinkStatus] = data[offset + 1];
            count = 2;

            message = new InsteonMessage(messageId, InsteonMessageType.DeviceLinkCleanup, properties);
            return true;
        }
示例#11
0
        internal override void OnMessage(InsteonMessage message)
        {

            if (message.MessageType == InsteonMessageType.OnCleanup)
            {
                SensorStatus = IOState.Closed;
                OnDeviceStatusChanged(InsteonDeviceStatus.SensorTriggerOn);
            }
            else if (message.MessageType == InsteonMessageType.OffCleanup)
            {
                SensorStatus = IOState.Open;
                OnDeviceStatusChanged(InsteonDeviceStatus.SensorTriggerOff);
            }
            else
            {
                base.OnMessage(message);
            }
        }
示例#12
0
        private static bool DeviceLinkCleanupMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length <= offset + 8)
            {
                return(false);
            }

            var messageId  = data[offset];
            var properties = new Dictionary <PropertyKey, int>();

            properties[PropertyKey.LinkStatus] = data[offset + 1];
            count = 2;

            message = new InsteonMessage(messageId, InsteonMessageType.DeviceLinkCleanup, properties);
            return(true);
        }
 internal override void OnMessage(InsteonMessage message)
 {
     var cmd2 = (byte)message.Properties[PropertyKey.Cmd2];
     
     if (cmd2 == 0x03 && message.MessageType == InsteonMessageType.OnCleanup)
     {
         logger.WarnFormat("Low battery in device {0}", Address.ToString());
         LowBattery = true;
         OnDeviceStatusChanged(InsteonDeviceStatus.LowBattery);
     }
     else if (cmd2 == 0x02 && message.MessageType == InsteonMessageType.OffCleanup)
     {
         logger.WarnFormat("Light detect in device {0}", Address.ToString());
         OnDeviceStatusChanged(InsteonDeviceStatus.LightDetected);
     }
     else
     {
         base.OnMessage(message);
     }
 }
示例#14
0
        private static bool GetInsteonModemInfo(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length < offset + 7)
            {
                return(false);
            }

            var messageId  = data[offset];
            var properties = new Dictionary <PropertyKey, int>();

            properties[PropertyKey.Address]         = new InsteonAddress(data[offset + 1], data[offset + 2], data[offset + 3]).Value;
            properties[PropertyKey.DevCat]          = data[offset + 4];
            properties[PropertyKey.SubCat]          = data[offset + 5];
            properties[PropertyKey.FirmwareVersion] = data[offset + 6];
            count = 7;

            message = new InsteonMessage(messageId, InsteonMessageType.GetInsteonModemInfo, properties);
            return(true);
        }
示例#15
0
        private void UpdateWaitItems(InsteonMessage message)
        {
            lock (waitList)
            {
                for (int i = 0; i < waitList.Count; ++i)
                {
                    WaitItem item = waitList[i];

                    if (message.MessageId == item.MessageId)
                    {
                        if (item.MessageType == null || item.MessageType.Value == message.MessageType)
                        {
                            if (item.Message == null)
                            {
                                item.Message = message;
                                item.MessageEvent.Set();
                            }
                        }
                    }
                }
            }
        }
示例#16
0
        public static bool ProcessMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length <= offset)
            {
                return(false);
            }

            switch ((InsteonModemSerialCommand)data[offset])
            {
            case InsteonModemSerialCommand.StandardMessage:
                return(StandardMessage(data, offset, out count, out message));

            case InsteonModemSerialCommand.ExtendedMessage:
                return(ExtendedMessage(data, offset, out count, out message));

            case InsteonModemSerialCommand.DeviceLinkingCompleted:
                return(DeviceLinkMessage(data, offset, out count, out message));

            case InsteonModemSerialCommand.DeviceLinkRecord:
                return(DeviceLinkRecordMessage(data, offset, out count, out message));

            case InsteonModemSerialCommand.DeviceCleanup:
                return(DeviceLinkCleanupMessage(data, offset, out count, out message));

            case InsteonModemSerialCommand.GetImInfo:
                return(GetInsteonModemInfo(data, offset, out count, out message));

            case InsteonModemSerialCommand.ButtonEventReport:
                return(ButtonEvent(data, offset, out count, out message));

            default:
                logger.DebugFormat("Received message {0} but currently not processing it.", (InsteonModemSerialCommand)data[offset]);
                break;
            }

            return(false);
        }
示例#17
0
        private static bool DeviceLinkRecordMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length < offset + 9)
            {
                return(false);
            }

            var messageId  = data[offset];
            var properties = new Dictionary <PropertyKey, int>();

            properties[PropertyKey.LinkRecordFlags] = data[offset + 1];
            properties[PropertyKey.LinkGroup]       = data[offset + 2];
            properties[PropertyKey.LinkAddress]     = new InsteonAddress(data[offset + 3], data[offset + 4], data[offset + 5]).Value;
            properties[PropertyKey.LinkData1]       = data[offset + 6];
            properties[PropertyKey.LinkData2]       = data[offset + 7];
            properties[PropertyKey.LinkData3]       = data[offset + 8];
            count = 9;

            message = new InsteonMessage(messageId, InsteonMessageType.DeviceLinkRecord, properties);
            return(true);
        }
示例#18
0
        private static bool DeviceLinkMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count   = 0;
            if (data.Length < offset + 9)
            {
                return(false);
            }

            var messageId  = data[offset];
            var properties = new Dictionary <PropertyKey, int>();

            properties[PropertyKey.LinkType]  = data[offset + 1];
            properties[PropertyKey.LinkGroup] = data[offset + 2];
            GetAddressProperty(PropertyKey.Address, data, offset + 3, out count, properties);
            properties[PropertyKey.DevCat]          = data[offset + 6];
            properties[PropertyKey.SubCat]          = data[offset + 7];
            properties[PropertyKey.FirmwareVersion] = data[offset + 8];
            count = 9;

            message = new InsteonMessage(messageId, InsteonMessageType.DeviceLink, properties);
            return(true);
        }
        private static bool DeviceLinkMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length < offset + 9)
            {
                return false;
            }

            var messageId = data[offset];
            var properties = new Dictionary<PropertyKey, int>();

            properties[PropertyKey.LinkType] = data[offset + 1];
            properties[PropertyKey.LinkGroup] = data[offset + 2];
            GetAddressProperty(PropertyKey.Address, data, offset + 3, out count, properties);
            properties[PropertyKey.DevCat] = data[offset + 6];
            properties[PropertyKey.SubCat] = data[offset + 7];
            properties[PropertyKey.FirmwareVersion] = data[offset + 8];
            count = 9;

            message = new InsteonMessage(messageId, InsteonMessageType.DeviceLink, properties);
            return true;
        }
        private static bool DeviceLinkRecordMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length < offset + 9)
            {
                return false;
            }

            var messageId = data[offset];
            var properties = new Dictionary<PropertyKey, int>();

            properties[PropertyKey.LinkRecordFlags] = data[offset + 1];
            properties[PropertyKey.LinkGroup] = data[offset + 2];
            properties[PropertyKey.LinkAddress] = new InsteonAddress(data[offset + 3], data[offset + 4], data[offset + 5]).Value;
            properties[PropertyKey.LinkData1] = data[offset + 6];
            properties[PropertyKey.LinkData2] = data[offset + 7];
            properties[PropertyKey.LinkData3] = data[offset + 8];
            count = 9;

            message = new InsteonMessage(messageId, InsteonMessageType.DeviceLinkRecord, properties);
            return true;
        }
 internal void OnMessage(InsteonMessage message)
 {
     if (message.MessageType == InsteonMessageType.DeviceLink)
     {
         var address = new InsteonAddress(message.Properties[PropertyKey.Address]);
         var identity = new InsteonIdentity((byte)message.Properties[PropertyKey.DevCat],
                                             (byte)message.Properties[PropertyKey.SubCat],
                                             (byte)message.Properties[PropertyKey.FirmwareVersion]);
         var device = network.Devices.Add(address, identity);
         timer.Stop();
         IsInLinkingMode = false;
         if (linkingMode.HasValue)
         {
             if (linkingMode != InsteonLinkMode.Delete)
             {
                 OnDeviceLinked(device);
             }
             else
             {
                 OnDeviceUnlinked(device);
             }
         }
         else
         {
             OnDeviceLinked(device);
         }
     }
 }
        private static bool GetInsteonModemInfo(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length < offset + 7)
            {
                return false;
            }

            var messageId = data[offset];
            var properties = new Dictionary<PropertyKey, int>();

            properties[PropertyKey.Address] = new InsteonAddress(data[offset + 1], data[offset + 2], data[offset + 3]).Value;
            properties[PropertyKey.DevCat] = data[offset + 4];
            properties[PropertyKey.SubCat] = data[offset + 5];
            properties[PropertyKey.FirmwareVersion] = data[offset + 6];
            count = 7;

            message = new InsteonMessage(messageId, InsteonMessageType.GetInsteonModemInfo, properties);
            return true;
        }
 private static bool ButtonEvent(byte[] data, int offset, out int count, out InsteonMessage message)
 {
     //todo: something to actually process this.
     count = 0;
     message = null;
     return false;
 }
        private void UpdateWaitItems(InsteonMessage message)
        {
            lock (waitList)
            {
                for (int i = 0; i < waitList.Count; ++i)
                {
                    WaitItem item = waitList[i];

                    if (message.MessageId == item.MessageId)
                    {
                        if (item.MessageType == null || item.MessageType.Value == message.MessageType)
                        {
                            if (item.Message == null)
                            {
                                item.Message = message;
                                item.MessageEvent.Set();
                            }
                        }
                    }
                }
            }
        }
        internal virtual void OnMessage(InsteonMessage message)
        {
            switch (message.MessageType)
            {
                case InsteonMessageType.Ack:
                    PendingCommandAck(message);
                    break;

                case InsteonMessageType.OnCleanup:
                    OnDeviceStatusChanged(InsteonDeviceStatus.On);
                    break;

                case InsteonMessageType.OffCleanup:
                    OnDeviceStatusChanged(InsteonDeviceStatus.Off);
                    break;

                case InsteonMessageType.FastOnCleanup:
                    OnDeviceStatusChanged(InsteonDeviceStatus.On);
                    OnDeviceStatusChanged(InsteonDeviceStatus.FastOn);
                    break;

                case InsteonMessageType.FastOffCleanup:
                    OnDeviceStatusChanged(InsteonDeviceStatus.Off);
                    OnDeviceStatusChanged(InsteonDeviceStatus.FastOff);
                    break;

                case InsteonMessageType.IncrementBeginBroadcast:
                    dimmerDirection = message.Properties[PropertyKey.IncrementDirection] != 0 ? DimmerDirection.Up : DimmerDirection.Down;
                    break;

                case InsteonMessageType.IncrementEndBroadcast:
                    if (dimmerDirection == DimmerDirection.Up)
                    {
                        OnDeviceStatusChanged(InsteonDeviceStatus.Brighten);
                    }
                    else if (dimmerDirection == DimmerDirection.Down)
                    {
                        OnDeviceStatusChanged(InsteonDeviceStatus.Dim);
                    }
                    break;

                case InsteonMessageType.SetButtonPressed:
                    OnSetButtonPressed(message);
                    break;
                default:
                    logger.Warn("Unhandled message type");
                    break;
            }
        }
        private void OnMessage(InsteonMessage message)
        {
            if (message.Properties.ContainsKey(PropertyKey.FromAddress))
            {
                int address = message.Properties[PropertyKey.FromAddress];
                if (network.Devices.ContainsKey(address))
                {
                    logger.DebugFormat("Device {0} received message {1}", InsteonAddress.Format(address), message.ToString());
                    InsteonDevice device = network.Devices.Find(address);
                    device.OnMessage(message);
                }
                else if (message.MessageType == InsteonMessageType.SetButtonPressed)
                {
                    // don't warn about SetButtonPressed message from unknown devices, because it may be from a device about to be added
                }
                else if (network.AutoAdd)
                {
                    logger.DebugFormat("Unknown device {0} received message {1}, adding device", InsteonAddress.Format(address), message.ToString());

                    //note: due to how messages are handled and how devices cannot receive new messages while pending sends (I think) we should only add on certain message types.
                    // right now I've only tested devices where we get broadcast messages. Thus, we wait until the last message received. 
                    if (message.MessageType == InsteonMessageType.SuccessBroadcast)
                    {
                        InsteonIdentity? id;

                        // TODO: probably shouldn't be in a while loop. Need a better way to address this
                        while (!network.Controller.TryGetLinkIdentity(new InsteonAddress(address), out id))
                        {
                            if (id != null)
                            {
                                InsteonDevice device = network.Devices.Add(new InsteonAddress(address), id.Value);
                                device.OnMessage(message);
                            }
                        }
                    }
                }
                else
                {
                    logger.WarnFormat("Unknown device {0} received message {1}. Could be Identification process.", InsteonAddress.Format(address), message.ToString());
                }
            }
            else
            {
                logger.DebugFormat("Controller received message {0}", message.ToString());
                network.Controller.OnMessage(message);
            }
        }
        public static bool ProcessMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length <= offset)
            {
                return false;
            }

            switch ((InsteonModemSerialCommand)data[offset])
            {
                case InsteonModemSerialCommand.StandardMessage:
                    return StandardMessage(data, offset, out count, out message);
                case InsteonModemSerialCommand.ExtendedMessage:
                    return ExtendedMessage(data, offset, out count, out message);
                case InsteonModemSerialCommand.DeviceLinkingCompleted:
                    return DeviceLinkMessage(data, offset, out count, out message);
                case InsteonModemSerialCommand.DeviceLinkRecord:
                    return DeviceLinkRecordMessage(data, offset, out count, out message);
                case InsteonModemSerialCommand.DeviceCleanup:
                    return DeviceLinkCleanupMessage(data, offset, out count, out message);
                case InsteonModemSerialCommand.GetImInfo:
                    return GetInsteonModemInfo(data, offset, out count, out message);
                case InsteonModemSerialCommand.ButtonEventReport:
                    return ButtonEvent(data, offset, out count, out message);
                default:
                    logger.DebugFormat("Received message {0} but currently not processing it.", (InsteonModemSerialCommand)data[offset]);
                    break;
            }

            return false;
        }
 private void OnSetButtonPressed(InsteonMessage message)
 {
     if (Identity.IsEmpty)
     {
         var devCat = (byte)message.Properties[PropertyKey.DevCat];
         var subCat = (byte)message.Properties[PropertyKey.SubCat];
         var firmwareVersion = (byte)message.Properties[PropertyKey.FirmwareVersion];
         Identity = new InsteonIdentity(devCat, subCat, firmwareVersion);
     }
     OnDeviceIdentified();
 }
        private static bool StandardMessage(byte[] data, int offset, out int count, out InsteonMessage message)
        {
            message = null;
            count = 0;
            if (data.Length < offset + 10)
            {
                return false;
            }

            var messageId = data[offset];
            var properties = new Dictionary<PropertyKey, int>();

            GetAddressProperty(PropertyKey.FromAddress, data, offset + 1, out count, properties);
            GetMessageFlagProperty(data, offset, out count, properties);
            if (properties[PropertyKey.MessageFlagsBroadcast] == 0)
            {
                GetAddressProperty(PropertyKey.ToAddress, data, offset + 4, out count, properties);
            }
            properties[PropertyKey.Cmd1] = data[offset + 8];
            properties[PropertyKey.Cmd2] = data[offset + 9];
            count = 10;

            var messageType = GetMessageType(data, offset, properties);
            message = new InsteonMessage(messageId, messageType, properties);
            return true;
        }
 // if a command is pending determines whether the current message completes the pending command
 private void PendingCommandAck(InsteonMessage message)
 {
     lock (pendingEvent)
     {
         if (pendingCommand != null)
         {
             var cmd1 = message.Properties[PropertyKey.Cmd1];
             if (System.Enum.IsDefined(typeof(InsteonDirectCommands), cmd1))
             {
                 var command = (InsteonDirectCommands)cmd1;
                 if (pendingCommand.Value == command)
                 {
                     pendingCommand = null;
                     pendingValue = 0;
                     ackTimer.Change(Timeout.Infinite, Timeout.Infinite); // stop ACK timeout timer
                     pendingEvent.Set(); // unblock any thread that may be waiting on the pending command
                 }
             }
         }
     }
 }
        public EchoStatus TrySendEchoCommand(byte[] message, bool retryOnNak, int echoLength, out Dictionary<PropertyKey, int> properties)
        {
            echoMessage = null;

            echoCommand = true;
            EchoStatus status = TrySend(message, retryOnNak, echoLength);
            echoCommand = false;

            properties = echoMessage?.Properties;
            echoMessage = null;
            return status;
        }