From a603b7af487a1bab8bd83aa4202d72f9d525c36f Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Wed, 3 Jun 2015 16:24:43 +0200 Subject: [PATCH] - added IED_ERROR_TYPE_INCONSISTENT value to client API - server now reponds with type-inconsistent error when client tries to write a value of wrong type --- dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs | 3 ++ dotnet/IEC61850forCSharp/Reporting.cs | 20 +++++++++++ dotnet/control/ControlExample.cs | 34 ++++++++++++++++--- dotnet/reporting/ReportingExample.cs | 33 ++++++++++++++++-- src/iec61850/client/ied_connection.c | 3 ++ src/iec61850/inc/iec61850_client.h | 3 ++ src/mms/iso_mms/server/mms_write_service.c | 8 +++++ 7 files changed, 96 insertions(+), 8 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index e1336319..e24a20d4 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -1143,6 +1143,9 @@ namespace IEC61850 /** The server does not support the requested access method */ IED_ERROR_OBJECT_ACCESS_UNSUPPORTED = 24, + /** The server expected an object of another type */ + IED_ERROR_TYPE_INCONSISTENT = 25, + /* unknown error */ IED_ERROR_UNKNOWN = 99 } diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs index e88f5ff1..256880f4 100644 --- a/dotnet/IEC61850forCSharp/Reporting.cs +++ b/dotnet/IEC61850forCSharp/Reporting.cs @@ -120,6 +120,9 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr ClientReport_getRptId(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getEntryId(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr ClientReport_getDataReference(IntPtr self, int elementIndex); @@ -286,6 +289,23 @@ namespace IEC61850 return Marshal.PtrToStringAnsi (rptId); } + /// + /// Gets the EntryID of this report. + /// + /// The entryID as a byte array representing an MMS octet string. + public byte[] GetEntryId () + { + IntPtr entryIdRef = ClientReport_getEntryId (self); + + if (entryIdRef == IntPtr.Zero) + return null; + else { + MmsValue entryId = new MmsValue (entryIdRef); + + return entryId.getOctetString (); + } + } + } } diff --git a/dotnet/control/ControlExample.cs b/dotnet/control/ControlExample.cs index 7fc136a5..aa3d0a5a 100644 --- a/dotnet/control/ControlExample.cs +++ b/dotnet/control/ControlExample.cs @@ -32,7 +32,7 @@ namespace control { con.Connect(hostname, 102); - /* direct control with normal security */ + /* direct control with normal security or SBO with normal security */ string objectReference = "simpleIOGenericIO/GGIO1.SPCSO1"; ControlObject control = con.CreateControlObject(objectReference); @@ -41,11 +41,35 @@ namespace control Console.WriteLine(objectReference + " has control model " + controlModel.ToString()); - if (controlModel != ControlModel.STATUS_ONLY) - control.Operate(true); - if (!control.Operate(true)) - Console.WriteLine("operate failed!"); + switch (controlModel) { + + case ControlModel.STATUS_ONLY: + Console.WriteLine("Control is status-only!"); + break; + + case ControlModel.DIRECT_NORMAL: + case ControlModel.DIRECT_ENHANCED: + if (!control.Operate(true)) + Console.WriteLine("operate failed!"); + else + Console.WriteLine("operated successfully!"); + break; + + case ControlModel.SBO_NORMAL: + case ControlModel.SBO_ENHANCED: + + if (control.Select()) { + if (!control.Operate(true)) + Console.WriteLine("operate failed!"); + else + Console.WriteLine("operated successfully!"); + } + else + Console.WriteLine("Select failed!"); + + break; + } /* direct control with enhanced security */ objectReference = "simpleIOGenericIO/GGIO1.SPCSO3"; diff --git a/dotnet/reporting/ReportingExample.cs b/dotnet/reporting/ReportingExample.cs index 6a1d9538..4a319cc2 100644 --- a/dotnet/reporting/ReportingExample.cs +++ b/dotnet/reporting/ReportingExample.cs @@ -4,6 +4,7 @@ using System.Threading; using IEC61850.Client; using IEC61850.Common; +using System.Runtime.Remoting.Metadata.W3cXsd2001; namespace reporting { @@ -21,6 +22,14 @@ namespace reporting MmsValue values = report.GetDataSetValues (); + byte[] entryId = report.GetEntryId (); + + if (entryId != null) { + SoapHexBinary shb = new SoapHexBinary(entryId); + + Console.WriteLine (" entryID: " + shb.ToString ()); + } + Console.WriteLine (" report dataset contains " + values.Size () + " elements"); for (int i = 0; i < values.Size(); i++) { @@ -53,9 +62,7 @@ namespace reporting if (args.Length > 0) hostname = args [0]; else - hostname = "localhost"; - - hostname = "10.0.2.2"; + hostname = "localhost"; Console.WriteLine ("Connect to " + hostname); @@ -64,9 +71,11 @@ namespace reporting string rcbReference1 = "simpleIOGenericIO/LLN0.RP.EventsRCB01"; string rcbReference2 = "simpleIOGenericIO/LLN0.RP.EventsIndexed01"; + string rcbReference3 = "simpleIOGenericIO/LLN0.BR.Measurements01"; ReportControlBlock rcb1 = con.GetReportControlBlock(rcbReference1); ReportControlBlock rcb2 = con.GetReportControlBlock(rcbReference2); + ReportControlBlock rcb3 = con.GetReportControlBlock(rcbReference3); rcb1.GetRCBValues(); @@ -84,6 +93,9 @@ namespace reporting rcb2.GetRCBValues(); + if (rcb2.IsBuffered()) + Console.WriteLine ("RCB: " + rcbReference2 + " is buffered"); + rcb2.InstallReportHandler(reportHandler, rcb2); rcb2.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP | @@ -94,6 +106,21 @@ namespace reporting rcb2.SetRCBValues(); + rcb3.GetRCBValues(); + + if (rcb3.IsBuffered()) + Console.WriteLine ("RCB: " + rcbReference3 + " is buffered"); + + rcb3.InstallReportHandler(reportHandler, rcb2); + + rcb3.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP | + ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET); + rcb3.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); + rcb3.SetIntgPd(2000); + rcb3.SetRptEna(true); + + rcb3.SetRCBValues(); + /* run until Ctrl-C is pressed */ Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index 8fd66de0..5d9f7436 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -76,6 +76,9 @@ iedConnection_mapMmsErrorToIedError(MmsError mmsError) case MMS_ERROR_DEFINITION_OBJECT_EXISTS: return IED_ERROR_OBJECT_EXISTS; + case MMS_ERROR_DEFINITION_TYPE_INCONSISTENT: + return IED_ERROR_TYPE_INCONSISTENT; + case MMS_ERROR_SERVICE_TIMEOUT: return IED_ERROR_TIMEOUT; diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 7377300a..6fefb049 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -129,6 +129,9 @@ typedef enum { /** The server does not support the requested access method */ IED_ERROR_OBJECT_ACCESS_UNSUPPORTED = 24, + /** The server expected an object of another type */ + IED_ERROR_TYPE_INCONSISTENT = 25, + /* unknown error */ IED_ERROR_UNKNOWN = 99 } IedClientError; diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c index 9d50073b..291cf14f 100644 --- a/src/mms/iso_mms/server/mms_write_service.c +++ b/src/mms/iso_mms/server/mms_write_service.c @@ -212,6 +212,14 @@ mmsServer_handleWriteRequest( continue; } + /* Check for correct type */ + if (MmsValue_getType(value) != MmsVariableSpecification_getType(variable)) { + GLOBAL_FREEMEM(nameIdStr); + MmsValue_delete(value); + accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + continue; + } + if (alternateAccess != NULL) { if (domain != NULL)