- Implementation of functions IedConnection_getGoCBValuesAsync and IedConnection_setGoCBValuesAsync (LIB61850-344)

pull/521/head
Michael Zillgith 1 year ago
parent 31bbd1d6da
commit 8aa3646895

@ -12,6 +12,7 @@ New features and improvements:
- Java tools: Support for time stamp Val elements
- IedServer: added configuration options to IedServerConfig to make RCB elements read-only (LIB61850-404)
- .NET API: Added functions SetReportSetting and GetReportSetting to IedServerConfig (LIB61850-404)
- IED client: added functions IedConnection_setRCBValuesAsync and IedConnection_getRCBValuesAsync (LIB61850-334)
- TLS: TLS version 1.3 can be supported when mbedtls 3.6 is used when compiling the library (using mbedtls 2.28 is still possible)
- BETA: Support for R-GOOSE and R-SV
- BETA: SNTP client code

@ -27,6 +27,9 @@ add_subdirectory(iec61850_client_example_array)
add_subdirectory(iec61850_client_example_files)
add_subdirectory(iec61850_client_example_async)
add_subdirectory(iec61850_client_file_async)
add_subdirectory(iec61850_client_example_rcbAsync)
add_subdirectory(iec61850_client_example_ClientGooseControl)
add_subdirectory(iec61850_client_example_ClientGooseControlAsync)
if (${BUILD_SNTP_CLIENT_EXAMPLES})
add_subdirectory(sntp_example)

@ -29,6 +29,9 @@ EXAMPLE_DIRS += iec61850_9_2_LE_example
EXAMPLE_DIRS += iec61850_sv_client_example
EXAMPLE_DIRS += sv_publisher
EXAMPLE_DIRS += sv_subscriber
EXAMPLE_DIRS += iec61850_client_example_rcbAsync
EXAMPLE_DIRS += iec61850_client_example_ClientGooseControl
EXAMPLE_DIRS += iec61850_client_example_ClientGooseControlAsync
MODEL_DIRS += server_example_simple
MODEL_DIRS += server_example_basic_io

@ -152,6 +152,7 @@ close_connection:
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
Thread_sleep(60000);
}
IedConnection_destroy(con);

@ -0,0 +1,17 @@
set(iec61850_client_example_ClientGooseControl_SRCS
client_example_ClientGooseControl.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_ClientGooseControl_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_ClientGooseControl
${iec61850_client_example_ClientGooseControl_SRCS}
)
target_link_libraries(iec61850_client_example_ClientGooseControl
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_ClientGooseControl
PROJECT_SOURCES = client_example_ClientGooseControl.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,83 @@
/*
* client_example_ClientGooseControl.c
*
* This example is intended to be used with server_example_basic_io or server_example_goose.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
int main(int argc, char** argv)
{
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK)
{
/*Read GoCB Values*/
ClientGooseControlBlock goCB = IedConnection_getGoCBValues(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL);
bool GoEna = ClientGooseControlBlock_getGoEna(goCB);
printf("GoEna Value: %d\n", GoEna);
const char* id = ClientGooseControlBlock_getGoID(goCB);
printf("GoID Value: %s\n", id);
const char* datset = ClientGooseControlBlock_getDatSet(goCB);
printf("GoDatset Value: %s\n", datset);
/*Update Go CB Values locally*/
ClientGooseControlBlock_setGoID(goCB, "analog");
ClientGooseControlBlock_setDatSet(goCB, "simpleIOGenericIO/LLN0$AnalogValues");
ClientGooseControlBlock_setGoEna(goCB, false);
/*Update Go CB Values to server (Throws error because only GoEna is writeable)*/
IedConnection_setGoCBValues(con, &error, goCB, GOCB_ELEMENT_GO_ID | GOCB_ELEMENT_DATSET | GOCB_ELEMENT_GO_ENA, true);
if (error != IED_ERROR_OK)
printf("Fail to Set Values to Server (code: %i)\n", error);
/*Test to see if the values were updated correctly on the server*/
goCB = IedConnection_getGoCBValues(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL);
bool GoEnaUpdate = ClientGooseControlBlock_getGoEna(goCB);
printf("GoEna Value: %d\n", GoEnaUpdate);
const char* idUpdate = ClientGooseControlBlock_getGoID(goCB);
printf("GoID Value: %s\n", idUpdate);
const char* datsetUpdate = ClientGooseControlBlock_getDatSet(goCB);
printf("GoDatset Value: %s\n", datsetUpdate);
printf("\n");
Thread_sleep(50000);
close_connection:
IedConnection_close(con);
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -0,0 +1,17 @@
set(iec61850_client_example_ClientGooseControlAsync_SRCS
client_example_ClientGooseControlAsync.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_ClientGooseControlAsync_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_ClientGooseControlAsync
${iec61850_client_example_ClientGooseControlAsync_SRCS}
)
target_link_libraries(iec61850_client_example_ClientGooseControlAsync
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_ClientGooseControlAsync
PROJECT_SOURCES = client_example_ClientGooseControlAsync.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,142 @@
/*
* client_example_ClientGooseControlAsync.c
*
* This example is intended to be used with server_example_goose.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static ClientGooseControlBlock GOCB = NULL;
static void
getGoCBValuesHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientGooseControlBlock goCB)
{
if (err == IED_ERROR_OK)
{
if (goCB)
{
printf("Access to GoCB\n");
bool GoEna = ClientGooseControlBlock_getGoEna(goCB);
printf("GoEna Value : % d\n", GoEna);
const char* id = ClientGooseControlBlock_getGoID(goCB);
printf("GoID Value: %s\n", id);
const char* datset = ClientGooseControlBlock_getDatSet(goCB);
printf("GoDatset Value: %s\n", datset);
GOCB = goCB;
}
}
else {
printf("Failed to get GoCV values (err=%i)\n", err);
}
}
static void
genericServiceHandler(uint32_t invokeId, void* parameter, IedClientError err)
{
if (err == IED_ERROR_OK) {
printf("Set GoCB Values successful");
}
else {
printf("Error triggering a report (code: %i)\n", err);
}
}
int
main(int argc, char** argv)
{
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK)
{
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED)
{
if (IedConnection_getState(con) == IED_STATE_CLOSED)
{
success = false;
break;
}
Thread_sleep(10);
}
if (success)
{
/*Read GoCB Values*/
IedConnection_getGoCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL, getGoCBValuesHandler, NULL);
if (error != IED_ERROR_OK) {
printf("getGoCBValues service error! %i\n", error);
}
while (GOCB == NULL) {}
if (GOCB != NULL)
{
/*Update Go CB Values locally*/
ClientGooseControlBlock_setGoID(GOCB, "analog");
ClientGooseControlBlock_setDatSet(GOCB, "simpleIOGenericIO/LLN0$AnalogValues");
ClientGooseControlBlock_setGoEna(GOCB, false);
/*Update Go CB Values to server (Throws error because only GoEna is writeable)*/
IedConnection_setGoCBValuesAsync(con, &error, GOCB, GOCB_ELEMENT_GO_ID | GOCB_ELEMENT_DATSET | GOCB_ELEMENT_GO_ENA, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK) {
printf("setGoCBValues service error: %i\n", error);
}
/*Test to see if the values were updated correctly on the server*/
IedConnection_getGoCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL, getGoCBValuesHandler, NULL);
ClientGooseControlBlock_destroy(GOCB);
}
}
Thread_sleep(10000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK)
{
printf("Release returned error: %d\n", error);
}
else
{
while (IedConnection_getState(con) != IED_STATE_CLOSED)
{
Thread_sleep(10);
}
}
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -0,0 +1,17 @@
set(iec61850_client_example_rcbAsync_SRCS
client_example_rcbAsync.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_rcbAsync_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_rcbAsync
${iec61850_client_example_rcbAsync_SRCS}
)
target_link_libraries(iec61850_client_example_rcbAsync
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_rcbAsync
PROJECT_SOURCES = client_example_rcbAsync.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,226 @@
/*
* client_example_rcbAsync.c
*
* This example is intended to be used with server_example_basic_io or server_example_goose.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static ClientDataSet clientDataSet = NULL;
static ClientReportControlBlock RCB = NULL;
static void
printValue(char* name, MmsValue* value)
{
char buf[1000];
MmsValue_printToBuffer(value, buf, 1000);
printf("%s: %s\n", name, buf);
}
static void
readObjectHandler(uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value)
{
if (err == IED_ERROR_OK) {
printValue((char*)parameter, value);
MmsValue_delete(value);
}
else {
printf("Failed to read object %s (err=%i)\n", (char*)parameter, err);
}
}
static void
readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet)
{
if (err == IED_ERROR_OK) {
clientDataSet = dataSet;
printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet));
MmsValue* values = ClientDataSet_getValues(dataSet);
if (MmsValue_getType(values) == MMS_ARRAY) {
int i;
for (i = 0; i < MmsValue_getArraySize(values); i++) {
printf(" [%i]", i);
printValue("", MmsValue_getElement(values, i));
}
}
}
else {
printf("Failed to read data set (err=%i\n", err);
}
}
void
reportCallbackFunction(void* parameter, ClientReport report)
{
MmsValue* dataSetValues = ClientReport_getDataSetValues(report);
printf("received report for %s\n", ClientReport_getRcbReference(report));
int i;
for (i = 0; i < 4; i++) {
ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
if (reason != IEC61850_REASON_NOT_INCLUDED) {
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
}
}
}
static void
getRCBValuesHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb)
{
if (err == IED_ERROR_OK) {
if (rcb) {
bool rptEna = ClientReportControlBlock_getRptEna(rcb);
printf("RptEna = %i\n", rptEna);
const char* RptId = ClientReportControlBlock_getRptId(rcb);
printf("RptID = %s\n", RptId);
RCB = rcb;
}
}
else{
printf("Failed to get RCB Values (err=%i)\n", err);
}
};
static void
genericServiceHandler(uint32_t invokeId, void* parameter, IedClientError err)
{
if (err == IED_ERROR_OK) {
printf("Success triggering a GI report\n");
}
else {
printf("Error triggering a GI report (code: %i)\n", err);
}
}
int main(int argc, char** argv) {
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED) {
if (IedConnection_getState(con) == IED_STATE_CLOSED) {
success = false;
break;
}
Thread_sleep(10);
}
if (success) {
/*read measurement value from server*/
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn2.mag.f");
if (error != IED_ERROR_OK) {
printf("read object error %i\n", error);
}
/*read data set*/
IedConnection_readDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", NULL, readDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("read data set error %i\n", error);
}
/* Read RCB values from server*/
IedConnection_getRCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL, getRCBValuesHandler, NULL);
if (error != IED_ERROR_OK) {
printf("getRCBValues service error! %i\n", error);
}
while (RCB == NULL) {}
if (RCB != NULL) {
/*Set RCB Values locally*/
ClientReportControlBlock_setResv(RCB, true);
ClientReportControlBlock_setTrgOps(RCB, TRG_OPT_DATA_CHANGED | TRG_OPT_QUALITY_CHANGED | TRG_OPT_GI);
ClientReportControlBlock_setDataSetReference(RCB, "simpleIOGenericIO/LLN0$Events"); /* NOTE the "$" instead of "." ! */
ClientReportControlBlock_setRptEna(RCB, true);
ClientReportControlBlock_setGI(RCB, true);
/*Set RCB Values to server*/
IedConnection_setRCBValuesAsync(con, &error, RCB, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_TRG_OPS | RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_GI, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK) {
printf("setRCBValues service error!\n");
}
Thread_sleep(1000);
/*Trigger GI Report*/
ClientReportControlBlock_setGI(RCB, true);
IedConnection_setRCBValuesAsync(con, &error, RCB, RCB_ELEMENT_GI, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK)
printf("Error triggering a GI report (code: %i)\n", error);
Thread_sleep(60000);
/*Disable Reporting*/
ClientReportControlBlock_setRptEna(RCB, false);
IedConnection_setRCBValuesAsync(con, &error, RCB, RCB_ELEMENT_RPT_ENA, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK)
printf("disable reporting failed (code: %i)\n", error);
ClientDataSet_destroy(clientDataSet);
ClientReportControlBlock_destroy(RCB);
}
}
Thread_sleep(50000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK) {
printf("Release returned error: %d\n", error);
}
else {
while (IedConnection_getState(con) != IED_STATE_CLOSED) {
Thread_sleep(10);
}
}
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -3,7 +3,7 @@
*
* Implementation of the ClientReportControlBlock class
*
* Copyright 2014 Michael Zillgith
* Copyright 2014-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -31,7 +31,8 @@
#include "libiec61850_platform_includes.h"
struct sClientGooseControlBlock {
struct sClientGooseControlBlock
{
char* objectReference;
MmsValue* goEna;
MmsValue* goID;
@ -49,13 +50,18 @@ ClientGooseControlBlock_create(const char* objectReference)
{
ClientGooseControlBlock self = (ClientGooseControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientGooseControlBlock));
if (self)
{
self->objectReference = StringUtils_copyString(objectReference);
}
return self;
}
void
ClientGooseControlBlock_destroy(ClientGooseControlBlock self)
{
if (self)
{
GLOBAL_FREEMEM(self->objectReference);
@ -71,6 +77,7 @@ ClientGooseControlBlock_destroy(ClientGooseControlBlock self)
GLOBAL_FREEMEM(self);
}
}
bool
ClientGooseControlBlock_getGoEna(ClientGooseControlBlock self)
@ -172,13 +179,17 @@ ClientGooseControlBlock_getFixedOffs(ClientGooseControlBlock self)
}
static MmsValue*
newEmptyPhyCommAddress(void) {
newEmptyPhyCommAddress(void)
{
MmsValue* self = MmsValue_createEmptyStructure(4);
if (self)
{
MmsValue_setElement(self, 0, MmsValue_newOctetString(6, 6));
MmsValue_setElement(self, 1, MmsValue_newUnsigned(8));
MmsValue_setElement(self, 2, MmsValue_newUnsigned(16));
MmsValue_setElement(self, 3, MmsValue_newUnsigned(16));
}
return self;
}
@ -191,24 +202,28 @@ ClientGooseControlBlock_getDstAddress(ClientGooseControlBlock self)
if (self->dstAddress == NULL) goto exit_error;
if (MmsValue_getType(self->dstAddress) != MMS_STRUCTURE) {
if (MmsValue_getType(self->dstAddress) != MMS_STRUCTURE)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - addr has wrong type\n");
goto exit_error;
}
if (MmsValue_getArraySize(self->dstAddress) != 4) {
if (MmsValue_getArraySize(self->dstAddress) != 4)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - addr has wrong type\n");
goto exit_error;
}
MmsValue* addr = MmsValue_getElement(self->dstAddress, 0);
if (MmsValue_getType(addr) != MMS_OCTET_STRING) {
if (MmsValue_getType(addr) != MMS_OCTET_STRING)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - addr has wrong type\n");
goto exit_error;
}
if (MmsValue_getOctetStringSize(addr) != 6) {
if (MmsValue_getOctetStringSize(addr) != 6)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - addr has wrong size\n");
goto exit_error;
}
@ -219,7 +234,8 @@ ClientGooseControlBlock_getDstAddress(ClientGooseControlBlock self)
MmsValue* prio = MmsValue_getElement(self->dstAddress, 1);
if (MmsValue_getType(prio) != MMS_UNSIGNED) {
if (MmsValue_getType(prio) != MMS_UNSIGNED)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - prio has wrong type\n");
goto exit_error;
}
@ -228,7 +244,8 @@ ClientGooseControlBlock_getDstAddress(ClientGooseControlBlock self)
MmsValue* vid = MmsValue_getElement(self->dstAddress, 2);
if (MmsValue_getType(vid) != MMS_UNSIGNED) {
if (MmsValue_getType(vid) != MMS_UNSIGNED)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - vid has wrong type\n");
goto exit_error;
}
@ -237,7 +254,8 @@ ClientGooseControlBlock_getDstAddress(ClientGooseControlBlock self)
MmsValue* appID = MmsValue_getElement(self->dstAddress, 3);
if (MmsValue_getType(appID) != MMS_UNSIGNED) {
if (MmsValue_getType(appID) != MMS_UNSIGNED)
{
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: GoCB - appID has wrong type\n");
goto exit_error;
}
@ -254,8 +272,8 @@ ClientGooseControlBlock_setDstAddress(ClientGooseControlBlock self, PhyComAddres
if (self->dstAddress == NULL)
self->dstAddress = newEmptyPhyCommAddress();
if (self->dstAddress) {
if (self->dstAddress)
{
MmsValue* addr = MmsValue_getElement(self->dstAddress, 0);
MmsValue_setOctetString(addr, value.dstAddress, 6);
@ -364,7 +382,8 @@ private_ClientGooseControlBlock_updateValues(ClientGooseControlBlock self, MmsVa
{
int elementCount = MmsValue_getArraySize(values);
if (elementCount > 5) {
if (elementCount > 5)
{
updateOrClone(&(self->goEna), values, 0);
updateOrClone(&(self->goID), values, 1);
updateOrClone(&(self->datSet), values, 2);
@ -398,7 +417,8 @@ IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const cha
char domainId[65];
char itemId[130];
if (MmsMapping_getMmsDomainFromObjectReference(goCBReference, domainId) == NULL) {
if (MmsMapping_getMmsDomainFromObjectReference(goCBReference, domainId) == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return NULL;
}
@ -409,7 +429,8 @@ IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const cha
const char* separator = strchr(itemIdStart, '.');
if (separator == NULL) {
if (separator == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return NULL;
}
@ -431,18 +452,21 @@ IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const cha
MmsValue* goCB = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId);
if (mmsError != MMS_ERROR_NONE) {
if (mmsError != MMS_ERROR_NONE)
{
*error = iedConnection_mapMmsErrorToIedError(mmsError);
return NULL;
}
if (goCB == NULL) {
if (goCB == NULL)
{
*error = IED_ERROR_OBJECT_DOES_NOT_EXIST;
return NULL;
}
if (MmsValue_getType(goCB) != MMS_STRUCTURE) {
if (MmsValue_getType(goCB) != MMS_STRUCTURE)
{
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n");
@ -465,6 +489,147 @@ IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const cha
return returnGoCB;
}
static void
readObjectHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, MmsValue* value)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call)
{
IedConnection_GetGoCBValuesHandler handler = (IedConnection_GetGoCBValuesHandler) call->callback;
ClientGooseControlBlock updateGoCB = (ClientGooseControlBlock) call->specificParameter;
char* goCBReference = (char*) call->specificParameter2.pointer;
if (err != MMS_ERROR_NONE)
{
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), NULL);
}
else
{
if (value == NULL)
{
handler(invokeId, call->callbackParameter, IED_ERROR_OBJECT_DOES_NOT_EXIST, NULL);
}
else
{
if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR)
{
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getGoCBValues returned data-access-error!\n");
handler(invokeId, call->callbackParameter, iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)), NULL);
}
else
{
ClientGooseControlBlock returnGoCB = updateGoCB;
if (returnGoCB == NULL)
returnGoCB = ClientGooseControlBlock_create(goCBReference);
if (private_ClientGooseControlBlock_updateValues(returnGoCB, value))
{
handler(invokeId, call->callbackParameter, IED_ERROR_OK, returnGoCB);
}
else
{
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getGoCBValues returned wrong type!\n");
handler(invokeId, call->callbackParameter, IED_ERROR_TYPE_INCONSISTENT, NULL);
if (updateGoCB == NULL)
ClientGooseControlBlock_destroy(returnGoCB);
}
}
MmsValue_delete(value);
}
}
GLOBAL_FREEMEM(goCBReference);
iedConnection_releaseOutstandingCall(self, call);
}
else
{
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t
IedConnection_getGoCBValuesAsync(IedConnection self, IedClientError* error, const char* goCBReference, ClientGooseControlBlock updateGoCB,
IedConnection_GetGoCBValuesHandler handler, void* parameter)
{
*error = IED_ERROR_OK;
char domainId[65];
char itemId[130];
if (MmsMapping_getMmsDomainFromObjectReference(goCBReference, domainId) == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
int domainIdSize = strlen(domainId);
const char* itemIdStart = goCBReference + domainIdSize + 1;
const char* separator = strchr(itemIdStart, '.');
if (separator == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
int separatorOffset = separator - itemIdStart;
memcpy(itemId, itemIdStart, separatorOffset);
itemId[separatorOffset] = '$';
itemId[separatorOffset + 1] = 'G';
itemId[separatorOffset + 2] = 'O';
itemId[separatorOffset + 3] = '$';
itemId[separatorOffset + 4] = 0;
StringUtils_appendString(itemId, 130, separator + 1);
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL)
{
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
return 0;
}
call->callback = handler;
call->callbackParameter = parameter;
call->specificParameter = updateGoCB;
call->specificParameter2.pointer = StringUtils_copyString(goCBReference);
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: readGoCBValues for %s\n", goCBReference);
MmsError err = MMS_ERROR_NONE;
MmsConnection_readVariableAsync(self->connection, &(call->invokeId), &err, domainId, itemId, readObjectHandlerInternal, self);
*error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE)
{
GLOBAL_FREEMEM(call->specificParameter2.pointer);
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId;
}
void
IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGooseControlBlock goCB,
uint32_t parametersMask, bool singleRequest)
@ -476,7 +641,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
char domainId[65];
char itemId[130];
if (MmsMapping_getMmsDomainFromObjectReference(goCB->objectReference, domainId) == NULL) {
if (MmsMapping_getMmsDomainFromObjectReference(goCB->objectReference, domainId) == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return;
}
@ -485,7 +651,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
char* separator = strchr(itemIdStart, '.');
if (separator == NULL) {
if (separator == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return;
}
@ -512,7 +679,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
LinkedList values = LinkedList_create();
/* add rGoEna as last element */
if (parametersMask & GOCB_ELEMENT_GO_ID) {
if (parametersMask & GOCB_ELEMENT_GO_ID)
{
StringUtils_appendString(itemId, 130, "$GoID");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -521,7 +689,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_DATSET) {
if (parametersMask & GOCB_ELEMENT_DATSET)
{
StringUtils_appendString(itemId, 130, "$DatSet");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -530,7 +699,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_CONF_REV) {
if (parametersMask & GOCB_ELEMENT_CONF_REV)
{
StringUtils_appendString(itemId, 130, "$ConfRev");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -539,7 +709,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_NDS_COMM) {
if (parametersMask & GOCB_ELEMENT_NDS_COMM)
{
StringUtils_appendString(itemId, 130, "$NdsCom");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -548,7 +719,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_DST_ADDRESS) {
if (parametersMask & GOCB_ELEMENT_DST_ADDRESS)
{
StringUtils_appendString(itemId, 130, "$DstAddress");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -557,7 +729,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_MIN_TIME) {
if (parametersMask & GOCB_ELEMENT_MIN_TIME)
{
StringUtils_appendString(itemId, 130, "$MinTime");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -566,7 +739,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_MAX_TIME) {
if (parametersMask & GOCB_ELEMENT_MAX_TIME)
{
StringUtils_appendString(itemId, 130, "$MaxTime");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -575,7 +749,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_FIXED_OFFS) {
if (parametersMask & GOCB_ELEMENT_FIXED_OFFS)
{
StringUtils_appendString(itemId, 130, "$FixedOffs");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -584,7 +759,8 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_GO_ENA) {
if (parametersMask & GOCB_ELEMENT_GO_ENA)
{
StringUtils_appendString(itemId, 130, "$GoEna");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -593,23 +769,26 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
itemId[itemIdLen] = 0;
}
if (singleRequest) {
if (singleRequest)
{
LinkedList accessResults = NULL;
*error = IED_ERROR_OK;
MmsConnection_writeMultipleVariables(self->connection, &mmsError, domainId, itemIds, values, &accessResults);
if (accessResults != NULL) {
if (accessResults)
{
LinkedList element = LinkedList_getNext(accessResults);
while (element != NULL) {
while (element)
{
MmsValue* accessResult = (MmsValue*) element->data;
MmsDataAccessError resErr = MmsValue_getDataAccessError(accessResult);
if (MmsValue_getDataAccessError(accessResult) != DATA_ACCESS_ERROR_SUCCESS) {
if (MmsValue_getDataAccessError(accessResult) != DATA_ACCESS_ERROR_SUCCESS)
{
*error = iedConnection_mapDataAccessErrorToIedError(resErr);
break;
@ -623,11 +802,13 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo
goto exit_function;
}
else {
else
{
LinkedList itemIdElement = LinkedList_getNext(itemIds);
LinkedList valueElement = LinkedList_getNext(values);
while (itemIdElement != NULL) {
while (itemIdElement)
{
char* rcbItemId = (char*) itemIdElement->data;
MmsValue* value = (MmsValue*) valueElement->data;
@ -649,3 +830,345 @@ exit_function:
LinkedList_destroyStatic(values);
}
static void
writeMultipleVariablesHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsValue*> */ accessResults)
{
IedConnection self = (IedConnection)parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call)
{
IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler) call->callback;
if (accessResults)
{
IedClientError error = IED_ERROR_OK;
LinkedList accessResult = LinkedList_getNext(accessResults);
while (accessResult)
{
MmsValue* dataAccessError = (MmsValue*) accessResult->data;
if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS)
{
error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(dataAccessError));
break;
}
accessResult = LinkedList_getNext(accessResult);
}
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction)MmsValue_delete);
handler(invokeId, call->callbackParameter, error);
}
else
{
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(mmsError));
}
iedConnection_releaseOutstandingCall(self, call);
}
else
{
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call with invoke ID: %u!\n", invokeId);
}
}
struct sWriteGoCBVariablesParameter
{
LinkedList itemIds;
LinkedList values;
LinkedList currentItemId;
LinkedList currentValue;
char* domainId;
uint32_t originalInvokeId;
};
static void
releaseWriteCall(IedConnection self, IedConnectionOutstandingCall call, struct sWriteGoCBVariablesParameter* param)
{
GLOBAL_FREEMEM(param->domainId);
LinkedList_destroy(param->itemIds);
LinkedList_destroyStatic(param->values);
GLOBAL_FREEMEM(param);
iedConnection_releaseOutstandingCall(self, call);
}
static void
writeVariableHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsDataAccessError accessError)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call)
{
IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler) call->callback;
struct sWriteGoCBVariablesParameter* param = (struct sWriteGoCBVariablesParameter*) call->specificParameter2.pointer;
if ((mmsError != MMS_ERROR_NONE) || (accessError != DATA_ACCESS_ERROR_SUCCESS))
{
IedClientError err;
if (mmsError != MMS_ERROR_NONE)
err = iedConnection_mapMmsErrorToIedError(mmsError);
else
err = iedConnection_mapDataAccessErrorToIedError(accessError);
handler(param->originalInvokeId, call->callbackParameter, err);
releaseWriteCall(self, call, param);
}
param->currentItemId = LinkedList_getNext(param->currentItemId);
if (param->currentItemId == NULL)
{
handler(param->originalInvokeId, call->callbackParameter, IED_ERROR_OK);
releaseWriteCall(self, call, param);
}
else
{
param->currentValue = LinkedList_getNext(param->currentValue);
char* itemId = (char*) LinkedList_getData(param->currentItemId);
MmsValue* value = (MmsValue*)LinkedList_getData(param->currentValue);
MmsError writeError;
MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &writeError, param->domainId, itemId, value, writeVariableHandler, self);
if (writeError != MMS_ERROR_NONE)
{
handler(param->originalInvokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(writeError));
releaseWriteCall(self, call, param);
}
}
}
else
{
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t
IedConnection_setGoCBValuesAsync(IedConnection self, IedClientError* error, ClientGooseControlBlock goCB,
uint32_t parametersMask, bool singleRequest, IedConnection_GenericServiceHandler handler, void* parameter)
{
*error = IED_ERROR_OK;
uint32_t invokeId = 0;
char domainId[65];
char itemId[130];
if (MmsMapping_getMmsDomainFromObjectReference(goCB->objectReference, domainId) == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;;
}
char* itemIdStart = goCB->objectReference + strlen(domainId) + 1;
char* separator = strchr(itemIdStart, '.');
if (separator == NULL)
{
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
goto exit_function;
}
int separatorOffset = separator - itemIdStart;
memcpy(itemId, itemIdStart, separatorOffset);
itemId[separatorOffset] = '$';
itemId[separatorOffset + 1] = 'G';
itemId[separatorOffset + 2] = 'O';
itemId[separatorOffset + 3] = '$';
itemId[separatorOffset + 4] = 0;
StringUtils_appendString(itemId, 130, separator + 1);
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: setGoCBValues for %s\n", goCB->objectReference);
int itemIdLen = strlen(itemId);
/* create the list of requested itemIds references */
LinkedList itemIds = LinkedList_create();
LinkedList values = LinkedList_create();
/* add rGoEna as last element */
if (parametersMask & GOCB_ELEMENT_GO_ID)
{
StringUtils_appendString(itemId, 130, "$GoID");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->goID);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_DATSET)
{
StringUtils_appendString(itemId, 130, "$DatSet");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->datSet);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_CONF_REV)
{
StringUtils_appendString(itemId, 130, "$ConfRev");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->confRev);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_NDS_COMM)
{
StringUtils_appendString(itemId, 130, "$NdsCom");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->ndsCom);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_DST_ADDRESS)
{
StringUtils_appendString(itemId, 130, "$DstAddress");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->dstAddress);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_MIN_TIME)
{
StringUtils_appendString(itemId, 130, "$MinTime");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->minTime);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_MAX_TIME)
{
StringUtils_appendString(itemId, 130, "$MaxTime");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->maxTime);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_FIXED_OFFS)
{
StringUtils_appendString(itemId, 130, "$FixedOffs");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->fixedOffs);
itemId[itemIdLen] = 0;
}
if (parametersMask & GOCB_ELEMENT_GO_ENA)
{
StringUtils_appendString(itemId, 130, "$GoEna");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, goCB->goEna);
itemId[itemIdLen] = 0;
}
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->specificParameter = goCB;
MmsError err;
if (singleRequest)
{
MmsConnection_writeMultipleVariablesAsync(self->connection, &(call->invokeId), &err, domainId, itemIds, values, writeMultipleVariablesHandler, self);
*error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self, call);
}
else
{
invokeId = call->invokeId;
}
goto exit_function;
}
else
{
struct sWriteGoCBVariablesParameter* param = (struct sWriteGoCBVariablesParameter*) GLOBAL_MALLOC(sizeof(struct sWriteGoCBVariablesParameter));
call->specificParameter2.pointer = param;
param->itemIds = itemIds;
param->values = values;
param->currentItemId = LinkedList_getNext(itemIds);
param->currentValue = LinkedList_getNext(values);
param->domainId = StringUtils_copyString(domainId);
char* variableId = (char*)LinkedList_getData(param->currentItemId);
MmsValue* value = (MmsValue*)LinkedList_getData(param->currentValue);
MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &err, domainId, variableId, value, writeVariableHandler, self);
param->originalInvokeId = call->invokeId;
invokeId = call->invokeId;
*error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self, call);
GLOBAL_FREEMEM(param->domainId);
GLOBAL_FREEMEM(param);
goto exit_function;
}
else
return invokeId;
}
exit_function:
LinkedList_destroy(itemIds);
LinkedList_destroyStatic(values);
return invokeId;
}

@ -795,8 +795,9 @@ ClientGooseControlBlock_setDstAddress_appid(ClientGooseControlBlock self, uint16
********************************************************/
/**
* \brief Read access to attributes of a GOOSE control block (GoCB) at the connected server. A GoCB contains
* the configuration values for a single GOOSE publisher.
* \brief Read access to attributes of a GOOSE control block (GoCB) at the connected server.
*
* A GoCB contains the configuration values for a single GOOSE publisher.
*
* The requested GoCB has to be specified by its object IEC 61850 ACSI object reference. E.g.
*
@ -824,6 +825,42 @@ ClientGooseControlBlock_setDstAddress_appid(ClientGooseControlBlock self, uint16
LIB61850_API ClientGooseControlBlock
IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const char* goCBReference, ClientGooseControlBlock updateGoCB);
typedef void
(*IedConnection_GetGoCBValuesHandler) (uint32_t invokeId, void* parameter, IedClientError err, ClientGooseControlBlock goCB);
/**
* \brief Read access to attributes of a GOOSE control block (GoCB) at the connected server (async version)
*
* A GoCB contains the configuration values for a single GOOSE publisher.
*
* The requested GoCB has to be specified by its object IEC 61850 ACSI object reference. E.g.
*
* "simpleIOGernericIO/LLN0.gcbEvents"
*
* This function is used to perform the actual read service for the GoCB values.
* To access the received values the functions of ClientGooseControlBlock have to be used.
*
* If called with a NULL argument for the updateGoCB parameter a new ClientGooseControlBlock instance is created
* and populated with the values received by the server. It is up to the user to release this object by
* calling the ClientGooseControlBlock_destroy function when the object is no longer needed. If called with a reference
* to an existing ClientGooseControlBlock instance the values of the attributes will be updated and no new instance
* will be created.
*
* Note: This function maps to a single MMS read request to retrieve the complete GoCB at once.
*
* \param connection the connection object
* \param error the error code if an error occurs
* \param goCBReference IEC 61850-7-2 ACSI object reference of the GOOSE control block
* \param updateRcb a reference to an existing ClientGooseControlBlock instance or NULL
* \param handler the user callback that is called when the service is completed or timed out
* \param parameter user provided parameter that is passed to the callback handler
*
* \return the invoke ID of the request
*/
LIB61850_API uint32_t
IedConnection_getGoCBValuesAsync(IedConnection self, IedClientError* error, const char* goCBReference, ClientGooseControlBlock updateGoCB,
IedConnection_GetGoCBValuesHandler handler, void* parameter);
/**
* \brief Write access to attributes of a GOOSE control block (GoCB) at the connected server
*
@ -849,6 +886,35 @@ LIB61850_API void
IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGooseControlBlock goCB,
uint32_t parametersMask, bool singleRequest);
/**
* \brief Write access to attributes of a GOOSE control block (GoCB) at the connected server (async version)
*
* The GoCB and the values to be written are specified with the goCB parameter.
*
* The parametersMask parameter specifies which attributes of the remote GoCB have to be set by this request.
* You can specify multiple attributes by ORing the defined bit values. If all attributes have to be written
* GOCB_ELEMENT_ALL can be used.
*
* The singleRequest parameter specifies the mapping to the corresponding MMS write request. Standard compliant
* servers should accept both variants. But some server accept only one variant. Then the value of this parameter
* will be of relevance.
*
* \param connection the connection object
* \param error the error code if an error occurs
* \param goCB ClientGooseControlBlock instance that actually holds the parameter
* values to be written.
* \param parametersMask specifies the parameters contained in the setGoCBValues request.
* \param singleRequest specifies if the seGoCBValues services is mapped to a single MMS write request containing
* multiple variables or to multiple MMS write requests.
* \param handler the user callback that is called when the service is completed or timed out
* \param parameter user provided parameter that is passed to the callback handler
*
* \return the invoke ID of the request
*/
LIB61850_API uint32_t
IedConnection_setGoCBValuesAsync(IedConnection self, IedClientError* error, ClientGooseControlBlock goCB,
uint32_t parametersMask, bool singleRequest, IedConnection_GenericServiceHandler handler, void* parameter);
/** @} */

@ -235,7 +235,6 @@ IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const cha
LIB61850_API void
IsoConnectionParameters_setLocalTcpParameters(IsoConnectionParameters self, const char* localIpAddress, int localTcpPort);
/**
* \brief set the remote AP-Title and AE-Qualifier
*

@ -281,6 +281,8 @@ MmsConnection_destroy(MmsConnection self);
LIB61850_API bool
MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort);
LIB61850_API void
MmsConnection_connectAsync(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort);

Loading…
Cancel
Save