Merge branch 'v1.5_feature_260' into v1.5

pull/367/head
Michael Zillgith 4 years ago
commit 01b1f96590

@ -1,7 +1,7 @@
/*
* IEC61850ClientAPI.cs
*
* Copyright 2014-2019 Michael Zillgith
* Copyright 2014-2021 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -625,13 +625,31 @@ namespace IEC61850
int fc, IedConnection_GetVariableSpecificationHandler handler, IntPtr parameter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void IedConnection_ReadDataSetHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr dataSet);
private delegate void IedConnection_ReadDataSetHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSet);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32
IedConnection_readDataSetValuesAsync(IntPtr self, out int error, string dataSetReference, IntPtr dataSet,
IedConnection_ReadDataSetHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32
IedConnection_createDataSetAsync(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet,
IedConnection_GenericServiceHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32
IedConnection_deleteDataSetAsync(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference,
IedConnection_GenericServiceHandler handler, IntPtr parameter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void IedConnection_GetDataSetDirectoryHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSetDirectory, [MarshalAs(UnmanagedType.I1)] bool isDeletable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32
IedConnection_getDataSetDirectoryAsync(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference,
IedConnection_GetDataSetDirectoryHandler handler, IntPtr parameter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void IedConnection_GetRCBValuesHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr rcb);
@ -1742,9 +1760,6 @@ namespace IEC61850
return invokeId;
}
/// <summary>
/// Abort (close) the connection.
/// </summary>
@ -2004,6 +2019,47 @@ namespace IEC61850
}
/// <summary>
/// Create a new data set - asynchronous version.
/// </summary>
/// <description>This function creates a new data set at the server. The data set consists of the members defined
/// by the list of object references provided.</description>
/// <param name="dataSetReference">The object reference of the data set</param>
/// <param name="dataSetElements">A list of object references of the data set elements</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 CreateDataSetAsync(string dataSetReference, List<string> dataSetElements, GenericServiceHandler handler, object parameter)
{
int error = 0;
IntPtr linkedList = LinkedList_create();
foreach (string dataSetElement in dataSetElements)
{
IntPtr dataSetElementHandle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(dataSetElement);
LinkedList_add(linkedList, dataSetElementHandle);
}
Tuple<GenericServiceHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
UInt32 invokeId = IedConnection_createDataSetAsync(connection, out error, dataSetReference, linkedList, nativeGenericServiceHandler, GCHandle.ToIntPtr(handle));
LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Create data set failed", error);
}
return invokeId;
}
/// <summary>
/// Delete a data set.
/// </summary>
@ -2024,6 +2080,35 @@ namespace IEC61850
return isDeleted;
}
/// <summary>
/// Delete a data set - asynchronous version.
/// </summary>
/// <description>This function will delete a data set at the server. This function may fail if the data set is not
/// deletable.</description>
/// <param name="dataSetReference">The object reference of the data set</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 DeleteDataSetAsync(string dataSetReference, GenericServiceHandler handler, object parameter)
{
int error = 0;
Tuple<GenericServiceHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
UInt32 invokeId = IedConnection_deleteDataSetAsync(connection, out error, dataSetReference, nativeGenericServiceHandler, GCHandle.ToIntPtr(handle));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Delete data set failed", error);
}
return invokeId;
}
/// <summary>
/// Get the directory of the data set.
/// </summary>
@ -2073,6 +2158,72 @@ namespace IEC61850
return newList;
}
/// <summary>
/// Get data set directory handler.
/// </summary>
/// <param name="invokeId">The invoke ID of the reqeust triggering this callback</param>
/// <param name="parameter">user provided callback parameter</param>
/// <param name="err">Error code of response or timeout error in case of a response timeout</param>
/// <param name="dataSetDirectory">the list of data set entry references</param>
/// <param name="isDeletable">data set can be deleted by a client (dynamic data set)</param>
public delegate void GetDataSetDirectoryHandler(UInt32 invokeId, object parameter, IedClientError err, List<string> dataSetDirectory, bool isDeletable);
private void nativeGetDataSetDirectoryHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSetDirectory, bool isDeletable)
{
GCHandle handle = GCHandle.FromIntPtr(parameter);
Tuple<GetDataSetDirectoryHandler, object> callbackInfo = handle.Target as Tuple<GetDataSetDirectoryHandler, object>;
GetDataSetDirectoryHandler handler = callbackInfo.Item1;
object handlerParameter = callbackInfo.Item2;
IntPtr element = LinkedList_getNext(dataSetDirectory);
handle.Free();
List<string> newList = new List<string>();
while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject);
element = LinkedList_getNext(element);
}
LinkedList_destroy(dataSetDirectory);
handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable);
}
/// <summary>
/// Read the data set directory - asynchronous version
/// </summary>
/// <returns>The data set directory async.</returns>
/// <param name="dataSetReference">Data set reference.</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 GetDataSetDirectoryAsync(string dataSetReference, GetDataSetDirectoryHandler handler, object parameter)
{
int error = 0;
Tuple<GetDataSetDirectoryHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
UInt32 invokeId = IedConnection_getDataSetDirectoryAsync(connection, out error, dataSetReference, nativeGetDataSetDirectoryHandler, GCHandle.ToIntPtr(handle));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Get data set directory failed", error);
}
return invokeId;
}
/// <summary>
/// Read object handler.

@ -3009,7 +3009,6 @@ void
IedConnection_createDataSet(IedConnection self, IedClientError* error, const char* dataSetReference,
LinkedList /* <char*> */dataSetElements)
{
char domainIdBuffer[65];
char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1];
@ -3153,6 +3152,250 @@ exit_function:
return isDeleted;
}
static void
deleteNamedVariableListHandler(uint32_t invokeId, void* parameter, MmsError mmsError, bool success)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler)call->callback;
IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError);
if (err == IED_ERROR_OK) {
if (success == false)
err = IED_ERROR_ACCESS_DENIED;
}
handler(invokeId, call->callbackParameter, err);
iedConnection_releaseOutstandingCall(self, call);
}
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t
IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, const char* dataSetReference,
IedConnection_GenericServiceHandler handler, void* parameter)
{
*error = IED_ERROR_OK;
char domainIdBuf[65];
char *domainId = domainIdBuf;
char itemId[DATA_SET_MAX_NAME_LENGTH + 1];
bool isAssociationSpecific = false;
int dataSetReferenceLength = strlen(dataSetReference);
if (dataSetReference[0] != '@') {
if ((dataSetReference[0] == '/')
|| (strchr(dataSetReference, '/') == NULL)) {
domainId = NULL;
if (dataSetReference[0] == '/')
strcpy(itemId, dataSetReference + 1);
else
strcpy(itemId, dataSetReference);
}
else {
if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference,
domainId) == NULL) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
const char *itemIdString = dataSetReference + strlen(domainId) + 1;
if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
StringUtils_copyStringToBuffer(itemIdString, itemId);
StringUtils_replace(itemId, '.', '$');
}
}
else {
if (dataSetReferenceLength > 33) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
strcpy(itemId, dataSetReference + 1);
isAssociationSpecific = true;
}
MmsError mmsError;
if ((domainId == NULL) || (itemId == NULL)) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL) {
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
return 0;
}
call->callback = handler;
call->callbackParameter = parameter;
call->invokeId = 0;
if (isAssociationSpecific) {
MmsConnection_deleteAssociationSpecificNamedVariableListAsync(self->connection, &(call->invokeId), &mmsError, itemId, deleteNamedVariableListHandler, self);
}
else {
MmsConnection_deleteNamedVariableListAsync(self->connection, &(call->invokeId), &mmsError, domainId, itemId, deleteNamedVariableListHandler, self);
}
if (*error != IED_ERROR_OK) {
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId;
}
static void
createDataSetAsyncHandler(uint32_t invokeId, void* parameter, MmsError mmsError, bool success)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler)call->callback;
IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError);
if (err == IED_ERROR_OK) {
if (success == false)
err = IED_ERROR_ACCESS_DENIED;
}
handler(invokeId, call->callbackParameter, err);
iedConnection_releaseOutstandingCall(self, call);
}
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t
IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, const char* dataSetReference, LinkedList /* char* */ dataSetElements,
IedConnection_GenericServiceHandler handler, void* parameter)
{
uint32_t invokeId = 0;
char domainIdBuffer[65];
char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1];
const char* domainId;
const char* itemId;
bool isAssociationSpecific = false;
if (dataSetReference[0] != '@') {
if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) {
domainId = NULL;
if (dataSetReference[0] == '/')
itemId = dataSetReference + 1;
else
itemId = dataSetReference;
}
else {
domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer);
if (domainId == NULL) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
goto exit_function;
}
int domainIdLength = strlen(domainId);
if ((strlen(dataSetReference) - domainIdLength - 1) > 32) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
goto exit_function;
}
char* itemIdRef = StringUtils_copyStringToBuffer(dataSetReference + domainIdLength + 1, itemIdBuffer);
StringUtils_replace(itemIdRef, '.', '$');
itemId = itemIdRef;
}
}
else {
itemId = dataSetReference + 1;
isAssociationSpecific = true;
}
MmsError mmsError;
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL) {
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
goto exit_function;
}
call->callback = handler;
call->callbackParameter = parameter;
call->invokeId = 0;
LinkedList dataSetEntries = LinkedList_create();
LinkedList dataSetElement = LinkedList_getNext(dataSetElements);
while (dataSetElement != NULL) {
MmsVariableAccessSpecification* dataSetEntry =
MmsMapping_ObjectReferenceToVariableAccessSpec((char*) dataSetElement->data);
if (dataSetEntry == NULL) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
goto cleanup_list;
}
LinkedList_add(dataSetEntries, (void*) dataSetEntry);
dataSetElement = LinkedList_getNext(dataSetElement);
}
if (isAssociationSpecific) {
MmsConnection_defineNamedVariableListAssociationSpecificAsync(self->connection, &(call->invokeId),
&mmsError, itemId, dataSetEntries, createDataSetAsyncHandler, self);
}
else {
MmsConnection_defineNamedVariableListAsync(self->connection, &(call->invokeId),
&mmsError, domainId, itemId, dataSetEntries, createDataSetAsyncHandler, self);
}
invokeId = call->invokeId;
*error = iedConnection_mapMmsErrorToIedError(mmsError);
cleanup_list:
/* delete list and all elements */
LinkedList_destroyDeep(dataSetEntries, (LinkedListValueDeleteFunction) MmsVariableAccessSpecification_destroy);
exit_function:
return invokeId;
}
LinkedList /* <char*> */
IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, const char* dataSetReference, bool* isDeletable)
{
@ -3219,8 +3462,8 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con
dataSetMembers = LinkedList_create();
while (entry != NULL) {
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*) entry->data;
while (entry) {
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(entry);
char* objectReference = MmsMapping_varAccessSpecToObjectReference(varAccessSpec);
@ -3241,6 +3484,120 @@ exit_function:
return dataSetMembers;
}
static void
getDataSetDirectoryAsyncHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsVariableAccessSpecification*> */ specs, bool deletable)
{
IedConnection self = (IedConnection)parameter;
IedClientError err = IED_ERROR_OK;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
LinkedList dataSetMembers = NULL;
if (mmsError != MMS_ERROR_NONE)
err = iedConnection_mapMmsErrorToIedError(mmsError);
if (specs) {
dataSetMembers = LinkedList_create();
LinkedList specElem = LinkedList_getNext(specs);
while (specElem) {
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(specElem);
char* objectReference = MmsMapping_varAccessSpecToObjectReference(varAccessSpec);
LinkedList_add(dataSetMembers, objectReference);
specElem = LinkedList_getNext(specElem);
}
}
IedConnection_GetDataSetDirectoryHandler handler = (IedConnection_GetDataSetDirectoryHandler)call->callback;
if (handler)
handler(call->invokeId, call->callbackParameter, err, dataSetMembers, deletable);
}
if (specs)
LinkedList_destroyDeep(specs, (LinkedListValueDeleteFunction) MmsVariableAccessSpecification_destroy);
}
uint32_t
IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error, const char* dataSetReference,
IedConnection_GetDataSetDirectoryHandler handler, void* parameter)
{
uint32_t invokeId = 0;
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL) {
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
return 0;
}
call->callback = handler;
call->callbackParameter = parameter;
call->invokeId = 0;
char domainIdBuffer[65];
char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1];
const char* domainId = NULL;
const char* itemId = NULL;
bool isAssociationSpecific = false;
if (dataSetReference[0] != '@') {
if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) {
domainId = NULL;
if (dataSetReference[0] == '/')
itemId = dataSetReference + 1;
else
itemId = dataSetReference;
}
else {
domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer);
if (domainId == NULL) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
goto exit_function;
}
const char* itemIdRef = dataSetReference + strlen(domainId) + 1;
if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
goto exit_function;
}
char* itemIdRefInBuffer = StringUtils_copyStringToBuffer(itemIdRef, itemIdBuffer);
StringUtils_replace(itemIdRefInBuffer, '.', '$');
itemId = itemIdRefInBuffer;
}
}
else {
itemId = dataSetReference + 1;
isAssociationSpecific = true;
}
MmsError mmsError = MMS_ERROR_NONE;
if (isAssociationSpecific)
MmsConnection_readNamedVariableListDirectoryAssociationSpecificAsync(self->connection, &(call->invokeId), &mmsError, itemId, getDataSetDirectoryAsyncHandler, self);
else
MmsConnection_readNamedVariableListDirectoryAsync(self->connection, &(call->invokeId), &mmsError, domainId, itemId, getDataSetDirectoryAsyncHandler, self);
*error = iedConnection_mapMmsErrorToIedError(mmsError);
exit_function:
return invokeId;
}
ClientDataSet
IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference,
ClientDataSet dataSet)

@ -1,7 +1,7 @@
/*
* iec61850_client.h
*
* Copyright 2013-2019 Michael Zillgith
* Copyright 2013-2021 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -1771,6 +1771,31 @@ IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error,
LIB61850_API void
IedConnection_createDataSet(IedConnection self, IedClientError* error, const char* dataSetReference, LinkedList /* char* */ dataSetElements);
/**
* \brief create a new data set at the connected server device
*
* This function creates a new data set at the server. The parameter dataSetReference is the name of the new data set
* to create. It is either in the form LDName/LNodeName.dataSetName for permanent domain or VMD scope data sets or
* @dataSetName for an association specific data set. If the LDName part of the reference is missing the resulting
* data set will be of VMD scope.
*
* The dataSetElements parameter contains a linked list containing the object references of FCDs or FCDAs. The format of
* this object references is LDName/LNodeName.item(arrayIndex)component[FC].
*
* \param connection the connection object
* \param error the error code if an error occurs
* \param dataSetReference object reference of the data set
* \param dataSetElements a list of object references defining the members of the new data set
*
* \param handler the callback handler that is called when the response is received or timeout
* \param parameter user provided parameter that is passed to the callback handler
*
* \return the invoke ID of the request
*/
LIB61850_API uint32_t
IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, const char* dataSetReference, LinkedList /* char* */ dataSetElements,
IedConnection_GenericServiceHandler handler, void* parameter);
/**
* \brief delete a deletable data set at the connected server device
*
@ -1787,9 +1812,29 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, const cha
LIB61850_API bool
IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const char* dataSetReference);
/**
* \brief delete a deletable data set at the connected server device - asynchronous version
*
* This function deletes a data set at the server. The parameter dataSetReference is the name of the data set
* to delete. It is either in the form LDName/LNodeName.dataSetName or @dataSetName for an association specific data set.
*
* The data set was deleted successfully when the callback parameter "error" is IED_ERROR_OK. Otherwise the "error"
* parameter contains a particular error code.
*
* \param connection the connection object
* \param error the error code if an error occurs
* \param dataSetReference object reference of the data set
* \param handler the callback handler that is called when the response is received or timeout
* \param parameter user provided parameter that is passed to the callback handler
*
* \return the invoke ID of the request
*/
LIB61850_API uint32_t
IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, const char* dataSetReference,
IedConnection_GenericServiceHandler handler, void* parameter);
/**
* \brief returns the object references of the elements of a data set
* \brief read the data set directory
*
* The return value contains a linked list containing the object references of FCDs or FCDAs. The format of
* this object references is LDName/LNodeName.item(arrayIndex)component[FC].
@ -1805,6 +1850,34 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha
LIB61850_API LinkedList /* <char*> */
IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, const char* dataSetReference, bool* isDeletable);
/**
* \brief GetDataSetDirectory response or timeout callback
*
* \param dataSetDirectory a linked list containing the object references of FCDs or FCDAs. The format of
* this object references is LDName/LNodeName.item(arrayIndex)component[FC].
* \param isDeletable this is an output parameter indicating that the requested data set is deletable by clients.
*/
typedef void
(*IedConnection_GetDataSetDirectoryHandler) (uint32_t invokeId, void* parameter, IedClientError err, LinkedList /* <char*> */ dataSetDirectory, bool isDeletable);
/**
* \brief read the data set directory - asynchronous version
*
* The result data is a linked list containing the object references of FCDs or FCDAs. The format of
* this object references is LDName/LNodeName.item(arrayIndex)component[FC].
*
* \param connection the connection object
* \param[out] error the error code if an error occurs
* \param dataSetReference object reference of the data set
* \param handler the callback handler that is called when the response is received or timeout
* \param parameter user provided parameter that is passed to the callback handler
*
* \return the invoke ID of the request
*/
LIB61850_API uint32_t
IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error, const char* dataSetReference,
IedConnection_GetDataSetDirectoryHandler handler, void* parameter);
/**
* \brief Write the data set values to the server
*

@ -291,7 +291,7 @@ mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeB
const char* domainId, const char* listNameId);
LIB61850_INTERNAL bool
mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* invokeId);
mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* invokeId, long* numberDeleted, long* numberMatched);
LIB61850_INTERNAL void
mmsClient_createDeleteAssociationSpecificNamedVariableListRequest(

@ -804,9 +804,19 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
else {
bool success = false;
if (mmsClient_parseDeleteNamedVariableListResponse(response, NULL))
long numberMatched = 0;
long numberDeleted = 0;
if (mmsClient_parseDeleteNamedVariableListResponse(response, NULL, &numberDeleted, &numberMatched))
success = true;
if (numberMatched == 0)
err = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT;
else {
if (numberDeleted == 0)
err = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED;
}
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, success);
}
}

@ -117,7 +117,7 @@ mmsClient_createDeleteAssociationSpecificNamedVariableListRequest(
}
bool
mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* invokeId)
mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* invokeId, long* numberDeleted, long* numberMatched)
{
MmsPdu_t* mmsPdu = 0;
@ -138,11 +138,10 @@ mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* in
DeleteNamedVariableListResponse_t* response =
&(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.deleteNamedVariableList);
long numberDeleted;
asn_INTEGER2long(&(response->numberDeleted), numberDeleted);
asn_INTEGER2long(&(response->numberMatched), numberMatched);
asn_INTEGER2long(&(response->numberDeleted), &numberDeleted);
if (numberDeleted == 1)
if (*numberDeleted == 1)
retVal = true;
}
}

Loading…
Cancel
Save