private static void ReturnSNError(GXDLMSSettings settings, GXDLMSServer server, Command cmd, ErrorCode error, GXByteBuffer replyData) { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt8(error); GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, cmd, 1, (byte)SingleReadResponse.DataAccessError, bb, null), replyData); settings.ResetBlockIndex(); }
private static void HanleSetRequestWithDataBlock(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXDLMSLNParameters p, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { GXDataInfo reply = new GXDataInfo(); p.multipleBlocks = data.GetUInt8() == 0; UInt32 blockNumber = data.GetUInt32(); if (blockNumber != settings.BlockIndex) { Debug.WriteLine("HanleSetRequestWithDataBlock failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); p.status = (byte)ErrorCode.DataBlockNumberInvalid; } else { 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; } 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; }
public static void HandleGetRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { //Return error if connection is not established. if (xml == null && settings.Connected == ConnectionState.None && !settings.CanAccess()) { replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } byte invokeID = 0; GetCommandType type = GetCommandType.NextDataBlock; //If GBT is used data is empty. if (data.Size != 0) { type = (GetCommandType)data.GetUInt8(); // Get invoke ID and priority. invokeID = data.GetUInt8(); settings.UpdateInvokeId(invokeID); if (xml != null) { xml.AppendStartTag(Command.GetRequest); xml.AppendStartTag(Command.GetRequest, type); xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invokeID, 2)); } } // GetRequest normal if (type == GetCommandType.Normal) { GetRequestNormal(settings, invokeID, server, data, replyData, xml); } else if (type == GetCommandType.NextDataBlock) { // Get request for next data block GetRequestNextDataBlock(settings, invokeID, server, data, replyData, xml, false); } else if (type == GetCommandType.WithList) { // Get request with a list. GetRequestWithList(settings, invokeID, server, data, replyData, xml); } else { Debug.WriteLine("HandleGetRequest failed. Invalid command type."); settings.ResetBlockIndex(); GXByteBuffer bb = new GXByteBuffer(); // Access Error : Device reports a hardware fault. bb.SetUInt8((byte)ErrorCode.HardwareFault); GXDLMS.GetLNPdu(new GXDLMSLNParameters(null, settings, invokeID, Command.GetResponse, (byte)type, null, bb, (byte)ErrorCode.Ok), replyData); } if (xml != null) { xml.AppendEndTag(Command.GetRequest, type); xml.AppendEndTag(Command.GetRequest); } }
///<summary> ///Handle set request. ///</summary> ///<returns> ///Reply to the client. ///</returns> public static void HandleSetRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { //Return error if connection is not established. if (xml == null && settings.Connected == ConnectionState.None && !settings.CanAccess()) { replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } // Get type. SetRequestType type = (SetRequestType)data.GetUInt8(); // Get invoke ID and priority. byte invoke = data.GetUInt8(); settings.UpdateInvokeId(invoke); // SetRequest normal or Set Request With First Data Block GXDLMSLNParameters p = new GXDLMSLNParameters(null, settings, invoke, Command.SetResponse, (byte)type, null, null, 0); if (xml != null) { xml.AppendStartTag(Command.SetRequest); xml.AppendStartTag(Command.SetRequest, type); //InvokeIdAndPriority xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invoke, 2)); } switch (type) { case SetRequestType.Normal: case SetRequestType.FirstDataBlock: HandleSetRequestNormal(settings, server, data, (byte)type, p, replyData, xml); break; case SetRequestType.WithDataBlock: HanleSetRequestWithDataBlock(settings, server, data, p, replyData, xml); break; case SetRequestType.WithList: HanleSetRequestWithList(settings, invoke, server, data, p, replyData, xml); break; default: System.Diagnostics.Debug.WriteLine("HandleSetRequest failed. Unknown command."); settings.ResetBlockIndex(); p.status = (byte)ErrorCode.HardwareFault; break; } if (xml != null) { xml.AppendEndTag(Command.SetRequest, type); xml.AppendEndTag(Command.SetRequest); return; } GXDLMS.GetLNPdu(p, replyData); }
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(); } }
/// <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(); } }
///<summary> ///Handle set request. ///</summary> ///<returns> ///Reply to the client. ///</returns> private byte[][] HandleSetRequest() { ErrorCode error = ErrorCode.Ok; GXByteBuffer data = Reply.Data; GXDataInfo info = new GXDataInfo(); GXByteBuffer bb = new GXByteBuffer(); // Get type. short type = data.GetUInt8(); // Get invoke ID and priority. data.GetUInt8(); // SetRequest normal if (type == 1) { Settings.ResetBlockIndex(); ServerReply.Index = 0; // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute index. int index = data.GetUInt8(); // Get Access Selection. data.GetUInt8(); object value = GXCommon.GetData(data, info); GXDLMSObject obj = Settings.Objects.FindByLN(ci, GXDLMSObject.ToLogicalName(ln)); if (obj == null) { obj = FindObject(ci, 0, GXDLMSObject.ToLogicalName(ln)); } // If target is unknown. if (obj == null) { Debug.WriteLine("Undefined object."); // Device reports a undefined object. error = ErrorCode.UndefinedObject; } else { AccessMode am = obj.GetAccess(index); // If write is denied. if (am != AccessMode.Write && am != AccessMode.ReadWrite) { Debug.WriteLine("Read Write denied."); error = ErrorCode.ReadWriteDenied; } else { try { if (value is byte[]) { DataType dt = (obj as IGXDLMSBase).GetDataType(index); if (dt != DataType.None) { value = GXDLMSClient.ChangeType((byte[])value, dt); } } ValueEventArgs e = new ValueEventArgs(obj, index, 0, null); Write(e); if (!e.Handled) { (obj as IGXDLMSBase).SetValue(Settings, index, value); } } catch (Exception e) { Debug.WriteLine(e.Message); error = ErrorCode.HardwareFault; } } } } else { Debug.WriteLine("handleSetRequest failed. Unknown command."); Settings.ResetBlockIndex(); error = ErrorCode.HardwareFault; } return(GXDLMS.SplitPdu(Settings, Command.SetResponse, 1, bb, error, DateTime.MinValue)[0]); }
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(); } }
/// <summary> /// Handle get request normal command. /// </summary> /// <param name="data">Received data.</param> private static void GetRequestNormal(GXDLMSSettings settings, byte invokeID, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { ValueEventArgs e = null; GXByteBuffer bb = new GXByteBuffer(); // Get type. ErrorCode status = ErrorCode.Ok; settings.Count = settings.Index = 0; settings.ResetBlockIndex(); // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute Id byte attributeIndex = data.GetUInt8(); // AccessSelection byte selection = data.GetUInt8(); byte selector = 0; object parameters = null; GXDataInfo info = new GXDataInfo(); if (selection != 0) { selector = data.GetUInt8(); } if (xml != null) { AppendAttributeDescriptor(xml, (int)ci, ln, attributeIndex); if (selection != 0) { info.xml = xml; xml.AppendStartTag(TranslatorTags.AccessSelection); xml.AppendLine(TranslatorTags.AccessSelector, "Value", xml.IntegerToHex(selector, 2)); xml.AppendStartTag(TranslatorTags.AccessParameters); GXCommon.GetData(settings, data, info); xml.AppendEndTag(TranslatorTags.AccessParameters); xml.AppendEndTag(TranslatorTags.AccessSelection); } return; } if (selection != 0) { parameters = GXCommon.GetData(settings, data, info); } GXDLMSObject obj = settings.Objects.FindByLN(ci, GXCommon.ToLogicalName(ln)); if (obj == null) { obj = server.NotifyFindObject(ci, 0, GXCommon.ToLogicalName(ln)); } e = new ValueEventArgs(server, obj, attributeIndex, selector, parameters); e.InvokeId = invokeID; if (obj == null) { // "Access Error : Device reports a undefined object." status = ErrorCode.UndefinedObject; } else { if (server.NotifyGetAttributeAccess(e) == AccessMode.NoAccess) { //Read Write denied. status = ErrorCode.ReadWriteDenied; } else { if (e.Target is GXDLMSProfileGeneric && attributeIndex == 2) { e.RowToPdu = GXDLMS.RowsToPdu(settings, (GXDLMSProfileGeneric)e.Target); } object value; server.NotifyRead(new ValueEventArgs[] { e }); if (e.Handled) { value = e.Value; } else { settings.Count = e.RowEndIndex - e.RowBeginIndex; value = (obj as IGXDLMSBase).GetValue(settings, e); } if (e.ByteArray) { bb.Set((byte[])value); } else { GXDLMS.AppendData(settings, obj, attributeIndex, bb, value); } server.NotifyPostRead(new ValueEventArgs[] { e }); status = e.Error; } } GXDLMSLNParameters p = new GXDLMSLNParameters(null, settings, e.InvokeId, Command.GetResponse, 1, null, bb, (byte)status); GXDLMS.GetLNPdu(p, replyData); if (settings.Count != settings.Index || bb.Size != bb.Position) { server.transaction = new GXDLMSLongTransaction(new ValueEventArgs[] { e }, Command.GetRequest, bb); } }
/// <summary> /// Handle get request normal command. /// </summary> /// <param name="data">Received data.</param> private static void GetRequestNormal(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { ValueEventArgs e = null; GXByteBuffer bb = new GXByteBuffer(); // Get type. ErrorCode status = ErrorCode.Ok; settings.Count = settings.Index = 0; settings.ResetBlockIndex(); // CI ObjectType ci = (ObjectType)data.GetUInt16(); byte[] ln = new byte[6]; data.Get(ln); // Attribute Id byte attributeIndex = data.GetUInt8(); // AccessSelection byte selection = data.GetUInt8(); byte selector = 0; object parameters = null; GXDataInfo info = new GXDataInfo(); if (selection != 0) { selector = data.GetUInt8(); } if (xml != null) { AppendAttributeDescriptor(xml, (int)ci, ln, attributeIndex); if (selection != 0) { info.xml = xml; xml.AppendStartTag(TranslatorTags.AccessSelection); xml.AppendLine(TranslatorTags.AccessSelector, "Value", xml.IntegerToHex(selector, 2)); xml.AppendStartTag(TranslatorTags.AccessParameters); GXCommon.GetData(settings, data, info); xml.AppendEndTag(TranslatorTags.AccessParameters); xml.AppendEndTag(TranslatorTags.AccessSelection); } return; } if (selection != 0) { parameters = GXCommon.GetData(settings, data, info); } GXDLMSObject obj = settings.Objects.FindByLN(ci, GXDLMSObject.ToLogicalName(ln)); if (obj == null) { obj = server.NotifyFindObject(ci, 0, GXDLMSObject.ToLogicalName(ln)); } if (obj == null) { // "Access Error : Device reports a undefined object." status = ErrorCode.UndefinedObject; } else { if (obj.GetAccess(attributeIndex) == AccessMode.NoAccess) { //Read Write denied. status = ErrorCode.ReadWriteDenied; } else { e = new ValueEventArgs(settings, obj, attributeIndex, selector, parameters); server.NotifyRead(new ValueEventArgs[] { e }); object value; if (e.Handled) { value = e.Value; } else { value = (obj as IGXDLMSBase).GetValue(settings, e); } GXDLMS.AppendData(settings, obj, attributeIndex, bb, value); status = e.Error; } } GXDLMS.GetLNPdu(new GXDLMSLNParameters(settings, Command.GetResponse, 1, null, bb, (byte)status), replyData); if (settings.Count != settings.Index || bb.Size != bb.Position) { server.transaction = new GXDLMSLongTransaction(new ValueEventArgs[] { e }, Command.GetRequest, bb); } }
///<summary> ///Handle set request. ///</summary> ///<returns> ///Reply to the client. ///</returns> public static void HandleSetRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { //Return error if connection is not established. if (xml == null && !settings.Connected) { replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } // Get type. SetRequestType type = (SetRequestType)data.GetUInt8(); // Get invoke ID and priority. byte invoke = data.GetUInt8(); // SetRequest normal or Set Request With First Data Block GXDLMSLNParameters p = new GXDLMSLNParameters(settings, Command.SetResponse, (byte)type, null, null, 0); if (xml != null) { xml.AppendStartTag(Command.SetRequest); xml.AppendStartTag(Command.SetRequest, type); //InvokeIdAndPriority xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invoke, 2)); } switch (type) { case SetRequestType.Normal: case SetRequestType.FirstDataBlock: HandleSetRequestNormal(settings, server, data, (byte)type, p, replyData, xml); break; case SetRequestType.WithDataBlock: HanleSetRequestWithDataBlock(settings, server, data, p, replyData, xml); break; default: System.Diagnostics.Debug.WriteLine("HandleSetRequest failed. Unknown command."); settings.ResetBlockIndex(); p.status = (byte)ErrorCode.HardwareFault; break; } if (xml != null) { xml.AppendEndTag(Command.SetRequest, type); xml.AppendEndTag(Command.SetRequest); return; } GXDLMS.GetLNPdu(p, replyData); }
/// <summary> /// Get value from the data. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="reply"> Received data.</param> internal static void GetValueFromData(GXDLMSSettings settings, GXReplyData reply) { GXByteBuffer data = reply.Data; GXDataInfo info = new GXDataInfo(); if (reply.Value is Object[]) { info.Type = DataType.Array; info.Count = reply.TotalCount; info.Index = reply.Count; } int index = data.Position; data.Position = reply.ReadPosition; try { Object value = GXCommon.GetData(settings, data, info); if (value != null) { lock (reply) { // If new data. if (!(value is Object[])) { reply.DataType = info.Type; reply.Value = value; reply.TotalCount = 0; reply.ReadPosition = data.Position; } else { if (((Object[])value).Length != 0) { if (reply.Value == null) { reply.Value = value; } else { // Add items to collection. List<Object> list = new List<Object>(); list.AddRange((Object[])reply.Value); list.AddRange((Object[])value); reply.Value = list.ToArray(); } } reply.ReadPosition = data.Position; // Element count. reply.TotalCount = info.Count; } } } else if (info.Complete && reply.Command == Command.DataNotification) { // If last item is null. This is a special case. reply.ReadPosition = data.Position; } } finally { data.Position = index; } // If last data frame of the data block is read. if (reply.Command != Command.DataNotification && info.Complete && reply.MoreData == RequestTypes.None) { // If all blocks are read. settings.ResetBlockIndex(); data.Position = 0; } }
/// <summary> /// Handle get response and get data from block and/or update error status. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="reply">Received data from the client.</param> /// <param name="index">Block index number.</param> static bool HandleGetResponse(GXDLMSSettings settings, GXReplyData reply, int index) { bool ret = true; long number; short ch = 0; GXByteBuffer data = reply.Data; // Get type. GetCommandType type = (GetCommandType)data.GetUInt8(); // Get invoke ID and priority. ch = data.GetUInt8(); if (reply.Xml != null) { reply.Xml.AppendStartTag(Command.GetResponse); reply.Xml.AppendStartTag(Command.GetResponse, type); //InvokeIdAndPriority reply.Xml.AppendLine(TranslatorTags.InvokeId, "Value", reply.Xml.IntegerToHex(ch, 2)); } // Response normal if (type == GetCommandType.Normal) { // Result ch = data.GetUInt8(); if (ch != 0) { reply.Error = data.GetUInt8(); } if (reply.Xml != null) { // Result start tag. reply.Xml.AppendStartTag(TranslatorTags.Result); if (reply.Error != 0) { reply.Xml.AppendLine(TranslatorTags.DataAccessError, "Value", GXDLMSTranslator.ErrorCodeToString( reply.Xml.OutputType, (ErrorCode)reply.Error)); } else { reply.Xml.AppendStartTag(TranslatorTags.Data); GXDataInfo di = new GXDataInfo(); di.xml = reply.Xml; GXCommon.GetData(settings, reply.Data, di); reply.Xml.AppendEndTag(TranslatorTags.Data); } } else { GetDataFromBlock(data, 0); } } else if (type == GetCommandType.NextDataBlock) { // Is Last block. ch = data.GetUInt8(); if (reply.Xml != null) { //Result start tag. reply.Xml.AppendStartTag(TranslatorTags.Result); //LastBlock reply.Xml.AppendLine(TranslatorTags.LastBlock, "Value", reply.Xml.IntegerToHex(ch, 2)); } if (ch == 0) { reply.MoreData = (RequestTypes)(reply.MoreData | RequestTypes.DataBlock); } else { reply.MoreData = (RequestTypes)(reply.MoreData & ~RequestTypes.DataBlock); } // Get Block number. number = data.GetUInt32(); if (reply.Xml != null) { //BlockNumber reply.Xml.AppendLine(TranslatorTags.BlockNumber, "Value", reply.Xml.IntegerToHex(number, 8)); } else { //If meter's block index is zero based. if (number != 1 && settings.BlockIndex == 1) { settings.BlockIndex = (uint)number; } if (number != settings.BlockIndex) { throw new ArgumentException( "Invalid Block number. It is " + number + " and it should be " + settings.BlockIndex + "."); } } // Get status. ch = data.GetUInt8(); if (ch != 0) { reply.Error = data.GetUInt8(); } if (reply.Xml != null) { // Get data size. int blockLength = GXCommon.GetObjectCount(data); // if whole block is read. if ((reply.MoreData & RequestTypes.Frame) == 0) { // Check Block length. if (blockLength > data.Size - data.Position) { throw new OutOfMemoryException(); } } //Result reply.Xml.AppendStartTag(TranslatorTags.Result); reply.Xml.AppendLine(TranslatorTags.RawData, "Value", GXCommon.ToHex(reply.Data.Data, false, data.Position, reply.Data.Size - data.Position)); reply.Xml.AppendEndTag(TranslatorTags.Result); } else if (data.Position != data.Size) { // Get data size. int blockLength = GXCommon.GetObjectCount(data); // if whole block is read. if ((reply.MoreData & RequestTypes.Frame) == 0) { // Check Block length. if (blockLength > data.Size - data.Position) { throw new OutOfMemoryException(); } reply.Command = Command.None; } GetDataFromBlock(data, index); // If last packet and data is not try to peek. if (reply.MoreData == RequestTypes.None) { if (!reply.Peek) { data.Position = 0; } settings.ResetBlockIndex(); } } } else if (type == GetCommandType.WithList) { //Get object count. int cnt = GXCommon.GetObjectCount(data); object[] values = new object[cnt]; if (reply.Xml != null) { //Result start tag. reply.Xml.AppendStartTag(TranslatorTags.Result, "Qty", reply.Xml.IntegerToHex(cnt, 2)); } for (int pos = 0; pos != cnt; ++pos) { // Result ch = data.GetUInt8(); if (ch != 0) { reply.Error = data.GetUInt8(); } else { if (reply.Xml != null) { GXDataInfo di = new GXDataInfo(); di.xml = reply.Xml; //Data. reply.Xml.AppendStartTag(Command.ReadResponse, SingleReadResponse.Data); GXCommon.GetData(settings, reply.Data, di); reply.Xml.AppendEndTag(Command.ReadResponse, SingleReadResponse.Data); } else { reply.ReadPosition = reply.Data.Position; GetValueFromData(settings, reply); reply.Data.Position = reply.ReadPosition; if (values != null) { values[pos] = reply.Value; } reply.Value = null; } } } reply.Value = values; ret = false; } else { throw new ArgumentException("Invalid Get response."); } if (reply.Xml != null) { reply.Xml.AppendEndTag(TranslatorTags.Result); reply.Xml.AppendEndTag(Command.GetResponse, type); reply.Xml.AppendEndTag(Command.GetResponse); } return ret; }
/// <summary> /// Handle read response data block result. /// </summary> /// <param name="settings">DLMS settings.</param> /// <param name="reply">Received reply.</param> /// <param name="index">Starting index.</param> static bool ReadResponseDataBlockResult(GXDLMSSettings settings, GXReplyData reply, int index) { reply.Error = 0; byte lastBlock = reply.Data.GetUInt8(); // Get Block number. UInt32 number = reply.Data.GetUInt16(); int blockLength = GXCommon.GetObjectCount(reply.Data); // Check block length when all data is received. if ((reply.MoreData & RequestTypes.Frame) == 0) { if (blockLength != reply.Data.Size - reply.Data.Position) { throw new OutOfMemoryException(); } reply.Command = Command.None; if (reply.Xml != null) { reply.Data.Trim(); reply.Xml.AppendStartTag(Command.ReadResponse, SingleReadResponse.DataBlockResult); reply.Xml.AppendLine(TranslatorTags.LastBlock, "Value", reply.Xml.IntegerToHex(lastBlock, 2)); reply.Xml.AppendLine(TranslatorTags.BlockNumber, "Value", reply.Xml.IntegerToHex(number, 4)); reply.Xml.AppendLine(TranslatorTags.RawData, "Value", GXCommon.ToHex(reply.Data.Data, false, 0, reply.Data.Size)); reply.Xml.AppendEndTag(Command.ReadResponse, SingleReadResponse.DataBlockResult); return false; } } GetDataFromBlock(reply.Data, index); // Is not Last block. if (lastBlock == 0) { reply.MoreData = (RequestTypes)(reply.MoreData | RequestTypes.DataBlock); } else { reply.MoreData = (RequestTypes)(reply.MoreData & ~RequestTypes.DataBlock); } //If meter's block index is zero based. if (number != 1 && settings.BlockIndex == 1) { settings.BlockIndex = (uint)number; } UInt32 expectedIndex = settings.BlockIndex; if (number != expectedIndex) { throw new ArgumentException( "Invalid Block number. It is " + number + " and it should be " + expectedIndex + "."); } // If last packet and data is not try to peek. if (reply.MoreData == RequestTypes.None) { reply.Data.Position = 0; HandleReadResponse(settings, reply, index); settings.ResetBlockIndex(); } return true; }
private static void ReturnSNError(GXDLMSSettings settings, GXDLMSServer server, Command cmd, ErrorCode error, GXByteBuffer replyData) { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt8(error); GXDLMS.GetSNPdu(new GXDLMSSNParameters(settings, cmd, 1, (byte)SingleReadResponse.DataAccessError, bb, null), replyData); settings.ResetBlockIndex(); }
public static void HandleGetRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { //Return error if connection is not established. if (xml == null && !settings.Connected) { replyData.Set(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } GetCommandType type = (GetCommandType)data.GetUInt8(); // Get invoke ID and priority. byte invokeID = data.GetUInt8(); if (xml != null) { xml.AppendStartTag(Command.GetRequest); xml.AppendStartTag(Command.GetRequest, type); xml.AppendLine(TranslatorTags.InvokeId, "Value", xml.IntegerToHex(invokeID, 2)); } // GetRequest normal if (type == GetCommandType.Normal) { GetRequestNormal(settings, server, data, replyData, xml); } else if (type == GetCommandType.NextDataBlock) { // Get request for next data block GetRequestNextDataBlock(settings, server, data, replyData, xml); } else if (type == GetCommandType.WithList) { // Get request with a list. GetRequestWithList(settings, server, data, replyData, xml); } else { Debug.WriteLine("HandleGetRequest failed. Invalid command type."); settings.ResetBlockIndex(); GXByteBuffer bb = new GXByteBuffer(); // Access Error : Device reports a hardware fault. bb.SetUInt8((byte)ErrorCode.HardwareFault); GXDLMS.GetLNPdu(new GXDLMSLNParameters(settings, Command.GetResponse, (byte)type, null, bb, (byte)ErrorCode.Ok), replyData); } if (xml != null) { xml.AppendEndTag(Command.GetRequest, type); xml.AppendEndTag(Command.GetRequest); } }
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; } } } }
/// <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 HanleSetRequestWithDataBlock(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXDLMSLNParameters p, GXByteBuffer replyData, GXDLMSTranslatorStructure xml) { GXDataInfo reply = new GXDataInfo(); p.multipleBlocks = data.GetUInt8() == 0; UInt32 blockNumber = data.GetUInt32(); if (blockNumber != settings.BlockIndex) { Debug.WriteLine("HanleSetRequestWithDataBlock failed. Invalid block number. " + settings.BlockIndex + "/" + blockNumber); p.status = (byte)ErrorCode.DataBlockNumberInvalid; } else { 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; } 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); } } 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]); } } catch (Exception) { p.status = (byte)ErrorCode.HardwareFault; } finally { server.transaction = null; } settings.ResetBlockIndex(); } } p.multipleBlocks = true; }
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); } 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(); } }