diff --git a/CHANGELOG b/CHANGELOG
index 7f6e4b20..1e9d5045 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,12 @@
+Changes to version 1.3.1
+------------------------
+- IEC 61850 client: improved support for handling segmented reports
+- .NET API: Added some additional access function to ReportControlBlock
+- Java SCL parser: added support for timestamp values in "Val" elements
+- fixed bug in cmake file (winpcap support)
+- added C# example code for client side setting group handling
+- .NET API: added some additional wrapper code for MmsVariableSpecification functions
+
Changes to version 1.3.0
------------------------
- IEC 61850 server: more features configurable at runtime
@@ -17,7 +26,6 @@ Changes to version 1.3.0
- MMS server: fixed bug in delete variable list service - scope of delete was not considered optional
- some more small bug fixes and optimizations
-
Changes to version 1.2.2
------------------------
diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs
index 90ddba2d..398db95a 100644
--- a/dotnet/IEC61850forCSharp/Reporting.cs
+++ b/dotnet/IEC61850forCSharp/Reporting.cs
@@ -1,7 +1,7 @@
/*
* Reporting.cs
*
- * Copyright 2014 Michael Zillgith
+ * Copyright 2014-2018 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -147,6 +147,15 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReport_getDataReference(IntPtr self, int elementIndex);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasSubSeqNum(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt16 ClientReport_getSubSeqNum(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_getMoreSeqmentsFollow(IntPtr self);
+
private IntPtr self;
private IntPtr dataSetValues = IntPtr.Zero;
@@ -213,16 +222,55 @@ namespace IEC61850
return ClientReport_getBufOvfl(self);
}
+ ///
+ /// Indicates if the report contains a sequence number (SeqNum) field
+ ///
+ /// true if this instance has SeqNum; otherwise, false.
public bool HasSeqNum ()
{
return ClientReport_hasSeqNum(self);
}
+ ///
+ /// Gets the value of the SeqNum field
+ ///
+ /// The report sequence number
public UInt16 GetSeqNum ()
{
return ClientReport_getSeqNum(self);
}
+ ///
+ /// Indicates if the report contains a sub sequence number (SubSeqNum) and more segments follow (MoreSegmentsFollow) field
+ ///
+ /// true if this instance has SubSeqNum and MoreSegmentsFollow; otherwise, false.
+ public bool HasSubSeqNum()
+ {
+ return ClientReport_hasSubSeqNum(self);
+ }
+
+ ///
+ /// Gets the sub sequence number (SubSeqNum) value of a segmented report
+ ///
+ /// The sub sequence number.
+ public UInt16 GetSubSeqNum()
+ {
+ return ClientReport_getSubSeqNum(self);
+ }
+
+ ///
+ /// Gets the more segments follow (MoreSegmentsFollow) flag
+ ///
+ /// true, if more report segments follow, false otherwise.
+ public bool GetMoreSegmentsFollow()
+ {
+ return ClientReport_getMoreSeqmentsFollow(self);
+ }
+
+ ///
+ /// Determines whether this report contains reason for inclusion information
+ ///
+ /// true if this report contains reason for inclusion information; otherwise, false.
public bool HasReasonForInclusion ()
{
return ClientReport_hasReasonForInclusion(self);
diff --git a/src/iec61850/client/client_report.c b/src/iec61850/client/client_report.c
index b2a76df9..26c670c4 100644
--- a/src/iec61850/client/client_report.c
+++ b/src/iec61850/client/client_report.c
@@ -3,7 +3,7 @@
*
* Client implementation for IEC 61850 reporting.
*
- * Copyright 2013, 2014 Michael Zillgith
+ * Copyright 2013-2018 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -56,11 +56,15 @@ struct sClientReport
bool hasConfRev;
bool hasTimestamp;
bool hasBufOverflow;
+ bool hasSubSequenceNumber;
uint64_t timestamp;
uint16_t seqNum;
uint32_t confRev;
bool bufOverflow;
+
+ uint16_t subSeqNum;
+ bool moreSegementsFollow;
};
char*
@@ -242,6 +246,24 @@ ClientReport_getDataSetValues(ClientReport self)
return self->dataSetValues;
}
+bool
+ClientReport_hasSubSeqNum(ClientReport self)
+{
+ return self->hasSubSequenceNumber;
+}
+
+uint16_t
+ClientReport_getSubSeqNum(ClientReport self)
+{
+ return self->subSeqNum;
+}
+
+bool
+ClientReport_getMoreSeqmentsFollow(ClientReport self)
+{
+ return self->moreSegementsFollow;
+}
+
static ClientReport
lookupReportHandler(IedConnection self, const char* rcbReference)
{
@@ -386,6 +408,7 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
matchingReport->hasConfRev = false;
matchingReport->hasDataSetName = false;
matchingReport->hasBufOverflow = false;
+ matchingReport->hasSubSequenceNumber = false;
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received report with ID %s\n", MmsValue_toString(rptIdValue));
@@ -535,10 +558,43 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
inclusionIndex++;
}
+ /* handle segmentation fields (check ReportedOptFlds.segmentation) */
+ if (MmsValue_getBitStringBit(optFlds, 9) == true) {
+
+ MmsValue* subSeqNum = MmsValue_getElement(value, inclusionIndex);
+ inclusionIndex++;
+
+ if ((subSeqNum == NULL) || (MmsValue_getType(subSeqNum) != MMS_UNSIGNED)) {
+ if (DEBUG_IED_CLIENT)
+ printf("IED_CLIENT: received malformed report (SubSeqNum)\n");
+
+ goto exit_function;
+ }
+ else {
+ matchingReport->subSeqNum = (uint16_t) MmsValue_toUint32(subSeqNum);
+ }
+
+ MmsValue* moreSegmentsFollow = MmsValue_getElement(value, inclusionIndex);
+ inclusionIndex++;
+
+ if ((moreSegmentsFollow == NULL) || (MmsValue_getType(moreSegmentsFollow) != MMS_BOOLEAN)) {
+ if ((subSeqNum == NULL) || (MmsValue_getType(subSeqNum) != MMS_UNSIGNED)) {
+ if (DEBUG_IED_CLIENT)
+ printf("IED_CLIENT: received malformed report (MoreSegmentsFollow)\n");
+
+ goto exit_function;
+ }
+ }
+ else {
+ matchingReport->moreSegementsFollow = MmsValue_getBoolean(moreSegmentsFollow);
+ }
- /* skip segmentation fields */
- if (MmsValue_getBitStringBit(optFlds, 9) == true)
- inclusionIndex += 2;
+ matchingReport->hasSequenceNumber = true;
+ }
+ else {
+ matchingReport->subSeqNum = 0;
+ matchingReport->moreSegementsFollow = false;
+ }
MmsValue* inclusion = MmsValue_getElement(value, inclusionIndex);
diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h
index 594d97ee..549ef634 100644
--- a/src/iec61850/inc/iec61850_client.h
+++ b/src/iec61850/inc/iec61850_client.h
@@ -1336,6 +1336,42 @@ ClientReport_getDataReference(ClientReport self, int elementIndex);
LIB61850_API uint64_t
ClientReport_getTimestamp(ClientReport self);
+/**
+ * \brief indicates if the report contains a sub sequence number and a more segments follow flags (for segmented reporting)
+ *
+ * \param self the ClientReport instance
+ *
+ * \returns true if the report contains sub-sequence-number and more-follows-flag, false otherwise
+ */
+LIB61850_API bool
+ClientReport_hasSubSeqNum(ClientReport self);
+
+/**
+ * \brief get the sub sequence number of the report (for segmented reporting)
+ *
+ * Returns the sub sequence number of the report. This is 0 for the first report of a segmented report and
+ * will be increased by one for each report segment.
+ *
+ * \param self the ClientReport instance
+ *
+ * \return the sub sequence number of the last received report message.
+ */
+LIB61850_API uint16_t
+ClientReport_getSubSeqNum(ClientReport self);
+
+/**
+ * \brief get the more segments follow flag of the received report segment (for segmented reporting)
+ *
+ * Will return true in case this is part of a segmented report and more report segments will follow or false, if
+ * the current report is not a segmented report or is the last segment of a segmented report.
+ *
+ * \param self the ClientReport instance
+ *
+ * \return true when more segments of the current report will follow, false otherwise
+ */
+LIB61850_API bool
+ClientReport_getMoreSeqmentsFollow(ClientReport self);
+
/**
* \brief get the reason for inclusion of as a human readable string
*