Added write access handler data reference parameter

pull/345/head
Kevin Jhang 4 years ago
parent 407ee9048f
commit 4a7982ae69

@ -2034,7 +2034,7 @@ namespace IEC61850
public delegate void RCBEventHandler(object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError); public delegate void RCBEventHandler(object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError);
public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, MmsValue value, public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, string dataRef, MmsValue value,
ClientConnection connection, object parameter); ClientConnection connection, object parameter);
/// <summary> /// <summary>
@ -2215,7 +2215,7 @@ namespace IEC61850
static extern void IedServer_setWriteAccessPolicy(IntPtr self, FunctionalConstraint fc, AccessPolicy policy); static extern void IedServer_setWriteAccessPolicy(IntPtr self, FunctionalConstraint fc, AccessPolicy policy);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int InternalWriteAccessHandler (IntPtr dataAttribute, IntPtr value, IntPtr connection, IntPtr parameter); private delegate int InternalWriteAccessHandler (IntPtr dataAttribute, IntPtr dataRef, IntPtr value, IntPtr connection, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_handleWriteAccess(IntPtr self, IntPtr dataAttribute, static extern void IedServer_handleWriteAccess(IntPtr self, IntPtr dataAttribute,
@ -2397,7 +2397,7 @@ namespace IEC61850
} }
} }
int WriteAccessHandlerImpl (IntPtr dataAttribute, IntPtr value, IntPtr connection, IntPtr parameter) int WriteAccessHandlerImpl (IntPtr dataAttribute, IntPtr dataRef, IntPtr value, IntPtr connection, IntPtr parameter)
{ {
WriteAccessHandlerInfo info; WriteAccessHandlerInfo info;
@ -2407,9 +2407,11 @@ namespace IEC61850
clientConnections.TryGetValue(connection, out con); clientConnections.TryGetValue(connection, out con);
string dataRefereence = Marshal.PtrToStringAnsi(dataRef);
MmsValue mmsValue = new MmsValue(value); MmsValue mmsValue = new MmsValue(value);
return (int)info.handler(info.dataAttribute, mmsValue.Clone(), con, info.parameter); return (int)info.handler(info.dataAttribute, dataRefereence, mmsValue.Clone(), con, info.parameter);
} }
else else
{ {

@ -107,7 +107,7 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v
} }
static MmsDataAccessError static MmsDataAccessError
writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter)
{ {
ControlModel ctlModelVal = (ControlModel) MmsValue_toInt32(value); ControlModel ctlModelVal = (ControlModel) MmsValue_toInt32(value);

@ -128,7 +128,7 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v
static MmsDataAccessError static MmsDataAccessError
writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter)
{ {
void* securityToken = ClientConnection_getSecurityToken(connection); void* securityToken = ClientConnection_getSecurityToken(connection);

@ -70,7 +70,7 @@ updateProcessValues()
} }
static MmsDataAccessError static MmsDataAccessError
writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter)
{ {
if (dataAttribute == IEDMODEL_LD1_GGIO1_AnIn1_subEna) { if (dataAttribute == IEDMODEL_LD1_GGIO1_AnIn1_subEna) {

@ -22,7 +22,7 @@ void sigint_handler(int signalId)
} }
static MmsDataAccessError static MmsDataAccessError
writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) writeAccessHandler (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter)
{ {
if (dataAttribute == IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f) { if (dataAttribute == IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f) {

@ -1713,6 +1713,7 @@ MmsGooseControlBlock_getNdsCom(MmsGooseControlBlock self);
* stack will not update the value automatically. * stack will not update the value automatically.
* *
* \param the data attribute that has been written by an MMS client. * \param the data attribute that has been written by an MMS client.
* \param the dataRef the data reference for alternate access
* \param the value the client want to write to the data attribute * \param the value the client want to write to the data attribute
* \param connection the connection object of the client connection that invoked the write operation * \param connection the connection object of the client connection that invoked the write operation
* \param parameter the user provided parameter * \param parameter the user provided parameter
@ -1720,7 +1721,7 @@ MmsGooseControlBlock_getNdsCom(MmsGooseControlBlock self);
* \return DATA_ACCESS_ERROR_SUCCESS, or DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied. * \return DATA_ACCESS_ERROR_SUCCESS, or DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied.
*/ */
typedef MmsDataAccessError typedef MmsDataAccessError
(*WriteAccessHandler) (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter); (*WriteAccessHandler) (DataAttribute* dataAttribute, char* dataRef, MmsValue* value, ClientConnection connection, void* parameter);
/** /**
* \brief Install a WriteAccessHandler for a data attribute. * \brief Install a WriteAccessHandler for a data attribute.

@ -2530,7 +2530,7 @@ getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc)
static MmsDataAccessError static MmsDataAccessError
mmsWriteHandler(void* parameter, MmsDomain* domain, mmsWriteHandler(void* parameter, MmsDomain* domain,
char* variableId, MmsValue* value, MmsServerConnection connection) char* variableId, char* dataRef, MmsValue* value, MmsServerConnection connection)
{ {
MmsMapping* self = (MmsMapping*) parameter; MmsMapping* self = (MmsMapping*) parameter;
@ -2838,11 +2838,6 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId); cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId);
if (cachedValue) { if (cachedValue) {
if (!MmsValue_equalTypes(cachedValue, value)) {
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
bool handlerFound = false; bool handlerFound = false;
AccessPolicy nodeAccessPolicy = getAccessPolicyForFC(self, fc); AccessPolicy nodeAccessPolicy = getAccessPolicyForFC(self, fc);
@ -2878,7 +2873,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
connection); connection);
MmsDataAccessError handlerResult = MmsDataAccessError handlerResult =
accessHandler->handler(dataAttribute, value, clientConnection, accessHandler->handler(dataAttribute, dataRef, value, clientConnection,
accessHandler->parameter); accessHandler->parameter);
if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) { if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) {

@ -403,6 +403,10 @@ LIB61850_INTERNAL MmsDataAccessError
mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value,
MmsServerConnection connection); MmsServerConnection connection);
LIB61850_INTERNAL MmsDataAccessError
mmsServer_setValueWithAlternateAccess(MmsServer self, MmsDomain* domain, char* itemId, AlternateAccess_t* alternateAccess,
MmsVariableSpecification* variable, MmsValue* value, MmsServerConnection connection);
/** /**
* \brief Get the current value of a variable in the server data model * \brief Get the current value of a variable in the server data model
* *

@ -34,7 +34,7 @@ typedef MmsDataAccessError (*MmsReadAccessHandler) (void* parameter, MmsDomain*
char* variableId, MmsServerConnection connection, bool isDirectAccess); char* variableId, MmsServerConnection connection, bool isDirectAccess);
typedef MmsDataAccessError (*MmsWriteVariableHandler)(void* parameter, typedef MmsDataAccessError (*MmsWriteVariableHandler)(void* parameter,
MmsDomain* domain, char* variableId, MmsValue* value, MmsDomain* domain, char* variableId, char* dataRef, MmsValue* value,
MmsServerConnection connection); MmsServerConnection connection);
typedef void (*MmsConnectionHandler)(void* parameter, typedef void (*MmsConnectionHandler)(void* parameter,

@ -481,15 +481,116 @@ MmsServer_insertIntoCache(MmsServer self, MmsDomain* domain, char* itemId, MmsVa
} }
} }
static bool
isAccessToArrayComponent(AlternateAccess_t* alternateAccess)
{
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess != NULL)
{
if (alternateAccess->list.array[0]->choice.unnamed->
choice.selectAlternateAccess.alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present ==
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component)
{
return true;
}
else
return false;
}
else
return false;
}
static MmsValue*
getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable,
MmsValue* structuredValue, char* dataRefBuf)
{
MmsValue* retValue = NULL ;
if (isAccessToArrayComponent(alternateAccess))
{
Identifier_t component = alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess
->list.array[0]->choice.unnamed->choice.selectAccess.choice.component;
if (component.size > 129)
goto exit_function;
MmsVariableSpecification* structSpec;
if (namedVariable->type == MMS_ARRAY)
structSpec = namedVariable->typeSpec.array.elementTypeSpec;
else if (namedVariable->type == MMS_STRUCTURE)
structSpec = namedVariable;
else
goto exit_function;
int i;
for (i = 0; i < structSpec->typeSpec.structure.elementCount; i++) {
if ((int)strlen(structSpec->typeSpec.structure.elements[i]->name)
== component.size) {
if (strncmp(structSpec->typeSpec.structure.elements[i]->name,
(char*)component.buf, component.size) == 0) {
snprintf(dataRefBuf, 129, "%s.%s", dataRefBuf, (char*)component.buf);
MmsValue* value = MmsValue_getElement(structuredValue, i);
if (isAccessToArrayComponent(
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) {
retValue =
getComponentOfArrayElement(
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess,
structSpec->typeSpec.structure.elements[i],
value, dataRefBuf);
}
else
retValue = value;
goto exit_function;
}
}
}
}
exit_function:
return retValue;
}
static char*
mmsServer_getDataRef(MmsDomain* domain, char* itemId) {
char dataRefBuf[130];
const char* separator = strchr(itemId, '$');
if (separator != NULL) {
snprintf(dataRefBuf, 129, "%s/", domain->domainName);
int bufOffset = strlen(domain->domainName) + 1;
strncpy(dataRefBuf + bufOffset, itemId, 129 - bufOffset);
bufOffset += separator - itemId;
strncpy(dataRefBuf + bufOffset, separator + 3, 129 - bufOffset);
}
dataRefBuf[129] = 0;
StringUtils_replace(dataRefBuf, '$', '.');
return dataRefBuf;
}
MmsDataAccessError MmsDataAccessError
mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value,
MmsServerConnection connection) MmsServerConnection connection)
{ {
MmsDataAccessError indication; MmsDataAccessError indication;
char* dataRefBuf = mmsServer_getDataRef(domain, itemId);
if (self->writeHandler != NULL) { if (self->writeHandler != NULL) {
indication = self->writeHandler(self->writeHandlerParameter, domain, indication = self->writeHandler(self->writeHandlerParameter, domain,
itemId, value, connection); itemId, dataRefBuf, value, connection);
} }
else { else {
MmsValue* cachedValue; MmsValue* cachedValue;
@ -509,6 +610,96 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va
return indication; return indication;
} }
MmsDataAccessError
mmsServer_setValueWithAlternateAccess(MmsServer self, MmsDomain* domain, char* itemId, AlternateAccess_t* alternateAccess, MmsVariableSpecification* variable,
MmsValue* value, MmsServerConnection connection)
{
MmsDataAccessError indication;
char* dataRefBuf = mmsServer_getDataRef(domain, itemId);
MmsValue* cachedArray;
if (domain == NULL)
domain = (MmsDomain*)self->device;
cachedArray = MmsServer_getValueFromCache(self, domain, itemId);
if (cachedArray != NULL) {
int index = mmsServer_getLowIndex(alternateAccess);
int numberOfElements = mmsServer_getNumberOfElements(alternateAccess);
snprintf(dataRefBuf, 129, "%s(%d)", dataRefBuf, index);
if (numberOfElements == 0) { /* select single array element with index */
MmsValue* elementValue;
if (isAccessToArrayComponent(alternateAccess)) {
if (variable->typeSpec.array.elementTypeSpec->type != MMS_STRUCTURE) {
indication = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
goto exit_function;
}
MmsValue* structValue = MmsValue_getElement(cachedArray, index);
if (structValue == NULL) {
indication = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
goto exit_function;
}
elementValue = getComponentOfArrayElement(alternateAccess, variable, structValue, dataRefBuf);
}
else {
elementValue = MmsValue_getElement(cachedArray, index);
}
if (self->writeHandler == NULL) {
if (MmsValue_update(elementValue, value) == false) {
indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto exit_function;
}
}
}
else { /* select sub-array with start-index and number-of-elements */
if (MmsValue_getType(value) != MMS_ARRAY) {
indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
}
else {
if (self->writeHandler == NULL) {
int elementNo;
for (elementNo = 0; elementNo < numberOfElements; elementNo++) {
MmsValue* newElement = MmsValue_getElement(value, elementNo);
MmsValue* elementValue = MmsValue_getElement(cachedArray, index++);
if ((elementValue == NULL) || (newElement == NULL))
indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
else if (MmsValue_update(elementValue, newElement) == false) {
indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto exit_function;
}
}
}
}
}
indication = DATA_ACCESS_ERROR_SUCCESS;
if (self->writeHandler != NULL) {
indication = self->writeHandler(self->writeHandlerParameter, domain,
itemId, dataRefBuf, value, connection);
}
}
else
indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
exit_function:
return indication;
}
MmsValue* MmsValue*
mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess) mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess)
{ {

@ -615,74 +615,22 @@ mmsServer_handleWriteRequest(
continue; continue;
} }
if (alternateAccess != NULL) { MmsDataAccessError valueIndication;
if (domain == NULL)
domain = (MmsDomain*) device;
MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); if (alternateAccess != NULL) {
valueIndication =
if (cachedArray == NULL) { mmsServer_setValueWithAlternateAccess(connection->server, domain, nameIdStr, alternateAccess, variable, value, connection);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; }
else {
/* Check for correct type */
if (MmsVariableSpecification_isValueOfType(variable, value) == false) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop; goto end_of_main_loop;
} }
int index = mmsServer_getLowIndex(alternateAccess); valueIndication =
int numberOfElements = mmsServer_getNumberOfElements(alternateAccess);
if (numberOfElements == 0) { /* select single array element with index */
MmsValue* elementValue = MmsValue_getElement(cachedArray, index);
if (elementValue == NULL) {
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
goto end_of_main_loop;
}
if (MmsValue_update(elementValue, value) == false) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop;
}
}
else { /* select sub-array with start-index and number-of-elements */
if (MmsValue_getType(value) != MMS_ARRAY) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop;
}
int elementNo;
for (elementNo = 0; elementNo < numberOfElements; elementNo++) {
MmsValue* newElement = MmsValue_getElement(value, elementNo);
MmsValue* elementValue = MmsValue_getElement(cachedArray, index++);
if ((elementValue == NULL) || (newElement == NULL) ) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop;
}
if (MmsValue_update(elementValue, newElement) == false) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop;
}
}
}
accessResults[i] = DATA_ACCESS_ERROR_SUCCESS;
goto end_of_main_loop;
}
/* Check for correct type */
if (MmsVariableSpecification_isValueOfType(variable, value) == false) {
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
goto end_of_main_loop;
}
MmsDataAccessError valueIndication =
mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); mmsServer_setValue(connection->server, domain, nameIdStr, value, connection);
}
if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE) if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE)
sendResponse = false; sendResponse = false;

Loading…
Cancel
Save