skyscraper8/skyscraper8/Docsis/MacManagement/T5_V1_RangingResponse.cs
2025-05-17 22:52:12 +02:00

302 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Numerics;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Docsis.AnnexC;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
namespace skyscraper5.Docsis.MacManagement
{
[SkyscraperPlugin]
[MacManagementMessageType(1,5)]
[MacManagementMessageType(5,5)]
public class RangingResponse : MacManagementMessage
{
public RangingResponse(PhysicalAddress source, PhysicalAddress destination, byte[] buffer) : base(source, destination, buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
SID = ms.ReadUInt16BE();
UpstreamChannelId = ms.ReadUInt8();
long positionFor1516;
while (ms.GetAvailableBytes() > 2)
{
positionFor1516 = ms.Position;
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
if (length > ms.GetAvailableBytes())
{
Valid = false;
return;
}
if (length == 0)
{
Valid = false;
return;
}
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 0:
//reserved
break;
case 1:
if (length < 4)
{
Valid = false;
return;
}
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
TimingAdjust = BitConverter.ToUInt32(v, 0);
break;
case 2:
PowerLevelAdjust = v[0];
break;
case 3:
if (length < 2)
{
Valid = false;
return;
}
(v[0], v[1]) = (v[1], v[0]);
OffsetFrequencyAdjust = BitConverter.ToUInt16(v, 0);
break;
case 4:
TxEqualizationData = v;
break;
case 5:
RangingStatus = (RangingStatusEnum)v[0];
break;
case 6:
if (length < 4)
{
Valid = false;
return;
}
(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
DownstreamFrequencyOverride = BitConverter.ToUInt32(v, 0);
break;
case 7:
UpstreamChannelIdOverride = v[0];
break;
case 8:
TimingAdjustFractionalPart = v[0];
break;
case 9:
TransmitEqualizationSet = v;
break;
case 10:
SCdmaMaximumScheduledCodes = v[0];
break;
case 11:
SCdmaPowerHeadroom = v[0];
break;
case 12:
byte[] upstreamChannelAdjustmentsBuffer = ms.ReadBytes(length);
UpstreamChannelAdjustments = new UpstreamChannelAdjustmentsObject(upstreamChannelAdjustmentsBuffer);
break;
case 13:
T4TimeoutMultiplier = v[0];
break;
case 14:
DynamicRangeWindowUpperEdge = ((double)v[0]) * 0.25;
break;
case 15:
case 16:
ms.Position = positionFor1516;
byte type2 = ms.ReadUInt8();
ushort newLen = ms.ReadUInt16BE();
if (ms.GetAvailableBytes() < newLen)
{
newLen = (ushort)ms.GetAvailableBytes();
}
v = ms.ReadBytes(newLen);
TransmitEqualizationEncodingsForOfdmaChannels result1516 = Parse1516(v);
if (type == 15)
TransmitEqualizationAdjustForOfdmaChannels = Parse1516(v);
else if (type == 16)
TransmitEqualizationSetForOfdmaChannels = Parse1516(v);
else
throw new NotImplementedException(String.Format("2-byte TLV entry in Ranging Response with ID {0}", type));
break;
case 17:
CommandPower = new CommandPowerObject(v);
if (!CommandPower.Valid)
{
CommandPower = null;
Valid = false;
return;
}
break;
case 18:
FdxCommandedPower = new CommandPowerObject(v);
if (!FdxCommandedPower.Valid)
{
FdxCommandedPower = null;
Valid = false;
return;
}
break;
default:
if (type > 18)
{
Valid = false;
return;
}
//see CM-SP-MULPIv4.0-I01-190815.pdf page 141
throw new NotImplementedException(String.Format("{0} Type {1}", nameof(RangingResponse), type));
}
}
Valid = true;
}
public byte[] TransmitEqualizationSet { get; private set; }
private TransmitEqualizationEncodingsForOfdmaChannels Parse1516(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer);
byte l = ms.ReadUInt8();
byte m = ms.ReadUInt8();
byte r = ms.ReadUInt8();
TransmitEqualizationEncodingsForOfdmaChannels result = new TransmitEqualizationEncodingsForOfdmaChannels();
result.LowestSubcarrier = (l << 4);
result.LowestSubcarrier += ((m & 0xf0) >> 4);
result.HighestSubcarrier = (m & 0x0f);
result.HighestSubcarrier <<= 4;
result.HighestSubcarrier += r;
long numCoefficents = ms.GetAvailableBytes() / 4;
result.Coefficients = new Complex[numCoefficents];
for (int i = 0; i < numCoefficents; i++)
{
ushort real = ms.ReadUInt16BE();
ushort imaginary = ms.ReadUInt16BE();
result.Coefficients[i] = new Complex(real, imaginary);
}
return result;
}
public TransmitEqualizationEncodingsForOfdmaChannels TransmitEqualizationAdjustForOfdmaChannels { get; private set; }
private CommandPowerObject CommandPower { get; set; }
class CommandPowerObject : Validatable
{
public CommandPowerObject(byte[] buffer)
{
if (buffer.Length < 2)
{
Valid = false;
return;
}
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
if (length > ms.GetAvailableBytes())
{
Valid = false;
return;
}
byte[] v = ms.ReadBytes(length);
switch (type)
{
case 1:
DynamicRangeWindow = v[0];
break;
case 2:
TransmitPowerLevels = v;
break;
default:
Valid = false;
return;
}
}
Valid = true;
}
public byte[] TransmitPowerLevels { get; set; }
public byte? DynamicRangeWindow { get; set; }
}
public byte? T4TimeoutMultiplier { get; set; }
public byte[] TxEqualizationData { get; set; }
public byte? PowerLevelAdjust { get; set; }
public RangingStatusEnum? RangingStatus { get; private set; }
public enum RangingStatusEnum : byte
{
Continue = 1,
Abort = 2,
Success = 3
}
public ushort? OffsetFrequencyAdjust { get; set; }
public uint? TimingAdjust { get; set; }
public ushort? UpstreamChannelId { get; set; }
public ushort? SID { get; set; }
public TransmitEqualizationEncodingsForOfdmaChannels TransmitEqualizationSetForOfdmaChannels { get; private set; }
public double? DynamicRangeWindowUpperEdge { get; private set; }
public uint? DownstreamFrequencyOverride { get; }
public byte? UpstreamChannelIdOverride { get; private set; }
public byte? SCdmaPowerHeadroom { get; }
public UpstreamChannelAdjustmentsObject UpstreamChannelAdjustments { get; private set; }
private CommandPowerObject FdxCommandedPower { get; }
public byte? TimingAdjustFractionalPart { get; }
public byte? SCdmaMaximumScheduledCodes { get; }
public class UpstreamChannelAdjustmentsObject : Validatable
{
public UpstreamChannelAdjustmentsObject(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
while (ms.GetAvailableBytes() > 2)
{
byte type = ms.ReadUInt8();
byte length = ms.ReadUInt8();
if (length > ms.GetAvailableBytes())
{
Valid = false;
return;
}
byte[] v = ms.ReadBytes(length);
switch (type)
{
default:
if (type > 6)
{
Valid = false;
return;
}
//See CM-SP-MULPIv4.0-I01-190815.pdf page 142
throw new NotImplementedException(String.Format("{0} TLV Type {1}", nameof(UpstreamChannelAdjustmentsObject), type));
}
}
Valid = true;
}
}
public class TransmitEqualizationEncodingsForOfdmaChannels
{
public int LowestSubcarrier { get; internal set; }
public int HighestSubcarrier { get; internal set; }
public Complex[] Coefficients { get; internal set; }
}
}
}