/// <summary>
/// Get next logical name PDU.
/// </summary>
/// <param name="p">LN parameters.</param>
/// <param name="reply">Generated message.</param>
internal static void GetLNPdu(GXDLMSLNParameters p, GXByteBuffer reply)
{
bool ciphering = p.settings.Cipher != null && p.settings.Cipher.Security != Gurux.DLMS.Enums.Security.None;
int len = 0;
if (!ciphering && p.settings.InterfaceType == InterfaceType.HDLC)
{
AddLLCBytes(p.settings, reply);
}
if (p.command == Command.Aarq)
{
reply.Set(p.attributeDescriptor);
}
else
{
if (p.settings.LnSettings.GeneralBlockTransfer)
{
reply.SetUInt8((byte)Command.GeneralBlockTransfer);
MultipleBlocks(p, reply, ciphering);
// Is last block
if (!p.lastBlock)
{
reply.SetUInt8(0);
}
else
{
reply.SetUInt8(0x80);
}
// Set block number sent.
reply.SetUInt8(0);
// Set block number acknowledged
reply.SetUInt8((byte)p.blockIndex);
++p.blockIndex;
// Add APU tag.
reply.SetUInt8(0);
// Add Addl fields
reply.SetUInt8(0);
}
// Add command.
reply.SetUInt8((byte)p.command);
if (p.command == Command.DataNotification ||
p.command == Command.AccessRequest ||
p.command == Command.AccessResponse)
{
// Add Long-Invoke-Id-And-Priority
reply.SetUInt32(GetLongInvokeIDPriority(p.settings));
// Add date time.
if (p.time == null || p.time.Value.DateTime == DateTime.MinValue || p.time.Value.DateTime == DateTime.MaxValue ||
p.time.Value.LocalDateTime == DateTime.MinValue || p.time.Value.LocalDateTime == DateTime.MaxValue)
{
reply.SetUInt8(DataType.None);
}
else
{
// Data is send in octet string. Remove data type.
int pos = reply.Size;
GXCommon.SetData(p.settings, reply, DataType.OctetString, p.time);
reply.Move(pos + 1, pos, reply.Size - pos - 1);
}
}
else
{
//Get request size can be bigger than PDU size.
if (p.command != Command.GetRequest &&
p.data != null && p.data.Size != 0)
{
MultipleBlocks(p, reply, ciphering);
}
//Change Request type if Set request and multiple blocks is needed.
if (p.command == Command.SetRequest)
{
if (p.multipleBlocks)
{
if (p.requestType == 1)
{
p.requestType = 2;
}
else if (p.requestType == 2)
{
p.requestType = 3;
}
}
}
//Change request type If get response and multiple blocks is needed.
if (p.command == Command.GetResponse)
{
if (p.multipleBlocks)
{
if (p.requestType == 1)
{
p.requestType = 2;
}
}
}
reply.SetUInt8(p.requestType);
// Add Invoke Id And Priority.
reply.SetUInt8(GetInvokeIDPriority(p.settings));
}
//Add attribute descriptor.
reply.Set(p.attributeDescriptor);
if (p.command != Command.DataNotification && !p.settings.LnSettings.GeneralBlockTransfer)
{
//If multiple blocks.
if (p.multipleBlocks)
{
// Is last block.
if (p.lastBlock)
{
reply.SetUInt8(1);
p.settings.Count = p.settings.Index = 0;
}
else
{
reply.SetUInt8(0);
}
// Block index.
reply.SetUInt32(p.blockIndex);
++p.blockIndex;
//Add status if reply.
if (p.status != 0xFF)
{
if (p.status != 0 && p.command == Command.GetResponse)
{
reply.SetUInt8(1);
}
reply.SetUInt8(p.status);
}
//Block size.
if (p.data != null)
{
len = p.data.Size - p.data.Position;
}
else
{
len = 0;
}
int totalLength = len + reply.Size;
if (ciphering)
{
totalLength += CipheringHeaderSize;
}
if (totalLength > p.settings.MaxPduSize)
{
len = p.settings.MaxPduSize - reply.Size - p.data.Position;
if (ciphering)
{
len -= CipheringHeaderSize;
}
len -= GXCommon.GetObjectCountSizeInBytes(len);
}
GXCommon.SetObjectCount(len, reply);
reply.Set(p.data, len);
}
}
//Add data that fits to one block.
if (len == 0)
{
//Add status if reply.
if (p.status != 0xFF)
{
if (p.status != 0 && p.command == Command.GetResponse)
{
reply.SetUInt8(1);
}
reply.SetUInt8(p.status);
}
if (p.data != null && p.data.Size != 0)
{
len = p.data.Size - p.data.Position;
//Get request size can be bigger than PDU size.
if (p.command != Command.GetRequest && len + reply.Size > p.settings.MaxPduSize)
{
len = p.settings.MaxPduSize - reply.Size;
}
reply.Set(p.data, len);
}
}
if (ciphering)
{
byte[] tmp = p.settings.Cipher.Encrypt((byte)GetGloMessage(p.command),
p.settings.Cipher.SystemTitle, reply.Array());
reply.Size = 0;
if (p.settings.InterfaceType == InterfaceType.HDLC)
{
AddLLCBytes(p.settings, reply);
}
if (p.command == Command.DataNotification)
{
// Add command.
reply.SetUInt8(tmp[0]);
// Add system title.
GXCommon.SetObjectCount(
p.settings.Cipher.SystemTitle.Length,
reply);
reply.Set(p.settings.Cipher.SystemTitle);
// Add data.
reply.Set(tmp, 1, tmp.Length - 1);
}
else
{
reply.Set(tmp);
}
}
}
}