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); } }
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); }