private static void HanleSetRequestWithDataBlock(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXDLMSLNParameters p, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { GXDataInfo reply = new GXDataInfo(); reply.xml = xml; byte lastBlock = data.GetUInt8(); p.multipleBlocks = lastBlock == 0; UInt32 blockNumber = data.GetUInt32(); if (xml == null && blockNumber != settings.BlockIndex) { Debug.WriteLine("HanleSetRequestWithDataBlock failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); p.status = (byte)ErrorCode.DataBlockNumberInvalid; } else { settings.IncreaseBlockIndex(); int size = GXCommon.GetObjectCount(data); int realSize = data.Size - data.Position; if (size != realSize) { Debug.WriteLine("HanleSetRequestWithDataBlock failed. Invalid block size."); p.status = (byte)ErrorCode.DataBlockUnavailable; } if (xml != null) { xml.AppendStartTag(TranslatorTags.DataBlock); xml.AppendLine(TranslatorTags.LastBlock, "Value", xml.IntegerToHex(lastBlock, 2)); xml.AppendLine(TranslatorTags.BlockNumber, "Value", xml.IntegerToHex(blockNumber, 8)); xml.AppendLine(TranslatorTags.RawData, "Value", data.RemainingHexString(false)); xml.AppendEndTag(TranslatorTags.DataBlock); return; } server.transaction.data.Set(data); //If all data is received. if (!p.multipleBlocks) { try { object value = GXCommon.GetData(settings, server.transaction.data, reply); if (value is byte[]) { DataType dt = (server.transaction.targets[0].Target as IGXDLMSBase).GetDataType(server.transaction.targets[0].Index); if (dt != DataType.None && dt != DataType.OctetString) { value = GXDLMSClient.ChangeType((byte[])value, dt, settings.UseUtc2NormalTime); } } server.transaction.targets[0].Value = value; server.NotifyWrite(server.transaction.targets); if (!server.transaction.targets[0].Handled && !p.multipleBlocks) { (server.transaction.targets[0].Target as IGXDLMSBase).SetValue(settings, server.transaction.targets[0]); server.NotifyPostWrite(server.transaction.targets); } } catch (Exception) { p.status = (byte)ErrorCode.HardwareFault; } finally { server.transaction = null; } settings.ResetBlockIndex(); } } p.multipleBlocks = true; }
/// <summary> /// Handle get request next data block command. /// </summary> /// <param name="data">Received data.</param> internal static void GetRequestNextDataBlock(GXDLMSSettings settings, byte invokeID, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml, bool streaming) { GXByteBuffer bb = new GXByteBuffer(); if (!streaming) { UInt32 index; // Get block index. index = data.GetUInt32(); if (xml != null) { xml.AppendLine(TranslatorTags.BlockNumber, null, xml.IntegerToHex(index, 8)); return; } if (index != settings.BlockIndex) { Debug.WriteLine("handleGetRequest failed. Invalid block number. " + settings.BlockIndex + "/" + index); GXDLMS.GetLNPdu(new GXDLMSLNParameters(null, settings, 0, Command.GetResponse, 2, null, bb, (byte)ErrorCode.DataBlockNumberInvalid), replyData); return; } } settings.IncreaseBlockIndex(); GXDLMSLNParameters p = new GXDLMSLNParameters(null, settings, invokeID, streaming ? Command.GeneralBlockTransfer : Command.GetResponse, 2, null, bb, (byte)ErrorCode.Ok); p.Streaming = streaming; p.WindowSize = settings.WindowSize; //If transaction is not in progress. if (server.transaction == null) { p.status = (byte)ErrorCode.NoLongGetOrReadInProgress; } else { bb.Set(server.transaction.data); bool moreData = settings.Index != settings.Count; if (moreData) { //If there is multiple blocks on the buffer. //This might happen when Max PDU size is very small. if (bb.Size < settings.MaxPduSize) { foreach (ValueEventArgs arg in server.transaction.targets) { object value; server.NotifyRead(new ValueEventArgs[] { arg }); if (arg.Handled) { value = arg.Value; } else { value = (arg.Target as IGXDLMSBase).GetValue(settings, arg); } //Add data. if (arg.ByteArray) { bb.Set((byte[])value); } else { GXDLMS.AppendData(settings, arg.Target, arg.Index, bb, value); } } moreData = settings.Index != settings.Count; } } p.multipleBlocks = true; GXDLMS.GetLNPdu(p, replyData); if (moreData || bb.Size - bb.Position != 0) { server.transaction.data = bb; } else { server.transaction = null; settings.ResetBlockIndex(); } } }
private static void HandleSetRequestNormal(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, byte type, GXDLMSLNParameters p, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { object value = null; GXDataInfo reply = new GXDataInfo(); // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute index. byte index = data.GetUInt8(); // Get Access Selection. data.GetUInt8(); if (type == 2) { byte lastBlock = data.GetUInt8(); p.multipleBlocks = lastBlock == 0; UInt32 blockNumber = data.GetUInt32(); if (blockNumber != settings.BlockIndex) { Debug.WriteLine("HandleSetRequest failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); p.status = (byte)ErrorCode.DataBlockNumberInvalid; return; } settings.IncreaseBlockIndex(); int size = GXCommon.GetObjectCount(data); int realSize = data.Size - data.Position; if (size != realSize) { Debug.WriteLine("HandleSetRequest failed. Invalid block size."); p.status = (byte)ErrorCode.DataBlockUnavailable; return; } if (xml != null) { AppendAttributeDescriptor(xml, (int)ci, ln, index); xml.AppendStartTag(TranslatorTags.DataBlock); xml.AppendLine(TranslatorTags.LastBlock, "Value", xml.IntegerToHex(lastBlock, 2)); xml.AppendLine(TranslatorTags.BlockNumber, "Value", xml.IntegerToHex(blockNumber, 8)); xml.AppendLine(TranslatorTags.RawData, "Value", data.RemainingHexString(false)); xml.AppendEndTag(TranslatorTags.DataBlock); } return; } if (xml != null) { AppendAttributeDescriptor(xml, (int)ci, ln, index); xml.AppendStartTag(TranslatorTags.Value); GXDataInfo di = new GXDataInfo(); di.xml = xml; value = GXCommon.GetData(settings, data, di); if (!di.Complete) { value = GXCommon.ToHex(data.Data, false, data.Position, data.Size - data.Position); } else if (value is byte[]) { value = GXCommon.ToHex((byte[])value, false); } xml.AppendEndTag(TranslatorTags.Value); return; } if (!p.multipleBlocks) { settings.ResetBlockIndex(); value = GXCommon.GetData(settings, data, reply); } GXDLMSObject obj = settings.Objects.FindByLN(ci, GXCommon.ToLogicalName(ln)); if (obj == null) { obj = server.NotifyFindObject(ci, 0, GXCommon.ToLogicalName(ln)); } // If target is unknown. if (obj == null) { // Device reports a undefined object. p.status = (byte)ErrorCode.UndefinedObject; } else { ValueEventArgs e = new ValueEventArgs(server, obj, index, 0, null); e.InvokeId = p.InvokeId; AccessMode am = server.NotifyGetAttributeAccess(e); // If write is denied. if (am != AccessMode.Write && am != AccessMode.ReadWrite) { //Read Write denied. p.status = (byte)ErrorCode.ReadWriteDenied; } else { try { if (value is byte[]) { DataType dt = (obj as IGXDLMSBase).GetDataType(index); if (dt != DataType.None && dt != DataType.OctetString && dt != DataType.Structure) { value = GXDLMSClient.ChangeType((byte[])value, dt, settings.UseUtc2NormalTime); } } e.Value = value; ValueEventArgs[] list = new ValueEventArgs[] { e }; if (p.multipleBlocks) { server.transaction = new GXDLMSLongTransaction(list, Command.GetRequest, data); } server.NotifyWrite(list); if (e.Error != 0) { p.status = (byte)e.Error; } else if (!e.Handled && !p.multipleBlocks) { (obj as IGXDLMSBase).SetValue(settings, e); server.NotifyPostWrite(list); if (e.Error != 0) { p.status = (byte)e.Error; } } p.InvokeId = e.InvokeId; } catch (Exception) { p.status = (byte)ErrorCode.HardwareFault; } } } }
/// <summary> /// Handle read Block in blocks. /// </summary> /// <param name="data">Received data.</param> private static void HandleReadBlockNumberAccess(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { UInt16 blockNumber = data.GetUInt16(); if (xml != null) { xml.AppendStartTag(Command.ReadRequest, VariableAccessSpecification.BlockNumberAccess); xml.AppendLine("<BlockNumber Value=\"" + xml.IntegerToHex(blockNumber, 4) + "\" />"); xml.AppendEndTag(Command.ReadRequest, VariableAccessSpecification.BlockNumberAccess); return; } if (blockNumber != settings.BlockIndex) { GXByteBuffer bb = new GXByteBuffer(); Debug.WriteLine("handleReadRequest failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); bb.SetUInt8(ErrorCode.DataBlockNumberInvalid); GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, Command.ReadResponse, 1, (byte)SingleReadResponse.DataAccessError, bb, null), replyData); settings.ResetBlockIndex(); return; } if (settings.Index != settings.Count && server.transaction.data.Size < settings.MaxPduSize) { List <ValueEventArgs> reads = new List <ValueEventArgs>(); List <ValueEventArgs> actions = new List <ValueEventArgs>(); foreach (ValueEventArgs it in server.transaction.targets) { if (it.action) { actions.Add(it); } else { reads.Add(it); } } if (reads.Count != 0) { server.NotifyRead(reads.ToArray()); } if (actions.Count != 0) { server.NotifyAction(actions.ToArray()); } GetReadData(settings, server.transaction.targets, server.transaction.data); if (reads.Count != 0) { server.NotifyPostRead(reads.ToArray()); } if (actions.Count != 0) { server.NotifyPostAction(actions.ToArray()); } } settings.IncreaseBlockIndex(); GXDLMSSNParameters p = new GXDLMSSNParameters(settings, Command.ReadResponse, 1, (byte)SingleReadResponse.DataBlockResult, null, server.transaction.data); p.multipleBlocks = true; GXDLMS.GetSNPdu(p, replyData); //If all data is sent. if (server.transaction.data.Size == server.transaction.data.Position) { server.transaction = null; settings.ResetBlockIndex(); } else { server.transaction.data.Trim(); } }
private static void HandleReadDataBlockAccess( GXDLMSSettings settings, GXDLMSServer server, Command command, GXByteBuffer data, int cnt, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { GXByteBuffer bb = new GXByteBuffer(); byte lastBlock = data.GetUInt8(); UInt16 blockNumber = data.GetUInt16(); if (xml != null) { if (command == Command.WriteResponse) { xml.AppendStartTag(TranslatorTags.WriteDataBlockAccess); } else { xml.AppendStartTag(TranslatorTags.ReadDataBlockAccess); } xml.AppendLine("<LastBlock Value=\"" + xml.IntegerToHex(lastBlock, 2) + "\" />"); xml.AppendLine("<BlockNumber Value=\"" + xml.IntegerToHex(blockNumber, 4) + "\" />"); if (command == Command.WriteResponse) { xml.AppendEndTag(TranslatorTags.WriteDataBlockAccess); } else { xml.AppendEndTag(TranslatorTags.ReadDataBlockAccess); } return; } if (blockNumber != settings.BlockIndex) { Debug.WriteLine("handleReadRequest failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); bb.SetUInt8(ErrorCode.DataBlockNumberInvalid); GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, command, 1, (byte)SingleReadResponse.DataAccessError, bb, null), replyData); settings.ResetBlockIndex(); return; } int count = 1; byte type = (byte)DataType.OctetString; if (command == Command.WriteResponse) { count = GXCommon.GetObjectCount(data); type = data.GetUInt8(); } int size = GXCommon.GetObjectCount(data); int realSize = data.Size - data.Position; if (count != 1 || type != (byte)DataType.OctetString || size != realSize) { Debug.WriteLine("handleGetRequest failed. Invalid block size."); bb.SetUInt8(ErrorCode.DataBlockUnavailable); GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, command, cnt, (byte)SingleReadResponse.DataAccessError, bb, null), replyData); settings.ResetBlockIndex(); return; } if (server.transaction == null) { server.transaction = new GXDLMSLongTransaction(null, command, data); } else { server.transaction.data.Set(data); } if (lastBlock == 0) { bb.SetUInt16(blockNumber); settings.IncreaseBlockIndex(); if (command == Command.ReadResponse) { type = (byte)SingleReadResponse.BlockNumber; } else { type = (byte)SingleWriteResponse.BlockNumber; } GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, command, cnt, type, null, bb), replyData); return; } else { if (server.transaction != null) { data.Size = 0; data.Set(server.transaction.data); server.transaction = null; } if (command == Command.ReadResponse) { HandleReadRequest(settings, server, data, replyData, xml); } else { HandleWriteRequest(settings, server, data, replyData, xml); } settings.ResetBlockIndex(); } }
private static void HandleSetRequestNormal(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, byte type, GXDLMSLNParameters p, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { object value = null; GXDataInfo reply = new GXDataInfo(); // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute index. byte index = data.GetUInt8(); // Get Access Selection. data.GetUInt8(); if (xml != null) { AppendAttributeDescriptor(xml, (int)ci, ln, index); xml.AppendStartTag(TranslatorTags.Value); GXDataInfo di = new GXDataInfo(); di.xml = xml; value = GXCommon.GetData(settings, data, di); if (!di.Complete) { value = GXCommon.ToHex(data.Data, false, data.Position, data.Size - data.Position); } else if (value is byte[]) { value = GXCommon.ToHex((byte[])value, false); } xml.AppendEndTag(TranslatorTags.Value); return; } if (type == 2) { p.multipleBlocks = data.GetUInt8() == 0; UInt32 blockNumber = data.GetUInt32(); if (blockNumber != settings.BlockIndex) { Debug.WriteLine("HandleSetRequest failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); p.status = (byte)ErrorCode.DataBlockNumberInvalid; return; } settings.IncreaseBlockIndex(); int size = GXCommon.GetObjectCount(data); int realSize = data.Size - data.Position; if (size != realSize) { Debug.WriteLine("HandleSetRequest failed. Invalid block size."); p.status = (byte)ErrorCode.DataBlockUnavailable; return; } } if (!p.multipleBlocks) { settings.ResetBlockIndex(); value = GXCommon.GetData(settings, data, reply); } GXDLMSObject obj = settings.Objects.FindByLN(ci, GXDLMSObject.ToLogicalName(ln)); if (obj == null) { obj = server.NotifyFindObject(ci, 0, GXDLMSObject.ToLogicalName(ln)); } // If target is unknown. if (obj == null) { // Device reports a undefined object. p.status = (byte)ErrorCode.UndefinedObject; } else { AccessMode am = obj.GetAccess(index); // If write is denied. if (am != AccessMode.Write && am != AccessMode.ReadWrite) { //Read Write denied. p.status = (byte)ErrorCode.ReadWriteDenied; } else { try { if (value is byte[]) { DataType dt = (obj as IGXDLMSBase).GetDataType(index); if (dt != DataType.None && dt != DataType.OctetString) { value = GXDLMSClient.ChangeType((byte[])value, dt); } } ValueEventArgs e = new ValueEventArgs(settings, obj, index, 0, null); e.Value = value; ValueEventArgs[] list = new ValueEventArgs[] { e }; if (p.multipleBlocks) { server.transaction = new GXDLMSLongTransaction(list, Command.GetRequest, data); } server.NotifyWrite(list); if (e.Error != 0) { p.status = (byte)e.Error; } else if (!e.Handled && !p.multipleBlocks) { (obj as IGXDLMSBase).SetValue(settings, e); } } catch (Exception) { p.status = (byte)ErrorCode.HardwareFault; } } } }
private byte[][] HandleGetRequest() { ErrorCode error = ErrorCode.Ok; GXByteBuffer data = Reply.Data; GXByteBuffer bb = new GXByteBuffer(); short type; int index = 0; object parameters = null; // Get type. type = data.GetUInt8(); // Get invoke ID and priority. data.GetUInt8(); // GetRequest normal if (type == 1) { Settings.ResetBlockIndex(); ServerReply.Index = 0; parameters = null; // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute Id int attributeIndex = data.GetUInt8(); GXDLMSObject obj = Settings.Objects.FindByLN(ci, GXDLMSObject.ToLogicalName(ln)); if (obj == null) { obj = FindObject(ci, 0, GXDLMSObject.ToLogicalName(ln)); } if (obj == null) { // "Access Error : Device reports a undefined object." error = ErrorCode.UndefinedObject; } else { // AccessSelection int selection = data.GetUInt8(); int selector = 0; if (selection != 0) { selector = data.GetUInt8(); GXDataInfo info = new GXDataInfo(); parameters = GXCommon.GetData(data, info); } ValueEventArgs e = new ValueEventArgs(obj, attributeIndex, 0, parameters); Read(e); object value; if (e.Handled) { value = e.Value; } else { value = (obj as IGXDLMSBase).GetValue(Settings, attributeIndex, selector, parameters); } GXDLMS.AppedData(obj, attributeIndex, bb, value); } ServerReply.ReplyMessages = GXDLMS.SplitPdu(Settings, Command.GetResponse, 1, bb, error, DateTime.MinValue); } else if (type == 2) { // Get request for next data block // Get block index. index = (int)data.GetUInt32(); if (index != Settings.BlockIndex + 1) { Debug.WriteLine("handleGetRequest failed. Invalid block number. " + Settings.BlockIndex + "/" + index); ServerReply.ReplyMessages = GXDLMS.SplitPdu(Settings, Command.GetResponse, 1, bb, ErrorCode.DataBlockNumberInvalid, DateTime.MinValue); index = 0; ServerReply.Index = index; } else { Settings.IncreaseBlockIndex(); index = ServerReply.Index + 1; ServerReply.Index = index; } } else if (type == 3) { // Get request with a list. int cnt = GXCommon.GetObjectCount(data); GXCommon.SetObjectCount(cnt, bb); for (int pos = 0; pos != cnt; ++pos) { ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); short attributeIndex = data.GetUInt8(); GXDLMSObject obj = Settings.Objects.FindByLN(ci, GXDLMSObject.ToLogicalName(ln)); if (obj == null) { obj = FindObject(ci, 0, GXDLMSObject.ToLogicalName(ln)); } if (obj == null) { // "Access Error : Device reports a undefined object." error = ErrorCode.UndefinedObject; } else { // AccessSelection int selection = data.GetUInt8(); int selector = 0; if (selection != 0) { selector = data.GetUInt8(); GXDataInfo info = new GXDataInfo(); parameters = GXCommon.GetData(data, info); } try { ValueEventArgs e = new ValueEventArgs(obj, attributeIndex, 0, parameters); Read(e); object value; if (e.Handled) { value = e.Value; } else { value = (obj as IGXDLMSBase).GetValue(Settings, attributeIndex, selector, parameters); } bb.SetUInt8(ErrorCode.Ok); GXDLMS.AppedData(obj, attributeIndex, bb, value); } catch (Exception) { bb.SetUInt8(1); bb.SetUInt8(ErrorCode.HardwareFault); } } } ServerReply.ReplyMessages = GXDLMS.SplitPdu(Settings, Command.GetResponse, 3, bb, error, DateTime.MinValue); } else { Debug.WriteLine("handleGetRequest failed. Invalid command type."); Settings.ResetBlockIndex(); // Access Error : Device reports a hardware fault. ServerReply.ReplyMessages = GXDLMS.SplitPdu(Settings, Command.GetResponse, 1, bb, ErrorCode.HardwareFault, DateTime.MinValue); } ServerReply.Index = index; return(ServerReply.ReplyMessages[index]); }
/// <summary> /// Handle get request next data block command. /// </summary> /// <param name="data">Received data.</param> private static void GetRequestNextDataBlock(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { GXByteBuffer bb = new GXByteBuffer(); UInt32 index; // Get block index. index = data.GetUInt32(); if (xml != null) { xml.AppendLine(TranslatorTags.BlockNumber, null, xml.IntegerToHex(index, 8)); return; } if (index != settings.BlockIndex) { Debug.WriteLine("handleGetRequest failed. Invalid block number. " + settings.BlockIndex + "/" + index); GXDLMS.GetLNPdu(new GXDLMSLNParameters(settings, Command.GetResponse, 2, null, bb, (byte)ErrorCode.DataBlockNumberInvalid), replyData); } else { settings.IncreaseBlockIndex(); GXDLMSLNParameters p = new GXDLMSLNParameters(settings, Command.GetResponse, 2, null, bb, (byte)ErrorCode.Ok); //If transaction is not in progress. if (server.transaction == null) { p.status = (byte)ErrorCode.NoLongGetOrReadInProgress; } else { bb.Set(server.transaction.data); bool moreData = settings.Index != settings.Count; if (moreData) { //If there is multiple blocks on the buffer. //This might happen when Max PDU size is very small. if (bb.Size < settings.MaxPduSize) { foreach (ValueEventArgs arg in server.transaction.targets) { object value; if (arg.Handled) { server.NotifyRead(new ValueEventArgs[] { arg }); value = arg.Value; } else { value = (arg.Target as IGXDLMSBase).GetValue(settings, arg); } //Add data. GXDLMS.AppendData(settings, arg.Target, arg.Index, bb, value); } moreData = settings.Index != settings.Count; } } p.multipleBlocks = true; GXDLMS.GetLNPdu(p, replyData); if (moreData || bb.Size - bb.Position != 0) { server.transaction.data = bb; } else { server.transaction = null; } } } }
///<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]; }
/// <summary> /// Handle read response and get data from block and/or update error status. /// </summary> /// <param name="reply">Received data from the client.</param> static bool HandleReadResponse(GXDLMSSettings settings, GXReplyData reply, int index) { int cnt = GXCommon.GetObjectCount(reply.Data); //Set total count if not set yet. if (reply.TotalCount == 0) { reply.TotalCount = cnt; } SingleReadResponse type = SingleReadResponse.Data; List<object> values = null; if (cnt != 1) { values = new List<object>(); } if (reply.Xml != null) { reply.Xml.AppendStartTag(Command.ReadResponse, "Qty", reply.Xml.IntegerToHex(cnt, 2)); } for (int pos = 0; pos != cnt; ++pos) { //Some meters are returning wrong count. if (reply.Xml != null && reply.Data.Position == reply.Data.Size) { } else { // Get status code. if (reply.Data.Position == reply.ReadPosition) { reply.TotalCount = 0; reply.Data.Position = index; GetDataFromBlock(reply.Data, 0); reply.Value = null; //Ask that data is parsed after last block is received. reply.CommandType = (byte)SingleReadResponse.DataBlockResult; return false; } reply.CommandType = reply.Data.GetUInt8(); type = (SingleReadResponse)reply.CommandType; } switch (type) { case SingleReadResponse.Data: reply.Error = 0; if (reply.Xml != null) { if (reply.Xml.OutputType == TranslatorOutputType.StandardXml) { reply.Xml.AppendStartTag(TranslatorTags.Choice); } reply.Xml.AppendStartTag(Command.ReadResponse, SingleReadResponse.Data); GXDataInfo di = new GXDataInfo(); di.xml = reply.Xml; GXCommon.GetData(settings, reply.Data, di); reply.Xml.AppendEndTag(Command.ReadResponse, SingleReadResponse.Data); if (reply.Xml.OutputType == TranslatorOutputType.StandardXml) { reply.Xml.AppendEndTag(TranslatorTags.Choice); } } else if (cnt == 1) { GetDataFromBlock(reply.Data, 0); } else { reply.ReadPosition = reply.Data.Position; GetValueFromData(settings, reply); if (reply.Data.Position == reply.ReadPosition) { //If multiple values remove command. if (cnt != 1 && reply.TotalCount == 0) { ++index; } reply.TotalCount = 0; reply.Data.Position = index; GetDataFromBlock(reply.Data, 0); reply.Value = null; //Ask that data is parsed after last block is received. reply.CommandType = (byte)SingleReadResponse.DataBlockResult; return false; } reply.Data.Position = reply.ReadPosition; values.Add(reply.Value); reply.Value = null; } break; case SingleReadResponse.DataAccessError: // Get error code. reply.Error = reply.Data.GetUInt8(); if (reply.Xml != null) { if (reply.Xml.OutputType == TranslatorOutputType.StandardXml) { reply.Xml.AppendStartTag(TranslatorTags.Choice); } reply.Xml.AppendLine( (int)Command.ReadResponse << 8 | (int)SingleReadResponse.DataAccessError, null, GXDLMSTranslator.ErrorCodeToString( reply.Xml.OutputType, (ErrorCode)reply.Error)); if (reply.Xml.OutputType == TranslatorOutputType.StandardXml) { reply.Xml.AppendEndTag(TranslatorTags.Choice); } //reply.Xml.AppendLine("<" + SingleReadResponse.DataAccessError.ToString() + " Value=\"" + ((ErrorCode)reply.Error).ToString() + "\" />"); } break; case SingleReadResponse.DataBlockResult: if (!ReadResponseDataBlockResult(settings, reply, index)) { //If xml only received bytes are shown. Data is not try to parse. if (reply.Xml != null) { reply.Xml.AppendEndTag(Command.ReadResponse); } return false; } break; case SingleReadResponse.BlockNumber: // Get Block number. UInt32 number = reply.Data.GetUInt16(); if (number != settings.BlockIndex) { throw new ArgumentException( "Invalid Block number. It is " + number + " and it should be " + settings.BlockIndex + "."); } settings.IncreaseBlockIndex(); reply.MoreData = (RequestTypes)(reply.MoreData | RequestTypes.DataBlock); break; default: throw new GXDLMSException("HandleReadResponse failed. Invalid tag."); } } if (reply.Xml != null) { reply.Xml.AppendEndTag(Command.ReadResponse); return true; } if (values != null) { reply.Value = values.ToArray(); } return cnt == 1; }
/// <summary> /// Handle read Block in blocks. /// </summary> /// <param name="data">Received data.</param> private static void HandleReadBlockNumberAccess(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { UInt16 blockNumber = data.GetUInt16(); if (xml != null) { xml.AppendStartTag(Command.ReadRequest, VariableAccessSpecification.BlockNumberAccess); xml.AppendLine("<BlockNumber Value=\"" + xml.IntegerToHex(blockNumber, 4) + "\" />"); xml.AppendEndTag(Command.ReadRequest, VariableAccessSpecification.BlockNumberAccess); return; } if (blockNumber != settings.BlockIndex) { GXByteBuffer bb = new GXByteBuffer(); Debug.WriteLine("handleReadRequest failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); bb.SetUInt8(ErrorCode.DataBlockNumberInvalid); GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, Command.ReadResponse, 1, (byte)SingleReadResponse.DataAccessError, bb, null), replyData); settings.ResetBlockIndex(); return; } if (settings.Index != settings.Count && server.transaction.data.Size < settings.MaxPduSize) { List<ValueEventArgs> reads = new List<ValueEventArgs>(); List<ValueEventArgs> actions = new List<ValueEventArgs>(); foreach (ValueEventArgs it in server.transaction.targets) { if (it.action) { actions.Add(it); } else { reads.Add(it); } } if (reads.Count != 0) { server.NotifyRead(reads.ToArray()); } if (actions.Count != 0) { server.NotifyAction(actions.ToArray()); } GetReadData(settings, server.transaction.targets, server.transaction.data); } settings.IncreaseBlockIndex(); GXDLMSSNParameters p = new GXDLMSSNParameters(settings, Command.ReadResponse, 1, (byte)SingleReadResponse.DataBlockResult, null, server.transaction.data); p.multipleBlocks = true; GXDLMS.GetSNPdu(p, replyData); //If all data is sent. if (server.transaction.data.Size == server.transaction.data.Position) { server.transaction = null; settings.ResetBlockIndex(); } else { server.transaction.data.Trim(); } }