Implemented ATSC A/330 Link Layer Signalling detection.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 45s
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 45s
This commit is contained in:
parent
1843d914ed
commit
51353a8014
@ -1,6 +1,7 @@
|
||||
using skyscraper5.Ietf.Rfc971;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using skyscraper8.Atsc.A330;
|
||||
using skyscraper8.GSE.GSE_HEM;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -13,6 +14,12 @@ namespace skyscraper8.Atsc.A322
|
||||
{
|
||||
internal class AtscPlpBasebandParser
|
||||
{
|
||||
private RayBuffer rayBuffer;
|
||||
private const int MINIMUM_REQUIRED_RAY_LENGTH = 65535 * 2;
|
||||
private const int MINIMUM_REQUIRED_RAY_PACKETS = 2;
|
||||
private uint delivered_bbframes_total;
|
||||
private uint delivered_alp_total;
|
||||
|
||||
internal void PushBbframe(Span<byte> payload)
|
||||
{
|
||||
byte a = payload[0];
|
||||
@ -66,6 +73,11 @@ namespace skyscraper8.Atsc.A322
|
||||
}
|
||||
|
||||
Span<byte> bbHeaderStripped = payload.Slice(addToPointer);
|
||||
if (rayBuffer == null)
|
||||
rayBuffer = new RayBuffer();
|
||||
rayBuffer.Enqueue(new MemoryStream(bbHeaderStripped.ToArray(), false), pointer);
|
||||
delivered_bbframes_total++;
|
||||
|
||||
if (pointer + 4 > bbHeaderStripped.Length)
|
||||
{
|
||||
Console.WriteLine("BBFRame, offset: {0}, less than four bytes left.", pointer);
|
||||
@ -74,117 +86,51 @@ namespace skyscraper8.Atsc.A322
|
||||
{
|
||||
Console.WriteLine("BBFRame, offset: {0}, first bytes: 0x{1:X2}{2:X2}{3:X2}{4:X2}", pointer, bbHeaderStripped[pointer], bbHeaderStripped[pointer + 1], bbHeaderStripped[pointer + 2], bbHeaderStripped[pointer + 3]);
|
||||
}
|
||||
/*while (ms.GetAvailableBytes() > 0)
|
||||
|
||||
while (rayBuffer.AvailableBytes >= MINIMUM_REQUIRED_RAY_LENGTH && rayBuffer.QueuedItems >= MINIMUM_REQUIRED_RAY_PACKETS)
|
||||
{
|
||||
switch(stateMachineState)
|
||||
AlpPacket newPacket = new AlpPacket();
|
||||
ushort syncWord = rayBuffer.ReadUInt16BE();
|
||||
newPacket.PacketType = (AlpPacketType)((syncWord & 0xe000) >> 13);
|
||||
newPacket.PayloadConfiguration = (syncWord & 0x1000) != 0;
|
||||
if (!newPacket.PayloadConfiguration)
|
||||
{
|
||||
case 0: //Initial state, nothing parsed yet.
|
||||
if (pointer == 8191)
|
||||
{
|
||||
return; //no new packet to be found in this BBFRAME.
|
||||
}
|
||||
ms.Position = pointer + addToPointer;
|
||||
neededBuffer = null;
|
||||
neededBufferOffset = 0;
|
||||
currentAlpPacket = null;
|
||||
stateMachineState = 1;
|
||||
break;
|
||||
case 1: //Prepare get Base Header for ALP packet encapsulation
|
||||
neededBuffer = new byte[2];
|
||||
stateMachineState = 2;
|
||||
neededBufferOffset = 0;
|
||||
break;
|
||||
case 2: //Get Base Header for ALP packet encapsulation
|
||||
int readSucessful = ms.Read(neededBuffer, neededBufferOffset, neededBuffer.Length - neededBufferOffset);
|
||||
neededBufferOffset += readSucessful;
|
||||
if (neededBufferOffset == neededBuffer.Length)
|
||||
{
|
||||
stateMachineState = 3;
|
||||
}
|
||||
break;
|
||||
case 3: //Parse current ALP packet
|
||||
currentAlpPacket = new AlpPacket(neededBuffer);
|
||||
if (!currentAlpPacket.PayloadConfiguration)
|
||||
{
|
||||
if (currentAlpPacket.HeaderMode.Value)
|
||||
{
|
||||
throw new NotImplementedException("Single Packet Header not yet implemented.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!currentAlpPacket.SegmentationConcatenation.Value)
|
||||
{
|
||||
throw new NotImplementedException("Segmentation Header not yet implemented.");
|
||||
}
|
||||
else
|
||||
{
|
||||
stateMachineState = 7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stateMachineState = 4;
|
||||
break;
|
||||
case 4: //Prepate get packet payload
|
||||
neededBufferOffset = 0;
|
||||
neededBuffer = new byte[currentAlpPacket.Length];
|
||||
stateMachineState = 5;
|
||||
break;
|
||||
case 5: //Get packet payload
|
||||
int readSuccesful2 = ms.Read(neededBuffer, neededBufferOffset, neededBuffer.Length - neededBufferOffset);
|
||||
neededBufferOffset += readSuccesful2;
|
||||
if (neededBufferOffset == neededBuffer.Length)
|
||||
{
|
||||
stateMachineState = 6;
|
||||
}
|
||||
break;
|
||||
case 6: //Deliver packet
|
||||
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));
|
||||
newPacket.HeaderMode = (syncWord & 0x0800) != 0;
|
||||
newPacket.Length = (syncWord & 0x07ff);
|
||||
if (newPacket.HeaderMode)
|
||||
{
|
||||
throw new NotImplementedException("single packet header");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(("yes payload configuration"));
|
||||
}
|
||||
|
||||
if (newPacket.PacketType == AlpPacketType.Ipv4 && newPacket.Length < 20)
|
||||
{
|
||||
rayBuffer.Resync();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newPacket.PacketType == AlpPacketType.LinkLayerSignalling)
|
||||
{
|
||||
newPacket.AdditionalHeaderForSignalingInformation = new AdditionalHeaderForSignalingInformation(rayBuffer.ReadBytes(5));
|
||||
}
|
||||
|
||||
newPacket.Payload = rayBuffer.ReadBytes(newPacket.Length);
|
||||
DeliverPacket(newPacket);
|
||||
}
|
||||
}
|
||||
|
||||
private List<AlpPacket> packets;
|
||||
private void DeliverPacket(AlpPacket newPacket)
|
||||
{
|
||||
Console.WriteLine(newPacket.ToString());
|
||||
delivered_alp_total++;
|
||||
if (packets == null)
|
||||
packets = new List<AlpPacket>();
|
||||
packets.Add(newPacket);
|
||||
}
|
||||
|
||||
private void HandleExtension(bool isLongExtension, int extType, Span<byte> extensionField)
|
||||
@ -196,11 +142,7 @@ namespace skyscraper8.Atsc.A322
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void DeliverPacket(AlpPacket? currentAlpPacket, byte[]? neededBuffer)
|
||||
{
|
||||
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()
|
||||
{
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
|
||||
namespace skyscraper8.Atsc.A330
|
||||
{
|
||||
internal class AdditionalHeaderForSignalingInformation : Validatable
|
||||
{
|
||||
public AdditionalHeaderForSignalingInformation(byte[] readBytes)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(readBytes, false);
|
||||
SignalingType = ms.ReadUInt8();
|
||||
SignalingTypeExtension = ms.ReadUInt16BE();
|
||||
SignalingVersion = ms.ReadUInt8();
|
||||
|
||||
byte a = ms.ReadUInt8();
|
||||
SignalingFormat = (CodeValuesForSignalingFormat)((a & 0xb0) >> 6);
|
||||
SignalingEncoding = (CodeValuesForSignalingEncoding)((a & 0x30) >> 4);
|
||||
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
public CodeValuesForSignalingEncoding SignalingEncoding { get; set; }
|
||||
|
||||
public CodeValuesForSignalingFormat SignalingFormat { get; set; }
|
||||
|
||||
public byte SignalingVersion { get; set; }
|
||||
|
||||
public ushort SignalingTypeExtension { get; set; }
|
||||
|
||||
public byte SignalingType { get; set; }
|
||||
}
|
||||
|
||||
public enum CodeValuesForSignalingFormat : int
|
||||
{
|
||||
Binary = 0,
|
||||
Xml = 1,
|
||||
Json = 2,
|
||||
}
|
||||
|
||||
public enum CodeValuesForSignalingEncoding : int
|
||||
{
|
||||
Uncompressed = 0,
|
||||
Deflate = 1
|
||||
}
|
||||
}
|
||||
@ -9,37 +9,23 @@ namespace skyscraper8.Atsc.A330
|
||||
{
|
||||
internal class AlpPacket
|
||||
{
|
||||
public AlpPacket(byte[] buffer)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(buffer, false);
|
||||
ushort first16bits = ms.ReadUInt16BE();
|
||||
PacketType = (AlpPacketType)((first16bits & 0xe000) >> 13);
|
||||
PayloadConfiguration = (first16bits & 0x1000) != 0;
|
||||
if (!PayloadConfiguration)
|
||||
{
|
||||
HeaderMode = (first16bits & 0x0800) != 0;
|
||||
Length = (first16bits & 0x07ff);
|
||||
}
|
||||
else
|
||||
{
|
||||
SegmentationConcatenation = (first16bits & 0x0800) != 0;
|
||||
Length = (first16bits & 0x07ff);
|
||||
}
|
||||
}
|
||||
|
||||
public AlpPacketType PacketType { get; private set; }
|
||||
public bool PayloadConfiguration { get; private set; }
|
||||
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; }
|
||||
public AlpPacketType PacketType { get; internal set; }
|
||||
public bool PayloadConfiguration { get; set; }
|
||||
public bool HeaderMode { get; set; }
|
||||
public int Length { get; set; }
|
||||
public byte[] Payload { get; set; }
|
||||
public AdditionalHeaderForSignalingInformation AdditionalHeaderForSignalingInformation { get; set; }
|
||||
|
||||
internal void ParseConcatenationHeaderLengths(byte[]? neededBuffer)
|
||||
public override string ToString()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < Math.Min(4, Length); i++)
|
||||
{
|
||||
sb.AppendFormat("{0:X2}", Payload[i]);
|
||||
}
|
||||
|
||||
return String.Format("ALP Packet Type = {0}, PayloadConf = {1}, HeaderMode = {2}, Length = {3}, First bytes = 0x{4}", PacketType, PayloadConfiguration, HeaderMode, Length, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user