/**
         * Utility function to join an existing network as a Router
         *
         * @param networkParameters the required {@link EmberNetworkParameters}
         * @param linkKey the {@link ZigBeeKey} with the initial link key. This cannot be set to all 00 or all FF.
         */
        public void JoinNetwork(EmberNetworkParameters networkParameters, ZigBeeKey linkKey)
        {
            Log.Debug("Joining Ember network with configuration {Parameters}", networkParameters);

            // Leave the current network so we can initialise a new network
            EmberNcp ncp = new EmberNcp(_protocolHandler);

            if (CheckNetworkJoined())
            {
                ncp.LeaveNetwork();
            }

            ncp.ClearKeyTable();

            // Initialise security - no network key as we'll get that from the coordinator
            SetSecurityState(linkKey, null);

            DoJoinNetwork(networkParameters);
        }
        /**
         * Performs an energy scan and returns the quietest channel
         *
         * @param ncp {@link EmberNcp}
         * @param scanDuration duration of the scan on each channel
         * @return the quietest channel, or null on error
         */
        private int?DoEnergyScan(EmberNcp ncp, int scanDuration)
        {
            List <EzspEnergyScanResultHandler> channels = ncp.DoEnergyScan(ZigBeeChannelMask.CHANNEL_MASK_2GHZ, scanDuration);

            if (channels == null)
            {
                Log.Debug("Error during energy scan: {Status}", ncp.GetLastStatus());
                return(null);
            }

            int lowestRSSI    = 999;
            int lowestChannel = 11;

            foreach (EzspEnergyScanResultHandler channel in channels)
            {
                if (channel.GetMaxRssiValue() < lowestRSSI)
                {
                    lowestRSSI    = channel.GetMaxRssiValue();
                    lowestChannel = channel.GetChannel();
                }
            }

            return(lowestChannel);
        }
 /**
  * Constructor to set the {@link EmberNcp}
  *
  * @param ncp the {@link EmberNcp} used to communicate with the NCP
  */
 public EmberStackConfiguration(EmberNcp ncp)
 {
     this._ncp = ncp;
 }
        /**
         * This utility function uses emberStartScan, emberStopScan, emberScanCompleteHandler, emberEnergyScanResultHandler,
         * and emberNetworkFoundHandler to discover other networks or determine the background noise level. It then uses
         * emberFormNetwork to create a new network with a unique PAN-ID on a channel with low background noise.
         * <p>
         * Setting the PAN-ID or Extended PAN-ID to 0 will set these values to a random value.
         * <p>
         * If channel is set to 0, the quietest channel will be used.
         *
         * @param networkParameters the required {@link EmberNetworkParameters}
         * @param linkKey the {@link ZigBeeKey} with the link key. This can not be set to all 00 or all FF.
         * @param networkKey the {@link ZigBeeKey} with the network key. This can not be set to all 00 or all FF.
         */
        public void FormNetwork(EmberNetworkParameters networkParameters, ZigBeeKey linkKey, ZigBeeKey networkKey)
        {
            if (networkParameters.GetExtendedPanId() == null)
            {
                networkParameters.SetExtendedPanId(new ExtendedPanId());
            }

            Log.Debug("Initialising Ember network with configuration {NetworkParameters}", networkParameters);

            EmberNcp ncp = new EmberNcp(_protocolHandler);

            // Leave the current network so we can initialise a new network
            if (CheckNetworkJoined())
            {
                ncp.LeaveNetwork();
            }

            ncp.ClearKeyTable();

            // Perform an energy scan to find a clear channel
            int?quietestChannel = DoEnergyScan(ncp, _scanDuration);

            Log.Debug("Energy scan reports quietest channel is {QuietestChannel}", quietestChannel);

            // Check if any current networks were found and avoid those channels, PAN ID and especially Extended PAN ID
            ncp.DoActiveScan(ZigBeeChannelMask.CHANNEL_MASK_2GHZ, _scanDuration);

            // Read the current network parameters
            GetNetworkParameters();

            // Create a random PAN ID and Extended PAN ID
            if (networkParameters.GetPanId() == 0 || networkParameters.GetExtendedPanId().Equals(new ExtendedPanId()))
            {
                Random random = new Random();
                int    panId  = random.Next(65535);
                networkParameters.SetPanId(panId);
                Log.Debug("Created random PAN ID: {PanId}", panId);

                byte[] extendedPanIdBytes = new byte[8];
                random.NextBytes(extendedPanIdBytes);
                ExtendedPanId extendedPanId = new ExtendedPanId(extendedPanIdBytes);
                networkParameters.SetExtendedPanId(extendedPanId);
                Log.Debug("Created random Extended PAN ID: {ExtendedPanId}", extendedPanId.ToString());
            }

            if (networkParameters.GetRadioChannel() == 0 && quietestChannel.HasValue)
            {
                networkParameters.SetRadioChannel(quietestChannel.Value);
            }

            // If the channel set is empty, use the single channel defined above
            if (networkParameters.GetChannels() == 0)
            {
                networkParameters.SetChannels(1 << networkParameters.GetRadioChannel());
            }

            // Initialise security
            SetSecurityState(linkKey, networkKey);

            // And now form the network
            DoFormNetwork(networkParameters);
        }
        /**
         * Sets the initial security state
         *
         * @param linkKey the initial {@link ZigBeeKey}
         * @param networkKey the initial {@link ZigBeeKey}
         * @return true if the security state was set successfully
         */
        private bool SetSecurityState(ZigBeeKey linkKey, ZigBeeKey networkKey)
        {
            EzspSetInitialSecurityStateRequest securityState = new EzspSetInitialSecurityStateRequest();
            EmberInitialSecurityState          state         = new EmberInitialSecurityState();

            state.AddBitmask(EmberInitialSecurityBitmask.EMBER_TRUST_CENTER_GLOBAL_LINK_KEY);

            EmberKeyData networkKeyData = new EmberKeyData();

            if (networkKey != null)
            {
                networkKeyData.SetContents(Array.ConvertAll(networkKey.Key, c => (int)c));
                state.AddBitmask(EmberInitialSecurityBitmask.EMBER_HAVE_NETWORK_KEY);
                if (networkKey.SequenceNumber.HasValue)
                {
                    state.SetNetworkKeySequenceNumber(networkKey.SequenceNumber.Value);
                }
            }
            state.SetNetworkKey(networkKeyData);

            EmberKeyData linkKeyData = new EmberKeyData();

            if (linkKey != null)
            {
                linkKeyData.SetContents(Array.ConvertAll(linkKey.Key, c => (int)c));
                state.AddBitmask(EmberInitialSecurityBitmask.EMBER_HAVE_PRECONFIGURED_KEY);
                state.AddBitmask(EmberInitialSecurityBitmask.EMBER_REQUIRE_ENCRYPTED_KEY);
            }
            state.SetPreconfiguredKey(linkKeyData);

            state.SetPreconfiguredTrustCenterEui64(new IeeeAddress());

            securityState.SetState(state);
            EzspSingleResponseTransaction transaction = new EzspSingleResponseTransaction(securityState, typeof(EzspSetInitialSecurityStateResponse));

            _protocolHandler.SendEzspTransaction(transaction);
            EzspSetInitialSecurityStateResponse securityStateResponse = (EzspSetInitialSecurityStateResponse)transaction.GetResponse();

            Log.Debug(securityStateResponse.ToString());
            if (securityStateResponse.GetStatus() != EmberStatus.EMBER_SUCCESS)
            {
                Log.Debug("Error during retrieval of network parameters: {Response}", securityStateResponse);
                return(false);
            }

            EmberNcp ncp = new EmberNcp(_protocolHandler);

            if (networkKey != null && networkKey.OutgoingFrameCounter.HasValue)
            {
                EzspSerializer serializer = new EzspSerializer();
                serializer.SerializeUInt32(networkKey.OutgoingFrameCounter.Value);
                if (ncp.SetValue(EzspValueId.EZSP_VALUE_NWK_FRAME_COUNTER, serializer.GetPayload()) != EzspStatus.EZSP_SUCCESS)
                {
                    return(false);
                }
            }
            if (linkKey != null && linkKey.OutgoingFrameCounter.HasValue)
            {
                EzspSerializer serializer = new EzspSerializer();
                serializer.SerializeUInt32(linkKey.OutgoingFrameCounter.Value);
                if (ncp.SetValue(EzspValueId.EZSP_VALUE_APS_FRAME_COUNTER, serializer.GetPayload()) != EzspStatus.EZSP_SUCCESS)
                {
                    return(false);
                }
            }

            return(true);
        }