secs gem 解包
using System.Text;
public enum SECSFormat
{
List,
Binary,
Boolean,
Ascii,
Char,
I1,
I2,
I4,
I8,
U1,
U2,
U4,
U8,
F4,
F8,
UNRECOGNIZE_FORMAT
}
public class Logger
{
private int _indentationLevel;
private readonly StringBuilder _logBuilder = new StringBuilder();
public void Indent() => _indentationLevel++;
public void Unindent() => _indentationLevel = Math.Max(0, _indentationLevel - 1);
public void Print(string message)
{
var spaces = new string(' ', _indentationLevel * 3);
_logBuilder.AppendLine(spaces + message);
}
public string GetLog() => _logBuilder.ToString();
public void Clear() => _logBuilder.Clear();
}
class Program
{
private static readonly Logger Logger = new Logger();
static void Main(string[] args)
{
// Console.WriteLine("请输入十六进制报文(空格分隔,例如: 01 0A FF):");
// var input = Console.ReadLine();
var input = "00 00 81 0D 00 00 00 00 00 22 01 02 41 04 54 45 53 54 41 03 31 2E 31";
// Console.WriteLine("包含头报文?(Y/N)");
// var hasHeader = Console.ReadLine()?.Trim().ToUpper() == "Y";
var hasHeader = true;
try
{
var bytes = HexStringToByteArray(input);
ParseMessage(bytes, hasHeader);
Console.WriteLine("\n解析结果:");
Console.WriteLine(Logger.GetLog());
}
catch (Exception ex)
{
Console.WriteLine($"解析错误: {ex.Message}");
}
}
private static byte[] HexStringToByteArray(string hex)
{
if (string.IsNullOrWhiteSpace(hex))
return Array.Empty<byte>();
var hexValues = hex.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var bytes = new byte[hexValues.Length];
for (var i = 0; i < hexValues.Length; i++)
{
bytes[i] = Convert.ToByte(hexValues[i], 16);
}
return bytes;
}
private static void ParseMessage(byte[] message, bool hasHeader)
{
Logger.Clear();
var index = 0;
if (hasHeader && message.Length >= 10)
{
var header = ParseHeader(message);
Logger.Print($"S{header.StreamID}F{header.FunctionID} {header.Wait}");
index = 10;
}
ParseMessageBody(message, ref index);
}
private static (int StreamID, int FunctionID, string Wait) ParseHeader(byte[] header)
{
var waitBit = (header[2] & 0x80) != 0;
var streamID = header[2] & 0x7F;
var functionID = header[3];
return (streamID, functionID, waitBit ? "W" : "");
}
private static void ParseMessageBody(byte[] message, ref int index)
{
System.Console.WriteLine("111111111111");
Console.WriteLine(string.Join(" ", message.Select(b => b.ToString("X2"))));
while (index < message.Length)
{
var formatCode = message[index++];
System.Console.WriteLine("222222222");
System.Console.WriteLine(formatCode.ToString("X2"));
var (format, lengthBytes) = GetFormat(formatCode);
if (format == SECSFormat.UNRECOGNIZE_FORMAT)
{
Logger.Print("UNRECOGNIZE_FORMAT");
return;
}
if (format == SECSFormat.List)
{
var listLength = message[index++];
Logger.Print($"<L[{listLength}]");
Logger.Indent();
for (var i = 0; i < listLength; i++)
{
ParseMessageBody(message, ref index);
}
Logger.Unindent();
Logger.Print(">");
}
else
{
var dataLength = message[index++];
var data = new byte[dataLength];
Array.Copy(message, index, data, 0, dataLength);
index += dataLength;
var value = GetValue(format, data);
Logger.Print(format == SECSFormat.Ascii ? $"<{format}[{dataLength}] '{value}'>" : $"<{format}[{dataLength}] {value}>");
}
}
}
private static (SECSFormat format, int lengthBytes) GetFormat(byte formatCode)
{
var bits = Convert.ToString(formatCode, 2).PadLeft(8, '0');
var formatBits = bits[..6];
var lengthBits = bits[6..];
var lengthBytes = lengthBits switch
{
"01" => 1,
"10" => 2,
"11" => 3,
_ => 1
};
return formatBits switch
{
"000000" => (SECSFormat.List, lengthBytes),
"001000" => (SECSFormat.Binary, lengthBytes),
"001001" => (SECSFormat.Boolean, lengthBytes),
"010000" => (SECSFormat.Ascii, lengthBytes),
"010010" => (SECSFormat.Char, lengthBytes),
"011001" => (SECSFormat.I1, lengthBytes),
"011010" => (SECSFormat.I2, lengthBytes),
"011100" => (SECSFormat.I4, lengthBytes),
"011000" => (SECSFormat.I8, lengthBytes),
"101001" => (SECSFormat.U1, lengthBytes),
"101010" => (SECSFormat.U2, lengthBytes),
"101100" => (SECSFormat.U4, lengthBytes),
"101000" => (SECSFormat.U8, lengthBytes),
"100100" => (SECSFormat.F4, lengthBytes),
"100000" => (SECSFormat.F8, lengthBytes),
_ => (SECSFormat.UNRECOGNIZE_FORMAT, 0)
};
}
private static string GetValue(SECSFormat format, byte[] data)
{
Array.Reverse(data); // 处理字节序
return format switch
{
SECSFormat.Ascii => Encoding.ASCII.GetString(data),
SECSFormat.Boolean => (data[0] != 0).ToString(),
SECSFormat.Char => ((char)data[0]).ToString(),
SECSFormat.F4 => BitConverter.ToSingle(data, 0).ToString(),
SECSFormat.F8 => BitConverter.ToDouble(data, 0).ToString(),
SECSFormat.I1 => ((sbyte)data[0]).ToString(),
SECSFormat.I2 => BitConverter.ToInt16(data, 0).ToString(),
SECSFormat.I4 => BitConverter.ToInt32(data, 0).ToString(),
SECSFormat.I8 => BitConverter.ToInt64(data, 0).ToString(),
SECSFormat.U1 => data[0].ToString(),
SECSFormat.U2 => BitConverter.ToUInt16(data, 0).ToString(),
SECSFormat.U4 => BitConverter.ToUInt32(data, 0).ToString(),
SECSFormat.U8 => BitConverter.ToUInt64(data, 0).ToString(),
SECSFormat.Binary => BitConverter.ToString(data).Replace("-", " "),
_ => "UNKNOWN_TYPE"
};
}
}
参考原博主的js版本链接:https://www.cnblogs.com/xfweb/p/18144831
浙公网安备 33010602011771号