コード例 #1
0
        /// <summary>
        /// Worker thread to indicate received frames to upper layer sequentially.
        /// </summary>
        private void DataIndicationThread()
        {
            while (true)
            {
                _rxEvent.WaitOne();
                if (_rxThreadExit)
                    break;

                while (true)
                {
                    Frame frame = null;
                    lock (_rxFrameQueue)
                    {
                        frame = _rxFrameQueue.GetFrame();
                    }

                    if (frame == null)
                        break;

                    byte lqi = frame.ReadByte(frame.LengthDataUsed - 1); // pull LQI from frame
                    frame.DeleteFromBack(1);

                    Header hdr = new Header();
                    if (hdr.ReadFromFrameHeader(frame, true))
                    {
                        ReceiveData(hdr, ref frame, lqi);
                    }

                    Frame.Release(ref frame);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// process frame from Phy layer. FCS has been removed already.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="frame"></param>
        /// <param name="linkQuality"></param>
        public void PhyDataIndication(
            IPhyDataSap sender,
            ref Frame frame,
            Byte linkQuality)
        {
            Frames.Type type;
            bool ok = Header.GetType(frame, out type);

            if (ok && type == Frames.Type.Data)
            {
                frame.AllocBack(1);
                frame.Write(frame.LengthDataUsed - 1, linkQuality);
                lock (_rxFrameQueue)
                {
                    _rxFrameQueue.AddFrame(ref frame);
                }

                _rxEvent.Set();
                Frame.Release(ref frame);
                return;
            }

            Header hdr = new Header();
            if (hdr.ReadFromFrameHeader(frame, true))
            {
                switch (hdr.fcs.Type)
                {
                    case Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Type.Beacon:
                        ReceiveBeacon(hdr, ref frame, linkQuality);
                        break;
                    case Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Type.Cmd:
                        ReceiveCommand(hdr, ref frame, linkQuality);
                        break;
                    default:
                        // drop, data and ack frames are handled before
                        break;
                }
            }
        }
コード例 #3
0
        private void ReceiveBeacon(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            bool ok = true;
            ok &= hdr.fcs.DstAddrMode == AddressingMode.None;
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.Short || hdr.fcs.SrcAddrMode == AddressingMode.Extended);
            ok &= (_state.macPromiscousMode || hdr.srcPanId == _state.macPanId || _state.macPanId == State.cBroadcastPanId);
            if (hdr.fcs.Security)
                ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2006);
            else
                ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            if (!ok)
                return;

            Beacon beacon = new Beacon();
            if (beacon.ReadFromFrame(ref frame))
            {
                PanDescriptor pd = new PanDescriptor();
                if (hdr.fcs.SrcAddrMode == AddressingMode.Short)
                    pd.coordAddr.ShortAddress = hdr.srcAddrShort;
                else
                    pd.coordAddr.ExtendedAddress = hdr.srcAddrExt;
                pd.coordPanId = hdr.srcPanId;
                pd.logicalChannel = _state.phyChannelNumber;
                pd.channelPage = _state.phyChannelPage;
                //pd.superframeSpec
                pd.gtsPermit = (beacon.gtsPermit > 0);
                pd.linkQuality = linkQuality;
                //pd.timeStamp
                //pd.securityFailure
                //pd.securityOptions

                if (!_state.scanning || beacon.payload != null)
                { // signal upper layer
                    BeaconNotifyIndicationHandler ind = _BeaconNotifyIndication;
                    if (ind != null)
                    {
                        ind.Invoke(this, hdr.seqNo, pd, beacon.shortAddrPending, beacon.extAddrPending, beacon.payload);
                        beacon.payload = null;
                    }
                }

                if (_state.scanning)
                {
                    lock (_scannedBeacons)
                    {
                        _scannedBeacons.Add(pd);
                    }
                }
            }
        }
コード例 #4
0
        private void ReceiveGtsRequest(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.9
            bool ok = true;
            ok &= (_state.panCoordinator == true);
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.None);
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.Short);
            ok &= (hdr.srcPanId == _state.macPanId);

            Command.GtsRequest msg = new Command.GtsRequest();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                // FIXME: not implemented
            }
        }
コード例 #5
0
        private void ReceiveCoordinatorRealignment(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.8
            bool ok = true;
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003 ||
                hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2006);
            ok &= (hdr.fcs.DstAddrMode != AddressingMode.None);
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.Extended);
            ok &= (hdr.dstPanId == State.cBroadcastPanId);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.Extended && hdr.dstAddrExt == _state.aExtendedAddress) ||
                (hdr.fcs.DstAddrMode == AddressingMode.Short && hdr.dstAddrShort == _state.macShortAddr);
            ok &= (hdr.fcs.PanIdCompression == false);

            Command.CoordinatorRealignment msg = new Command.CoordinatorRealignment();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                // FIXME: not implemented
            }
        }
コード例 #6
0
        private void ReceiveBeaconRequest(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.7
            bool ok = true;
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.Short);
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.None);
            ok &= (hdr.dstPanId == State.cBroadcastPanId);
            ok &= (hdr.dstAddrShort == State.cBroadcastShortAddr);

            Command.BeaconRequest msg = new Command.BeaconRequest();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                TaskBeaconRequest task = new TaskBeaconRequest();
                _taskQueue.Add(task);
            }
        }
コード例 #7
0
        private void ReceiveOrphanNotification(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.6
            bool ok = true;
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.Extended);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.Short);
            ok &= (hdr.fcs.PanIdCompression == true);
            ok &= (hdr.dstPanId == State.cBroadcastPanId);
            ok &= (hdr.dstAddrShort == State.cBroadcastShortAddr);

            Command.OrphanNotification msg = new Command.OrphanNotification();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                // FIXME: not implemented
            }
        }
コード例 #8
0
        private void ReceiveDataRequest(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.4
            bool ok = true;
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.None && hdr.dstPanId == _state.macPanId) ||
                (hdr.fcs.DstAddrMode == AddressingMode.Extended && hdr.dstAddrExt == _state.aExtendedAddress) ||
                (hdr.fcs.DstAddrMode == AddressingMode.Short && hdr.dstAddrShort == _state.macShortAddr);
            ok &= (hdr.fcs.SrcAddrMode != AddressingMode.None);

            Command.DataRequest msg = new Command.DataRequest();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                // FIXME: not implemented
            }
        }
コード例 #9
0
        private void ReceiveAssociationResponse(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.2
            bool ok = true;
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.Extended && hdr.dstAddrExt == _state.aExtendedAddress);
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.Extended);
            ok &= (hdr.fcs.PanIdCompression == true);
            ok &= (hdr.dstPanId != State.cBroadcastPanId); // the real PAN ID

            Command.AssociationResponse msg = new Command.AssociationResponse();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                // FIXME: not implemented
            }
        }
コード例 #10
0
        private void ReceiveAssociationRequest(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            // see 7.3.1
            bool ok = true;
            ok &= (hdr.fcs.Version == Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003);
            ok &= (hdr.fcs.SrcAddrMode == AddressingMode.Extended);
            ok &= (hdr.fcs.DstAddrMode == AddressingMode.Extended && hdr.dstAddrExt == _state.aExtendedAddress) ||
                  (hdr.fcs.DstAddrMode == AddressingMode.Short && hdr.dstAddrShort == _state.macShortAddr);
            ok &= (hdr.fcs.PanIdCompression == false);
            ok &= (hdr.dstPanId == _state.macPanId);
            ok &= (hdr.srcPanId == State.cBroadcastPanId);

            Command.AssociationRequest msg = new Command.AssociationRequest();
            if (ok && msg.ReadFromFrame(ref frame))
            {
                AssociateIndicationHandler ind = AssociateIndication;
                if (ind != null)
                    ind.Invoke(this, hdr.srcAddrExt, msg.capabilities, new SecurityOptions());
            }
        }
コード例 #11
0
        private void ReceiveData(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            MacAddress srcAddr = new MacAddress(); // default: NoAddress
            MacAddress dstAddr = new MacAddress(); // default: NoAddress
            UInt16 srcPanId = State.cBroadcastPanId;
            UInt16 dstPanId = State.cBroadcastPanId;

            bool drop = (hdr.fcs.Version != Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2003 &&
                hdr.fcs.Version != Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Version.IEEE2006);
            if (!drop)
            {
                switch (hdr.fcs.DstAddrMode)
                {
                    case AddressingMode.None:
                        if (!_state.macPromiscousMode && !_state.panCoordinator)
                        {
                            drop = true;
                        }
                        break;
                    case AddressingMode.Short:
                        if (!_state.macPromiscousMode &&
                            ((hdr.dstAddrShort != _state.macShortAddr && hdr.dstAddrShort != State.cBroadcastShortAddr) ||
                            (hdr.dstPanId != _state.macPanId && hdr.dstPanId != State.cBroadcastPanId)))
                        {
                            drop = true;
                        }
                        else
                        {
                            dstAddr.ShortAddress = hdr.dstAddrShort;
                            dstPanId = hdr.dstPanId;
                        }
                        break;
                    case AddressingMode.Extended:
                        if (!_state.macPromiscousMode &&
                            ((hdr.dstAddrExt != _state.aExtendedAddress ||
                            (hdr.dstPanId != _state.macPanId && hdr.dstPanId != State.cBroadcastPanId))))
                        {
                            drop = true;
                        }
                        else
                        {
                            dstAddr.ExtendedAddress = hdr.dstAddrExt;
                            dstPanId = hdr.dstPanId;
                        }
                        break;
                    case AddressingMode.Reserved:
                        drop = true;
                        break;
                }
            }

            if (!drop)
            {
                bool havePanId = false;
                switch (hdr.fcs.SrcAddrMode)
                {
                    case AddressingMode.None:
                        if (dstAddr.Mode == MacAddressingMode.NoAddress)
                            drop = true; // at least one address must be valid
                        break;
                    case AddressingMode.Short:
                        srcAddr.ShortAddress = hdr.srcAddrShort;
                        havePanId = true;
                        break;
                    case AddressingMode.Extended:
                        srcAddr.ExtendedAddress = hdr.srcAddrExt;
                        havePanId = true;
                        break;
                    case AddressingMode.Reserved:
                        drop = true;
                        break;
                }

                if (havePanId)
                {
                    if (hdr.fcs.PanIdCompression)
                    {
                        if (dstAddr.Mode == MacAddressingMode.NoAddress)
                        {
                            drop = true;
                        }
                        else
                        {
                            srcPanId = dstPanId;
                        }
                    }
                    else
                    {
                        srcPanId = hdr.srcPanId;
                    }
                }
            }

            if (!drop)
            {
                DataIndicationHandler ind = _DataIndication;
                if (ind != null)
                {
                    // synchronous from dataIndicationThread
                    try
                    {
                        ind.Invoke(this, srcAddr, srcPanId, dstAddr, dstPanId,
                            frame, linkQuality, hdr.seqNo, 0, new SecurityOptions());
                    }
                    catch (Exception) { }
                    frame = null;
                }
            }
        }
コード例 #12
0
        private void ReceiveCommand(
            Header hdr,
            ref Frame frame,
            Byte linkQuality)
        {
            bool ok = true;

            ok &= (frame != null && frame.LengthDataUsed > 0);
            ok &= (hdr.fcs.DstAddrMode != AddressingMode.Reserved);
            ok &= (hdr.fcs.SrcAddrMode != AddressingMode.Reserved);
            ok &= (hdr.fcs.DstAddrMode != AddressingMode.None || hdr.fcs.SrcAddrMode != AddressingMode.None);

            if (ok)
            {
                switch (hdr.fcs.DstAddrMode)
                {
                    case AddressingMode.Short:
                        ok &= (hdr.dstAddrShort == _state.macShortAddr || hdr.dstAddrShort == State.cBroadcastShortAddr);
                        ok &= (hdr.dstPanId == _state.macPanId || hdr.dstPanId == State.cBroadcastPanId);
                        break;
                    case AddressingMode.Extended:
                        ok &= (hdr.dstAddrExt == _state.aExtendedAddress);
                        ok &= (hdr.dstPanId == _state.macPanId || hdr.dstPanId == State.cBroadcastPanId);
                        break;
                    case AddressingMode.None:
                        ok &= (_state.panCoordinator);
                        ok &= (hdr.srcPanId == _state.macPanId);
                        break;
                }
            }

            if (ok)
            {
                switch (Command.DecodeType(frame))
                {
                    case Command.Type.AssociationRequest:
                        ReceiveAssociationRequest(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.AssociationResponse:
                        ReceiveAssociationResponse(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.DisassociationNotification:
                        ReceiveDisassociationNotification(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.DataRequest:
                        ReceiveDataRequest(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.PanIdConflictNotification:
                        ReceivePanIdConflictNotification(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.OrphanNotification:
                        ReceiveOrphanNotification(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.BeaconRequest:
                        ReceiveBeaconRequest(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.CoordinatorRealignment:
                        ReceiveCoordinatorRealignment(hdr, ref frame, linkQuality);
                        break;
                    case Command.Type.GtsRequest:
                        ReceiveGtsRequest(hdr, ref frame, linkQuality);
                        break;
                }
            }
        }
コード例 #13
0
ファイル: Mac.cs プロジェクト: prabby/miniclr
        private Frame Encode(Header header, Command.Base cmd)
        {
            int lenHeader = header.Length();
            int len = _state.phyFrameHead + lenHeader; ;
            Frame frame = Frame.GetFrame(len, cmd.LengthMax + _state.phyFrameTail);
            if (!cmd.WriteToFrame(frame) || !header.WriteToFrameHeader(frame))
            {
                Frame.Release(ref frame);
                Trace.Print("Mac: unable to create command frame");
                return null;
            }

            return frame;
        }
コード例 #14
0
        private void BeaconRequest()
        {
            bool send = true;
            Frame frame = null;

            lock (_state)
            {
                if (_state.autoBeacon)
                {
                    Header hdr = new Header();
                    hdr.fcs.SrcAddrMode = AddressingMode.Short;
                    hdr.srcAddrShort = _state.macShortAddr;
                    hdr.srcPanId = _state.macPanId;
                    hdr.seqNo = _state.macBSN++;

                    Beacon bc = new Beacon();
                    bc.beaconOrder = _state.macBeaconOrder;
                    bc.superframeOrder = _state.macSuperframeOrder;
                    // finalCapSlot
                    // batteryLifeExtension
                    if (_state.panCoordinator)
                        bc.panCoordinator = 1;
                    bc.associationPermit = 0;
                    // gtsPermit
                    // gtsDirectionsMask
                    // gtsDescriptor;
                    // shortAddrPending;
                    // extAddrPending;
                    bc.payload = _state.macBeaconPayload;

                    int lenHeader = hdr.Length();
                    int len = _state.phyFrameHead + lenHeader; ;
                    frame = Frame.GetFrame(len + bc.Length() + _state.phyFrameTail);
                    frame.ReserveHeader(len);
                    if (bc.WriteToFrame(frame) && hdr.WriteToFrameHeader(frame))
                    {
                        send = true;
                    }
                }
            }

            if (send)
            {
                _sendReceive.SendFrame(ref frame, false, 0);
            }

            Frame.Release(ref frame);
        }
コード例 #15
0
        private void DataRequest(TaskDataRequest task)
        {
            if (task == null)
                return;

            MacEnum result = MacEnum.Success;
            bool is2006 = false;
            // check frame
            if (task.msdu == null || task.msdu.LengthDataUsed == 0)
            {
                result = MacEnum.InvalidParameter;
            }
            else if (task.msdu.LengthDataUsed > State.aMaxMACSafePayloadSize)
            {
                if (_state.phySupports2006)
                {
                    is2006 = true;
                }
                else
                {
                    result = MacEnum.FrameTooLong;
                }
            }

            if (result == MacEnum.Success)
            {
                // data request is a value type, cannot be null
                Header hdr = new Header();

                hdr.fcs.Type = Frames.Type.Data;
                if (is2006)
                    hdr.fcs.Version = Frames.Version.IEEE2006;
                else
                    hdr.fcs.Version = Frames.Version.IEEE2003;
                if (task.options.AcknowledgedTransmission)
                    hdr.fcs.Ack = true;
                // FIXME: security

                lock (_state)
                {
                    hdr.seqNo = _state.macDSN++;

                    // dst address
                    hdr.dstPanId = task.dstPANId;
                    switch (task.dstAddr.Mode)
                    {
                        case MacAddressingMode.NoAddress:
                            hdr.fcs.DstAddrMode = AddressingMode.None;
                            break;
                        case MacAddressingMode.ShortAddress:
                            hdr.fcs.DstAddrMode = AddressingMode.Short;
                            hdr.dstAddrShort = task.dstAddr.ShortAddress;
                            break;
                        case MacAddressingMode.ExtendedAddress:
                            hdr.fcs.DstAddrMode = AddressingMode.Extended;
                            hdr.dstAddrExt = task.dstAddr.ExtendedAddress;
                            break;
                    }

                    // src addr
                    if (_state.macPanId == task.dstPANId)
                    {
                        hdr.fcs.PanIdCompression = true;
                    }
                    else
                    {
                        hdr.srcPanId = _state.macPanId;
                    }

                    switch (task.srcAddrMode)
                    {
                        case MacAddressingMode.NoAddress:
                            hdr.fcs.SrcAddrMode = AddressingMode.None;
                            break;
                        case MacAddressingMode.ShortAddress:
                            hdr.fcs.SrcAddrMode = AddressingMode.Short;
                            hdr.srcAddrShort = _state.macShortAddr;
                            break;
                        case MacAddressingMode.ExtendedAddress:
                            hdr.fcs.SrcAddrMode = AddressingMode.Extended;
                            hdr.srcAddrExt = _state.aExtendedAddress;
                            break;
                    }
                }

                // encode
                result = MacEnum.Congested;
                if (hdr.WriteToFrameHeader(task.msdu))
                {
                    if (task.msdu.LengthDataUsed > State.aMaxPhyPacketSize)
                    {
                        result = MacEnum.FrameTooLong;
                    }
                    else
                    {
                        result = _sendReceive.SendFrame(ref task.msdu, task.options.AcknowledgedTransmission, hdr.seqNo);
                    }
                }
                else
                {
                    Trace.Print("Mac: DataRequest: cannot add Mac header");
                }
            }

            Frame.Release(ref task.msdu);

            if (task.handler != null)
            {
                task.handler.Invoke(this, task.msduHandle, result);
            }
        }
コード例 #16
0
        private void ScanRequest(TaskScanRequest task)
        {
            if (task == null)
                return;
            if (task.handler == null)
                return;

            UInt16 oldPanId;
            lock (_state)
            { // recv thread is holding lock while processing frames. this ensures consistency
                _state.scanning = true;
                oldPanId = _state.macPanId;
                _state.macPanId = State.cBroadcastPanId;
            }

            bool wasRunning = _sendReceive.Running;
            if (!wasRunning)
                _sendReceive.Start();

            // calculate scan duration
            UInt32 durationSymbols = task.scanDuration;
            if (durationSymbols > 14)
                durationSymbols = 14;
            durationSymbols = (UInt32)(State.aBaseSuperframeDuration * ((1 << (int)durationSymbols) + 1));

            // result
            UInt32 unscannedChannels = 0; // bitmap
            byte[] energyDetectList = null;
            PanDescriptor[] panDescriptorList = null;

            // set page
            Phy.Status status;
            Phy.PibValue pibValue = new Phy.PibValue();
            pibValue.Int = task.channelPage;
            _phy.SetRequest(Phy.PibAttribute.phyCurrentPage, pibValue, out status);
            if (status != Phy.Status.Success)
            {
                unscannedChannels = task.scanChannels;
            }
            else
            {
                _state.phyChannelPage = task.channelPage;

                // energyDetectList
                int channelCount = 0;
                if (task.scanType == ScanType.ED)
                {
                    for (int channel = 0; channel < 27; channel++)
                    {
                        if (((1 << channel) & task.scanChannels) != 0)
                        {
                            channelCount++;
                        }
                    }

                    energyDetectList = new byte[channelCount];
                    channelCount = 0;
                }

                // Note: there can be a race between switching the channels here and getting the current channel when
                // receiving beacons in MacReceive. This is solved through thread priorities: recv thread has higher
                // priority and should not be blocked from this thread. There is still a small chance that we switch
                // channel and recv assigns the new (wrong) channel, but this is by design and cannot be changed.

                // iterate through all channels
                for (int channel = 0; channel < 27; channel++)
                {
                    if (((1 << channel) & task.scanChannels) != 0)
                    {
                        // set channel
                        pibValue.Int = channel;
                        _phy.SetRequest(Phy.PibAttribute.phyCurrentChannel, pibValue, out status);
                        if (status != Phy.Status.Success)
                        {
                            unscannedChannels |= (UInt32)(1 << channel);
                            channelCount++;
                        }
                        else
                        {
                            _state.phyChannelNumber = (Byte)channel;
                            // max value of durationSymb is 2^24, correct would be: dur*1000/rate, however this exceeds int range
                            // as symbolrate is multiple of 100, this works:
                            int durationMS = (int)(durationSymbols * 10) / (_state.phySymbolrate / 100); // symbolrate is non-zero

                            // perform the actual channel request
                            switch (task.scanType)
                            {
                                case ScanType.ED:
                                    {
                                        // Continuously read ED values in software for given amount of time.
#if MICROFRAMEWORK
                                        ThreadPriority oldPriority = Thread.CurrentThread.Priority;
                                        Thread.CurrentThread.Priority = ThreadPriority.Highest; // RT thread
#endif
                                        Byte result = 0;
                                        bool resultValid = false;
                                        DateTime dtStart = System.DateTime.Now;
                                        for (; ; )
                                        {
                                            Byte b;
                                            _phy.EDRequest(out status, out b);
                                            if (status == Phy.Status.Success)
                                            {
                                                resultValid = true;
                                                if (b > result)
                                                    result = b;
                                            }

                                            //Thread.Sleep(1);
                                            DateTime dtNow = System.DateTime.Now;
                                            TimeSpan ts = dtNow - dtStart;
                                            int elapsedMS = ts.Milliseconds + 1000 * (ts.Seconds + 60 * ts.Minutes);
                                            if (elapsedMS >= durationMS)
                                                break;
                                        }

#if MICROFRAMEWORK
                                        Thread.CurrentThread.Priority = oldPriority;
#endif
                                        if (resultValid)
                                        {
                                            energyDetectList[channelCount] = result;
                                        }
                                        else
                                        {
                                            unscannedChannels |= (UInt32)(1 << channel);
                                        }

                                        channelCount++;
                                        Thread.Sleep(0); // reschedule
                                        break;
                                    }
                                case ScanType.ActiveScan:
                                case ScanType.PassiveScan:
                                    {
                                        // clear any old beacon
                                        lock (_scannedBeacons)
                                        {
                                            _scannedBeacons.Clear();
                                        }

                                        // send beacon request
                                        if (task.scanType == ScanType.ActiveScan)
                                        {
                                            Header hdr = new Header();
                                            Command.BeaconRequest cmd = new Command.BeaconRequest();
                                            hdr.fcs.Type = Microsoft.SPOT.Wireless.IEEE_802_15_4.Mac.Frames.Type.Cmd;
                                            hdr.fcs.DstAddrMode = AddressingMode.Short;
                                            hdr.dstAddrShort = State.cBroadcastShortAddr;
                                            hdr.dstPanId = State.cBroadcastPanId;
                                            hdr.fcs.SrcAddrMode = AddressingMode.None;
                                            hdr.seqNo = _state.macDSN++;

                                            Frame frame = Encode(hdr, cmd);
                                            if (frame != null)
                                                _sendReceive.SendFrame(ref frame, false, hdr.seqNo);
                                            Frame.Release(ref frame);
                                        }

                                        // wait
                                        Thread.Sleep(durationMS);

                                        // create result list
                                        lock (_scannedBeacons)
                                        {
                                            if (_scannedBeacons.Count > 0)
                                            {
                                                int cntOld = 0;
                                                int cntNew = _scannedBeacons.Count;
                                                if (panDescriptorList == null)
                                                {
                                                    panDescriptorList = new PanDescriptor[cntNew];
                                                }
                                                else
                                                {
                                                    cntOld = panDescriptorList.Length;
                                                    PanDescriptor[] tmp = new PanDescriptor[cntOld + cntNew];
                                                    for (int i = 0; i < cntOld; i++)
                                                        tmp[i] = panDescriptorList[i];
                                                    panDescriptorList = tmp;
                                                }

                                                for (int i = 0; i < cntNew; i++)
                                                    panDescriptorList[i + cntOld] = (PanDescriptor)_scannedBeacons[i];
                                                _scannedBeacons.Clear();
                                            }
                                        }
                                        break;
                                    }
                                case ScanType.OrphanScan:
                                    // FIXME: not implemented
                                    Trace.Print("Mac: ScanRequest: OrphanScan not implemented");
                                    unscannedChannels |= (UInt32)(1 << channel);
                                    break;
                            }
                        }
                    }
                }
            }

            if (!wasRunning)
                _sendReceive.Stop();

            lock (_state)
            {
                _state.scanning = false;
                _state.macPanId = oldPanId;
            }

            task.handler.Invoke(this, MacEnum.Success,
                task.scanType, task.channelPage, unscannedChannels, energyDetectList, panDescriptorList);
        }