/// <summary> /// Get all Short Name messages. Client uses this to generate messages. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="command">DLMS command.</param> /// <param name="count">Attribute descriptor.</param> /// <param name="data">Data.</param> /// <returns>Generated messages.</returns> internal static byte[][] GetSnMessages(GXDLMSSNParameters p) { GXByteBuffer reply = new GXByteBuffer(); List<byte[]> messages = new List<byte[]>(); byte frame = 0x0; if (p.command == Command.Aarq) { frame = 0x10; } else if (p.command == Command.None) { frame = p.settings.NextSend(); } do { GetSNPdu(p, reply); if (p.command != Command.Aarq && p.command != Command.Aare) { System.Diagnostics.Debug.Assert(!(p.settings.MaxPduSize < reply.Size)); } //Command is not add to next PDUs. while (reply.Position != reply.Size) { if (p.settings.InterfaceType == Enums.InterfaceType.WRAPPER) { messages.Add(GXDLMS.GetWrapperFrame(p.settings, reply)); } else if (p.settings.InterfaceType == Enums.InterfaceType.HDLC) { messages.Add(GXDLMS.GetHdlcFrame(p.settings, frame, reply)); frame = 0; } else if (p.settings.InterfaceType == Enums.InterfaceType.PDU) { messages.Add(reply.Array()); frame = 0; break; } else { throw new ArgumentOutOfRangeException("InterfaceType"); } } reply.Clear(); } while (p.data != null && p.data.Position != p.data.Size); return messages.ToArray(); }
/// <summary> /// Get data from Block. /// </summary> /// <param name="data">Stored data block.</param> /// <param name="index">Position where data starts.</param> /// <returns>Amount of removed bytes.</returns> private static int GetDataFromBlock(GXByteBuffer data, int index) { if (data.Size == data.Position) { data.Clear(); return 0; } int len = data.Position - index; System.Buffer.BlockCopy(data.Data, data.Position, data.Data, data.Position - len, data.Size - data.Position); data.Position = (data.Position - len); data.Size = (data.Size - len); return len; }
/// <summary> /// Get all Logical name messages. Client uses this to generate messages. /// </summary> /// <param name="p">LN settings.</param> /// <returns>Generated messages.</returns> internal static byte[][] GetLnMessages(GXDLMSLNParameters p) { GXByteBuffer reply = new GXByteBuffer(); List<byte[]> messages = new List<byte[]>(); byte frame = 0; if (p.command == Command.Aarq) { frame = 0x10; } do { GetLNPdu(p, reply); p.lastBlock = true; if (p.attributeDescriptor == null) { ++p.settings.BlockIndex; } if (p.command == Command.Aarq && p.command == Command.GetRequest) { System.Diagnostics.Debug.Assert(!(p.settings.MaxPduSize < reply.Size)); } while (reply.Position != reply.Size) { if (p.settings.InterfaceType == Enums.InterfaceType.WRAPPER) { messages.Add(GXDLMS.GetWrapperFrame(p.settings, reply)); } else if (p.settings.InterfaceType == Enums.InterfaceType.HDLC) { messages.Add(GXDLMS.GetHdlcFrame(p.settings, frame, reply)); frame = 0; } else if (p.settings.InterfaceType == Enums.InterfaceType.PDU) { messages.Add(reply.Array()); frame = 0; break; } else { throw new ArgumentOutOfRangeException("InterfaceType"); } } reply.Clear(); } while (p.data != null && p.data.Position != p.data.Size); return messages.ToArray(); }
public static bool GetData(GXDLMSSettings settings, GXByteBuffer reply, GXReplyData data) { byte frame = 0; // If DLMS frame is generated. if (settings.InterfaceType == InterfaceType.HDLC) { frame = GetHdlcData(settings.IsServer, settings, reply, data); data.FrameId = frame; } else if (settings.InterfaceType == InterfaceType.WRAPPER) { GetTcpData(settings, reply, data); } else if (settings.InterfaceType == InterfaceType.PDU) { data.PacketLength = reply.Size; data.IsComplete = true; } else { throw new ArgumentException("Invalid Interface type."); } // If all data is not read yet. if (!data.IsComplete) { return false; } GetDataFromFrame(reply, data); // If keepalive or get next frame request. if (data.Xml != null || (frame & 0x1) != 0) { if (settings.InterfaceType == InterfaceType.HDLC && data.Data.Size != 0) { reply.Position += 3; System.Diagnostics.Debug.Assert(reply.GetUInt8(reply.Position - 1) == 0x7e); } return true; } GetPdu(settings, data); if (data.Command == Command.DataNotification) { // Check is there more messages left. // This is Push message special case. if (reply.Position == reply.Size) { reply.Clear(); } else { int cnt = reply.Size - reply.Position; reply.Move(reply.Position, 0, cnt); reply.Position = 0; } } return true; }
/// <summary> /// Get HDLC frame for data. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="frame">Frame ID. If zero new is generated.</param> /// <param name="data">Data to add.</param> /// <returns>HDLC frames.</returns> internal static byte[] GetHdlcFrame(GXDLMSSettings settings, byte frame, GXByteBuffer data) { GXByteBuffer bb = new GXByteBuffer(); int frameSize, len = 0; byte[] primaryAddress, secondaryAddress; if (settings.IsServer) { primaryAddress = GetHdlcAddressBytes(settings.ClientAddress, 0); secondaryAddress = GetHdlcAddressBytes(settings.ServerAddress, settings.ServerAddressSize); } else { primaryAddress = GetHdlcAddressBytes(settings.ServerAddress, settings.ServerAddressSize); secondaryAddress = GetHdlcAddressBytes(settings.ClientAddress, 0); } // Add BOP bb.SetUInt8(GXCommon.HDLCFrameStartEnd); frameSize = Convert.ToInt32(settings.Limits.MaxInfoTX); // If no data if (data == null || data.Size == 0) { bb.SetUInt8(0xA0); } else if (data.Size - data.Position <= frameSize) { // Is last packet. bb.SetUInt8(0xA0); len = data.Size - data.Position; } else { // More data to left. bb.SetUInt8(0xA8); len = frameSize; } //Frame len. if (len == 0) { bb.SetUInt8((byte)(5 + primaryAddress.Length + secondaryAddress.Length + len)); } else { bb.SetUInt8((byte)(7 + primaryAddress.Length + secondaryAddress.Length + len)); } // Add primary address. bb.Set(primaryAddress); // Add secondary address. bb.Set(secondaryAddress); //Add frame ID. if (frame == 0) { frame = settings.NextSend(); } bb.SetUInt8(frame); // Add header CRC. UInt16 crc = GXFCS16.CountFCS16(bb.Data, 1, bb.Size - 1); bb.SetUInt16(crc); if (len != 0) { //Add data. bb.Set(data, len); // Add data CRC. crc = GXFCS16.CountFCS16(bb.Data, 1, bb.Size - 1); bb.SetUInt16(crc); } // Add EOP bb.SetUInt8(GXCommon.HDLCFrameStartEnd); if (data != null) { //Remove sent data in server side. if (settings.IsServer) { if (data.Size == data.Position) { data.Clear(); } else { data.Move(data.Position, 0, data.Size - data.Position); data.Position = 0; } } } return bb.Array(); }
/// <summary> /// Split DLMS PDU to wrapper frames. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="data"> Wrapped data.</param> /// <returns>Wrapper frames</returns> internal static byte[] GetWrapperFrame(GXDLMSSettings settings, GXByteBuffer data) { GXByteBuffer bb = new GXByteBuffer(); // Add version. bb.SetUInt16(1); if (settings.IsServer) { bb.SetUInt16((UInt16)settings.ServerAddress); bb.SetUInt16((UInt16)settings.ClientAddress); } else { bb.SetUInt16((UInt16)settings.ClientAddress); bb.SetUInt16((UInt16)settings.ServerAddress); } if (data == null) { // Data length. bb.SetUInt16(0); } else { // Data length. bb.SetUInt16((UInt16)data.Size); // Data bb.Set(data); } //Remove sent data in server side. if (settings.IsServer) { if (data.Size == data.Position) { data.Clear(); } else { data.Move(data.Position, 0, data.Size - data.Position); data.Position = 0; } } return bb.Array(); }
/// <summary> /// Handle read request. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="server">DLMS server.</param> /// <param name="data">Received data.</param> public static void HandleReadRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { GXByteBuffer bb = new GXByteBuffer(); int cnt = 0xFF; byte type = 0; List<ValueEventArgs> list = new List<ValueEventArgs>(); //If get next frame. if (xml == null && data.Size == 0) { if (server.transaction != null) { return; } bb.Set(replyData); replyData.Clear(); foreach (ValueEventArgs it in server.transaction.targets) { list.Add(it); } } else { cnt = GXCommon.GetObjectCount(data); List<ValueEventArgs> reads = new List<ValueEventArgs>(); List<ValueEventArgs> actions = new List<ValueEventArgs>(); if (xml != null) { xml.AppendStartTag(Command.ReadRequest, "Qty", xml.IntegerToHex(cnt, 2)); } for (int pos = 0; pos != cnt; ++pos) { type = data.GetUInt8(); if (type == (byte)VariableAccessSpecification.VariableName || type == (byte)VariableAccessSpecification.ParameterisedAccess) { HandleRead(settings, server, type, data, list, reads, actions, replyData, xml); } else if (type == (byte)VariableAccessSpecification.BlockNumberAccess) { HandleReadBlockNumberAccess(settings, server, data, replyData, xml); if (xml != null) { xml.AppendEndTag(Command.ReadRequest); } return; } else if (type == (byte)VariableAccessSpecification.ReadDataBlockAccess) { HandleReadDataBlockAccess(settings, server, Command.ReadResponse, data, cnt, replyData, xml); if (xml != null) { xml.AppendEndTag(Command.ReadRequest); } return; } else { ReturnSNError(settings, server, Command.ReadResponse, ErrorCode.ReadWriteDenied, replyData); if (xml != null) { xml.AppendEndTag(Command.ReadRequest); } return; } } if (reads.Count != 0) { server.NotifyRead(reads.ToArray()); } if (actions.Count != 0) { server.NotifyAction(actions.ToArray()); } } if (xml != null) { xml.AppendEndTag(Command.ReadRequest); return; } byte requestType = (byte)GetReadData(settings, list.ToArray(), bb); GXDLMSSNParameters p = new GXDLMSSNParameters(settings, Command.ReadResponse, list.Count, requestType, null, bb); GXDLMS.GetSNPdu(p, replyData); if (server.transaction == null && (bb.Size != bb.Position || settings.Count != settings.Index)) { List<ValueEventArgs> reads = new List<ValueEventArgs>(); foreach (var it in list) { reads.Add(it); } server.transaction = new GXDLMSLongTransaction(reads.ToArray(), Command.ReadRequest, bb); } else if (server.transaction != null) { replyData.Set(bb); return; } }
/// <summary> /// Find next frame from the string. /// </summary> /// <remarks> /// Position of data is set to the begin of new frame. If Pdu is null it is not updated. /// </remarks> /// <param name="data">Data where frame is search.</param> /// <param name="pdu">Pdu of received frame is set here.</param> /// <returns>Is new frame found.</returns> public bool FindNextFrame(GXByteBuffer data, GXByteBuffer pdu) { GXDLMSSettings settings = new GXDLMSSettings(true); GXReplyData reply = new GXReplyData(); reply.Xml = new GXDLMSTranslatorStructure(OutputType, Hex, ShowStringAsHex, null); int pos; while (data.Position != data.Size) { if (data.GetUInt8(data.Position) == 0x7e) { pos = data.Position; settings.InterfaceType = Enums.InterfaceType.HDLC; GXDLMS.GetData(settings, data, reply); data.Position = pos; break; } else if (data.Position + 2 < data.Size && data.GetUInt16(data.Position) == 0x1) { pos = data.Position; settings.InterfaceType = Enums.InterfaceType.WRAPPER; GXDLMS.GetData(settings, data, reply); data.Position = pos; break; } ++data.Position; } if (pdu != null) { pdu.Clear(); pdu.Set(reply.Data.Data, 0, reply.Data.Size); } return data.Position != data.Size; }