Implemented ATSC 3 L1BasicSignalling and L1DetailSignalling
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 44s
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 44s
This commit is contained in:
parent
f4193297d2
commit
ef903cba96
@ -1,4 +1,5 @@
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using skyscraper5.Ietf.Rfc971;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using skyscraper8.Atsc.A330;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -103,7 +104,8 @@ namespace skyscraper8.Atsc.A322
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Concatenation Header not yet implemented.");
|
||||
stateMachineState = 7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stateMachineState = 4;
|
||||
@ -125,6 +127,45 @@ namespace skyscraper8.Atsc.A322
|
||||
DeliverPacket(currentAlpPacket, neededBuffer);
|
||||
stateMachineState = 1;
|
||||
break;
|
||||
case 7: //Read Concatenation Header first byte.
|
||||
byte[] concatHeaderFirstByteBuffer = new byte[1];
|
||||
int readResult = ms.Read(concatHeaderFirstByteBuffer, 0, 1);
|
||||
if (readResult == 0)
|
||||
break;
|
||||
|
||||
currentAlpPacket.ConcatLengthMsb = (concatHeaderFirstByteBuffer[0] & 0xf0) >> 4;
|
||||
currentAlpPacket.Count = (concatHeaderFirstByteBuffer[0] & 0x0e) >> 1;
|
||||
currentAlpPacket.SIF = (concatHeaderFirstByteBuffer[0] & 0x01) != 0;
|
||||
|
||||
int neededLength = 12 * currentAlpPacket.Count;
|
||||
if ((currentAlpPacket.Count & 1) == 0)
|
||||
neededLength += 4;
|
||||
neededLength /= 8;
|
||||
|
||||
neededBufferOffset = 0;
|
||||
stateMachineState = 8;
|
||||
|
||||
break;
|
||||
case 8: //Get Concatenation Header Lengths
|
||||
int readSuccesful3 = ms.Read(neededBuffer, neededBufferOffset, neededBuffer.Length - neededBufferOffset);
|
||||
neededBufferOffset += readSuccesful3;
|
||||
if (neededBufferOffset == neededBuffer.Length)
|
||||
{
|
||||
stateMachineState = 9;
|
||||
}
|
||||
break;
|
||||
case 9: //Parse Concatenation Header Lengths
|
||||
currentAlpPacket.ParseConcatenationHeaderLengths(neededBuffer);
|
||||
if (currentAlpPacket.PacketType == AlpPacketType.LinkLayerSignalling)
|
||||
{
|
||||
throw new NotImplementedException("Concatenated Link Layer Signalling Packets in ATSC 3.0 not yet supported.");
|
||||
}
|
||||
|
||||
currentAlpPacket.Length2 = (currentAlpPacket.ConcatLengthMsb << 11) | currentAlpPacket.Length;
|
||||
neededBufferOffset = 0;
|
||||
neededBuffer = new byte[currentAlpPacket.Length2];
|
||||
stateMachineState = 5;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("ATSC PLP Baseband Parser State machine state #{0}", stateMachineState));
|
||||
}
|
||||
@ -133,7 +174,7 @@ namespace skyscraper8.Atsc.A322
|
||||
|
||||
private void DeliverPacket(AlpPacket? currentAlpPacket, byte[]? neededBuffer)
|
||||
{
|
||||
Console.WriteLine("PacketType = {0} \t Length = {1}", currentAlpPacket.PacketType, neededBuffer.Length);
|
||||
Console.WriteLine("PacketType = {0} \t Length = {1} (first bytes = {2:X2},{3:X2},{4:X2})", currentAlpPacket.PacketType, neededBuffer.Length, neededBuffer[0], neededBuffer[1], neededBuffer[2]);
|
||||
}
|
||||
|
||||
internal void OnSyncLoss()
|
||||
@ -145,6 +186,7 @@ namespace skyscraper8.Atsc.A322
|
||||
private int stateMachineState;
|
||||
private byte[] neededBuffer;
|
||||
private int neededBufferOffset;
|
||||
|
||||
}
|
||||
|
||||
internal enum OfiDescription
|
||||
|
||||
@ -39,8 +39,8 @@ namespace skyscraper8.Atsc.A322
|
||||
L1DetailAdditionalParityMode = bitstream.ReadBitsAsByte(2);
|
||||
L1DetailTotalCells = bitstream.ReadBitsAsUint(19);
|
||||
FirstSubMimo = bitstream.ReadBitAsBoolean();
|
||||
FirstSubMiso = bitstream.ReadBitsAsByte(2);
|
||||
FirstSubFftSize = bitstream.ReadBitsAsByte(2);
|
||||
FirstSubMiso = (MisoSignallingFormat)bitstream.ReadBitsAsByte(2);
|
||||
FirstSubFftSize = (FftSizeSignallingFormat)bitstream.ReadBitsAsByte(2);
|
||||
FirstSubReducedCarries = bitstream.ReadBitsAsByte(3);
|
||||
FirstSubGuardInterval = bitstream.ReadBitsAsByte(4);
|
||||
FirstSubNumOfdmSymbols = bitstream.ReadBitsAsUint(11);
|
||||
@ -49,6 +49,9 @@ namespace skyscraper8.Atsc.A322
|
||||
FirstSubSbsFirst = bitstream.ReadBitAsBoolean();
|
||||
FirstSubSbsLast = bitstream.ReadBitAsBoolean();
|
||||
FirstSubMimoMixed = bitstream.ReadBitAsBoolean();
|
||||
|
||||
byte[] bytes = bitstream.ReadBitsAsByteArray(47); //reserved
|
||||
uint crc = bitstream.ReadBitsAsUint(32);
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
@ -71,8 +74,8 @@ namespace skyscraper8.Atsc.A322
|
||||
public byte L1DetailAdditionalParityMode { get; }
|
||||
public uint L1DetailTotalCells { get; }
|
||||
public bool FirstSubMimo { get; }
|
||||
public byte FirstSubMiso { get; }
|
||||
public byte FirstSubFftSize { get; }
|
||||
public MisoSignallingFormat FirstSubMiso { get; }
|
||||
public FftSizeSignallingFormat FirstSubFftSize { get; }
|
||||
public byte FirstSubReducedCarries { get; }
|
||||
public byte FirstSubGuardInterval { get; private set; }
|
||||
public uint FirstSubNumOfdmSymbols { get; }
|
||||
@ -98,4 +101,5 @@ namespace skyscraper8.Atsc.A322
|
||||
AceOnly,
|
||||
TrAndAce
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -9,8 +10,307 @@ namespace skyscraper8.Atsc.A322
|
||||
{
|
||||
internal class L1DetailSignalling : Validatable
|
||||
{
|
||||
public L1DetailSignalling(byte[] bytes)
|
||||
public L1DetailSignalling(byte[] bytes, L1BasicSignalling basicSignalling)
|
||||
{
|
||||
InBitStream bitStream = new InBitStream(bytes);
|
||||
this.Version = new Version(bitStream.ReadBitsAsByte(4), 0);
|
||||
|
||||
byte numRf = bitStream.ReadBitsAsByte(3);
|
||||
RfIds = new ushort[numRf];
|
||||
for (int i = 1; i < numRf; i++)
|
||||
{
|
||||
RfIds[i] = bitStream.ReadBitsAsUInt16(16);
|
||||
bitStream.ReadBitsAsByte(3); //reserved
|
||||
}
|
||||
|
||||
if (basicSignalling.TimeInfoFlag != 0)
|
||||
{
|
||||
uint secs = 0;
|
||||
int msecs = 0;
|
||||
int microsecs = 0;
|
||||
int nanosecs = 0;
|
||||
secs = bitStream.ReadBitsAsUint(32);
|
||||
msecs = bitStream.ReadBitsAsUInt16(10);
|
||||
if ((int)basicSignalling.TimeInfoFlag != 1)
|
||||
{
|
||||
microsecs = bitStream.ReadBitsAsUInt16(10);
|
||||
if ((int)basicSignalling.TimeInfoFlag != 2)
|
||||
{
|
||||
nanosecs = bitStream.ReadBitsAsUInt16(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Subframes = new L1Subframe[basicSignalling.NumSubframes];
|
||||
for (int i = 0; i < basicSignalling.NumSubframes; i++)
|
||||
{
|
||||
L1Subframe child = new L1Subframe();
|
||||
Subframes[i] = child;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
child.Mimo = bitStream.ReadBitAsBoolean();
|
||||
child.Miso = (MisoSignallingFormat)bitStream.ReadBitsAsByte(2);
|
||||
child.FftSize = (FftSizeSignallingFormat)bitStream.ReadBitsAsByte(2);
|
||||
child.ReducedCarriers = bitStream.ReadBitsAsByte(3);
|
||||
child.GuardInterval = bitStream.ReadBitsAsByte(3);
|
||||
child.NumOfdmSymbols = bitStream.ReadBitsAsUInt16(11);
|
||||
child.ScatteredPilotPatern = bitStream.ReadBitsAsByte(5);
|
||||
child.ScatteredPilotBoost = bitStream.ReadBitsAsByte(3);
|
||||
child.SbsFirst = bitStream.ReadBitAsBoolean();
|
||||
child.SbsLast = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
|
||||
if (basicSignalling.NumSubframes > 0)
|
||||
{
|
||||
child.SubframeMultiplex = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
child.FrequencyInterleaver = bitStream.ReadBitAsBoolean();
|
||||
|
||||
if (((i == 0) && (basicSignalling.FirstSubSbsFirst || basicSignalling.FirstSubSbsLast)) || ((i > 0) && (child.SbsFirst | child.SbsLast)))
|
||||
{
|
||||
child.SbsNullCells = bitStream.ReadBitsAsUInt16(13);
|
||||
}
|
||||
byte numPlp = bitStream.ReadBitsAsByte(6);
|
||||
child.Plps = new L1SubframePlp[numPlp];
|
||||
|
||||
for (int j = 0; j < numPlp; j++)
|
||||
{
|
||||
L1SubframePlp plp = new L1SubframePlp();
|
||||
child.Plps[j] = plp;
|
||||
|
||||
plp.Id = bitStream.ReadBitsAsByte(6);
|
||||
plp.LlsFlag = bitStream.ReadBitAsBoolean();
|
||||
plp.Layer = bitStream.ReadBitsAsByte(2);
|
||||
plp.Start = bitStream.ReadBitsAsUint(24);
|
||||
plp.Size = bitStream.ReadBitsAsUint(24);
|
||||
plp.ScramblerType = bitStream.ReadBitsAsByte(2);
|
||||
plp.FecType = (PlpFecTypeSignallingFormat)bitStream.ReadBitsAsByte(4);
|
||||
if (plp.NeedModCod())
|
||||
{
|
||||
plp.Mod = (PlpModSignallingFormat)bitStream.ReadBitsAsByte(4);
|
||||
plp.Cod = (PlpCodSignallingFormat)bitStream.ReadBitsAsByte(4);
|
||||
}
|
||||
plp.TiMode = (PlpTiModeSignallingFormat)bitStream.ReadBitsAsByte(2);
|
||||
if (plp.TiMode == PlpTiModeSignallingFormat.NoTimeInterleaving)
|
||||
{
|
||||
plp.FecBlockStart = bitStream.ReadBitsAsUInt16(15);
|
||||
}
|
||||
else if (plp.TiMode == PlpTiModeSignallingFormat.ConvolutionalTimeInterleaving)
|
||||
{
|
||||
plp.CtiFecBlockStart = bitStream.ReadBitsAsUint(22);
|
||||
}
|
||||
if (numRf > 0)
|
||||
{
|
||||
byte numChannelBonded = bitStream.ReadBitsAsByte(3);
|
||||
if (numChannelBonded > 0)
|
||||
{
|
||||
plp.ChannelBondingFormat = (PlpChannelBondingFormatSignallingFormat)bitStream.ReadBitsAsByte(2);
|
||||
plp.BondedRfId = new byte[numChannelBonded];
|
||||
for (byte k = 0; k < numChannelBonded; k++)
|
||||
{
|
||||
plp.BondedRfId[k] = bitStream.ReadBitsAsByte(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((i == 0 && basicSignalling.FirstSubMimo) || (i > 0 && child.Mimo))
|
||||
{
|
||||
plp.MimoStreamCombining = bitStream.ReadBitAsBoolean();
|
||||
plp.MimoIqInterleaving = bitStream.ReadBitAsBoolean();
|
||||
plp.MimoPh = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
|
||||
if (plp.Layer == 0)
|
||||
{
|
||||
plp.Type = bitStream.ReadBitAsBoolean();
|
||||
if (plp.Type)
|
||||
{
|
||||
plp.NumSubslices = bitStream.ReadBitsAsUInt16(14);
|
||||
plp.SubsliceInterval = bitStream.ReadBitsAsUint(24);
|
||||
}
|
||||
if (((plp.TiMode == PlpTiModeSignallingFormat.ConvolutionalTimeInterleaving) || (plp.TiMode == PlpTiModeSignallingFormat.HybridTimeInterleaving) && (plp.Mod == 0)))
|
||||
{
|
||||
plp.TiExtendedInterleaving = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
if (plp.TiMode == PlpTiModeSignallingFormat.ConvolutionalTimeInterleaving)
|
||||
{
|
||||
plp.CtiDepth = bitStream.ReadBitsAsByte(3);
|
||||
plp.CtiStartRow = bitStream.ReadBitsAsUInt16(11);
|
||||
}
|
||||
else if (plp.TiMode == PlpTiModeSignallingFormat.HybridTimeInterleaving)
|
||||
{
|
||||
plp.HtiInterSubframe = bitStream.ReadBitAsBoolean();
|
||||
byte htiNumTiBlocks = bitStream.ReadBitsAsByte(4);
|
||||
plp.HtiNumFecBlocksMax = bitStream.ReadBitsAsUInt16(12);
|
||||
if (!plp.HtiInterSubframe)
|
||||
{
|
||||
plp.HtiNumFecBlocksMax = bitStream.ReadBitsAsUInt16(12);
|
||||
}
|
||||
else
|
||||
{
|
||||
plp.HtiNumFecBlocks = new ushort[htiNumTiBlocks];
|
||||
for (byte k = 0; k < htiNumTiBlocks; k++)
|
||||
{
|
||||
plp.HtiNumFecBlocks[k] = bitStream.ReadBitsAsUInt16(12);
|
||||
}
|
||||
}
|
||||
plp.HtiCellInterleaver = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plp.LdmInjectionLevel = bitStream.ReadBitsAsByte(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
Bsid = bitStream.ReadBitsAsUInt16(16);
|
||||
for (int i = 0; i < basicSignalling.NumSubframes; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
Subframes[i].MimoMixed = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
if ((i == 0 && basicSignalling.FirstSubMimoMixed) || (i > 0 || Subframes[i].MimoMixed))
|
||||
{
|
||||
for (int j = 0; j < Subframes[i].Plps.Length; j++)
|
||||
{
|
||||
Subframes[i].Plps[j].Mimo = bitStream.ReadBitAsBoolean();
|
||||
if (Subframes[i].Plps[j].Mimo)
|
||||
{
|
||||
Subframes[i].Plps[j].MimoStreamCombining = bitStream.ReadBitAsBoolean();
|
||||
Subframes[i].Plps[j].MimoIqInterleaving = bitStream.ReadBitAsBoolean();
|
||||
Subframes[i].Plps[j].MimoPh = bitStream.ReadBitAsBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
public Version Version { get; }
|
||||
public ushort[] RfIds { get; private set; }
|
||||
public L1Subframe[] Subframes { get; private set; }
|
||||
public ushort Bsid { get; }
|
||||
}
|
||||
|
||||
internal class L1SubframePlp
|
||||
{
|
||||
public byte Id { get; internal set; }
|
||||
public bool LlsFlag { get; internal set; }
|
||||
public byte Layer { get; internal set; }
|
||||
public uint Start { get; internal set; }
|
||||
public uint Size { get; internal set; }
|
||||
public byte ScramblerType { get; internal set; }
|
||||
public PlpFecTypeSignallingFormat FecType { get; internal set; }
|
||||
public PlpModSignallingFormat Mod { get; internal set; }
|
||||
public PlpCodSignallingFormat Cod { get; internal set; }
|
||||
public PlpTiModeSignallingFormat TiMode { get; internal set; }
|
||||
public ushort FecBlockStart { get; internal set; }
|
||||
public uint CtiFecBlockStart { get; internal set; }
|
||||
public PlpChannelBondingFormatSignallingFormat ChannelBondingFormat { get; internal set; }
|
||||
public byte[] BondedRfId { get; internal set; }
|
||||
public bool MimoStreamCombining { get; internal set; }
|
||||
public bool MimoIqInterleaving { get; internal set; }
|
||||
public bool MimoPh { get; internal set; }
|
||||
public bool Type { get; internal set; }
|
||||
public ushort NumSubslices { get; internal set; }
|
||||
public uint SubsliceInterval { get; internal set; }
|
||||
public bool TiExtendedInterleaving { get; internal set; }
|
||||
public byte CtiDepth { get; internal set; }
|
||||
public ushort CtiStartRow { get; internal set; }
|
||||
public bool HtiInterSubframe { get; internal set; }
|
||||
public ushort HtiNumFecBlocksMax { get; internal set; }
|
||||
public ushort[] HtiNumFecBlocks { get; internal set; }
|
||||
public bool HtiCellInterleaver { get; internal set; }
|
||||
public byte LdmInjectionLevel { get; internal set; }
|
||||
public bool Mimo { get; internal set; }
|
||||
|
||||
internal bool NeedModCod()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
class L1Subframe
|
||||
{
|
||||
public bool Mimo { get; internal set; }
|
||||
public MisoSignallingFormat Miso { get; internal set; }
|
||||
public FftSizeSignallingFormat FftSize { get; internal set; }
|
||||
public byte ReducedCarriers { get; internal set; }
|
||||
public byte GuardInterval { get; internal set; }
|
||||
public ushort NumOfdmSymbols { get; internal set; }
|
||||
public byte ScatteredPilotPatern { get; internal set; }
|
||||
public byte ScatteredPilotBoost { get; internal set; }
|
||||
public bool SbsFirst { get; internal set; }
|
||||
public bool SbsLast { get; internal set; }
|
||||
public bool SubframeMultiplex { get; internal set; }
|
||||
public bool FrequencyInterleaver { get; internal set; }
|
||||
public ushort SbsNullCells { get; internal set; }
|
||||
public L1SubframePlp[] Plps { get; internal set; }
|
||||
public bool MimoMixed { get; internal set; }
|
||||
}
|
||||
|
||||
enum MisoSignallingFormat
|
||||
{
|
||||
NoMiso,
|
||||
_64Coefficients,
|
||||
_256Coefficients,
|
||||
}
|
||||
|
||||
enum FftSizeSignallingFormat
|
||||
{
|
||||
_8k,
|
||||
_16k,
|
||||
_32k,
|
||||
}
|
||||
|
||||
enum PlpFecTypeSignallingFormat
|
||||
{
|
||||
Bch16kLdpc,
|
||||
Bch64kLdpc,
|
||||
Crc16kLdpc,
|
||||
Crc64kLdpc,
|
||||
_16kLdpc,
|
||||
_64kLdpc,
|
||||
}
|
||||
|
||||
enum PlpModSignallingFormat
|
||||
{
|
||||
Qpsk,
|
||||
_16QAM,
|
||||
_64QAM,
|
||||
_256QAM,
|
||||
_1024QAM,
|
||||
_4096Q
|
||||
}
|
||||
|
||||
enum PlpCodSignallingFormat
|
||||
{
|
||||
_2_15,
|
||||
_3_15,
|
||||
_4_15,
|
||||
_5_15,
|
||||
_6_15,
|
||||
_7_15,
|
||||
_8_15,
|
||||
_9_15,
|
||||
_10_15,
|
||||
_11_15,
|
||||
_12_15,
|
||||
_13_15,
|
||||
}
|
||||
|
||||
enum PlpTiModeSignallingFormat
|
||||
{
|
||||
NoTimeInterleaving,
|
||||
ConvolutionalTimeInterleaving,
|
||||
HybridTimeInterleaving
|
||||
}
|
||||
|
||||
enum PlpChannelBondingFormatSignallingFormat
|
||||
{
|
||||
PlainChannelBonding,
|
||||
SnrAveragedChannelBonding
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ namespace skyscraper8.Atsc.A324
|
||||
}
|
||||
else if (plp == 65)
|
||||
{
|
||||
throw new NotImplementedException("desynced timing and management");
|
||||
DesyncTimingAndManagement();
|
||||
}
|
||||
else if (plp <= 63)
|
||||
{
|
||||
@ -126,7 +126,18 @@ namespace skyscraper8.Atsc.A324
|
||||
throw new NotImplementedException(String.Format("Unknown PLP: {0}", plp));
|
||||
}
|
||||
}
|
||||
plpSequenceNumbers[plp] = rtpPacket.RtpSequenceNumber;
|
||||
plpSequenceNumbers[plp]++;
|
||||
}
|
||||
|
||||
private TimingAndManagementPacket timingAndManagement;
|
||||
|
||||
private void DesyncTimingAndManagement()
|
||||
{
|
||||
if (timingAndManagement != null)
|
||||
{
|
||||
timingAndManagement.Valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void DesyncPreamble()
|
||||
@ -153,7 +164,7 @@ namespace skyscraper8.Atsc.A324
|
||||
|
||||
private void HandleTimingAndManagementData(byte[] rtpPayload)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
timingAndManagement = new TimingAndManagementPacket(rtpPayload);
|
||||
}
|
||||
|
||||
private PreambleData preambleData;
|
||||
|
||||
@ -30,7 +30,7 @@ namespace skyscraper8.Atsc.A324
|
||||
}
|
||||
|
||||
long detailLength = expectedLength - 25;
|
||||
DetailSignalling = new L1DetailSignalling(ms.ReadBytes(detailLength));
|
||||
DetailSignalling = new L1DetailSignalling(ms.ReadBytes(detailLength), BasicSignalling);
|
||||
Valid = DetailSignalling.Valid;
|
||||
}
|
||||
|
||||
|
||||
128
skyscraper8/Atsc/A324/TImingAndManagementPacket.cs
Normal file
128
skyscraper8/Atsc/A324/TImingAndManagementPacket.cs
Normal file
@ -0,0 +1,128 @@
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.Atsc.A324
|
||||
{
|
||||
internal class TimingAndManagementPacket : Validatable
|
||||
{
|
||||
public TimingAndManagementPacket(byte[] rtpPayload)
|
||||
{
|
||||
//STRUCTURE DATA
|
||||
InBitStream bitStream = new InBitStream(rtpPayload);
|
||||
ushort length = bitStream.ReadBitsAsUInt16(16);
|
||||
if (length != rtpPayload.Length)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
byte versionMajor = bitStream.ReadBitsAsByte(4);
|
||||
byte versionMinor = bitStream.ReadBitsAsByte(4);
|
||||
this.Version = new Version(versionMajor, versionMinor);
|
||||
|
||||
MajLogRepCntPre = bitStream.ReadBitsAsByte(4);
|
||||
MajLogRepCntTim = bitStream.ReadBitsAsByte(4);
|
||||
|
||||
byte bootstrapMajor = bitStream.ReadBitsAsByte(4);
|
||||
byte bootstrapMinor = bitStream.ReadBitsAsByte(4);
|
||||
this.Bootstrap = new Version(bootstrapMajor, bootstrapMinor);
|
||||
|
||||
MinTimeToNext = bitStream.ReadBitsAsByte(5);
|
||||
SystemBandwidth = bitStream.ReadBitsAsByte(2);
|
||||
BsrCoefficient = bitStream.ReadBitsAsByte(7);
|
||||
PreambleStructure = bitStream.ReadBitsAsByte(8);
|
||||
EaWakeup = bitStream.ReadBitsAsByte(2);
|
||||
byte numEmissionTim = bitStream.ReadBitsAsByte(6);
|
||||
byte numXmtrsInGroupMinus1 = bitStream.ReadBitsAsByte(6);
|
||||
XmtrGroupNum = bitStream.ReadBitsAsByte(7);
|
||||
MajLogOverride = bitStream.ReadBitsAsByte(3);
|
||||
NumMisoFiltCodes = bitStream.ReadBitsAsByte(2);
|
||||
TxCarrierOffset = bitStream.ReadBitsAsByte(2);
|
||||
MimoFlag = bitStream.ReadBitAsBoolean();
|
||||
bitStream.ReadBitsAsByte(6); //reserved
|
||||
|
||||
//BOOTSTRAP TIMING DATA
|
||||
EmissionTim = new TimeSpan[numEmissionTim];
|
||||
for (int i = 0; i < numEmissionTim; i++)
|
||||
{
|
||||
uint seconds = bitStream.ReadBitsAsUint(32);
|
||||
uint nanoseconds = bitStream.ReadBitsAsUint(32);
|
||||
long microsecs = nanoseconds / 1000;
|
||||
EmissionTim[i] = new TimeSpan(0, 0, 0, (int)seconds, 0, (int)microsecs);
|
||||
}
|
||||
|
||||
//PER TRANSMITTER DATA
|
||||
for (int i = 0; i <= numXmtrsInGroupMinus1; i++)
|
||||
{
|
||||
int intMimoFlag = MimoFlag ? 1 : 0;
|
||||
for (int j = 0; j <= intMimoFlag; j++)
|
||||
{
|
||||
if (PerTransmitterData == null)
|
||||
PerTransmitterData = new PerTransmitPolarizationData[numXmtrsInGroupMinus1 + 1][];
|
||||
if (PerTransmitterData[i] == null)
|
||||
PerTransmitterData[i] = new PerTransmitPolarizationData[intMimoFlag + 1];
|
||||
|
||||
PerTransmitPolarizationData child = new PerTransmitPolarizationData();
|
||||
PerTransmitterData[i][j] = child;
|
||||
|
||||
child.XmtrId = bitStream.ReadBitsAsUInt16(13);
|
||||
if (j == 0)
|
||||
{
|
||||
child.TxTimeOffset = bitStream.ReadBitsAsUInt16(16);
|
||||
}
|
||||
child.TxIdInjectionLevel = bitStream.ReadBitsAsUint(4);
|
||||
child.MisoFiltCodeIndex = bitStream.ReadBitsAsByte(2);
|
||||
}
|
||||
if (!MimoFlag)
|
||||
{
|
||||
bitStream.ReadBitsAsUint(29);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitStream.ReadBitsAsUint(10);
|
||||
}
|
||||
}
|
||||
|
||||
//PACKET RELEASE TIME
|
||||
byte pktRlsSeconds = bitStream.ReadBitsAsByte(4);
|
||||
ushort pktRlsAMilliseconds = bitStream.ReadBitsAsUInt16(10);
|
||||
PktRls = new TimeSpan(0, 0, 0, pktRlsSeconds, pktRlsAMilliseconds);
|
||||
bitStream.SkipBits(2);
|
||||
|
||||
//ERROR CHECK DATA
|
||||
ushort crc16 = bitStream.ReadBitsAsUInt16(16);
|
||||
}
|
||||
|
||||
public Version Version { get; }
|
||||
public byte MajLogRepCntPre { get; }
|
||||
public byte MajLogRepCntTim { get; }
|
||||
public Version Bootstrap { get; }
|
||||
public byte MinTimeToNext { get; }
|
||||
public byte SystemBandwidth { get; }
|
||||
public byte BsrCoefficient { get; }
|
||||
public byte PreambleStructure { get; }
|
||||
public byte EaWakeup { get; }
|
||||
public byte XmtrGroupNum { get; }
|
||||
public byte MajLogOverride { get; }
|
||||
public byte NumMisoFiltCodes { get; }
|
||||
public byte TxCarrierOffset { get; }
|
||||
public bool MimoFlag { get; }
|
||||
public TimeSpan[] EmissionTim { get; }
|
||||
|
||||
public PerTransmitPolarizationData[][] PerTransmitterData { get; }
|
||||
public TimeSpan PktRls { get; }
|
||||
}
|
||||
|
||||
public class PerTransmitPolarizationData
|
||||
{
|
||||
public ushort XmtrId { get; internal set; }
|
||||
public ushort TxTimeOffset { get; internal set; }
|
||||
public uint TxIdInjectionLevel { get; internal set; }
|
||||
public byte MisoFiltCodeIndex { get; internal set; }
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,15 @@ namespace skyscraper8.Atsc.A330
|
||||
public bool? HeaderMode { get; }
|
||||
public bool? SegmentationConcatenation { get; }
|
||||
public int Length { get; }
|
||||
public int ConcatLengthMsb { get; internal set; }
|
||||
public int Count { get; internal set; }
|
||||
public bool SIF { get; internal set; }
|
||||
public int Length2 { get; internal set; }
|
||||
|
||||
internal void ParseConcatenationHeaderLengths(byte[]? neededBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
enum AlpPacketType
|
||||
|
||||
@ -110,12 +110,12 @@ namespace skyscraper5.Skyscraper.IO
|
||||
|
||||
public byte[] ReadBitsAsByteArray(uint v)
|
||||
{
|
||||
byte[] result = new byte[v / 8];
|
||||
byte[] result = new byte[(v / 8) + 1];
|
||||
int offset = 0;
|
||||
while (v > 0)
|
||||
{
|
||||
uint nextSize = Math.Min(8, v);
|
||||
result[offset++] = ReadBitsAsByte(8);
|
||||
byte nextSize = Math.Min((byte)8, (byte)v);
|
||||
result[offset++] = ReadBitsAsByte(nextSize);
|
||||
v -= nextSize;
|
||||
}
|
||||
return result;
|
||||
@ -125,7 +125,7 @@ namespace skyscraper5.Skyscraper.IO
|
||||
|
||||
public long GetBitsAvailable()
|
||||
{
|
||||
long result = _wrapped.GetAvailableBytes();
|
||||
long result = _wrapped.GetAvailableBytes() * 8;
|
||||
result += (8 - bitPointer);
|
||||
return result;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user