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); } } } }
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); }
// handler for scan result private void HandlerScanResult( IMacMgmtSap sender, MacEnum status, ScanType scanType, Byte channelPage, UInt32 unscannedChannel, byte[] energyDetectList, PanDescriptor[] panDescriptorList) { // store networks if (panDescriptorList != null) { lock (_scanResults) { int length = panDescriptorList.Length; for (int i = 0; i < length; i++) { ScanResultInternal res = new ScanResultInternal(); res.panDescriptor = panDescriptorList[i]; res.isMeshProtocol = false; _scanResults.Add(res); } } } ScanNextPage(); }
/// <summary> /// handler for mac beacon notifications /// </summary> /// <param name="sender"></param> /// <param name="BSN"></param> /// <param name="panDescriptor"></param> /// <param name="pendingShortAddrs"></param> /// <param name="pendingExtendedAddrs"></param> /// <param name="beaconPayload"></param> public void MacBeaconNotifyIndication( IMacMgmtSap sender, ushort BSN, PanDescriptor panDescriptor, ushort[] pendingShortAddrs, UInt64[] pendingExtendedAddrs, Frame beaconPayload) { if (!_scanning) return; ScanResultInternal res = new ScanResultInternal(); res.panDescriptor = panDescriptor; res.isMeshProtocol = false; if (beaconPayload.LengthDataUsed == 8) { UInt64 meshId = beaconPayload.ReadUInt64Canonical(0); if (meshId == NetworkLayer.cMeshId) { res.isMeshProtocol = true; } Frame.Release(ref beaconPayload); } lock (_scanResults) { _scanResults.Add(res); } }
private void MacBeaconNotifyIndication( IMacMgmtSap sender, ushort BSN, PanDescriptor panDescriptor, ushort[] pendingShortAddrs, UInt64[] pendingExtendedAddrs, Frame beaconPayload) { _mgmt.MacBeaconNotifyIndication(sender, BSN, panDescriptor, pendingShortAddrs, pendingExtendedAddrs, beaconPayload); }