static byte GetHdlcData(bool server, GXDLMSSettings settings, GXByteBuffer reply, GXReplyData data) { short ch; int pos, packetStartID = reply.Position, frameLen = 0; int crc, crcRead; // If whole frame is not received yet. if (reply.Size - reply.Position < 9) { data.IsComplete = false; return 0; } data.IsComplete = true; // Find start of HDLC frame. for (pos = reply.Position; pos < reply.Size; ++pos) { ch = reply.GetUInt8(); if (ch == GXCommon.HDLCFrameStartEnd) { packetStartID = pos; break; } } // Not a HDLC frame. // Sometimes meters can send some strange data between DLMS frames. if (reply.Position == reply.Size) { data.IsComplete = false; // Not enough data to parse; return 0; } byte frame = reply.GetUInt8(); if ((frame & 0xF0) != 0xA0) { //If same strage data. return GetHdlcData(server, settings, reply, data); } // Check frame length. if ((frame & 0x7) != 0) { frameLen = ((frame & 0x7) << 8); } ch = reply.GetUInt8(); // If not enough data. frameLen += ch; if (reply.Size - reply.Position + 1 < frameLen) { data.IsComplete = false; reply.Position = packetStartID; // Not enough data to parse; return 0; } int eopPos = frameLen + packetStartID + 1; ch = reply.GetUInt8(eopPos); if (ch != GXCommon.HDLCFrameStartEnd) { throw new GXDLMSException("Invalid data format."); } // Check addresses. if (!CheckHdlcAddress(server, settings, reply, eopPos)) { //If echo, reply.Position = 1 + eopPos; return GetHdlcData(server, settings, reply, data); } // Is there more data available. if ((frame & 0x8) != 0) { data.MoreData = (RequestTypes)(data.MoreData | RequestTypes.Frame); } else { data.MoreData = (RequestTypes)(data.MoreData & ~RequestTypes.Frame); } // Get frame type. frame = reply.GetUInt8(); if (data.Xml == null && !settings.CheckFrame(frame)) { reply.Position = (eopPos + 1); return GetHdlcData(server, settings, reply, data); } // Check that header CRC is correct. crc = GXFCS16.CountFCS16(reply.Data, packetStartID + 1, reply.Position - packetStartID - 1); crcRead = reply.GetUInt16(); if (crc != crcRead) { throw new Exception("Wrong CRC."); } // Check that packet CRC match only if there is a data part. if (reply.Position != packetStartID + frameLen + 1) { crc = GXFCS16.CountFCS16(reply.Data, packetStartID + 1, frameLen - 2); crcRead = reply.GetUInt16(packetStartID + frameLen - 1); if (crc != crcRead) { throw new Exception("Wrong CRC."); } // Remove CRC and EOP from packet length. data.PacketLength = eopPos - 2; } else { data.PacketLength = reply.Position + 1; } if ((frame & (byte)HdlcFrameType.Uframe) == (byte)HdlcFrameType.Uframe) { //Get Eop if there is no data. if (reply.Position == packetStartID + frameLen + 1) { // Get EOP. reply.GetUInt8(); } data.Command = (Command)frame; } //If S-frame else if ((frame & (byte)HdlcFrameType.Sframe) == (byte)HdlcFrameType.Sframe) { //If frame is rejected. int tmp = (frame >> 2) & 0x3; if (tmp == (byte)HdlcControlFrame.Reject) { data.Error = (int)ErrorCode.Rejected; } else if (tmp == (byte)HdlcControlFrame.ReceiveNotReady) { data.Error = (int)ErrorCode.Rejected; } else if (tmp == (byte)HdlcControlFrame.ReceiveReady) { System.Diagnostics.Debug.WriteLine("Get next frame."); } //Get Eop if there is no data. if (reply.Position == packetStartID + frameLen + 1) { // Get EOP. reply.GetUInt8(); } } else //Iframe { //Get Eop if there is no data. if (reply.Position == packetStartID + frameLen + 1) { // Get EOP. reply.GetUInt8(); if ((frame & 0x1) == 0x1) { data.MoreData = RequestTypes.Frame; } } else { if (!GetLLCBytes(server, reply) && data.Xml != null) { GetLLCBytes(!server, reply); } } } return frame; }