19 throw new ArgumentNullException(nameof(packet));
21 var sb =
new StringBuilder();
23 string deltaString = FormatTimeDelta(timeDelta);
24 string direction = packet.CommandType !=
null ?
"ACU -> PD" :
"PD -> ACU";
25 string type = (packet.
CommandType?.GetDisplayName() ?? packet.
ReplyType?.GetDisplayName()) ??
"Unknown";
27 sb.AppendLine($
"{timestamp:yy-MM-dd HH:mm:ss.fff}{deltaString} {direction}: {type}");
28 sb.Append($
" Address: {packet.Address} Sequence: {packet.Sequence}");
35 sb.Append(
" [Clear Text]");
41 sb.AppendLine(
" *** Payload is encrypted - SCBK (Secure Channel Base Key) required to decrypt ***");
45 string secureChannelDetails = FormatSecureChannelHandshake(packet);
46 if (secureChannelDetails !=
null)
48 sb.AppendLine(secureChannelDetails);
53 if (payloadData !=
null)
55 string payloadString = payloadData
switch
57 byte[] data => $
" {BitConverter.ToString(data)}",
58 _ => $
" {payloadData}"
60 sb.AppendLine(payloadString);
74 private static string FormatSecureChannelHandshake(
Packet packet)
79 return FormatSessionChallenge(packet);
81 return FormatServerCryptogram(packet);
87 return FormatCrypticData(packet);
89 return FormatInitialRMac(packet);
95 private static string FormatSessionChallenge(
Packet packet)
98 var lines =
new List<string>
100 " Secure Channel Handshake: osdp_CHLNG (Step 1 of 4 - ACU challenge)",
101 FormatSecurityBlockLine(packet, DescribeKeyType(packet))
103 lines.Add(payload.Length >= 8
104 ? $
" RND.A (ACU random): {Hex(payload.Slice(0, 8))}"
105 : $
" Payload: {Hex(payload)}");
106 return string.Join(Environment.NewLine, lines);
109 private static string FormatCrypticData(Packet packet)
112 var lines =
new List<string>
114 " Secure Channel Handshake: osdp_CCRYPT (Step 2 of 4 - PD response)",
115 FormatSecurityBlockLine(packet, DescribeKeyType(packet))
117 if (payload.Length >= 32)
119 lines.Add($
" cUID (PD unique ID): {Hex(payload.Slice(0, 8))}");
120 lines.Add($
" RND.B (PD random): {Hex(payload.Slice(8, 8))}");
121 lines.Add($
" Client cryptogram: {Hex(payload.Slice(16, 16))}");
125 lines.Add($
" Payload: {Hex(payload)}");
127 return string.Join(Environment.NewLine, lines);
130 private static string FormatServerCryptogram(Packet packet)
132 return string.Join(Environment.NewLine,
133 " Secure Channel Handshake: osdp_SCRYPT (Step 3 of 4 - ACU server cryptogram)",
134 FormatSecurityBlockLine(packet, DescribeKeyType(packet)),
135 $
" Server cryptogram: {Hex(packet.RawPayloadData)}");
138 private static string FormatInitialRMac(Packet packet)
140 return string.Join(Environment.NewLine,
141 " Secure Channel Handshake: osdp_RMAC_I (Step 4 of 4 - secure channel established)",
142 FormatSecurityBlockLine(packet, DescribeCryptogramAcceptance(packet)),
143 $
" Initial R-MAC: {Hex(packet.RawPayloadData)}");
150 private static string FormatSecurityBlockLine(Packet packet,
string interpretation)
154 string suffix =
string.IsNullOrEmpty(interpretation) ? string.Empty : $
" ({interpretation})";
155 return $
" Security Block: {scsType}, SEC_BLK_DATA: {data}{suffix}";
158 private static string DescribeSecurityBlockType(
byte type)
178 private static string DescribeKeyType(Packet packet)
181 if (secureBlockData ==
null || secureBlockData.Length == 0)
186 return secureBlockData[0] == 0x00 ?
"Default key (SCBK-D)" :
"Configured key (SCBK)";
194 private static string DescribeCryptogramAcceptance(Packet packet)
197 if (secureBlockData ==
null || secureBlockData.Length == 0)
202 return secureBlockData[0] == 0x01
203 ?
"Server cryptogram accepted"
204 :
"Server cryptogram rejected";
207 private static string FormatSecureBlockData(
byte[] data) =>
208 data ==
null || data.Length == 0 ?
"(none)" : BitConverter.ToString(data);
210 private static string Hex(ReadOnlySpan<byte> data) => BitConverter.ToString(data.ToArray());
214 public string FormatError(
byte[] rawData, DateTime timestamp, TimeSpan? timeDelta,
string errorMessage)
217 throw new ArgumentNullException(nameof(rawData));
219 var sb =
new StringBuilder();
220 string deltaString = FormatTimeDelta(timeDelta);
222 sb.AppendLine($
"{timestamp:yy-MM-dd HH:mm:ss.fff}{deltaString}");
223 sb.AppendLine($
"*** Error parsing packet: {errorMessage} ***");
224 sb.AppendLine($
" Raw data: {BitConverter.ToString(rawData)}");
226 return sb.ToString();
229 private static string FormatTimeDelta(TimeSpan? timeDelta)
231 return timeDelta.HasValue ? $
" [ {timeDelta.Value:g} ]" :
string.Empty;
string FormatError(byte[] rawData, DateTime timestamp, TimeSpan? timeDelta, string errorMessage)
Formats a packet that failed to parse due to an error.Formatted text with error information and raw d...