Exemplo n.º 1
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);
            }
        }
Exemplo n.º 2
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);
        }