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;
}