7internal class OutgoingMessage :
Message
9 private const int StartOfMessageLength = 5;
11 internal OutgoingMessage(
byte address, Control controlBlock, PayloadData data)
14 ControlBlock = controlBlock;
18 internal Control ControlBlock {
get; }
20 internal byte Code => PayloadData.
Code;
22 internal PayloadData PayloadData {
get; }
24 internal byte[] BuildMessage(IMessageSecureChannel secureChannel)
26 var payload = PayloadData.BuildData();
28 var securityEstablished = secureChannel is { IsSecurityEstablished:
true };
30 if (securityEstablished && payload.Length > 0)
32 payload = secureChannel.
PadTheData(payload).ToArray();
35 bool isSecurityBlockPresent = securityEstablished || PayloadData.IsSecurityInitialization;
36 var securityBlock = isSecurityBlockPresent ? PayloadData.SecurityControlBlock() : Array.Empty<
byte>();
38 int headerLength = StartOfMessageLength + securityBlock.Length +
sizeof(
ReplyType);
39 int totalLength = headerLength + payload.Length +
40 (ControlBlock.UseCrc ? 2 : 1) +
41 (securityEstablished ?
MacSize : 0);
42 var buffer =
new byte[totalLength];
43 int currentLength = 0;
46 buffer[currentLength++] =
Address;
47 buffer[currentLength++] = (byte)(totalLength & 0xff);
48 buffer[currentLength++] = (byte)((totalLength >> 8) & 0xff);
49 buffer[currentLength++] = (byte)((ControlBlock.ControlByte & 0x07) | (isSecurityBlockPresent ? 0x08 : 0x00));
51 if (isSecurityBlockPresent)
53 securityBlock.CopyTo(buffer.AsSpan(currentLength));
54 currentLength += securityBlock.Length;
57 buffer[currentLength++] = PayloadData.Code;
59 if (securityEstablished)
61 secureChannel.
EncodePayload(payload, buffer.AsSpan(currentLength));
62 currentLength += payload.Length;
63 secureChannel.
GenerateMac(buffer.AsSpan(0, currentLength),
false)
65 .CopyTo(buffer.AsSpan(currentLength));
70 payload.CopyTo(buffer, currentLength);
71 currentLength += payload.Length;
74 if (ControlBlock.UseCrc)
85 if (currentLength != buffer.Length)
88 $
"Invalid processing of reply data, expected length {currentLength}, actual length {buffer.Length}");
91 PayloadData.CustomMessageUpdate(buffer);
96 var messageBuffer =
new byte[buffer.Length + 1];
97 messageBuffer[0] = Bus.DriverByte;
98 Buffer.BlockCopy(buffer, 0, messageBuffer, 1, buffer.Length);
100 return messageBuffer;
103 protected override ReadOnlySpan<byte>
Data()
105 return PayloadData.BuildData();
110internal class OutgoingReply : OutgoingMessage
112 internal OutgoingReply(IncomingMessage command, PayloadData replyPayload) :
113 base((byte)(command.
Address | 0x80), command.ControlBlock, replyPayload)
117 internal IncomingMessage Command {
get; }
A base message class for sending or replying.
const ushort MacSize
Size in bytes of MAC signature in message suffix when the secure channel has been established.
static void AddChecksum(IList< byte > packet)
Adds the checksum to the packet.
byte Address
Address assigned to the device.
const byte StartOfMessage
OSDP message SOM (start of the message) byte.
ReadOnlySpan< byte > Data()
The data.
byte Code
Gets the command or reply code byte value that represent the type of data.
ReadOnlySpan< byte > GenerateMac(ReadOnlySpan< byte > message, bool isIncoming)
Generates a new Message Authentication Code.
void EncodePayload(byte[] payload, Span< byte > destination)
Encrypts the payload using the secure channel context.
ReadOnlySpan< byte > PadTheData(ReadOnlySpan< byte > payload)
Pads the given data with padding bytes to make it a multiple of a specified length.
ReplyType
Identifies the type of OSDP protocol reply (PD -> ACU) message.