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