skyscraper8/skyscraper8/Docsis/MacManagement/T29_V3_UpstreamChannelDescriptor.cs

390 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
namespace skyscraper5.Docsis.MacManagement
{
[SkyscraperPlugin]
[MacManagementMessageType(3, 29)]
[MacManagementMessageType(5, 51)]
public class UpstreamChannelDescriptor : MacManagementMessage
{
public UpstreamChannelDescriptor(PhysicalAddress source, PhysicalAddress destination, byte[] buffer) : base(source, destination, buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
UpstreamChannelID = ms.ReadUInt8();
ConfigurationChangeCount = ms.ReadUInt8();
MinislotSize = ms.ReadUInt8();
DownstreamChannelId = ms.ReadUInt8();
while (ms.GetAvailableBytes() >= 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
if (ms.GetAvailableBytes() < length)
{
Valid = false;
return;
}
byte[] v = ms.ReadBytes(length);
switch (type)
{
//Found in CM-SP-MULPIv3.1-I03-1406101.pdf on page 107
case 1:
ModulationRate = v[0];
break;
case 2:
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
Frequency = BitConverter.ToUInt32(v);
break;
case 3:
PreamblePattern = v;
break;
case 5:
if (BurstDescriptors == null)
BurstDescriptors = new List<BurstDescriptor>();
BurstDescriptors.Add(new BurstDescriptor(v));
break;
case 6:
ExtendedPreamblePattern = v;
break;
case 7:
if (v[0] == 1) S_CDMAMode = true;
else if (v[0] == 2) S_CDMAMode = false;
else break;
break;
case 15:
//Undocumented as of DOCSIS 4.0 ?
break;
case 16:
RangingRequired = (RangingRequiredEnum)v[0];
break;
case 23:
goto case 5;
case 24:
(v[0], v[1]) = (v[1], v[0]);
UcdChangeIndicator = new UcdChangeIndicatorBitmask(BitConverter.ToUInt16(v, 0));
break;
case 25:
OfdmaTimestampSnapshot = v[0] & 0x0f;
OfdmaTimestampSnapshot <<= 8; //4 bits
OfdmaTimestampSnapshot += v[1];
OfdmaTimestampSnapshot <<= 8; //12 bits
OfdmaTimestampSnapshot += v[2];
OfdmaTimestampSnapshot <<= 8; //20 bits
OfdmaTimestampSnapshot += v[3];
OfdmaTimestampSnapshot <<= 4; //28 bits
OfdmaTimestampSnapshot += ((v[4] & 0xf0) >> 4);
OfdmaTimestampSnapshotDivideBy20 = v[4] & 0x0f;
break;
case 26:
OfdmaCyclicPrefixSize = v[0];
break;
case 27:
OfdmaRolloffPeriodSize = v[0];
break;
case 28:
SubcarrierSpacing = v[0];
break;
case 29:
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
CenterFrequencyOfSubcarrier0 = BitConverter.ToUInt32(v);
break;
case 30:
SubcarrierExclusionBand = new Tuple<ushort, ushort>[length / 4];
for (int i = 0; i < length / 4; i++)
{
(v[(i * 4) + 0], v[(i * 4) + 1]) = (v[(i * 4) + 1], v[(i * 4) + 0]);
(v[(i * 4) + 2], v[(i * 4) + 3]) = (v[(i * 4) + 3], v[(i * 4) + 2]);
SubcarrierExclusionBand[i] = new Tuple<ushort, ushort>(BitConverter.ToUInt16(v, (i * 4) + 0), BitConverter.ToUInt16(v, (i * 4) + 2));
}
break;
case 32:
SymbolsInOfdmaFrame = v[0];
break;
case 33:
byte[] v2 = new byte[4];
(v2[0], v2[1], v2[2]) = (v[2], v[1], v[0]);
RandomizationSeed = BitConverter.ToUInt32(v2, 0);
break;
default:
if (type > 34)
{
Valid = false;
return;
}
throw new NotImplementedException(String.Format("{0} TLV type {1}", nameof(UpstreamChannelDescriptor), type));
}
}
Valid = true;
}
public uint RandomizationSeed { get; set; }
public byte? SymbolsInOfdmaFrame { get; set; }
public Tuple<ushort, ushort>[] SubcarrierExclusionBand { get; private set; }
public uint? CenterFrequencyOfSubcarrier0 { get; set; }
public byte? SubcarrierSpacing { get; set; }
public byte? OfdmaRolloffPeriodSize { get; set; }
public byte? OfdmaCyclicPrefixSize { get; set; }
public int? OfdmaTimestampSnapshotDivideBy20 { get; set; }
public int? OfdmaTimestampSnapshot { get; set; }
public UcdChangeIndicatorBitmask UcdChangeIndicator { get; private set; }
public List<BurstDescriptor> BurstDescriptors { get; private set; }
public bool? S_CDMAMode { get; set; }
public byte[] PreamblePattern { get; set; }
public uint? Frequency { get; set; }
public byte? ModulationRate { get; set; }
public byte DownstreamChannelId { get; set; }
public byte MinislotSize { get; set; }
public byte ConfigurationChangeCount { get; set; }
public byte UpstreamChannelID { get; set; }
public byte[] ExtendedPreamblePattern { get; private set; }
public RangingRequiredEnum RangingRequired { get; private set; }
public enum RangingRequiredEnum : byte
{
NoRangingRequired = 0,
UnicastInitialRangingRequired = 1,
BroadcastInitialRangingRequired = 2,
ProbingRequired = 3
}
public class BurstDescriptor
{
public BurstDescriptor(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
IntervalUsageCode = ms.ReadUInt8();
while (ms.GetAvailableBytes() > 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
byte[] v = ms.ReadBytes(length);
switch (type)
{
//Found in CM-SP-MULPIv4.0-I01-190815.pdf, page 118
case 1:
ModulationType = v[0];
break;
case 2:
if (v[0] == 1)
DifferentialEncoding = true;
else if (v[0] == 2)
DifferentialEncoding = false;
else
break;
break;
case 3:
(v[1], v[0]) = (v[0], v[1]);
PreambleLength = BitConverter.ToUInt16(v, 0);
break;
case 4:
(v[1], v[0]) = (v[0], v[1]);
PreambleValueOffset = BitConverter.ToUInt16(v, 0);
break;
case 5:
FecErrorCorrection = v[0];
break;
case 6:
FecCodewordInformationBytes = v[0];
break;
case 7:
(v[1], v[0]) = (v[0], v[1]);
ScramblerSeed = BitConverter.ToUInt16(v, 0);
ScramblerSeed &= 0x7fff;
break;
case 8:
MaximumBurstSize = v[0];
break;
case 9:
GuardTimeSize = v[0];
break;
case 10:
LastCodewordLength = (CodewordLength)v[0];
break;
case 11:
if (v[0] == 1)
Scrambler = true;
else if (v[0] == 2)
Scrambler = false;
else
break;
break;
case 12:
RsInterleaverDepth = v[0];
break;
case 13:
(v[1], v[0]) = (v[0], v[1]);
RsInterleaverBlockSize = BitConverter.ToUInt16(v, 0);
break;
case 14:
PreambleType = (PreambleTypeEnum)v[0];
break;
case 19:
(v[1], v[0]) = (v[0], v[1]);
SubcarriersInitialRanging = BitConverter.ToUInt16(v, 0);
break;
case 20:
(v[1], v[0]) = (v[0], v[1]);
SubcarriersFineRanging = BitConverter.ToUInt16(v, 0);
break;
case 21:
OfdmaDataProfiles = new OfdmaDataProfile[length / 2];
for (int i = 0; i < length / 2; i++)
{
OfdmaDataProfiles[i] = new OfdmaDataProfile(v[(i * 2) + 0], v[(i * 2) + 1]);
}
break;
case 22:
OfdmaBroadcastIrStartingPowerLevel = (double)v[0] * 1.6;
OfdmaBroadcastIrStartingPowerLevelIncrease = (double)v[1] * 0.25;
break;
default:
throw new NotImplementedException(String.Format("{0} {1} {2}", nameof(BurstDescriptor), nameof(type), type));
}
}
}
public OfdmaDataProfile[] OfdmaDataProfiles { get; private set; }
public ushort? SubcarriersFineRanging { get; set; }
public double? OfdmaBroadcastIrStartingPowerLevelIncrease { get; set; }
public double? OfdmaBroadcastIrStartingPowerLevel { get; set; }
public ushort? SubcarriersInitialRanging { get; set; }
public PreambleTypeEnum? PreambleType { get; private set; }
public enum PreambleTypeEnum : byte
{
QPSK0 = 1,
QPSK1 = 2
}
public ushort? RsInterleaverBlockSize { get; set; }
public byte? RsInterleaverDepth { get; set; }
public bool? Scrambler { get; set; }
public CodewordLength? LastCodewordLength { get; set; }
public enum CodewordLength : byte
{
Fixed = 1,
Shortened = 2
}
public byte? GuardTimeSize { get; set; }
public byte? MaximumBurstSize { get; set; }
public int? ScramblerSeed { get; set; }
public byte? FecCodewordInformationBytes { get; set; }
public byte? FecErrorCorrection { get; set; }
public ushort? PreambleValueOffset { get; set; }
public ushort? PreambleLength { get; set; }
public bool? DifferentialEncoding { get; set; }
public byte? ModulationType { get; set; }
public byte IntervalUsageCode { get; set; }
}
public class UcdChangeIndicatorBitmask
{
private readonly ushort rawValue;
public UcdChangeIndicatorBitmask(ushort readUInt16Be)
{
this.rawValue = readUInt16Be;
}
public bool ChangeIuc14 => (rawValue & 0x0020) != 0;
public bool ChangeIuc13 => (rawValue & 0x0040) != 0;
public bool ChangeIuc12 => (rawValue & 0x0080) != 0;
public bool ChangeIuc11 => (rawValue & 0x0100) != 0;
public bool ChangeIuc10 => (rawValue & 0x0200) != 0;
public bool ChangeIuc9 => (rawValue & 0x0400) != 0;
public bool ChangeIuc6 => (rawValue & 0x0800) != 0;
public bool ChangeIuc5 => (rawValue & 0x1000) != 0;
public bool ChangeOtherParameters => (rawValue & 0x2000) != 0;
public bool ChangeUnusedSubcarrierSpecification => (rawValue & 0x4000) != 0;
public bool ChangeSubcarrierExclusionBand => (rawValue & 0x8000) != 0;
public ushort GetRawValue()
{
return rawValue;
}
}
public class OfdmaDataProfile
{
private readonly byte first;
private readonly byte second;
public OfdmaDataProfile(byte first, byte second)
{
this.first = first;
this.second = second;
}
public ModulationOrderIndex Modulation => (ModulationOrderIndex)((first & 0xf0) >> 4);
public int PilotPatternIndex => (first & 0x0f);
public byte NumberOfMinisolts => second;
public enum ModulationOrderIndex
{
NoBitLoading,
Reserved,
QPSK,
_8QAM,
_16QAM,
_32QAM,
_64QAM,
_128QAM,
_256QAM,
_512QAM,
_1024QAM,
_2048QAM,
_4096QAM
}
}
}
}