diff --git a/examples/server_example_complex_array/mhai_array.cid b/examples/server_example_complex_array/mhai_array.cid index be81a20d..0b588518 100644 --- a/examples/server_example_complex_array/mhai_array.cid +++ b/examples/server_example_complex_array/mhai_array.cid @@ -102,6 +102,20 @@ + + + + + + + + + + + + + + 16 diff --git a/examples/server_example_complex_array/static_model.c b/examples/server_example_complex_array/static_model.c index d9bc2a48..3f5a6f14 100644 --- a/examples/server_example_complex_array/static_model.c +++ b/examples/server_example_complex_array/static_model.c @@ -1,14 +1,79 @@ /* * static_model.c * - * automatically generated from mhai_array.icd + * automatically generated from mhai_array.cid */ #include "static_model.h" static void initializeValues(); +extern DataSet iedModelds_ComplexArray_MHAI1_TestMHAI; +extern DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda0; +extern DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda1; +extern DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda2; +extern DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda3; +extern DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda4; + +DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda0 = { + "ComplexArray", + false, + "MHAI1$MX$HA$phsAHar", + 7, + NULL, + NULL, + &iedModelds_ComplexArray_MHAI1_TestMHAI_fcda1 +}; + +DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda1 = { + "ComplexArray", + false, + "MHAI1$MX$HA$phsAHar", + 8, + NULL, + NULL, + &iedModelds_ComplexArray_MHAI1_TestMHAI_fcda2 +}; + +DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda2 = { + "ComplexArray", + false, + "MHAI1$MX$HA$phsAHar", + 9, + "cVal", + NULL, + &iedModelds_ComplexArray_MHAI1_TestMHAI_fcda3 +}; + +DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda3 = { + "ComplexArray", + false, + "MHAI1$MX$HA$phsAHar", + 10, + "cVal$mag", + NULL, + &iedModelds_ComplexArray_MHAI1_TestMHAI_fcda4 +}; + +DataSetEntry iedModelds_ComplexArray_MHAI1_TestMHAI_fcda4 = { + "ComplexArray", + false, + "MHAI1$MX$HA$phsAHar", + 11, + "cVal$mag$f", + NULL, + NULL +}; + +DataSet iedModelds_ComplexArray_MHAI1_TestMHAI = { + "ComplexArray", + "MHAI1$TestMHAI", + 5, + &iedModelds_ComplexArray_MHAI1_TestMHAI_fcda0, + NULL +}; + LogicalDevice iedModel_ComplexArray = { LogicalDeviceModelType, "ComplexArray", @@ -1977,7 +2042,9 @@ DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency = { NULL, 0}; +extern ReportControlBlock iedModel_ComplexArray_MHAI1_report0; +ReportControlBlock iedModel_ComplexArray_MHAI1_report0 = {&iedModel_ComplexArray_MHAI1, "MHAIRCB01", "TestMHAI", false, "TestMHAI", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL}; @@ -1988,8 +2055,8 @@ DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency = { IedModel iedModel = { "test", &iedModel_ComplexArray, - NULL, - NULL, + &iedModelds_ComplexArray_MHAI1_TestMHAI, + &iedModel_ComplexArray_MHAI1_report0, NULL, NULL, NULL, diff --git a/examples/server_example_complex_array/static_model.h b/examples/server_example_complex_array/static_model.h index 18f5206e..d6bb6179 100644 --- a/examples/server_example_complex_array/static_model.h +++ b/examples/server_example_complex_array/static_model.h @@ -1,7 +1,7 @@ /* * static_model.h * - * automatically generated from mhai_array.icd + * automatically generated from mhai_array.cid */ #ifndef STATIC_MODEL_H_ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 1422f79a..adfe596c 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -377,18 +377,64 @@ updateDataSetsWithCachedValues(IedServer self) MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); - MmsValue* value = MmsServer_getValueFromCache(self->mmsServer, domain, dataSetEntry->variableName); + char variableName[66]; + + strncpy(variableName, dataSetEntry->variableName, 65); + variableName[65] = 0; + + MmsVariableSpecification* typeSpec = NULL; + + MmsValue* value = MmsServer_getValueFromCacheEx(self->mmsServer, domain, variableName, &typeSpec); if (value == NULL) { if (DEBUG_IED_SERVER) { - printf("LD: %s dataset: %s : error cannot get value from cache for %s -> %s!\n", + printf("IED_SERVER: LD: %s dataset: %s : error cannot get value from cache for %s -> %s!\n", dataSet->logicalDeviceName, dataSet->name, dataSetEntry->logicalDeviceName, dataSetEntry->variableName); } } - else - dataSetEntry->value = value; + else { + /* check if array element */ + + if (dataSetEntry->index != -1) { + if (typeSpec->type == MMS_ARRAY) { + MmsValue* elementValue = MmsValue_getElement(value, dataSetEntry->index); + + if (elementValue) { + + if (dataSetEntry->componentName) { + MmsVariableSpecification* elementType = typeSpec->typeSpec.array.elementTypeSpec; + + MmsValue* subElementValue = MmsVariableSpecification_getChildValue(elementType, elementValue, dataSetEntry->componentName); + + if (subElementValue) { + dataSetEntry->value = subElementValue; + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - component %s of array element not found\n", dataSetEntry->componentName); + } + + } + else { + dataSetEntry->value = elementValue; + } + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - array element %i not found\n", dataSetEntry->index); + } + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - variable %s/%s is not an array\n", dataSetEntry->logicalDeviceName, dataSetEntry->variableName); + } + } + else { + dataSetEntry->value = value; + } + } dataSetEntry = dataSetEntry->sibling; } diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 798c1d47..63f58d4a 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3732,7 +3732,6 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi /* use variable name part of domain name as logicalDeviceName */ dataSetEntry->logicalDeviceName = MmsDomain_getName(listEntry->domain) + strlen(self->model->name); - dataSetEntry->variableName = listEntry->variableName; dataSetEntry->index = listEntry->arrayIndex; dataSetEntry->componentName = listEntry->componentName; @@ -3743,8 +3742,49 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi else lastDataSetEntry->sibling = dataSetEntry; - dataSetEntry->value = - MmsServer_getValueFromCache(self->mmsServer, listEntry->domain, listEntry->variableName); + MmsVariableSpecification* dataSetEntryVarSpec = NULL; + + MmsValue* dataSetEntryValue = MmsServer_getValueFromCacheEx(self->mmsServer, listEntry->domain, listEntry->variableName, &dataSetEntryVarSpec); + + if (dataSetEntryValue) { + if (dataSetEntry->index != -1) { + if (dataSetEntryVarSpec->type == MMS_ARRAY) { + MmsValue* elementValue = MmsValue_getElement(dataSetEntryValue, dataSetEntry->index); + + if (elementValue) { + + if (dataSetEntry->componentName) { + MmsVariableSpecification* elementType = dataSetEntryVarSpec->typeSpec.array.elementTypeSpec; + + MmsValue* subElementValue = MmsVariableSpecification_getChildValue(elementType, elementValue, dataSetEntry->componentName); + + if (subElementValue) { + dataSetEntry->value = subElementValue; + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - component %s of array element not found\n", dataSetEntry->componentName); + } + + } + else { + dataSetEntry->value = elementValue; + } + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - array element %i not found\n", dataSetEntry->index); + } + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - variable %s/%s is not an array\n", dataSetEntry->logicalDeviceName, dataSetEntry->variableName); + } + } + else { + dataSetEntry->value = dataSetEntryValue; + } + } lastDataSetEntry = dataSetEntry; diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h index 6bc4455c..a1b14e5f 100644 --- a/src/mms/inc_private/mms_client_internal.h +++ b/src/mms/inc_private/mms_client_internal.h @@ -177,6 +177,9 @@ mmsClient_createAlternateAccess(uint32_t index, uint32_t elementCount); LIB61850_INTERNAL void mmsClient_deleteAlternateAccess(AlternateAccess_t* alternateAccess); +LIB61850_INTERNAL AlternateAccess_t* +mmsClient_createAlternateAccessComponent(const char* componentName); + LIB61850_INTERNAL void mmsClient_deleteAlternateAccessIndexComponent(AlternateAccess_t* alternateAccess); diff --git a/src/mms/inc_private/mms_server_libinternal.h b/src/mms/inc_private/mms_server_libinternal.h index c18a7ac3..2e18f4a2 100644 --- a/src/mms/inc_private/mms_server_libinternal.h +++ b/src/mms/inc_private/mms_server_libinternal.h @@ -79,6 +79,9 @@ MmsServer_getDevice(MmsServer self); LIB61850_INTERNAL MmsValue* MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, const char* itemId); +LIB61850_INTERNAL MmsValue* +MmsServer_getValueFromCacheEx(MmsServer self, MmsDomain* domain, const char* itemId, MmsVariableSpecification** typeSpec); + LIB61850_INTERNAL bool MmsServer_isLocked(MmsServer self); diff --git a/src/mms/inc_private/mms_value_cache.h b/src/mms/inc_private/mms_value_cache.h index 8c89be4e..bdacbb27 100644 --- a/src/mms/inc_private/mms_value_cache.h +++ b/src/mms/inc_private/mms_value_cache.h @@ -36,7 +36,7 @@ LIB61850_INTERNAL void MmsValueCache_insertValue(MmsValueCache self, char* itemId, MmsValue* value); LIB61850_INTERNAL MmsValue* -MmsValueCache_lookupValue(MmsValueCache self, const char* itemId); +MmsValueCache_lookupValue(MmsValueCache self, const char* itemId, MmsVariableSpecification** outSpec); LIB61850_INTERNAL void MmsValueCache_destroy(MmsValueCache self); diff --git a/src/mms/iso_mms/client/mms_client_common.c b/src/mms/iso_mms/client/mms_client_common.c index 1b5e1972..11a92994 100644 --- a/src/mms/iso_mms/client/mms_client_common.c +++ b/src/mms/iso_mms/client/mms_client_common.c @@ -137,8 +137,8 @@ mmsClient_deleteAlternateAccess(AlternateAccess_t* alternateAccess) GLOBAL_FREEMEM(alternateAccess); } -static AlternateAccess_t* -createAlternateAccessComponent(const char* componentName) +AlternateAccess_t* +mmsClient_createAlternateAccessComponent(const char* componentName) { AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); alternateAccess->list.count = 1; @@ -161,7 +161,7 @@ createAlternateAccessComponent(const char* componentName) (uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator); alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size; - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = mmsClient_createAlternateAccessComponent(separator + 1); } else { int size = strlen(componentName); @@ -201,7 +201,7 @@ mmsClient_createAlternateAccessIndexComponent(uint32_t index, const char* compon asn_long2INTEGER(asnIndex, index); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(componentName); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = mmsClient_createAlternateAccessComponent(componentName); } else { alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; @@ -217,3 +217,4 @@ mmsClient_createAlternateAccessIndexComponent(uint32_t index, const char* compon return alternateAccess; } + diff --git a/src/mms/iso_mms/client/mms_client_named_variable_list.c b/src/mms/iso_mms/client/mms_client_named_variable_list.c index 630eb9dd..3ca329e1 100644 --- a/src/mms/iso_mms/client/mms_client_named_variable_list.c +++ b/src/mms/iso_mms/client/mms_client_named_variable_list.c @@ -354,49 +354,12 @@ mmsClient_createDefineNamedVariableListRequest( domainspecific.itemId.buf = (uint8_t*) StringUtils_copyString(variableSpec->itemId); if (variableSpec->arrayIndex != -1) { - - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); - alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); - - alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = - AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index; - - asn_long2INTEGER(&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.index), - variableSpec->arrayIndex); - - if (variableSpec->componentName != NULL) { - - AlternateAccess_t* componentAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); - - componentAccess->list.count = 1; - componentAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); - componentAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); - - componentAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - componentAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - - componentAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - componentAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_component; - - Identifier_t* componentIdentifier = - &(componentAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component); - - componentIdentifier->size = strlen(variableSpec->componentName); - componentIdentifier->buf = (uint8_t*) StringUtils_copyString(variableSpec->componentName); - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess - = componentAccess; + if (variableSpec->componentName) { + request->listOfVariable.list.array[i]->alternateAccess = mmsClient_createAlternateAccessIndexComponent(variableSpec->arrayIndex, variableSpec->componentName); + } + else { + request->listOfVariable.list.array[i]->alternateAccess = mmsClient_createAlternateAccess(variableSpec->arrayIndex, 0); } - - request->listOfVariable.list.array[i]->alternateAccess = alternateAccess; } element = LinkedList_getNext(element); @@ -404,9 +367,16 @@ mmsClient_createDefineNamedVariableListRequest( i++; } - der_encode(&asn_DEF_MmsPdu, mmsPdu, + asn_enc_rval_t rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + if (rval.encoded == -1) { + writeBuffer->size = 0; + + if (DEBUG_MMS_SERVER) + printf("MMS_CLIENT: createDefineNamedVariableListRequest - failed to encode request!\n"); + } + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); } diff --git a/src/mms/iso_mms/server/mms_named_variable_list.c b/src/mms/iso_mms/server/mms_named_variable_list.c index 69770a97..31694780 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list.c +++ b/src/mms/iso_mms/server/mms_named_variable_list.c @@ -46,6 +46,8 @@ void MmsNamedVariableListEntry_destroy(MmsNamedVariableListEntry self) { GLOBAL_FREEMEM(self->variableName); + if (self->componentName) + GLOBAL_FREEMEM(self->componentName); GLOBAL_FREEMEM(self); } diff --git a/src/mms/iso_mms/server/mms_named_variable_list_service.c b/src/mms/iso_mms/server/mms_named_variable_list_service.c index 72d30f90..a8039236 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list_service.c +++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c @@ -1,7 +1,7 @@ /* * mms_named_variable_list_service.c * - * Copyright 2013-2015 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -23,6 +23,7 @@ #include "libiec61850_platform_includes.h" #include "mms_server_internal.h" +#include "mms_client_internal.h" #include "mms_named_variable_list.h" #include "ber_encoder.h" @@ -281,6 +282,8 @@ checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier) return false; if (accessSpecifier->componentName != NULL) { + variableSpec = variableSpec->typeSpec.array.elementTypeSpec; + if (MmsVariableSpecification_getNamedVariableRecursive(variableSpec, accessSpecifier->componentName) == NULL) return false; } @@ -289,6 +292,74 @@ checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier) return true; } +static char* +getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, char* componentNameBuf, int nameBufPos) +{ + if (alternateAccess->list.count == 1) { + + if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) { + + if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) { + + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component) + { + Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed-> + choice.selectAlternateAccess.accessSelection.choice.component; + + AlternateAccess_t* nextAlternateAccess = alternateAccess->list.array[0]->choice.unnamed-> + choice.selectAlternateAccess.alternateAccess; + + if (nextAlternateAccess) { + if (nameBufPos + componentIdentifier.size + 1 < 65) { + memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size); + nameBufPos += componentIdentifier.size; + componentNameBuf[nameBufPos++] = '$'; + return getComponentNameFromAlternateAccess(nextAlternateAccess, componentNameBuf, nameBufPos); + } + else { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: component identifier name too long!\n"); + } + } + else { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: next alternate access specification is missing!\n"); + } + } + } + else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) { + + /* final component part */ + + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == + AlternateAccessSelection__selectAccess_PR_component) + { + Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed-> + choice.selectAccess.choice.component; + + if (nameBufPos + componentIdentifier.size + 1 < 65) { + memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size); + nameBufPos += componentIdentifier.size; + componentNameBuf[nameBufPos++] = 0; + return componentNameBuf; + } + else { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: component identifier name too long!\n"); + } + } + } + + } + + } + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: invalid component access specification\n"); + + return NULL; +} static MmsNamedVariableList createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, @@ -299,6 +370,9 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, int variableCount = request->listOfVariable.list.count; + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: create-named-variable-list (%i variable(s) | max=%i)\n", variableCount, server->maxDataSetEntries); + #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) if ((variableCount == 0 ) || (variableCount > server->maxDataSetEntries)) { #else @@ -324,6 +398,10 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, if (request->listOfVariable.list.array[i]->alternateAccess != NULL) { if (request->listOfVariable.list.array[i]->alternateAccess->list.count != 1) { + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: create-named-variable list - only one alternate access specification allowed!\n"); + MmsNamedVariableList_destroy(namedVariableList); namedVariableList = NULL; break; @@ -334,21 +412,31 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, request->listOfVariable.list.array[i]->alternateAccess->list.array[0]; if ((alternateAccess->present == AlternateAccess__Member_PR_unnamed) - &&(alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) + && (alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) && (alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index)) { asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.index), &arrayIndex); - Identifier_t componentIdentifier = alternateAccess->choice.unnamed-> - choice.selectAlternateAccess.alternateAccess->list.array[0]-> - choice.unnamed->choice.selectAccess.choice.component; - - componentName = - StringUtils_createStringFromBufferInBuffer(componentNameBuf, - componentIdentifier.buf, componentIdentifier.size); + if (alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess) { + componentNameBuf[0] = 0; + componentName = getComponentNameFromAlternateAccess( + alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess, + componentNameBuf, 0); + } + else { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: create-named-variable-list - component specification is missing!\n"); + } + } + else if ((alternateAccess->present == AlternateAccess__Member_PR_unnamed) + && (alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) + && (alternateAccess->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_index) + ) + { + asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAccess.choice.index), &arrayIndex); } else { MmsNamedVariableList_destroy(namedVariableList); @@ -356,9 +444,7 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS; break; } - } - } if (varSpec->present == VariableSpecification_PR_name) { @@ -383,15 +469,21 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, accessSpecifier.arrayIndex = arrayIndex; accessSpecifier.componentName = componentName; + if (DEBUG_MMS_SERVER) + printf("MMS SERVER: add named variable list entry: %s/%s(%li)%s\n", MmsDomain_getName(elementDomain), variableName, arrayIndex, componentName); + /* check if element exists */ if (checkIfVariableExists(device, &accessSpecifier) == true) { - MmsNamedVariableListEntry variable = MmsNamedVariableListEntry_create(accessSpecifier); MmsNamedVariableList_addVariable(namedVariableList, variable); } else { + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: failed - variable does not exist!\n"); + MmsNamedVariableList_destroy(namedVariableList); namedVariableList = NULL; i = variableCount; /* exit loop after freeing loop variables */ @@ -655,6 +747,15 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, varListResponse->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. domainspecific.itemId.size = strlen(variableEntry->variableName); + if (variableEntry->arrayIndex != -1) { + varListResponse->listOfVariable.list.array[i]->alternateAccess = + mmsClient_createAlternateAccessIndexComponent(variableEntry->arrayIndex, variableEntry->componentName); + } + else if (variableEntry->componentName) { + varListResponse->listOfVariable.list.array[i]->alternateAccess = + mmsClient_createAlternateAccessComponent(variableEntry->componentName); + } + variable = LinkedList_getNext(variable); } diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 2f38a854..5c64abe8 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -269,9 +269,6 @@ alternateArrayAccess(MmsServerConnection connection, int lowIndex = mmsServer_getLowIndex(alternateAccess); int numberOfElements = mmsServer_getNumberOfElements(alternateAccess); - if (DEBUG_MMS_SERVER) printf("Alternate access index: %i elements %i\n", - lowIndex, numberOfElements); - int index = lowIndex; MmsValue* arrayValue = mmsServer_getValue(connection->server, domain, itemId, connection, false); @@ -707,6 +704,61 @@ exit: #if (MMS_DATA_SET_SERVICE == 1) +static void +addNamedVariableToNamedVariableListResultList(MmsVariableSpecification* namedVariable, MmsDomain* domain, char* nameIdStr, + LinkedList /**/ values, MmsServerConnection connection, MmsNamedVariableListEntry listEntry) +{ + if (namedVariable != NULL) { + + if (DEBUG_MMS_SERVER) + printf("MMS read: found named variable %s with search string %s\n", + namedVariable->name, nameIdStr); + + MmsValue* value = mmsServer_getValue(connection->server, domain, nameIdStr, connection, false); + + if (value) { + if (listEntry->arrayIndex != -1) { + if (MmsValue_getType(value) == MMS_ARRAY) { + + MmsValue* elementValue = MmsValue_getElement(value, listEntry->arrayIndex); + + if (listEntry->componentName) { + MmsVariableSpecification* elementType = namedVariable->typeSpec.array.elementTypeSpec; + + MmsValue* subElementValue = MmsVariableSpecification_getChildValue(elementType, elementValue, listEntry->componentName); + + if (subElementValue) { + appendValueToResultList(subElementValue, values); + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - component %s of array element not found\n", listEntry->componentName); + } + } + else { + appendValueToResultList(elementValue, values); + } + + } + else { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: data set entry of unexpected type!\n"); + + appendErrorToResultList(values, DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT); + } + } + else { + appendValueToResultList(value, values); + } + } + else { + appendErrorToResultList(values, DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT); + } + } + else + appendErrorToResultList(values, DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT); +} + static void createNamedVariableListResponse(MmsServerConnection connection, MmsNamedVariableList namedList, int invokeId, ByteBuffer* response, bool isSpecWithResult, VarAccessSpec* accessSpec) @@ -731,8 +783,8 @@ createNamedVariableListResponse(MmsServerConnection connection, MmsNamedVariable MmsVariableSpecification* namedVariable = MmsDomain_getNamedVariable(variableDomain, variableName); - addNamedVariableToResultList(namedVariable, variableDomain, variableName, - values, connection, NULL, false); + addNamedVariableToNamedVariableListResultList(namedVariable, variableDomain, variableName, + values, connection, variableListEntry); variable = LinkedList_getNext(variable); } diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 2803e82c..80af245b 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -444,7 +444,18 @@ MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, const char* itemI MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); if (cache != NULL) - return MmsValueCache_lookupValue(cache, itemId); + return MmsValueCache_lookupValue(cache, itemId, NULL); + + return NULL ; +} + +MmsValue* +MmsServer_getValueFromCacheEx(MmsServer self, MmsDomain* domain, const char* itemId, MmsVariableSpecification** typeSpec) +{ + MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); + + if (cache != NULL) + return MmsValueCache_lookupValue(cache, itemId, typeSpec); return NULL ; } diff --git a/src/mms/iso_mms/server/mms_value_cache.c b/src/mms/iso_mms/server/mms_value_cache.c index 0af1d164..fcabff0f 100644 --- a/src/mms/iso_mms/server/mms_value_cache.c +++ b/src/mms/iso_mms/server/mms_value_cache.c @@ -89,7 +89,7 @@ getChildSubString (const char* itemId, char* parentId) } static MmsValue* -searchCacheForValue(MmsValueCache self, const char* itemId, char* parentId) +searchCacheForValue(MmsValueCache self, const char* itemId, char* parentId, MmsVariableSpecification** outSpec) { MmsValueCacheEntry* cacheEntry; MmsValue* value = NULL; @@ -100,7 +100,7 @@ searchCacheForValue(MmsValueCache self, const char* itemId, char* parentId) char* parentItemId = getParentSubString(parentId); if (parentItemId != NULL) { - value = searchCacheForValue(self, itemId, parentItemId); + value = searchCacheForValue(self, itemId, parentItemId, outSpec); } } else { @@ -109,13 +109,18 @@ searchCacheForValue(MmsValueCache self, const char* itemId, char* parentId) MmsVariableSpecification* typeSpec = MmsDomain_getNamedVariable(self->domain, parentId); value = MmsVariableSpecification_getChildValue(typeSpec, cacheEntry->value, childId); + + if (outSpec) { + *outSpec = MmsVariableSpecification_getNamedVariableRecursive(typeSpec, childId); + } + } return value; } MmsValue* -MmsValueCache_lookupValue(MmsValueCache self, const char* itemId) +MmsValueCache_lookupValue(MmsValueCache self, const char* itemId, MmsVariableSpecification** outSpec) { /* * get value for first matching key substring! @@ -133,14 +138,20 @@ MmsValueCache_lookupValue(MmsValueCache self, const char* itemId) char* parentItemId = getParentSubString(itemIdCopy); if (parentItemId != NULL) { - value = searchCacheForValue(self, itemId, parentItemId); + value = searchCacheForValue(self, itemId, parentItemId, outSpec); } GLOBAL_FREEMEM(itemIdCopy); } - if (cacheEntry != NULL) + if (cacheEntry != NULL) { + + if (outSpec) { + *outSpec = cacheEntry->typeSpec; + } + return cacheEntry->value; + } else return value; } diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java index 4e1ae291..6198bb76 100644 --- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java @@ -1565,12 +1565,41 @@ public class StaticModelGenerator { if (fcda.getDaName() != null) mmsVariableName += "$" + toMmsString(fcda.getDaName()); - - // TODO implement index processing! + + int arrayStart = mmsVariableName.indexOf('('); + + String variableName = mmsVariableName; + int arrayIndex = -1; + String componentName = null; + + if (arrayStart != -1) { + variableName = mmsVariableName.substring(0, arrayStart); + + int arrayEnd = mmsVariableName.indexOf(')'); + + String arrayIndexStr = mmsVariableName.substring(arrayStart + 1, arrayEnd); + arrayIndex = Integer.parseInt(arrayIndexStr); + + String componentNamePart = mmsVariableName.substring(arrayEnd + 1); + + if ((componentNamePart != null) && (componentNamePart.length() > 0)) { + if (componentNamePart.charAt(0) == '$') { + componentNamePart = componentNamePart.substring(1); + } + + if ((componentNamePart != null) && (componentNamePart.length() > 0)) + componentName = componentNamePart; + } + } + cOut.println(" false,"); - cOut.println(" \"" + mmsVariableName + "\","); - cOut.println(" -1,"); - cOut.println(" NULL,"); + cOut.println(" \"" + variableName + "\", "); + cOut.println(" " + arrayIndex + ","); + if (componentName == null) + cOut.println(" NULL,"); + else + cOut.println(" \"" + componentName + "\","); + cOut.println(" NULL,"); if (fcdaCount + 1 < numberOfFcdas)