public static Frame CreateACK(byte sequenceNumber, bool pending) { var result = new Frame(); result.Length = 5; result.Type = FrameType.ACK; result.FramePending = pending; result.DataSequenceNumber = sequenceNumber; result.Encode(); return result; }
private bool ShouldWeAcceptThisFrame(Frame frame) { // (1) check if length is ok // (2) check reserved FCF bits // for now we assume it is fine - let's be optimistic // (3) check FCF version if(frame.FrameVersion > maxFrameVersion.Value) { this.Log(LogLevel.Noisy, "Wrong frame version."); return false; } // (4) check source/destination addressing mode if(frame.SourceAddressingMode == AddressingMode.Reserved || frame.DestinationAddressingMode == AddressingMode.Reserved) { this.Log(LogLevel.Noisy, "Wrong addressing mode."); return false; } // (5) check destination address if(frame.DestinationAddressingMode != AddressingMode.None) { // (5.1) check destination PAN if(frame.AddressInformation.DestinationPan != BroadcastPanIdentifier && frame.AddressInformation.DestinationPan != GetPanId()) { this.Log(LogLevel.Noisy, "Wrong destination PAN."); return false; } // (5.2) check destination short address if(frame.DestinationAddressingMode == AddressingMode.ShortAddress) { if(!frame.AddressInformation.DestinationAddress.IsShortBroadcast && !frame.AddressInformation.DestinationAddress.Equals(shortAddress)) { this.Log(LogLevel.Noisy, "Wrong destination short address."); return false; } } // (5.3) check destination extended address else if(frame.DestinationAddressingMode == AddressingMode.ExtendedAddress) { if(!frame.AddressInformation.DestinationAddress.Equals(extendedAddress)) { this.Log(LogLevel.Noisy, "Wrong destination extended address (i'm {0}, but the message is directed to {1}.", extendedAddress.GetValue(), frame.AddressInformation.DestinationAddress.GetValue()); return false; } } } // (6) check frame type switch(frame.Type) { case FrameType.Beacon: if(!acceptBeaconFrames.Value || frame.Length < 9 || frame.DestinationAddressingMode != AddressingMode.None || (frame.SourceAddressingMode != AddressingMode.ShortAddress && frame.SourceAddressingMode != AddressingMode.ExtendedAddress) || (frame.AddressInformation.SourcePan != BroadcastPanIdentifier && frame.AddressInformation.SourcePan != GetPanId())) { this.Log(LogLevel.Noisy, "Wrong beacon frame."); return false; } break; case FrameType.Data: if(!acceptDataFrames.Value || frame.Length < 9 || (frame.DestinationAddressingMode == AddressingMode.None && (!isPanCoordinator.Value || frame.AddressInformation.SourcePan != GetPanId()))) { this.Log(LogLevel.Noisy, "Wrong data frame."); return false; } break; case FrameType.ACK: if(!acceptAckFrames.Value || frame.Length != 5) { this.Log(LogLevel.Noisy, "Wrong ACK frame."); return false; } break; case FrameType.MACControl: if(!acceptMacCmdFrames.Value || frame.Length < 9 || (frame.DestinationAddressingMode == AddressingMode.None && (!isPanCoordinator.Value || frame.AddressInformation.SourcePan != GetPanId()))) { this.Log(LogLevel.Noisy, "Wrong MAC control frame."); return false; } break; default: return false; } return true; }
private void SendData() { if(txQueue.Count == 0) { this.Log(LogLevel.Warning, "Attempted to transmit an empty frame."); return; } irqHandler.RequestInterrupt(InterruptSource.StartOfFrameDelimiter); var crc = Frame.CalculateCRC(txQueue.Skip(1)); var frame = new Frame(txQueue.Concat(crc).ToArray()); this.DebugLog("Sending frame {0}.", frame.Bytes.Select(x => "0x{0:X}".FormatWith(x)).Stringify()); var frameSent = FrameSent; if(frameSent != null) { frameSent(this, frame.Bytes); } irqHandler.RequestInterrupt(InterruptSource.TxDone); }
public void ReceiveFrame(byte[] bytes) { irqHandler.RequestInterrupt(InterruptSource.StartOfFrameDelimiter); Frame ackFrame = null; var frame = new Frame(bytes); var crcOK = frame.CheckCRC(); if(autoCrc.Value && !crcOK) { this.Log(LogLevel.Warning, "Received frame with wrong CRC"); } if(frameFilterEnabled.Value) { if(!ShouldWeAcceptThisFrame(frame)) { this.DebugLog("Not accepting a frame"); return; } irqHandler.RequestInterrupt(InterruptSource.FrameAccepted); } lock(rxLock) { var autoPendingBit = false; var index = NoSourceIndex; if(sourceAddressMatchingEnabled.Value && crcOK) { switch(frame.SourceAddressingMode) { case AddressingMode.ShortAddress: for(var i = 0u; i < srcShortEnabled.Length; i++) { if(!srcShortEnabled[i]) { continue; } if(frame.AddressInformation.SourcePan == GetShortPanIdFromRamTable(i) && frame.AddressInformation.SourceAddress.GetValue() == GetShortSourceAddressFromRamTable(i)) { matchedSourceAddresses[i] = true; autoPendingBit |= srcShortPendEnabled[i]; if(index == NoSourceIndex) { index = i; } } } break; case AddressingMode.ExtendedAddress: for(var i = 0u; i < srcExtendedEnabled.Length; i++) { if(!srcExtendedEnabled[i]) { continue; } if(frame.AddressInformation.SourceAddress.GetValue() == GetExtendedSourceAddressFromRamTable(i)) { matchedSourceAddresses[2 * i] = true; matchedSourceAddresses[2 * i + 1] = true; autoPendingBit |= srcExtendedPendEnabled[i]; if(index == NoSourceIndex) { index = i | 0x20; } } } break; } matchedSourceIndexField.Value = index; autoPendingBit &= autoPendEnabled.Value && frameFilterEnabled.Value && (!pendDataRequestOnly.Value || (frame.Type == FrameType.MACControl && frame.Payload.Count > 0 && frame.Payload[0] == 0x4)); BitHelper.SetBit(ref index, 6, autoPendingBit); if(index != NoSourceIndex) { irqHandler.RequestInterrupt(InterruptSource.SrcMatchFound); } irqHandler.RequestInterrupt(InterruptSource.SrcMatchDone); } if(autoCrc.Value) { var rssi = 70; // why 70? var secondByte = crcOK ? (1u << 7) : 0; if(appendDataMode.Value) { secondByte |= index & 0x7F; } else { secondByte |= 100; // correlation value 100 means near maximum quality } frame.Bytes[frame.Bytes.Length - 2] = (byte)rssi; frame.Bytes[frame.Bytes.Length - 1] = (byte)secondByte; } rxQueue.Enqueue(frame); irqHandler.RequestInterrupt(InterruptSource.FifoP); if(crcOK && autoAck.Value && frame.AcknowledgeRequest && frame.Type != FrameType.Beacon && frame.Type != FrameType.ACK) { ackFrame = Frame.CreateACK(frame.DataSequenceNumber, pendingOr.Value | autoPendingBit); } } var frameSent = FrameSent; if(frameSent != null && ackFrame != null) { frameSent(this, ackFrame.Bytes); irqHandler.RequestInterrupt(InterruptSource.TxAckDone); } irqHandler.RequestInterrupt(InterruptSource.RxPktDone); }