Files
DP44/DataPRO/SLICECommands/MulticastCommands/MulticastDiscoverSlice6.cs
2026-04-17 14:55:32 -04:00

233 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using DTS.DASLib.Command.Classes;
using DTS.Common.Utilities.Logging;
using DTS.Common.Interface.DASFactory;
using DTS.Common.Enums.DASFactory;
namespace DTS.DASLib.Command.SLICE.MulticastCommands
{
/// <summary>
/// 10558 Auto-discovery to add cmd/res support for MAC table
/// </summary>
public class MulticastDiscoverSlice6 : MulticastCommandBase
{
#region constants and enums
private const int COMMAND_PAYLOAD_SIZE = 80;
private const int DEVICE_CLASS_OFFSET = 36;
private const int NUMBER_OF_RECORDS_OFFSET = 40;
private const int RESERVED_OFFSET = 42;
private const int START_OF_MAC_TABLE = 48;
private const int SIZE_OF_MAC_RECORD = 12;//bytes
private const int PORT_OFFSET = 2;
private const int FILTER_OFFSET = 4;
private const int MAC_OFFSET = 6;
#endregion
#region private properties
protected override Commands Command => Commands.GetMACTable;
protected override bool StopAfterFirstMessage => false;
private uint _deviceClass;
private byte _responseOption;
private IPAddress _address;
private const string RX_MULTICAST_ADDRESS = "239.4.5.6";
private void SetMulticastConfig()
{
IPAddress.TryParse(RX_MULTICAST_ADDRESS, out _address);
}
#endregion
#region public properties
public DeviceClasses DeviceClass { set { _deviceClass = (uint)value; command.SetParameter(36, (int)_deviceClass); } }
public ResponseOptions ResponseOption { set { _responseOption = (byte)value; command.SetParameter(40, _responseOption); } }
public uint DesiredPort
{
set => command.SetParameter(41, value);
}
public byte[] MACFilter
{
set => command.SetParameter(45, value);
}
public TextLogger Logger { get; set; }
public Dictionary<string, IDiscoveredDevice> MACAddressToDevice { get; set; }
private readonly List<DiscoveredConnectedSlice> _connectedDevices = new List<DiscoveredConnectedSlice>();
public DiscoveredConnectedSlice[] ConnectedDevices => _connectedDevices.ToArray();
#endregion
#region constructors and initializers
public MulticastDiscoverSlice6(DeviceClasses deviceClass, string hostMac)
: base(null)
{
command.Parameter = new byte[COMMAND_PAYLOAD_SIZE];
HostMac = hostMac;
DeviceClass = deviceClass;
ResponseOption = ResponseOptions.AlwaysRespond;
SetMulticastConfig();
DesiredPort = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3;
MACFilter = new[]
{
Convert.ToByte(0x00),
Convert.ToByte(0x19),
Convert.ToByte(0x9b),
byte.MaxValue,
byte.MaxValue,
byte.MaxValue
};
}
public MulticastDiscoverSlice6(string hostMac, int timeoutMillisec)
: base(null, timeoutMillisec)
{
command.Parameter = new byte[COMMAND_PAYLOAD_SIZE];
HostMac = hostMac;
DeviceClass = DeviceClasses.Any;
ResponseOption = ResponseOptions.AlwaysRespond;
SetMulticastConfig();
DesiredPort = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3;//ports 1-4
MACFilter = new[]
{
Convert.ToByte(0x00),
Convert.ToByte(0x19),
Convert.ToByte(0x9b),
byte.MaxValue,
byte.MaxValue,
byte.MaxValue
};
}
#endregion
#region methods
protected override CommandReceiveAction WholePackage()
{
if (response.Status != DFConstantsAndEnums.CommandStatus.StatusNoError)
return CommandReceiveAction.StopReceiving;
response.GetParameter(HOST_MAC_ADDRESS_OFFSET, out ResponseHostMac);
if (null == ResponseHostMac || !HostMac.Equals(ResponseHostMac))
{
response.Status = DFConstantsAndEnums.CommandStatus.StatusInvalidPacket;
return CommandReceiveAction.StopReceiving;
}
response.GetParameter(CLIENT_MAC_ADDRESS_OFFSET, out ResponseClientMac);
response.GetParameter(DEVICE_CLASS_OFFSET, out _deviceClass);
ushort numberOfEntries;
response.GetParameter(NUMBER_OF_RECORDS_OFFSET, out numberOfEntries);
var list = new List<MACTableEntry>();
for (var i = 0; i < numberOfEntries; i++)
{
try
{
response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD, out ushort age);
response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD + PORT_OFFSET, out ushort port);
response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD + FILTER_OFFSET, out ushort filter);
var mac = new byte[6];
for (var b = 0; b < mac.Length; b++)
{
response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD + MAC_OFFSET + b, out byte thisByte);
mac[b] = thisByte;
}
list.Add(new MACTableEntry(age, port, filter, mac));
}
catch (Exception ex)
{
APILogger.Log($"MulticastDiscoverSlice6 failed to get entry - ignoring entry", ex.Message);
}
}
_connectedDevices.Add(new DiscoveredConnectedSlice(ResponseClientMac, list.ToArray()));
var responseMac = ResponseClientMac.Replace('-', ':').ToUpper();
var serialNumber = "N/A";
if (null != MACAddressToDevice && MACAddressToDevice.ContainsKey(responseMac))
{
serialNumber = MACAddressToDevice[responseMac].Serial;
}
Log(ResponseHostMac, ResponseClientMac, list.ToArray(), serialNumber);
//Log(response.Parameter);
return CommandReceiveAction.StopReceiving;
}
private static string ByteToHex(byte b)
{
return $"{b:x2}";
}
private void Log(IReadOnlyList<byte> parameter)
{
var sb = new StringBuilder();
sb.Append("msg: ");
foreach (var b in parameter)
{
sb.Append(ByteToHex(b));
}
sb.AppendLine();
//var bytes = new List<byte>(parameter);
sb.Append("header: ");
for (var i = 0; i < START_OF_MAC_TABLE; i++)
{
sb.Append(ByteToHex(parameter[i]));
}
sb.AppendLine();
for (var i = START_OF_MAC_TABLE; i < parameter.Count; i += SIZE_OF_MAC_RECORD)
{
sb.Append("Record: ");
for (var idx = 0; idx < SIZE_OF_MAC_RECORD; idx++)
{
sb.Append(ByteToHex(parameter[i + idx]));
}
sb.AppendLine();
}
Log(sb.ToString());
}
private void Log(string responseHostMac, string responseClientMac, MACTableEntry[] entries, string serialNumber)
{
var sb = new StringBuilder();
sb.AppendFormat("Host: {0}, Client: {1}, SerialNumber: {2}", responseHostMac, responseClientMac, serialNumber);
sb.AppendLine();
sb.AppendLine("Age\tFilter\tMAC\t\t\tPort");
foreach (var entry in entries)
{
sb.AppendFormat("{0}\t{1}\t{2}\t{3}", entry.Age, entry.Filter, MACAddressToString(entry.MAC), entry.Port);
sb.AppendLine();
}
Log(sb.ToString());
}
public static string MACAddressToString(IEnumerable<byte> mac)
{
var list = mac.Select(b => $"{b:x2}").ToList();
return string.Join(":", list.ToArray()).ToUpper();
}
public override void CommandToString(ref List<List<string>> lines)
{
base.CommandToString(ref lines);
lines.Add(new List<string> { $"AutoDiscover: [{HostMac}]" });
}
private void Log(string msg)
{
if (null == Logger) { return; }
Logger.LogMessage($"====={DateTime.Now.ToShortDateString()} {DateTime.Now.ToShortTimeString()}=====\r\n");
Logger.LogMessage(msg);
}
#endregion
}
}