Merge branch 'v1.5_feature_274' into v1.5

pull/374/head
Michael Zillgith 4 years ago
commit 824c9ad5dd

@ -1,7 +1,7 @@
/* /*
* IEC61850ServerAPI.cs * IEC61850ServerAPI.cs
* *
* Copyright 2016 Michael Zillgith * Copyright 2016-2022 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -331,12 +331,19 @@ namespace IEC61850
this.parent = parent; this.parent = parent;
} }
internal Dictionary<IntPtr, ReportControlBlock> rcbs = new Dictionary<IntPtr, ReportControlBlock>();
public LogicalNode(string name, LogicalDevice parent) public LogicalNode(string name, LogicalDevice parent)
{ {
this.parent = parent; this.parent = parent;
base.self = LogicalNode_create(name, parent.self); base.self = LogicalNode_create(name, parent.self);
} }
internal void AddRcb(ReportControlBlock rcb)
{
rcbs.Add(rcb.self, rcb);
}
} }
public enum AccessPolicy { public enum AccessPolicy {
@ -1301,12 +1308,78 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void ReportControlBlock_setPreconfiguredClient(IntPtr self, byte type, [Out] byte[] buf); static extern void ReportControlBlock_setPreconfiguredClient(IntPtr self, byte type, [Out] byte[] buf);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern string ReportControlBlock_getName(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ReportControlBlock_getRptEna(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ReportControlBlock_getRptID(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ReportControlBlock_getDataSet(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 ReportControlBlock_getConfRev(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 ReportControlBlock_getOptFlds(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 ReportControlBlock_getBufTm(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt16 ReportControlBlock_getSqNum(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 ReportControlBlock_getTrgOps(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 ReportControlBlock_getIntgPd(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ReportControlBlock_getGI(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ReportControlBlock_getPurgeBuf(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ReportControlBlock_getEntryId(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt64 ReportControlBlock_getTimeofEntry(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt16 ReportControlBlock_getResvTms(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ReportControlBlock_getOwner(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void Memory_free(IntPtr self);
public IntPtr self = IntPtr.Zero; public IntPtr self = IntPtr.Zero;
private string name = null;
private LogicalNode parent = null;
public ReportControlBlock(string name, LogicalNode parent, string rptId, bool isBuffered, public ReportControlBlock(string name, LogicalNode parent, string rptId, bool isBuffered,
string dataSetName, uint confRev, byte trgOps, byte options, uint bufTm, uint intgPd) string dataSetName, uint confRev, byte trgOps, byte options, uint bufTm, uint intgPd)
{ {
self = ReportControlBlock_create(name, parent.self, rptId, isBuffered, dataSetName, confRev, trgOps, options, bufTm, intgPd); self = ReportControlBlock_create(name, parent.self, rptId, isBuffered, dataSetName, confRev, trgOps, options, bufTm, intgPd);
parent.AddRcb(this);
this.parent = parent;
}
internal ReportControlBlock(IntPtr self, LogicalNode parent)
{
this.parent = parent;
this.self = self;
parent.AddRcb(this);
} }
public void SetPreconfiguredClient(byte[] clientAddress) public void SetPreconfiguredClient(byte[] clientAddress)
@ -1316,6 +1389,187 @@ namespace IEC61850
else if (clientAddress.Length == 6) else if (clientAddress.Length == 6)
ReportControlBlock_setPreconfiguredClient(self, 6, clientAddress); ReportControlBlock_setPreconfiguredClient(self, 6, clientAddress);
} }
public string Name
{
get
{
if (name == null)
{
name = ReportControlBlock_getName(self);
}
return name;
}
}
public LogicalNode Parent
{
get
{
return parent;
}
}
public bool RptEna
{
get
{
return ReportControlBlock_getRptEna(self);
}
}
public string RptID
{
get
{
IntPtr rptIdPtr = ReportControlBlock_getRptID(self);
string rptId = Marshal.PtrToStringAnsi(rptIdPtr);
Memory_free(rptIdPtr);
return rptId;
}
}
public string DataSet
{
get
{
IntPtr dataSetPtr = ReportControlBlock_getDataSet(self);
string dataSet = Marshal.PtrToStringAnsi(dataSetPtr);
Memory_free(dataSetPtr);
return dataSet;
}
}
public UInt32 ConfRev
{
get
{
return ReportControlBlock_getConfRev(self);
}
}
public ReportOptions OptFlds
{
get
{
return (ReportOptions)ReportControlBlock_getOptFlds(self);
}
}
public UInt32 BufTm
{
get
{
return ReportControlBlock_getBufTm(self);
}
}
public UInt16 SqNum
{
get
{
return ReportControlBlock_getSqNum(self);
}
}
public TriggerOptions TrgOps
{
get
{
return (TriggerOptions)ReportControlBlock_getTrgOps(self);
}
}
public UInt32 IntgPd
{
get
{
return ReportControlBlock_getIntgPd(self);
}
}
public bool GI
{
get
{
return ReportControlBlock_getGI(self);
}
}
public bool PurgeBuf
{
get
{
return ReportControlBlock_getPurgeBuf(self);
}
}
public byte[] EntryID
{
get
{
IntPtr entryIdPtr = ReportControlBlock_getEntryId(self);
if (entryIdPtr != IntPtr.Zero)
{
byte[] entryId = null;
MmsValue octetStringVal = new MmsValue(entryIdPtr, true);
entryId = octetStringVal.getOctetString();
return entryId;
}
else
return null;
}
}
public UInt64 TimeofEntry
{
get
{
return ReportControlBlock_getTimeofEntry(self);
}
}
public UInt16 ResvTms
{
get
{
return ReportControlBlock_getResvTms(self);
}
}
public byte[] Owner
{
get
{
IntPtr mmsValuePtr = ReportControlBlock_getOwner(self);
if (mmsValuePtr != IntPtr.Zero)
{
byte[] owner = null;
MmsValue octetStringVal = new MmsValue(mmsValuePtr, true);
owner = octetStringVal.getOctetString();
return owner;
}
else
return null;
}
}
} }
/// <summary> /// <summary>
@ -1691,6 +1945,47 @@ namespace IEC61850
public delegate void GoCBEventHandler(MmsGooseControlBlock goCB, int cbEvent, object parameter); public delegate void GoCBEventHandler(MmsGooseControlBlock goCB, int cbEvent, object parameter);
/// <summary>
/// Report control block event types
/// </summary>
public enum RCBEventType
{
/// <summary>
/// parameter read by client (not implemented).
/// </summary>
GET_PARAMETER = 0,
/// <summary>
/// parameter set by client.
/// </summary>
SET_PARAMETER = 1,
/// <summary>
/// reservation canceled.
/// </summary>
UNRESERVED = 2,
/// <summary>
/// reservation
/// </summary>
RESERVED = 3,
/// <summary>
/// RCB enabled
/// </summary>
ENABLED = 4,
/// <summary>
/// RCB disabled
/// </summary>
DISABLED = 5,
/// <summary>
/// GI report triggered
/// </summary>
GI = 6,
/// <summary>
/// Purge buffer procedure executed
/// </summary>
PURGEBUF = 7
}
public delegate void RCBEventHandler(object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError);
public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, MmsValue value, public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, MmsValue value,
ClientConnection connection, object parameter); ClientConnection connection, object parameter);
@ -1917,6 +2212,12 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setGoCBHandler(IntPtr self, InternalGoCBEventHandler handler, IntPtr parameter); static extern void IedServer_setGoCBHandler(IntPtr self, InternalGoCBEventHandler handler, IntPtr parameter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void InternalRCBEventHandler(IntPtr paramter, IntPtr rcb, IntPtr connection, int eventType, string parameterName, int serviceError);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setRCBEventHandler(IntPtr self, InternalRCBEventHandler handler, IntPtr parameter);
private IntPtr self = IntPtr.Zero; private IntPtr self = IntPtr.Zero;
private InternalControlHandler internalControlHandlerRef = null; private InternalControlHandler internalControlHandlerRef = null;
@ -2561,6 +2862,70 @@ namespace IEC61850
} }
} }
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ReportControlBlock_getParent(IntPtr self);
private RCBEventHandler rcbEventHandler = null;
private object rcbEventHandlerParameter = null;
private InternalRCBEventHandler internalRCBEventHandler = null;
private void InternalRCBEventHandlerImplementation(IntPtr parameter, IntPtr rcb, IntPtr connection, int eventType, string parameterName, int serviceError)
{
if (rcbEventHandler != null)
{
ClientConnection con = null;
if (connection != IntPtr.Zero)
{
this.clientConnections.TryGetValue(connection, out con);
}
ReportControlBlock reportControlBlock = null;
if (rcb != IntPtr.Zero)
{
IntPtr lnPtr = ReportControlBlock_getParent(rcb);
if (lnPtr != IntPtr.Zero)
{
ModelNode lnModelNode = iedModel.GetModelNodeFromNodeRef(lnPtr);
if (lnModelNode != null)
{
LogicalNode ln = lnModelNode as LogicalNode;
if (ln.rcbs.TryGetValue(rcb, out reportControlBlock) == false)
{
reportControlBlock = new ReportControlBlock(rcb, ln);
}
}
}
}
rcbEventHandler.Invoke(rcbEventHandlerParameter, reportControlBlock, con, (RCBEventType)eventType, parameterName, (MmsDataAccessError)serviceError);
}
}
/// <summary>
/// Set a callback handler for RCB events
/// </summary>
/// <param name="handler">the callback handler</param>
/// <param name="parameter">user provided parameter that is passed to the callback handler</param>
public void SetRCBEventHandler(RCBEventHandler handler, object parameter)
{
rcbEventHandler = handler;
rcbEventHandlerParameter = parameter;
if (internalRCBEventHandler == null)
{
internalRCBEventHandler = new InternalRCBEventHandler(InternalRCBEventHandlerImplementation);
IedServer_setRCBEventHandler(self, internalRCBEventHandler, IntPtr.Zero);
}
}
} }
} }

@ -67,6 +67,25 @@ namespace server1
}, null); }, null);
iedServer.SetRCBEventHandler(delegate (object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError)
{
Console.WriteLine("RCB: " + rcb.Parent.GetObjectReference() + "." + rcb.Name + " event: " + eventType.ToString());
if (eventType == RCBEventType.ENABLED)
{
//Console.WriteLine(" RptID: " + rcb.RptID);
//Console.WriteLine(" DatSet: " + rcb.DataSet);
Console.WriteLine(" TrgOps: " + rcb.TrgOps.ToString());
}
if ((eventType == RCBEventType.SET_PARAMETER) || (eventType == RCBEventType.GET_PARAMETER))
{
Console.WriteLine(" param: " + parameterName);
Console.WriteLine(" result: " + serviceError.ToString());
}
}, null);
iedServer.Start(102); iedServer.Start(102);
if (iedServer.IsRunning()) if (iedServer.IsRunning())

@ -79,6 +79,27 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected,
printf("Connection closed\n"); printf("Connection closed\n");
} }
static void
rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
{
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER)) {
printf(" param: %s\n", parameterName);
printf(" result: %i\n", serviceError);
}
if (event == RCB_EVENT_ENABLE) {
char* rptId = ReportControlBlock_getRptID(rcb);
printf(" rptID: %s\n", rptId);
char* dataSet = ReportControlBlock_getDataSet(rcb);
printf(" datSet: %s\n", dataSet);
free(rptId);
free(dataSet);
}
}
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
@ -136,6 +157,8 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL);
/* By default access to variables with FC=DC and FC=CF is not allowed. /* By default access to variables with FC=DC and FC=CF is not allowed.
* This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used * This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used
* by iec61850_client_example1. * by iec61850_client_example1.

@ -1,7 +1,7 @@
/* /*
* iec61850_common.c * iec61850_common.c
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2022 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -70,6 +70,20 @@ Quality_fromMmsValue(const MmsValue* mmsValue)
return (Quality) MmsValue_getBitStringAsInteger(mmsValue); return (Quality) MmsValue_getBitStringAsInteger(mmsValue);
} }
MmsValue*
Quality_toMmsValue(Quality* self, MmsValue* mmsValue)
{
if (mmsValue == NULL) {
mmsValue = MmsValue_newBitString(13);
}
if (mmsValue) {
MmsValue_setBitStringFromInteger(mmsValue, *self);
}
return mmsValue;
}
Dbpos Dbpos
Dbpos_fromMmsValue(const MmsValue* mmsValue) Dbpos_fromMmsValue(const MmsValue* mmsValue)
{ {
@ -491,6 +505,25 @@ Timestamp_toMmsValue(Timestamp* self, MmsValue* mmsValue)
return convertedValue; return convertedValue;
} }
Timestamp*
Timestamp_fromMmsValue(Timestamp* self, MmsValue* mmsValue)
{
if (mmsValue->type == MMS_UTC_TIME) {
if (self == NULL)
self = Timestamp_create();
if (self) {
memcpy(self->val, mmsValue->value.utcTime, 8);
}
return self;
}
else {
return NULL;
}
}
char* char*
MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer) MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer)
{ {

@ -370,6 +370,9 @@ Quality_isFlagSet(Quality* self, int flag);
LIB61850_API Quality LIB61850_API Quality
Quality_fromMmsValue(const MmsValue* mmsValue); Quality_fromMmsValue(const MmsValue* mmsValue);
LIB61850_API MmsValue*
Quality_toMmsValue(Quality* self, MmsValue* mmsValue);
/** @} */ /** @} */
/** /**
@ -515,6 +518,17 @@ Timestamp_setByMmsUtcTime(Timestamp* self, const MmsValue* mmsValue);
LIB61850_API MmsValue* LIB61850_API MmsValue*
Timestamp_toMmsValue(Timestamp* self, MmsValue* mmsValue); Timestamp_toMmsValue(Timestamp* self, MmsValue* mmsValue);
/**
* \brief Get the Timestamp value from an MmsValue instance of type MMS_UTC_TIME
*
* \param self the Timestamp instance or NULL to create a new instance
* \param mmsValue the mmsValue instance of type MMS_UTC_TIME
*
* \return the updated Timestamp value or NULL in case of an error
*/
LIB61850_API Timestamp*
Timestamp_fromMmsValue(Timestamp* self, MmsValue* mmsValue);
/** /**
* \brief Get the version of the library as string * \brief Get the version of the library as string
* *

@ -211,6 +211,83 @@ ReportControlBlock_create(const char* name, LogicalNode* parent, const char* rpt
LIB61850_API void LIB61850_API void
ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clientType, const uint8_t* clientAddress); ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clientType, const uint8_t* clientAddress);
/**
* \brief Get the name of the RCB instance
*
* NOTE: the returned string is only valid during the lifetime of the ReportControlBlock instance!
*
* \param self the RCB instance
*
* \return the RCB instance name
*/
LIB61850_API const char*
ReportControlBlock_getName(ReportControlBlock* self);
/**
* \brief Is the RCB buffered or unbuffered?
*
* \param self the RCB instance
*
* \return true, in case of a buffered RCB, false otherwise
*/
LIB61850_API bool
ReportControlBlock_isBuffered(ReportControlBlock* self);
/**
* \brief Get the parent (LogicalNode) of the RCB instance
*
* \param self the RCB instance
*
* \return the parent (LogicalNode) of the RCB instance
*/
LIB61850_API LogicalNode*
ReportControlBlock_getParent(ReportControlBlock* self);
LIB61850_API char*
ReportControlBlock_getRptID(ReportControlBlock* self);
LIB61850_API int
ReportControlBlock_getRptEna(ReportControlBlock* self);
LIB61850_API char*
ReportControlBlock_getDataSet(ReportControlBlock* self);
LIB61850_API uint32_t
ReportControlBlock_getConfRev(ReportControlBlock* self);
LIB61850_API uint32_t
ReportControlBlock_getOptFlds(ReportControlBlock* self);
LIB61850_API uint32_t
ReportControlBlock_getBufTm(ReportControlBlock* self);
LIB61850_API uint16_t
ReportControlBlock_getSqNum(ReportControlBlock* self);
LIB61850_API uint32_t
ReportControlBlock_getTrgOps(ReportControlBlock* self);
LIB61850_API uint32_t
ReportControlBlock_getIntgPd(ReportControlBlock* self);
LIB61850_API bool
ReportControlBlock_getGI(ReportControlBlock* self);
LIB61850_API bool
ReportControlBlock_getPurgeBuf(ReportControlBlock* self);
LIB61850_API MmsValue*
ReportControlBlock_getEntryId(ReportControlBlock* self);
LIB61850_API uint64_t
ReportControlBlock_getTimeofEntry(ReportControlBlock* self);
LIB61850_API int16_t
ReportControlBlock_getResvTms(ReportControlBlock* self);
LIB61850_API MmsValue*
ReportControlBlock_getOwner(ReportControlBlock* self);
/** /**
* \brief create a new log control block (LCB) * \brief create a new log control block (LCB)
* *

@ -269,7 +269,9 @@ struct sReportControlBlock {
type can be one of (0 - no reservation, 4 - IPv4 client, 6 - IPv6 client) */ type can be one of (0 - no reservation, 4 - IPv4 client, 6 - IPv6 client) */
uint8_t clientReservation[17]; uint8_t clientReservation[17];
ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry
* at runtime reuse as pointer to ReportControl instance!
**/
}; };
struct sLogControlBlock { struct sLogControlBlock {

@ -3,7 +3,7 @@
* *
* IEC 61850 server API for libiec61850. * IEC 61850 server API for libiec61850.
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2022 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -1534,6 +1534,47 @@ IedServer_updateCtlModel(IedServer self, DataObject* ctlObject, ControlModel val
/**@}*/ /**@}*/
/**
* @defgroup IEC61850_SERVER_RCB Server side report control block (RCB) handling
*
* @{
*/
typedef enum {
RCB_EVENT_GET_PARAMETER, /* << parameter read by client (not implemented) */
RCB_EVENT_SET_PARAMETER, /* << parameter set by client */
RCB_EVENT_UNRESERVED, /* << RCB reservation canceled */
RCB_EVENT_RESERVED, /* << RCB reserved */
RCB_EVENT_ENABLE, /* << RCB enabled */
RCB_EVENT_DISABLE, /* << RCB disabled */
RCB_EVENT_GI, /* << GI report triggered */
RCB_EVENT_PURGEBUF /* << Purge buffer procedure executed */
} IedServer_RCBEventType;
/**
* \brief Callback that is called in case of RCB event
*
* \param parameter user provided parameter
* \param rcb affected report control block
* \param connection client connection that is involved
* \param event event type
* \param parameterName name of the parameter in case of RCB_EVENT_SET_PARAMETER
* \param serviceError service error in case of RCB_EVENT_SET_PARAMETER
*/
typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError);
/**
* \brief Set a handler for report control block (RCB) events
*
* \param self the instance of IedServer to operate on.
* \param handler the event handler to be used
* \param parameter a user provided parameter that is passed to the handler.
*/
LIB61850_API void
IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter);
/**@}*/
/** /**
* @defgroup IEC61850_SERVER_SVCB Server side sampled values control block (SVCB) handling * @defgroup IEC61850_SERVER_SVCB Server side sampled values control block (SVCB) handling
* *

@ -1,7 +1,7 @@
/* /*
* mms_mapping_internal.h * mms_mapping_internal.h
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2022 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -328,6 +328,9 @@ struct sMmsMapping {
IedConnectionIndicationHandler connectionIndicationHandler; IedConnectionIndicationHandler connectionIndicationHandler;
void* connectionIndicationHandlerParameter; void* connectionIndicationHandlerParameter;
IedServer_RCBEventHandler rcbEventHandler;
void* rcbEventHandlerParameter;
}; };
#endif /* MMS_MAPPING_INTERNAL_H_ */ #endif /* MMS_MAPPING_INTERNAL_H_ */

@ -53,8 +53,12 @@ typedef struct {
LogicalNode* parentLN; LogicalNode* parentLN;
MmsValue* rcbValues; MmsValue* rcbValues;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore rcbValuesLock;
#endif
MmsValue* inclusionField; MmsValue* inclusionField;
MmsValue* confRev;
DataSet* dataSet; DataSet* dataSet;
bool isDynamicDataSet; bool isDynamicDataSet;
@ -107,6 +111,7 @@ typedef struct {
MmsValue* timeOfEntry; MmsValue* timeOfEntry;
ReportControlBlock* rcb; ReportControlBlock* rcb;
ReportControlBlock* sibling; /* backup sibling field of original ReportControlBlock */
IedServer server; IedServer server;
} ReportControl; } ReportControl;
@ -136,7 +141,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
MmsServerConnection connection); MmsServerConnection connection);
LIB61850_INTERNAL void LIB61850_INTERNAL void
ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, char* elementName); ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName);
LIB61850_INTERNAL void LIB61850_INTERNAL void
Reporting_activateBufferedReports(MmsMapping* self); Reporting_activateBufferedReports(MmsMapping* self);

@ -584,6 +584,13 @@ IedServer_createWithTlsSupport(IedModel* dataModel, TLSConfiguration tlsConfigur
return IedServer_createWithConfig(dataModel, tlsConfiguration, NULL); return IedServer_createWithConfig(dataModel, tlsConfiguration, NULL);
} }
void
IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter)
{
self->mmsMapping->rcbEventHandler = handler;
self->mmsMapping->rcbEventHandlerParameter = parameter;
}
void void
IedServer_destroy(IedServer self) IedServer_destroy(IedServer self)
{ {

@ -2034,6 +2034,24 @@ MmsMapping_create(IedModel* model, IedServer iedServer)
MmsMapping_destroy(self); MmsMapping_destroy(self);
self = NULL; self = NULL;
} }
else {
LinkedList rcElem = LinkedList_getNext(self->reportControls);
while (rcElem) {
ReportControl* rc = (ReportControl*)LinkedList_getData(rcElem);
/* backup original sibling of ReportControlBlock */;
rc->sibling = rc->rcb->sibling;
/* reuse ReportControlBlock.sibling as reference to runtime information (ReportControl) */
rc->rcb->sibling = (ReportControlBlock*)rc;
/* set runtime mode flag (indicate that sibling field contains now runtime information reference!) */
rc->rcb->trgOps |= 64;
rcElem = LinkedList_getNext(rcElem);
}
}
return self; return self;
} }
@ -3075,15 +3093,28 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo
char* elementName = MmsMapping_getNextNameElement(reportName); char* elementName = MmsMapping_getNextNameElement(reportName);
ReportControl_readAccess(rc, self, elementName); ReportControl_readAccess(rc, self, connection, elementName);
MmsValue* value = NULL; MmsValue* value = NULL;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(rc->rcbValuesLock);
#endif
if (elementName != NULL) if (elementName != NULL)
value = ReportControl_getRCBValue(rc, elementName); value = ReportControl_getRCBValue(rc, elementName);
else else
value = rc->rcbValues; value = rc->rcbValues;
if (value) {
value = MmsValue_clone(value);
MmsValue_setDeletableRecursive(value);
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(rc->rcbValuesLock);
#endif
retValue = value; retValue = value;
goto exit_function; goto exit_function;

File diff suppressed because it is too large Load Diff

@ -383,6 +383,24 @@ ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clie
} }
} }
const char*
ReportControlBlock_getName(ReportControlBlock* self)
{
return self->name;
}
LogicalNode*
ReportControlBlock_getParent(ReportControlBlock* self)
{
return self->parent;
}
bool
ReportControlBlock_isBuffered(ReportControlBlock* self)
{
return self->buffered;
}
#if (CONFIG_IEC61850_SETTING_GROUPS == 1) #if (CONFIG_IEC61850_SETTING_GROUPS == 1)
static void static void
LogicalNode_addSettingGroupControlBlock(LogicalNode* self, SettingGroupControlBlock* sgcb) LogicalNode_addSettingGroupControlBlock(LogicalNode* self, SettingGroupControlBlock* sgcb)

@ -1,7 +1,7 @@
/* /*
* mms_server_libinternal.h * mms_server_libinternal.h
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2022 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *

@ -1,7 +1,7 @@
/* /*
* mms_read_service.c * mms_read_service.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2022 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -98,10 +98,9 @@ addComplexValueToResultList(MmsVariableSpecification* namedVariable,
LinkedList typedValues, MmsServerConnection connection, LinkedList typedValues, MmsServerConnection connection,
MmsDomain* domain, char* nameIdStr) MmsDomain* domain, char* nameIdStr)
{ {
MmsValue* value = addNamedVariableValue(namedVariable, connection, domain, nameIdStr); MmsValue* value = addNamedVariableValue(namedVariable, connection, domain, nameIdStr);
if (value != NULL) if (value)
LinkedList_add(typedValues, value); LinkedList_add(typedValues, value);
} }
@ -109,9 +108,8 @@ addComplexValueToResultList(MmsVariableSpecification* namedVariable,
static void static void
appendValueToResultList(MmsValue* value, LinkedList values) appendValueToResultList(MmsValue* value, LinkedList values)
{ {
if (value)
if (value != NULL ) LinkedList_add(values, value);
LinkedList_add(values, value);
} }
static void static void
@ -126,15 +124,15 @@ deleteValueList(LinkedList values)
{ {
LinkedList value = LinkedList_getNext(values); LinkedList value = LinkedList_getNext(values);
while (value != NULL ) { while (value) {
MmsValue* typedValue = (MmsValue*) (value->data); MmsValue* typedValue = (MmsValue*) (value->data);
MmsValue_deleteConditional(typedValue); MmsValue_deleteConditional(typedValue);
value = LinkedList_getNext(value); value = LinkedList_getNext(value);
} }
LinkedList_destroyStatic(values); LinkedList_destroyStatic(values);
} }
static bool static bool

Loading…
Cancel
Save