/***************************************************************************
 * Copyright (c) 2009 Digi International Inc., All Rights Reserved
 * 
 * This software contains proprietary and confidential information of Digi
 * International Inc.  By accepting transfer of this copy, Recipient agrees
 * to retain this software in confidence, to prevent disclosure to others,
 * and to make no use of this software other than that for which it was
 * delivered.  This is an unpublished copyrighted work of Digi International
 * Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 * prohibited.
 * 
 * Restricted Rights Legend
 *
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7031 or
 * subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 * Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 ***************************************************************************
 *
 * @Descr: XBeeSensor Class
 *
 * @History:
 *    10/01/09:   gsarabia      initial version.
 *
 ***************************************************************************/

#region Namespace Inclusions

using System;
using System.Text;

#endregion

namespace Digi.ZigBee
{
    public class XBeeSensor
    {
        #region Variables

        public struct ChannelSourceDevice
        {
            public string Name;
            public string Unit;
            public float Value;
            public DateTime? TimeStamp;
        }

        public struct BatterySourceDevice
        {
            public string Name;
            public bool Value;
            public DateTime? TimeStamp;
        }

        private XBeeDeviceManager InternalXBeeDeviceManager = null;
        private ulong InternalIEEEAddress = 0x00;

        private ushort InternalIR = 60000;
        private ushort InternalST = 500;
        private ushort InternalWH = 125;

        private bool InternalHumidityPresent = false;

        private ChannelSourceDevice InternalLight = new ChannelSourceDevice();
        private ChannelSourceDevice InternalTemperature = new ChannelSourceDevice();
        private ChannelSourceDevice InternalHumidity = new ChannelSourceDevice();
        private BatterySourceDevice InternalBattery = new BatterySourceDevice();

        #endregion

        #region Constructors

        /// <summary>Initializes a new instance of the XBeeSensor class using the specified XBee device manager, and IEEE address.</summary>
        /// <param name="MyXBeeDeviceManager">Must be set to the name of an XBeeDeviceManager object.</param>
        /// <param name="IEEEAddress">The extended address of the XBee device you would like to monitor.</param>
        public XBeeSensor(XBeeDeviceManager MyXBeeDeviceManager, ulong IEEEAddress)
        {
            InternalLight.Name = "Light";
            InternalLight.Unit = "Brightness";
            InternalLight.Value = 0.0F;
            InternalLight.TimeStamp = null;

            InternalTemperature.Name = "Temperature";
            InternalTemperature.Unit = "ºC";
            InternalTemperature.Value = 0.0F;
            InternalTemperature.TimeStamp = null;

            InternalHumidity.Name = "Humidity";
            InternalHumidity.Unit = "%";
            InternalHumidity.Value = 0.0F;
            InternalHumidity.TimeStamp = null;

            InternalBattery.Name = "Low Battery";
            InternalBattery.Value = false;
            InternalBattery.TimeStamp = null;

            InternalXBeeDeviceManager = MyXBeeDeviceManager;
            InternalIEEEAddress = IEEEAddress;

            InternalXBeeDeviceManager.ReceivePacket += new XBeeDeviceManager.ReceivePacketEventHandler(XBeeSensorRx);
            InternalXBeeDeviceManager.ExplicitReceivePacket += new XBeeDeviceManager.ExplicitReceivePacketEventHandler(XBeeSensorExplicitRx);
            InternalXBeeDeviceManager.IOSample += new XBeeDeviceManager.IOSampleEventHandler(XBeeSensorIOSampleRx);
            InternalXBeeDeviceManager.NodeIdentification += new XBeeDeviceManager.NodeIdentificationEventHandler(XBeeSensorNodeIdentificationRx);
            InternalXBeeDeviceManager.RouteRecord += new XBeeDeviceManager.RouteRecordEventHandler(XBeeSensorRouteRecordRx);
        }

        /// <summary>Initializes a new instance of the XBeeWallRouter class using the specified XBee device manager, IEEE address, and sample rate.</summary>
        /// <param name="MyXBeeDeviceManager">Must be set to the name of an XBeeDeviceManager object.</param>
        /// <param name="IEEEAddress">The extended address of the XBee device you would like to monitor.</param>
        /// <param name="SampleRate">The sample rate of the XBee Sensor.</param>
        public XBeeSensor(XBeeDeviceManager MyXBeeDeviceManager, ulong IEEEAddress, ushort SampleRate)
        {
            InternalLight.Name = "Light";
            InternalLight.Unit = "Brightness";
            InternalLight.Value = 0.0F;
            InternalLight.TimeStamp = null;

            InternalTemperature.Name = "Temperature";
            InternalTemperature.Unit = "ºC";
            InternalTemperature.Value = 0.0F;
            InternalTemperature.TimeStamp = null;

            InternalHumidity.Name = "Humidity";
            InternalHumidity.Unit = "%";
            InternalHumidity.Value = 0.0F;
            InternalHumidity.TimeStamp = null;

            InternalBattery.Name = "Low Battery";
            InternalBattery.Value = false;
            InternalBattery.TimeStamp = null;

            InternalXBeeDeviceManager = MyXBeeDeviceManager;
            InternalIEEEAddress = IEEEAddress;
            InternalIR = SampleRate;

            InternalXBeeDeviceManager.ReceivePacket += new XBeeDeviceManager.ReceivePacketEventHandler(XBeeSensorRx);
            InternalXBeeDeviceManager.ExplicitReceivePacket += new XBeeDeviceManager.ExplicitReceivePacketEventHandler(XBeeSensorExplicitRx);
            InternalXBeeDeviceManager.IOSample += new XBeeDeviceManager.IOSampleEventHandler(XBeeSensorIOSampleRx);
            InternalXBeeDeviceManager.NodeIdentification += new XBeeDeviceManager.NodeIdentificationEventHandler(XBeeSensorNodeIdentificationRx);
            InternalXBeeDeviceManager.RouteRecord += new XBeeDeviceManager.RouteRecordEventHandler(XBeeSensorRouteRecordRx);
        }

        #endregion

        #region Properties

            #region Light Channel

            /// <summary>Gets light channel source device property.</summary>
            public ChannelSourceDevice Light
            {
                get
                {
                    return InternalLight;
                }
            }

            #endregion

            #region Temperature Channel

            /// <summary>Gets temperature channel source device property.</summary>
            public ChannelSourceDevice Temperature
            {
                get
                {
                    return InternalTemperature;
                }
            }

            #endregion

            #region Humidity Channel

            /// <summary>Gets humidity channel source device property.</summary>
            public ChannelSourceDevice Humidity
            {
                get
                {
                    return InternalHumidity;
                }
            }
    
            #endregion

            #region Low Battery

            /// <summary>Gets low battery source device property.</summary>
            public BatterySourceDevice LowBattery
            {
                get
                {
                    return InternalBattery;
                }
            }

            #endregion

        #endregion

        #region Methods

            #region XBee Sensor Rx

            public void XBeeSensorRx(XBeeDeviceManager sender, ulong? IEEEAddress, ushort? NwkAddress, Rx_Options? Options, byte[] ReceivedData)
            {
                if (InternalIEEEAddress == IEEEAddress)
                {
                    if (ReceivePacket != null)
                        ReceivePacket(this, IEEEAddress, NwkAddress, Options, ReceivedData);
                }
            }

            #endregion

            #region XBee Sensor Explicit Rx

            public void XBeeSensorExplicitRx(XBeeDeviceManager sender, ulong IEEEAddress, ushort NwkAddress, byte SourceEndPoint, byte DestinationEndPoint, ushort ClusterID, ushort ProfileID, Rx_Options Options, byte[] ReceivedData)
            {
                if (InternalIEEEAddress == IEEEAddress)
                {
                    if (ExplicitReceivePacket != null)
                        ExplicitReceivePacket(this, IEEEAddress, NwkAddress, SourceEndPoint, DestinationEndPoint, ClusterID, ProfileID, Options, ReceivedData);
                }
            }

            #endregion

            #region XBee Sensor IO Sample

            public void XBeeSensorIOSampleRx(XBeeDeviceManager sender, ulong IEEEAddress, ushort NwkAddress, Rx_Options Options, byte Samples, ushort? DigitalMask, byte? AnalogMask, ushort? DigitalSamples, ushort[] AnalogSamples)
            {
                if (InternalIEEEAddress == IEEEAddress)
                {
                    DateTime Time = DateTime.Now;

                    InternalLight.Value = (float)AnalogSamples[0];
                    InternalLight.TimeStamp = Time;

                    InternalTemperature.Value = (float)((AnalogSamples[1] - 500.0) / 10.0 - 4.0);
                    InternalTemperature.TimeStamp = Time;

                    if (InternalHumidityPresent)
                    {
                        InternalHumidity.Value = (float)(((AnalogSamples[2] * 108.2 / 33.2) / 5000.0 - 0.16) / 0.0062);
                        InternalHumidity.TimeStamp = Time;
                    }

                    if ((DigitalSamples & 0x800) > 0)
                        InternalBattery.Value = false;
                    else
                        InternalBattery.Value = true;
                    InternalBattery.TimeStamp = Time;
                }
            }

            #endregion

            #region XBee Sensor Node Identification

            public void XBeeSensorNodeIdentificationRx(XBeeDeviceManager sender, Rx_Options Options, ulong IEEEAddress, ushort NwkAddress, string NodeIdentifier, ushort Parent, Node_Type DeviceType, Source_Event SourceEvent, ushort ProfileID, ushort ManufacturerID, uint? DeviceTypeID)
            {
                if (InternalIEEEAddress == IEEEAddress)
                {
                    if (NodeIdentification != null)
                        NodeIdentification(this, Options, IEEEAddress, NwkAddress, NodeIdentifier, Parent, DeviceType, SourceEvent, ProfileID, ManufacturerID, DeviceTypeID);
                }
            }

            #endregion

            #region XBee Sensor Route Record

            public void XBeeSensorRouteRecordRx(XBeeDeviceManager sender, ulong IEEEAddress, ushort NwkAddress, Rx_Options Options, byte NumberAddresses, ushort[] Addresses)
            {
                if (InternalIEEEAddress == IEEEAddress)
                {
                    if (RouteRecord != null)
                        RouteRecord(this, IEEEAddress, NwkAddress, Options, NumberAddresses, Addresses);
                }
            }

            #endregion

            #region Sleep

            /// <summary>Sets the sleep mode on the XBee.</summary>
            /// <param name="Enable">Determines if we should put the device to sleep between samples.</param>
            /// <returns>True if successful.</returns>
            public bool Sleep(bool Enable)
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;
                    if (Enable)
                        InternalXBeeDeviceManager.SleepMode(Sleep_Mode.Cyclic_Sleep);
                    else
                        InternalXBeeDeviceManager.SleepMode(Sleep_Mode.Disabled);
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

            #region Humidity Present

            /// <summary>Force a sensor which has not been detected to have humidity capability to having humidity capability present.</summary>
            /// <param name="Present">Writes the devices DD device-type value as a side effect.</param>
            /// <returns>True if successful.</returns>
            public bool HumidityPresent(bool Present)
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;
                    uint DD = InternalXBeeDeviceManager.DeviceTypeIdentifier();
                    if (Present)
                    {
                        DD = (DD & 0xFFFFFFF0) | 0xD;
                        InternalXBeeDeviceManager.DeviceTypeIdentifier(DD);
                        InternalXBeeDeviceManager.AD3DIO3Configuration(AD3DIO3.Analog_Input);
                    }
                    else
                    {
                        DD = (DD & 0xFFFFFFF0) | 0xE;
                        InternalXBeeDeviceManager.DeviceTypeIdentifier(DD);
                        InternalXBeeDeviceManager.AD3DIO3Configuration(AD3DIO3.Disabled);
                    }
                    InternalHumidityPresent = Present;
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

            #region SampleRate

            /// <summary>
            /// Sets the IO Sample Rate to enable periodic sampling. For periodic sampling 
            /// to be enabled, IO Sample Rate must be set to a non-zero value. IO Samples 
            /// are sent to the Destination Address.
            /// </summary>
            /// <param name="Time">Sample rate of the XBee Wall Router in milliseconds.</param>
            /// <returns>True if successful.</returns>
            public bool SampleRate(ushort Time)
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;
                    InternalXBeeDeviceManager.IOSampleRate(Time);
                    TimeSleep(Time);
                    InternalIR = Time;
                    InternalXBeeDeviceManager.Write();
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

            #region Time Awake

            /// <summary>
            /// Sets the time before sleep timer on an end device. Once the timer expires, an end 
            /// device may enter low power operation. Applicable for cyclic sleep end devices only.
            /// </summary>
            /// <param name="Time">Time before sleep in milliseconds.</param>
            /// <returns>True if successful.</returns>
            public bool TimeAwake(ushort Time)
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;
                    InternalXBeeDeviceManager.TimeBeforeSleep(Time);
                    InternalST = Time;
                    InternalXBeeDeviceManager.Write();
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

            #region Sample Predelay

            /// <summary>
            /// Sets the wake host timer value. If the wake host timer is set to a nonzero value, 
            /// this timer specifies a time in millisecond that the device should allow after waking 
            /// from sleep before sending data out the UART or transmitting an IO sample.
            /// If serial characters are received, the wake host timer is stopped immediately.
            /// </summary>
            /// <param name="Time">Time wake host in milliseconds.</param>
            /// <returns>True if successful.</returns>
            public bool SamplePredelay(ushort Time)
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;
                    InternalXBeeDeviceManager.TimeBeforeSleep(Time);
                    InternalWH = Time;
                    InternalXBeeDeviceManager.Write();
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

            #region Time Sleep

            /// <summary>
            /// Sets the value that determines how long the end device will sleep at a time.
            /// </summary>
            /// <param name="Time">Period time in milliseconds.</param>
            /// <returns>True if successful.</returns>
            private bool TimeSleep(ushort Time)
            {
                bool Status = false;
                try
                {
                    if (Time >= 200 && Time <= 28000)
                    {
                        // Set sleep options (no always wake, no extended sleep)
                        InternalXBeeDeviceManager.SleepOptions(0x00);

                        // Set sleep period
                        InternalXBeeDeviceManager.NumberSleepPeriods(1);
                        InternalXBeeDeviceManager.SleepPeriod(Time);
                        
                        InternalXBeeDeviceManager.Write();
                    }
                    else if (Time > 28000)
                    {
                        // Set sleep options (always wake, extended sleep)
                        InternalXBeeDeviceManager.SleepOptions(0x06);

                        // Break the requested time into two parameters
                        ushort SP = 1;
                        ushort TimeAux = Time;
                        while ((TimeAux % 2 == 0) && (SP * 2 < 28000))
                        {
                            SP *= 2;
                            TimeAux /= 2;
                        }
                        ushort i = 3;
                        while ((i <= Math.Sqrt(TimeAux) + 1) && (TimeAux > 1) && (SP * i < 28000))
                        {
                            if (TimeAux % i == 0)
                            {
                                while ((TimeAux % i) == 0)
                                {
                                    SP *= i;
                                    TimeAux /= i;
                                }
                            }
                            else
                                i += 2;
                        }

                        // Set sleep period
                        InternalXBeeDeviceManager.NumberSleepPeriods((ushort)(Time / SP));
                        InternalXBeeDeviceManager.SleepPeriod(SP);
                        
                        InternalXBeeDeviceManager.Write();
                    }
                    else 
                    {
                        throw new Exception("Time is out of legal range.");
                    }
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                return Status;
            }

            #endregion

            #region Start

            /// <summary>Start the device driver.</summary>
            /// <returns>True if successful.</returns>
            public bool Start()
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    // Get the host IEEE address
                    ulong IEEEAddress = InternalXBeeDeviceManager.SerialNumber();

                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;

                    // Set the destination for I/O samples to be the host
                    InternalXBeeDeviceManager.DestinationAddress(IEEEAddress);

                    uint DD = InternalXBeeDeviceManager.DeviceTypeIdentifier();
                    if ((DD & 0xF) == 0xD)
                        InternalHumidityPresent = true;
                    else
                        InternalHumidityPresent = false;
                    
                    // Configure pins DI1, DI2 & DI3 for analog input
                    InternalXBeeDeviceManager.AD1DIO1Configuration(AD1DIO1.Analog_Input);
                    InternalXBeeDeviceManager.AD2DIO2Configuration(AD2DIO2.Analog_Input);
                    if (InternalHumidityPresent)
                        InternalXBeeDeviceManager.AD3DIO3Configuration(AD3DIO3.Analog_Input);

                    // Configure battery-monitor pin DIO11 for digital input
                    InternalXBeeDeviceManager.DIO11Configuration(DIO11.Digital_Input);
                    
                    // Enable change detection on DIO11
                    InternalXBeeDeviceManager.IODigitalChangeDetection(0x800);

                    // Configure the time awake
                    InternalXBeeDeviceManager.TimeBeforeSleep(InternalST);

                    // Configure the Sample Predelay
                    InternalXBeeDeviceManager.WakeHost(InternalWH);

                    // Configure the sleep period
                    TimeSleep(InternalIR);

                    // Configure the IO Sample Rate
                    InternalXBeeDeviceManager.IOSampleRate(InternalIR);

                    InternalXBeeDeviceManager.Write();

                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

            #region Stop

            /// <summary>Stop the device driver..</summary>
            /// <returns>True if successful.</returns>
            public bool Stop()
            {
                bool XBeeRemoteATCmdEnable = InternalXBeeDeviceManager.RemoteATCmdEnable;
                byte XBeeBroadcastRadius = InternalXBeeDeviceManager.BroadcastRadius;
                bool XBeeMulticastTransmissionEnable = InternalXBeeDeviceManager.MulticastTransmissionEnable;
                bool XBeeExplicitAddressingEnable = InternalXBeeDeviceManager.ExplicitAddressingEnable;
                InternalXBeeDeviceManager.RemoteATCmdEnable = false;
                InternalXBeeDeviceManager.BroadcastRadius = 0x00;
                InternalXBeeDeviceManager.MulticastTransmissionEnable = false;
                InternalXBeeDeviceManager.ExplicitAddressingEnable = false;

                bool Status = false;
                try
                {
                    InternalXBeeDeviceManager.DestinationAddress(InternalIEEEAddress);
                    InternalXBeeDeviceManager.RemoteATCmdEnable = true;
                    InternalXBeeDeviceManager.IOSampleRate(0);
                    InternalXBeeDeviceManager.Write();
                    Status = true;
                }
                catch
                {
                    Status = false;
                }
                finally
                {
                    InternalXBeeDeviceManager.ExplicitAddressingEnable = XBeeExplicitAddressingEnable;
                    InternalXBeeDeviceManager.MulticastTransmissionEnable = XBeeMulticastTransmissionEnable;
                    InternalXBeeDeviceManager.BroadcastRadius = XBeeBroadcastRadius;
                    InternalXBeeDeviceManager.RemoteATCmdEnable = XBeeRemoteATCmdEnable;
                }
                return Status;
            }

            #endregion

        #endregion

        #region Events & Delegates

        public event XBeeReceivePacketEventHandler ReceivePacket;
        public delegate void XBeeReceivePacketEventHandler(XBeeSensor sender, ulong? IEEEAddress, ushort? NwkAddress, Rx_Options? Options, byte[] ReceivedData);

        public event XBeeExplicitReceivePacketEventHandler ExplicitReceivePacket;
        public delegate void XBeeExplicitReceivePacketEventHandler(XBeeSensor sender, ulong IEEEAddress, ushort NwkAddress, byte SourceEndPoint, byte DestinationEndPoint, ushort ClusterID, ushort ProfileID, Rx_Options Options, byte[] ReceivedData);

        public event XBeeNodeIdentificationEventHandler NodeIdentification;
        public delegate void XBeeNodeIdentificationEventHandler(XBeeSensor sender, Rx_Options Options, ulong IEEEAddress, ushort NwkAddress, string NodeIdentifier, ushort Parent, Node_Type DeviceType, Source_Event SourceEvent, ushort ProfileID, ushort ManufacturerID, uint? DeviceTypeID);

        public event XBeeRouteRecordEventHandler RouteRecord;
        public delegate void XBeeRouteRecordEventHandler(XBeeSensor sender, ulong IEEEAddress, ushort NwkAddress, Rx_Options Options, byte NumberAddresses, ushort[] Addresses);

        #endregion
    }
}
     
