/// <summary> /// Generates data notification message(s). /// </summary> /// <param name="time">Date time. Set To Min or Max if not added</param> /// <param name="data">Notification body.</param> /// <returns>Generated data notification message(s).</returns> public byte[][] GenerateDataNotificationMessages(DateTime time, byte[] data) { byte[][] reply; if (UseLogicalNameReferencing) { GXDLMSLNParameters p = new GXDLMSLNParameters(null, Settings, 0, Command.DataNotification, 0, null, new GXByteBuffer(data), 0xff); p.time = time; reply = GXDLMS.GetLnMessages(p); } else { GXDLMSSNParameters p = new GXDLMSSNParameters(Settings, Command.DataNotification, 1, 0, new GXByteBuffer(data), null); reply = GXDLMS.GetSnMessages(p); } if ((Settings.NegotiatedConformance & Conformance.GeneralBlockTransfer) == 0 && reply.Length != 1) { throw new ArgumentException("Data is not fit to one PDU. Use general block transfer."); } return(reply); }
/// <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>(); List <ValueEventArgs> reads = new List <ValueEventArgs>(); List <ValueEventArgs> actions = 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); 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); if (reads.Count != 0) { server.NotifyPostRead(reads.ToArray()); } if (actions.Count != 0) { server.NotifyPostAction(actions.ToArray()); } 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)) { 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> /// 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> /// Generates data notification message. /// </summary> /// <param name="time">Date time. Set To Min or Max if not added</param> /// <param name="objects">List of objects and attribute indexes to notify.</param> /// <returns>Generated data notification message(s).</returns> public byte[][] GenerateDataNotificationMessages(DateTime time, List<KeyValuePair<GXDLMSObject, int>> objects) { if (objects == null) { throw new ArgumentNullException("objects"); } GXByteBuffer buff = new GXByteBuffer(); buff.SetUInt8(DataType.Structure); GXCommon.SetObjectCount(objects.Count, buff); foreach (KeyValuePair<GXDLMSObject, int> it in objects) { AddData(it.Key, it.Value, buff); } byte[][] reply; if (UseLogicalNameReferencing) { GXDLMSLNParameters p = new GXDLMSLNParameters(Settings, Command.DataNotification, 0, null, buff, 0xff); p.time = time; reply = GXDLMS.GetLnMessages(p); } else { GXDLMSSNParameters p = new GXDLMSSNParameters(Settings, Command.DataNotification, 1, 0, buff, null); reply = GXDLMS.GetSnMessages(p); } return reply; }
/// <summary> /// Generates data notification message(s). /// </summary> /// <param name="time">Date time. Set To Min or Max if not added</param> /// <param name="data">Notification body.</param> /// <returns>Generated data notification message(s).</returns> public byte[][] GenerateDataNotificationMessages(DateTime time, GXByteBuffer data) { byte[][] reply; if (UseLogicalNameReferencing) { GXDLMSLNParameters p = new GXDLMSLNParameters(Settings, Command.DataNotification, 0, null, data, 0xff); p.time = time; p.time.Skip |= DateTimeSkips.Ms; reply = GXDLMS.GetLnMessages(p); } else { GXDLMSSNParameters p = new GXDLMSSNParameters(Settings, Command.DataNotification, 1, 0, data, null); reply = GXDLMS.GetSnMessages(p); } return reply; }
/// <summary> /// Generates data notification message(s). /// </summary> /// <param name="time">Date time. Set To Min or Max if not added</param> /// <param name="data">Notification body.</param> /// <returns>Generated data notification message(s).</returns> public byte[][] GenerateDataNotificationMessages(DateTime time, byte[] data) { byte[][] reply; if (UseLogicalNameReferencing) { GXDLMSLNParameters p = new GXDLMSLNParameters(Settings, Command.DataNotification, 0, null, new GXByteBuffer(data), 0xff); p.time = time; reply = GXDLMS.GetLnMessages(p); } else { GXDLMSSNParameters p = new GXDLMSSNParameters(Settings, Command.DataNotification, 1, 0, new GXByteBuffer(data), null); reply = GXDLMS.GetSnMessages(p); } if (!GeneralBlockTransfer && reply.Length != 1) { throw new ArgumentException("Data is not fit to one PDU. Use general block transfer."); } return reply; }
private byte[] ReportError(Command cmd, ErrorCode error) { switch (cmd) { case Command.ReadRequest: cmd = Command.ReadResponse; break; case Command.WriteRequest: cmd = Command.WriteResponse; break; case Command.GetRequest: cmd = Command.GetResponse; break; case Command.SetRequest: cmd = Command.SetResponse; break; case Command.MethodRequest: cmd = Command.MethodResponse; break; default: //Return HW error and close connection.. break; } if (Settings.UseLogicalNameReferencing) { GXDLMS.GetLNPdu(new GXDLMSLNParameters(Settings, cmd, 1, null, null, (byte)error), replyData); } else { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt8(error); GXDLMSSNParameters p = new GXDLMSSNParameters(Settings, cmd, 1, (byte)error, null, bb); GXDLMS.GetSNPdu(p, replyData); } if (this.InterfaceType == Enums.InterfaceType.WRAPPER) { return GXDLMS.GetWrapperFrame(Settings, replyData); } else { return GXDLMS.GetHdlcFrame(Settings, 0, replyData); } }
/// <summary> /// /// </summary> /// <param name="p"></param> /// <param name="reply"></param> internal static void GetSNPdu(GXDLMSSNParameters p, GXByteBuffer reply) { bool ciphering = p.settings.Cipher != null && p.settings.Cipher.Security != Gurux.DLMS.Enums.Security.None; if (!ciphering && p.settings.InterfaceType == InterfaceType.HDLC) { if (p.settings.IsServer) { reply.Set(GXCommon.LLCReplyBytes); } else if (reply.Size == 0) { reply.Set(GXCommon.LLCSendBytes); } } int cnt = 0, cipherSize = 0; if (ciphering) { cipherSize = CipheringHeaderSize; /* if (p.settings.Cipher.Security == Security.Encryption) { cipherSize = 7; } else if (p.settings.Cipher.Security == Security.Authentication) { cipherSize = 19; } else if (p.settings.Cipher.Security == Security.AuthenticationEncryption) { cipherSize = 7; } * */ } if (p.data != null) { cnt = p.data.Size - p.data.Position; } // Add command. if (p.command != Command.Aarq && p.command != Command.Aare) { reply.SetUInt8((byte)p.command); if (p.count != 0xFF) { GXCommon.SetObjectCount(p.count, reply); } if (p.requestType != 0xFF) { reply.SetUInt8(p.requestType); } reply.Set(p.attributeDescriptor); if (!p.multipleBlocks) { p.multipleBlocks = reply.Size + cipherSize + cnt > p.settings.MaxPduSize; //If reply data is not fit to one PDU. if (p.multipleBlocks) { //Remove command. GXByteBuffer tmp = new GXByteBuffer(); int offset = 1; if (!ciphering && p.settings.InterfaceType == InterfaceType.HDLC) { offset = 4; } tmp.Set(reply.Data, offset, reply.Size - offset); reply.Size = 0; if (!ciphering && p.settings.InterfaceType == InterfaceType.HDLC) { if (p.settings.IsServer) { reply.Set(GXCommon.LLCReplyBytes); } else if (reply.Size == 0) { reply.Set(GXCommon.LLCSendBytes); } } if (p.command == Command.WriteRequest) { p.requestType = (byte)VariableAccessSpecification.WriteDataBlockAccess; } else if (p.command == Command.ReadRequest) { p.requestType = (byte)VariableAccessSpecification.ReadDataBlockAccess; } else if (p.command == Command.ReadResponse) { p.requestType = (byte)SingleReadResponse.DataBlockResult; } else { throw new ArgumentException("Invalid command."); } reply.SetUInt8((byte)p.command); //Set object count. reply.SetUInt8(1); if (p.requestType != 0xFF) { reply.SetUInt8(p.requestType); } cnt = GXDLMS.AppendMultipleSNBlocks(p, tmp, reply); } } else { cnt = GXDLMS.AppendMultipleSNBlocks(p, null, reply); } } // Add data. reply.Set(p.data, cnt); //Af all data is transfered. if (p.data != null && p.data.Position == p.data.Size) { p.settings.Index = p.settings.Count = 0; } // If Ciphering is used. if (ciphering && p.command != Command.Aarq && p.command != Command.Aare) { byte[] tmp = p.settings.Cipher.Encrypt((byte)GetGloMessage(p.command), p.settings.Cipher.SystemTitle, reply.Array()); System.Diagnostics.Debug.Assert(!(p.settings.MaxPduSize < tmp.Length)); reply.Size = 0; if (p.settings.InterfaceType == InterfaceType.HDLC) { if (p.settings.IsServer) { reply.Set(GXCommon.LLCReplyBytes); } else if (reply.Size == 0) { reply.Set(GXCommon.LLCSendBytes); } } reply.Set(tmp); } }
///<summary> /// Handle write request. ///</summary> public static void HandleWriteRequest(GXDLMSSettings settings, GXDLMSServer server, GXByteBuffer data, GXByteBuffer replyData, GXDLMSTranslatorStructure xml, Command cipheredCommand) { short type; object value; // Get object count. List <GXSNInfo> targets = new List <GXSNInfo>(); int cnt = GXCommon.GetObjectCount(data); if (xml != null) { xml.AppendStartTag(Command.WriteRequest); xml.AppendStartTag( TranslatorTags.ListOfVariableAccessSpecification, "Qty", xml.IntegerToHex(cnt, 2)); if (xml.OutputType == TranslatorOutputType.StandardXml) { xml.AppendStartTag( TranslatorTags.VariableAccessSpecification); } } GXDataInfo di; GXSNInfo info; GXByteBuffer results = new GXByteBuffer((ushort)cnt); for (int pos = 0; pos != cnt; ++pos) { type = data.GetUInt8(); if (type == (byte)VariableAccessSpecification.VariableName) { int sn = data.GetUInt16(); if (xml != null) { xml.AppendLine( (int)Command.WriteRequest << 8 | type, "Value", xml.IntegerToHex(sn, 4)); } else { info = FindSNObject(server, sn); targets.Add(info); // If target is unknown. if (info == null) { // Device reports a undefined object. results.SetUInt8(ErrorCode.UndefinedObject); } else { results.SetUInt8(ErrorCode.Ok); } } } else if (type == (byte)VariableAccessSpecification.WriteDataBlockAccess) { //Return error if connection is not established. if (xml == null && (settings.Connected & ConnectionState.Dlms) == 0 && cipheredCommand == Command.None) { replyData.Add(GXDLMSServer.GenerateConfirmedServiceError(ConfirmedServiceError.InitiateError, ServiceError.Service, (byte)Service.Unsupported)); return; } HandleReadDataBlockAccess(settings, server, Command.WriteResponse, data, cnt, replyData, xml, cipheredCommand); if (xml == null) { return; } } else { // Device reports a HW error. results.SetUInt8(ErrorCode.HardwareFault); } } if (xml != null) { if (xml.OutputType == TranslatorOutputType.StandardXml) { xml.AppendEndTag(TranslatorTags.VariableAccessSpecification); } xml.AppendEndTag( TranslatorTags.ListOfVariableAccessSpecification); } // Get data count. cnt = GXCommon.GetObjectCount(data); di = new GXDataInfo(); di.xml = xml; if (xml != null) { xml.AppendStartTag(TranslatorTags.ListOfData, "Qty", xml.IntegerToHex(cnt, 2)); } for (int pos = 0; pos != cnt; ++pos) { di.Clear(); if (xml != null) { if (xml.OutputType == TranslatorOutputType.StandardXml) { xml.AppendStartTag(Command.WriteRequest, SingleReadResponse.Data); } value = GXCommon.GetData(settings, data, di); if (!di.Complete) { value = GXCommon.ToHex(data.Data, false, data.Position, data.Size - data.Position); xml.AppendLine( GXDLMS.DATA_TYPE_OFFSET + (int)di.Type, "Value", value.ToString()); } if (xml.OutputType == TranslatorOutputType.StandardXml) { xml.AppendEndTag(Command.WriteRequest, SingleReadResponse.Data); } } else if (results.GetUInt8(pos) == 0) { bool access = true; // If object has found. GXSNInfo target = targets[pos]; value = GXCommon.GetData(settings, data, di); ValueEventArgs e = new ValueEventArgs(server, target.Item, target.Index, 0, null); if (target.IsAction) { MethodAccessMode am = server.NotifyGetMethodAccess(e); // If action is denied. if (am != MethodAccessMode.Access) { access = false; } } else { if (value is byte[]) { DataType dt = target.Item.GetDataType(target.Index); if (dt != DataType.None && dt != DataType.OctetString) { value = GXDLMSClient.ChangeType((byte[])value, dt, settings.UseUtc2NormalTime); } } AccessMode am = server.NotifyGetAttributeAccess(e); // If write is denied. if (am != AccessMode.Write && am != AccessMode.ReadWrite) { access = false; } } if (access) { if (target.IsAction) { e.Parameters = value; ValueEventArgs[] actions = new ValueEventArgs[] { e }; server.NotifyAction(actions); if (!e.Handled) { byte[] reply = (target.Item as IGXDLMSBase).Invoke(settings, e); server.NotifyPostAction(actions); if (target.Item is GXDLMSAssociationShortName && target.Index == 8 && reply != null) { GXByteBuffer bb = new GXByteBuffer(); bb.SetUInt8((byte)DataType.OctetString); bb.SetUInt8((byte)reply.Length); bb.Set(reply); GXDLMSSNParameters p = new GXDLMSSNParameters(settings, Command.ReadResponse, 1, 0, null, bb); GXDLMS.GetSNPdu(p, replyData); } } } else { e.Value = value; server.NotifyWrite(new ValueEventArgs[] { e }); if (e.Error != 0) { results.SetUInt8((byte)pos, (byte)e.Error); } else if (!e.Handled) { (target.Item as IGXDLMSBase).SetValue(settings, e); server.NotifyPostWrite(new ValueEventArgs[] { e }); } } } else { results.SetUInt8((byte)pos, (byte)ErrorCode.ReadWriteDenied); } } } if (xml != null) { xml.AppendEndTag(TranslatorTags.ListOfData); xml.AppendEndTag(Command.WriteRequest); return; } GenerateWriteResponse(settings, results, replyData); }
/// <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(); }
static int AppendMultipleSNBlocks(GXDLMSSNParameters p, GXByteBuffer header, GXByteBuffer reply) { bool ciphering = p.settings.Cipher != null && p.settings.Cipher.Security != Gurux.DLMS.Enums.Security.None; int hSize = reply.Size + 3; if (header != null) { hSize += header.Size; } //Add LLC bytes. if (p.command == Command.WriteRequest || p.command == Command.ReadRequest) { hSize += 1 + GXCommon.GetObjectCountSizeInBytes(p.count); } int maxSize = p.settings.MaxPduSize - hSize; if (ciphering) { maxSize -= CipheringHeaderSize; if (p.settings.InterfaceType == InterfaceType.HDLC) { maxSize -= 3; } } maxSize -= GXCommon.GetObjectCountSizeInBytes(maxSize); if (p.data.Size - p.data.Position > maxSize) { //More blocks. reply.SetUInt8(0); } else { //Last block. reply.SetUInt8(1); maxSize = p.data.Size - p.data.Position; } //Add block index. reply.SetUInt16(p.blockIndex); if (p.command == Command.WriteRequest) { ++p.blockIndex; GXCommon.SetObjectCount(p.count, reply); reply.SetUInt8(DataType.OctetString); } if (p.command == Command.ReadRequest) { ++p.blockIndex; } if (header != null) { GXCommon.SetObjectCount(maxSize + header.Size, reply); reply.Set(header); } else { GXCommon.SetObjectCount(maxSize, reply); } return maxSize; }
///<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 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> /// 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(); } }
/// <summary> /// Generate write reply. /// </summary> /// <param name="settings"></param> /// <param name="results"></param> /// <param name="replyData"></param> internal static void GenerateWriteResponse(GXDLMSSettings settings, GXByteBuffer results, GXByteBuffer replyData) { GXByteBuffer bb = new GXByteBuffer((UInt16)(2 * results.Size)); byte ret; for (int pos = 0; pos != results.Size; ++pos) { ret = results.GetUInt8(pos); // If meter returns error. if (ret != 0) { bb.SetUInt8(1); } bb.SetUInt8(ret); } GXDLMSSNParameters p = new GXDLMSSNParameters(settings, Command.WriteResponse, results.Size, 0xFF, null, bb); GXDLMS.GetSNPdu(p, replyData); }
/// <summary> /// Convert xml to byte array. /// </summary> /// <param name="xml">Converted xml.</param> /// <returns>Converted bytes.</returns> public byte[] XmlToPdu(string xml) { XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); GXDLMSXmlSettings s = new GXDLMSXmlSettings(OutputType, Hex, ShowStringAsHex, tagsByName); ReadAllNodes(doc, s); GXByteBuffer bb = new GXByteBuffer(); GXDLMSLNParameters ln; GXDLMSSNParameters sn; switch (s.command) { case Command.InitiateRequest: case Command.InitiateResponse: break; case Command.ReadRequest: case Command.WriteRequest: case Command.ReadResponse: case Command.WriteResponse: sn = new GXDLMSSNParameters(s.settings, s.command, s.count, s.requestType, s.attributeDescriptor, s.data); GXDLMS.GetSNPdu(sn, bb); break; case Command.GetRequest: case Command.GetResponse: case Command.SetRequest: case Command.SetResponse: case Command.MethodRequest: case Command.MethodResponse: ln = new GXDLMSLNParameters(s.settings, s.command, s.requestType, s.attributeDescriptor, s.data, 0xff); GXDLMS.GetLNPdu(ln, bb); break; case Command.GloGetRequest: case Command.GloGetResponse: case Command.GloSetRequest: case Command.GloSetResponse: case Command.GloMethodRequest: case Command.GloMethodResponse: case Command.GloReadRequest: case Command.GloWriteRequest: case Command.GloReadResponse: case Command.GloWriteResponse: bb.SetUInt8((byte)s.command); GXCommon.SetObjectCount(s.data.Size, bb); bb.Set(s.data); break; case Command.Rejected: break; case Command.Snrm: s.settings.IsServer = false; bb.Set(GXDLMS.GetHdlcFrame(s.settings, (byte)Command.Snrm, null)); break; case Command.Ua: break; case Command.Aarq: case Command.GloInitiateRequest: GXAPDU.GenerateAarq(s.settings, s.settings.Cipher, s.data, bb); break; case Command.Aare: case Command.GloInitiateResponse: GXAPDU.GenerateAARE(s.settings, bb, s.result, s.diagnostic, s.settings.Cipher, s.data); break; case Command.DisconnectRequest: break; case Command.ReleaseRequest: bb.SetUInt8((byte)s.command); bb.SetUInt8(0); break; case Command.ReleaseResponse: bb.SetUInt8((byte)s.command); //Len bb.SetUInt8(3); //BerType bb.SetUInt8(BerType.Context); //Len. bb.SetUInt8(1); bb.SetUInt8(s.reason); break; case Command.ConfirmedServiceError: break; case Command.ExceptionResponse: break; case Command.GeneralBlockTransfer: break; case Command.AccessRequest: ln = new GXDLMSLNParameters(s.settings, s.command, s.requestType, s.attributeDescriptor, s.data, 0xff); GXDLMS.GetLNPdu(ln, bb); break; case Command.AccessResponse: ln = new GXDLMSLNParameters(s.settings, s.command, s.requestType, s.attributeDescriptor, s.data, 0xff); GXDLMS.GetLNPdu(ln, bb); break; case Command.DataNotification: ln = new GXDLMSLNParameters(s.settings, s.command, s.requestType, s.attributeDescriptor, s.data, 0xff); ln.time = s.time; GXDLMS.GetLNPdu(ln, bb); break; case Command.GloGeneralCiphering: break; case Command.GloEventNotificationRequest: break; default: case Command.None: throw new ArgumentException("Invalid command."); } return bb.Array(); }