/// <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); } } } }
/// <summary> /// Convert HDLC address to bytes. /// </summary> /// <param name="value"></param> /// <param name="size">Address size in bytes.</param> /// <returns></returns> private static byte[] GetHdlcAddressBytes(int value, byte size) { Object tmp = GetHhlcAddress(value, size); GXByteBuffer bb = new GXByteBuffer(); if (tmp is byte) { bb.SetUInt8((byte)tmp); } else if (tmp is UInt16) { bb.SetUInt16((UInt16)tmp); } else if (tmp is UInt32) { bb.SetUInt32((UInt32)tmp); } else { throw new ArgumentException("Invalid address type."); } return bb.Array(); }
///<summary> ///Generates an acknowledgment message, with which the server is informed to send next packets. ///</summary> ///<param name="type"> /// Frame type. /// </param> ///<returns> ///Acknowledgment message as byte array. ///</returns> internal static byte[] ReceiverReady(GXDLMSSettings settings, RequestTypes type) { if (type == RequestTypes.None) { throw new ArgumentException("Invalid receiverReady RequestTypes parameter."); } // Get next frame. if ((type & RequestTypes.Frame) != 0) { byte id = settings.ReceiverReady(); return GetHdlcFrame(settings, id, null); } Command cmd; if (settings.UseLogicalNameReferencing) { if (settings.IsServer) { cmd = Command.GetResponse; } else { cmd = Command.GetRequest; } } else { if (settings.IsServer) { cmd = Command.ReadResponse; } else { cmd = Command.ReadRequest; } } // Get next block. GXByteBuffer bb = new GXByteBuffer(6); if (settings.UseLogicalNameReferencing) { bb.SetUInt32(settings.BlockIndex); } else { bb.SetUInt16((UInt16)settings.BlockIndex); } settings.IncreaseBlockIndex(); byte[][] reply; if (settings.UseLogicalNameReferencing) { GXDLMSLNParameters p = new GXDLMSLNParameters(settings, cmd, (byte)GetCommandType.NextDataBlock, bb, null, 0xff); reply = GXDLMS.GetLnMessages(p); } else { GXDLMSSNParameters p = new GXDLMSSNParameters(settings, cmd, 1, (byte)VariableAccessSpecification.BlockNumberAccess, bb, null); reply = GXDLMS.GetSnMessages(p); } return reply[0]; }