- IedConnection: code format updates

v1.6
Michael Zillgith 4 weeks ago
parent 9b467fa60d
commit 8a4b7bb616

@ -1,7 +1,7 @@
/* /*
* client_control.c * client_control.c
* *
* Copyright 2013-2021 Michael Zillgith * Copyright 2013-2025 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -221,7 +221,8 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
/* request control model from server */ /* request control model from server */
char reference[129]; char reference[129];
if (strlen(objectReference) < 120) { if (strlen(objectReference) < 120)
{
StringUtils_concatString(reference, 129, objectReference, ".ctlModel"); StringUtils_concatString(reference, 129, objectReference, ".ctlModel");
} }
else else
@ -261,19 +262,19 @@ exit_function:
void void
ControlObjectClient_destroy(ControlObjectClient self) ControlObjectClient_destroy(ControlObjectClient self)
{ {
if (self != NULL) if (self)
{ {
GLOBAL_FREEMEM(self->objectReference); GLOBAL_FREEMEM(self->objectReference);
iedConnection_removeControlClient(self->connection, self); iedConnection_removeControlClient(self->connection, self);
if (self->ctlVal != NULL) if (self->ctlVal)
MmsValue_delete(self->ctlVal); MmsValue_delete(self->ctlVal);
if (self->analogValue != NULL) if (self->analogValue)
MmsValue_delete(self->analogValue); MmsValue_delete(self->analogValue);
if (self->orIdent != NULL) if (self->orIdent)
GLOBAL_FREEMEM(self->orIdent); GLOBAL_FREEMEM(self->orIdent);
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
@ -316,7 +317,7 @@ ControlObjectClient_changeServerControlModel(ControlObjectClient self, ControlMo
MmsType MmsType
ControlObjectClient_getCtlValType(ControlObjectClient self) ControlObjectClient_getCtlValType(ControlObjectClient self)
{ {
if (self->analogValue != NULL) if (self->analogValue)
return MmsValue_getType(self->analogValue); return MmsValue_getType(self->analogValue);
else else
return MmsValue_getType(self->ctlVal); return MmsValue_getType(self->ctlVal);
@ -334,10 +335,10 @@ ControlObjectClient_getLastError(ControlObjectClient self)
void void
ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat) ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat)
{ {
if (self->orIdent != NULL) if (self->orIdent)
GLOBAL_FREEMEM(self->orIdent); GLOBAL_FREEMEM(self->orIdent);
if (orIdent != NULL) if (orIdent)
self->orIdent = StringUtils_copyString(orIdent); self->orIdent = StringUtils_copyString(orIdent);
else else
self->orIdent = NULL; self->orIdent = NULL;
@ -596,14 +597,16 @@ ControlObjectClient_operateAsync(ControlObjectClient self, IedClientError* err,
*err = IED_ERROR_OK; *err = IED_ERROR_OK;
uint32_t invokeId = 0; uint32_t invokeId = 0;
if (ctlVal == NULL) { if (ctlVal == NULL)
{
*err = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; *err = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
goto exit_function; goto exit_function;
} }
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection);
if (call == NULL) { if (call == NULL)
{
*err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; *err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
goto exit_function; goto exit_function;
} }
@ -636,10 +639,12 @@ ControlObjectClient_operateAsync(ControlObjectClient self, IedClientError* err,
*err = iedConnection_mapMmsErrorToIedError(mmsError); *err = iedConnection_mapMmsErrorToIedError(mmsError);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
else { else
{
MmsValue_update(self->ctlVal, ctlVal); MmsValue_update(self->ctlVal, ctlVal);
self->opertime = operTime; self->opertime = operTime;
@ -667,8 +672,10 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal)
MmsValue* selValParameters = MmsValue_createEmptyStructure(selValElementCount); MmsValue* selValParameters = MmsValue_createEmptyStructure(selValElementCount);
/* support simplified usage of APC controls - user doesn't need to create the structure */ /* support simplified usage of APC controls - user doesn't need to create the structure */
if (self->analogValue != NULL) { if (self->analogValue)
if (MmsValue_getType(ctlVal) != MMS_STRUCTURE) { {
if (MmsValue_getType(ctlVal) != MMS_STRUCTURE)
{
MmsValue_setElement(self->analogValue, 0, ctlVal); MmsValue_setElement(self->analogValue, 0, ctlVal);
ctlVal = self->analogValue; ctlVal = self->analogValue;
} }
@ -678,7 +685,8 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal)
int index = 1; int index = 1;
if (self->hasTimeActivatedMode) { if (self->hasTimeActivatedMode)
{
MmsValue* operTm = MmsValue_newUtcTimeByMsTime(0); MmsValue* operTm = MmsValue_newUtcTimeByMsTime(0);
MmsValue_setElement(selValParameters, index++, operTm); MmsValue_setElement(selValParameters, index++, operTm);
} }
@ -688,7 +696,8 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal)
self->ctlNum++; self->ctlNum++;
if (self->hasCtlNum) { if (self->hasCtlNum)
{
MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
MmsValue_setElement(selValParameters, index++, ctlNum); MmsValue_setElement(selValParameters, index++, ctlNum);
} }
@ -699,13 +708,15 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal)
if (self->useConstantT) if (self->useConstantT)
self->constantT = timestamp; self->constantT = timestamp;
if (self->edition == 2) { if (self->edition == 2)
{
ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); ctlTime = MmsValue_newUtcTimeByMsTime(timestamp);
if (self->connection) if (self->connection)
MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality); MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality);
} }
else { else
{
ctlTime = MmsValue_newBinaryTime(false); ctlTime = MmsValue_newBinaryTime(false);
MmsValue_setBinaryTime(ctlTime, timestamp); MmsValue_setBinaryTime(ctlTime, timestamp);
} }
@ -763,7 +774,8 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
self->lastMmsError = mmsError; self->lastMmsError = mmsError;
self->lastAccessError = writeResult; self->lastAccessError = writeResult;
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n"); printf("IED_CLIENT: select-with-value failed!\n");
@ -771,8 +783,10 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
goto exit_function; goto exit_function;
} }
else { else
if (writeResult != DATA_ACCESS_ERROR_SUCCESS) { {
if (writeResult != DATA_ACCESS_ERROR_SUCCESS)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n"); printf("IED_CLIENT: select-with-value failed!\n");
@ -795,13 +809,13 @@ exit_function:
static void static void
internalSelWithValHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataAccessError accessError) internalSelWithValHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataAccessError accessError)
{ {
ControlObjectClient self = (ControlObjectClient) parameter; ControlObjectClient self = (ControlObjectClient)parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self->connection, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self->connection, invokeId);
if (call) { if (call)
{
ControlObjectClient_ControlActionHandler handler = (ControlObjectClient_ControlActionHandler) call->callback; ControlObjectClient_ControlActionHandler handler = (ControlObjectClient_ControlActionHandler)call->callback;
IedClientError iedError = iedConnection_mapMmsErrorToIedError(err); IedClientError iedError = iedConnection_mapMmsErrorToIedError(err);
@ -810,18 +824,21 @@ internalSelWithValHandler(uint32_t invokeId, void* parameter, MmsError err, MmsD
self->lastMmsError = err; self->lastMmsError = err;
self->lastAccessError = accessError; self->lastAccessError = accessError;
if (iedError == IED_ERROR_OK) { if (iedError == IED_ERROR_OK)
{
iedError = iedConnection_mapDataAccessErrorToIedError(accessError); iedError = iedConnection_mapDataAccessErrorToIedError(accessError);
if (iedError == IED_ERROR_OK) if (iedError == IED_ERROR_OK)
success = true; success = true;
} }
if (success) { if (success)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value+\n"); printf("IED_CLIENT: select-with-value+\n");
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n"); printf("IED_CLIENT: select-with-value failed!\n");
} }
@ -830,7 +847,8 @@ internalSelWithValHandler(uint32_t invokeId, void* parameter, MmsError err, MmsD
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n"); printf("IED_CLIENT: internal error - no matching outstanding call!\n");
} }
@ -843,14 +861,16 @@ ControlObjectClient_selectWithValueAsync(ControlObjectClient self, IedClientErro
*err = IED_ERROR_OK; *err = IED_ERROR_OK;
uint32_t invokeId = 0; uint32_t invokeId = 0;
if (ctlVal == NULL) { if (ctlVal == NULL)
{
*err = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; *err = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
goto exit_function; goto exit_function;
} }
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection);
if (call == NULL) { if (call == NULL)
{
*err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; *err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
goto exit_function; goto exit_function;
} }
@ -876,7 +896,8 @@ ControlObjectClient_selectWithValueAsync(ControlObjectClient self, IedClientErro
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId); printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId);
MmsConnection_writeVariableAsync(self->connection->connection, &(call->invokeId), &mmsError, domainId, itemId, selValParameters, internalSelWithValHandler, self); MmsConnection_writeVariableAsync(self->connection->connection, &(call->invokeId), &mmsError, domainId, itemId,
selValParameters, internalSelWithValHandler, self);
invokeId = call->invokeId; invokeId = call->invokeId;
@ -885,10 +906,12 @@ ControlObjectClient_selectWithValueAsync(ControlObjectClient self, IedClientErro
*err = iedConnection_mapMmsErrorToIedError(mmsError); *err = iedConnection_mapMmsErrorToIedError(mmsError);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
else { else
{
MmsValue_update(self->ctlVal, ctlVal); MmsValue_update(self->ctlVal, ctlVal);
} }
@ -919,8 +942,8 @@ ControlObjectClient_select(ControlObjectClient self)
MmsError mmsError; MmsError mmsError;
MmsValue* value = MmsConnection_readVariable(IedConnection_getMmsConnection(self->connection), MmsValue* value =
&mmsError, domainId, itemId); MmsConnection_readVariable(IedConnection_getMmsConnection(self->connection), &mmsError, domainId, itemId);
bool selected = false; bool selected = false;
@ -929,30 +952,36 @@ ControlObjectClient_select(ControlObjectClient self)
self->lastMmsError = mmsError; self->lastMmsError = mmsError;
self->lastAccessError = DATA_ACCESS_ERROR_SUCCESS; self->lastAccessError = DATA_ACCESS_ERROR_SUCCESS;
if (value == NULL) { if (value == NULL)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select: read SBO failed!\n"); printf("IED_CLIENT: select: read SBO failed!\n");
goto exit_function; goto exit_function;
} }
if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { if (MmsValue_getType(value) == MMS_VISIBLE_STRING)
if (strcmp(MmsValue_toString(value), "") == 0) { {
if (strcmp(MmsValue_toString(value), "") == 0)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("select-response-\n"); printf("select-response-\n");
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("select-response+: (%s)\n", MmsValue_toString(value)); printf("select-response+: (%s)\n", MmsValue_toString(value));
selected = true; selected = true;
} }
} }
else if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) { else if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR)
{
self->lastAccessError = MmsValue_getDataAccessError(value); self->lastAccessError = MmsValue_getDataAccessError(value);
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select returned data-access-error: %i\n", self->lastAccessError); printf("IED_CLIENT: select returned data-access-error: %i\n", self->lastAccessError);
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select: unexpected response from server!\n"); printf("IED_CLIENT: select: unexpected response from server!\n");
} }
@ -970,8 +999,8 @@ internalSelectHandler(uint32_t invokeId, void* parameter, MmsError err, MmsValue
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self->connection, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self->connection, invokeId);
if (call) { if (call)
{
ControlObjectClient_ControlActionHandler handler = (ControlObjectClient_ControlActionHandler) call->callback; ControlObjectClient_ControlActionHandler handler = (ControlObjectClient_ControlActionHandler) call->callback;
IedClientError iedError = iedConnection_mapMmsErrorToIedError(err); IedClientError iedError = iedConnection_mapMmsErrorToIedError(err);
@ -983,15 +1012,16 @@ internalSelectHandler(uint32_t invokeId, void* parameter, MmsError err, MmsValue
self->ctlNum++; self->ctlNum++;
if (iedError == IED_ERROR_OK) { if (iedError == IED_ERROR_OK)
{
if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR)
{
MmsDataAccessError dataAccessError = MmsValue_getDataAccessError(value); MmsDataAccessError dataAccessError = MmsValue_getDataAccessError(value);
self->lastAccessError = dataAccessError; self->lastAccessError = dataAccessError;
iedError = iedConnection_mapDataAccessErrorToIedError(dataAccessError); iedError = iedConnection_mapDataAccessErrorToIedError(dataAccessError);
} }
else if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { else if (MmsValue_getType(value) == MMS_VISIBLE_STRING)
{
char domainId[65]; char domainId[65];
char itemId[65]; char itemId[65];
@ -1001,17 +1031,20 @@ internalSelectHandler(uint32_t invokeId, void* parameter, MmsError err, MmsValue
StringUtils_appendString(itemId, 65, "$SBO"); StringUtils_appendString(itemId, 65, "$SBO");
if (strcmp(MmsValue_toString(value), "") == 0) { if (strcmp(MmsValue_toString(value), "") == 0)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("select-response-\n"); printf("select-response-\n");
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("select-response+: (%s)\n", MmsValue_toString(value)); printf("select-response+: (%s)\n", MmsValue_toString(value));
success = true; success = true;
} }
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select: unexpected response from server!\n"); printf("IED_CLIENT: select: unexpected response from server!\n");
} }
@ -1021,7 +1054,8 @@ internalSelectHandler(uint32_t invokeId, void* parameter, MmsError err, MmsValue
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n"); printf("IED_CLIENT: internal error - no matching outstanding call!\n");
} }
@ -1048,7 +1082,8 @@ ControlObjectClient_selectAsync(ControlObjectClient self, IedClientError* err, C
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection);
if (call == NULL) { if (call == NULL)
{
*err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; *err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
return 0; return 0;
} }
@ -1068,7 +1103,8 @@ ControlObjectClient_selectAsync(ControlObjectClient self, IedClientError* err, C
*err = iedConnection_mapMmsErrorToIedError(mmsError); *err = iedConnection_mapMmsErrorToIedError(mmsError);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
@ -1089,7 +1125,8 @@ createCancelParameters(ControlObjectClient self)
int index = 1; int index = 1;
if (self->hasTimeActivatedMode) { if (self->hasTimeActivatedMode)
{
MmsValue* operTm = MmsValue_newUtcTimeByMsTime(self->opertime); MmsValue* operTm = MmsValue_newUtcTimeByMsTime(self->opertime);
MmsValue_setElement(cancelParameters, index++, operTm); MmsValue_setElement(cancelParameters, index++, operTm);
} }
@ -1110,13 +1147,15 @@ createCancelParameters(ControlObjectClient self)
MmsValue* ctlTime; MmsValue* ctlTime;
if (self->edition == 2) { if (self->edition == 2)
{
ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); ctlTime = MmsValue_newUtcTimeByMsTime(timestamp);
if (self->connection) if (self->connection)
MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality); MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality);
} }
else { else
{
ctlTime = MmsValue_newBinaryTime(false); ctlTime = MmsValue_newBinaryTime(false);
MmsValue_setBinaryTime(ctlTime, timestamp); MmsValue_setBinaryTime(ctlTime, timestamp);
} }
@ -1158,13 +1197,16 @@ ControlObjectClient_cancel(ControlObjectClient self)
MmsValue_setElement(cancelParameters, 0, NULL); MmsValue_setElement(cancelParameters, 0, NULL);
MmsValue_delete(cancelParameters); MmsValue_delete(cancelParameters);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: cancel failed!\n"); printf("IED_CLIENT: cancel failed!\n");
return false; return false;
} }
else { else
if (writeResult != DATA_ACCESS_ERROR_SUCCESS) { {
if (writeResult != DATA_ACCESS_ERROR_SUCCESS)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: cancel failed!\n"); printf("IED_CLIENT: cancel failed!\n");
return false; return false;
@ -1177,13 +1219,13 @@ ControlObjectClient_cancel(ControlObjectClient self)
static void static void
internalCancelHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataAccessError accessError) internalCancelHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataAccessError accessError)
{ {
ControlObjectClient self = (ControlObjectClient) parameter; ControlObjectClient self = (ControlObjectClient)parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self->connection, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self->connection, invokeId);
if (call) { if (call)
{
ControlObjectClient_ControlActionHandler handler = (ControlObjectClient_ControlActionHandler) call->callback; ControlObjectClient_ControlActionHandler handler = (ControlObjectClient_ControlActionHandler)call->callback;
IedClientError iedError = iedConnection_mapMmsErrorToIedError(err); IedClientError iedError = iedConnection_mapMmsErrorToIedError(err);
@ -1192,18 +1234,21 @@ internalCancelHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataA
self->lastMmsError = err; self->lastMmsError = err;
self->lastAccessError = accessError; self->lastAccessError = accessError;
if (iedError == IED_ERROR_OK) { if (iedError == IED_ERROR_OK)
{
iedError = iedConnection_mapDataAccessErrorToIedError(accessError); iedError = iedConnection_mapDataAccessErrorToIedError(accessError);
if (iedError == IED_ERROR_OK) if (iedError == IED_ERROR_OK)
success = true; success = true;
} }
if (success) { if (success)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: cancel+\n"); printf("IED_CLIENT: cancel+\n");
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: cancel failed!\n"); printf("IED_CLIENT: cancel failed!\n");
} }
@ -1212,21 +1257,24 @@ internalCancelHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataA
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n"); printf("IED_CLIENT: internal error - no matching outstanding call!\n");
} }
} }
uint32_t uint32_t
ControlObjectClient_cancelAsync(ControlObjectClient self, IedClientError* err, ControlObjectClient_ControlActionHandler handler, void* parameter) ControlObjectClient_cancelAsync(ControlObjectClient self, IedClientError* err,
ControlObjectClient_ControlActionHandler handler, void* parameter)
{ {
*err = IED_ERROR_OK; *err = IED_ERROR_OK;
uint32_t invokeId = 0; uint32_t invokeId = 0;
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection);
if (call == NULL) { if (call == NULL)
{
*err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; *err = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
goto exit_function; goto exit_function;
} }
@ -1252,7 +1300,8 @@ ControlObjectClient_cancelAsync(ControlObjectClient self, IedClientError* err, C
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId); printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId);
MmsConnection_writeVariableAsync(self->connection->connection, &(call->invokeId), &mmsError, domainId, itemId, cancelParameters, internalCancelHandler, self); MmsConnection_writeVariableAsync(self->connection->connection, &(call->invokeId), &mmsError, domainId, itemId,
cancelParameters, internalCancelHandler, self);
invokeId = call->invokeId; invokeId = call->invokeId;
@ -1261,7 +1310,8 @@ ControlObjectClient_cancelAsync(ControlObjectClient self, IedClientError* err, C
*err = iedConnection_mapMmsErrorToIedError(mmsError); *err = iedConnection_mapMmsErrorToIedError(mmsError);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self->connection, call); iedConnection_releaseOutstandingCall(self->connection, call);
} }
@ -1326,6 +1376,6 @@ ControlObjectClient_setCtlNum(ControlObjectClient self, uint8_t ctlNum)
void void
controlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self) controlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self)
{ {
if (self->commandTerminationHandler != NULL) if (self->commandTerminationHandler)
self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self); self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self);
} }

@ -3,7 +3,7 @@
* *
* Implementation of the ClientReportControlBlock class * Implementation of the ClientReportControlBlock class
* *
* Copyright 2014-2024 Michael Zillgith * Copyright 2014-2025 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -1145,6 +1145,12 @@ IedConnection_setGoCBValuesAsync(IedConnection self, IedClientError* error, Clie
{ {
struct sWriteGoCBVariablesParameter* param = (struct sWriteGoCBVariablesParameter*) GLOBAL_MALLOC(sizeof(struct sWriteGoCBVariablesParameter)); struct sWriteGoCBVariablesParameter* param = (struct sWriteGoCBVariablesParameter*) GLOBAL_MALLOC(sizeof(struct sWriteGoCBVariablesParameter));
if (param == NULL)
{
*error = IED_ERROR_UNKNOWN;
goto exit_function;
}
call->specificParameter2.pointer = param; call->specificParameter2.pointer = param;
param->itemIds = itemIds; param->itemIds = itemIds;

@ -3,7 +3,7 @@
* *
* Client implementation for IEC 61850 reporting. * Client implementation for IEC 61850 reporting.
* *
* Copyright 2013-2024 Michael Zillgith * Copyright 2013-2025 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -93,7 +93,10 @@ ClientReport_create()
{ {
ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport)); ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport));
if (self)
{
self->dataSetSize = -1; self->dataSetSize = -1;
}
return self; return self;
} }
@ -101,27 +104,30 @@ ClientReport_create()
void void
ClientReport_destroy(ClientReport self) ClientReport_destroy(ClientReport self)
{ {
if (self)
{
if (self->entryId) if (self->entryId)
MmsValue_delete(self->entryId); MmsValue_delete(self->entryId);
GLOBAL_FREEMEM(self->rcbReference); GLOBAL_FREEMEM(self->rcbReference);
if (self->rptId != NULL) if (self->rptId)
GLOBAL_FREEMEM(self->rptId); GLOBAL_FREEMEM(self->rptId);
if (self->dataSetValues != NULL) if (self->dataSetValues)
MmsValue_delete(self->dataSetValues); MmsValue_delete(self->dataSetValues);
if (self->dataReferences != NULL) if (self->dataReferences)
MmsValue_delete(self->dataReferences); MmsValue_delete(self->dataReferences);
if (self->reasonForInclusion != NULL) if (self->reasonForInclusion)
GLOBAL_FREEMEM(self->reasonForInclusion); GLOBAL_FREEMEM(self->reasonForInclusion);
if (self->dataSetName != NULL) if (self->dataSetName)
GLOBAL_FREEMEM((void*) self->dataSetName); GLOBAL_FREEMEM((void*) self->dataSetName);
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
}
} }
char* char*
@ -163,7 +169,6 @@ ClientReport_getTimestamp(ClientReport self)
return self->timestamp; return self->timestamp;
} }
bool bool
ClientReport_hasSeqNum(ClientReport self) ClientReport_hasSeqNum(ClientReport self)
{ {
@ -223,11 +228,14 @@ ClientReport_getDataReference(ClientReport self, int elementIndex)
{ {
char* dataReference = NULL; char* dataReference = NULL;
if (self->dataReferences != NULL) { if (self->dataReferences)
{
MmsValue* dataRefValue = MmsValue_getElement(self->dataReferences, elementIndex); MmsValue* dataRefValue = MmsValue_getElement(self->dataReferences, elementIndex);
if (dataRefValue != NULL) { if (dataRefValue)
if (MmsValue_getType(dataRefValue) == MMS_VISIBLE_STRING) { {
if (MmsValue_getType(dataRefValue) == MMS_VISIBLE_STRING)
{
return MmsValue_toString(dataRefValue); return MmsValue_toString(dataRefValue);
} }
} }
@ -271,8 +279,9 @@ lookupReportHandler(IedConnection self, const char* rcbReference)
{ {
LinkedList element = LinkedList_getNext(self->enabledReports); LinkedList element = LinkedList_getNext(self->enabledReports);
while (element != NULL) { while (element)
ClientReport report = (ClientReport) element->data; {
ClientReport report = (ClientReport)element->data;
if (strcmp(report->rcbReference, rcbReference) == 0) if (strcmp(report->rcbReference, rcbReference) == 0)
return report; return report;
@ -288,21 +297,23 @@ uninstallReportHandler(IedConnection self, const char* rcbReference)
{ {
ClientReport report = lookupReportHandler(self, rcbReference); ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) { if (report)
{
LinkedList_remove(self->enabledReports, report); LinkedList_remove(self->enabledReports, report);
ClientReport_destroy(report); ClientReport_destroy(report);
} }
} }
void void
IedConnection_installReportHandler(IedConnection self, const char* rcbReference, const char* rptId, ReportCallbackFunction handler, IedConnection_installReportHandler(IedConnection self, const char* rcbReference, const char* rptId,
void* handlerParameter) ReportCallbackFunction handler, void* handlerParameter)
{ {
Semaphore_wait(self->reportHandlerMutex); Semaphore_wait(self->reportHandlerMutex);
ClientReport report = lookupReportHandler(self, rcbReference); ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) { if (report)
{
uninstallReportHandler(self, rcbReference); uninstallReportHandler(self, rcbReference);
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -310,11 +321,14 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
} }
report = ClientReport_create(); report = ClientReport_create();
if (report)
{
report->callback = handler; report->callback = handler;
report->callbackParameter = handlerParameter; report->callbackParameter = handlerParameter;
report->rcbReference = StringUtils_copyString(rcbReference); report->rcbReference = StringUtils_copyString(rcbReference);
if (rptId != NULL) if (rptId)
report->rptId = StringUtils_copyString(rptId); report->rptId = StringUtils_copyString(rptId);
else else
report->rptId = NULL; report->rptId = NULL;
@ -325,6 +339,7 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: Installed new report callback handler for %s\n", rcbReference); printf("DEBUG_IED_CLIENT: Installed new report callback handler for %s\n", rcbReference);
}
} }
void void
@ -361,13 +376,15 @@ IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const c
MmsValue_delete(gi); MmsValue_delete(gi);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: failed to trigger GI for %s!\n", rcbReference); printf("DEBUG_IED_CLIENT: failed to trigger GI for %s!\n", rcbReference);
*error = iedConnection_mapMmsErrorToIedError(mmsError); *error = iedConnection_mapMmsErrorToIedError(mmsError);
} }
else { else
{
*error = IED_ERROR_OK; *error = IED_ERROR_OK;
} }
} }
@ -379,7 +396,8 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
MmsValue* rptIdValue = MmsValue_getElement(value, 0); MmsValue* rptIdValue = MmsValue_getElement(value, 0);
if ((rptIdValue == NULL) || (MmsValue_getType(rptIdValue) != MMS_VISIBLE_STRING)) { if ((rptIdValue == NULL) || (MmsValue_getType(rptIdValue) != MMS_VISIBLE_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (RptId)\n"); printf("IED_CLIENT: received malformed report (RptId)\n");
@ -389,19 +407,22 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
LinkedList element = LinkedList_getNext(self->enabledReports); LinkedList element = LinkedList_getNext(self->enabledReports);
ClientReport matchingReport = NULL; ClientReport matchingReport = NULL;
while (element != NULL) { while (element)
ClientReport report = (ClientReport) element->data; {
ClientReport report = (ClientReport)element->data;
char defaultRptId[130]; char defaultRptId[130];
char* rptId = report->rptId; char* rptId = report->rptId;
if ((rptId == NULL) || (strlen(rptId) == 0)) { if ((rptId == NULL) || (strlen(rptId) == 0))
{
StringUtils_concatString(defaultRptId, 130, report->rcbReference, ""); StringUtils_concatString(defaultRptId, 130, report->rcbReference, "");
StringUtils_replace(defaultRptId, '.', '$'); StringUtils_replace(defaultRptId, '.', '$');
rptId = defaultRptId; rptId = defaultRptId;
} }
if (strcmp(MmsValue_toString(rptIdValue), rptId) == 0) { if (strcmp(MmsValue_toString(rptIdValue), rptId) == 0)
{
matchingReport = report; matchingReport = report;
break; break;
} }
@ -426,7 +447,8 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
MmsValue* optFlds = MmsValue_getElement(value, 1); MmsValue* optFlds = MmsValue_getElement(value, 1);
if ((optFlds == NULL) || (MmsValue_getType(optFlds) != MMS_BIT_STRING)) { if ((optFlds == NULL) || (MmsValue_getType(optFlds) != MMS_BIT_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (OptFlds)\n"); printf("IED_CLIENT: received malformed report (OptFlds)\n");
@ -436,29 +458,31 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int inclusionIndex = 2; int inclusionIndex = 2;
/* has sequence-number */ /* has sequence-number */
if (MmsValue_getBitStringBit(optFlds, 1) == true) { if (MmsValue_getBitStringBit(optFlds, 1) == true)
{
MmsValue* seqNum = MmsValue_getElement(value, inclusionIndex); MmsValue* seqNum = MmsValue_getElement(value, inclusionIndex);
if ((seqNum == NULL) || (MmsValue_getType(seqNum) != MMS_UNSIGNED)) { if ((seqNum == NULL) || (MmsValue_getType(seqNum) != MMS_UNSIGNED))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (seqNum)\n"); printf("IED_CLIENT: received malformed report (seqNum)\n");
goto exit_function; goto exit_function;
} }
matchingReport->seqNum = (uint16_t) MmsValue_toUint32(seqNum); matchingReport->seqNum = (uint16_t)MmsValue_toUint32(seqNum);
matchingReport->hasSequenceNumber = true; matchingReport->hasSequenceNumber = true;
inclusionIndex++; inclusionIndex++;
} }
/* has report-timestamp */ /* has report-timestamp */
if (MmsValue_getBitStringBit(optFlds, 2) == true) { if (MmsValue_getBitStringBit(optFlds, 2) == true)
{
MmsValue* timeStampValue = MmsValue_getElement(value, inclusionIndex); MmsValue* timeStampValue = MmsValue_getElement(value, inclusionIndex);
if ((timeStampValue == NULL) || (MmsValue_getType(timeStampValue) != MMS_BINARY_TIME)) { if ((timeStampValue == NULL) || (MmsValue_getType(timeStampValue) != MMS_BINARY_TIME))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (timeStamp)\n"); printf("IED_CLIENT: received malformed report (timeStamp)\n");
@ -469,18 +493,20 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
matchingReport->timestamp = MmsValue_getBinaryTimeAsUtcMs(timeStampValue); matchingReport->timestamp = MmsValue_getBinaryTimeAsUtcMs(timeStampValue);
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: report has timestamp %llu\n", (unsigned long long) matchingReport->timestamp); printf("IED_CLIENT: report has timestamp %llu\n", (unsigned long long)matchingReport->timestamp);
inclusionIndex++; inclusionIndex++;
} }
/* check if data set name is present */ /* check if data set name is present */
if (MmsValue_getBitStringBit(optFlds, 4) == true) { if (MmsValue_getBitStringBit(optFlds, 4) == true)
{
matchingReport->hasDataSetName = true; matchingReport->hasDataSetName = true;
MmsValue* dataSetName = MmsValue_getElement(value, inclusionIndex); MmsValue* dataSetName = MmsValue_getElement(value, inclusionIndex);
if ((dataSetName == NULL) || (MmsValue_getType(dataSetName) != MMS_VISIBLE_STRING)) { if ((dataSetName == NULL) || (MmsValue_getType(dataSetName) != MMS_VISIBLE_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (DatSet)\n"); printf("IED_CLIENT: received malformed report (DatSet)\n");
@ -490,13 +516,16 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int dataSetNameSize = MmsValue_getStringSize(dataSetName); int dataSetNameSize = MmsValue_getStringSize(dataSetName);
/* limit to prevent large memory allocation */ /* limit to prevent large memory allocation */
if (dataSetNameSize < 130) { if (dataSetNameSize < 130)
{
const char* dataSetNameStr = MmsValue_toString(dataSetName); const char* dataSetNameStr = MmsValue_toString(dataSetName);
if (matchingReport->dataSetName == NULL) { if (matchingReport->dataSetName == NULL)
matchingReport->dataSetName = (char*) GLOBAL_MALLOC(dataSetNameSize + 1); {
matchingReport->dataSetName = (char*)GLOBAL_MALLOC(dataSetNameSize + 1);
if (matchingReport->dataSetName == NULL) { if (matchingReport->dataSetName == NULL)
{
matchingReport->dataSetNameSize = 0; matchingReport->dataSetNameSize = 0;
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -507,13 +536,16 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
matchingReport->dataSetNameSize = dataSetNameSize + 1; matchingReport->dataSetNameSize = dataSetNameSize + 1;
} }
else { else
if (matchingReport->dataSetNameSize < MmsValue_getStringSize(dataSetName) + 1) { {
GLOBAL_FREEMEM((void*) matchingReport->dataSetName); if (matchingReport->dataSetNameSize < MmsValue_getStringSize(dataSetName) + 1)
{
GLOBAL_FREEMEM((void*)matchingReport->dataSetName);
matchingReport->dataSetName = (char*) GLOBAL_MALLOC(dataSetNameSize + 1); matchingReport->dataSetName = (char*)GLOBAL_MALLOC(dataSetNameSize + 1);
if (matchingReport->dataSetName == NULL) { if (matchingReport->dataSetName == NULL)
{
matchingReport->dataSetNameSize = 0; matchingReport->dataSetNameSize = 0;
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -528,7 +560,8 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
StringUtils_copyStringMax(matchingReport->dataSetName, dataSetNameSize + 1, dataSetNameStr); StringUtils_copyStringMax(matchingReport->dataSetName, dataSetNameSize + 1, dataSetNameStr);
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: report DatSet name too large (%i)\n", dataSetNameSize); printf("IED_CLIENT: report DatSet name too large (%i)\n", dataSetNameSize);
@ -542,10 +575,12 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
printf("IED_CLIENT: Found enabled report!\n"); printf("IED_CLIENT: Found enabled report!\n");
/* check bufOvfl */ /* check bufOvfl */
if (MmsValue_getBitStringBit(optFlds, 6) == true) { if (MmsValue_getBitStringBit(optFlds, 6) == true)
{
MmsValue* bufOverflow = MmsValue_getElement(value, inclusionIndex); MmsValue* bufOverflow = MmsValue_getElement(value, inclusionIndex);
if ((bufOverflow == NULL) || (MmsValue_getType(bufOverflow) != MMS_BOOLEAN)) { if ((bufOverflow == NULL) || (MmsValue_getType(bufOverflow) != MMS_BOOLEAN))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (BufOvfl)\n"); printf("IED_CLIENT: received malformed report (BufOvfl)\n");
@ -559,24 +594,28 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
} }
/* check for entryId */ /* check for entryId */
if (MmsValue_getBitStringBit(optFlds, 7) == true) { if (MmsValue_getBitStringBit(optFlds, 7) == true)
{
MmsValue* entryId = MmsValue_getElement(value, inclusionIndex); MmsValue* entryId = MmsValue_getElement(value, inclusionIndex);
if ((entryId == NULL) || (MmsValue_getType(entryId) != MMS_OCTET_STRING)) { if ((entryId == NULL) || (MmsValue_getType(entryId) != MMS_OCTET_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (entryID)\n"); printf("IED_CLIENT: received malformed report (entryID)\n");
goto exit_function; goto exit_function;
} }
if (matchingReport->entryId != NULL) { if (matchingReport->entryId != NULL)
{
if (!MmsValue_update(matchingReport->entryId, entryId)) { if (!MmsValue_update(matchingReport->entryId, entryId))
{
MmsValue_delete(matchingReport->entryId); MmsValue_delete(matchingReport->entryId);
matchingReport->entryId = MmsValue_clone(entryId); matchingReport->entryId = MmsValue_clone(entryId);
} }
} }
else { else
{
matchingReport->entryId = MmsValue_clone(entryId); matchingReport->entryId = MmsValue_clone(entryId);
} }
@ -584,10 +623,12 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
} }
/* check for confRev */ /* check for confRev */
if (MmsValue_getBitStringBit(optFlds, 8) == true) { if (MmsValue_getBitStringBit(optFlds, 8) == true)
{
MmsValue* confRev = MmsValue_getElement(value, inclusionIndex); MmsValue* confRev = MmsValue_getElement(value, inclusionIndex);
if ((confRev == NULL) || (MmsValue_getType(confRev) != MMS_UNSIGNED)) { if ((confRev == NULL) || (MmsValue_getType(confRev) != MMS_UNSIGNED))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (confRev)\n"); printf("IED_CLIENT: received malformed report (confRev)\n");
@ -601,46 +642,53 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
} }
/* handle segmentation fields (check ReportedOptFlds.segmentation) */ /* handle segmentation fields (check ReportedOptFlds.segmentation) */
if (MmsValue_getBitStringBit(optFlds, 9) == true) { if (MmsValue_getBitStringBit(optFlds, 9) == true)
{
MmsValue* subSeqNum = MmsValue_getElement(value, inclusionIndex); MmsValue* subSeqNum = MmsValue_getElement(value, inclusionIndex);
inclusionIndex++; inclusionIndex++;
if ((subSeqNum == NULL) || (MmsValue_getType(subSeqNum) != MMS_UNSIGNED)) { if ((subSeqNum == NULL) || (MmsValue_getType(subSeqNum) != MMS_UNSIGNED))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (SubSeqNum)\n"); printf("IED_CLIENT: received malformed report (SubSeqNum)\n");
goto exit_function; goto exit_function;
} }
else { else
matchingReport->subSeqNum = (uint16_t) MmsValue_toUint32(subSeqNum); {
matchingReport->subSeqNum = (uint16_t)MmsValue_toUint32(subSeqNum);
} }
MmsValue* moreSegmentsFollow = MmsValue_getElement(value, inclusionIndex); MmsValue* moreSegmentsFollow = MmsValue_getElement(value, inclusionIndex);
inclusionIndex++; inclusionIndex++;
if ((moreSegmentsFollow == NULL) || (MmsValue_getType(moreSegmentsFollow) != MMS_BOOLEAN)) { if ((moreSegmentsFollow == NULL) || (MmsValue_getType(moreSegmentsFollow) != MMS_BOOLEAN))
if ((subSeqNum == NULL) || (MmsValue_getType(subSeqNum) != MMS_UNSIGNED)) { {
if ((subSeqNum == NULL) || (MmsValue_getType(subSeqNum) != MMS_UNSIGNED))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (MoreSegmentsFollow)\n"); printf("IED_CLIENT: received malformed report (MoreSegmentsFollow)\n");
goto exit_function; goto exit_function;
} }
} }
else { else
{
matchingReport->moreSegementsFollow = MmsValue_getBoolean(moreSegmentsFollow); matchingReport->moreSegementsFollow = MmsValue_getBoolean(moreSegmentsFollow);
} }
matchingReport->hasSequenceNumber = true; matchingReport->hasSequenceNumber = true;
} }
else { else
{
matchingReport->subSeqNum = 0; matchingReport->subSeqNum = 0;
matchingReport->moreSegementsFollow = false; matchingReport->moreSegementsFollow = false;
} }
MmsValue* inclusion = MmsValue_getElement(value, inclusionIndex); MmsValue* inclusion = MmsValue_getElement(value, inclusionIndex);
if ((inclusion == NULL) || (MmsValue_getType(inclusion) != MMS_BIT_STRING)) { if ((inclusion == NULL) || (MmsValue_getType(inclusion) != MMS_BIT_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (inclusion)\n"); printf("IED_CLIENT: received malformed report (inclusion)\n");
@ -649,11 +697,14 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int dataSetSize = MmsValue_getBitStringSize(inclusion); int dataSetSize = MmsValue_getBitStringSize(inclusion);
if (matchingReport->dataSetSize == -1) { if (matchingReport->dataSetSize == -1)
{
matchingReport->dataSetSize = dataSetSize; matchingReport->dataSetSize = dataSetSize;
} }
else { else
if (dataSetSize != matchingReport->dataSetSize) { {
if (dataSetSize != matchingReport->dataSetSize)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (inclusion has no plausible size)\n"); printf("IED_CLIENT: received malformed report (inclusion has no plausible size)\n");
@ -664,14 +715,13 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int includedElements = MmsValue_getNumberOfSetBits(inclusion); int includedElements = MmsValue_getNumberOfSetBits(inclusion);
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: Report includes %i data set elements of %i\n", includedElements, printf("IED_CLIENT: Report includes %i data set elements of %i\n", includedElements, dataSetSize);
dataSetSize);
int valueIndex = inclusionIndex + 1; int valueIndex = inclusionIndex + 1;
/* parse data-references if required */ /* parse data-references if required */
if (MmsValue_getBitStringBit(optFlds, 5) == true) { if (MmsValue_getBitStringBit(optFlds, 5) == true)
{
if (matchingReport->dataReferences == NULL) if (matchingReport->dataReferences == NULL)
matchingReport->dataReferences = MmsValue_createEmptyArray(dataSetSize); matchingReport->dataReferences = MmsValue_createEmptyArray(dataSetSize);
@ -679,19 +729,23 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int elementIndex; int elementIndex;
for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++) { for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++)
if (MmsValue_getBitStringBit(inclusion, elementIndex) == true) { {
if (MmsValue_getBitStringBit(inclusion, elementIndex) == true)
{
MmsValue* dataSetElement = MmsValue_getElement(matchingReport->dataReferences, elementIndex); MmsValue* dataSetElement = MmsValue_getElement(matchingReport->dataReferences, elementIndex);
if (dataSetElement == NULL) { if (dataSetElement == NULL)
{
MmsValue* dataRefValue = MmsValue_getElement(value, valueIndex); MmsValue* dataRefValue = MmsValue_getElement(value, valueIndex);
if ((dataRefValue == NULL) || (MmsValue_getType(dataRefValue) != MMS_VISIBLE_STRING)) { if ((dataRefValue == NULL) || (MmsValue_getType(dataRefValue) != MMS_VISIBLE_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: report contains invalid data reference\n"); printf("IED_CLIENT: report contains invalid data reference\n");
} }
else { else
{
dataSetElement = MmsValue_clone(dataRefValue); dataSetElement = MmsValue_clone(dataRefValue);
MmsValue_setElement(matchingReport->dataReferences, elementIndex, dataSetElement); MmsValue_setElement(matchingReport->dataReferences, elementIndex, dataSetElement);
@ -705,16 +759,23 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int i; int i;
if (matchingReport->dataSetValues == NULL) { if (matchingReport->dataSetValues == NULL)
{
matchingReport->dataSetValues = MmsValue_createEmptyArray(dataSetSize); matchingReport->dataSetValues = MmsValue_createEmptyArray(dataSetSize);
matchingReport->reasonForInclusion = (ReasonForInclusion*) matchingReport->reasonForInclusion =
GLOBAL_MALLOC(sizeof(ReasonForInclusion) * dataSetSize); (ReasonForInclusion*)GLOBAL_MALLOC(sizeof(ReasonForInclusion) * dataSetSize);
if (matchingReport->reasonForInclusion)
{
int elementIndex; int elementIndex;
for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++) for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++)
matchingReport->reasonForInclusion[elementIndex] = IEC61850_REASON_NOT_INCLUDED; matchingReport->reasonForInclusion[elementIndex] = IEC61850_REASON_NOT_INCLUDED;
}
else
{
goto exit_function;
}
} }
MmsValue* dataSetValues = matchingReport->dataSetValues; MmsValue* dataSetValues = matchingReport->dataSetValues;
@ -724,14 +785,16 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
if (hasReasonForInclusion) if (hasReasonForInclusion)
matchingReport->hasReasonForInclusion = true; matchingReport->hasReasonForInclusion = true;
for (i = 0; i < dataSetSize; i++) { for (i = 0; i < dataSetSize; i++)
if (MmsValue_getBitStringBit(inclusion, i) == true) { {
if (MmsValue_getBitStringBit(inclusion, i) == true)
{
MmsValue* dataSetElement = MmsValue_getElement(dataSetValues, i); MmsValue* dataSetElement = MmsValue_getElement(dataSetValues, i);
MmsValue* newElementValue = MmsValue_getElement(value, valueIndex); MmsValue* newElementValue = MmsValue_getElement(value, valueIndex);
if (newElementValue == NULL) { if (newElementValue == NULL)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: report is missing expected element value\n"); printf("IED_CLIENT: report is missing expected element value\n");
@ -746,10 +809,12 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue)); printf("IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue));
if (hasReasonForInclusion) { if (hasReasonForInclusion)
{
MmsValue* reasonForInclusion = MmsValue_getElement(value, includedElements + valueIndex); MmsValue* reasonForInclusion = MmsValue_getElement(value, includedElements + valueIndex);
if ((reasonForInclusion == NULL) || (MmsValue_getType(reasonForInclusion) != MMS_BIT_STRING)) { if ((reasonForInclusion == NULL) || (MmsValue_getType(reasonForInclusion) != MMS_BIT_STRING))
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: report contains invalid reason-for-inclusion\n"); printf("IED_CLIENT: report contains invalid reason-for-inclusion\n");
@ -759,7 +824,7 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
matchingReport->reasonForInclusion[i] = IEC61850_REASON_NOT_INCLUDED; matchingReport->reasonForInclusion[i] = IEC61850_REASON_NOT_INCLUDED;
if (MmsValue_getBitStringBit(reasonForInclusion, 1) == true) if (MmsValue_getBitStringBit(reasonForInclusion, 1) == true)
matchingReport->reasonForInclusion[i] |= (ReasonForInclusion) IEC61850_REASON_DATA_CHANGE; matchingReport->reasonForInclusion[i] |= (ReasonForInclusion)IEC61850_REASON_DATA_CHANGE;
if (MmsValue_getBitStringBit(reasonForInclusion, 2) == true) if (MmsValue_getBitStringBit(reasonForInclusion, 2) == true)
matchingReport->reasonForInclusion[i] |= IEC61850_REASON_QUALITY_CHANGE; matchingReport->reasonForInclusion[i] |= IEC61850_REASON_QUALITY_CHANGE;
if (MmsValue_getBitStringBit(reasonForInclusion, 3) == true) if (MmsValue_getBitStringBit(reasonForInclusion, 3) == true)
@ -769,18 +834,20 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
if (MmsValue_getBitStringBit(reasonForInclusion, 5) == true) if (MmsValue_getBitStringBit(reasonForInclusion, 5) == true)
matchingReport->reasonForInclusion[i] |= IEC61850_REASON_GI; matchingReport->reasonForInclusion[i] |= IEC61850_REASON_GI;
} }
else { else
{
matchingReport->reasonForInclusion[i] = IEC61850_REASON_UNKNOWN; matchingReport->reasonForInclusion[i] = IEC61850_REASON_UNKNOWN;
} }
valueIndex++; valueIndex++;
} }
else { else
{
matchingReport->reasonForInclusion[i] = IEC61850_REASON_NOT_INCLUDED; matchingReport->reasonForInclusion[i] = IEC61850_REASON_NOT_INCLUDED;
} }
} }
if (matchingReport->callback != NULL) if (matchingReport->callback)
matchingReport->callback(matchingReport->callbackParameter, matchingReport); matchingReport->callback(matchingReport->callbackParameter, matchingReport);
exit_function: exit_function:
@ -789,4 +856,3 @@ exit_function:
return; return;
} }

@ -60,16 +60,19 @@ ClientReportControlBlock_create(const char* objectReference)
isBuffered = isBufferedRcb(objectReference, &isReferenceValid); isBuffered = isBufferedRcb(objectReference, &isReferenceValid);
if (isReferenceValid == false) { if (isReferenceValid == false)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: RCB reference invalid\n"); printf("DEBUG_IED_CLIENT: RCB reference invalid\n");
return NULL; return NULL;
} }
ClientReportControlBlock self = (ClientReportControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock)); ClientReportControlBlock self =
(ClientReportControlBlock)GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock));
if (self) { if (self)
{
self->objectReference = StringUtils_copyString(objectReference); self->objectReference = StringUtils_copyString(objectReference);
self->isBuffered = isBuffered; self->isBuffered = isBuffered;
} }
@ -80,6 +83,8 @@ ClientReportControlBlock_create(const char* objectReference)
void void
ClientReportControlBlock_destroy(ClientReportControlBlock self) ClientReportControlBlock_destroy(ClientReportControlBlock self)
{ {
if (self)
{
GLOBAL_FREEMEM(self->objectReference); GLOBAL_FREEMEM(self->objectReference);
MmsValue_delete(self->rptId); MmsValue_delete(self->rptId);
@ -100,6 +105,7 @@ ClientReportControlBlock_destroy(ClientReportControlBlock self)
MmsValue_delete(self->owner); MmsValue_delete(self->owner);
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
}
} }
char* char*
@ -117,7 +123,7 @@ ClientReportControlBlock_isBuffered(ClientReportControlBlock self)
const char* const char*
ClientReportControlBlock_getRptId(ClientReportControlBlock self) ClientReportControlBlock_getRptId(ClientReportControlBlock self)
{ {
if (self->rptId != NULL) if (self->rptId)
return MmsValue_toString(self->rptId); return MmsValue_toString(self->rptId);
else else
return NULL; return NULL;
@ -132,11 +138,11 @@ ClientReportControlBlock_setRptId(ClientReportControlBlock self, const char* rpt
MmsValue_setVisibleString(self->rptId, rptId); MmsValue_setVisibleString(self->rptId, rptId);
} }
bool bool
ClientReportControlBlock_getRptEna(ClientReportControlBlock self) ClientReportControlBlock_getRptEna(ClientReportControlBlock self)
{ {
if (self->rptEna != NULL) { if (self->rptEna)
{
return MmsValue_getBoolean(self->rptEna); return MmsValue_getBoolean(self->rptEna);
} }
else else
@ -155,7 +161,8 @@ ClientReportControlBlock_setRptEna(ClientReportControlBlock self, bool rptEna)
bool bool
ClientReportControlBlock_getResv(ClientReportControlBlock self) ClientReportControlBlock_getResv(ClientReportControlBlock self)
{ {
if (self->resv != NULL) { if (self->resv)
{
return MmsValue_getBoolean(self->resv); return MmsValue_getBoolean(self->resv);
} }
else else
@ -174,7 +181,7 @@ ClientReportControlBlock_setResv(ClientReportControlBlock self, bool resv)
const char* const char*
ClientReportControlBlock_getDataSetReference(ClientReportControlBlock self) ClientReportControlBlock_getDataSetReference(ClientReportControlBlock self)
{ {
if (self->datSet != NULL) if (self->datSet)
return MmsValue_toString(self->datSet); return MmsValue_toString(self->datSet);
else else
return NULL; return NULL;
@ -192,7 +199,7 @@ ClientReportControlBlock_setDataSetReference(ClientReportControlBlock self, cons
uint32_t uint32_t
ClientReportControlBlock_getConfRev(ClientReportControlBlock self) ClientReportControlBlock_getConfRev(ClientReportControlBlock self)
{ {
if (self->confRev != NULL) if (self->confRev)
return MmsValue_toUint32(self->confRev); return MmsValue_toUint32(self->confRev);
else else
return 0; return 0;
@ -219,7 +226,7 @@ ClientReportControlBlock_setOptFlds(ClientReportControlBlock self, int optFlds)
uint32_t uint32_t
ClientReportControlBlock_getBufTm(ClientReportControlBlock self) ClientReportControlBlock_getBufTm(ClientReportControlBlock self)
{ {
if (self->bufTm != NULL) if (self->bufTm)
return MmsValue_toUint32(self->bufTm); return MmsValue_toUint32(self->bufTm);
else else
return 0; return 0;
@ -237,7 +244,7 @@ ClientReportControlBlock_setBufTm(ClientReportControlBlock self, uint32_t bufTm)
uint16_t uint16_t
ClientReportControlBlock_getSqNum(ClientReportControlBlock self) ClientReportControlBlock_getSqNum(ClientReportControlBlock self)
{ {
if (self->sqNum != NULL) if (self->sqNum)
return (uint16_t) MmsValue_toUint32(self->sqNum); return (uint16_t) MmsValue_toUint32(self->sqNum);
else else
return 0; return 0;
@ -248,7 +255,8 @@ ClientReportControlBlock_getTrgOps(ClientReportControlBlock self)
{ {
int triggerOps = 0; int triggerOps = 0;
if (self->trgOps != NULL) { if (self->trgOps)
{
if (MmsValue_getBitStringBit(self->trgOps, 1)) if (MmsValue_getBitStringBit(self->trgOps, 1))
triggerOps += TRG_OPT_DATA_CHANGED; triggerOps += TRG_OPT_DATA_CHANGED;
if (MmsValue_getBitStringBit(self->trgOps, 2)) if (MmsValue_getBitStringBit(self->trgOps, 2))
@ -276,7 +284,7 @@ ClientReportControlBlock_setTrgOps(ClientReportControlBlock self, int trgOps)
uint32_t uint32_t
ClientReportControlBlock_getIntgPd(ClientReportControlBlock self) ClientReportControlBlock_getIntgPd(ClientReportControlBlock self)
{ {
if (self->intgPd != NULL) if (self->intgPd)
return MmsValue_toUint32(self->intgPd); return MmsValue_toUint32(self->intgPd);
else else
return 0; return 0;
@ -294,7 +302,7 @@ ClientReportControlBlock_setIntgPd(ClientReportControlBlock self, uint32_t intgP
bool bool
ClientReportControlBlock_getGI(ClientReportControlBlock self) ClientReportControlBlock_getGI(ClientReportControlBlock self)
{ {
if (self->gi != NULL) if (self->gi)
return MmsValue_getBoolean(self->gi); return MmsValue_getBoolean(self->gi);
else else
return false; return false;
@ -312,7 +320,7 @@ ClientReportControlBlock_setGI(ClientReportControlBlock self, bool gi)
bool bool
ClientReportControlBlock_getPurgeBuf(ClientReportControlBlock self) ClientReportControlBlock_getPurgeBuf(ClientReportControlBlock self)
{ {
if (self->purgeBuf != NULL) if (self->purgeBuf)
return MmsValue_getBoolean(self->purgeBuf); return MmsValue_getBoolean(self->purgeBuf);
else else
return false; return false;
@ -336,7 +344,7 @@ ClientReportControlBlock_hasResvTms(ClientReportControlBlock self)
int16_t int16_t
ClientReportControlBlock_getResvTms(ClientReportControlBlock self) ClientReportControlBlock_getResvTms(ClientReportControlBlock self)
{ {
if (self->resvTms != NULL) if (self->resvTms)
return (int16_t) MmsValue_toInt32(self->resvTms); return (int16_t) MmsValue_toInt32(self->resvTms);
else else
return 0; return 0;
@ -360,11 +368,14 @@ ClientReportControlBlock_getEntryId(ClientReportControlBlock self)
void void
ClientReportControlBlock_setEntryId(ClientReportControlBlock self, MmsValue* entryId) ClientReportControlBlock_setEntryId(ClientReportControlBlock self, MmsValue* entryId)
{ {
if (self->entryId != NULL) { if (self->entryId)
{
MmsValue_update(self->entryId, entryId); MmsValue_update(self->entryId, entryId);
} }
else { else
if (MmsValue_getType(entryId) != MMS_OCTET_STRING) { {
if (MmsValue_getType(entryId) != MMS_OCTET_STRING)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ClientReportControlBlock_setEntryId invalid argument type\n"); printf("IED_CLIENT: ClientReportControlBlock_setEntryId invalid argument type\n");
} }
@ -376,7 +387,7 @@ ClientReportControlBlock_setEntryId(ClientReportControlBlock self, MmsValue* ent
uint64_t uint64_t
ClientReportControlBlock_getEntryTime(ClientReportControlBlock self) ClientReportControlBlock_getEntryTime(ClientReportControlBlock self)
{ {
if (self->timeOfEntry != NULL) if (self->timeOfEntry)
return MmsValue_getBinaryTimeAsUtcMs(self->timeOfEntry); return MmsValue_getBinaryTimeAsUtcMs(self->timeOfEntry);
else else
return 0; return 0;
@ -391,7 +402,7 @@ ClientReportControlBlock_getOwner(ClientReportControlBlock self)
static void static void
updateOrClone(MmsValue** valuePtr, MmsValue* values, int index) updateOrClone(MmsValue** valuePtr, MmsValue* values, int index)
{ {
if (*valuePtr != NULL) if (*valuePtr)
MmsValue_update(*valuePtr, MmsValue_getElement(values, index)); MmsValue_update(*valuePtr, MmsValue_getElement(values, index));
else else
*valuePtr = MmsValue_clone(MmsValue_getElement(values, index)); *valuePtr = MmsValue_clone(MmsValue_getElement(values, index));
@ -421,53 +432,87 @@ clientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* v
int rcbElementCount = MmsValue_getArraySize(values); int rcbElementCount = MmsValue_getArraySize(values);
if (self->isBuffered) { if (self->isBuffered)
if ((rcbElementCount < 13) || (rcbElementCount > 15)) { {
if ((rcbElementCount < 13) || (rcbElementCount > 15))
{
return false; return false;
} }
if (!checkElementType(values, 0, MMS_VISIBLE_STRING)) return false; if (!checkElementType(values, 0, MMS_VISIBLE_STRING))
if (!checkElementType(values, 1, MMS_BOOLEAN)) return false; return false;
if (!checkElementType(values, 2, MMS_VISIBLE_STRING)) return false; if (!checkElementType(values, 1, MMS_BOOLEAN))
if (!checkElementType(values, 3, MMS_UNSIGNED)) return false; return false;
if (!checkElementType(values, 4, MMS_BIT_STRING)) return false; if (!checkElementType(values, 2, MMS_VISIBLE_STRING))
if (!checkElementType(values, 5, MMS_UNSIGNED)) return false; return false;
if (!checkElementType(values, 6, MMS_UNSIGNED)) return false; if (!checkElementType(values, 3, MMS_UNSIGNED))
if (!checkElementType(values, 7, MMS_BIT_STRING)) return false; return false;
if (!checkElementType(values, 8, MMS_UNSIGNED)) return false; if (!checkElementType(values, 4, MMS_BIT_STRING))
if (!checkElementType(values, 9, MMS_BOOLEAN)) return false; return false;
if (!checkElementType(values, 10, MMS_BOOLEAN)) return false; if (!checkElementType(values, 5, MMS_UNSIGNED))
if (!checkElementType(values, 11, MMS_OCTET_STRING)) return false; return false;
if (!checkElementType(values, 12, MMS_BINARY_TIME)) return false; if (!checkElementType(values, 6, MMS_UNSIGNED))
return false;
if (rcbElementCount == 14) { if (!checkElementType(values, 7, MMS_BIT_STRING))
return false;
if (!checkElementType(values, 8, MMS_UNSIGNED))
return false;
if (!checkElementType(values, 9, MMS_BOOLEAN))
return false;
if (!checkElementType(values, 10, MMS_BOOLEAN))
return false;
if (!checkElementType(values, 11, MMS_OCTET_STRING))
return false;
if (!checkElementType(values, 12, MMS_BINARY_TIME))
return false;
if (rcbElementCount == 14)
{
if (!checkElementType(values, 13, MMS_OCTET_STRING) && !checkElementType(values, 13, MMS_INTEGER)) if (!checkElementType(values, 13, MMS_OCTET_STRING) && !checkElementType(values, 13, MMS_INTEGER))
return false; return false;
} }
else if (rcbElementCount == 15) { else if (rcbElementCount == 15)
if (!checkElementType(values, 13, MMS_INTEGER)) return false; {
if (!checkElementType(values, 14, MMS_OCTET_STRING)) return false; if (!checkElementType(values, 13, MMS_INTEGER))
return false;
if (!checkElementType(values, 14, MMS_OCTET_STRING))
return false;
} }
} }
else { else
if ((rcbElementCount < 11) || (rcbElementCount > 12)) { {
if ((rcbElementCount < 11) || (rcbElementCount > 12))
{
return false; return false;
} }
if (!checkElementType(values, 0, MMS_VISIBLE_STRING)) return false; if (!checkElementType(values, 0, MMS_VISIBLE_STRING))
if (!checkElementType(values, 1, MMS_BOOLEAN)) return false; return false;
if (!checkElementType(values, 2, MMS_BOOLEAN)) return false; if (!checkElementType(values, 1, MMS_BOOLEAN))
if (!checkElementType(values, 3, MMS_VISIBLE_STRING)) return false; return false;
if (!checkElementType(values, 4, MMS_UNSIGNED)) return false; if (!checkElementType(values, 2, MMS_BOOLEAN))
if (!checkElementType(values, 5, MMS_BIT_STRING)) return false; return false;
if (!checkElementType(values, 6, MMS_UNSIGNED)) return false; if (!checkElementType(values, 3, MMS_VISIBLE_STRING))
if (!checkElementType(values, 7, MMS_UNSIGNED)) return false; return false;
if (!checkElementType(values, 8, MMS_BIT_STRING)) return false; if (!checkElementType(values, 4, MMS_UNSIGNED))
if (!checkElementType(values, 9, MMS_UNSIGNED)) return false; return false;
if (!checkElementType(values, 10, MMS_BOOLEAN)) return false; if (!checkElementType(values, 5, MMS_BIT_STRING))
return false;
if (!checkElementType(values, 6, MMS_UNSIGNED))
return false;
if (!checkElementType(values, 7, MMS_UNSIGNED))
return false;
if (!checkElementType(values, 8, MMS_BIT_STRING))
return false;
if (!checkElementType(values, 9, MMS_UNSIGNED))
return false;
if (!checkElementType(values, 10, MMS_BOOLEAN))
return false;
if (rcbElementCount == 12) { if (rcbElementCount == 12)
if (!checkElementType(values, 11, MMS_OCTET_STRING)) return false; {
if (!checkElementType(values, 11, MMS_OCTET_STRING))
return false;
} }
} }
@ -476,34 +521,37 @@ clientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* v
updateOrClone(&(self->rptId), values, 0); updateOrClone(&(self->rptId), values, 0);
updateOrClone(&(self->rptEna), values, 1); updateOrClone(&(self->rptEna), values, 1);
if (self->isBuffered) { if (self->isBuffered)
{
updateOrClone(&(self->datSet), values, 2); updateOrClone(&(self->datSet), values, 2);
updateOrClone(&(self->confRev), values, 3); updateOrClone(&(self->confRev), values, 3);
updateOrClone(&(self->optFlds), values, 4); updateOrClone(&(self->optFlds), values, 4);
updateOrClone(&(self->bufTm), values, 5); updateOrClone(&(self->bufTm), values, 5);
updateOrClone(&(self->sqNum), values, 6); updateOrClone(&(self->sqNum), values, 6);
updateOrClone(&(self->trgOps), values,7); updateOrClone(&(self->trgOps), values, 7);
updateOrClone(&(self->intgPd), values, 8); updateOrClone(&(self->intgPd), values, 8);
updateOrClone(&(self->gi), values, 9); updateOrClone(&(self->gi), values, 9);
updateOrClone(&(self->purgeBuf), values, 10); updateOrClone(&(self->purgeBuf), values, 10);
updateOrClone(&(self->entryId), values, 11); updateOrClone(&(self->entryId), values, 11);
updateOrClone(&(self->timeOfEntry), values, 12); updateOrClone(&(self->timeOfEntry), values, 12);
if (rcbElementCount > 13) { if (rcbElementCount > 13)
{
MmsValue* element13 = MmsValue_getElement(values, 13); MmsValue* element13 = MmsValue_getElement(values, 13);
if (MmsValue_getType(element13) == MMS_OCTET_STRING) if (MmsValue_getType(element13) == MMS_OCTET_STRING)
updateOrClone(&(self->owner), values, 13); updateOrClone(&(self->owner), values, 13);
else { else
{
updateOrClone(&(self->resvTms), values, 13); updateOrClone(&(self->resvTms), values, 13);
if (rcbElementCount > 14) if (rcbElementCount > 14)
updateOrClone(&(self->owner), values, 14); updateOrClone(&(self->owner), values, 14);
} }
} }
} }
else { else
{
updateOrClone(&(self->resv), values, 2); updateOrClone(&(self->resv), values, 2);
updateOrClone(&(self->datSet), values, 3); updateOrClone(&(self->datSet), values, 3);
updateOrClone(&(self->confRev), values, 4); updateOrClone(&(self->confRev), values, 4);
@ -667,30 +715,33 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char
MmsValue* rcb = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId); MmsValue* rcb = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId);
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE)
{
*error = iedConnection_mapMmsErrorToIedError(mmsError); *error = iedConnection_mapMmsErrorToIedError(mmsError);
return NULL; return NULL;
} }
if (rcb == NULL) { if (rcb == NULL)
{
*error = IED_ERROR_OBJECT_DOES_NOT_EXIST; *error = IED_ERROR_OBJECT_DOES_NOT_EXIST;
return NULL; return NULL;
} }
if (MmsValue_getType(rcb) == MMS_DATA_ACCESS_ERROR) { if (MmsValue_getType(rcb) == MMS_DATA_ACCESS_ERROR)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getRCBValues returned data-access-error!\n"); printf("DEBUG_IED_CLIENT: getRCBValues returned data-access-error!\n");
*error = iedConnection_mapDataAccessErrorToIedError( *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(rcb));
MmsValue_getDataAccessError(rcb));
MmsValue_delete(rcb); MmsValue_delete(rcb);
return NULL; return NULL;
} }
if (MmsValue_getType(rcb) != MMS_STRUCTURE) { if (MmsValue_getType(rcb) != MMS_STRUCTURE)
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n"); printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n");
@ -703,16 +754,19 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char
if (returnRcb == NULL) if (returnRcb == NULL)
returnRcb = ClientReportControlBlock_create(rcbReference); returnRcb = ClientReportControlBlock_create(rcbReference);
if (clientReportControlBlock_updateValues(returnRcb, rcb)) { if (clientReportControlBlock_updateValues(returnRcb, rcb))
{
*error = IED_ERROR_OK; *error = IED_ERROR_OK;
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n"); printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n");
*error = IED_ERROR_TYPE_INCONSISTENT; *error = IED_ERROR_TYPE_INCONSISTENT;
if (updateRcb == NULL) { if (updateRcb == NULL)
{
ClientReportControlBlock_destroy(returnRcb); ClientReportControlBlock_destroy(returnRcb);
returnRcb = NULL; returnRcb = NULL;
} }
@ -724,26 +778,30 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char
} }
static void static void
writeMultipleVariablesHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsValue*> */ accessResults) writeMultipleVariablesHandler(uint32_t invokeId, void* parameter, MmsError mmsError,
LinkedList /* <MmsValue*> */ accessResults)
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection)parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call)
{
IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler) call->callback; IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler)call->callback;
if (accessResults != NULL) { if (accessResults)
{
IedClientError error = IED_ERROR_OK; IedClientError error = IED_ERROR_OK;
LinkedList accessResult = LinkedList_getNext(accessResults); LinkedList accessResult = LinkedList_getNext(accessResults);
while (accessResult != NULL) { while (accessResult)
MmsValue* dataAccessError = (MmsValue*) accessResult->data; {
MmsValue* dataAccessError = (MmsValue*)accessResult->data;
if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS) { if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS)
{
error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(dataAccessError)); error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(dataAccessError));
break; break;
} }
@ -751,17 +809,19 @@ writeMultipleVariablesHandler(uint32_t invokeId, void* parameter, MmsError mmsEr
accessResult = LinkedList_getNext(accessResult); accessResult = LinkedList_getNext(accessResult);
} }
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete); LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction)MmsValue_delete);
handler(invokeId, call->callbackParameter, error); handler(invokeId, call->callbackParameter, error);
} }
else { else
{
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(mmsError)); handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(mmsError));
} }
iedConnection_releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call with invoke ID: %u!\n", invokeId); printf("IED_CLIENT: internal error - no matching outstanding call with invoke ID: %u!\n", invokeId);
} }
@ -793,18 +853,19 @@ releaseWriteCall(IedConnection self, IedConnectionOutstandingCall call, struct s
static void static void
writeVariableHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsDataAccessError accessError) writeVariableHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsDataAccessError accessError)
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection)parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call)
{
IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler) call->callback; IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler)call->callback;
struct sWriteRcbVariablesParameter* param = (struct sWriteRcbVariablesParameter*) call->specificParameter2.pointer;
if ((mmsError != MMS_ERROR_NONE) || (accessError != DATA_ACCESS_ERROR_SUCCESS)) { struct sWriteRcbVariablesParameter* param =
(struct sWriteRcbVariablesParameter*)call->specificParameter2.pointer;
if ((mmsError != MMS_ERROR_NONE) || (accessError != DATA_ACCESS_ERROR_SUCCESS))
{
IedClientError err; IedClientError err;
if (mmsError != MMS_ERROR_NONE) if (mmsError != MMS_ERROR_NONE)
@ -821,30 +882,36 @@ writeVariableHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsD
param->currentItemId = LinkedList_getNext(param->currentItemId); param->currentItemId = LinkedList_getNext(param->currentItemId);
if (param->currentItemId == NULL) { if (param->currentItemId == NULL)
{
handler(param->originalInvokeId, call->callbackParameter, IED_ERROR_OK); handler(param->originalInvokeId, call->callbackParameter, IED_ERROR_OK);
releaseWriteCall(self, call, param); releaseWriteCall(self, call, param);
} }
else { else
{
param->currentValue = LinkedList_getNext(param->currentValue); param->currentValue = LinkedList_getNext(param->currentValue);
char* itemId = (char*) LinkedList_getData(param->currentItemId); char* itemId = (char*)LinkedList_getData(param->currentItemId);
MmsValue* value = (MmsValue*) LinkedList_getData(param->currentValue); MmsValue* value = (MmsValue*)LinkedList_getData(param->currentValue);
MmsError writeError; MmsError writeError;
MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &writeError, param->domainId, itemId, value, writeVariableHandler, self); MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &writeError, param->domainId, itemId,
value, writeVariableHandler, self);
if (writeError != MMS_ERROR_NONE) { if (writeError != MMS_ERROR_NONE)
{
handler(param->originalInvokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(writeError)); handler(param->originalInvokeId, call->callbackParameter,
iedConnection_mapMmsErrorToIedError(writeError));
releaseWriteCall(self, call, param); releaseWriteCall(self, call, param);
} }
} }
} }
else { else
{
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n"); printf("IED_CLIENT: internal error - no matching outstanding call!\n");
} }
@ -856,7 +923,8 @@ exit_function:
uint32_t uint32_t
IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, ClientReportControlBlock rcb, IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, ClientReportControlBlock rcb,
uint32_t parametersMask, bool singleRequest, IedConnection_GenericServiceHandler handler, void* parameter) uint32_t parametersMask, bool singleRequest,
IedConnection_GenericServiceHandler handler, void* parameter)
{ {
uint32_t invokeId = 0; uint32_t invokeId = 0;
@ -883,7 +951,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
LinkedList values = LinkedList_create(); LinkedList values = LinkedList_create();
/* add resv/resvTms as first element and rptEna as last element */ /* add resv/resvTms as first element and rptEna as last element */
if (parametersMask & RCB_ELEMENT_RESV) { if (parametersMask & RCB_ELEMENT_RESV)
{
if (isBuffered) if (isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -895,7 +964,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_RESV_TMS) { if (parametersMask & RCB_ELEMENT_RESV_TMS)
{
if (!isBuffered) if (!isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -907,7 +977,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_RPT_ID) { if (parametersMask & RCB_ELEMENT_RPT_ID)
{
StringUtils_appendString(itemId, 130, "$RptID"); StringUtils_appendString(itemId, 130, "$RptID");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -916,7 +987,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_DATSET) { if (parametersMask & RCB_ELEMENT_DATSET)
{
StringUtils_appendString(itemId, 130, "$DatSet"); StringUtils_appendString(itemId, 130, "$DatSet");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -925,7 +997,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_ENTRY_ID) { if (parametersMask & RCB_ELEMENT_ENTRY_ID)
{
StringUtils_appendString(itemId, 130, "$EntryID"); StringUtils_appendString(itemId, 130, "$EntryID");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -934,7 +1007,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_OPT_FLDS) { if (parametersMask & RCB_ELEMENT_OPT_FLDS)
{
StringUtils_appendString(itemId, 130, "$OptFlds"); StringUtils_appendString(itemId, 130, "$OptFlds");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -943,7 +1017,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_BUF_TM) { if (parametersMask & RCB_ELEMENT_BUF_TM)
{
StringUtils_appendString(itemId, 130, "$BufTm"); StringUtils_appendString(itemId, 130, "$BufTm");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -952,7 +1027,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_TRG_OPS) { if (parametersMask & RCB_ELEMENT_TRG_OPS)
{
StringUtils_appendString(itemId, 130, "$TrgOps"); StringUtils_appendString(itemId, 130, "$TrgOps");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -961,7 +1037,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_INTG_PD) { if (parametersMask & RCB_ELEMENT_INTG_PD)
{
StringUtils_appendString(itemId, 130, "$IntgPd"); StringUtils_appendString(itemId, 130, "$IntgPd");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -970,14 +1047,16 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_GI) { if (parametersMask & RCB_ELEMENT_GI)
{
if (parametersMask & RCB_ELEMENT_RPT_ENA) { if (parametersMask & RCB_ELEMENT_RPT_ENA)
{
if (MmsValue_getBoolean(rcb->rptEna)) if (MmsValue_getBoolean(rcb->rptEna))
sendGILast = true; sendGILast = true;
} }
if (sendGILast == false) { if (sendGILast == false)
{
StringUtils_appendString(itemId, 130, "$GI"); StringUtils_appendString(itemId, 130, "$GI");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -987,7 +1066,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
} }
} }
if (parametersMask & RCB_ELEMENT_PURGE_BUF) { if (parametersMask & RCB_ELEMENT_PURGE_BUF)
{
if (!isBuffered) if (!isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -999,7 +1079,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY) { if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY)
{
if (!isBuffered) if (!isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -1011,7 +1092,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_RPT_ENA) { if (parametersMask & RCB_ELEMENT_RPT_ENA)
{
StringUtils_appendString(itemId, 130, "$RptEna"); StringUtils_appendString(itemId, 130, "$RptEna");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1020,7 +1102,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (sendGILast) { if (sendGILast)
{
StringUtils_appendString(itemId, 130, "$GI"); StringUtils_appendString(itemId, 130, "$GI");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1031,7 +1114,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL) { if (call == NULL)
{
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
goto exit_function; goto exit_function;
} }
@ -1042,24 +1126,34 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
MmsError err; MmsError err;
if (singleRequest) { if (singleRequest)
{
MmsConnection_writeMultipleVariablesAsync(self->connection, &(call->invokeId), &err, domainId, itemIds, values, writeMultipleVariablesHandler, self); MmsConnection_writeMultipleVariablesAsync(self->connection, &(call->invokeId), &err, domainId, itemIds, values,
writeMultipleVariablesHandler, self);
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) { if (err != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else
{
invokeId = call->invokeId; invokeId = call->invokeId;
} }
goto exit_function; goto exit_function;
} }
else { else
{
struct sWriteRcbVariablesParameter* param =
(struct sWriteRcbVariablesParameter*)GLOBAL_MALLOC(sizeof(struct sWriteRcbVariablesParameter));
struct sWriteRcbVariablesParameter* param = (struct sWriteRcbVariablesParameter*) GLOBAL_MALLOC(sizeof(struct sWriteRcbVariablesParameter)); if (param == NULL)
{
*error = IED_ERROR_UNKNOWN;
goto exit_function;
}
call->specificParameter2.pointer = param; call->specificParameter2.pointer = param;
@ -1070,10 +1164,11 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
param->currentValue = LinkedList_getNext(values); param->currentValue = LinkedList_getNext(values);
param->domainId = StringUtils_copyString(domainId); param->domainId = StringUtils_copyString(domainId);
char* variableId = (char*) LinkedList_getData(param->currentItemId); char* variableId = (char*)LinkedList_getData(param->currentItemId);
MmsValue* value = (MmsValue*) LinkedList_getData(param->currentValue); MmsValue* value = (MmsValue*)LinkedList_getData(param->currentValue);
MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &err, domainId, variableId, value, writeVariableHandler, self); MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &err, domainId, variableId, value,
writeVariableHandler, self);
param->originalInvokeId = call->invokeId; param->originalInvokeId = call->invokeId;
@ -1081,7 +1176,8 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) { if (err != MMS_ERROR_NONE)
{
iedConnection_releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
GLOBAL_FREEMEM(param->domainId); GLOBAL_FREEMEM(param->domainId);
GLOBAL_FREEMEM(param); GLOBAL_FREEMEM(param);
@ -1132,8 +1228,10 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
LinkedList values = LinkedList_create(); LinkedList values = LinkedList_create();
/* add rptEna = false as first element */ /* add rptEna = false as first element */
if (ClientReportControlBlock_getRptEna(rcb) == false) { if (ClientReportControlBlock_getRptEna(rcb) == false)
if (parametersMask & RCB_ELEMENT_RPT_ENA) { {
if (parametersMask & RCB_ELEMENT_RPT_ENA)
{
StringUtils_appendString(itemId, 130, "$RptEna"); StringUtils_appendString(itemId, 130, "$RptEna");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1144,7 +1242,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
} }
/* add resv/resvTms as first element and rptEna as last element when enabling a report */ /* add resv/resvTms as first element and rptEna as last element when enabling a report */
if (parametersMask & RCB_ELEMENT_RESV) { if (parametersMask & RCB_ELEMENT_RESV)
{
if (isBuffered) if (isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -1156,7 +1255,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_RESV_TMS) { if (parametersMask & RCB_ELEMENT_RESV_TMS)
{
if (!isBuffered) if (!isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -1168,7 +1268,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_RPT_ID) { if (parametersMask & RCB_ELEMENT_RPT_ID)
{
StringUtils_appendString(itemId, 130, "$RptID"); StringUtils_appendString(itemId, 130, "$RptID");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1177,7 +1278,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_DATSET) { if (parametersMask & RCB_ELEMENT_DATSET)
{
StringUtils_appendString(itemId, 130, "$DatSet"); StringUtils_appendString(itemId, 130, "$DatSet");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1186,7 +1288,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_ENTRY_ID) { if (parametersMask & RCB_ELEMENT_ENTRY_ID)
{
StringUtils_appendString(itemId, 130, "$EntryID"); StringUtils_appendString(itemId, 130, "$EntryID");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1195,7 +1298,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_OPT_FLDS) { if (parametersMask & RCB_ELEMENT_OPT_FLDS)
{
StringUtils_appendString(itemId, 130, "$OptFlds"); StringUtils_appendString(itemId, 130, "$OptFlds");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1204,7 +1308,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_BUF_TM) { if (parametersMask & RCB_ELEMENT_BUF_TM)
{
StringUtils_appendString(itemId, 130, "$BufTm"); StringUtils_appendString(itemId, 130, "$BufTm");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1213,7 +1318,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_TRG_OPS) { if (parametersMask & RCB_ELEMENT_TRG_OPS)
{
StringUtils_appendString(itemId, 130, "$TrgOps"); StringUtils_appendString(itemId, 130, "$TrgOps");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1222,7 +1328,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_INTG_PD) { if (parametersMask & RCB_ELEMENT_INTG_PD)
{
StringUtils_appendString(itemId, 130, "$IntgPd"); StringUtils_appendString(itemId, 130, "$IntgPd");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1231,14 +1338,16 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_GI) { if (parametersMask & RCB_ELEMENT_GI)
{
if (parametersMask & RCB_ELEMENT_RPT_ENA) { if (parametersMask & RCB_ELEMENT_RPT_ENA)
{
if (MmsValue_getBoolean(rcb->rptEna)) if (MmsValue_getBoolean(rcb->rptEna))
sendGILast = true; sendGILast = true;
} }
if (sendGILast == false) { if (sendGILast == false)
{
StringUtils_appendString(itemId, 130, "$GI"); StringUtils_appendString(itemId, 130, "$GI");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1248,7 +1357,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
} }
} }
if (parametersMask & RCB_ELEMENT_PURGE_BUF) { if (parametersMask & RCB_ELEMENT_PURGE_BUF)
{
if (!isBuffered) if (!isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -1260,7 +1370,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY) { if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY)
{
if (!isBuffered) if (!isBuffered)
goto error_invalid_parameter; goto error_invalid_parameter;
@ -1272,8 +1383,10 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (ClientReportControlBlock_getRptEna(rcb) == true) { if (ClientReportControlBlock_getRptEna(rcb) == true)
if (parametersMask & RCB_ELEMENT_RPT_ENA) { {
if (parametersMask & RCB_ELEMENT_RPT_ENA)
{
StringUtils_appendString(itemId, 130, "$RptEna"); StringUtils_appendString(itemId, 130, "$RptEna");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1283,7 +1396,8 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
} }
} }
if (sendGILast) { if (sendGILast)
{
StringUtils_appendString(itemId, 130, "$GI"); StringUtils_appendString(itemId, 130, "$GI");
LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(itemIds, StringUtils_copyString(itemId));
@ -1292,19 +1406,23 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
itemId[itemIdLen] = 0; itemId[itemIdLen] = 0;
} }
if (singleRequest) { if (singleRequest)
{
LinkedList accessResults = NULL; LinkedList accessResults = NULL;
MmsConnection_writeMultipleVariables(self->connection, &mmsError, domainId, itemIds, values, &accessResults); MmsConnection_writeMultipleVariables(self->connection, &mmsError, domainId, itemIds, values, &accessResults);
if (accessResults != NULL) { if (accessResults)
{
LinkedList accessResult = LinkedList_getNext(accessResults); LinkedList accessResult = LinkedList_getNext(accessResults);
while (accessResult != NULL) { while (accessResult)
MmsValue* dataAccessError = (MmsValue*) accessResult->data; {
MmsValue* dataAccessError = (MmsValue*)accessResult->data;
if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS) { if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS)
{
*error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(dataAccessError)); *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(dataAccessError));
break; break;
} }
@ -1312,20 +1430,22 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo
accessResult = LinkedList_getNext(accessResult); accessResult = LinkedList_getNext(accessResult);
} }
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete); LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction)MmsValue_delete);
} }
else else
*error = iedConnection_mapMmsErrorToIedError(mmsError); *error = iedConnection_mapMmsErrorToIedError(mmsError);
goto exit_function; goto exit_function;
} }
else { else
{
LinkedList itemIdElement = LinkedList_getNext(itemIds); LinkedList itemIdElement = LinkedList_getNext(itemIds);
LinkedList valueElement = LinkedList_getNext(values); LinkedList valueElement = LinkedList_getNext(values);
while (itemIdElement != NULL) { while (itemIdElement)
char* rcbItemId = (char*) itemIdElement->data; {
MmsValue* value = (MmsValue*) valueElement->data; char* rcbItemId = (char*)itemIdElement->data;
MmsValue* value = (MmsValue*)valueElement->data;
MmsConnection_writeVariable(self->connection, &mmsError, domainId, rcbItemId, value); MmsConnection_writeVariable(self->connection, &mmsError, domainId, rcbItemId, value);

@ -1,7 +1,7 @@
/* /*
* client_sv_control.c * client_sv_control.c
* *
* Copyright 2015-2022 Michael Zillgith * Copyright 2015-2025 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -29,7 +29,8 @@
#include "libiec61850_platform_includes.h" #include "libiec61850_platform_includes.h"
struct sClientSVControlBlock { struct sClientSVControlBlock
{
IedConnection connection; IedConnection connection;
bool isMulticast; bool isMulticast;
char* reference; char* reference;
@ -45,26 +46,30 @@ ClientSVControlBlock_create(IedConnection connection, const char* reference)
IedClientError error; IedClientError error;
MmsValue* value = IedConnection_readObject(connection, &error, reference, IEC61850_FC_MS); MmsValue* value = IedConnection_readObject(connection, &error, reference, IEC61850_FC_MS);
if ((error == IED_ERROR_OK) && (MmsValue_getType(value) != MMS_DATA_ACCESS_ERROR)) { if ((error == IED_ERROR_OK) && (MmsValue_getType(value) != MMS_DATA_ACCESS_ERROR))
{
isMulticast = true; isMulticast = true;
MmsValue_delete(value); MmsValue_delete(value);
} }
else { else
{
MmsValue_delete(value); MmsValue_delete(value);
value = IedConnection_readObject(connection, &error, reference, IEC61850_FC_US); value = IedConnection_readObject(connection, &error, reference, IEC61850_FC_US);
if ((error == IED_ERROR_OK) && (MmsValue_getType(value) != MMS_DATA_ACCESS_ERROR)) if ((error == IED_ERROR_OK) && (MmsValue_getType(value) != MMS_DATA_ACCESS_ERROR))
MmsValue_delete(value); MmsValue_delete(value);
else { else
{
MmsValue_delete(value); MmsValue_delete(value);
return NULL; return NULL;
} }
} }
ClientSVControlBlock self = (ClientSVControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientSVControlBlock)); ClientSVControlBlock self = (ClientSVControlBlock)GLOBAL_CALLOC(1, sizeof(struct sClientSVControlBlock));
if (self) { if (self)
{
self->connection = connection; self->connection = connection;
self->reference = StringUtils_copyString(reference); self->reference = StringUtils_copyString(reference);
self->isMulticast = isMulticast; self->isMulticast = isMulticast;
@ -76,7 +81,8 @@ ClientSVControlBlock_create(IedConnection connection, const char* reference)
void void
ClientSVControlBlock_destroy(ClientSVControlBlock self) ClientSVControlBlock_destroy(ClientSVControlBlock self)
{ {
if (self) { if (self)
{
GLOBAL_FREEMEM(self->reference); GLOBAL_FREEMEM(self->reference);
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
} }
@ -110,7 +116,6 @@ setBooleanVariable(ClientSVControlBlock self, const char* varName, bool value)
else else
IedConnection_writeBooleanValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_US, value); IedConnection_writeBooleanValue(self->connection, &(self->lastError), refBuf, IEC61850_FC_US, value);
if (self->lastError == IED_ERROR_OK) if (self->lastError == IED_ERROR_OK)
return true; return true;
else else
@ -288,27 +293,36 @@ ClientSVControlBlock_getDstAddress(ClientSVControlBlock self)
PhyComAddress retVal; PhyComAddress retVal;
memset(&retVal, 0, sizeof(retVal)); memset(&retVal, 0, sizeof(retVal));
if (dstAddrValue == NULL) goto exit_error; if (dstAddrValue == NULL)
goto exit_error;
if (MmsValue_getType(dstAddrValue) != MMS_STRUCTURE) { if (MmsValue_getType(dstAddrValue) != MMS_STRUCTURE)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong type\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - addr has wrong type\n");
goto exit_cleanup; goto exit_cleanup;
} }
if (MmsValue_getArraySize(dstAddrValue) != 4) { if (MmsValue_getArraySize(dstAddrValue) != 4)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong type\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - addr has wrong type\n");
goto exit_cleanup; goto exit_cleanup;
} }
MmsValue* addr = MmsValue_getElement(dstAddrValue, 0); MmsValue* addr = MmsValue_getElement(dstAddrValue, 0);
if (MmsValue_getType(addr) != MMS_OCTET_STRING) { if (MmsValue_getType(addr) != MMS_OCTET_STRING)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong type\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - addr has wrong type\n");
goto exit_cleanup; goto exit_cleanup;
} }
if (MmsValue_getOctetStringSize(addr) != 6) { if (MmsValue_getOctetStringSize(addr) != 6)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - addr has wrong size\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - addr has wrong size\n");
goto exit_cleanup; goto exit_cleanup;
} }
@ -318,8 +332,10 @@ ClientSVControlBlock_getDstAddress(ClientSVControlBlock self)
MmsValue* prio = MmsValue_getElement(dstAddrValue, 1); MmsValue* prio = MmsValue_getElement(dstAddrValue, 1);
if (MmsValue_getType(prio) != MMS_UNSIGNED) { if (MmsValue_getType(prio) != MMS_UNSIGNED)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - prio has wrong type\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - prio has wrong type\n");
goto exit_cleanup; goto exit_cleanup;
} }
@ -327,8 +343,10 @@ ClientSVControlBlock_getDstAddress(ClientSVControlBlock self)
MmsValue* vid = MmsValue_getElement(dstAddrValue, 2); MmsValue* vid = MmsValue_getElement(dstAddrValue, 2);
if (MmsValue_getType(vid) != MMS_UNSIGNED) { if (MmsValue_getType(vid) != MMS_UNSIGNED)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - vid has wrong type\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - vid has wrong type\n");
goto exit_cleanup; goto exit_cleanup;
} }
@ -336,18 +354,18 @@ ClientSVControlBlock_getDstAddress(ClientSVControlBlock self)
MmsValue* appID = MmsValue_getElement(dstAddrValue, 3); MmsValue* appID = MmsValue_getElement(dstAddrValue, 3);
if (MmsValue_getType(appID) != MMS_UNSIGNED) { if (MmsValue_getType(appID) != MMS_UNSIGNED)
if (DEBUG_IED_CLIENT) printf("IED_CLIENT: SVCB - appID has wrong type\n"); {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: SVCB - appID has wrong type\n");
goto exit_cleanup; goto exit_cleanup;
} }
retVal.appId = MmsValue_toUint32(appID); retVal.appId = MmsValue_toUint32(appID);
exit_cleanup: exit_cleanup:
MmsValue_delete(dstAddrValue); MmsValue_delete(dstAddrValue);
exit_error: exit_error:
return retVal; return retVal;
} }

Loading…
Cancel
Save