/// <summary>
        /// Creates a port from the specified settings node tree.
        /// </summary>
        /// <param name="portNode">The port node.</param>
        /// <returns>The device port.</returns>
        /// <exception cref="System.Exception">
        /// Invalid port format.
        /// </exception>
        protected virtual IDevicePort CreatePort(SettingsNode portNode)
        {
            SettingsNode tcpAddrNode = null;

            if (portNode.ContainsName("Address"))
            {
                tcpAddrNode = portNode["Address"];
            }
            else if (portNode.ContainsName("IPAddress"))
            {
                tcpAddrNode = portNode["IPAddress"];
            }
            else if (portNode.ContainsName("IpAddress"))
            {
                tcpAddrNode = portNode["IpAddress"];
            }
            else if (portNode.ContainsName("TCPAddress"))
            {
                tcpAddrNode = portNode["TCPAddress"];
            }
            else if (portNode.ContainsName("TcpAddress"))
            {
                tcpAddrNode = portNode["TcpAddress"];
            }

            if (tcpAddrNode != null)
            {
                string    ipAddrName = tcpAddrNode.GetValueAs <string>();
                IPAddress ipAddress;

                if (!IPAddress.TryParse(ipAddrName, out ipAddress))
                {
                    throw new Exception(String.Format("'{0}' is an invalid IP address.", ipAddrName));
                }

                DevicePortTcp tcpPort = new DevicePortTcp(ipAddress);

                if (portNode.ContainsName("Port"))
                {
                    tcpPort.Port = portNode["Port"].GetValueAs <int>();
                }

                if (portNode.ContainsName("ReplyAddress"))
                {
                    string    replyAddrName = portNode["ReplyAddress"].GetValueAs <string>();
                    IPAddress replyAddress;

                    if (!IPAddress.TryParse(replyAddrName, out replyAddress))
                    {
                        throw new Exception(String.Format("'{0}' is an invalid reply IP address.", replyAddrName));
                    }

                    tcpPort.ReplyAddress = replyAddress;

                    if (portNode.ContainsName("ReplyPort"))
                    {
                        tcpPort.ReplyPort = portNode["ReplyPort"].GetValueAs <int>();
                    }
                }

                return(tcpPort);
            }

            if (portNode.ContainsName("Number"))
            {
                int portNum = portNode["Number"].GetValueAs <int>();
                return(new DevicePortNumber(portNum));
            }

            if (portNode.ContainsName("Name"))
            {
                string portName = portNode["Name"].GetValueAs <string>();
                return(new DevicePortName(portName));
            }

            if (portNode.HasAValue)
            {
                string portShorthand = portNode.GetValueAs <string>();
                return(CreatePort(portShorthand));
            }

            throw new Exception("Invalid port format.");
        }
        /// <summary>
        /// Finds or creates the device specified in the settings node tree.
        /// </summary>
        /// <param name="deviceNode">The device node.</param>
        /// <returns></returns>
        public virtual IDevice FindOrCreateDevice(SettingsNode deviceNode)
        {
            string deviceName = deviceNode.Name;

            if (deviceNode.ExistsAndHasAValue <string>("Name"))
            {
                deviceName = deviceNode["Name"].GetValueAs <string>();
            }

            if (!deviceNode.ContainsName("Model"))
            {
                Log.Error(this, "Device '{0}' has an undefined model type. Ensure that the device settings include a 'Model' node.", deviceName);
                return(null);
            }

            string modelName = deviceNode["Model"].GetValueAs <string>();
            string modelKey  = modelName.ToLower();

            if (!_validDeviceTypes.ContainsKey(modelKey))
            {
                Log.Error(this, "Device '{0}' has an unresolved device model type '{1}'. Device cannot be created.", deviceName, modelName);
                return(null);
            }

            IDevice     device = null;
            IDevicePort port   = null;

            device = _devices.FirstOrDefault(d => deviceName.Equals(d.Name, StringComparison.CurrentCultureIgnoreCase));

            if (device == null)
            {
                SettingsNode portNode = deviceNode["Port"];
                if (portNode == null)
                {
                    Log.Error(this, "Device '{0}' is using the default port.", deviceName);
                }
                else
                {
                    try
                    {
                        Log.Info(this, "Device '{0}' discovering port settings...", deviceName);

                        port = CreatePort(portNode);

                        Log.Info(this, "Device '{0}' port settings = {1}", deviceName, port);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(this, "Device '{0}' has invalid port settings. {1}", deviceName, ex);
                        Log.Error(this, "Device '{0}' is switching to the default port.", deviceName);
                    }

                    device = _devices.FirstOrDefault(d =>
                                                     modelName.Equals(d.GetType().Name, StringComparison.CurrentCultureIgnoreCase) &&
                                                     port.Equals(d.Port));

                    if (device != null)
                    {
                        Log.Error(this, "Device '{0}' has the same port settings as Device '{1}'.", deviceName, device.Name);
                    }
                }

                try
                {
                    Type type = _validDeviceTypes[modelKey];
                    device = (IDevice)Activator.CreateInstance(type);
                }
                catch (Exception ex)
                {
                    Log.Error(this, "Device '{0}' could not be instantiated.", deviceName);
                    Log.Error(this, ex.ToString());
                    return(null);
                }

                device.Name = deviceName;
                device.Port = port;

                _devices.Add(device);
            }

            if (deviceNode.ExistsAndHasAValue <bool>("Logging"))
            {
                device.Logging = deviceNode["Logging"].GetValueAs <bool>();
            }
            else if (deviceNode.ExistsAndHasAValue <bool>("Log"))
            {
                device.Logging = deviceNode["Log"].GetValueAs <bool>();
            }

            if (device.Logging)
            {
                Log.Info(this, "Device '{0}' logging is enabled.", deviceName);
            }

            return(device);
        }