/// <summary> /// Factory method parsing <see cref="BaseBandHeader"/>. /// </summary> /// <param name="reader"><see cref="PDUStreamReader"/> for stream from which the <see cref="BaseBandHeader"/> /// should be parsed.</param> /// <exception cref="InvalidPacketFormatException">If DFL (Data Field Length) field is not in range [0,58112].</exception> /// <returns>Parsed <see cref="BaseBandHeader"/> object.</returns> public static BaseBandHeader Parse(PDUStreamReader reader) { // Byte 0, MATYPE-1 var matype1 = Matype1.Parse(reader.ReadByte()); // Byte 1, MATYPE-2 var matype2 = reader.ReadByte(); // Byte 2-3, UPL var userPacketLenght = reader.ReadUInt16(); // Byte 4-5, DFL var dataFieldLength = reader.ReadUInt16(); // http://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf#page=18 if (dataFieldLength > 58112) { throw new InvalidPacketFormatException( $"DFL (Data Field Length) field has be in range [0,58112]. {dataFieldLength} > 58112"); } // Byte 6, SYNC var sync = reader.ReadByte(); // Byte 7-8, SYNCD var syncD = reader.ReadUInt16(); // Byte 9, CRC-8 var crc8 = reader.ReadByte(); // NOTE: DVB-S2 base band frame, base band header, CRC-8 is not validated. return(new BaseBandHeader(matype1, matype2, userPacketLenght, dataFieldLength, sync, syncD, crc8)); }
/// <summary> /// Factory method parsing <see cref="ModeAdaptationHeaderL3"/>. /// </summary> /// /// <param name="reader"><see cref="PDUStreamReader"/> for stream from which the <see cref="ModeAdaptationHeaderL3"/> /// should be parsed.</param> /// <exception cref="InvalidPacketFormatException">If read data does not correspond to valid format.</exception> /// <returns>Parsed <see cref="ModeAdaptationHeaderL3"/> object.</returns> public static ModeAdaptationHeaderL3 Parse(PDUStreamReader reader) { // Byte 0, SYNC var b = reader.ReadByte(); if (b != Sync) { throw new InvalidPacketFormatException($"SYNC byte mismatch at byte 0. {b}!={Sync}"); } // Byte 1, ACM command, received MODCOD and frame type // Individual bits of ACM command byte are indexed from MSB to LSB according to the standard // (Table 5-3 in SatLabs ref.: sl_561 v1.3 // http://satlabs.org/pdf/sl_561_Mode_Adaptation_Input_and_Output_Interfaces_for_DVB-S2_Equipment_v1.3.pdf). // Bit 0 is therefore MSB and bit 7 is LSB. Indexing of this field is inverted in comparison // with other fields. The other fields have even explicit statement of "Bit 0: LSB". b = reader.ReadByte(); // Bit 0 (7): Not used, set to 0 if ((b & 0b1000_0000) != 0) { throw new InvalidPacketFormatException($"Unexpected bit 1 at byte 1, bit 7."); } // Bit 1 (6): TYPE(0) - pilots configuration (0 = no pilots, 1 = pilots) var pilotsConfiguration = (b & 0b0100_0000) == 1; // Bit 2 (5): TYPE(1) - FECFRAME sizes (0 = normal; 1 = short) var fecFrameSize = (b & 0b0010_0000) == 0? FecFrameSize.Normal : FecFrameSize.Short; // Bit 3-7: MODCOD // ModCod enum has 32 values, therefore we use Enum.Parse instead of Enum.TryParse. var modcod = (Modcod)Enum.Parse(typeof(Modcod), (b & 0b0001_1111).ToString()); // Byte 2, CNI // 0: modem unlocked, SNR not available // 1: -1.0 dB // 2: -0.875 dB // 254: 30.625 dB b = reader.ReadByte(); var carrierToNoise = b == 0? null : (double?)(-1.125 + b * 0.125); // Byte 3, Frame number (PL FRAME ID) var frameNumber = reader.ReadByte(); return(new ModeAdaptationHeaderL3(pilotsConfiguration, fecFrameSize, modcod, carrierToNoise, frameNumber)); }
/// <summary> /// Factory method parsing <see cref="GseHeader"/>. /// </summary> /// <param name="reader"><see cref="PDUStreamReader"/> for stream from which the <see cref="GseHeader"/> /// should be parsed.</param> /// <exception cref="InvalidPacketFormatException">If read data does not correspond to valid format.</exception> /// <returns>Parsed <see cref="GseHeader"/> object.</returns> /// <remarks> /// For complete syntax of GSE Packet structure, see Table 2 in /// <a href="http://www.etsi.org/deliver/etsi_ts/102600_102699/10260601/01.02.01_60/ts_10260601v010201p.pdf#page=13"> /// ETSI TS 102 606-1 V1.2.1.</a> /// </remarks> public static GseHeader Parse(PDUStreamReader reader) { var b = reader.ReadByte(); // Byte 0-1, Fixed Header Fields // Bit 15: S var startIndicator = (b & 0b1000_0000) == 0b1000_0000; // Bit 14: E var endIndicator = (b & 0b0100_0000) == 0b0100_0000; // Bit 13-12: LT // LabelType enum has 4 values, therefore we use Enum.Parse instead of Enum.TryParse. var labelTypeIndicator = (LabelType)Enum.Parse(typeof(LabelType), ((b & 0b0011_0000) >> 4).ToString()); // possibly null values which might not be present in packet ushort?gseLength = null; ushort?bytesAfterGseLengthField = null; byte? fragmentID = null; ushort?totalLength = null; ushort?protocolType = null; byte[] label = null; long?gseLengthFieldStreamPosition = null; // Bit 11-0 if (!startIndicator && !endIndicator && labelTypeIndicator == LabelType.Byte6) { // 4 padding bits if ((b & 0b0000_1111) != 0b0000_0000) { throw new InvalidPacketFormatException($"Expected 4 zero-padding bits."); } // N1 Padding bytes (N1 is the number of bytes until the end of the Base-Band frame.) while (!reader.EndOfPDU) { if (reader.ReadByte() != 0) { throw new InvalidPacketFormatException( $"Expected zero-padding bits until the end of the Base-Band frame."); } } } else { // 12 bits byte[] tmpMaskedBytes = { reader.ReadByte(), (byte)(b & 0b0000_1111) }; // BigEndian gseLength = BitConverter.ToUInt16(tmpMaskedBytes, 0); gseLengthFieldStreamPosition = reader.PDUStreamBasedProvider.Position; if (!startIndicator || !endIndicator) { fragmentID = reader.ReadByte(); } if (startIndicator && !endIndicator) { totalLength = reader.ReadUInt16(); } if (startIndicator) { protocolType = reader.ReadUInt16(); if (labelTypeIndicator == LabelType.Byte6) { label = new byte[6]; if (reader.Read(label, 0, 6) != 6) { throw new InvalidPacketFormatException("Reader could not read 6 bytes."); } } else if (labelTypeIndicator == LabelType.Byte3) { label = new byte[3]; if (reader.Read(label, 0, 3) != 3) { throw new InvalidPacketFormatException("Reader could not read 3 bytes."); } } } }