diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs index 51692901..19acd559 100644 --- a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs @@ -29,6 +29,13 @@ namespace IEC61850 namespace Common { + public enum Iec61850Edition : byte + { + EDITION_1 = 0, + EDITION_2 = 1, + EDITION_2_1 = 2 + } + public class LibIEC61850 { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] diff --git a/dotnet/IEC61850forCSharp/IedServerConfig.cs b/dotnet/IEC61850forCSharp/IedServerConfig.cs index 550c3a26..9f1d7bde 100644 --- a/dotnet/IEC61850forCSharp/IedServerConfig.cs +++ b/dotnet/IEC61850forCSharp/IedServerConfig.cs @@ -23,6 +23,7 @@ using System; using System.Runtime.InteropServices; +using IEC61850.Common; namespace IEC61850.Server { @@ -49,6 +50,12 @@ namespace IEC61850.Server [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr IedServerConfig_getFileServiceBasePath(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServerConfig_setEdition(IntPtr self, byte edition); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern byte IedServerConfig_getEdition(IntPtr self); + internal IntPtr self; public IedServerConfig () @@ -84,6 +91,16 @@ namespace IEC61850.Server } } + public Iec61850Edition Edition + { + get { + return (Iec61850Edition)IedServerConfig_getEdition (self); + } + set { + IedServerConfig_setEdition (self, (byte) value); + } + } + /// /// Releases all resource used by the object. /// diff --git a/examples/server_example_basic_io/server_example_basic_io.c b/examples/server_example_basic_io/server_example_basic_io.c index d5c9a6b8..55e789ec 100644 --- a/examples/server_example_basic_io/server_example_basic_io.c +++ b/examples/server_example_basic_io/server_example_basic_io.c @@ -90,6 +90,8 @@ main(int argc, char** argv) /* Set buffer size for buffered report control blocks to 200000 bytes */ IedServerConfig_setReportBufferSize(config, 200000); + IedServerConfig_setEdition(config, IEC_61850_EDITION_2); + /* Set the base path for the MMS file services */ IedServerConfig_setFileServiceBasePath(config, "./vmd-filestore/"); diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h index f0a67246..a41a7db4 100644 --- a/src/iec61850/inc/iec61850_common.h +++ b/src/iec61850/inc/iec61850_common.h @@ -37,6 +37,15 @@ extern "C" { */ /**@{*/ +/** IEC 61850 edition 1 */ +#define IEC_61850_EDITION_1 0 + +/** IEC 61850 edition 2 */ +#define IEC_61850_EDITION_2 1 + +/** IEC 61850 edition 2.1 */ +#define IEC_61850_EDITION_2_1 2 + /** PhyComAddress type contains Ethernet address and VLAN attributes */ typedef struct { uint8_t vlanPriority; diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 7e146468..8f6cabce 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -62,6 +62,9 @@ struct sIedServerConfig /** when true (default) enable log service */ bool enableLogService; + + /** IEC 61850 edition (0 = edition 1, 1 = edition 2, 2 = edition 2.1, ...) */ + uint8_t edition; }; /** @@ -78,6 +81,22 @@ IedServerConfig_create(void); void IedServerConfig_destroy(IedServerConfig self); +/** + * \brief Set the IEC 61850 standard edition to use (default is edition 2) + * + * \param edition IEC_61850_EDITION_1, IEC_61850_EDITION_2, or IEC_61850_EDITION_2_1 + */ +void +IedServerConfig_setEdition(IedServerConfig self, uint8_t edition); + +/** + * \brief Get the configued IEC 61850 standard edition + * + * \returns IEC_61850_EDITION_1, IEC_61850_EDITION_2, or IEC_61850_EDITION_2_1 + */ +uint8_t +IedServerConfig_getEdition(IedServerConfig self); + /** * \brief Set the report buffer size for buffered reporting * diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h index 825c032b..003c1613 100644 --- a/src/iec61850/inc_private/ied_server_private.h +++ b/src/iec61850/inc_private/ied_server_private.h @@ -55,6 +55,8 @@ struct sIedServer bool logServiceEnabled; #endif + uint8_t edition; + bool running; }; diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index b603efd4..540078b1 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -94,10 +94,12 @@ typedef struct { ReportBuffer* reportBuffer; MmsValue* timeOfEntry; + + IedServer server; } ReportControl; ReportControl* -ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize); +ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize, IedServer server); void ReportControl_destroy(ReportControl* self); diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index dc487c3a..d33a1e43 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -400,12 +400,20 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio self->running = false; self->localIpAddress = NULL; +#if (CONFIG_IEC61850_EDITION_1 == 1) + self->edition = IEC_61850_EDITION_1; +#else + self->edition = IEC_61850_EDITION_2; +#endif + #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) self->logServiceEnabled = true; if (serverConfiguration) { self->logServiceEnabled = serverConfiguration->enableLogService; + self->edition = serverConfiguration->edition; } + #endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ #if (CONFIG_MMS_THREADLESS_STACK != 1) @@ -430,12 +438,10 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio MmsServer_enableFileService(self->mmsServer, serverConfiguration->enableFileService); MmsServer_enableDynamicNamedVariableListService(self->mmsServer, serverConfiguration->enableDynamicDataSetService); MmsServer_enableJournalService(self->mmsServer, serverConfiguration->enableLogService); + MmsServer_setFilestoreBasepath(self->mmsServer, serverConfiguration->fileServiceBasepath); } #endif - if (serverConfiguration) - MmsServer_setFilestoreBasepath(self->mmsServer, serverConfiguration->fileServiceBasepath); - MmsMapping_setMmsServer(self->mmsMapping, self->mmsServer); MmsMapping_installHandlers(self->mmsMapping); diff --git a/src/iec61850/server/impl/ied_server_config.c b/src/iec61850/server/impl/ied_server_config.c index fe8c7ea5..6712c0b9 100644 --- a/src/iec61850/server/impl/ied_server_config.c +++ b/src/iec61850/server/impl/ied_server_config.c @@ -35,6 +35,7 @@ IedServerConfig_create() self->enableFileService = true; self->enableDynamicDataSetService = true; self->enableLogService = true; + self->edition = IEC_61850_EDITION_2; } return self; @@ -47,6 +48,18 @@ IedServerConfig_destroy(IedServerConfig self) GLOBAL_FREEMEM(self); } +void +IedServerConfig_setEdition(IedServerConfig self, uint8_t edition) +{ + self->edition = edition; +} + +uint8_t +IedServerConfig_getEdition(IedServerConfig self) +{ + return self->edition; +} + void IedServerConfig_setReportBufferSize(IedServerConfig self, int reportBufferSize) { diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index b32f6525..1e2e5ce1 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -47,11 +47,6 @@ #define CONFIG_IEC61850_BRCB_WITH_RESVTMS 0 #endif - -#ifndef CONFIG_IEC61850_EDITION_1 -#define CONFIG_IEC61850_EDITION_1 0 -#endif - static ReportBuffer* ReportBuffer_create(int bufferSize) { @@ -84,7 +79,7 @@ ReportBuffer_destroy(ReportBuffer* self) } ReportControl* -ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize) +ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize, IedServer iedServer) { ReportControl* self = (ReportControl*) GLOBAL_MALLOC(sizeof(ReportControl)); self->name = NULL; @@ -119,6 +114,8 @@ ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize) self->valueReferences = NULL; self->lastEntryId = 0; + self->server = iedServer; + if (buffered) { self->reportBuffer = ReportBuffer_create(reportBufferSize); } @@ -251,17 +248,21 @@ ReportControl_getRCBValue(ReportControl* rc, char* elementName) return MmsValue_getElement(rc->rcbValues, 11); else if (strcmp(elementName, "TimeofEntry") == 0) return MmsValue_getElement(rc->rcbValues, 12); -#if (CONFIG_IEC61850_EDITION_1 == 0) + + if (rc->server->edition >= IEC_61850_EDITION_2) { #if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) - else if (strcmp(elementName, "ResvTms") == 0) - return MmsValue_getElement(rc->rcbValues, 13); - else if (strcmp(elementName, "Owner") == 0) - return MmsValue_getElement(rc->rcbValues, 14); + if (strcmp(elementName, "ResvTms") == 0) + return MmsValue_getElement(rc->rcbValues, 13); + if (strcmp(elementName, "Owner") == 0) + return MmsValue_getElement(rc->rcbValues, 14); #else - else if (strcmp(elementName, "Owner") == 0) - return MmsValue_getElement(rc->rcbValues, 13); -#endif + if (strcmp(elementName, "Owner") == 0) + return MmsValue_getElement(rc->rcbValues, 13); #endif + } + + + } else { if (strcmp(elementName, "RptID") == 0) return MmsValue_getElement(rc->rcbValues, 0); @@ -819,11 +820,12 @@ createUnbufferedReportControlBlock(ReportControlBlock* reportControlBlock, mmsValue->deleteValue = false; mmsValue->type = MMS_STRUCTURE; -#if ((CONFIG_IEC61850_EDITION_1 == 0)) - int structSize = 12; -#else - int structSize = 11; -#endif + int structSize; + + if (reportControl->server->edition >= IEC_61850_EDITION_2) + structSize = 12; + else + structSize = 11; mmsValue->value.structure.size = structSize; mmsValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(structSize, sizeof(MmsValue*)); @@ -925,14 +927,14 @@ createUnbufferedReportControlBlock(ReportControlBlock* reportControlBlock, rcb->typeSpec.structure.elements[10] = namedVariable; mmsValue->value.structure.components[10] = MmsValue_newBoolean(false); -#if (CONFIG_IEC61850_EDITION_1 == 0) - namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); - namedVariable->name = StringUtils_copyString("Owner"); - namedVariable->type = MMS_OCTET_STRING; - namedVariable->typeSpec.octetString = -64; - rcb->typeSpec.structure.elements[11] = namedVariable; - mmsValue->value.structure.components[11] = MmsValue_newOctetString(0, 128); -#endif /* (CONFIG_IEC61850_EDITION_1 == 0) */ + if (reportControl->server->edition >= IEC_61850_EDITION_2) { + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = StringUtils_copyString("Owner"); + namedVariable->type = MMS_OCTET_STRING; + namedVariable->typeSpec.octetString = -64; + rcb->typeSpec.structure.elements[11] = namedVariable; + mmsValue->value.structure.components[11] = MmsValue_newOctetString(0, 128); + } reportControl->rcbValues = mmsValue; @@ -955,13 +957,14 @@ createBufferedReportControlBlock(ReportControlBlock* reportControlBlock, int brcbElementCount = 13; -#if (CONFIG_IEC61850_EDITION_1 == 0) + if (reportControl->server->edition >= IEC_61850_EDITION_2) { + #if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) - brcbElementCount++; + brcbElementCount++; #endif - brcbElementCount++; -#endif /* (CONFIG_IEC61850_EDITION_1 == 0) */ + brcbElementCount++; + } MmsValue* mmsValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); mmsValue->deleteValue = false; @@ -1083,28 +1086,26 @@ createBufferedReportControlBlock(ReportControlBlock* reportControlBlock, reportControl->timeOfEntry = mmsValue->value.structure.components[12]; -#if (CONFIG_IEC61850_EDITION_1 == 0) - int currentIndex = 13; -#endif + if (reportControl->server->edition >= IEC_61850_EDITION_2) { + int currentIndex = 13; -#if ((CONFIG_IEC61850_EDITION_1 == 0) && (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1)) - namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); - namedVariable->name = StringUtils_copyString("ResvTms"); - namedVariable->type = MMS_INTEGER; - namedVariable->typeSpec.integer = 16; - rcb->typeSpec.structure.elements[currentIndex] = namedVariable; - mmsValue->value.structure.components[currentIndex] = MmsValue_newInteger(16); - currentIndex++; +#if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = StringUtils_copyString("ResvTms"); + namedVariable->type = MMS_INTEGER; + namedVariable->typeSpec.integer = 16; + rcb->typeSpec.structure.elements[currentIndex] = namedVariable; + mmsValue->value.structure.components[currentIndex] = MmsValue_newInteger(16); + currentIndex++; #endif /* (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) */ -#if (CONFIG_IEC61850_EDITION_1 == 0) - namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); - namedVariable->name = StringUtils_copyString("Owner"); - namedVariable->type = MMS_OCTET_STRING; - namedVariable->typeSpec.octetString = -64; - rcb->typeSpec.structure.elements[currentIndex] = namedVariable; - mmsValue->value.structure.components[currentIndex] = MmsValue_newOctetString(0, 128); /* size 4 is enough to store client IPv4 address */ -#endif /* (CONFIG_IEC61850_EDITION_1 == 0) */ + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = StringUtils_copyString("Owner"); + namedVariable->type = MMS_OCTET_STRING; + namedVariable->typeSpec.octetString = -64; + rcb->typeSpec.structure.elements[currentIndex] = namedVariable; + mmsValue->value.structure.components[currentIndex] = MmsValue_newOctetString(0, 128); /* size 4 is enough to store client IPv4 address */ + } reportControl->rcbValues = mmsValue; @@ -1158,7 +1159,7 @@ Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain, int currentReport = 0; while (currentReport < reportsCount) { - ReportControl* rc = ReportControl_create(true, logicalNode, self->iedServer->reportBufferSize); + ReportControl* rc = ReportControl_create(true, logicalNode, self->iedServer->reportBufferSize, self->iedServer); rc->domain = domain; @@ -1195,7 +1196,7 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain, int currentReport = 0; while (currentReport < reportsCount) { - ReportControl* rc = ReportControl_create(false, logicalNode, self->iedServer->reportBufferSize); + ReportControl* rc = ReportControl_create(false, logicalNode, self->iedServer->reportBufferSize, self->iedServer); rc->domain = domain; @@ -1221,58 +1222,59 @@ updateOwner(ReportControl* rc, MmsServerConnection connection) { rc->clientConnection = connection; -#if (CONFIG_IEC61850_EDITION_1 == 0) - MmsValue* owner = ReportControl_getRCBValue(rc, "Owner"); + if (rc->server->edition >= IEC_61850_EDITION_2) { - if (owner != NULL) { + MmsValue* owner = ReportControl_getRCBValue(rc, "Owner"); - if (connection != NULL) { - char* clientAddressString = MmsServerConnection_getClientAddress(connection); + if (owner != NULL) { - if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: set owner to %s\n", clientAddressString); + if (connection != NULL) { + char* clientAddressString = MmsServerConnection_getClientAddress(connection); - if (strchr(clientAddressString, '.') != NULL) { - if (DEBUG_IED_SERVER) - printf("IED_SERVER: reporting.c: client address is IPv4 address\n"); + if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: set owner to %s\n", clientAddressString); - uint8_t ipV4Addr[4]; + if (strchr(clientAddressString, '.') != NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: reporting.c: client address is IPv4 address\n"); - int addrElementCount = 0; + uint8_t ipV4Addr[4]; - char* separator = clientAddressString; + int addrElementCount = 0; - while (separator != NULL && addrElementCount < 4) { - int intVal = atoi(separator); + char* separator = clientAddressString; - ipV4Addr[addrElementCount] = intVal; + while (separator != NULL && addrElementCount < 4) { + int intVal = atoi(separator); - separator = strchr(separator, '.'); + ipV4Addr[addrElementCount] = intVal; - if (separator != NULL) - separator++; // skip '.' character + separator = strchr(separator, '.'); - addrElementCount ++; - } + if (separator != NULL) + separator++; // skip '.' character - if (addrElementCount == 4) - MmsValue_setOctetString(owner, ipV4Addr, 4); - else - MmsValue_setOctetString(owner, ipV4Addr, 0); + addrElementCount ++; + } + + if (addrElementCount == 4) + MmsValue_setOctetString(owner, ipV4Addr, 4); + else + MmsValue_setOctetString(owner, ipV4Addr, 0); + } + else { + uint8_t ipV6Addr[16]; + MmsValue_setOctetString(owner, ipV6Addr, 0); + if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: client address is IPv6 address or unknown\n"); + } } else { - uint8_t ipV6Addr[16]; - MmsValue_setOctetString(owner, ipV6Addr, 0); - if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: client address is IPv6 address or unknown\n"); + uint8_t emptyAddr[1]; + MmsValue_setOctetString(owner, emptyAddr, 0); } } - else { - uint8_t emptyAddr[1]; - MmsValue_setOctetString(owner, emptyAddr, 0); - } - } -#endif /* (CONFIG_IEC61850_EDITION_1 == 0) */ + } } diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def index c769a4d8..30d98eb4 100644 --- a/src/vs/libiec61850-wo-goose.def +++ b/src/vs/libiec61850-wo-goose.def @@ -610,3 +610,5 @@ EXPORTS IedServerConfig_isDynamicDataSetServiceEnabled IedServerConfig_enableLogService IedServerConfig_isLogServiceEnabled + IedServerConfig_setEdition + IedServerConfig_getEdition diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def index 8e5edab4..039e5ea8 100644 --- a/src/vs/libiec61850.def +++ b/src/vs/libiec61850.def @@ -738,3 +738,5 @@ EXPORTS IedServerConfig_isDynamicDataSetServiceEnabled IedServerConfig_enableLogService IedServerConfig_isLogServiceEnabled + IedServerConfig_setEdition + IedServerConfig_getEdition