- IEC 61850 client: added async client side RCB handling

pull/93/head
Michael Zillgith 7 years ago
parent 2b7dc5c5fe
commit 7ec38e9615

@ -219,7 +219,7 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: Detected edition %i control\n", self->edition); printf("IED_CLIENT: Detected edition %i control\n", self->edition);
private_IedConnection_addControlClient(connection, self); iedConnection_addControlClient(connection, self);
free_varspec: free_varspec:
MmsVariableSpecification_destroy(ctlVarSpec); MmsVariableSpecification_destroy(ctlVarSpec);
@ -235,7 +235,7 @@ ControlObjectClient_destroy(ControlObjectClient self)
{ {
GLOBAL_FREEMEM(self->objectReference); GLOBAL_FREEMEM(self->objectReference);
private_IedConnection_removeControlClient(self->connection, self); iedConnection_removeControlClient(self->connection, self);
if (self->ctlVal != NULL) if (self->ctlVal != NULL)
MmsValue_delete(self->ctlVal); MmsValue_delete(self->ctlVal);
@ -752,7 +752,7 @@ ControlObjectClient_getLastApplError(ControlObjectClient self)
} }
void void
private_ControlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self) controlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self)
{ {
if (self->commandTerminationHandler != NULL) if (self->commandTerminationHandler != NULL)
self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self); self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self);

@ -343,7 +343,7 @@ IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const c
} }
void void
private_IedConnection_handleReport(IedConnection self, MmsValue* value) iedConnection_handleReport(IedConnection self, MmsValue* value)
{ {
MmsValue* rptIdValue = MmsValue_getElement(value, 0); MmsValue* rptIdValue = MmsValue_getElement(value, 0);

@ -3,7 +3,7 @@
* *
* Implementation of the ClientReportControlBlock class * Implementation of the ClientReportControlBlock class
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2018 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -388,11 +388,81 @@ updateOrClone(MmsValue** valuePtr, MmsValue* values, int index)
*valuePtr = MmsValue_clone(MmsValue_getElement(values, index)); *valuePtr = MmsValue_clone(MmsValue_getElement(values, index));
} }
static bool
checkElementType(MmsValue* value, int index, MmsType type)
{
MmsValue* element = MmsValue_getElement(value, index);
if (element == NULL)
return false;
if (MmsValue_getType(element) == type)
return true;
else
return false;
}
bool bool
private_ClientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* values) clientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* values)
{ {
/* check type and return false if type is wrong */
if (MmsValue_getType(values) != MMS_STRUCTURE)
return false;
int rcbElementCount = MmsValue_getArraySize(values); int rcbElementCount = MmsValue_getArraySize(values);
if (self->isBuffered) {
if ((rcbElementCount < 13) || (rcbElementCount > 15)) {
return false;
}
if (!checkElementType(values, 0, MMS_VISIBLE_STRING)) return false;
if (!checkElementType(values, 1, MMS_BOOLEAN)) return false;
if (!checkElementType(values, 2, MMS_VISIBLE_STRING)) return false;
if (!checkElementType(values, 3, MMS_UNSIGNED)) return false;
if (!checkElementType(values, 4, MMS_BIT_STRING)) return false;
if (!checkElementType(values, 5, MMS_UNSIGNED)) return false;
if (!checkElementType(values, 6, MMS_UNSIGNED)) return false;
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)) return false;
}
else if (rcbElementCount == 15) {
if (!checkElementType(values, 13, MMS_INTEGER)) return false;
if (!checkElementType(values, 14, MMS_OCTET_STRING)) return false;
}
}
else {
if ((rcbElementCount < 11) || (rcbElementCount > 12)) {
return false;
}
if (!checkElementType(values, 0, MMS_VISIBLE_STRING)) return false;
if (!checkElementType(values, 1, MMS_BOOLEAN)) return false;
if (!checkElementType(values, 2, MMS_BOOLEAN)) return false;
if (!checkElementType(values, 3, MMS_VISIBLE_STRING)) return false;
if (!checkElementType(values, 4, MMS_UNSIGNED)) 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 (!checkElementType(values, 11, MMS_OCTET_STRING)) return false;
}
}
/* when type is correct, update local copy */
updateOrClone(&(self->rptId), values, 0); updateOrClone(&(self->rptId), values, 0);
updateOrClone(&(self->rptEna), values, 1); updateOrClone(&(self->rptEna), values, 1);
@ -441,14 +511,120 @@ private_ClientReportControlBlock_updateValues(ClientReportControlBlock self, Mms
return true; return true;
} }
typedef void static void
(*IedConnection_GetRCBValuesHandler) (int invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb); readObjectHandlerInternal(int invokeId, void* parameter, MmsError err, MmsValue* value)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_GetRCBValuesHandler handler = (IedConnection_GetRCBValuesHandler) call->callback;
ClientReportControlBlock updateRcb = (ClientReportControlBlock) call->specificParameter;
char* rcbReference = (char*) call->specificParameter2;
if (err != MMS_ERROR_NONE) {
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), NULL);
}
else {
if (value == NULL) {
handler(invokeId, call->callbackParameter, IED_ERROR_OBJECT_DOES_NOT_EXIST, NULL);
}
else {
if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) {
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getRCBValues returned data-access-error!\n");
handler(invokeId, call->callbackParameter, iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)), NULL);
}
else {
ClientReportControlBlock returnRcb = updateRcb;
if (returnRcb == NULL)
returnRcb = ClientReportControlBlock_create(rcbReference);
if (clientReportControlBlock_updateValues(returnRcb, value)) {
handler(invokeId, call->callbackParameter, IED_ERROR_OK, returnRcb);
}
else {
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n");
handler(invokeId, call->callbackParameter, IED_ERROR_TYPE_INCONSISTENT , NULL);
if (updateRcb == NULL)
ClientReportControlBlock_destroy(returnRcb);
}
}
MmsValue_delete(value);
}
}
GLOBAL_FREEMEM(rcbReference);
iedConnection_releaseOutstandingCall(self, call);
}
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t uint32_t
IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const char* rcbReference, IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const char* rcbReference, ClientReportControlBlock updateRcb,
IedConnection_GetRCBValuesHandler handler, void* parameter) IedConnection_GetRCBValuesHandler handler, void* parameter)
{ {
//TODO implement *error = IED_ERROR_OK;
char domainId[65];
char itemId[65];
char* domainName = MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId);
if (domainName == NULL) {
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
return 0;
}
strcpy(itemId, rcbReference + strlen(domainId) + 1);
StringUtils_replace(itemId, '.', '$');
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL) {
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
return 0;
}
call->callback = handler;
call->callbackParameter = parameter;
call->specificParameter = updateRcb;
call->specificParameter2 = StringUtils_copyString(rcbReference);
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: readRCBValues for %s\n", rcbReference);
MmsError err = MMS_ERROR_NONE;
call->invokeId = MmsConnection_readVariableAsync(self->connection, &err, domainId, itemId, readObjectHandlerInternal, self);
*error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
GLOBAL_FREEMEM(call->specificParameter2);
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId;
} }
ClientReportControlBlock ClientReportControlBlock
@ -510,7 +686,7 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char
if (returnRcb == NULL) if (returnRcb == NULL)
returnRcb = ClientReportControlBlock_create(rcbReference); returnRcb = ClientReportControlBlock_create(rcbReference);
private_ClientReportControlBlock_updateValues(returnRcb, rcb); clientReportControlBlock_updateValues(returnRcb, rcb);
MmsValue_delete(rcb); MmsValue_delete(rcb);
@ -519,11 +695,346 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char
return returnRcb; return returnRcb;
} }
static void
writeMultipleVariablesHandler(int invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsValue*> */ accessResults)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_WriteObjectHandler handler = (IedConnection_WriteObjectHandler) call->callback;
if (accessResults != NULL) {
IedClientError error = IED_ERROR_OK;
LinkedList accessResult = LinkedList_getNext(accessResults);
while (accessResult != NULL) {
MmsValue* dataAccessError = (MmsValue*) accessResult->data;
if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS) {
error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(dataAccessError));
break;
}
accessResult = LinkedList_getNext(accessResult);
}
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete);
handler(invokeId, call->callbackParameter, error);
}
else {
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(mmsError));
}
iedConnection_releaseOutstandingCall(self, call);
}
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
struct sWriteRcbVariablesParameter
{
LinkedList itemIds;
LinkedList values;
LinkedList currentItemId;
LinkedList currentValue;
char* domainId;
uint32_t originalInvokeId;
};
static void
releaseWriteCall(IedConnection self, IedConnectionOutstandingCall call, struct sWriteRcbVariablesParameter* param)
{
GLOBAL_FREEMEM(param->domainId);
LinkedList_destroy(param->itemIds);
LinkedList_destroyStatic(param->values);
GLOBAL_FREEMEM(param);
iedConnection_releaseOutstandingCall(self, call);
}
static void
writeVariableHandler(int invokeId, void* parameter, MmsError mmsError, MmsDataAccessError accessError)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_WriteObjectHandler handler = (IedConnection_WriteObjectHandler) call->callback;
struct sWriteRcbVariablesParameter* param = (struct sWriteRcbVariablesParameter*) call->specificParameter2;
if ((mmsError != MMS_ERROR_NONE) || (accessError != DATA_ACCESS_ERROR_SUCCESS)) {
IedClientError err;
if (mmsError != MMS_ERROR_NONE)
err = iedConnection_mapMmsErrorToIedError(mmsError);
else
err = iedConnection_mapDataAccessErrorToIedError(accessError);
handler(param->originalInvokeId, call->callbackParameter, err);
releaseWriteCall(self, call, param);
}
param->currentItemId = LinkedList_getNext(param->currentItemId);
if (param->currentItemId == NULL) {
handler(param->originalInvokeId, call->callbackParameter, IED_ERROR_OK);
releaseWriteCall(self, call, param);
}
else {
param->currentValue = LinkedList_getNext(param->currentValue);
char* itemId = (char*) LinkedList_getData(param->currentItemId);
MmsValue* value = (MmsValue*) LinkedList_getData(param->currentValue);
MmsError writeError;
call->invokeId = MmsConnection_writeVariableAsync(self->connection, &writeError, param->domainId, itemId, value, writeVariableHandler, self);
if (writeError != MMS_ERROR_NONE) {
handler(param->originalInvokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(writeError));
releaseWriteCall(self, call, param);
}
}
}
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t uint32_t
IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, ClientReportControlBlock rcb, IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, ClientReportControlBlock rcb,
uint32_t parametersMask, bool singleRequest, IedConnection_WriteObjectHandler handler, void* parameter) uint32_t parametersMask, bool singleRequest, IedConnection_WriteObjectHandler handler, void* parameter)
{ {
//TODO implement uint32_t invokeId = 0;
bool isBuffered = ClientReportControlBlock_isBuffered(rcb);
bool sendGILast = false; /* GI should be sent last when RptEna=TRUE is included */
char domainId[65];
char itemId[129];
char* rcbReference = ClientReportControlBlock_getObjectReference(rcb);
MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId);
strcpy(itemId, rcbReference + strlen(domainId) + 1);
StringUtils_replace(itemId, '.', '$');
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: setRCBValues for %s\n", rcbReference);
int itemIdLen = strlen(itemId);
/* prepare data to send -> create the list of requested itemIds references */
LinkedList itemIds = LinkedList_create();
LinkedList values = LinkedList_create();
/* add resv/resvTms as first element and rptEna as last element */
if (parametersMask & RCB_ELEMENT_RESV) {
if (isBuffered)
goto error_invalid_parameter;
strcpy(itemId + itemIdLen, "$Resv");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->resv);
}
if (parametersMask & RCB_ELEMENT_RESV_TMS) {
if (!isBuffered)
goto error_invalid_parameter;
strcpy(itemId + itemIdLen, "$ResvTms");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->resvTms);
}
if (parametersMask & RCB_ELEMENT_RPT_ID) {
strcpy(itemId + itemIdLen, "$RptID");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->rptId);
}
if (parametersMask & RCB_ELEMENT_DATSET) {
strcpy(itemId + itemIdLen, "$DatSet");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->datSet);
}
if (parametersMask & RCB_ELEMENT_ENTRY_ID) {
strcpy(itemId + itemIdLen, "$EntryID");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->entryId);
}
if (parametersMask & RCB_ELEMENT_OPT_FLDS) {
strcpy(itemId + itemIdLen, "$OptFlds");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->optFlds);
}
if (parametersMask & RCB_ELEMENT_BUF_TM) {
strcpy(itemId + itemIdLen, "$BufTm");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->bufTm);
}
if (parametersMask & RCB_ELEMENT_TRG_OPS) {
strcpy(itemId + itemIdLen, "$TrgOps");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->trgOps);
}
if (parametersMask & RCB_ELEMENT_INTG_PD) {
strcpy(itemId + itemIdLen, "$IntgPd");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->intgPd);
}
if (parametersMask & RCB_ELEMENT_GI) {
if (parametersMask & RCB_ELEMENT_RPT_ENA) {
if (MmsValue_getBoolean(rcb->rptEna))
sendGILast = true;
}
if (sendGILast == false) {
strcpy(itemId + itemIdLen, "$GI");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->gi);
}
}
if (parametersMask & RCB_ELEMENT_PURGE_BUF) {
if (!isBuffered)
goto error_invalid_parameter;
strcpy(itemId + itemIdLen, "$PurgeBuf");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->purgeBuf);
}
if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY) {
if (!isBuffered)
goto error_invalid_parameter;
strcpy(itemId + itemIdLen, "$TimeofEntry");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->timeOfEntry);
}
if (parametersMask & RCB_ELEMENT_RPT_ENA) {
strcpy(itemId + itemIdLen, "$RptEna");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->rptEna);
}
if (sendGILast) {
strcpy(itemId + itemIdLen, "$GI");
LinkedList_add(itemIds, StringUtils_copyString(itemId));
LinkedList_add(values, rcb->gi);
}
IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self);
if (call == NULL) {
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
goto exit_function;
}
call->callback = handler;
call->callbackParameter = parameter;
call->specificParameter = rcb;
MmsError err;
if (singleRequest) {
invokeId = MmsConnection_writeMultipleVariablesAsync(self->connection, &err, domainId, itemIds, values, writeMultipleVariablesHandler, self);
*error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
iedConnection_releaseOutstandingCall(self, call);
}
goto exit_function;
}
else {
struct sWriteRcbVariablesParameter* param = (struct sWriteRcbVariablesParameter*) GLOBAL_MALLOC(sizeof(struct sWriteRcbVariablesParameter));
call->specificParameter2 = param;
param->itemIds = itemIds;
param->values = values;
param->currentItemId = LinkedList_getNext(itemIds);
param->currentValue = LinkedList_getNext(values);
param->domainId = StringUtils_copyString(domainId);
char* itemId = (char*) LinkedList_getData(param->currentItemId);
MmsValue* value = (MmsValue*) LinkedList_getData(param->currentValue);
call->invokeId = MmsConnection_writeVariableAsync(self->connection, &err, domainId, itemId, value, writeVariableHandler, self);
param->originalInvokeId = call->invokeId;
invokeId = call->invokeId;
*error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
iedConnection_releaseOutstandingCall(self, call);
GLOBAL_FREEMEM(param->domainId);
GLOBAL_FREEMEM(param);
goto exit_function;
}
else
return invokeId;
}
error_invalid_parameter:
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
exit_function:
LinkedList_destroy(itemIds);
LinkedList_destroyStatic(values);
return invokeId;
} }
void void

@ -153,6 +153,61 @@ iedConnection_mapDataAccessErrorToIedError(MmsDataAccessError mmsError)
} }
} }
IedConnectionOutstandingCall
iedConnection_allocateOutstandingCall(IedConnection self)
{
Semaphore_wait(self->outstandingCallsLock);
IedConnectionOutstandingCall call = NULL;
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].used == false) {
self->outstandingCalls[i].used = true;
call = &(self->outstandingCalls[i]);
break;
}
}
Semaphore_post(self->outstandingCallsLock);
return call;
}
void
iedConnection_releaseOutstandingCall(IedConnection self, IedConnectionOutstandingCall call)
{
Semaphore_wait(self->outstandingCallsLock);
call->used = false;
Semaphore_post(self->outstandingCallsLock);
}
IedConnectionOutstandingCall
iedConnection_lookupOutstandingCall(IedConnection self, uint32_t invokeId)
{
Semaphore_wait(self->outstandingCallsLock);
IedConnectionOutstandingCall call = NULL;
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
printf("%d: used: %d invokeId: %d\n", i, self->outstandingCalls[i].used, self->outstandingCalls[i].invokeId);
if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) {
call = &(self->outstandingCalls[i]);
break;
}
}
Semaphore_post(self->outstandingCallsLock);
return call;
}
static ICLogicalDevice* static ICLogicalDevice*
ICLogicalDevice_create(char* name) ICLogicalDevice_create(char* name)
@ -234,7 +289,7 @@ ClientDataSet_getDataSetSize(ClientDataSet self)
} }
bool bool
private_IedConnection_doesControlObjectMatch(const char* objRef, const char* cntrlObj) iedConnection_doesControlObjectMatch(const char* objRef, const char* cntrlObj)
{ {
int i = 0; int i = 0;
@ -418,7 +473,7 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError)
const char* objectRef = ControlObjectClient_getObjectReference(object); const char* objectRef = ControlObjectClient_getObjectReference(object);
if (private_IedConnection_doesControlObjectMatch(objectRef, MmsValue_toString(cntrlObj))) { if (iedConnection_doesControlObjectMatch(objectRef, MmsValue_toString(cntrlObj))) {
ControlObjectClient_setLastApplError(object, self->lastApplError); ControlObjectClient_setLastApplError(object, self->lastApplError);
} }
@ -438,7 +493,7 @@ informationReportHandler(void* parameter, char* domainName,
if (domainName == NULL) { if (domainName == NULL) {
if (isVariableListName) { if (isVariableListName) {
private_IedConnection_handleReport(self, value); iedConnection_handleReport(self, value);
} }
else { else {
if (strcmp(variableListName, "LastApplError") == 0) if (strcmp(variableListName, "LastApplError") == 0)
@ -461,7 +516,7 @@ informationReportHandler(void* parameter, char* domainName,
char* objectRef = ControlObjectClient_getObjectReference(object); char* objectRef = ControlObjectClient_getObjectReference(object);
if (doesReportMatchControlObject(domainName, variableListName, objectRef)) if (doesReportMatchControlObject(domainName, variableListName, objectRef))
private_ControlObjectClient_invokeCommandTerminationHandler(object); controlObjectClient_invokeCommandTerminationHandler(object);
control = LinkedList_getNext(control); control = LinkedList_getNext(control);
} }
@ -718,62 +773,6 @@ IedConnection_destroy(IedConnection self)
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
} }
static IedConnectionOutstandingCall
allocateOutstandingCall(IedConnection self)
{
Semaphore_wait(self->outstandingCallsLock);
IedConnectionOutstandingCall call = NULL;
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].used == false) {
self->outstandingCalls[i].used = true;
call = &(self->outstandingCalls[i]);
break;
}
}
Semaphore_post(self->outstandingCallsLock);
return call;
}
static void
releaseOutstandingCall(IedConnection self, IedConnectionOutstandingCall call)
{
Semaphore_wait(self->outstandingCallsLock);
call->used = false;
Semaphore_post(self->outstandingCallsLock);
}
static IedConnectionOutstandingCall
lookupOutstandingCall(IedConnection self, uint32_t invokeId)
{
Semaphore_wait(self->outstandingCallsLock);
IedConnectionOutstandingCall call = NULL;
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
printf("%d: used: %d invokeId: %d\n", i, self->outstandingCalls[i].used, self->outstandingCalls[i].invokeId);
if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) {
call = &(self->outstandingCalls[i]);
break;
}
}
Semaphore_post(self->outstandingCallsLock);
return call;
}
MmsVariableSpecification* MmsVariableSpecification*
IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference, IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference,
FunctionalConstraint fc) FunctionalConstraint fc)
@ -813,7 +812,7 @@ getAccessAttrHandler(int invokeId, void* parameter, MmsError err, MmsVariableSpe
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call) {
@ -821,7 +820,7 @@ getAccessAttrHandler(int invokeId, void* parameter, MmsError err, MmsVariableSpe
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), typeSpec); handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), typeSpec);
releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -841,7 +840,7 @@ IedConnection_getVariableSpecificationAsync(IedConnection self, IedClientError*
char* domainId; char* domainId;
char* itemId; char* itemId;
MmsError mmsError; MmsError err;
MmsVariableSpecification* varSpec = NULL; MmsVariableSpecification* varSpec = NULL;
domainId = MmsMapping_getMmsDomainFromObjectReference(dataAttributeReference, domainIdBuffer); domainId = MmsMapping_getMmsDomainFromObjectReference(dataAttributeReference, domainIdBuffer);
@ -852,7 +851,7 @@ IedConnection_getVariableSpecificationAsync(IedConnection self, IedClientError*
goto cleanup_and_exit; goto cleanup_and_exit;
} }
IedConnectionOutstandingCall call = 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;
@ -862,11 +861,14 @@ IedConnection_getVariableSpecificationAsync(IedConnection self, IedClientError*
call->callback = handler; call->callback = handler;
call->callbackParameter = parameter; call->callbackParameter = parameter;
call->invokeId = MmsConnection_getVariableAccessAttributesAsync(self->connection, &mmsError, domainId, itemId, getAccessAttrHandler, self); call->invokeId = MmsConnection_getVariableAccessAttributesAsync(self->connection, &err, domainId, itemId, getAccessAttrHandler, self);
invokeId = call->invokeId; invokeId = call->invokeId;
*error = iedConnection_mapMmsErrorToIedError(mmsError); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE)
iedConnection_releaseOutstandingCall(self, call);
cleanup_and_exit: cleanup_and_exit:
@ -892,7 +894,7 @@ readObjectHandlerInternal(int invokeId, void* parameter, MmsError err, MmsValue*
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call) {
@ -900,7 +902,7 @@ readObjectHandlerInternal(int invokeId, void* parameter, MmsError err, MmsValue*
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), value); handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), value);
releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -928,7 +930,7 @@ IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const c
return 0; return 0;
} }
IedConnectionOutstandingCall call = 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;
@ -975,7 +977,7 @@ IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const c
if (err != MMS_ERROR_NONE) if (err != MMS_ERROR_NONE)
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
return 0; return 0;
} }
@ -1295,7 +1297,7 @@ writeVariableHandler(int invokeId, void* parameter, MmsError err, MmsDataAccessE
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call) {
@ -1308,7 +1310,7 @@ writeVariableHandler(int invokeId, void* parameter, MmsError err, MmsDataAccessE
handler(invokeId, call->callbackParameter, iedError); handler(invokeId, call->callbackParameter, iedError);
releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -1320,6 +1322,8 @@ uint32_t
IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const char* objectReference, IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const char* objectReference,
FunctionalConstraint fc, MmsValue* value, IedConnection_WriteObjectHandler handler, void* parameter) FunctionalConstraint fc, MmsValue* value, IedConnection_WriteObjectHandler handler, void* parameter)
{ {
*error = IED_ERROR_OK;
char domainIdBuffer[65]; char domainIdBuffer[65];
char itemIdBuffer[65]; char itemIdBuffer[65];
@ -1334,7 +1338,7 @@ IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const
return 0; return 0;
} }
IedConnectionOutstandingCall call = 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;
@ -1380,6 +1384,11 @@ IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId; return call->invokeId;
} }
@ -1650,7 +1659,7 @@ fileDirectoryHandler(int invokeId, void* parameter, MmsError err, char* filename
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call) {
@ -1659,7 +1668,7 @@ fileDirectoryHandler(int invokeId, void* parameter, MmsError err, char* filename
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), filename, size, lastModfified, moreFollows); handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), filename, size, lastModfified, moreFollows);
if (filename == NULL) if (filename == NULL)
releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -1674,7 +1683,7 @@ IedConnection_getFileDirectoryAsync(IedConnection self, IedClientError* error, c
MmsError err = MMS_ERROR_NONE; MmsError err = MMS_ERROR_NONE;
IedConnectionOutstandingCall call = 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;
@ -1684,12 +1693,16 @@ IedConnection_getFileDirectoryAsync(IedConnection self, IedClientError* error, c
call->callback = handler; call->callback = handler;
call->callbackParameter = parameter; call->callbackParameter = parameter;
call->invokeId = MmsConnection_getFileDirectoryAsync(self->connection, &err, directoryName, continueAfter, call->invokeId = MmsConnection_getFileDirectoryAsync(self->connection, &err, directoryName, continueAfter,
fileDirectoryHandler, self); fileDirectoryHandler, self);
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId; return call->invokeId;
} }
@ -2964,7 +2977,7 @@ readJournalHandler(int invokeId, void* parameter, MmsError err, LinkedList /* <M
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId); IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) { if (call) {
@ -2972,7 +2985,7 @@ readJournalHandler(int invokeId, void* parameter, MmsError err, LinkedList /* <M
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), journalEntries, moreFollows); handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), journalEntries, moreFollows);
releaseOutstandingCall(self, call); iedConnection_releaseOutstandingCall(self, call);
} }
else { else {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
@ -2996,7 +3009,7 @@ IedConnection_queryLogByTimeAsync(IedConnection self, IedClientError* error, con
logName[0] = 0; logName[0] = 0;
logName++; logName++;
IedConnectionOutstandingCall call = 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;
@ -3022,6 +3035,11 @@ IedConnection_queryLogByTimeAsync(IedConnection self, IedClientError* error, con
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId; return call->invokeId;
} }
else { else {
@ -3047,7 +3065,7 @@ IedConnection_queryLogAfterAsync(IedConnection self, IedClientError* error, cons
logName[0] = 0; logName[0] = 0;
logName++; logName++;
IedConnectionOutstandingCall call = 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;
@ -3069,6 +3087,11 @@ IedConnection_queryLogAfterAsync(IedConnection self, IedClientError* error, cons
*error = iedConnection_mapMmsErrorToIedError(err); *error = iedConnection_mapMmsErrorToIedError(err);
if (err != MMS_ERROR_NONE) {
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId; return call->invokeId;
} }
else { else {
@ -3131,13 +3154,13 @@ IedConnection_getLastApplError(IedConnection self)
} }
void void
private_IedConnection_addControlClient(IedConnection self, ControlObjectClient control) iedConnection_addControlClient(IedConnection self, ControlObjectClient control)
{ {
LinkedList_add(self->clientControls, control); LinkedList_add(self->clientControls, control);
} }
void void
private_IedConnection_removeControlClient(IedConnection self, ControlObjectClient control) iedConnection_removeControlClient(IedConnection self, ControlObjectClient control)
{ {
LinkedList_remove(self->clientControls, control); LinkedList_remove(self->clientControls, control);
} }

@ -964,7 +964,7 @@ typedef void
(*IedConnection_GetRCBValuesHandler) (int invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb); (*IedConnection_GetRCBValuesHandler) (int invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb);
LIB61850_API uint32_t LIB61850_API uint32_t
IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const char* rcbReference, IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const char* rcbReference, ClientReportControlBlock updateRcb,
IedConnection_GetRCBValuesHandler handler, void* parameter); IedConnection_GetRCBValuesHandler handler, void* parameter);
/** Describes the reason for the inclusion of the element in the report */ /** Describes the reason for the inclusion of the element in the report */

@ -37,6 +37,8 @@ struct sIedConnectionOutstandingCall {
uint32_t invokeId; uint32_t invokeId;
void* callback; void* callback;
void* callbackParameter; void* callbackParameter;
void* specificParameter; /* function/service specific parameter */
void* specificParameter2; /* function/service specific parameter */
}; };
struct sIedConnection struct sIedConnection
@ -81,23 +83,20 @@ struct sClientReportControlBlock {
MmsValue* owner; MmsValue* owner;
}; };
LIB61850_INTERNAL IedClientError
private_IedConnection_mapMmsErrorToIedError(MmsError mmsError);
LIB61850_INTERNAL bool LIB61850_INTERNAL bool
private_IedConnection_doesControlObjectMatch(const char* objRef, const char* cntrlObj); iedConnection_doesControlObjectMatch(const char* objRef, const char* cntrlObj);
LIB61850_INTERNAL void LIB61850_INTERNAL void
private_IedConnection_addControlClient(IedConnection self, ControlObjectClient control); iedConnection_addControlClient(IedConnection self, ControlObjectClient control);
LIB61850_INTERNAL void LIB61850_INTERNAL void
private_IedConnection_removeControlClient(IedConnection self, ControlObjectClient control); iedConnection_removeControlClient(IedConnection self, ControlObjectClient control);
LIB61850_INTERNAL bool LIB61850_INTERNAL bool
private_ClientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* values); clientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* values);
LIB61850_INTERNAL void LIB61850_INTERNAL void
private_IedConnection_handleReport(IedConnection self, MmsValue* value); iedConnection_handleReport(IedConnection self, MmsValue* value);
LIB61850_INTERNAL IedClientError LIB61850_INTERNAL IedClientError
iedConnection_mapMmsErrorToIedError(MmsError mmsError); iedConnection_mapMmsErrorToIedError(MmsError mmsError);
@ -105,6 +104,15 @@ iedConnection_mapMmsErrorToIedError(MmsError mmsError);
LIB61850_INTERNAL IedClientError LIB61850_INTERNAL IedClientError
iedConnection_mapDataAccessErrorToIedError(MmsDataAccessError mmsError); iedConnection_mapDataAccessErrorToIedError(MmsDataAccessError mmsError);
LIB61850_INTERNAL IedConnectionOutstandingCall
iedConnection_allocateOutstandingCall(IedConnection self);
LIB61850_INTERNAL void
iedConnection_releaseOutstandingCall(IedConnection self, IedConnectionOutstandingCall call);
LIB61850_INTERNAL IedConnectionOutstandingCall
iedConnection_lookupOutstandingCall(IedConnection self, uint32_t invokeId);
LIB61850_INTERNAL ClientReport LIB61850_INTERNAL ClientReport
ClientReport_create(void); ClientReport_create(void);
@ -112,7 +120,7 @@ LIB61850_INTERNAL void
ClientReport_destroy(ClientReport self); ClientReport_destroy(ClientReport self);
LIB61850_INTERNAL void LIB61850_INTERNAL void
private_ControlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self); controlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self);
/* some declarations that are shared with server side ! */ /* some declarations that are shared with server side ! */

Loading…
Cancel
Save