diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..d625cbc --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,381 @@ +Changes to version 0.8.7 +------------------------ +- client: added client side control service support for edition 1 and 2 APC CDCs +- client: ControlObjectClient uses GetVarSpec instead of GetNameList and ReadData to get required information from the server (compatible with more server implementations) +- client: Added function ControlObjectClient_useConstantT to support constant T parameter during a control sequence (required my some non-standard conformant servers) +- server: Fixed problem with SqNum in RCBs and reports +- windows file provider now supports unicode file name and converts them to UTF-8 +- some small API changes (some char* parameter became const char*; new function ClientReport_getDataSetName) +- client API: added function ClientReport_getDataSetName +- .NET API: new methods Report.GetDataSetName, ReportControlBlock.GetEntryID, ReportControlBlock.SetEntryID, Dispose methods for ReportControlBlock and IedConnection classes +- .NET API: fixed bug with garbage collected CommandTerminationHandler +- server: getNameList response with alphabetically sorted variable names (configurable by CONFIG_MMS_SORT_NAME_LIST option) +- server: only client that set EditSG can change EditSG and modify variables with FC=SE +- server: changed ControlObjectClient_create function: doesn't read "Oper" and uses GetVarSpec instead of GetNameList service +- extended beoglebone demo (write access to GAPC settings, ...) +- server: File service: support for wildcard character ('*') in requests; support for flat file list +- server: changed signature of WriteAccessHandler: Handler now returns MmsDataAccessError instead of boolean value! +- server: added function IedModel_setIedNameForDynamicModel +- and some more small changes and bug fixes + +Changes to version 0.8.6 +------------------------ +- demos: extended beaglebone demo to use SBO control +- common: fixed bug that led to wrong encoding of large unsigned integer values on big endian systems +- server: fixed server crash problem when read request contains only LN but no FC +- server: fixed server sending empty report when RCB is disabled while report is pending during bufTm +- server: fixed server allowed creation of dynamic data set with wrong LD name +- server: sending type-inconsistent instead of unknown-error when receiving a write request with invalid value type +- server: fixed server side SBO control handling code provides wrong ClientConnection object to PerformCheckHandler +- client: fixed client does not correctly handle GCBs for edition 1 devices. Also will fail for edition 2 devices when optional elements are missing. +- GOOSE subscriber: fixed - subscriber rejects messages with trailing data (like PRP trail) +- server: added support for multiple data models with static model generator. +- client: added function ClientReport_getBufOvfl to client API +- dotnet: added support to access report entry ID + +Changes to version 0.8.5 +------------------------ +- server/GOOSE: better support for GOOSE minTime, maxTime +- server/GOOSE: it is now configurable which GoCB elements are writable +- server: fixed problem (buffer overflow) with large report data sets +- server: improved memory handling in report generation module +- server/GOOSE: added IedServer_setGooseInterfaceId to change ethernet interface for GOOSE at runtime +- server: fixed bug in delete data set service (server crashed when client sent an unknown LD name) +- client: fixed memory leak in IedConnection_readDataSetValues function +- server: fixed memory alignement problem for buffered reporting on ARM platform +- client: fixed timeout bug in Socket_connect functions +- windows: fixed problem with non-blocking socket send function on windows (as a consequence COTP fragmentation and file read service didn't work on the windows platform). + +Changes to version 0.8.4 +------------------------ +- server: implemented all optional report elements for buffered reporting +- server: fixed bug (server crash) for buffered reporting of integer values +- client: client closes socket after timeout when sending an ABORT message +- common: removed wrong transport disconnect parameter from session FINISH message +- client: LastApplError contrlObj detection is now more robust +- SCL parser: parser consider default values from "DataTypeTemplates" section +- server: now sending error message when client sends a getDataDefinition with wrong domain name +- server: fixed standard deviations in unbuffered reporting +- server: predefined data sets can contain element of multiple logical devices +- MMS server: added callbacks for deletion and creation of new data sets (named variable lists) +- and a lot of small buf fixes + + +Changes to version 0.8.3 +------------------------ +- client: better support for optional report elements +- server: fixed some minor problems with reporting +- C# API: Fixed report handler and other problems in C# wrapper layer +- C# API: Fixed problem with data set creation +- server: support for association specific data sets in reports +- server: added bufOvl support for buffered reporting +- server: added support for data-references in reports +- server: fixed server crash when client tries to read structured SE variables +- SCL: configuration file creator supports default values from SCL type templates + +Changes to version 0.8.2 +------------------------ +- Client: Added adjustable timeout to connect functions +- Client: Support for T selectors with different size than two bytes +- GOOSE publisher: added support for explicit GoID +- GOOSE subscriber: refactored subscriber +- Server: Added support for setting groups +- Server: Added support for data references in reports +- SCL parser: support for "Val" attributes in DA type definitions +- Server: Added function to disable all GOOSE publishing +- Client/Server: added helper functions for Dbpos +- C# API: more features and improved stability + +Changes to version 0.8.1 +------------------------ +- IEC 61850/MMS client: IedConnection and MmsConnection objects can now be reused +- reorganization of library header files +- C# API provides support for bit string and octet string data type +- IEC 61850 client/server: Added support for CommandTermination- +- C# API added handler for CommandTermination messages +- IEC 61850 server: IED name for static device model can now be configured at runtime +- Client/server: Fixed problem with association specific data sets +- GOOSE: fixed triggering GOOSE reports for data set members without trigger condition set +- Linux/Windows/BSD: added support for select based socket read (reduces CPU load) +- C# API added support for file services +- a lot of small bug fixes + +Changes to version 0.8 +----------------------- +- HAL: socket layer. Some changes. read and accept are now non-blocking. Changes the standard implementations (Linux/POSIX, WIN32, BSD) accordingly +- server stack: added single-threaded and threadless operation modes to better fit to resource constraint devices (added new configuration option CONFIG_MMS_SINGLE_THREADED) +- some small changes in server side control model handling (ControlHandler return values and behaviour) to enable threadless and single-threaded operation. +- C# client API extended and XML documentation completed +- some smaller bug fixes and extensions + + +Changes to version 0.7.8 +------------------------ +- IED client: added client side support for Ed.1 compliant control (client side automatically detects if a control is ed1 or ed2 compliant) +- Tools: SCL parser throws exceptions if names are defined multiple times in the same context +- build support for FreeBSD (gmake and cmake) +- server: fixed BER encoding problen in file close/delete response messages +- server: fixed wrong reason-for-inclusion encoding for GI/integrity reports in buffered reporting +- server: fixed endianess issue with report entry id +- Configuration tools: fixed bug in static model generator - generator does not create RCBs for all logical devices +- mms server: added support for vmd-scope named variables +- mms server: support for standard MMS get-name-list behaviour (no flat address space) +- common: refactored MmsValue string handling +- some small extensions to C# client API + +Changes to version 0.7.7 +------------------------ +- client: fixed encoding bug in file close service +- Configuration tools: fixed code generator problem with index report control blocks +- Configuration tools: fixed problem with multiple data sets in a logical node +- Configuration tools: configuration file generator can now handle arrays of data objects +- Configuration toosl: configuration file generator does now properly define predefined unicode strings +- removed some older functions of client API report setup in favor of ClientReportControlBlock +- client side report handling does no longer require to read the data set before reports can be received +- added preview version of C# client API +- added support (HAL) for Mac OS X (thanks to Michael Clausen - HES-SO Valais-Wallis) +- some fixes in server side report handling (data set containing complex data attributes or FCDOs) +- buffered reporting: fixed problem when buffer can only hold a single entry +- fixed problem in function MmsValue_cloneToBuffer used by buffered reporting +- fixed problem in GOOSE publisher (sqNum starts with 1 instead of 0) +- added convenience methods IedServer_updateInt64AttributeValue and IedServer_updateVisibleStringAttributeValue +- added conditional extern "C" declaration to header files for use in C++ projects +- server now closes TCP socket after sending the ACSE release message + +Changes to version 0.7.6 +------------------------ +- Server: fixed bug: authenticator will be called and can accept client connection even if no authentication value is provided +- Tools: SCL parser accepts SCL files without communication section +- Server: fixed missing support for nested control objects (required to support IEC 61400-25-2) +- client API: fixed some bugs in client API functions of version 0.7.5 +- client API: added support to receive CommandTermination message of enhanced control models +- server API: new function to get access to DataAttribute references without knowing the IED name +- some other small changes... + +Changes to version 0.7.5 +------------------------ +- Client API: added convenience functions to avoid direct handling with MmsValue instances +- Added timestamp handling functions +- Configuration tools (genmodel/genconfig) allow specification of access point and IED for SCL files containing more then one IED / access point +- client/server: COTP layer is now more efficient +- added server example to illustrate using arrays of data objects +- MMS server: fixed potential dead-lock problem server side +- IED server: solved problem that client writes didn't trigger a report +- MMS server: fixed problem in fileDirectory response +- server: removed optional transfer syntax field in ACSE layer to improve compatibility with some clients +- some other smaller bug fixes ... + +Changes to version 0.7.4 +------------------------ +- Configurations tools: fixed bug with default values and short addresses for sub data objects and sub data attributes +- DLL build with Visual Studio now exports functions +- server stack is more configurable (some services can be excluded to reduce binary size) +- improved doxygen documentation +- Client API: control service supports originator value (orIdent/orCat) +- Server: control service checks for valid originator value +- fixed problem with blocking client abort function +- Server API: helper functions for dynamic data model creation now contains support for most CDCs of IEC 61850-7-3 (Ed.2) +- Client API: client report structure now provides access to report timestamp +- Configuration tool: fixed data set problem with static model generator of 0.7 series +- fixed some other minor problems ... + +Changes to version 0.7.3 +------------------------ +- Server/Client: MMS deleteFile and renameFile services +- IEC client API: deleteFile ACSI service +- fixed bug when compiling for big endian systems +- Client/Server API: added Quality data type and handling functions +- Server API: added IedServer_updateQuality, IedServer_updateFloatAttributeValue.. convenience functions. +- extended cmake builder (contains some experimental configuration options) +- added install target to cmake and make build systems. + +Changes to version 0.7.2 +------------------------ + +- Server API: added API to create data models at runtime +- Server: added some helper functions to create common CDCs at runtime +- Server/ Server API: added configuration file parser +- Server: Implemented AcseAuthenticator to provide more flexible authentication and access control schemes +- Server: added windows support for file services (both for Visual Studio and MinGW) +- Server/Tools: Added access to data attributes by simple integer short addresses ("sAddr" SCL file attribute) +- Tools: added configuration file generator tool +- Added examples for using file services and dynamic model features +- GOOSE publisher: fixed bug - sending wrong confRef field + +Changes to version 0.7.1.1 +-------------------------- + +- Server: fixed long term stack memory leak present in versions 0.7 and 0.7.1 + +Changes to version 0.7.1 +------------------------ +- Server API: Added IedServer_getFunctionalConstrainedData function to simplify handling of arrays of data objects. +- Client API: Made connetion parameters for ACSE and lower layers fully configurable (AP-title, AEQualifier, PSel, SSel, TSel) - required to be compatible with some servers +- MMS server: made number of concurrent TCP connections configurable by CONFIG_MAXIMUM_... define +- MMS client/server: added MMS status services +- MMS server: made MMS identify service optional +- added file access abstraction to HAL +- MMS client/server: added getFileDirectory, fileOpen, fileRead, fileClose services +- Client/server: added GetFile ACSI service + +Changes to version 0.7 +----------------------- +- Server: added support for buffered reporting +- Server: Bug fix: trigger reasons for reports are taken from SCL file +- Server/Server API: added callback to perform access control on write accesses +- Server/Server API: added default access policies to writable FCs +- Client API: get/setGoCBValues ACSI services - new ClientGooseControlBlock class +- Client API: added callbacks for connection losses +- GOOSE Subscriber: API change -> use GoCBReference instead of DataSetReference to identify a GOOSE message +- GOOSE Subscriber: Bug fix: Linux driver now switches interface to promiscuous mode. +- MMS Client: improved buffer handling +- MMS Client/MMS Client API: Added functions to browse and read VMD scope variables +- Client/Client API/Server: Implemented ABORT and RELEASE services +- Client API: Allows definition of association specific data sets +- MMS Client API: Removed all occurances of MmsIndication type in MMS client API + +Changes to version 0.6 +------------------------ +- Client API: getDataSetDirectory ACSI service +- Client API: create and delete data set ACSI services +- Client API: added getRCBValue/setRCBValues ACSI services to improve client support for reporting +- client side stack: improved error handling +- Client API: Methods to allow clients track the connection state +- Client API: Report handler provides access to reason-for-inclusion +- Server API: added callbacks for connection events +- Server API: new ClientConnection object that will be handed over to some callback functions to allow connection specific reactions on events -> some callback handler signatures have changed! +- Added server side support for indexed RCBs +- more efficient server side buffer handling +- added BeagleBone LED control demo +- DEBUG output can be switched on/off for stack components +- and a lot of small improvements and bug fixes + +Changes to version 0.5.3 +------------------------ +- MMS client/server: multiple variables can be written with a single MMS write request +- changed encoding of boolean to be compatible with buggy server devices +- added TCP keep alive support to MMS client +- added IedConnection_triggerGIReport function +- some enhancements in server side report handling +- some bug fixes + +Changes to version 0.5.2.1 +-------------------------- +- all examples now compile with VC++ +- CMake script supports GOOSE for Windows if winpcap is available + +Changes to version 0.5.2 +------------------------ +- fixed problem when compiling with MINGW +- changed order of FC named variables according to standard +- fixed some other compatibility problems +- allows read access to sub-elements of control variables +- allows write access to GoCB if the control block is not enabled +- allows dynamically generated datasets to be used with GOOSE + +Changes to version 0.5.1 +------------------------ +- made code compatible with Visual Studio C++ (tested with versions 2010/2012) +- added new build system based on cmake. It is now possible to create solution and project files for different versions ofVisual Studio as well as for other IDEs/toolchains. +- fixed interoperability problem in ACSE layer +- added server side support to use dynamically created data sets in reports (addSubscription service according to IEC 61400-25) + +Changes to version 0.5 +---------------------- +- client support for control +- client support for multiple outstanding requests. +- full server support for all control models and time avtivated control +- added client and server support for MMS identify service +- extended build system to build shared libraries (linux shared objects and DLLs) with "make dynlib" +- some small bug fixes in model generator tool +- fixed bug in handling reject messages + +Changes to version 0.4.1 +------------------------ +- SCL parser/code generator is more tolerant +- ubrcb supports resv handling +- fixed problems in presentation layer +- fixed problems when running on 64 bit systems + + +Changes to version 0.4.0.2 +-------------------------- +- removed too strict requirements in accepting session layer accept message client side. +- fixed memory management bugs in client and server. + + +Changes to version 0.4.0.1 +-------------------------- +- fixed problem in client association request message in new presentation layer code +- MMS read access to GoCB and control objects is now more flexibel to be compatible with more clients + +Changes to version 0.4 +---------------------- +- GOOSE publisher for windows based on winpcap +- GOOSE subscriber for linux and windows +- Started to implement a IEC 61850 client API (supported functions yet: read/write variables, simple model discovery functions, support for receiving reports) +- reimplemented presentation layer and ACSE for more efficient memory handling. +- changed error handling in MMS client + +Changes to version 0.3.3.1 +-------------------------- +- fixed bug in MMS client that causes a segmentation fault when the connection to the server cannot be established. + +Changes to version 0.3.3 +------------------------ +- added facility to observe write access to individual data attributes. +- added experimental GOOSE publisher code for Linux. The server also exposes configuration parameters with the GoCB. +- Server now respects the "BufTm" parameter as set by the client or SCL file. This allows related events to be accumulated for the period of time specified by "BufTm" and reported in a single report message. + +Changes to version 0.3.2 +------------------------ +- added support functions for MMS time types (MMS_BINARY_TIME and MMS_UTC_TIME). +- improved server side support for reporting. Reports can now contain TimeOfEntry values. The server now +respects most of the options for reports set by the client. +- added Semaphore functions to HAL API (thread.h). Semaphores are used by the server stack for internal +synchonization. +- fixed bugs in code that is responsible for remote access to report control blocks. +- fixed bug in COTP code when TPDU size is larger than 1024 bytes. TPDU size can now be as large as 16384 bytes. +- fixed bug in Hal_getTimeInMs function for Windows. Window filetime value will now be correctly converted. +- fixed problems with read access to complex array types (arrays of constructed attribute classes). + +Changes to version 0.3.1 +------------------------ +- improved support for reporting - more options are possible, reason code can be included in reports +- basic support for control model (operate) in server and server API +- added server example for control model (server_example3) + +Changes to version 0.3 +---------------------- +- change server API, access to data model via handles +- SCL file parser supports buffered and unbuffered report control blocks +- server support for unbuffered reporting (supported triggers are GI, integrity and value update) +- MMS client support for MMS information reports +- MMS stack supports fragmented transmission for MMS getNameList service +- new structure for examples directory -> each example is in its own directory and has its own Makefile +- server support for additional ACSI types -> better support for IEC 61850 data models +- server enforces write access restrictions to the IEC 61850 data model based on functional constraints. +- added support for TCP keepalive +- and a lot of bug fixes + +Changes to version 0.2.1 +------------------------ +- fixed bug in SCL file parser +- Added doxygen generated documentation to source distribution +- some bug fixes + + +Changes to version 0.2 +----------------------- +- Support for association specific data sets (named variable lists) +- Support for permanent data sets configured in SCL file +- fixed bug when deleting data sets +- data sets can now contain variables of different MMS domains (IEC 61850 logical devices) +- Changed handling of MMS GetNameList service in MMS client API + +Changes to version 0.1.1 +------------------------- +- a template project and makefile to simplify getting started with the library. +- New implementation of the model generator tool that now contains its own SCL file parser. + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..13296b5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,145 @@ +cmake_minimum_required(VERSION 2.8) + +# automagically detect if we should cross-compile +if(DEFINED ENV{TOOLCHAIN}) + set(CMAKE_C_COMPILER $ENV{TOOLCHAIN}gcc) + set(CMAKE_CXX_COMPILER $ENV{TOOLCHAIN}g++) + set(CMAKE_AR "$ENV{TOOLCHAIN}ar" CACHE FILEPATH "CW archiver" FORCE) +endif() + +project(libiec61850) + +set(LIB_VERSION_MAJOR "0") +set(LIB_VERSION_MINOR "8") +set(LIB_VERSION_PATCH "7") + +# feature checks +include(CheckLibraryExists) +check_library_exists(rt clock_gettime "time.h" CONFIG_SYSTEM_HAS_CLOCK_GETTIME) + +# check if we are on a little or a big endian +include (TestBigEndian) +test_big_endian(PLATFORM_IS_BIGENDIAN) + +set(CONFIG_MMS_MAXIMUM_PDU_SIZE "65000" CACHE STRING "Configure the maximum size of an MMS PDU (default 65000)" ) +set(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 CACHE STRING "Configure the maximum number of clients allowed to connect to the server") + +option(BUILD_EXAMPLES "Build the examples" ON) + +option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" OFF) +option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF) + +# choose the library features which shall be included +option(CONFIG_INCLUDE_GOOSE_SUPPORT "Build with GOOSE support" ON) + +option(CONFIG_IEC61850_CONTROL_SERVICE "Build with support for IEC 61850 control features" ON) + +option(CONFIG_IEC61850_REPORT_SERVICE "Build with support for IEC 61850 reporting services" ON) + +option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON) + +option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON) + +set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "8000" CACHE STRING "Default buffer size for buffered reports in byte" ) + +# advanced options +option(DEBUG "Enable debugging mode (include assertions)" OFF) +option(DEBUG_SOCKET "Enable printf debugging for socket layer" OFF) +option(DEBUG_COTP "Enable COTP printf debugging" OFF) +option(DEBUG_ISO_SERVER "Enable ISO SERVER printf debugging" OFF) +option(DEBUG_ISO_CLIENT "Enable ISO CLIENT printf debugging" OFF) +option(DEBUG_IED_SERVER "Enable IED SERVER printf debugging" OFF) +option(DEBUG_IED_CLIENT "Enable IED CLIENT printf debugging" OFF) +option(DEBUG_MMS_SERVER "Enable MMS SERVER printf debugging" OFF) +option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" OFF) +#mark_as_advanced(DEBUG DEBUG_COTP DEBUG_ISO_SERVER DEBUG_ISO_CLIENT DEBUG_IED_SERVER +# DEBUG_IED_CLIENT DEBUG_MMS_SERVER DEBUG_MMS_CLIENT) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR}/config + src/common/inc + src/goose + src/hal/inc + src/iec61850/inc + src/iec61850/inc_private + src/mms/inc + src/mms/inc_private + src/mms/iso_mms/asn1c +) + +set(API_HEADERS + src/hal/inc/hal_time.h + src/hal/inc/hal_thread.h + src/hal/inc/hal_filesystem.h + src/common/inc/libiec61850_common_api.h + src/common/inc/linked_list.h + src/common/inc/byte_buffer.h + src/common/inc/lib_memory.h + src/iec61850/inc/iec61850_client.h + src/iec61850/inc/iec61850_common.h + src/iec61850/inc/iec61850_server.h + src/iec61850/inc/iec61850_model.h + src/iec61850/inc/iec61850_cdc.h + src/iec61850/inc/iec61850_dynamic_model.h + src/iec61850/inc/iec61850_config_file_parser.h + src/mms/inc/mms_value.h + src/mms/inc/mms_common.h + src/mms/inc/mms_types.h + src/mms/inc/mms_device_model.h + src/mms/inc/mms_server.h + src/mms/inc/mms_named_variable_list.h + src/mms/inc/mms_type_spec.h + src/mms/inc/mms_client_connection.h + src/mms/inc/iso_connection_parameters.h + src/mms/inc/iso_server.h + src/mms/inc/ber_integer.h + src/mms/inc/asn1_ber_primitive_value.h + src/goose/goose_subscriber.h + src/goose/goose_receiver.h +) + +IF(WIN32) +include_directories( + src/vs +) +ENDIF(WIN32) + +# write the detected stuff to this file +configure_file(config/stack_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h) + +if(BUILD_EXAMPLES) + add_subdirectory(examples) +endif(BUILD_EXAMPLES) + +add_subdirectory(src) + +INSTALL(FILES ${API_HEADERS} DESTINATION include/libiec61850) + + +IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") +INCLUDE(InstallRequiredSystemLibraries) + +SET(CPACK_SET_DESTDIR "on") +SET(CPACK_INSTALL_PREFIX "/usr") +SET(CPACK_GENERATOR "DEB") + +SET(CPACK_PACKAGE_DESCRIPTION "IEC 61850 MMS/GOOSE client and server library") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IEC 61850 MMS/GOOSE client and server library") +SET(CPACK_PACKAGE_VENDOR "The libIEC61850 project") +SET(CPACK_PACKAGE_CONTACT "info@libiec61850.com") +SET(CPACK_PACKAGE_VERSION_MAJOR "${LIB_VERSION_MAJOR}") +SET(CPACK_PACKAGE_VERSION_MINOR "${LIB_VERSION_MINOR}") +SET(CPACK_PACKAGE_VERSION_PATCH "${LIB_VERSION_PATCH}") +SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CMAKE_SYSTEM_PROCESSOR}") +SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + +SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") +SET(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) + +SET(CPACK_COMPONENTS_ALL Libraries ApplicationData) +INCLUDE(CPack) + +ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + + + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..816d55f --- /dev/null +++ b/Makefile @@ -0,0 +1,160 @@ +LIBIEC_HOME=. + +include make/target_system.mk + +LIB_SOURCE_DIRS = src/mms/iso_acse +LIB_SOURCE_DIRS += src/mms/iso_acse/asn1c +LIB_SOURCE_DIRS += src/mms/iso_presentation/asn1c +LIB_SOURCE_DIRS += src/mms/iso_presentation +LIB_SOURCE_DIRS += src/mms/iso_session +LIB_SOURCE_DIRS += src/common +LIB_SOURCE_DIRS += src/mms/asn1 +LIB_SOURCE_DIRS += src/mms/iso_cotp +LIB_SOURCE_DIRS += src/mms/iso_mms/server +LIB_SOURCE_DIRS += src/mms/iso_mms/client +LIB_SOURCE_DIRS += src/mms/iso_client +LIB_SOURCE_DIRS += src/mms/iso_common +LIB_SOURCE_DIRS += src/mms/iso_mms/common +LIB_SOURCE_DIRS += src/mms/iso_mms/asn1c +LIB_SOURCE_DIRS += src/mms/iso_server +ifndef EXCLUDE_ETHERNET_WINDOWS +LIB_SOURCE_DIRS += src/goose +endif +LIB_SOURCE_DIRS += src/iec61850/client +LIB_SOURCE_DIRS += src/iec61850/common +LIB_SOURCE_DIRS += src/iec61850/server +LIB_SOURCE_DIRS += src/iec61850/server/model +LIB_SOURCE_DIRS += src/iec61850/server/mms_mapping +LIB_SOURCE_DIRS += src/iec61850/server/impl +ifeq ($(HAL_IMPL), WIN32) +LIB_SOURCE_DIRS += src/hal/socket/win32 +LIB_SOURCE_DIRS += src/hal/thread/win32 +LIB_SOURCE_DIRS += src/hal/ethernet/win32 +LIB_SOURCE_DIRS += src/hal/filesystem/win32 +LIB_SOURCE_DIRS += src/hal/time/win32 +else ifeq ($(HAL_IMPL), POSIX) +LIB_SOURCE_DIRS += src/hal/socket/linux +LIB_SOURCE_DIRS += src/hal/thread/linux +LIB_SOURCE_DIRS += src/hal/ethernet/linux +LIB_SOURCE_DIRS += src/hal/filesystem/linux +LIB_SOURCE_DIRS += src/hal/time/unix +else ifeq ($(HAL_IMPL), BSD) +LIB_SOURCE_DIRS += src/hal/socket/bsd +LIB_SOURCE_DIRS += src/hal/thread/linux +LIB_SOURCE_DIRS += src/hal/ethernet/bsd +LIB_SOURCE_DIRS += src/hal/filesystem/linux +LIB_SOURCE_DIRS += src/hal/time/unix +endif +LIB_INCLUDE_DIRS += config +LIB_INCLUDE_DIRS += src/common/inc +LIB_INCLUDE_DIRS += src/mms/iso_mms/asn1c +LIB_INCLUDE_DIRS += src/mms/inc +LIB_INCLUDE_DIRS += src/mms/inc_private +LIB_INCLUDE_DIRS += src/hal/inc +LIB_INCLUDE_DIRS += src/goose +LIB_INCLUDE_DIRS += src/iec61850/inc +LIB_INCLUDE_DIRS += src/iec61850/inc_private +ifeq ($(HAL_IMPL), WIN32) +LIB_INCLUDE_DIRS += third_party/winpcap/Include +endif + +LIB_INCLUDES = $(addprefix -I,$(LIB_INCLUDE_DIRS)) + +ifndef INSTALL_PREFIX +INSTALL_PREFIX = ./.install +endif + +LIB_API_HEADER_FILES = src/hal/inc/hal_time.h +LIB_API_HEADER_FILES += src/hal/inc/hal_thread.h +LIB_API_HEADER_FILES += src/hal/inc/hal_filesystem.h +LIB_API_HEADER_FILES += src/common/inc/libiec61850_common_api.h +LIB_API_HEADER_FILES += src/common/inc/linked_list.h +LIB_API_HEADER_FILES += src/common/inc/byte_buffer.h +LIB_API_HEADER_FILES += src/common/inc/lib_memory.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_client.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_common.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_server.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_model.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_cdc.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_dynamic_model.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_config_file_parser.h +LIB_API_HEADER_FILES += src/mms/inc/mms_value.h +LIB_API_HEADER_FILES += src/mms/inc/mms_common.h +LIB_API_HEADER_FILES += src/mms/inc/mms_types.h +LIB_API_HEADER_FILES += src/mms/inc/mms_device_model.h +LIB_API_HEADER_FILES += src/mms/inc/mms_server.h +LIB_API_HEADER_FILES += src/mms/inc/mms_named_variable_list.h +LIB_API_HEADER_FILES += src/mms/inc/mms_type_spec.h +LIB_API_HEADER_FILES += src/mms/inc/mms_client_connection.h +LIB_API_HEADER_FILES += src/mms/inc/iso_connection_parameters.h +LIB_API_HEADER_FILES += src/mms/inc/iso_server.h +LIB_API_HEADER_FILES += src/mms/inc/ber_integer.h +LIB_API_HEADER_FILES += src/mms/inc/asn1_ber_primitive_value.h +LIB_API_HEADER_FILES += src/goose/goose_subscriber.h +LIB_API_HEADER_FILES += src/goose/goose_receiver.h + +get_sources_from_directory = $(wildcard $1/*.c) +get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir))) +src_to = $(addprefix $(LIB_OBJS_DIR)/,$(subst .c,$1,$2)) + +LIB_SOURCES = $(call get_sources,$(LIB_SOURCE_DIRS)) + +LIB_OBJS = $(call src_to,.o,$(LIB_SOURCES)) + +CFLAGS += -std=gnu99 +#CFLAGS += -Wno-error=format +CFLAGS += -Wstrict-prototypes + +ifneq ($(HAL_IMPL), WIN32) +CFLAGS += -Wuninitialized +endif + +CFLAGS += -Wsign-compare +CFLAGS += -Wpointer-arith +CFLAGS += -Wnested-externs +CFLAGS += -Wmissing-declarations +CFLAGS += -Wshadow +CFLAGS += -Wall +#CFLAGS += -Werror + +all: lib + +static_checks: lib + splint -preproc +posixlib +skip-sys-headers +gnuextensions $(LIB_INCLUDES) $(LIB_SOURCES) + +cppcheck: lib + cppcheck --force --std=c99 --enable=all $(LIB_INCLUDES) $(LIB_SOURCES) 2> cppcheck-output.xml + +lib: $(LIB_NAME) + +dynlib: CFLAGS += -fPIC + +dynlib: $(DYN_LIB_NAME) + +.PHONY: examples + +examples: + cd examples; $(MAKE) + +$(LIB_NAME): $(LIB_OBJS) + $(AR) r $(LIB_NAME) $(LIB_OBJS) + $(RANLIB) $(LIB_NAME) + +$(DYN_LIB_NAME): $(LIB_OBJS) + $(CC) $(LDFLAGS) $(DYNLIB_LDFLAGS) -shared -o $(DYN_LIB_NAME) $(LIB_OBJS) $(LDLIBS) + +$(LIB_OBJS_DIR)/%.o: %.c config + @echo compiling $(notdir $<) + $(SILENCE)mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $(LIB_INCLUDES) $(OUTPUT_OPTION) $< + +install: $(LIB_NAME) + mkdir -p $(INSTALL_PREFIX)/include + mkdir -p $(INSTALL_PREFIX)/lib + cp $(LIB_API_HEADER_FILES) $(INSTALL_PREFIX)/include + cp $(LIB_NAME) $(INSTALL_PREFIX)/lib + +clean: + rm -f $(EXAMPLES) + rm -rf $(LIB_OBJS_DIR) + diff --git a/README b/README new file mode 100644 index 0000000..88150ba --- /dev/null +++ b/README @@ -0,0 +1,103 @@ +README: +------- + +This file is part of the documentation of libiec61850. More documentation can be found online at http://libiec61850.com or in the provided doxygen documentation. + +Content: +- Overview +- Building and running the examples +- Installing the library and the API headers +- Building on Windows with GOOSE support +- Building with the cmake build script +- C# client API +- Licensing +- Third-party contributions + + +Overview +--------- + +libiec61850 is an open-source (GPLv3) implementation of an IEC 61850 client and server library. It is implemented in C (according to the C99 standard) to provide maximum portability. It can be used to implement IEC 61850 compliant client and server applications on embedded systems and PCs running Linux and Windows. Included is a set of simple example applications that can be used as a starting point to implement own IEC 61850 compliant devices or to communicate with IEC 61850 devices. + + +Building and running the examples +---------------------------------------- + +In the project root directoy type + +> make examples + +If the build succeeds you can find a few binary files in the projects root directory. You can also find a binary version of the library ("libiec61850.a") in the "build" directory. + +Run the sample applications in the example folders. E.g.: + +> cd examples/server_example1 +> sudo ./server_example1 + +on the Linux command line. + +You can test the server examples by using a generic client or the provided client example applications. + + +Installing the library and the API headers +-------------------------------------------- + +The make and cmake build scripts provide an install target. This target copies the API header files and the static library to a single directory for the headers (INSTALL_PREFIX/include) and the static library (INSTALL_PREFIX/lib). With this feature it is more easy to integrate libiec61850 in an external application since you only have to add a simple include directory to the build tool of your choice. + +This can be invoked with + +make install + +The default install directory for the make build script is ".install". + +You can modify this by setting the INSTALL_PREFIX environment variable (e.g.): + +make INSTALL_PREFIX=/usr/local install + +For the cmake build script you have to provide the CMAKE_INSTALL_PREFIX variable + + +Building on windows with GOOSE support +--------------------------------------- + +To build the library and run libiec61850 applications with GOOSE support on Windows (7/8) the use of a third-party library (winpcap) is required. This is necessary because current versions of Windows have no working support for raw sockets. You can download winpcap here (http://www.winpcap.org). + +1. Download and install winpcap. Make sure that the winpcap driver is loaded at boot time (you can choose this option at the last screen of the winpcap installer). +2. Reboot the system (you can do this also later, but you need to reboot or load the winpcap driver before running any llibiec61850 applications that use GOOSE). +3. Download the winpcap developers pack from here (http://www.winpcap.org/install/bin/WpdPack_4_1_2.zip) +4. Unpack the zip file. Copy the folders Lib and Include from the WpdPack directory in the third_party/winpcap directory of libiec61850 + +Building with the cmake build script +------------------------------------- + +With the help of the cmake build script it is possible to create platform independet project descriptions and let cmake create specific project or build files for other tools like Make or Visual Studio. + +If you have cmake installed fire up a command line (cmd.exe) and create a new subdirectory in the libiec61850-0.x folder. Change to this subdirectory. Then you can invoke cmake. As an command line argument you have to supply a "generator" that is used by cmake to create the project file for the actual build tool (in our case Visual Studio). + +cmake -G "Visual Studio 11" .. + +will instruct cmake to create a "solution" for Visual Studio 2012. To do the same thing for Visual Studio 2010 type + +cmake -G "Visual Studio 10" .. + +Note: The ".." at the end of the command line tells cmake where to find the main build script file (called CMakeLists.txt). This should point to the folder libiec61850-0.x which is in our case the parent directory (..). + +To select some configuration options you can use ccmake or cmake-gui. + +C# client API +-------------- + +A C#/.NET wrapper and examples and Visual Studio/MonoDevelop project files can be found in the dotnet folder. The examples and the C# wrapper API can be build and run on .NET or Mono. + + +Commercial licenses +------------------- +Commercial licensing and support options are provided by MZ Automation GmbH. Please contact info@mz-automation.de for more details. + + +Third-party contributions: +-------------------------- +- The Mac OS X socket and ethernet layer has been kindly contributed by Michael Clausen, HES-SO Valais-Wallis, http://www.hevs.ch + + + diff --git a/config/stack_config.h b/config/stack_config.h new file mode 100644 index 0000000..53c649f --- /dev/null +++ b/config/stack_config.h @@ -0,0 +1,200 @@ +/* + * config.h + * + * Contains global defines to configure the stack. You need to recompile the stack to make + * changes effective (make clean; make) + * + */ + +#ifndef STACK_CONFIG_H_ +#define STACK_CONFIG_H_ + +/* include asserts if set to 1 */ +#define DEBUG 0 + +/* print debugging information with printf if set to 1 */ +#define DEBUG_SOCKET 0 +#define DEBUG_COTP 0 +#define DEBUG_ISO_SERVER 0 +#define DEBUG_ISO_CLIENT 0 +#define DEBUG_IED_SERVER 0 +#define DEBUG_IED_CLIENT 0 +#define DEBUG_MMS_CLIENT 0 +#define DEBUG_MMS_SERVER 0 +#define DEBUG_GOOSE_SUBSCRIBER 0 +#define DEBUG_GOOSE_PUBLISHER 0 + +/* Maximum MMS PDU SIZE - default is 65000 */ +#define CONFIG_MMS_MAXIMUM_PDU_SIZE 65000 + +/* + * Enable single threaded mode + * + * 1 ==> server runs in single threaded mode (a single thread for the server and all client connections) + * 0 ==> server runs in multi-threaded mode (one thread for each connection and + * one server background thread ) + */ +#define CONFIG_MMS_SINGLE_THREADED 0 + +/* + * Optimize stack for threadless operation - don't use semaphores + * + * WARNING: If set to 1 normal single- and multi-threaded server are no longer working! + */ +#define CONFIG_MMS_THREADLESS_STACK 0 + +/* number of concurrent MMS client connections the server accepts, -1 for no limit */ +#define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 + +/* activate TCP keep alive mechanism. 1 -> activate */ +#define CONFIG_ACTIVATE_TCP_KEEPALIVE 1 + +/* time (in s) between last message and first keepalive message */ +#define CONFIG_TCP_KEEPALIVE_IDLE 5 + +/* time between subsequent keepalive messages if no ack received */ +#define CONFIG_TCP_KEEPALIVE_INTERVAL 2 + +/* number of not missing keepalive responses until socket is considered dead */ +#define CONFIG_TCP_KEEPALIVE_CNT 2 + +/* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */ +#define CONFIG_COTP_MAX_TPDU_SIZE 8192 + +/* timeout while reading from TCP stream in ms */ +#define CONFIG_TCP_READ_TIMEOUT_MS 1000 + +/* Ethernet interface ID for GOOSE and SV */ +#define CONFIG_ETHERNET_INTERFACE_ID "eth0" +//#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" +//#define CONFIG_ETHERNET_INTERFACE_ID "eth-f" +//#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. + +/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */ +#define CONFIG_INCLUDE_GOOSE_SUPPORT 1 + +#ifdef _WIN32 + +/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */ +#ifdef EXCLUDE_ETHERNET_WINDOWS +#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT +#undef CONFIG_INCLUDE_GOOSE_SUPPORT +#endif +#define CONFIG_INCLUDE_GOOSE_SUPPORT 0 +#define CONFIG_INCUDE_ETHERNET_WINDOWS 0 +#else +#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1 +#undef CONFIG_ETHERNET_INTERFACE_ID +#define CONFIG_ETHERNET_INTERFACE_ID "0" +#endif +#endif + +/* The GOOSE retransmission interval in ms for the stable condition - i.e. no monitored value changed */ +#define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000 + +/* The GOOSE retransmission interval in ms in the case an event happens. */ +#define CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL 500 + +/* The number of GOOSE retransmissions after an event */ +#define CONFIG_GOOSE_EVENT_RETRANSMISSION_COUNT 2 + +/* Define if GOOSE control block elements are writable (1) or read-only (0) */ +#define CONFIG_GOOSE_GOID_WRITABLE 1 +#define CONFIG_GOOSE_DATSET_WRITABLE 1 +#define CONFIG_GOOSE_CONFREV_WRITABLE 0 +#define CONFIG_GOOSE_NDSCOM_WRITABLE 0 +#define CONFIG_GOOSE_DSTADDRESS_WRITABLE 0 +#define CONFIG_GOOSE_MINTIME_WRITABLE 0 +#define CONFIG_GOOSE_MAXTIME_WRITABLE 0 +#define CONFIG_GOOSE_FIXEDOFFS_WRITABLE 0 + +/* The default value for the priority field of the 802.1Q header (allowed range 0-7) */ +#define CONFIG_GOOSE_DEFAULT_PRIORITY 4 + +/* The default value for the VLAN ID field of the 802.1Q header - the allowed range is 2-4096 or 0 if VLAN/priority is not used */ +#define CONFIG_GOOSE_DEFAULT_VLAN_ID 0 + +/* Configure the 16 bit APPID field in the GOOSE header */ +#define CONFIG_GOOSE_DEFAULT_APPID 0x1000 + +/* Default destination MAC address for GOOSE */ +#define CONFIG_GOOSE_DEFAULT_DST_ADDRESS {0x01, 0x0c, 0xcd, 0x01, 0x00, 0x01} + +/* include support for IEC 61850 control services */ +#define CONFIG_IEC61850_CONTROL_SERVICE 1 + +/* The default select timeout in ms. This will apply only if no sboTimeout attribute exists for a control object. Set to 0 for no timeout. */ +#define CONFIG_CONTROL_DEFAULT_SBO_TIMEOUT 15000 + +/* include support for IEC 61850 reporting services */ +#define CONFIG_IEC61850_REPORT_SERVICE 1 + +/* The default buffer size of buffered RCBs in bytes */ +#define CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE 65536 + +/* include support for setting groups */ +#define CONFIG_IEC61850_SETTING_GROUPS 1 + +/* default reservation time of a setting group control block in s */ +#define CONFIG_IEC61850_SG_RESVTMS 300 + +/* default results for MMS identify service */ +#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" +#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" +#define CONFIG_DEFAULT_MMS_REVISION "0.8.7" + +/* MMS virtual file store base path - where file services are looking for files */ +#define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/" + +/* Maximum number of open file per MMS connection (for MMS file read service) */ +#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5 + +/* Maximum number of the domain specific data sets - this also includes the static (pre-configured) and dynamic data sets */ +#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10 + +/* Maximum number of association specific data sets */ +#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10 + +/* Maximum number of VMD specific data sets */ +#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10 + +/* Maximum number of the members in a data set (named variable list) */ +#define CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 50 + +/* Definition of supported services */ +#define MMS_DEFAULT_PROFILE 1 + +#if (MMS_DEFAULT_PROFILE == 1) +#define MMS_READ_SERVICE 1 +#define MMS_WRITE_SERVICE 1 +#define MMS_GET_NAME_LIST 1 +#define MMS_GET_VARIABLE_ACCESS_ATTRIBUTES 1 +#define MMS_DATA_SET_SERVICE 1 +#define MMS_DYNAMIC_DATA_SETS 1 +#define MMS_GET_DATA_SET_ATTRIBUTES 1 +#define MMS_STATUS_SERVICE 1 +#define MMS_IDENTIFY_SERVICE 1 +#define MMS_FILE_SERVICE 1 +#endif /* MMS_DEFAULT_PROFILE */ + +#if (MMS_WRITE_SERVICE != 1) +#undef CONFIG_IEC61850_CONTROL_SERVICE +#define CONFIG_IEC61850_CONTROL_SERVICE 0 +#endif + +/* support flat named variable name space required by IEC 61850-8-1 MMS mapping */ +#define CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE 1 + +/* VMD scope named variables are not used by IEC 61850 (one application is ICCP) */ +#define CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES 0 + +/* Sort getNameList response according to the MMS specified collation order - this is required by the standard + * Set to 0 only for performance reasons and when no certification is required! */ +#define CONFIG_MMS_SORT_NAME_LIST 1 + +#define CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS 0 + +/* use short FC defines as in old API */ +#define CONFIG_PROVIDE_OLD_FC_DEFINES 0 + +#endif /* STACK_CONFIG_H_ */ diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake new file mode 100644 index 0000000..011cbf8 --- /dev/null +++ b/config/stack_config.h.cmake @@ -0,0 +1,189 @@ +/* + * config.h (template for cmake) + * + * Contains global defines to configure the stack. You need to recompile the stack to make + * changes effective (make clean; make) + * + */ + +#ifndef STACK_CONFIG_H_ +#define STACK_CONFIG_H_ + +/* set to 0 for a little-endian target, 1 for a big-endian target */ +#cmakedefine01 PLATFORM_IS_BIGENDIAN + +/* define if the system supports clock_gettime */ +#cmakedefine CONFIG_SYSTEM_HAS_CLOCK_GETTIME + +/* include asserts if set to 1 */ +#cmakedefine01 DEBUG + +/* print debugging information with printf if set to 1 */ +#cmakedefine01 DEBUG_SOCKET +#cmakedefine01 DEBUG_COTP +#cmakedefine01 DEBUG_ISO_SERVER +#cmakedefine01 DEBUG_ISO_CLIENT +#cmakedefine01 DEBUG_IED_SERVER +#cmakedefine01 DEBUG_IED_CLIENT +#cmakedefine01 DEBUG_MMS_CLIENT +#cmakedefine01 DEBUG_MMS_SERVER +#cmakedefine01 DEBUG_GOOSE_SUBSCRIBER +#cmakedefine01 DEBUG_GOOSE_PUBLISHER + +/* 1 ==> server runs in single threaded mode (one dedicated thread for the server) + * 0 ==> server runs in multi threaded mode (one thread for each connection and + * one server background thread ) + */ +#cmakedefine01 CONFIG_MMS_SINGLE_THREADED + +/* Optimize stack for threadless operation - don't use semaphores */ +#cmakedefine01 CONFIG_MMS_THREADLESS_STACK + +/* Maximum MMS PDU SIZE - default is 65000 */ +#cmakedefine CONFIG_MMS_MAXIMUM_PDU_SIZE @CONFIG_MMS_MAXIMUM_PDU_SIZE@ + +/* number of concurrent MMS client connections the server accepts, -1 for no limit */ +#cmakedefine CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS @CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS@ + +/* activate TCP keep alive mechanism. 1 -> activate */ +#cmakedefine01 CONFIG_ACTIVATE_TCP_KEEPALIVE + +/* time (in s) between last message and first keepalive message */ +#define CONFIG_TCP_KEEPALIVE_IDLE 5 + +/* time between subsequent keepalive messages if no ack received */ +#define CONFIG_TCP_KEEPALIVE_INTERVAL 2 + +/* number of not missing keepalive responses until socket is considered dead */ +#define CONFIG_TCP_KEEPALIVE_CNT 2 + +/* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */ +#define CONFIG_COTP_MAX_TPDU_SIZE 8192 + +/* timeout while reading from TCP stream in ms */ +#define CONFIG_TCP_READ_TIMEOUT_MS 1000 + +/* Ethernet interface ID for GOOSE and SV */ +#define CONFIG_ETHERNET_INTERFACE_ID "eth0" +//#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" +//#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. + +/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */ +#cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT + +#ifdef _WIN32 + +/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */ +#ifdef EXCLUDE_ETHERNET_WINDOWS +#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT +#undef CONFIG_INCLUDE_GOOSE_SUPPORT +#endif +#define CONFIG_INCLUDE_GOOSE_SUPPORT 0 +#define CONFIG_INCUDE_ETHERNET_WINDOWS 0 +#else +#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1 +#undef CONFIG_ETHERNET_INTERFACE_ID +#define CONFIG_ETHERNET_INTERFACE_ID "0" +#endif +#endif + +/* The GOOSE retransmission interval in ms for the stable condition - i.e. no monitored value changed */ +#define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000 + +/* The GOOSE retransmission interval in ms in the case an event happens. */ +#define CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL 500 + +/* The number of GOOSE retransmissions after an event */ +#define CONFIG_GOOSE_EVENT_RETRANSMISSION_COUNT 2 + +/* Define if GOOSE control block elements are writable (1) or read-only (0) */ +#define CONFIG_GOOSE_GOID_WRITABLE 1 +#define CONFIG_GOOSE_DATSET_WRITABLE 1 +#define CONFIG_GOOSE_CONFREV_WRITABLE 1 +#define CONFIG_GOOSE_NDSCOM_WRITABLE 1 +#define CONFIG_GOOSE_DSTADDRESS_WRITABLE 1 +#define CONFIG_GOOSE_MINTIME_WRITABLE 1 +#define CONFIG_GOOSE_MAXTIME_WRITABLE 1 +#define CONFIG_GOOSE_FIXEDOFFS_WRITABLE 1 + +/* The default value for the priority field of the 802.1Q header (allowed range 0-7) */ +#define CONFIG_GOOSE_DEFAULT_PRIORITY 4 + +/* The default value for the VLAN ID field of the 802.1Q header - the allowed range is 2-4096 or 0 if VLAN/priority is not used */ +#define CONFIG_GOOSE_DEFAULT_VLAN_ID 0 + +/* Configure the 16 bit APPID field in the GOOSE header */ +#define CONFIG_GOOSE_DEFAULT_APPID 0x1000 + +/* Default destination MAC address for GOOSE */ +#define CONFIG_GOOSE_DEFAULT_DST_ADDRESS {0x01, 0x0c, 0xcd, 0x01, 0x00, 0x01} + +/* include support for IEC 61850 control services */ +#cmakedefine01 CONFIG_IEC61850_CONTROL_SERVICE + +/* The default select timeout in ms. This will apply only if no sboTimeout attribute exists for a control object. Set to 0 for no timeout. */ +#define CONFIG_CONTROL_DEFAULT_SBO_TIMEOUT 15000 + +/* include support for IEC 61850 reporting services */ +#cmakedefine01 CONFIG_IEC61850_REPORT_SERVICE + +/* The default buffer size of buffered RCBs in bytes */ +#cmakedefine CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE @CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE@ + +/* include support for setting groups */ +#cmakedefine01 CONFIG_IEC61850_SETTING_GROUPS + +/* default reservation time of a setting group control block in s */ +#define CONFIG_IEC61850_SG_RESVTMS 100 + +/* default results for MMS identify service */ +#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" +#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" +#define CONFIG_DEFAULT_MMS_REVISION "${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}" + +/* support flatted named variable name space required by IEC 61850-8-1 MMS mapping */ +#define CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE 1 + +/* VMD scope named variables are not used by IEC 61850 */ +#define CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES 0 + +/* MMS virtual file store base path - where file services are looking for files */ +#define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/" + +/* Maximum number of open file per MMS connection (for MMS file read service) */ +#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5 + +#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10 + +#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10 + +#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10 + +/* Maximum number of the members in a data set (named variable list) */ +#define CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 50 + +/* Definition of supported services */ +#define MMS_DEFAULT_PROFILE 1 + +#if MMS_DEFAULT_PROFILE +#define MMS_READ_SERVICE 1 +#define MMS_WRITE_SERVICE 1 +#define MMS_GET_NAME_LIST 1 +#define MMS_GET_VARIABLE_ACCESS_ATTRIBUTES 1 +#define MMS_DATA_SET_SERVICE 1 +#define MMS_DYNAMIC_DATA_SETS 1 +#define MMS_GET_DATA_SET_ATTRIBUTES 1 +#define MMS_STATUS_SERVICE 1 +#define MMS_IDENTIFY_SERVICE 1 +#define MMS_FILE_SERVICE 1 +#endif /* MMS_DEFAULT_PROFILE */ + +#if (MMS_WRITE_SERVICE != 1) +#undef CONFIG_IEC61850_CONTROL_SERVICE +#define CONFIG_IEC61850_CONTROL_SERVICE 0 +#endif + +/* use short FC defines as in old API */ +#define CONFIG_PROVIDE_OLD_FC_DEFINES 0 + +#endif /* STACK_CONFIG_H_ */ diff --git a/demos/beaglebone/CMakeLists.txt b/demos/beaglebone/CMakeLists.txt new file mode 100644 index 0000000..eb0d580 --- /dev/null +++ b/demos/beaglebone/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(beagle_demo_SRCS + beagle_demo.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${beagle_demo_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example3 + ${beagle_demo_SRCS} +) + +target_link_libraries(server_example3 + iec61850 +) diff --git a/demos/beaglebone/Makefile b/demos/beaglebone/Makefile new file mode 100644 index 0000000..202498d --- /dev/null +++ b/demos/beaglebone/Makefile @@ -0,0 +1,26 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = beagle_demo +PROJECT_SOURCES = beagle_demo.c +PROJECT_SOURCES += beaglebone_leds.c +PROJECT_SOURCES += static_model.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +LDLIBS += -lm + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +beagle_client: beagle_client.c $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o beagle_client beagle_client.c $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) beagle_client + + diff --git a/demos/beaglebone/beagle_client.c b/demos/beaglebone/beagle_client.c new file mode 100644 index 0000000..aff7c4c --- /dev/null +++ b/demos/beaglebone/beagle_client.c @@ -0,0 +1,115 @@ +/* + * beagle_client.c + * + * Switch LEDs on the BeagleBone + */ + +#include "iec61850_client.h" + +#include +#include + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + + /************************ + * Direct control + ***********************/ + + bool led4State = false; + + ControlObjectClient controlLED1 + = ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO1", con); + + ControlObjectClient controlLED2 + = ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO2", con); + + ControlObjectClient controlLED3 + = ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO3", con); + + ControlObjectClient controlLED4 + = ControlObjectClient_create("beagleGenericIO/GGIO1.DPCSO1", con); + + MmsValue* ctlValOn = MmsValue_newBoolean(true); + + MmsValue* ctlValOff = MmsValue_newBoolean(false); + + if (!ControlObjectClient_operate(controlLED1, ctlValOff, 0)) goto control_error; + + ControlObjectClient_select(controlLED2); + if (!ControlObjectClient_operate(controlLED2, ctlValOff, 0)) goto control_error; + + if (!ControlObjectClient_operate(controlLED4, ctlValOff, 0)) goto control_error; + + while (1) { + if (!ControlObjectClient_operate(controlLED3, ctlValOff, 0)) goto control_error; + if (!ControlObjectClient_operate(controlLED1, ctlValOn, 0)) goto control_error; + Thread_sleep(1000); + + if (!ControlObjectClient_operate(controlLED1, ctlValOff, 0)) goto control_error; + + ControlObjectClient_select(controlLED2); + if (!ControlObjectClient_operate(controlLED2, ctlValOn, 0)) goto control_error; + + Thread_sleep(1000); + + ControlObjectClient_select(controlLED2); + if (!ControlObjectClient_operate(controlLED2, ctlValOff, 0)) goto control_error; + + if (!ControlObjectClient_operate(controlLED3, ctlValOn, 0)) goto control_error; + Thread_sleep(1000); + + if (led4State == false) { + if (!ControlObjectClient_operate(controlLED4, ctlValOn, 0)) goto control_error; + led4State = true; + } + else { + if (!ControlObjectClient_operate(controlLED4, ctlValOff, 0)) goto control_error; + led4State = false; + } + } + + goto exit_control_loop; + +control_error: + printf("Error controlling device!\n"); + +exit_control_loop: + + MmsValue_delete(ctlValOn); + MmsValue_delete(ctlValOff); + + ControlObjectClient_destroy(controlLED1); + ControlObjectClient_destroy(controlLED2); + ControlObjectClient_destroy(controlLED3); + ControlObjectClient_destroy(controlLED4); + + IedConnection_close(con); + } + else { + printf("Connection failed!\n"); + } + + IedConnection_destroy(con); +} + + diff --git a/demos/beaglebone/beagle_demo.c b/demos/beaglebone/beagle_demo.c new file mode 100644 index 0000000..82c1ac0 --- /dev/null +++ b/demos/beaglebone/beagle_demo.c @@ -0,0 +1,331 @@ +/* + * beagle_demo.c + * + * This demo shows how to connect the libiec61850 server stack to a real device. + * + */ + +#include "iec61850_server.h" +#include "iso_server.h" +#include "acse.h" +#include "hal_thread.h" +#include +#include +#include +#include + +#include "static_model.h" + +#include "beaglebone_leds.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; +static IedServer iedServer = NULL; + +static bool automaticOperationMode = true; +static ClientConnection controllingClient = NULL; + +static uint32_t dpcState = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + +static void +connectionIndicationHandler(IedServer server, ClientConnection connection, bool connected, void* parameter) +{ + const char* clientAddress = ClientConnection_getPeerAddress(connection); + + if (connected) { + printf("BeagleDemoServer: new client connection from %s\n", clientAddress); + } + else { + printf("BeagleDemoServer: client connection from %s closed\n", clientAddress); + + if (controllingClient == connection) { + printf("Controlling client has closed connection -> switch to automatic operation mode\n"); + controllingClient = NULL; + automaticOperationMode = true; + } + } +} + +static CheckHandlerResult +performCheckHandler(void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, ClientConnection connection) +{ + if (controllingClient == NULL) { + printf("Client takes control -> switch to remote control operation mode\n"); + controllingClient = connection; + automaticOperationMode = false; + } + + /* test command not accepted if mode is "on" */ + if (test) + return CONTROL_TEMPORARILY_UNAVAILABLE; + + /* If there is already another client that controls the device reject the control attempt */ + if (controllingClient == connection) + return CONTROL_ACCEPTED; + else + return CONTROL_TEMPORARILY_UNAVAILABLE; +} + +static void +updateLED1stVal(bool newLedState, uint64_t timeStamp) { + switchLED(LED1, newLedState); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); + IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, newLedState); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_q, QUALITY_VALIDITY_GOOD | QUALITY_SOURCE_SUBSTITUTED); +} + +static void +updateLED2stVal(bool newLedState, uint64_t timeStamp) { + switchLED(LED2, newLedState); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); + IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, newLedState); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_q, QUALITY_VALIDITY_QUESTIONABLE | QUALITY_DETAIL_OSCILLATORY); +} + +static void +updateLED3stVal(bool newLedState, uint64_t timeStamp) { + switchLED(LED3, newLedState); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); + IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, newLedState); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_q, QUALITY_VALIDITY_GOOD); +} + +static ControlHandlerResult +controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) +{ + if (test) + return CONTROL_RESULT_OK; + + uint64_t timeStamp = Hal_getTimeInMs(); + + bool newState = MmsValue_getBoolean(value); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) + updateLED1stVal(newState, timeStamp); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) + updateLED2stVal(newState, timeStamp); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) + updateLED3stVal(newState, timeStamp); + + if (parameter == IEDMODEL_GenericIO_GGIO1_DPCSO1) { /* example for Double Point Control - DPC */ + + dpcState = 0; /* DPC_STATE_INTERMEDIATE */ + IedServer_updateBitStringAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal, dpcState); + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_t, timeStamp); + + + if (newState) { + flashLED(LED4); + Thread_sleep(3000); + switchLED(LED4, 1); + dpcState = 2; /* DPC_STATE_ON */ + } + else { + flashLED(LED4); + Thread_sleep(3000); + switchLED(LED4, 0); + dpcState = 1; /* DPC_STATE_OFF */ + } + + IedServer_updateBitStringAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal, dpcState); + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_t, timeStamp); + } + + return CONTROL_RESULT_OK; +} + +static int ledOnTimeMs = 1000; +static int ledOffTimeMs = 1000; +static int32_t opCnt = 0; + +static ControlHandlerResult +controlHandlerForInt32Controls(void* parameter, MmsValue* value, bool test) +{ + if (test) + return CONTROL_RESULT_OK; + + if (parameter == IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs) { + int32_t newValue = MmsValue_toInt32(value); + + opCnt = newValue; + + uint64_t currentTime = Hal_getTimeInMs(); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t, currentTime); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal, opCnt); + } + + return CONTROL_RESULT_OK; +} + + + +static MmsDataAccessError +int32WriteAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) +{ + int newValue = MmsValue_toInt32(value); + + /* Check if value is inside of valid range */ + if (newValue < 0) + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + + if (dataAttribute == IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal) { + + printf("New value for TIM_GAPC1.OpDlTmms.setVal = %i\n", newValue); + + ledOffTimeMs = newValue; + + return DATA_ACCESS_ERROR_SUCCESS; + } + + if (dataAttribute == IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal) { + + printf("New value for TIM_GAPC1.RsDlTmms.setVal = %i\n", newValue); + + ledOnTimeMs = newValue; + + return DATA_ACCESS_ERROR_SUCCESS; + } + + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; +} + + +int main(int argc, char** argv) { + + initLEDs(); + + iedServer = IedServer_create(&iedModel); + + /* Set control callback handlers */ + IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionIndicationHandler, NULL); + + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1, + (ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_DPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_DPCSO1); + + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs, (ControlHandler) controlHandlerForInt32Controls, + IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs); + + /* Initialize process values */ + MmsValue* DPCSO1_stVal = IedServer_getAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal); + MmsValue_setBitStringFromInteger(DPCSO1_stVal, 1); /* set DPC to OFF */ + + /* Intitalize setting values */ + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal, ledOffTimeMs); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal, ledOnTimeMs); + + /* Set callback handler for settings */ + IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal, int32WriteAccessHandler, NULL); + IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal, int32WriteAccessHandler, NULL); + + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float t = 0.f; + + bool ledStateValue = false; + + uint64_t nextLedToggleTime = Hal_getTimeInMs() + 1000; + + while (running) { + uint64_t currentTime = Hal_getTimeInMs(); + + if (automaticOperationMode) { + if (nextLedToggleTime <= currentTime) { + + + if (ledStateValue) + nextLedToggleTime = currentTime + ledOffTimeMs; + else + nextLedToggleTime = currentTime + ledOnTimeMs; + + ledStateValue = !ledStateValue; + + if (ledStateValue) { + opCnt++; + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t, currentTime); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal, opCnt); + } + + updateLED1stVal(ledStateValue, currentTime); + updateLED2stVal(ledStateValue, currentTime); + updateLED3stVal(ledStateValue, currentTime); + } + } + + t += 0.1f; + + IedServer_lockDataModel(iedServer); + + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, sinf(t)); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD); + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, currentTime); + + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, sinf(t + 1.f)); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_q, QUALITY_VALIDITY_GOOD); + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, currentTime); + + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, sinf(t + 2.f)); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_q, QUALITY_VALIDITY_GOOD); + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, currentTime); + + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, sinf(t + 3.f)); + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_q, QUALITY_VALIDITY_GOOD); + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, currentTime); + + IedServer_unlockDataModel(iedServer); + + Thread_sleep(100); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/demos/beaglebone/beagle_demo.icd b/demos/beaglebone/beagle_demo.icd new file mode 100644 index 0000000..259c21f --- /dev/null +++ b/demos/beaglebone/beagle_demo.icd @@ -0,0 +1,350 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + sbo-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-enhanced-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EXT:2015 + + + + + + + + + + + + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + on + blocked + test + test/blocked + off + + + + unknown + forward + backward + both + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/demos/beaglebone/beaglebone_leds.c b/demos/beaglebone/beaglebone_leds.c new file mode 100644 index 0000000..314aa81 --- /dev/null +++ b/demos/beaglebone/beaglebone_leds.c @@ -0,0 +1,63 @@ +/* + * beaglebone_leds.c + */ + +#include +#include "beaglebone_leds.h" + +#ifndef SIMULATED +static void +writeToFile(char* filename, char* text) +{ + FILE* file = fopen(filename, "w"); + fprintf(file, "%s", text); + fclose(file); +} +#endif /* SIMULATED */ + +void +flashLED(char* led) +{ +#ifndef SIMULATED + char filename[255]; + + sprintf(filename, "%s/trigger", led); + writeToFile(filename, "timer"); + + sprintf(filename, "%s/delay_on", led); + writeToFile(filename, "200"); + + sprintf(filename, "%s/delay_off", led); + writeToFile(filename, "200"); +#else + printf("FLASH: %s\n", led); +#endif +} + +void +switchLED(char* led, int value) +{ +#ifndef SIMULATED + char filename[255]; + char valueStr[10]; + + sprintf(filename, "%s/trigger", led); + writeToFile(filename, "none"); + + sprintf(filename, "%s/brightness", led); + sprintf(valueStr, "%i", value); + + writeToFile(filename, valueStr); +#else + printf("SWITCH: %s %i\n", led, value); +#endif +} + +void +initLEDs() +{ + switchLED(LED1, 0); + switchLED(LED2, 0); + switchLED(LED3, 0); + switchLED(LED4, 0); +} diff --git a/demos/beaglebone/beaglebone_leds.h b/demos/beaglebone/beaglebone_leds.h new file mode 100644 index 0000000..61a396c --- /dev/null +++ b/demos/beaglebone/beaglebone_leds.h @@ -0,0 +1,38 @@ +/* + * beaglebone_leds.h + */ + +#ifndef BEAGLEBONE_LEDS_H_ +#define BEAGLEBONE_LEDS_H_ + + +/* set to 1 if you want to run the demo on a PC */ +//#define SIMULATED 1 + + + +/* select correct file paths to access LEDs - depends on beaglebones linux distro/version */ +#if 0 +#define LED1 "/sys/class/leds/beaglebone::usr0" +#define LED2 "/sys/class/leds/beaglebone::usr1" +#define LED3 "/sys/class/leds/beaglebone::usr2" +#define LED4 "/sys/class/leds/beaglebone::usr3" +#endif + +#if 1 +#define LED1 "/sys/class/leds/beaglebone:green:usr0" +#define LED2 "/sys/class/leds/beaglebone:green:usr1" +#define LED3 "/sys/class/leds/beaglebone:green:usr2" +#define LED4 "/sys/class/leds/beaglebone:green:usr3" +#endif + +void +flashLED(char* led); + +void +switchLED(char* led, int value); + +void +initLEDs(); + +#endif /* BEAGLEBONE_LEDS_H_ */ diff --git a/demos/beaglebone/static_model.c b/demos/beaglebone/static_model.c new file mode 100644 index 0000000..993db3e --- /dev/null +++ b/demos/beaglebone/static_model.c @@ -0,0 +1,2439 @@ +/* + * static_model.c + * + * automatically generated from beagle_demo.icd + */ +#include "static_model.h" + +static void initializeValues(); + +extern DataSet iedModelds_GenericIO_LLN0_Events; + + +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$DPCSO1$stVal", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Events = { + "GenericIO", + "LLN0$Events", + 4, + &iedModelds_GenericIO_LLN0_Events_fcda0, + NULL +}; + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0 +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, +}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, +}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_SBO, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_SBO = { + DataAttributeModelType, + "SBO", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + IEC61850_FC_CO, + VISIBLE_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + INT8, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_DPCSO1 = { + DataObjectModelType, + "DPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + CODEDENUM, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_DPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_TIM_GAPC1 = { + LogicalNodeModelType, + "TIM_GAPC1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh, +}; + +DataObject iedModel_GenericIO_TIM_GAPC1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_TIM_GAPC1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_TIM_GAPC1_Str = { + DataObjectModelType, + "Str", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str_general, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_general = { + DataAttributeModelType, + "general", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str_dirGeneral, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_dirGeneral = { + DataAttributeModelType, + "dirGeneral", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Str, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_TIM_GAPC1_Op = { + DataObjectModelType, + "Op", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpDlTmms, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op_general, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Op_general = { + DataAttributeModelType, + "general", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Op_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_Op_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_Op, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_TIM_GAPC1_OpDlTmms = { + DataObjectModelType, + "OpDlTmms", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_RsDlTmms, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpDlTmms_setVal, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpDlTmms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpDlTmms, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpDlTmms_dataNs, + NULL, + 0, + IEC61850_FC_SP, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpDlTmms_dataNs = { + DataAttributeModelType, + "dataNs", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpDlTmms, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_TIM_GAPC1_RsDlTmms = { + DataObjectModelType, + "RsDlTmms", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_RsDlTmms_setVal, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_RsDlTmms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_RsDlTmms, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_RsDlTmms_dataNs, + NULL, + 0, + IEC61850_FC_SP, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_RsDlTmms_dataNs = { + DataAttributeModelType, + "dataNs", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_RsDlTmms, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_TIM_GAPC1_OpCntRs = { + DataObjectModelType, + "OpCntRs", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1, + NULL, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_ctlModel, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_TIM_GAPC1_OpCntRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_GenericIO_LLN0_report0; +extern ReportControlBlock iedModel_GenericIO_LLN0_report1; +extern ReportControlBlock iedModel_GenericIO_LLN0_report2; +extern ReportControlBlock iedModel_GenericIO_LLN0_report3; +extern ReportControlBlock iedModel_GenericIO_LLN0_report4; + +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; +ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCB02", "Events1", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2}; +ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsRCB03", "Events1", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3}; +ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsRCB04", "Events1", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report4}; +ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "EventsRCB05", "Events1", false, "Events", 1, 24, 111, 50, 1000, NULL}; + + + + +IedModel iedModel = { + "beagle", + &iedModel_GenericIO, + &iedModelds_GenericIO_LLN0_Events, + &iedModel_GenericIO_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(2); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_DPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); + +iedModel_GenericIO_TIM_GAPC1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_TIM_GAPC1_OpDlTmms_dataNs.mmsValue = MmsValue_newVisibleString("EXT:2015"); + +iedModel_GenericIO_TIM_GAPC1_RsDlTmms_dataNs.mmsValue = MmsValue_newVisibleString("EXT:2015"); + +iedModel_GenericIO_TIM_GAPC1_OpCntRs_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); +} diff --git a/demos/beaglebone/static_model.h b/demos/beaglebone/static_model.h new file mode 100644 index 0000000..a50ade8 --- /dev/null +++ b/demos/beaglebone/static_model.h @@ -0,0 +1,399 @@ +/* + * static_model.h + * + * automatically generated from beagle_demo.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_SBO; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_DPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_DPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; +extern LogicalNode iedModel_GenericIO_TIM_GAPC1; +extern DataObject iedModel_GenericIO_TIM_GAPC1_Beh; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Beh_q; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Beh_t; +extern DataObject iedModel_GenericIO_TIM_GAPC1_Mod; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_stVal; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_q; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_t; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_TIM_GAPC1_Str; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_general; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_dirGeneral; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_q; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Str_t; +extern DataObject iedModel_GenericIO_TIM_GAPC1_Op; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Op_general; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Op_q; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_Op_t; +extern DataObject iedModel_GenericIO_TIM_GAPC1_OpDlTmms; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpDlTmms_setVal; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpDlTmms_dataNs; +extern DataObject iedModel_GenericIO_TIM_GAPC1_RsDlTmms; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_RsDlTmms_setVal; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_RsDlTmms_dataNs; +extern DataObject iedModel_GenericIO_TIM_GAPC1_OpCntRs; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_stVal; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_q; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_t; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_T; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Test; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Check; +extern DataAttribute iedModel_GenericIO_TIM_GAPC1_OpCntRs_ctlModel; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_stVal (&iedModel_GenericIO_GGIO1_Mod_stVal) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_SBO (&iedModel_GenericIO_GGIO1_SPCSO2_SBO) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1 (&iedModel_GenericIO_GGIO1_DPCSO1) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal (&iedModel_GenericIO_GGIO1_DPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_q (&iedModel_GenericIO_GGIO1_DPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper (&iedModel_GenericIO_GGIO1_DPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_DPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_DPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_DPCSO1_t (&iedModel_GenericIO_GGIO1_DPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) +#define IEDMODEL_GenericIO_TIM_GAPC1 (&iedModel_GenericIO_TIM_GAPC1) +#define IEDMODEL_GenericIO_TIM_GAPC1_Beh (&iedModel_GenericIO_TIM_GAPC1_Beh) +#define IEDMODEL_GenericIO_TIM_GAPC1_Beh_stVal (&iedModel_GenericIO_TIM_GAPC1_Beh_stVal) +#define IEDMODEL_GenericIO_TIM_GAPC1_Beh_q (&iedModel_GenericIO_TIM_GAPC1_Beh_q) +#define IEDMODEL_GenericIO_TIM_GAPC1_Beh_t (&iedModel_GenericIO_TIM_GAPC1_Beh_t) +#define IEDMODEL_GenericIO_TIM_GAPC1_Mod (&iedModel_GenericIO_TIM_GAPC1_Mod) +#define IEDMODEL_GenericIO_TIM_GAPC1_Mod_stVal (&iedModel_GenericIO_TIM_GAPC1_Mod_stVal) +#define IEDMODEL_GenericIO_TIM_GAPC1_Mod_q (&iedModel_GenericIO_TIM_GAPC1_Mod_q) +#define IEDMODEL_GenericIO_TIM_GAPC1_Mod_t (&iedModel_GenericIO_TIM_GAPC1_Mod_t) +#define IEDMODEL_GenericIO_TIM_GAPC1_Mod_ctlModel (&iedModel_GenericIO_TIM_GAPC1_Mod_ctlModel) +#define IEDMODEL_GenericIO_TIM_GAPC1_Str (&iedModel_GenericIO_TIM_GAPC1_Str) +#define IEDMODEL_GenericIO_TIM_GAPC1_Str_general (&iedModel_GenericIO_TIM_GAPC1_Str_general) +#define IEDMODEL_GenericIO_TIM_GAPC1_Str_dirGeneral (&iedModel_GenericIO_TIM_GAPC1_Str_dirGeneral) +#define IEDMODEL_GenericIO_TIM_GAPC1_Str_q (&iedModel_GenericIO_TIM_GAPC1_Str_q) +#define IEDMODEL_GenericIO_TIM_GAPC1_Str_t (&iedModel_GenericIO_TIM_GAPC1_Str_t) +#define IEDMODEL_GenericIO_TIM_GAPC1_Op (&iedModel_GenericIO_TIM_GAPC1_Op) +#define IEDMODEL_GenericIO_TIM_GAPC1_Op_general (&iedModel_GenericIO_TIM_GAPC1_Op_general) +#define IEDMODEL_GenericIO_TIM_GAPC1_Op_q (&iedModel_GenericIO_TIM_GAPC1_Op_q) +#define IEDMODEL_GenericIO_TIM_GAPC1_Op_t (&iedModel_GenericIO_TIM_GAPC1_Op_t) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms (&iedModel_GenericIO_TIM_GAPC1_OpDlTmms) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal (&iedModel_GenericIO_TIM_GAPC1_OpDlTmms_setVal) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_dataNs (&iedModel_GenericIO_TIM_GAPC1_OpDlTmms_dataNs) +#define IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms (&iedModel_GenericIO_TIM_GAPC1_RsDlTmms) +#define IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal (&iedModel_GenericIO_TIM_GAPC1_RsDlTmms_setVal) +#define IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_dataNs (&iedModel_GenericIO_TIM_GAPC1_RsDlTmms_dataNs) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs (&iedModel_GenericIO_TIM_GAPC1_OpCntRs) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_stVal) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_q (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_q) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_t) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlVal (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlVal) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orCat (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orCat) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orIdent (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlNum (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_ctlNum) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_T (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_T) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_Test (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Test) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_Oper_Check (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_Oper_Check) +#define IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_ctlModel (&iedModel_GenericIO_TIM_GAPC1_OpCntRs_ctlModel) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/dotnet/IEC61850forCSharp/AssemblyInfo.cs b/dotnet/IEC61850forCSharp/AssemblyInfo.cs new file mode 100644 index 0000000..479370f --- /dev/null +++ b/dotnet/IEC61850forCSharp/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("IEC61850 API for C#")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("MZ Automation GmbH")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Michael Zillgith")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/IEC61850forCSharp/Control.cs b/dotnet/IEC61850forCSharp/Control.cs new file mode 100644 index 0000000..cd425d8 --- /dev/null +++ b/dotnet/IEC61850forCSharp/Control.cs @@ -0,0 +1,422 @@ +/* + * Control.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +using System; +using System.Runtime.InteropServices; + +using IEC61850.Common; + +namespace IEC61850 +{ + + /// + /// IEC 61850 common API parts (used by client and server API) + /// + namespace Common { + + /// + /// Control model + /// + public enum ControlModel + { + /** status only */ + STATUS_ONLY = 0, + /** direct with normal security */ + DIRECT_NORMAL= 1, + /** select before operate (SBO) with normal security */ + SBO_NORMAL = 2, + /** direct with enhanced security */ + DIRECT_ENHANCED = 3, + /** select before operate (SBO) with enhanced security */ + SBO_ENHANCED = 4 + } + + /// + /// Originator category + /// + public enum OrCat { + /** Not supported - should not be used */ + NOT_SUPPORTED = 0, + /** Control operation issued from an operator using a client located at bay level */ + BAY_CONTROL = 1, + /** Control operation issued from an operator using a client located at station level */ + STATION_CONTROL = 2, + /** Control operation from a remote operator outside the substation (for example network control center) */ + REMOTE_CONTROL = 3, + /** Control operation issued from an automatic function at bay level */ + AUTOMATIC_BAY = 4, + /** Control operation issued from an automatic function at station level */ + AUTOMATIC_STATION = 5, + /** Control operation issued from a automatic function outside of the substation */ + AUTOMATIC_REMOTE = 6, + /** Control operation issued from a maintenance/service tool */ + MAINTENANCE = 7, + /** Status change occurred without control action (for example external trip of a circuit breaker or failure inside the breaker) */ + PROCESS = 8 + } + } + + namespace Client { + + [StructLayout(LayoutKind.Sequential)] + internal struct LastApplErrorInternal + { + public int ctlNum; + public int error; + public int addCause; + } + + public class LastApplError + { + public int ctlNum; + public int error; + public ControlAddCause addCause; + + + internal LastApplError (LastApplErrorInternal lastApplError) + { + this.addCause = (ControlAddCause) lastApplError.addCause; + this.error = lastApplError.error; + this.ctlNum = lastApplError.ctlNum; + } + } + + /// + /// Control object. + /// + public class ControlObject + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern LastApplErrorInternal ControlObjectClient_getLastApplError(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr ControlObjectClient_create(string objectReference, IntPtr connection); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_destroy(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern int ControlObjectClient_getControlModel(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool ControlObjectClient_select(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool ControlObjectClient_selectWithValue(IntPtr self, IntPtr ctlVal); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool ControlObjectClient_cancel(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_setOrigin(IntPtr self, string orIdent, int orCat); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_enableInterlockCheck(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_enableSynchroCheck(IntPtr self); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void InternalCommandTerminationHandler(IntPtr parameter,IntPtr controlClient); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_setCommandTerminationHandler(IntPtr self, + InternalCommandTerminationHandler handler, IntPtr handlerParameter); + + public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject); + + private IedConnection iedConnection; + private IntPtr controlObject; + + private CommandTerminationHandler commandTerminationHandler = null; + private Object commandTerminationHandlerParameter = null; + + private void MyCommandTerminationHandler (IntPtr paramter, IntPtr controlClient) + { + if (commandTerminationHandler != null) + commandTerminationHandler(commandTerminationHandlerParameter, this); + } + + private InternalCommandTerminationHandler intCommandTerminationHandler; + + internal ControlObject (string objectReference, IntPtr connection, IedConnection iedConnection) + { + this.iedConnection = iedConnection; + + this.controlObject = ControlObjectClient_create(objectReference, connection); + + if (this.controlObject == System.IntPtr.Zero) + throw new IedConnectionException("Control object not found", 0); + + intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler); + + ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject); + } + + ~ControlObject () + { + if (this.controlObject != System.IntPtr.Zero) + ControlObjectClient_destroy(controlObject); + } + + /// + /// Gets the control model. + /// + /// + /// The control model. + /// + public ControlModel GetControlModel () + { + ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(controlObject); + + return controlModel; + } + + /// + /// Sets the origin parameter used by control commands. + /// + /// + /// Originator. An arbitrary string identifying the controlling client. + /// + /// + /// Originator category. + /// + public void SetOrigin (string originator, OrCat originatorCategory) + { + ControlObjectClient_setOrigin(controlObject, originator, (int) originatorCategory); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise + public bool Operate (bool ctlVal) + { + return Operate (ctlVal, 0); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise + public bool Operate (bool ctlVal, UInt64 operTime) + { + MmsValue value = new MmsValue(ctlVal); + + return Operate (value, operTime); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise + public bool Operate (float ctlVal) + { + return Operate (ctlVal, 0); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise + public bool Operate (float ctlVal, UInt64 operTime) + { + MmsValue value = new MmsValue(ctlVal); + + return Operate (value, operTime); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise + public bool Operate (int ctlVal) + { + return Operate (ctlVal, 0); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise + public bool Operate (int ctlVal, UInt64 operTime) + { + MmsValue value = new MmsValue(ctlVal); + + return Operate (value, operTime); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise + public bool Operate (MmsValue ctlVal) + { + return Operate (ctlVal, 0); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise + public bool Operate (MmsValue ctlVal, UInt64 operTime) + { + return ControlObjectClient_operate(controlObject, ctlVal.valueReference, operTime); + } + + /// + /// Select the control object. + /// + /// true when the selection has been successful, false otherwise + public bool Select () + { + return ControlObjectClient_select(controlObject); + } + + + /// + /// Send a select with value command for generic MmsValue instances + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (MmsValue ctlVal) + { + return ControlObjectClient_selectWithValue(controlObject, ctlVal.valueReference); + } + + /// + /// Send a select with value command for boolean controls + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (bool ctlVal) + { + return SelectWithValue(new MmsValue(ctlVal)); + } + + /// + /// Send a select with value command for integer controls + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (int ctlVal) + { + return SelectWithValue(new MmsValue(ctlVal)); + } + + /// + /// Send a select with value command for float controls + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (float ctlVal) + { + return SelectWithValue(new MmsValue(ctlVal)); + } + + /// + /// Cancel a selection or time activated operation + /// + /// true when the cancelation has been successful, false otherwise + public bool Cancel () + { + return ControlObjectClient_cancel(controlObject); + } + + /// + /// Enables the synchro check for operate commands + /// + public void EnableSynchroCheck () + { + ControlObjectClient_enableSynchroCheck(controlObject); + } + + /// + /// Enables the interlock check for operate and select commands + /// + public void EnableInterlockCheck () + { + ControlObjectClient_enableInterlockCheck(controlObject); + } + + /// + /// Gets the last received LastApplError (Additional Cause Diagnostics) value. + /// + /// + /// The last appl error. + /// + public LastApplError GetLastApplError () + { + LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(controlObject); + + return new LastApplError(lastApplError); + } + + /// + /// Sets the command termination handler. + /// + /// + /// the handler (delegate) that is invoked when a CommandTerminationMessage is received. + /// + /// + /// Parameter. + /// + public void SetCommandTerminationHandler (CommandTerminationHandler handler, Object parameter) + { + this.commandTerminationHandler = handler; + this.commandTerminationHandlerParameter = parameter; + } + + } + + } + +} + diff --git a/dotnet/IEC61850forCSharp/DataSet.cs b/dotnet/IEC61850forCSharp/DataSet.cs new file mode 100644 index 0000000..c0c887e --- /dev/null +++ b/dotnet/IEC61850forCSharp/DataSet.cs @@ -0,0 +1,122 @@ +/* + * DataSet.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; + +using System.Runtime.InteropServices; + +using IEC61850.Common; + +namespace IEC61850 +{ + namespace Client + { + /// + /// This class is used to represent a data set. It is used to store the values + /// of a data set. + /// + public class DataSet + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientDataSet_destroy (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientDataSet_getValues (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientDataSet_getReference (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int ClientDataSet_getDataSetSize (IntPtr self); + + private IntPtr nativeObject; + private MmsValue values = null; + private string reference = null; + + internal DataSet (IntPtr nativeObject) + { + this.nativeObject = nativeObject; + } + + /// + /// Gets the object reference of the data set + /// + /// + /// object reference. + /// + public string GetReference () + { + if (reference == null) { + IntPtr nativeString = ClientDataSet_getReference (nativeObject); + + reference = Marshal.PtrToStringAnsi (nativeString); + } + + return reference; + } + + /// + /// Gets the values associated with the data set object + /// + /// This function will return the locally stored values associated with the data set. + /// These are the values received by the last request to the server. A call to this method doesn't + /// invoke a request to the server! + /// + /// The locally stored values of the data set (as MmsValue instance of type MMS_ARRAY) + /// + public MmsValue GetValues () + { + if (values == null) { + IntPtr nativeValues = ClientDataSet_getValues (nativeObject); + + values = new MmsValue (nativeValues, false); + } + + return values; + } + + + /// + /// Gets the number of elements of the data set + /// + /// + /// the number of elementes (data set members) + /// + public int GetSize () + { + return ClientDataSet_getDataSetSize (nativeObject); + } + + ~DataSet () + { + ClientDataSet_destroy (nativeObject); + } + + internal IntPtr getNativeInstance () + { + return nativeObject; + } + } + + } + +} diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs new file mode 100644 index 0000000..3c58197 --- /dev/null +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -0,0 +1,1414 @@ +/* + * IEC61850ClientAPI.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; +using System.Text; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Collections; + +using IEC61850.Common; + +/// +/// IEC 61850 API for the libiec61850 .NET wrapper library +/// +namespace IEC61850 +{ + /// + /// IEC 61850 client API. + /// + namespace Client + { + + [StructLayout(LayoutKind.Sequential)] + public class MmsServerIdentity + { + public string vendorName; + public string modelName; + public string revision; + } + + public class MmsConnection + { + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern IntPtr MmsConnection_create(); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern void MmsConnection_destroy(IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern IntPtr MmsConnection_identify(IntPtr self, out int mmsError); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern void MmsServerIdentity_destroy(IntPtr self); + + private IntPtr self = IntPtr.Zero; + private bool selfDestroy = false; + + public MmsConnection() { + selfDestroy = true; + + self = MmsConnection_create(); + } + + internal MmsConnection(IntPtr mmsConnection) { + self = mmsConnection; + } + + ~MmsConnection () + { + if (selfDestroy) + if (self != IntPtr.Zero) + MmsConnection_destroy(self); + } + + public MmsServerIdentity GetServerIdentity () + { + int mmsError; + + if (self == IntPtr.Zero) { + throw new IedConnectionException("Pointer is Zero!"); + } + + IntPtr identity = MmsConnection_identify(self, out mmsError); + + MmsServerIdentity serverIdentity = (MmsServerIdentity) + Marshal.PtrToStructure(identity, typeof(MmsServerIdentity)); + + MmsServerIdentity_destroy(identity); + + return serverIdentity; + } + + } + + /// + /// This class acts as the entry point for the IEC 61850 client API. It represents a single + /// (MMS) connection to a server. + /// + public partial class IedConnection + { + /************* + * MmsValue + *************/ + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr MmsValue_toString (IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern float MmsValue_toFloat (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool MmsValue_getBoolean (IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern UInt32 MmsValue_getBitStringAsInteger (IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern int MmsValue_getType (IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void MmsValue_delete (IntPtr self); + + /**************** + * IedConnection + ***************/ + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr IedConnection_create (); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_destroy (IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_setConnectTimeout(IntPtr self, UInt32 timeoutInMs); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_connect (IntPtr self, out int error, string hostname, int tcpPort); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_abort (IntPtr self, out int error); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern void IedConnection_release(IntPtr self, out int error); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern void IedConnection_close(IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr IedConnection_readObject (IntPtr self, out int error, string objectReference, int fc); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_writeObject (IntPtr self, out int error, string dataAttributeReference, int fc, IntPtr value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataDirectory (IntPtr self, out int error, string dataReference); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataDirectoryByFC (IntPtr self, out int error, string dataReference, FunctionalConstraint fc); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataDirectoryFC (IntPtr self, out int error, string dataReference); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getLogicalNodeDirectory (IntPtr self, out int error, string logicalNodeReference, int acsiClass); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getServerDirectory (IntPtr self, out int error, bool getFileNames); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_getDeviceModelFromServer(IntPtr self, out int error); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getLogicalDeviceDirectory (IntPtr self, out int error, string logicalDeviceName); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void InternalConnectionClosedHandler (IntPtr parameter,IntPtr Iedconnection); + + public delegate void ConnectionClosedHandler (IedConnection connection); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_installConnectionClosedHandler (IntPtr self, InternalConnectionClosedHandler handler, IntPtr parameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_readDataSetValues (IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_createDataSet (IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_deleteDataSet (IntPtr self, out int error, string dataSetReference); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataSetDirectory(IntPtr self, out int error, string dataSetReference, [MarshalAs(UnmanagedType.I1)] out bool isDeletable); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getMmsConnection (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_deleteFile(IntPtr self, out int error, string fileName); + + /******************** + * FileDirectoryEntry + *********************/ + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void FileDirectoryEntry_destroy(IntPtr self); + + /**************** + * LinkedList + ***************/ + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_getNext (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_getData (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroy (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroyStatic(IntPtr self); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void LinkedListValueDeleteFunction(IntPtr pointer); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_create (); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_add (IntPtr self, IntPtr data); + + private IntPtr connection = IntPtr.Zero; + private InternalConnectionClosedHandler connectionClosedHandler; + private ConnectionClosedHandler userProvidedHandler = null; + + public IedConnection () + { + connection = IedConnection_create (); + } + + /// + /// Releases all resource used by the object. + /// + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After + /// calling , you must release all references to the + /// so the garbage collector can reclaim the memory that the was occupying. + public void Dispose() + { + if (connection != IntPtr.Zero) { + cleanupRCBs (); + + IedConnection_destroy (connection); + + connection = IntPtr.Zero; + } + } + + ~IedConnection () + { + if (connection != IntPtr.Zero) { + cleanupRCBs (); + + IedConnection_destroy (connection); + } + } + + public IsoConnectionParameters GetConnectionParameters () + { + IntPtr mmsConnection = IedConnection_getMmsConnection(connection); + + IntPtr parameters = MmsConnection_getIsoConnectionParameters(mmsConnection); + + return new IsoConnectionParameters(parameters); + } + + private void FreeHGlobaleDeleteFunction (IntPtr pointer) + { + Marshal.FreeHGlobal(pointer); + } + + + private UInt32 connectTimeout = 10000; + + public UInt32 ConnectTimeout { + get { + return connectTimeout; + } + set { + connectTimeout = value; + } + } + + + public MmsConnection GetMmsConnection () + { + IntPtr mmsConnectionPtr = IedConnection_getMmsConnection(connection); + + return new MmsConnection(mmsConnectionPtr); + } + + /// Establish an MMS connection to a server + /// This exception is thrown if there is a connection or service error + public void Connect (string hostname, int tcpPort) + { + int error; + + IedConnection_setConnectTimeout(connection, connectTimeout); + + IedConnection_connect (connection, out error, hostname, tcpPort); + + if (error != 0) + throw new IedConnectionException ("Connect to " + hostname + ":" + tcpPort + " failed", error); + } + + /// Establish an MMS connection to a server. + /// This exception is thrown if there is a connection or service error. + public void Connect (string hostname) + { + Connect (hostname, 102); + } + + /// This exception is thrown if there is a connection or service error + public ControlObject CreateControlObject (string objectReference) + { + ControlObject controlObject = new ControlObject (objectReference, connection, this); + + return controlObject; + } + + public void UpdateDeviceModel() + { + int error; + + IedConnection_getDeviceModelFromServer(connection, out error); + + if (error != 0) + throw new IedConnectionException("UpdateDeviceModel failed", error); + } + + /// This exception is thrown if there is a connection or service error + public List GetServerDirectory (bool fileDirectory = false) + { + int error; + + IntPtr linkedList = IedConnection_getServerDirectory (connection, out error, fileDirectory); + + if (error != 0) + throw new IedConnectionException ("GetDeviceDirectory failed", error); + + List newList = new List (); + + if (fileDirectory == false) { + + IntPtr element = LinkedList_getNext (linkedList); + + while (element != IntPtr.Zero) { + string ld = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (ld); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + } + else { + + IntPtr element = LinkedList_getNext(linkedList); + + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); + + FileDirectoryEntry entry = new FileDirectoryEntry(elementData); + + newList.Add(entry.GetFileName()); + + FileDirectoryEntry_destroy(elementData); + + element = LinkedList_getNext(element); + } + + LinkedList_destroyStatic(linkedList); + } + + return newList; + } + + /// This exception is thrown if there is a connection or service error + public List GetLogicalDeviceDirectory (string logicalDeviceName) + { + int error; + + IntPtr linkedList = IedConnection_getLogicalDeviceDirectory (connection, out error, logicalDeviceName); + + if (error != 0) + throw new IedConnectionException ("GetLogicalDeviceDirectory failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string ln = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (ln); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + + /// Get the directory of a logical node (LN) + /// This function returns the directory contents of a LN. Depending on the provided ACSI class + /// The function returns either data object references, or references of other objects like data sets, + /// report control blocks, ... + /// The object reference of a DO, SDO, or DA. + /// the ACSI class of the requested directory elements. + /// This exception is thrown if there is a connection or service error + public List GetLogicalNodeDirectory (string logicalNodeName, ACSIClass acsiClass) + { + int error; + + IntPtr linkedList = IedConnection_getLogicalNodeDirectory (connection, out error, logicalNodeName, (int)acsiClass); + + if (error != 0) + throw new IedConnectionException ("GetLogicalNodeDirectory failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (dataObject); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + + /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA + /// The object reference of a DO, SDO, or DA. + /// This exception is thrown if there is a connection or service error + public List GetDataDirectory (string dataReference) + { + int error; + + IntPtr linkedList = IedConnection_getDataDirectory (connection, out error, dataReference); + + if (error != 0) + throw new IedConnectionException ("GetDataDirectory failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (dataObject); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + + /// Get the list of attributes with the specified FC of a DO, SDO, or DA + /// The object reference of a DO, SDO, or DA. + /// Functional constraint + /// This exception is thrown if there is a connection or service error + public List GetDataDirectory (string dataReference, FunctionalConstraint fc) + { + int error; + + IntPtr linkedList = IedConnection_getDataDirectoryByFC (connection, out error, dataReference, fc); + + if (error != 0) + throw new IedConnectionException ("GetDataDirectory failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (dataObject); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + + /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA + /// This function is similar to the GetDataDirectory except that the returned element names + /// have the functional contraint (FC) appended. + /// The object reference of a DO, SDO, or DA. + /// This exception is thrown if there is a connection or service error + public List GetDataDirectoryFC (string dataReference) + { + int error; + + IntPtr linkedList = IedConnection_getDataDirectoryFC (connection, out error, dataReference); + + if (error != 0) + throw new IedConnectionException ("GetDataDirectoryFC failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (dataObject); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + + + /// Read the variable specification (type description of a DA or FDCO + /// The object reference of a DA or FCDO. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public MmsVariableSpecification GetVariableSpecification (string objectReference, FunctionalConstraint fc) + { + int error; + + IntPtr varSpecPtr = IedConnection_getVariableSpecification(connection, out error, objectReference, (int) fc); + + if (error != 0) + throw new IedConnectionException ("GetVariableSpecification failed", error); + + return new MmsVariableSpecification(varSpecPtr, true); + } + + private IntPtr readObjectInternal (string objectReference, FunctionalConstraint fc) + { + int error; + + IntPtr mmsValue = IedConnection_readObject (connection, out error, objectReference, (int)fc); + + if (error != 0) + throw new IedConnectionException ("Reading value failed", error); + + if (mmsValue.ToInt32 () == 0) + throw new IedConnectionException ("Variable not found on server", error); + + return mmsValue; + } + + /// Read the value of a data attribute (DA) or functional constraint data object (FCDO). + /// The object reference of a DA or FCDO. + /// The functional constraint (FC) of the object + /// the received value as an MmsValue instance + /// This exception is thrown if there is a connection or service error + public MmsValue ReadValue (String objectReference, FunctionalConstraint fc) + { + var value = readObjectInternal (objectReference, fc); + + return new MmsValue (value, true); + } + + /// Read the value of a basic data attribute (BDA) of type boolean. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// the received boolean value + /// This exception is thrown if there is a connection or service error + public bool ReadBooleanValue (string objectReference, FunctionalConstraint fc) + { + var mmsValue = ReadValue (objectReference, fc); + + if (mmsValue.GetType () == MmsType.MMS_BOOLEAN) + return mmsValue.GetBoolean (); + else + throw new IedConnectionException ("Result is not of type timestamp (MMS_UTC_TIME)", 0); + } + + /// Read the value of a basic data attribute (BDA) of type float. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public float ReadFloatValue (string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternal (objectReference, fc); + + if (MmsValue_getType (mmsValue) != (int)MmsType.MMS_FLOAT) + throw new IedConnectionException ("Result is not of type float", 0); + + float value = MmsValue_toFloat (mmsValue); + + MmsValue_delete (mmsValue); + + return value; + } + + /// Read the value of a basic data attribute (BDA) of type string (VisibleString or MmsString). + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public string ReadStringValue (string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternal (objectReference, fc); + + if (!((MmsValue_getType (mmsValue) == (int)MmsType.MMS_VISIBLE_STRING) || (MmsValue_getType (mmsValue) == (int)MmsType.MMS_STRING))) { + MmsValue_delete (mmsValue); + throw new IedConnectionException ("Result is not of type string", 0); + } + + IntPtr ptr = MmsValue_toString (mmsValue); + + string returnString = Marshal.PtrToStringAnsi (ptr); + + MmsValue_delete (mmsValue); + + return returnString; + } + + /// Read the value of a basic data attribute (BDA) of type quality. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public Quality ReadQualityValue (string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternal (objectReference, fc); + + if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { + int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); + + MmsValue_delete (mmsValue); + return new Quality (bitStringValue); + } else { + MmsValue_delete (mmsValue); + throw new IedConnectionException ("Result is not of type bit string(Quality)", 0); + } + } + + /// Read the value of a basic data attribute (BDA) of type bit string. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public int ReadBitStringValue (string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternal (objectReference, fc); + + if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { + int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); + + MmsValue_delete (mmsValue); + return bitStringValue; + } else { + MmsValue_delete (mmsValue); + throw new IedConnectionException ("Result is not of type bit string", 0); + } + } + + /// Read the value of a basic data attribute (BDA) of type timestamp (MMS_UTC_TIME). + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public UInt64 ReadTimestampValue (string objectReference, FunctionalConstraint fc) + { + var mmsValuePtr = readObjectInternal (objectReference, fc); + + var mmsValue = new MmsValue (mmsValuePtr, true); + + if (mmsValue.GetType () == MmsType.MMS_UTC_TIME) + return mmsValue.GetUtcTimeInMs (); + else + throw new IedConnectionException ("Result is not of type timestamp (MMS_UTC_TIME)", 0); + } + + /// Read the value of a basic data attribute (BDA) of type integer (MMS_INTEGER). + /// This function should also be used if enumerations are beeing read. Because + /// enumerations are mapped to integer types for the MMS mapping + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public Int64 ReadIntegerValue (string objectReference, FunctionalConstraint fc) + { + var mmsValuePtr = readObjectInternal (objectReference, fc); + + var mmsValue = new MmsValue (mmsValuePtr, true); + + if (mmsValue.GetType () == MmsType.MMS_INTEGER) + return mmsValue.ToInt64 (); + else + throw new IedConnectionException ("Result is not of type integer (MMS_INTEGER)", 0); + } + + /// Write the value of a data attribute (DA) or functional constraint data object (FCDO). + /// This function can be used to write simple or complex variables (setpoints, parameters, descriptive values...) + /// of the server. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// MmsValue object representing asimple or complex variable data + /// This exception is thrown if there is a connection or service error + public void WriteValue (string objectReference, FunctionalConstraint fc, MmsValue value) + { + int error; + + IedConnection_writeObject (connection, out error, objectReference, (int)fc, value.valueReference); + + if (error != 0) + throw new IedConnectionException ("Write value failed", error); + } + + /// Read the content of a file directory. + /// The name of the directory. + /// This exception is thrown if there is a connection or service error + public List GetFileDirectory(string directoryName) + { + int error; + + IntPtr fileEntryList = IedConnection_getFileDirectory(connection, out error, directoryName); + + if (error != 0) + throw new IedConnectionException("Reading file directory failed", error); + + List fileDirectory = new List(); + + IntPtr element = LinkedList_getNext(fileEntryList); + + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); + + FileDirectoryEntry entry = new FileDirectoryEntry(elementData); + + fileDirectory.Add(entry); + + FileDirectoryEntry_destroy(elementData); + + element = LinkedList_getNext(element); + } + + LinkedList_destroyStatic(fileEntryList); + + return fileDirectory; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool InternalIedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead); + + private bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + GetFileCallback getFileCallback = (GetFileCallback) handle.Target; + + byte[] bytes = new byte[bytesRead]; + + Marshal.Copy(buffer, bytes, 0, (int) bytesRead); + + return getFileCallback.handler(getFileCallback.parameter, bytes); + } + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 IedConnection_getFile(IntPtr self, out int error, string fileName, InternalIedClientGetFileHandler handler, + IntPtr handlerParameter); + + + public delegate bool GetFileHandler(object parameter, byte[] data); + + private class GetFileCallback + { + public GetFileCallback(GetFileHandler handler, object parameter) + { + this.handler = handler; + this.parameter = parameter; + } + + public GetFileHandler handler; + public object parameter; + } + + /// + /// Download a file from the server. + /// + /// + /// File name of the file (full path) + /// + /// + /// Callback handler that is invoked for each chunk of the file received + /// + /// + /// User provided parameter that is passed to the callback handler + /// + public void GetFile(string fileName, GetFileHandler handler, object parameter) + { + int error; + + GetFileCallback getFileCallback = new GetFileCallback(handler, parameter); + + GCHandle handle = GCHandle.Alloc(getFileCallback); + + IedConnection_getFile(connection, out error, fileName, new InternalIedClientGetFileHandler(iedClientGetFileHandler), + GCHandle.ToIntPtr(handle)); + + if (error != 0) + throw new IedConnectionException("Error reading file", error); + + handle.Free(); + } + + /// + /// Abort (close) the connection. + /// + /// This function will send an abort request to the server. This will immediately interrupt the + /// connection. + /// This exception is thrown if there is a connection or service error + public void Abort () + { + int error; + + IedConnection_abort (connection, out error); + + if (error != 0) + throw new IedConnectionException ("Abort failed", error); + } + + /// + /// Release (close) the connection. + /// + /// This function will send an release request to the server. The function will block until the + /// connection is released or an error occured. + /// This exception is thrown if there is a connection or service error + public void Release () + { + int error; + + IedConnection_release(connection, out error); + + if (error != 0) + throw new IedConnectionException ("Release failed", error); + } + + /// + /// Immediately close the connection. + /// + /// This function will close the connnection to the server by closing the TCP connection. + /// The client will not send an abort or release request as required by the specification! + /// This exception is thrown if there is a connection or service error + public void Close () + { + IedConnection_close(connection); + } + + private void MyConnectionClosedHandler (IntPtr parameter, IntPtr self) + { + if (userProvidedHandler != null) + userProvidedHandler (this); + } + + /// + /// Install a callback handler that will be invoked if the connection is closed. + /// + /// The handler is called when the connection is closed no matter if the connection was closed + /// by the client or by the server. Any new call to this function will replace the callback handler installed + /// by a prior function call. + /// The user provided callback handler + /// This exception is thrown if there is a connection or service error + public void InstallConnectionClosedHandler (ConnectionClosedHandler handler) + { + connectionClosedHandler = new InternalConnectionClosedHandler (MyConnectionClosedHandler); + + userProvidedHandler = handler; + + IedConnection_installConnectionClosedHandler (connection, connectionClosedHandler, connection); + } + + /// + /// Read the values of a data set (GetDataSetValues service). + /// + /// This function will invoke a readDataSetValues service and return a new DataSet value containing the + /// received values. + /// The object reference of the data set + + /// This exception is thrown if there is a connection or service error + public DataSet GetDataSetValues (string dataSetReference) + { + return ReadDataSetValues(dataSetReference, null); + } + + /// + /// Read the values of a data set (GetDataSetValues service). + /// + /// This function will invoke a readDataSetValues service and return a new DataSet value containing the + /// received values. If an existing instance of DataSet is provided to the function the existing instance will be + /// updated by the new values. + /// The object reference of the data set + /// The object reference of an existing data set instance or null + /// a DataSet instance containing the received values + /// This exception is thrown if there is a connection or service error + public DataSet ReadDataSetValues (string dataSetReference, DataSet dataSet) + { + IntPtr nativeClientDataSet = IntPtr.Zero; + + if (dataSet != null) + nativeClientDataSet = dataSet.getNativeInstance (); + + int error; + + nativeClientDataSet = IedConnection_readDataSetValues (connection, out error, dataSetReference, nativeClientDataSet); + + if (error != 0) + throw new IedConnectionException ("Reading data set failed", error); + + if (dataSet == null) + dataSet = new DataSet (nativeClientDataSet); + + return dataSet; + } + + /// + /// Create a new data set. + /// + /// This function creates a new data set at the server. The data set consists of the members defined + /// by the list of object references provided. + /// The object reference of the data set + /// A list of object references of the data set elements + /// This exception is thrown if there is a connection or service error + public void CreateDataSet (string dataSetReference, List dataSetElements) + { + IntPtr linkedList = LinkedList_create (); + + foreach (string dataSetElement in dataSetElements) { + IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi (dataSetElement); + + LinkedList_add (linkedList, handle); + } + + int error; + + IedConnection_createDataSet (connection, out error, dataSetReference, linkedList); + + LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction)); + + if (error != 0) + throw new IedConnectionException ("Failed to create data set", error); + + } + + /// + /// Delete a data set. + /// + /// This function will delete a data set at the server. This function may fail if the data set is not + /// deletable. + /// The object reference of the data set + /// This exception is thrown if there is a connection or service error + public void DeleteDataSet (string dataSetReference) + { + int error; + + IedConnection_deleteDataSet (connection, out error, dataSetReference); + + if (error != 0) + throw new IedConnectionException ("Failed to delete data set", error); + } + + /// + /// Get the directory of the data set. + /// + /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents. + /// The object reference of the data set + /// the list of object references + /// This exception is thrown if there is a connection or service error + public List GetDataSetDirectory(string dataSetReference) + { + bool isDeletable; + + return GetDataSetDirectory(dataSetReference, out isDeletable); + } + + /// + /// Get the directory of the data set. + /// + /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents. + /// The object reference of the data set + /// Indication if this data set is permanent or deletable. + /// the list of object references + /// This exception is thrown if there is a connection or service error + public List GetDataSetDirectory (string dataSetReference, out bool isDeletable) + { + int error; + + IntPtr linkedList = IedConnection_getDataSetDirectory (connection, out error, dataSetReference, out isDeletable); + + if (error != 0) + throw new IedConnectionException ("getDataSetDirectory failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (dataObject); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + } + + public class IedConnectionException : Exception + { + + private int errorCode; + + public IedConnectionException (string message, int errorCode) : base(message) + { + this.errorCode = errorCode; + } + + public IedConnectionException (string message) : base(message) + { + this.errorCode = 0; + } + + public int GetErrorCode () + { + return this.errorCode; + } + + public IedClientError GetIedClientError () + { + return (IedClientError)this.errorCode; + } + } + + public class FileDirectoryEntry + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr FileDirectoryEntry_getFileName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 FileDirectoryEntry_getFileSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt64 FileDirectoryEntry_getLastModified(IntPtr self); + + private string fileName; + private UInt32 fileSize; + private UInt64 lastModified; + + internal FileDirectoryEntry(IntPtr nativeFileDirectoryEntry) + { + fileName = Marshal.PtrToStringAnsi(FileDirectoryEntry_getFileName(nativeFileDirectoryEntry)); + fileSize = FileDirectoryEntry_getFileSize(nativeFileDirectoryEntry); + lastModified = FileDirectoryEntry_getLastModified(nativeFileDirectoryEntry); + } + + public string GetFileName() + { + return fileName; + } + + public UInt32 GetFileSize() + { + return fileSize; + } + + public UInt64 GetLastModified() + { + return lastModified; + } + } + + public enum IedClientError + { + /* general errors */ + + /** No error occurred - service request has been successful */ + IED_ERROR_OK = 0, + + /** The service request can not be executed because the client is not yet connected */ + IED_ERROR_NOT_CONNECTED = 1, + + /** Connect service not execute because the client is already connected */ + IED_ERROR_ALREADY_CONNECTED = 2, + + /** The service request can not be executed caused by a loss of connection */ + IED_ERROR_CONNECTION_LOST = 3, + + /** The service or some given parameters are not supported by the client stack or by the server */ + IED_ERROR_SERVICE_NOT_SUPPORTED = 4, + + /** Connection rejected by server */ + IED_ERROR_CONNECTION_REJECTED = 5, + + /* client side errors */ + + /** API function has been called with an invalid argument */ + IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT = 10, + + IED_ERROR_ENABLE_REPORT_FAILED_DATASET_MISMATCH = 11, + + /** The object provided object reference is invalid (there is a syntactical error). */ + IED_ERROR_OBJECT_REFERENCE_INVALID = 12, + + /** Received object is of unexpected type */ + IED_ERROR_UNEXPECTED_VALUE_RECEIVED = 13, + + /* service error - error reported by server */ + + /** The communication to the server failed with a timeout */ + IED_ERROR_TIMEOUT = 20, + + /** The server rejected the access to the requested object/service due to access control */ + IED_ERROR_ACCESS_DENIED = 21, + + /** The server reported that the requested object does not exist */ + IED_ERROR_OBJECT_DOES_NOT_EXIST = 22, + + /** The server reported that the requested object already exists */ + IED_ERROR_OBJECT_EXISTS = 23, + + /** The server does not support the requested access method */ + IED_ERROR_OBJECT_ACCESS_UNSUPPORTED = 24, + + /** The server expected an object of another type */ + IED_ERROR_TYPE_INCONSISTENT = 25, + + /** The object or service is temporarily unavailable */ + IED_ERROR_TEMPORARILY_UNAVAILABLE = 26, + + /** The specified object is not defined in the server (returned by server) */ + IED_ERROR_OBJECT_UNDEFINED = 27, + + /** The specified address is invalid (returned by server) */ + IED_ERROR_INVALID_ADDRESS = 28, + + /** Service failed due to a hardware fault (returned by server) */ + IED_ERROR_HARDWARE_FAULT = 29, + + /** The requested data type is not supported by the server (returned by server) */ + IED_ERROR_TYPE_UNSUPPORTED = 30, + + /** The provided attributes are inconsistent (returned by server) */ + IED_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT = 31, + + /** The provided object value is invalid (returned by server) */ + IED_ERROR_OBJECT_VALUE_INVALID = 32, + + /** The object is invalidated (returned by server) */ + IED_ERROR_OBJECT_INVALIDATED = 33, + + /* unknown error */ + IED_ERROR_UNKNOWN = 99 + } + } + + namespace Common + { + + [Flags] + public enum TriggerOptions { + NONE = 0, + /** send report when value of data changed */ + DATA_CHANGED = 1, + /** send report when quality of data changed */ + QUALITY_CHANGED = 2, + /** send report when data or quality is updated */ + DATA_UPDATE = 4, + /** periodic transmission of all data set values */ + INTEGRITY = 8, + /** general interrogation (on client request) */ + GI = 16 + } + + [Flags] + public enum ReportOptions { + NONE = 0, + SEQ_NUM = 1, + TIME_STAMP = 2, + REASON_FOR_INCLUSION = 4, + DATA_SET = 8, + DATA_REFERENCE = 16, + BUFFER_OVERFLOW = 32, + ENTRY_ID = 64, + CONF_REV = 128 + } + + public enum Validity + { + GOOD = 0, + INVALID = 1, + RESERVED = 2, + QUESTIONABLE = 3 + } + + /// + /// The quality of a data object. + /// + public class Quality + { + + private UInt16 value; + + public Quality (int bitStringValue) + { + value = (UInt16)bitStringValue; + } + + public Quality () + { + value = 0; + } + + public Validity GetValidity () + { + int qualityVal = value & 0x3; + + return (Validity)qualityVal; + } + + public void SetValidity (Validity validity) + { + value = (UInt16)(value & 0xfffc); + + value += (ushort)validity; + } + } + + public enum ACSIClass + { + /** data objects */ + ACSI_CLASS_DATA_OBJECT, + /** data sets (container for multiple data objects) */ + ACSI_CLASS_DATA_SET, + /** buffered report control blocks */ + ACSI_CLASS_BRCB, + /** unbuffered report control blocks */ + ACSI_CLASS_URCB, + /** log control blocks */ + ACSI_CLASS_LCB, + /** logs (journals) */ + ACSI_CLASS_LOG, + /** setting group control blocks */ + ACSI_CLASS_SGCB, + /** GOOSE control blocks */ + ACSI_CLASS_GoCB, + /** GSE control blocks */ + ACSI_CLASS_GsCB, + /** multicast sampled values control blocks */ + ACSI_CLASS_MSVCB, + /** unicast sampled values control blocks */ + ACSI_CLASS_USVCB + } + + public enum FunctionalConstraint + { + /** Status information */ + ST = 0, + /** Measurands - analog values */ + MX = 1, + /** Setpoint */ + SP = 2, + /** Substitution */ + SV = 3, + /** Configuration */ + CF = 4, + /** Description */ + DC = 5, + /** Setting group */ + SG = 6, + /** Setting group editable */ + SE = 7, + /** Service response / Service tracking */ + SR = 8, + /** Operate received */ + OR = 9, + /** Blocking */ + BL = 10, + /** Extended definition */ + EX = 11, + /** Control */ + CO = 12, + ALL = 99, + NONE = -1 + } + + public enum ControlAddCause { + ADD_CAUSE_UNKNOWN = 0, + ADD_CAUSE_NOT_SUPPORTED = 1, + ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2, + ADD_CAUSE_SELECT_FAILED = 3, + ADD_CAUSE_INVALID_POSITION = 4, + ADD_CAUSE_POSITION_REACHED = 5, + ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6, + ADD_CAUSE_STEP_LIMIT = 7, + ADD_CAUSE_BLOCKED_BY_MODE = 8, + ADD_CAUSE_BLOCKED_BY_PROCESS = 9, + ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10, + ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11, + ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12, + ADD_CAUSE_BLOCKED_BY_HEALTH = 13, + ADD_CAUSE_1_OF_N_CONTROL = 14, + ADD_CAUSE_ABORTION_BY_CANCEL = 15, + ADD_CAUSE_TIME_LIMIT_OVER = 16, + ADD_CAUSE_ABORTION_BY_TRIP = 17, + ADD_CAUSE_OBJECT_NOT_SELECTED = 18, + ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19, + ADD_CAUSE_NO_ACCESS_AUTHORITY = 20, + ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21, + ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22, + ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23, + ADD_CAUSE_ABORTION_BY_COMMAND = 24, + ADD_CAUSE_NONE = 25, + ADD_CAUSE_INCONSISTENT_PARAMETERS = 26, + ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27 + } + + /// + /// Object reference. Helper function to handle object reference strings. + /// + public static class ObjectReference { + + /// + /// Get the name part of an object reference with appended FC + /// + /// + /// The element name. + /// + /// + /// Object reference with appended fc. + /// + public static string getElementName (string objectReferenceWithFc) + { + int fcPartStartIndex = objectReferenceWithFc.IndexOf('['); + + if (fcPartStartIndex == -1) + return objectReferenceWithFc; + + return objectReferenceWithFc.Substring(0, fcPartStartIndex); + } + + /// + /// Get the FC of an object reference with appended FC. + /// + /// + /// The FC + /// + /// + /// Object reference with FC. + /// + public static FunctionalConstraint getFC (string objectReferenceWithFc) + { + int fcPartStartIndex = objectReferenceWithFc.IndexOf('['); + + if (fcPartStartIndex == -1) + return FunctionalConstraint.NONE; + + string fcString = objectReferenceWithFc.Substring(fcPartStartIndex + 1 , 2); + + try + { + return (FunctionalConstraint) Enum.Parse(typeof(FunctionalConstraint), fcString); + } + catch(ArgumentException) + { + return FunctionalConstraint.NONE; + } + } + } + + } +} diff --git a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj new file mode 100644 index 0000000..d5d09da --- /dev/null +++ b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj @@ -0,0 +1,50 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C35D624E-5506-4560-8074-1728F1FA1A4D} + Library + iec61850dotnet + iec61850dotnet + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + none + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs b/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs new file mode 100644 index 0000000..342dbc3 --- /dev/null +++ b/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs @@ -0,0 +1,203 @@ +/* + * IsoConnectionParameters.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +using System; +using System.Runtime.InteropServices; + +namespace IEC61850 +{ + namespace Client + { + + public enum AcseAuthenticationMechanism { + /** don't use authentication */ + ACSE_AUTH_NONE = 0, + /** use password authentication */ + ACSE_AUTH_PASSWORD = 1 + } + + /// + /// Connection parameters associated with the ISO protocol layers (transport, session, presentation, ACSE) + /// + public class IsoConnectionParameters + { + + [StructLayout(LayoutKind.Sequential)] + private struct NativeTSelector + { + public byte size; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] public byte[] value; + } + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IsoConnectionParameters_destroy(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IsoConnectionParameters_setRemoteApTitle(IntPtr self, string apTitle, int aeQualifier); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IsoConnectionParameters_setRemoteAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, NativeTSelector tSelector); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IsoConnectionParameters_setLocalApTitle(IntPtr self, string apTitle, int aeQualifier); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IsoConnectionParameters_setLocalAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, NativeTSelector tSelector); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IsoConnectionParameters_setAcseAuthenticationParameter(IntPtr self, IntPtr acseAuthParameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr AcseAuthenticationParameter_create(); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void AcseAuthenticationParameter_destroy(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void AcseAuthenticationParameter_setAuthMechanism(IntPtr self, int mechanism); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void AcseAuthenticationParameter_setPassword(IntPtr self, string password); + + private IntPtr self; + + private IntPtr authParameter = IntPtr.Zero; + + internal IsoConnectionParameters (IntPtr self) + { + this.self = self; + } + + ~IsoConnectionParameters () + { + if (authParameter != IntPtr.Zero) + AcseAuthenticationParameter_destroy(authParameter); + + //IsoConnectionParameters_destroy(self); + } + + /// + /// Sets the remote ap title related parameters + /// + /// + /// remote AP title. + /// + /// + /// remote AE qualifier. + /// + public void SetRemoteApTitle(string apTitle, int aeQualifier) + { + IsoConnectionParameters_setRemoteApTitle(self, apTitle, aeQualifier); + } + + /// + /// Sets the remote addresses for ISO layers (transport, session, presentation) + /// + /// + /// presentation layer address + /// + /// + /// session layer address + /// + /// + /// ISO COTP transport layer address + /// + public void SetRemoteAddresses (UInt32 pSelector, UInt16 sSelector, byte[] tSelector) + { + if (tSelector.Length > 4) + throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded"); + + NativeTSelector nativeTSelector; + nativeTSelector.size = (byte) tSelector.Length; + nativeTSelector.value = new byte[4]; + + for (int i = 0; i < tSelector.Length; i++) + nativeTSelector.value[i] = tSelector[i]; + + IsoConnectionParameters_setRemoteAddresses(self, pSelector, sSelector, nativeTSelector); + } + + /// + /// Sets the local ap title related parameters + /// + /// + /// local AP title. + /// + /// + /// local AE qualifier. + /// + public void SetLocalApTitle (string apTitle, int aeQualifier) + { + IsoConnectionParameters_setLocalApTitle(self, apTitle, aeQualifier); + } + + /// + /// Sets the local addresses for ISO layers (transport, session, presentation) + /// + /// + /// presentation layer address + /// + /// + /// session layer address + /// + /// + /// ISO COTP transport layer address + /// + public void SetLocalAddresses (UInt32 pSelector, UInt16 sSelector, byte[] tSelector) + { + if (tSelector.Length > 4) + throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded"); + + NativeTSelector nativeTSelector; + nativeTSelector.size = (byte) tSelector.Length; + nativeTSelector.value = new byte[4]; + + for (int i = 0; i < tSelector.Length; i++) + nativeTSelector.value[i] = tSelector[i]; + + IsoConnectionParameters_setLocalAddresses(self, pSelector, sSelector, nativeTSelector); + } + + /// + /// Instruct ACSE layer to use password authentication. + /// + /// + /// Password that will be used to authenticate the client + /// + public void UsePasswordAuthentication (string password) + { + if (authParameter == IntPtr.Zero) { + authParameter = AcseAuthenticationParameter_create (); + AcseAuthenticationParameter_setAuthMechanism (authParameter, (int)AcseAuthenticationMechanism.ACSE_AUTH_PASSWORD); + AcseAuthenticationParameter_setPassword (authParameter, password); + IsoConnectionParameters_setAcseAuthenticationParameter(self, authParameter); + } + else + throw new IedConnectionException("Authentication parameter already set"); + } + } + + } +} + diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs new file mode 100644 index 0000000..3f69b7b --- /dev/null +++ b/dotnet/IEC61850forCSharp/MmsValue.cs @@ -0,0 +1,726 @@ +/* + * MmsValue.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; + +using System.Runtime.InteropServices; +using System.Collections.Generic; + +using System.Collections; +using System.Text; + +namespace IEC61850 +{ + namespace Common + { + + /// + /// This class is used to hold MMS data values of different types. + /// + public class MmsValue : IEnumerable + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_toString (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern float MmsValue_toFloat (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern double MmsValue_toDouble (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool MmsValue_getBoolean (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 MmsValue_getBitStringAsInteger (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_setBitStringFromInteger(IntPtr self, UInt32 intValue); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsValue_getBitStringSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_setBitStringBit(IntPtr self, int bitPos, bool value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool MmsValue_getBitStringBit(IntPtr self, int bitPos); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern Int32 MmsValue_toInt32 (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern Int64 MmsValue_toInt64 (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 MmsValue_toUint32 (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsValue_getType (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_delete (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_getElement (IntPtr complexValue, int index); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsValue_getArraySize (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern ulong MmsValue_getUtcTimeInMs (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern ulong MmsValue_getUtcTimeInMsWithUs(IntPtr self, [Out] uint usec); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 MmsValue_toUnixTimestamp (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newBoolean (bool value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newFloat (float value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newDouble (double value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newIntegerFromInt32 (Int32 integer); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newUnsignedFromUint32(UInt32 integer); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newIntegerFromInt64 (Int64 integer); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newBitString(int bitSize); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newVisibleString(string value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newOctetString(int size, int maxSize); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_setOctetString(IntPtr self, [Out] byte[] buf, int size); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 MmsValue_getOctetStringSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 MmsValue_getOctetStringMaxSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_getOctetStringBuffer(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool MmsValue_equals(IntPtr self, IntPtr otherValue); + + + internal MmsValue (IntPtr value) + { + valueReference = value; + this.responsableForDeletion = false; + } + + internal MmsValue (IntPtr value, bool responsableForDeletion) + { + valueReference = value; + this.responsableForDeletion = responsableForDeletion; + } + + public MmsValue (bool value) + { + valueReference = MmsValue_newBoolean (value); + } + + public MmsValue (float value) + { + valueReference = MmsValue_newFloat (value); + } + + public MmsValue (double value) + { + valueReference = MmsValue_newDouble (value); + } + + public MmsValue (int value) + { + valueReference = MmsValue_newIntegerFromInt32 (value); + } + + public MmsValue (UInt32 value) + { + valueReference = MmsValue_newUnsignedFromUint32(value); + } + + public MmsValue (long value) + { + valueReference = MmsValue_newIntegerFromInt64 (value); + } + + public MmsValue (string value) + { + valueReference = MmsValue_newVisibleString(value); + } + + ~MmsValue () + { + if (responsableForDeletion) + MmsValue_delete (valueReference); + } + + /// + /// Create a new MmsValue instance of type MMS_BIT_STRING. + /// + /// + /// the new MmsValue instance + /// + /// + /// the size of the bit string in bits. + /// + public static MmsValue NewBitString(int bitSize) + { + IntPtr newValue = MmsValue_newBitString(bitSize); + + return new MmsValue(newValue, true); + } + + /// + /// Create a new MmsValue instance of type MMS_OCTET_STRING. + /// + /// + /// the new MmsValue instance + /// + /// + /// the maximum size of the octet string in bytes + /// + /// + /// the current size of the octet string in bytes (defaults to 0) + /// + public static MmsValue NewOctetString (int maxSize, int size = 0) + { + IntPtr newValue = MmsValue_newOctetString(size, maxSize); + + return new MmsValue(newValue, true); + } + + internal IntPtr valueReference; + private bool responsableForDeletion; + + /// + /// Gets the type of the value + /// + /// + /// The type. + /// + public new MmsType GetType () + { + return (MmsType)MmsValue_getType (valueReference); + } + + /// + /// Gets the size of an array, structure, or bit string + /// + /// + /// + /// Return the size of an array of structure (number of elements) + /// The value has to be of type MMS_ARRAY, MMS_STRUCTURE, MMS_BIT_STRING ... + /// + /// the number of elements (array/structure elements, octets, bits depending on type) + /// + /// This exception is thrown if the value has the wrong type. + public int Size () + { + if ((GetType () == MmsType.MMS_ARRAY) || (GetType () == MmsType.MMS_STRUCTURE)) { + return MmsValue_getArraySize (valueReference); + } else if (GetType () == MmsType.MMS_BIT_STRING) { + return MmsValue_getBitStringSize(valueReference); + } + else if (GetType () == MmsType.MMS_OCTET_STRING) { + return MmsValue_getOctetStringSize(valueReference); + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + /// + /// Gets the maximum size of an octet string + /// + /// + /// The maximum size (in bytes) of the octet string + /// + public int MaxSize () + { + if (GetType () == MmsType.MMS_OCTET_STRING) { + return MmsValue_getOctetStringMaxSize(valueReference); + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + /// + /// Gets the octet string as byte array + /// + /// Instance has to be of type MMS_OCTET_STRING. + /// + /// + /// Byte array containing the bytes of the octet string. + /// + /// This exception is thrown if the value has the wrong type. + public byte[] getOctetString () + { + if (GetType () == MmsType.MMS_OCTET_STRING) { + IntPtr buffer = MmsValue_getOctetStringBuffer(valueReference); + int bufferSize = this.Size(); + + byte[] octetString = new byte[bufferSize]; + + Marshal.Copy(buffer, octetString, 0, bufferSize); + + return octetString; + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + public void setOctetString (byte[] octetString) + { + if (GetType () == MmsType.MMS_OCTET_STRING) { + + if (this.MaxSize() < octetString.Length) + throw new MmsValueException("octet string is to large"); + + MmsValue_setOctetString(valueReference, octetString, octetString.Length); + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + /// + /// Get an element of an array or structure + /// + /// + /// the MmsValue element. + /// + /// + /// index of the element starting with 0 + /// + /// This exception is thrown if the value has the wrong type. + /// This exception is thrown if the index is out of range. + public MmsValue GetElement (int index) + { + MmsType type = GetType (); + + if ((type == MmsType.MMS_ARRAY) || (type == MmsType.MMS_STRUCTURE)) { + if ((index >= 0) && (index < Size ())) { + IntPtr value = MmsValue_getElement (valueReference, index); + + if (value == IntPtr.Zero) + return null; + else + return new MmsValue (value); + } else + throw new MmsValueException ("Index out of bounds"); + } else + throw new MmsValueException ("Value is of wrong type"); + } + + /// + /// Gets the timestamp value as UTC time in s (UNIX time stamp). + /// + /// + /// Return the value as seconds since epoch (1.1.1970 UTC). + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// The UTC time in seconds (UNIX time stamp). + /// + /// This exception is thrown if the value has the wrong type. + public UInt32 ToUnixTimestamp () + { + if (GetType () == MmsType.MMS_UTC_TIME) + return MmsValue_toUnixTimestamp (valueReference); + else + throw new MmsValueException ("Value is not a time type"); + } + + /// + /// Gets the timestamp value as UTC time in ms. + /// + /// + /// Return the value as milliseconds since epoch (1.1.1970 UTC). + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// The UTC time in ms. + /// + /// This exception is thrown if the value has the wrong type. + public ulong GetUtcTimeInMs () + { + if (GetType () == MmsType.MMS_UTC_TIME) { + return MmsValue_getUtcTimeInMs (valueReference); + } else + throw new MmsValueException ("Value is not a time type"); + } + + /// + /// Gets the timestamp value as UTC time in ms and the additional us part. + /// + /// + /// Return the value as milliseconds since epoch (1.1.1970 UTC) and the additional us part. + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// returns the usec part of the time value + /// + /// + /// The UTC time in ms. + /// + /// This exception is thrown if the value has the wrong type. + public ulong GetUtcTimeInMsWithUs(out int usec) + { + if (GetType() == MmsType.MMS_UTC_TIME) + { + uint uusec = 0; + var msVal = MmsValue_getUtcTimeInMsWithUs(valueReference, uusec); + usec = (int)uusec; + return msVal; + } + else + throw new MmsValueException("Value is not a time type"); + } + + /// + /// Convert a millisecond time (milliseconds since epoch) to DataTimeOffset + /// + /// + /// The time as DataTimeOffset + /// + /// + /// the millisecond time + /// + public static DateTimeOffset MsTimeToDateTimeOffset (UInt64 msTime) + { + DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + + return retVal.AddMilliseconds ((double) msTime); + } + + /// + /// Convert MMS_UTC_TIME to DateTimeOffset instance + /// + /// + /// Return the value as DateTimeOffset instance. + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// the value as DataTimeOffset instance + /// + /// This exception is thrown if the value has the wrong type. + public DateTimeOffset GetUtcTimeAsDateTimeOffset () + { + if (GetType () == MmsType.MMS_UTC_TIME) + return MsTimeToDateTimeOffset (GetUtcTimeInMs ()); + else + throw new MmsValueException ("Value is not a time type"); + } + + + /// + /// Return the value as 32 bit signed integer. + /// + /// + /// Return the value as 32 bit signed integer (Int32). + /// The value has to be of type MMS_INTEGER. + /// + /// + /// the value if the object as 32 bit signed integer + /// + /// This exception is thrown if the value has the wrong type. + public Int32 ToInt32 () + { + if (GetType () != MmsType.MMS_INTEGER) + throw new MmsValueException ("Value type is not integer"); + + return MmsValue_toInt32 (valueReference); + } + + /// + /// Return the value as 64 bit signed integer. + /// + /// + /// Return the value as 64 bit signed integer (Int64). + /// The value has to be of type MMS_INTEGER. + /// + /// + /// the value if the object as 64 bit signed integer + /// + /// This exception is thrown if the value has the wrong type. + public Int64 ToInt64 () + { + if (GetType () != MmsType.MMS_INTEGER) + throw new MmsValueException ("Value type is not integer"); + + return MmsValue_toInt64 (valueReference); + } + + /// + /// Return the value as 32 bit unsigned integer. + /// + /// + /// Return the value as 32 bit unsigned integer (Int32). + /// The value has to be of type MMS_INTEGER. + /// + /// + /// the value if the object as 32 bit unsigned integer + /// + /// This exception is thrown if the value has the wrong type. + public UInt32 ToUint32 () + { + if (GetType () != MmsType.MMS_UNSIGNED) + throw new MmsValueException ("Value type is not unsigned"); + + return MmsValue_toUint32 (valueReference); + } + + public UInt32 BitStringToUInt32 () + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + return MmsValue_getBitStringAsInteger(valueReference); + } + + public void BitStringFromUInt32 (UInt32 intValue) + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + MmsValue_setBitStringFromInteger(valueReference, intValue); + } + + public void SetBit (int bitPos, bool bitValue) + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + MmsValue_setBitStringBit(valueReference, bitPos, bitValue); + } + + public bool GetBit (int bitPos) + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + return MmsValue_getBitStringBit(valueReference, bitPos); + } + + private string GetBitStringAsString() + { + if (GetType() != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + int size = Size(); + + StringBuilder builder = new StringBuilder(size); + + for (int i = 0; i < size; i++) + { + if (MmsValue_getBitStringBit(valueReference, i)) + builder.Append('1'); + else + builder.Append('0'); + } + + return builder.ToString(); + } + + /// + /// Gets the boolean value + /// + /// + /// The boolean value + /// + /// This exception is thrown if the value has the wrong type. + public bool GetBoolean () + { + if (GetType () == MmsType.MMS_BOOLEAN) + return MmsValue_getBoolean (valueReference); + else + throw new MmsValueException ("Value type is not boolean"); + } + + /// + /// Gets the float value of an MMS_FLOAT instance + /// + /// + /// The float value + /// + /// This exception is thrown if the value has the wrong type. + public float ToFloat () + { + if (GetType () == MmsType.MMS_FLOAT) + return MmsValue_toFloat (valueReference); + else + throw new MmsValueException ("Value type is not float"); + } + + /// + /// Gets the double value of an MMS_FLOAT instance + /// + /// + /// The float value + /// + /// This exception is thrown if the value has the wrong type. + public double ToDouble () + { + if (GetType () == MmsType.MMS_FLOAT) + return MmsValue_toDouble (valueReference); + else + throw new MmsValueException ("Value type is not float"); + } + + public override bool Equals (object obj) + { + MmsValue otherValue = (MmsValue) obj; + + return MmsValue_equals(this.valueReference, otherValue.valueReference); + } + + // override standard ToString() method + public override string ToString () + { + switch (GetType ()) { + case MmsType.MMS_VISIBLE_STRING: + case MmsType.MMS_STRING: + return Marshal.PtrToStringAnsi (MmsValue_toString (valueReference)); + case MmsType.MMS_BOOLEAN: + return GetBoolean ().ToString (); + case MmsType.MMS_INTEGER: + return ToInt64 ().ToString (); + case MmsType.MMS_UNSIGNED: + return ToUint32 ().ToString (); + case MmsType.MMS_FLOAT: + return ToDouble ().ToString (); + case MmsType.MMS_UTC_TIME: + return GetUtcTimeAsDateTimeOffset ().ToString (); + case MmsType.MMS_BIT_STRING: + return GetBitStringAsString(); + default: + return "unknown"; + } + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new MmsValueEnumerator (this); + } + + private class MmsValueEnumerator : IEnumerator + { + private MmsValue value; + private int index = -1; + + public MmsValueEnumerator (MmsValue value) + { + this.value = value; + } + + #region IEnumerator Members + public void Reset () + { + index = -1; + } + + public object Current { + + get { return value.GetElement (index);} + } + + public bool MoveNext () + { + index++; + + if (index >= value.Size ()) + return false; + else + return true; + } + + #endregion + } + + } + + public class MmsValueException : Exception + { + public MmsValueException (string message) + : base(message) + { + } + } + + public enum MmsType + { + /** array type (multiple elements of the same type) */ + MMS_ARRAY = 0, + /** structure type (multiple elements of different types) */ + MMS_STRUCTURE = 1, + /** boolean */ + MMS_BOOLEAN = 2, + /** bit string */ + MMS_BIT_STRING = 3, + /** signed integer */ + MMS_INTEGER = 4, + /** unsigned integer */ + MMS_UNSIGNED = 5, + /** floating point value (32 or 64 bit) */ + MMS_FLOAT = 6, + /** octet string */ + MMS_OCTET_STRING = 7, + /** visible string - ANSI string */ + MMS_VISIBLE_STRING = 8, + /** Generalized time */ + MMS_GENERALIZED_TIME = 9, + /** Binary time */ + MMS_BINARY_TIME = 10, + /** Binary coded decimal (BCD) - not used */ + MMS_BCD = 11, + /** object ID - not used */ + MMS_OBJ_ID = 12, + /** Unicode string */ + MMS_STRING = 13, + /** UTC time */ + MMS_UTC_TIME = 14, + /** will be returned in case of an error (contains error code) */ + MMS_DATA_ACCESS_ERROR = 15 + } + + } +} + diff --git a/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs b/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs new file mode 100644 index 0000000..159f10e --- /dev/null +++ b/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs @@ -0,0 +1,201 @@ +/* + * MmsVariableSpecification.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; + +using System.Runtime.InteropServices; +using System.Collections.Generic; + +using System.Collections; + +namespace IEC61850 +{ + namespace Common + { + /// + /// MMS variable specification. This class is used to represent an MMS variable type definition. + /// + public class MmsVariableSpecification : IEnumerable + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsVariableSpecification_destroy(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getChildValue(IntPtr self, IntPtr value, string childId); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getNamedVariableRecursive(IntPtr variable, string nameId); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsVariableSpecification_getType(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsVariableSpecification_getSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getChildSpecificationByIndex(IntPtr self, int index); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getArrayElementSpecification(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsVariableSpecification_getExponentWidth(IntPtr self); + + private IntPtr self; + private bool responsableForDeletion; + + internal MmsVariableSpecification (IntPtr self) + { + this.self = self; + this.responsableForDeletion = false; + } + + internal MmsVariableSpecification (IntPtr self, bool responsableForDeletion) + { + this.self = self; + this.responsableForDeletion = responsableForDeletion; + } + + ~MmsVariableSpecification () + { + if (responsableForDeletion) + MmsVariableSpecification_destroy(self); + } + + /// + /// Gets the MmsValue type of the variable + /// + /// + /// The MmsType of the variable + /// + public new MmsType GetType () + { + return (MmsType) MmsVariableSpecification_getType(self); + } + + /// + /// Gets the type of the array elements. + /// + /// + /// The array element type. + /// + /// This exception is thrown if the value is not of type MMS_ARRAY + public MmsVariableSpecification getArrayElementType () + { + if (GetType() == MmsType.MMS_ARRAY) { + IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self); + return new MmsVariableSpecification(varSpecPtr); + } + else + throw new MmsValueException ("specification is of wrong type"); + } + + /// + /// Gets the element specification of a structure element + /// + /// + /// The element of the structure at given index + /// + /// + /// Index. + /// + public MmsVariableSpecification GetElement (int index) + { + if (GetType () == MmsType.MMS_STRUCTURE) { + + if ((index >= 0) && (index < Size ())) { + IntPtr varSpecPtr = MmsVariableSpecification_getChildSpecificationByIndex(self, index); + return new MmsVariableSpecification(varSpecPtr); + } + else + throw new MmsValueException ("Index out of bounds"); + } + else + throw new MmsValueException ("specification is of wrong type"); + } + + /// + /// Gets the name of the variable + /// + /// + /// The name. + /// + public string GetName () + { + IntPtr namePtr = MmsVariableSpecification_getName(self); + + return Marshal.PtrToStringAnsi (namePtr); + } + + /// + /// Get the "size" of the variable (array size, number of structure elements ...) + /// + public int Size () + { + return MmsVariableSpecification_getSize(self); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new MmsVariableSpecificationEnumerator (this); + } + + private class MmsVariableSpecificationEnumerator : IEnumerator + { + private MmsVariableSpecification value; + private int index = -1; + + public MmsVariableSpecificationEnumerator (MmsVariableSpecification value) + { + this.value = value; + } + + #region IEnumerator Members + public void Reset () + { + index = -1; + } + + public object Current { + + get { return value.GetElement (index);} + } + + public bool MoveNext () + { + index++; + + if (index >= value.Size ()) + return false; + else + return true; + } + + #endregion + } + + } + } +} diff --git a/dotnet/IEC61850forCSharp/ReportControlBlock.cs b/dotnet/IEC61850forCSharp/ReportControlBlock.cs new file mode 100644 index 0000000..889e8d6 --- /dev/null +++ b/dotnet/IEC61850forCSharp/ReportControlBlock.cs @@ -0,0 +1,716 @@ +/* + * ReportControlBlock.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; +using System.Runtime.InteropServices; +using System.Diagnostics; + +using IEC61850.Common; + +namespace IEC61850 +{ + namespace Client + { + + /// + /// Report handler. + /// + public delegate void ReportHandler (Report report, object parameter); + + /// + /// Report control block (RCB) representation. + /// + /// + /// This class is used as a client side representation (copy) of a report control block (RCB). + /// Values from the server will only be read when the GetRCBValues method is called. + /// Values at the server are only affected when the SetRCBValues method is called. + /// + public class ReportControlBlock + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReportControlBlock_create (string dataAttributeReference); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getRCBValues (IntPtr connection, out int error, string rcbReference, IntPtr updateRcb); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_setRCBValues (IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReportControlBlock_isBuffered (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReportControlBlock_getRptId (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setRptId (IntPtr self, string rptId); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReportControlBlock_getRptEna (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setRptEna(IntPtr self, bool rptEna); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReportControlBlock_getResv (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setResv (IntPtr self, bool resv); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReportControlBlock_getDataSetReference (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setDataSetReference (IntPtr self, string dataSetReference); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ClientReportControlBlock_getConfRev (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int ClientReportControlBlock_getOptFlds (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setOptFlds (IntPtr self, int optFlds); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ClientReportControlBlock_getBufTm (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setBufTm (IntPtr self, UInt32 bufTm); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 ClientReportControlBlock_getSqNum (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int ClientReportControlBlock_getTrgOps (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setTrgOps (IntPtr self, int trgOps); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ClientReportControlBlock_getIntgPd (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setIntgPd (IntPtr self, UInt32 intgPd); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReportControlBlock_getGI (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setGI (IntPtr self, bool gi); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReportControlBlock_getPurgeBuf (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setPurgeBuf (IntPtr self, bool purgeBuf); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern Int32 ClientReportControlBlock_getResvTms (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setResvTms (IntPtr self, Int16 resvTms); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReportControlBlock_getEntryId (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setEntryId (IntPtr self, IntPtr entryId); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt64 ClientReportControlBlock_getEntryTime (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReportControlBlock_getOwner (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_installReportHandler (IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler, + IntPtr handlerParameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_uninstallReportHandler(IntPtr connection, string rcbReference); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void InternalReportHandler (IntPtr parameter, IntPtr report); + + private IntPtr self; + private IntPtr connection; + private IedConnection iedConnection = null; + private string objectReference; + private bool flagRptId = false; + private bool flagRptEna = false; + private bool flagResv = false; + private bool flagDataSetReference = false; + private bool flagConfRev = false; + private bool flagOptFlds = false; + private bool flagBufTm = false; + private bool flagSqNum = false; + private bool flagTrgOps = false; + private bool flagIntgPd = false; + private bool flagGI = false; + private bool flagPurgeBuf = false; + private bool flagResvTms = false; + private bool flagEntryId = false; + + private event ReportHandler reportHandler = null; + private object reportHandlerParameter; + private bool reportHandlerInstalled = false; + private event InternalReportHandler internalHandler = null; + + private void resetSendFlags () + { + flagRptId = false; + flagRptEna = false; + flagResv = false; + flagDataSetReference = false; + flagConfRev = false; + flagOptFlds = false; + flagBufTm = false; + flagSqNum = false; + flagTrgOps = false; + flagIntgPd = false; + flagGI = false; + flagPurgeBuf = false; + flagResvTms = false; + flagEntryId = false; + } + + private Report report = null; + + private void internalReportHandler (IntPtr parameter, IntPtr report) + { + try { + + if (this.report == null) + this.report = new Report (report); + + if (reportHandler != null) + reportHandler(this.report, reportHandlerParameter); + + } catch (Exception e) + { + // older versions of mono 2.10 (for linux?) cause this exception + Console.WriteLine(e.Message); + } + } + + internal ReportControlBlock (string objectReference, IedConnection iedConnection, IntPtr connection) + { + self = ClientReportControlBlock_create (objectReference); + this.iedConnection = iedConnection; + this.connection = connection; + this.objectReference = objectReference; + } + + internal void DisposeInternal() + { + IedConnection_uninstallReportHandler(connection, objectReference); + } + + /// + /// Releases all resource used by the object. + /// + /// Call when you are finished using the . The + /// method leaves the in an unusable state. + /// After calling , you must release all references to the + /// so the garbage collector can reclaim the memory that the + /// was occupying. + public void Dispose() + { + DisposeInternal (); + + iedConnection.RemoveRCB (this); + } + + public string GetObjectReference () + { + return this.objectReference; + } + + /// + /// Installs the report handler. + /// + /// + /// This will install a callback handler (delegate) that is invoked whenever a report + /// related this RCB is received. Any call of this method will replace an previously registered + /// handler! + /// + /// + /// report handler + /// + /// + /// parameter is passed to the handler when the handler is invoked. + /// + public void InstallReportHandler (ReportHandler reportHandler, object parameter) + { + this.reportHandler = new ReportHandler(reportHandler); + + this.reportHandlerParameter = parameter; + + if (reportHandlerInstalled == false) { + + string reportId = this.GetRptId (); + + if (internalHandler == null) + { + internalHandler = new InternalReportHandler(internalReportHandler); + } + + IedConnection_installReportHandler(this.connection, objectReference, reportId, internalHandler, IntPtr.Zero); + reportHandlerInstalled = true; + } + } + + /// + /// Read all RCB values from the server + /// + /// This exception is thrown if there is a connection or service error + public void GetRCBValues () + { + int error; + + IedConnection_getRCBValues (connection, out error, objectReference, self); + + if (error != 0) + throw new IedConnectionException ("getRCBValues service failed", error); + } + + /// + /// Write changed RCB values to the server. + /// + /// + /// This function will only write the RCB values that were set by one of the setter methods. + /// The RCB values are sent by a single MMS write request. + /// + /// This exception is thrown if there is a connection or service error + public void SetRCBValues () + { + SetRCBValues (true); + } + + /// + /// Write changed RCB values to the server. + /// + /// + /// This function will only write the RCB values that were set by one of the setter methods. + /// + /// This exception is thrown if there is a connection or service error + /// + /// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests. + /// + public void SetRCBValues (bool singleRequest) + { + UInt32 parametersMask = 0; + + if (flagRptId) + parametersMask += 1; + + if (flagRptEna) + parametersMask += 2; + + if (flagResv) + parametersMask += 4; + + if (flagDataSetReference) + parametersMask += 8; + + if (flagConfRev) + parametersMask += 16; + + if (flagOptFlds) + parametersMask += 32; + + if (flagBufTm) + parametersMask += 64; + + if (flagSqNum) + parametersMask += 128; + + if (flagTrgOps) + parametersMask += 256; + + if (flagIntgPd) + parametersMask += 512; + + if (flagGI) + parametersMask += 1024; + + if (flagPurgeBuf) + parametersMask += 2048; + + if (flagEntryId) + parametersMask += 4096; + + if (flagResvTms) + parametersMask += 16384; + + int error; + + IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest); + + if (error != 0) + throw new IedConnectionException ("setRCBValues service failed", error); + + if (flagRptId) { + + if (reportHandlerInstalled) { + reportHandlerInstalled = false; + InstallReportHandler(this.reportHandler, this.reportHandlerParameter); + } + } + + resetSendFlags(); + } + + /// + /// Determines whether this instance is a buffered or unbuffered RCB. + /// + /// + /// true if this instance is a buffered RCB; otherwise, false. + /// + public bool IsBuffered () + { + return ClientReportControlBlock_isBuffered (self); + } + + /// + /// Gets the entry time of the RCB as ms time + /// + /// + /// The entry time is the timestamp of the last report sent. + /// + /// + /// The entry time as ms timestamp + /// + public UInt64 GetEntryTime () + { + return ClientReportControlBlock_getEntryTime (self); + } + + /// + /// Gets the entry time of the RCB as DateTimeOffset + /// + /// + /// The entry time is the timestamp of the last report sent. + /// + /// + /// The entry time as DataTimeOffset + /// + public DateTimeOffset GetEntryTimeAsDateTimeOffset () + { + UInt64 entryTime = GetEntryTime (); + + DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + + return retVal.AddMilliseconds (entryTime); + } + + /// + /// Gets the entryID of RCB + /// + /// Returns the EntryID of the last received GetRCBValues service response. + /// The EntryID is only present in buffered RCBs (BRCBs). + /// + /// The entry ID + public byte[] GetEntryID() + { + IntPtr entryIdRef = ClientReportControlBlock_getEntryId (self); + + if (entryIdRef == IntPtr.Zero) + return null; + else { + MmsValue entryId = new MmsValue (entryIdRef); + + return entryId.getOctetString (); + } + } + + public void SetEntryID(byte[] entryId) + { + flagEntryId = true; + + + + MmsValue entryID = MmsValue.NewOctetString (entryId.Length); + + entryID.setOctetString (entryId); + + ClientReportControlBlock_setEntryId (self, entryID.valueReference); + + + } + + + /// + /// Gets the data set reference of the associated data set + /// + /// + /// The data set reference. + /// + public string GetDataSetReference () + { + IntPtr dataSetRefPtr = ClientReportControlBlock_getDataSetReference (self); + + return Marshal.PtrToStringAnsi (dataSetRefPtr); + } + + /// + /// Sets the data set reference. Use this method to select the associated data set for the RCB + /// + /// + /// The data set reference. + /// + public void SetDataSetReference (string dataSetReference) + { + ClientReportControlBlock_setDataSetReference (self, dataSetReference); + + flagDataSetReference = true; + } + + /// + /// Gets the report identifier. + /// + /// + /// The report identifier. + /// + public string GetRptId () + { + IntPtr rptIdPtr = ClientReportControlBlock_getRptId (self); + + return Marshal.PtrToStringAnsi (rptIdPtr); + } + + /// + /// Sets the RptId (report ID) of the RCB + /// + /// + /// The new RptId + /// + public void SetRptId (string rptId) + { + ClientReportControlBlock_setRptId(self, rptId); + flagRptId = true; + } + + /// + /// Check if reporting is currently enabled + /// + /// + /// true, if reporting is enabled, false otherwise + /// + public bool GetRptEna () + { + return ClientReportControlBlock_getRptEna (self); + } + + /// + /// Sets report enable flag. Use this to enable reporting + /// + /// + /// true to enable reporting, false to disable + /// + public void SetRptEna (bool rptEna) + { + ClientReportControlBlock_setRptEna (self, rptEna); + flagRptEna = true; + } + + /// + /// Get the purgeBuf flag of the report control block + /// + /// the prugeBuf value + public bool GetPurgeBuf () + { + return ClientReportControlBlock_getPurgeBuf(self); + } + + /// + /// Set the purgeBuf flag of the report control block + /// + /// This is only for buffered RCBs. If set to true the report buffer of a buffered RCB will be cleaned. + /// set to true to flush report buffer + public void SetPurgeBuf (bool purgeBuf) + { + ClientReportControlBlock_setPurgeBuf(self, purgeBuf); + flagPurgeBuf = true; + } + + /// + /// Gets the buffer time. + /// + /// + /// The buffer time in ms. + /// + public UInt32 GetBufTm() + { + return ClientReportControlBlock_getBufTm (self); + } + + /// + /// Sets the buffer time. + /// + /// + /// Buffer time is ms. + /// + public void SetBufTm (UInt32 bufTm) + { + ClientReportControlBlock_setBufTm (self, bufTm); + + flagBufTm = true; + } + + /// + /// Gets the GI flag + /// + /// + /// true, if GI flag is set + /// + public bool GetGI () + { + return ClientReportControlBlock_getGI (self); + } + + /// + /// Sets the GI flag. Use this to trigger a GI (general interrogation) command. + /// + /// + /// request general interrogation of true + /// + public void SetGI (bool GI) + { + ClientReportControlBlock_setGI (self, GI); + flagGI = true; + } + + /// + /// Check if RCB is reserved by a client + /// + /// + /// true, the RCB is reserver by a client + /// + public bool GetResv () + { + return ClientReportControlBlock_getResv (self); + } + + /// + /// Gets the configuration revision of the RCB + /// + /// + /// The conf rev. + /// + public UInt32 GetConfRev () + { + return ClientReportControlBlock_getConfRev (self); + } + + /// + /// Sets RESV flag. Use this to reserve (allocate) this RCB. + /// + /// + /// true: reserver this RCB for exclusive use + /// + public void SetResv (bool resv) + { + ClientReportControlBlock_setResv (self, resv); + flagResv = true; + } + + /// + /// Gets the trigger options of the RCB + /// + /// + /// trigger options + /// + public TriggerOptions GetTrgOps() + { + return (TriggerOptions) ClientReportControlBlock_getTrgOps (self); + } + + /// + /// Sets the trigger options of the RCB. + /// + /// + /// trigger options + /// + public void SetTrgOps(TriggerOptions trgOps) + { + ClientReportControlBlock_setTrgOps (self, (int) trgOps); + + flagTrgOps = true; + } + + /// + /// Gets the integrity period + /// + /// + /// integrity period in ms + /// + public UInt32 GetIntgPd () + { + return ClientReportControlBlock_getIntgPd (self); + } + + /// + /// Sets the integrity period + /// + /// + /// integrity period in ms + /// + public void SetIntgPd (UInt32 intgPd) + { + ClientReportControlBlock_setIntgPd (self, intgPd); + flagIntgPd = true; + } + + /// + /// Gets the option fields. + /// + /// + /// The option fields + /// + public ReportOptions GetOptFlds() + { + return (ReportOptions) ClientReportControlBlock_getOptFlds (self); + } + + /// + /// Sets the option field. Used to enable or disable optional report elements + /// + /// + /// Option field. + /// + public void SetOptFlds(ReportOptions optFlds) + { + ClientReportControlBlock_setOptFlds (self, (int)optFlds); + + flagOptFlds = true; + } + } + + } +} diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs new file mode 100644 index 0000000..dfbf6d6 --- /dev/null +++ b/dotnet/IEC61850forCSharp/Reporting.cs @@ -0,0 +1,352 @@ +/* + * Reporting.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; +using System.Runtime.InteropServices; + +using IEC61850.Common; +using System.Collections.Generic; + +namespace IEC61850 +{ + namespace Client + { + public partial class IedConnection + { + + private List activeRCBs = null; + + private void cleanupRCBs() + { + if (activeRCBs != null) { + + foreach (ReportControlBlock rcb in activeRCBs) { + rcb.DisposeInternal (); + } + } + + } + + public ReportControlBlock GetReportControlBlock (string rcbObjectReference) + { + var newRCB = new ReportControlBlock (rcbObjectReference, this, connection); + + if (activeRCBs == null) + activeRCBs = new List (); + + activeRCBs.Add (newRCB); + + return newRCB; + } + + internal void RemoveRCB(ReportControlBlock rcb) { + if (activeRCBs != null) { + activeRCBs.Remove (rcb); + } + } + + } + + public enum ReasonForInclusion + { + /** the element is not included in the received report */ + REASON_NOT_INCLUDED = 0, + + /** the element is included due to a change of the data value */ + REASON_DATA_CHANGE = 1, + + /** the element is included due to a change in the quality of data */ + REASON_QUALITY_CHANGE = 2, + + /** the element is included due to an update of the data value */ + REASON_DATA_UPDATE = 3, + + /** the element is included due to a periodic integrity report task */ + REASON_INTEGRITY = 4, + + /** the element is included due to a general interrogation by the client */ + REASON_GI = 5, + + /** the reason for inclusion is unknown */ + REASON_UNKNOWN = 6 + } + + /// + /// A class to hold the contents of a received report + /// + public class Report + { + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasTimestamp (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt64 ClientReport_getTimestamp (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getDataSetValues(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int ClientReport_getReasonForInclusion(IntPtr self, int elementIndex); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasSeqNum(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 ClientReport_getSeqNum(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasDataSetName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasReasonForInclusion(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasConfRev(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ClientReport_getConfRev(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasBufOvfl(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_getBufOvfl(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ClientReport_hasDataReference(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getRcbReference(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getDataSetName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getRptId(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getEntryId(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getDataReference(IntPtr self, int elementIndex); + + private IntPtr self; + + private IntPtr dataSetValues = IntPtr.Zero; + + private MmsValue values = null; + + internal Report (IntPtr self) + { + this.self = self; + } + + /// + /// Determines whether the report has a timestamp. + /// + /// + /// true if this report has a timestamp; otherwise, false. + /// + public bool HasTimestamp () + { + return ClientReport_hasTimestamp (self); + } + + /// + /// Gets the timestamp. + /// + /// + /// The timestamp as milliseconds since 1.1.1970 UTC 00:00 or 0 if no timestamp is present. + /// + public UInt64 GetTimestamp () + { + if (HasTimestamp ()) + return ClientReport_getTimestamp (self); + else + return 0; + } + + public bool HasDataSetName () + { + return ClientReport_hasDataSetName(self); + } + + public bool HasDataReference () + { + return ClientReport_hasDataReference(self); + } + + public bool HasConfRev () + { + return ClientReport_hasConfRev(self); + } + + public UInt32 GetConfRev () + { + return ClientReport_getConfRev(self); + } + + public bool HasBufOvfl () + { + return ClientReport_hasBufOvfl(self); + } + + public bool GetBufOvfl () + { + return ClientReport_getBufOvfl(self); + } + + public bool HasSeqNum () + { + return ClientReport_hasSeqNum(self); + } + + public UInt16 GetSeqNum () + { + return ClientReport_getSeqNum(self); + } + + public bool HasReasonForInclusion () + { + return ClientReport_hasReasonForInclusion(self); + } + + /// + /// Gets the data set values as MMS_ARRAY instance. + /// + /// + /// The data set values. + /// + public MmsValue GetDataSetValues () + { + if (dataSetValues == IntPtr.Zero) { + dataSetValues = ClientReport_getDataSetValues(self); + + if (dataSetValues == IntPtr.Zero) + throw new IedConnectionException("No report values available yet"); + + values = new MmsValue(dataSetValues); + } + + return values; + } + + /// + /// Gets the reason for inclusion of data set member with the given index + /// + /// + /// The reason for inclusion. + /// + /// + /// index of the data set member in the data set + /// + public ReasonForInclusion GetReasonForInclusion (int index) + { + if (values == null) { + GetDataSetValues (); + + if (values == null) + throw new IedConnectionException("No ReasonForInclusion available yet"); + } + + int dataSetSize = values.Size(); + + if (index >= dataSetSize) + throw new IedConnectionException("data set index out of range (count = " + dataSetSize + ")"); + + return (ReasonForInclusion) ClientReport_getReasonForInclusion(self, index); + } + + public string GetRcbReference () + { + IntPtr rcbRef = ClientReport_getRcbReference(self); + + return Marshal.PtrToStringAnsi (rcbRef); + } + + public string GetDataSetName () + { + IntPtr dataSetName = ClientReport_getDataSetName (self); + + return Marshal.PtrToStringAnsi (dataSetName); + } + + /// + /// Gets the data reference for the specified data set element + /// + /// + /// The data reference or null if the data reference is not available + /// + /// + /// index of the data set element starting with 0 + /// + public string GetDataReference (int index) + { + IntPtr dataRef = ClientReport_getDataReference(self, index); + + if (dataRef != IntPtr.Zero) + return Marshal.PtrToStringAnsi(dataRef); + else + return null; + } + + public string GetRptId () + { + IntPtr rptId = ClientReport_getRptId(self); + + if (rptId == IntPtr.Zero) + return GetRcbReference(); + else + return Marshal.PtrToStringAnsi (rptId); + } + + /// + /// Gets the EntryID of this report. + /// + /// The entryID as a byte array representing an MMS octet string. + public byte[] GetEntryId () + { + IntPtr entryIdRef = ClientReport_getEntryId (self); + + if (entryIdRef == IntPtr.Zero) + return null; + else { + MmsValue entryId = new MmsValue (entryIdRef); + + return entryId.getOctetString (); + } + } + + } + + } +} + diff --git a/dotnet/authenticate/AssemblyInfo.cs b/dotnet/authenticate/AssemblyInfo.cs new file mode 100644 index 0000000..c77a4a9 --- /dev/null +++ b/dotnet/authenticate/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("authenticate")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/authenticate/Main.cs b/dotnet/authenticate/Main.cs new file mode 100644 index 0000000..afab952 --- /dev/null +++ b/dotnet/authenticate/Main.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Client; +using IEC61850.Common; + +namespace authenticate +{ + class MainClass + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + + try + { + IsoConnectionParameters parameters = con.GetConnectionParameters(); + + parameters.UsePasswordAuthentication("top secret"); + + con.Connect(hostname, 102); + + List serverDirectory = con.GetServerDirectory(false); + + foreach (string entry in serverDirectory) + { + Console.WriteLine("LD: " + entry); + } + + con.Release(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} \ No newline at end of file diff --git a/dotnet/authenticate/authenticate.csproj b/dotnet/authenticate/authenticate.csproj new file mode 100644 index 0000000..4521ac5 --- /dev/null +++ b/dotnet/authenticate/authenticate.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {0BECEC77-2315-4B95-AFF9-E6007E644BBF} + Exe + authenticate + authenticate + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/control/AssemblyInfo.cs b/dotnet/control/AssemblyInfo.cs new file mode 100644 index 0000000..21a7f0d --- /dev/null +++ b/dotnet/control/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("control")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/control/ControlExample.cs b/dotnet/control/ControlExample.cs new file mode 100644 index 0000000..5504f31 --- /dev/null +++ b/dotnet/control/ControlExample.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using IEC61850.Common; +using IEC61850.Client; +using System.Threading; + + +namespace control +{ + class ControlExample + { + private static void commandTerminationHandler (Object parameter, ControlObject control) + { + LastApplError lastApplError = control.GetLastApplError(); + Console.WriteLine("HANDLER CALLED! " + lastApplError.addCause); + } + + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + try + { + con.Connect(hostname, 102); + + /* direct control with normal security or SBO with normal security */ + string objectReference = "simpleIOGenericIO/GGIO1.SPCSO1"; + + ControlObject control = con.CreateControlObject(objectReference); + + ControlModel controlModel = control.GetControlModel(); + + Console.WriteLine(objectReference + " has control model " + controlModel.ToString()); + + + switch (controlModel) { + + case ControlModel.STATUS_ONLY: + Console.WriteLine("Control is status-only!"); + break; + + case ControlModel.DIRECT_NORMAL: + case ControlModel.DIRECT_ENHANCED: + if (!control.Operate(true)) + Console.WriteLine("operate failed!"); + else + Console.WriteLine("operated successfully!"); + break; + + case ControlModel.SBO_NORMAL: + case ControlModel.SBO_ENHANCED: + + if (control.Select()) { + if (!control.Operate(true)) + Console.WriteLine("operate failed!"); + else + Console.WriteLine("operated successfully!"); + } + else + Console.WriteLine("Select failed!"); + + break; + } + + /* direct control with enhanced security */ + objectReference = "simpleIOGenericIO/GGIO1.SPCSO3"; + control = con.CreateControlObject(objectReference); + + controlModel = control.GetControlModel(); + Console.WriteLine(objectReference + " has control model " + controlModel.ToString()); + + if (controlModel == ControlModel.DIRECT_ENHANCED) { + control.SetCommandTerminationHandler(commandTerminationHandler, null); + + control.Operate(true); + + Thread.Sleep(1000); + } + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + + } + } +} diff --git a/dotnet/control/control.csproj b/dotnet/control/control.csproj new file mode 100644 index 0000000..28c7e79 --- /dev/null +++ b/dotnet/control/control.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C351CFA4-E54E-49A1-86CE-69643535541A} + Exe + control + control + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/datasets/AssemblyInfo.cs b/dotnet/datasets/AssemblyInfo.cs new file mode 100644 index 0000000..4ebf096 --- /dev/null +++ b/dotnet/datasets/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("datasets")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/datasets/DataSetExample.cs b/dotnet/datasets/DataSetExample.cs new file mode 100644 index 0000000..727e275 --- /dev/null +++ b/dotnet/datasets/DataSetExample.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Client; +using IEC61850.Common; + +namespace datasets +{ + class DataSetExample + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + try + { + con.Connect(hostname, 102); + + List serverDirectory = con.GetServerDirectory(false); + + foreach (string entry in serverDirectory) + { + Console.WriteLine("LD: " + entry); + } + + // create a new data set + + List dataSetElements = new List(); + + string dataSetName = "simpleIOGenericIO/UNKNOWN.ds1"; + + //string dataSetName = "simpleIOGenericIO/LLN0.ds1"; + + dataSetElements.Add("simpleIOGenericIO/GGIO1.AnIn1.mag.f[MX]"); + dataSetElements.Add("simpleIOGenericIO/GGIO1.AnIn2.mag.f[MX]"); + + con.CreateDataSet(dataSetName, dataSetElements); + + // get the directory of the data set + List dataSetDirectory = con.GetDataSetDirectory(dataSetName); + + foreach (string entry in dataSetDirectory) + { + Console.WriteLine("DS element: " + entry); + } + + // read the values of the newly created data set + DataSet dataSet = con.ReadDataSetValues(dataSetName, null); + + MmsValue dataSetValues = dataSet.GetValues(); + + Console.WriteLine ("Data set contains " + dataSetValues.Size() + " elements"); + + foreach (MmsValue value in dataSetValues) { + Console.WriteLine(" DS value: " + value + " type: " + value.GetType()); + } + + // delete the data set + con.DeleteDataSet(dataSetName); + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message + " reason: " + e.GetIedClientError().ToString()); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + + } + } +} diff --git a/dotnet/datasets/datasets.csproj b/dotnet/datasets/datasets.csproj new file mode 100644 index 0000000..1b1240b --- /dev/null +++ b/dotnet/datasets/datasets.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {D5C7DD38-032A-49B6-B74F-FFD9724A8AE4} + Exe + datasets + datasets + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/dotnet.sln b/dotnet/dotnet.sln new file mode 100644 index 0000000..8ea2e27 --- /dev/null +++ b/dotnet/dotnet.sln @@ -0,0 +1,123 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850forCSharp", "IEC61850forCSharp\IEC61850forCSharp.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example1", "example1\example1.csproj", "{C616A6DF-831E-443C-9310-3F343A6E3D1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "model_browsing", "model_browsing\model_browsing.csproj", "{59B85486-F48D-4978-BD35-8F5C3A8288D4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "datasets", "datasets\datasets.csproj", "{D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "control", "control\control.csproj", "{C351CFA4-E54E-49A1-86CE-69643535541A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "reporting", "reporting\reporting.csproj", "{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example2", "example2\example2.csproj", "{2A226B6D-1D1F-4BFE-B8CC-158116F71270}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "authenticate", "authenticate\authenticate.csproj", "{0BECEC77-2315-4B95-AFF9-E6007E644BBF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{FBDFE530-DBEB-474B-BA54-9AB287DD57B3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "report_new_dataset", "report_new_dataset\report_new_dataset.csproj", "{71485F99-2976-45E6-B73D-4946E594C15C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Release|Any CPU.Build.0 = Release|Any CPU + {2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Release|Any CPU.Build.0 = Release|Any CPU + {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Release|Any CPU.Build.0 = Release|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Release|Any CPU.Build.0 = Release|Any CPU + {71485F99-2976-45E6-B73D-4946E594C15C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71485F99-2976-45E6-B73D-4946E594C15C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71485F99-2976-45E6-B73D-4946E594C15C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71485F99-2976-45E6-B73D-4946E594C15C}.Release|Any CPU.Build.0 = Release|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Release|Any CPU.Build.0 = Release|Any CPU + {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Release|Any CPU.Build.0 = Release|Any CPU + {C351CFA4-E54E-49A1-86CE-69643535541A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C351CFA4-E54E-49A1-86CE-69643535541A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C351CFA4-E54E-49A1-86CE-69643535541A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C351CFA4-E54E-49A1-86CE-69643535541A}.Release|Any CPU.Build.0 = Release|Any CPU + {C35D624E-5506-4560-8074-1728F1FA1A4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C35D624E-5506-4560-8074-1728F1FA1A4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C35D624E-5506-4560-8074-1728F1FA1A4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C35D624E-5506-4560-8074-1728F1FA1A4D}.Release|Any CPU.Build.0 = Release|Any CPU + {C616A6DF-831E-443C-9310-3F343A6E3D1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C616A6DF-831E-443C-9310-3F343A6E3D1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C616A6DF-831E-443C-9310-3F343A6E3D1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C616A6DF-831E-443C-9310-3F343A6E3D1A}.Release|Any CPU.Build.0 = Release|Any CPU + {D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}.Release|Any CPU.Build.0 = Release|Any CPU + {FBDFE530-DBEB-474B-BA54-9AB287DD57B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBDFE530-DBEB-474B-BA54-9AB287DD57B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBDFE530-DBEB-474B-BA54-9AB287DD57B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBDFE530-DBEB-474B-BA54-9AB287DD57B3}.Release|Any CPU.Build.0 = Release|Any CPU + {740DC107-F506-416C-B145-F71649A4A5A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {740DC107-F506-416C-B145-F71649A4A5A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {740DC107-F506-416C-B145-F71649A4A5A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {740DC107-F506-416C-B145-F71649A4A5A0}.Release|Any CPU.Build.0 = Release|Any CPU + {EDC263E3-0419-4B23-91A4-250EF0A6DD62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDC263E3-0419-4B23-91A4-250EF0A6DD62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDC263E3-0419-4B23-91A4-250EF0A6DD62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDC263E3-0419-4B23-91A4-250EF0A6DD62}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = IEC61850forCSharp\IEC61850forCSharp.csproj + Policies = $0 + $0.DotNetNamingPolicy = $1 + $1.DirectoryNamespaceAssociation = None + $1.ResourceNamePolicy = FileFormatDefault + $0.TextStylePolicy = $2 + $2.FileWidth = 120 + $2.TabsToSpaces = False + $2.inheritsSet = VisualStudio + $2.inheritsScope = text/plain + $2.scope = text/plain + $0.TextStylePolicy = $3 + $3.inheritsSet = null + $3.scope = text/microsoft-resx + $0.XmlFormattingPolicy = $4 + $4.inheritsSet = null + $4.scope = text/microsoft-resx + $0.TextStylePolicy = $5 + $5.inheritsSet = null + $5.scope = application/xml + $0.XmlFormattingPolicy = $6 + $6.inheritsSet = Mono + $6.inheritsScope = application/xml + $6.scope = application/xml + $0.StandardHeader = $7 + $7.Text = + $7.IncludeInNewFiles = True + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/dotnet/example1/AssemblyInfo.cs b/dotnet/example1/AssemblyInfo.cs new file mode 100644 index 0000000..a1fbaff --- /dev/null +++ b/dotnet/example1/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("example1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/example1/Main.cs b/dotnet/example1/Main.cs new file mode 100644 index 0000000..24de9eb --- /dev/null +++ b/dotnet/example1/Main.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Client; +using IEC61850.Common; + +namespace example1 +{ + class MainClass + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "10.0.2.2"; + + Console.WriteLine("Connect to " + hostname); + + + try + { + con.Connect(hostname, 102); + + List serverDirectory = con.GetServerDirectory(false); + + foreach (string entry in serverDirectory) + { + Console.WriteLine("LD: " + entry); + } + + + List lnDirectory = con.GetLogicalNodeDirectory("simpleIOGenericIO/LLN0", ACSIClass.ACSI_CLASS_DATA_SET); + + foreach (string entry in lnDirectory) + { + Console.WriteLine("Dataset: " + entry); + } + + string vendor = con.ReadStringValue ("simpleIOGenericIO/LLN0.NamPlt.vendor", FunctionalConstraint.DC); + Console.WriteLine ("Vendor: " + vendor); + + /* read FCDO */ + MmsValue value = con.ReadValue("simpleIOGenericIO/GGIO1.AnIn1", FunctionalConstraint.MX); + + if (value.GetType() == MmsType.MMS_STRUCTURE) + { + Console.WriteLine("Value is of complex type"); + + for (int i = 0; i < value.Size(); i++) + { + Console.WriteLine(" element: " + value.GetElement(i).GetType()); + if (value.GetElement(i).GetType() == MmsType.MMS_UTC_TIME) + { + Console.WriteLine(" -> " + value.GetElement(i).GetUtcTimeAsDateTimeOffset()); + } + } + } + + DataSet dataSet = con.ReadDataSetValues("simpleIOGenericIO/LLN0.Events", null); + + Console.WriteLine("Read data set " + dataSet.GetReference()); + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + + System.Threading.Thread.Sleep(2000); + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} diff --git a/dotnet/example1/example1.csproj b/dotnet/example1/example1.csproj new file mode 100644 index 0000000..087f4e6 --- /dev/null +++ b/dotnet/example1/example1.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C616A6DF-831E-443C-9310-3F343A6E3D1A} + Exe + example1 + example1 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/example2/AssemblyInfo.cs b/dotnet/example2/AssemblyInfo.cs new file mode 100644 index 0000000..7ad8e13 --- /dev/null +++ b/dotnet/example2/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("example2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/example2/WriteValueExample.cs b/dotnet/example2/WriteValueExample.cs new file mode 100644 index 0000000..eb8b022 --- /dev/null +++ b/dotnet/example2/WriteValueExample.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using IEC61850.Client; +using IEC61850.Common; + +namespace example2 +{ + class WriteValueExample + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + try + { + con.Connect(hostname, 102); + + float setMagF = con.ReadFloatValue("ied1Inverter/ZINV1.OutWSet.setMag.f", FunctionalConstraint.SP); + + Console.WriteLine("ied1Inverter/ZINV1.OutWSet.setMag.f: " + setMagF); + + setMagF += 1.0f; + + con.WriteValue("ied1Inverter/ZINV1.OutWSet.setMag.f", FunctionalConstraint.SP, new MmsValue(setMagF)); + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine("IED connection excepion: " + e.Message); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} diff --git a/dotnet/example2/example2.csproj b/dotnet/example2/example2.csproj new file mode 100644 index 0000000..18f5443 --- /dev/null +++ b/dotnet/example2/example2.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {2A226B6D-1D1F-4BFE-B8CC-158116F71270} + Exe + example2 + example2 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/example3/AssemblyInfo.cs b/dotnet/example3/AssemblyInfo.cs new file mode 100644 index 0000000..8fa9151 --- /dev/null +++ b/dotnet/example3/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("example3")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/example3/Main.cs b/dotnet/example3/Main.cs new file mode 100644 index 0000000..5247bd3 --- /dev/null +++ b/dotnet/example3/Main.cs @@ -0,0 +1,51 @@ +using System; +using IEC61850.Client; +using System.Collections.Generic; + +namespace example3 +{ + class MainClass + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + + try + { + IsoConnectionParameters parameters = con.GetConnectionParameters(); + + parameters.SetRemoteAddresses(1,1, new byte[] {0x00, 0x01, 0x02, 0x03}); + + con.ConnectTimeout = 10000; + + con.Connect(hostname, 102); + + List serverDirectory = con.GetServerDirectory(false); + + foreach (string entry in serverDirectory) + { + Console.WriteLine("LD: " + entry); + } + + con.Release(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} diff --git a/dotnet/example3/example3.csproj b/dotnet/example3/example3.csproj new file mode 100644 index 0000000..7a1f9d0 --- /dev/null +++ b/dotnet/example3/example3.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2} + Exe + example3 + example3 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/files/AssemblyInfo.cs b/dotnet/files/AssemblyInfo.cs new file mode 100644 index 0000000..1133bf6 --- /dev/null +++ b/dotnet/files/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("files")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/files/FileServicesExample.cs b/dotnet/files/FileServicesExample.cs new file mode 100644 index 0000000..6aed827 --- /dev/null +++ b/dotnet/files/FileServicesExample.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Client; +using IEC61850.Common; +using System.IO; + +namespace files +{ + class MainClass + { + public static void printFiles (IedConnection con, string prefix, string parent) + { + List files = con.GetFileDirectory (parent); + + foreach (FileDirectoryEntry file in files) { + Console.WriteLine(prefix + file.GetFileName() + "\t" + file.GetFileSize() + "\t" + + MmsValue.MsTimeToDateTimeOffset(file.GetLastModified())); + + if (file.GetFileName().EndsWith("/")) { + printFiles (con, prefix + " ", parent + file.GetFileName()); + } + } + + } + + static bool getFileHandler (object parameter, byte[] data) + { + Console.WriteLine("received " + data.Length + " bytes"); + + BinaryWriter binWriter = (BinaryWriter) parameter; + + binWriter.Write(data); + + return true; + } + + + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "10.0.2.2"; + + Console.WriteLine("Connect to " + hostname); + + try + { + con.Connect(hostname, 102); + + Console.WriteLine ("Files in server root directory:"); + List serverDirectory = con.GetServerDirectory(true); + + foreach (string entry in serverDirectory) { + Console.WriteLine(entry); + } + + Console.WriteLine(); + + Console.WriteLine ("File directory tree at server:"); + printFiles(con, "", ""); + Console.WriteLine(); + + string filename = "IEDSERVER.BIN"; + + Console.WriteLine("Download file " + filename); + + /* Download file from server and write it to a new local file */ + FileStream fs = new FileStream(filename, FileMode.Create); + BinaryWriter w = new BinaryWriter(fs); + + con.GetFile(filename, new IedConnection.GetFileHandler(getFileHandler), w); + + fs.Close(); + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} diff --git a/dotnet/files/files.csproj b/dotnet/files/files.csproj new file mode 100644 index 0000000..348f804 --- /dev/null +++ b/dotnet/files/files.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {77127456-19B9-4D1A-AEF9-40F8D1C5695E} + Exe + files + files + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/model_browsing/AssemblyInfo.cs b/dotnet/model_browsing/AssemblyInfo.cs new file mode 100644 index 0000000..bf82bd4 --- /dev/null +++ b/dotnet/model_browsing/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("model_browsing")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/model_browsing/ModelBrowsing.cs b/dotnet/model_browsing/ModelBrowsing.cs new file mode 100644 index 0000000..1322118 --- /dev/null +++ b/dotnet/model_browsing/ModelBrowsing.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Client; +using IEC61850.Common; + +/// +/// Example for browsing the data model of a server. Shows logical devices, logical nodes, +/// data sets and report control blocks +/// +namespace model_browsing +{ + class ModelBrowsing + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + try + { + Console.WriteLine("Connect to " + hostname + " ..."); + + con.Connect(hostname, 102); + + Console.WriteLine("Connected."); + + MmsConnection mmsCon = con.GetMmsConnection(); + + MmsServerIdentity identity = mmsCon.GetServerIdentity(); + + Console.WriteLine("Vendor: " + identity.vendorName); + Console.WriteLine("Model: " + identity.modelName); + Console.WriteLine("Revision: " + identity.revision); + + List serverDirectory = con.GetServerDirectory(false); + + foreach (string ldName in serverDirectory) + { + Console.WriteLine("LD: " + ldName); + + List lnNames = con.GetLogicalDeviceDirectory(ldName); + + foreach (string lnName in lnNames) + { + Console.WriteLine(" LN: " + lnName); + + string logicalNodeReference = ldName + "/" + lnName; + + // discover data objects + List dataObjects = + con.GetLogicalNodeDirectory(logicalNodeReference, ACSIClass.ACSI_CLASS_DATA_OBJECT); + + foreach (string dataObject in dataObjects) { + Console.WriteLine(" DO: " + dataObject); + + List dataDirectory = con.GetDataDirectoryFC(logicalNodeReference + "." + dataObject); + + foreach (string dataDirectoryElement in dataDirectory) { + + string daReference = logicalNodeReference + "." + dataObject + "." + ObjectReference.getElementName(dataDirectoryElement); + + // get the type specification of a variable + MmsVariableSpecification specification = con.GetVariableSpecification(daReference, ObjectReference.getFC(dataDirectoryElement)); + + Console.WriteLine (" DA/SDO: [" + ObjectReference.getFC(dataDirectoryElement) + "] " + + ObjectReference.getElementName(dataDirectoryElement) + " : " + specification.GetType() + + "(" + specification.Size() + ")"); + + if (specification.GetType() == MmsType.MMS_STRUCTURE) { + foreach (MmsVariableSpecification elementSpec in specification) { + Console.WriteLine(" " + elementSpec.GetName() + " : " + elementSpec.GetType()); + } + } + } + + } + + // discover data sets + List dataSets = + con.GetLogicalNodeDirectory(logicalNodeReference, ACSIClass.ACSI_CLASS_DATA_SET); + + foreach (string dataSet in dataSets) { + Console.WriteLine(" Dataset: " + dataSet); + } + + // discover unbuffered report control blocks + List urcbs = + con.GetLogicalNodeDirectory(logicalNodeReference, ACSIClass.ACSI_CLASS_URCB); + + foreach (string urcb in urcbs) { + Console.WriteLine(" URCB: " + urcb); + } + + // discover buffered report control blocks + List brcbs = + con.GetLogicalNodeDirectory(logicalNodeReference, ACSIClass.ACSI_CLASS_BRCB); + + foreach (string brcb in brcbs) { + Console.WriteLine(" BRCB: " + brcb); + } + + + } + + } + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} diff --git a/dotnet/model_browsing/model_browsing.csproj b/dotnet/model_browsing/model_browsing.csproj new file mode 100644 index 0000000..40bd89b --- /dev/null +++ b/dotnet/model_browsing/model_browsing.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {59B85486-F48D-4978-BD35-8F5C3A8288D4} + Exe + model_browsing + model_browsing + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/report_new_dataset/AssemblyInfo.cs b/dotnet/report_new_dataset/AssemblyInfo.cs new file mode 100644 index 0000000..1d974f1 --- /dev/null +++ b/dotnet/report_new_dataset/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("report_new_dataset")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/report_new_dataset/Main.cs b/dotnet/report_new_dataset/Main.cs new file mode 100644 index 0000000..9164452 --- /dev/null +++ b/dotnet/report_new_dataset/Main.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Common; +using IEC61850.Client; +using System.Threading; + +namespace report_new_dataset +{ + class ReportNewDataSetExample + { + private static void reportHandler (Report report, object parameter) + { + Console.WriteLine ("Received report:\n----------------"); + + if (report.HasTimestamp ()) + Console.WriteLine (" timestamp: " + MmsValue.MsTimeToDateTimeOffset (report.GetTimestamp ()).ToString ()); + + MmsValue values = report.GetDataSetValues (); + + Console.WriteLine (" report dataset contains " + values.Size () + " elements"); + + for (int i = 0; i < values.Size(); i++) { + if (report.GetReasonForInclusion(i) != ReasonForInclusion.REASON_NOT_INCLUDED) { + Console.WriteLine(" element " + i + " included for reason " + report.GetReasonForInclusion(i).ToString() + " " + values.GetElement(i)); + } + } + } + + private static bool running = true; + + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + try + { + con.Connect(hostname, 102); + + // create a new data set + + List dataSetElements = new List(); + + dataSetElements.Add("simpleIOGenericIO/GGIO1.AnIn1.mag.f[MX]"); + dataSetElements.Add("simpleIOGenericIO/GGIO1.AnIn2.mag.f[MX]"); + dataSetElements.Add("simpleIOGenericIO/GGIO1.AnIn3.mag.f[MX]"); + dataSetElements.Add("simpleIOGenericIO/GGIO1.AnIn4.mag.f[MX]"); + + // permanent (domain specific) data set + //string dataSetReference = "simpleIOGenericIO/LLN0.ds1"; + + // temporary (association specific) data set + string dataSetReference = "@newds"; + + // Note: this function will throw an exception when a data set with the same name already exists + con.CreateDataSet(dataSetReference, dataSetElements); + + // reconfigure existing RCB with new data set + + string rcbReference = "simpleIOGenericIO/LLN0.RP.EventsRCB01"; + + ReportControlBlock rcb = con.GetReportControlBlock(rcbReference); + + rcb.GetRCBValues(); + + // note: the second parameter is not required! + rcb.InstallReportHandler(reportHandler, rcb); + + string rcbDataSetReference = dataSetReference.Replace('.', '$'); + + rcb.SetDataSetReference(rcbDataSetReference); + rcb.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); + rcb.SetIntgPd(5000); + rcb.SetRptEna(true); + + rcb.SetRCBValues(); + + /* run until Ctrl-C is pressed */ + Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { + e.Cancel = true; + running = false; + }; + + while (running) { + Thread.Sleep(1000); + } + + // delete the data set + con.DeleteDataSet(dataSetReference); + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message + " reason: " + e.GetIedClientError().ToString()); + } + + // release all resources - do NOT use the object after this call!! + con.Dispose (); + } + } +} diff --git a/dotnet/report_new_dataset/report_new_dataset.csproj b/dotnet/report_new_dataset/report_new_dataset.csproj new file mode 100644 index 0000000..e33af7a --- /dev/null +++ b/dotnet/report_new_dataset/report_new_dataset.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {71485F99-2976-45E6-B73D-4946E594C15C} + Exe + report_new_dataset + report_new_dataset + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/reporting/AssemblyInfo.cs b/dotnet/reporting/AssemblyInfo.cs new file mode 100644 index 0000000..a58c9ab --- /dev/null +++ b/dotnet/reporting/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("reporting")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/reporting/ReportingExample.cs b/dotnet/reporting/ReportingExample.cs new file mode 100644 index 0000000..9857194 --- /dev/null +++ b/dotnet/reporting/ReportingExample.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +using IEC61850.Client; +using IEC61850.Common; +using System.Runtime.Remoting.Metadata.W3cXsd2001; + +namespace reporting +{ + class ReportingExample + { + + private static void reportHandler (Report report, object parameter) + { + Console.WriteLine ("Received report:\n----------------"); + + Console.WriteLine (" for RCB: " + report.GetRcbReference()); + + if (report.HasTimestamp ()) + Console.WriteLine (" timestamp: " + MmsValue.MsTimeToDateTimeOffset (report.GetTimestamp ()).ToString ()); + + MmsValue values = report.GetDataSetValues (); + + byte[] entryId = report.GetEntryId (); + + if (entryId != null) { + SoapHexBinary shb = new SoapHexBinary(entryId); + + Console.WriteLine (" entryID: " + shb.ToString ()); + } + + if (report.HasDataSetName ()) { + Console.WriteLine (" report data set: " + report.GetDataSetName ()); + } + + Console.WriteLine (" report dataset contains " + values.Size () + " elements"); + + for (int i = 0; i < values.Size(); i++) { + if (report.GetReasonForInclusion(i) != ReasonForInclusion.REASON_NOT_INCLUDED) { + Console.WriteLine(" element " + i + " included for reason " + report.GetReasonForInclusion(i).ToString() + " " + values.GetElement(i)); + } + + if (report.HasDataReference()) { + Console.WriteLine(" data-ref: " + report.GetDataReference(i)); + } + + } + + ReportControlBlock rcb = (ReportControlBlock) parameter; + + Console.WriteLine(" For RCB: " + rcb.GetObjectReference() + " Buffered: " + rcb.IsBuffered() + + " data-set: " + rcb.GetDataSetReference ()); + + } + + + private static bool running = true; + + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args [0]; + else + hostname = "localhost"; + + Console.WriteLine ("Connect to " + hostname); + + try { + con.Connect (hostname, 102); + + string rcbReference1 = "simpleIOGenericIO/LLN0.RP.EventsRCB01"; + string rcbReference2 = "simpleIOGenericIO/LLN0.RP.EventsIndexed01"; + string rcbReference3 = "simpleIOGenericIO/LLN0.BR.Measurements01"; + + ReportControlBlock rcb1 = con.GetReportControlBlock(rcbReference1); + ReportControlBlock rcb2 = con.GetReportControlBlock(rcbReference2); + ReportControlBlock rcb3 = con.GetReportControlBlock(rcbReference3); + + rcb1.GetRCBValues(); + + // note: the second parameter is not required! + rcb1.InstallReportHandler(reportHandler, rcb1); + + if (rcb1.IsBuffered()) + Console.WriteLine("RCB: " + rcbReference1 + " is buffered"); + + rcb1.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); + rcb1.SetIntgPd(5000); + rcb1.SetRptEna(true); + + rcb1.SetRCBValues(); + + rcb2.GetRCBValues(); + + if (rcb2.IsBuffered()) + Console.WriteLine("RCB: " + rcbReference2 + " is buffered"); + + rcb2.InstallReportHandler(reportHandler, rcb2); + + rcb2.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP | + ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET); + rcb2.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); + rcb2.SetIntgPd(2000); + rcb2.SetRptEna(true); + + rcb2.SetRCBValues(); + + rcb3.GetRCBValues(); + + if (rcb3.IsBuffered()) + Console.WriteLine ("RCB: " + rcbReference3 + " is buffered"); + + rcb3.InstallReportHandler(reportHandler, rcb2); + + rcb3.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP | + ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET); + rcb3.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); + rcb3.SetIntgPd(2000); + rcb3.SetRptEna(true); + + rcb3.SetRCBValues(); + + + /* run until Ctrl-C is pressed */ + Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { + e.Cancel = true; + ReportingExample.running = false; + }; + + /* stop main loop when connection is lost */ + con.InstallConnectionClosedHandler(delegate(IedConnection connection) { + Console.WriteLine("Connection closed"); + ReportingExample.running = false; + }); + + while (running) { + Thread.Sleep(10); + } + + /* Dispose the RCBs when you no longer need them */ + rcb1.Dispose(); + rcb2.Dispose(); + rcb3.Dispose(); + + con.Abort (); + + con.Dispose(); + } catch (IedConnectionException e) { + Console.WriteLine ("Error: " + e.Message); + + con.Dispose (); + } + + } + } +} diff --git a/dotnet/reporting/reporting.csproj b/dotnet/reporting/reporting.csproj new file mode 100644 index 0000000..319ba36 --- /dev/null +++ b/dotnet/reporting/reporting.csproj @@ -0,0 +1,95 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8} + Exe + reporting + reporting + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + True + True + Settings.settings + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + \ No newline at end of file diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs new file mode 100644 index 0000000..c5b03c0 --- /dev/null +++ b/dotnet/tests/Test.cs @@ -0,0 +1,79 @@ +using NUnit.Framework; +using System; +using IEC61850.Common; +using IEC61850.Client; + +namespace tests +{ + [TestFixture ()] + public class Test + { + [Test ()] + public void TestCase () + { + var val = new MmsValue (10.0f); + + Assert.AreEqual (10.0f, val.ToFloat ()); + } + + [Test ()] + public void MmsValueBitString () + { + var val = MmsValue.NewBitString(10); + + Assert.AreEqual (MmsType.MMS_BIT_STRING, val.GetType()); + Assert.AreEqual (10, val.Size()); + + val.BitStringFromUInt32(7); + + Assert.AreEqual(7, val.BitStringToUInt32()); + + Assert.AreEqual(true, val.GetBit(0)); + Assert.AreEqual(true, val.GetBit(1)); + Assert.AreEqual(true, val.GetBit(2)); + Assert.AreEqual(false, val.GetBit(3)); + + Assert.AreEqual(false, val.GetBit(9)); + + Assert.AreEqual(false, val.GetBit(10)); + + val.SetBit(3, true); + Assert.AreEqual(true, val.GetBit(3)); + + Assert.AreEqual(15, val.BitStringToUInt32()); + + val.SetBit(3, false); + Assert.AreEqual(7, val.BitStringToUInt32()); + } + + [Test()] + public void MmsValueOctetString () + { + var val = MmsValue.NewOctetString(20); + + Assert.AreEqual (0, val.Size()); + Assert.AreEqual (20, val.MaxSize()); + + byte[] octetString = val.getOctetString(); + + Assert.AreEqual (0, octetString.Length); + + octetString = new byte[5]; + octetString[0] = 0x11; + octetString[1] = 0x12; + octetString[2] = 0x13; + octetString[3] = 0x14; + octetString[4] = 0x15; + + val.setOctetString(octetString); + + Assert.AreEqual(5, val.Size()); + + byte[] secondOctetString = val.getOctetString(); + + Assert.AreEqual(octetString, secondOctetString); + } + + } +} + diff --git a/dotnet/tests/tests.csproj b/dotnet/tests/tests.csproj new file mode 100644 index 0000000..76e97b7 --- /dev/null +++ b/dotnet/tests/tests.csproj @@ -0,0 +1,47 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {FBDFE530-DBEB-474B-BA54-9AB287DD57B3} + Library + tests + tests + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + none + true + bin\Release + prompt + 4 + false + + + + + nunit + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..5bc51cf --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,25 @@ +add_subdirectory(server_example1) +add_subdirectory(server_example2) +add_subdirectory(server_example3) +add_subdirectory(server_example4) +add_subdirectory(server_example5) +add_subdirectory(server_example_goose) +add_subdirectory(server_example_control) +add_subdirectory(server_example_dynamic) +add_subdirectory(server_example_config_file) +add_subdirectory(server_example_complex_array) +add_subdirectory(server_example_threadless) +add_subdirectory(server_example_61400_25) +add_subdirectory(server_example_setting_groups) +add_subdirectory(iec61850_client_example1) +add_subdirectory(iec61850_client_example2) +add_subdirectory(iec61850_client_example3) +add_subdirectory(iec61850_client_example4) +add_subdirectory(iec61850_client_example5) +add_subdirectory(iec61850_client_example_files) +add_subdirectory(iec61850_client_example_reporting) +add_subdirectory(goose_subscriber) +add_subdirectory(mms_client_example1) +add_subdirectory(mms_client_example2) +add_subdirectory(mms_client_example3) +add_subdirectory(mms_client_example4) diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..61f781e --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,53 @@ + +EXAMPLE_DIRS = mms_client_example1 +EXAMPLE_DIRS += mms_client_example2 +EXAMPLE_DIRS += mms_client_example3 +EXAMPLE_DIRS += mms_client_example4 +EXAMPLE_DIRS += mms_client_example5 +EXAMPLE_DIRS += iec61850_client_example1 +EXAMPLE_DIRS += iec61850_client_example2 +EXAMPLE_DIRS += iec61850_client_example3 +EXAMPLE_DIRS += iec61850_client_example4 +EXAMPLE_DIRS += iec61850_client_example5 +EXAMPLE_DIRS += iec61850_client_example_reporting +EXAMPLE_DIRS += server_example1 +EXAMPLE_DIRS += server_example2 +EXAMPLE_DIRS += server_example3 +EXAMPLE_DIRS += server_example4 +EXAMPLE_DIRS += server_example5 +EXAMPLE_DIRS += server_example_goose +EXAMPLE_DIRS += server_example_control +EXAMPLE_DIRS += server_example_config_file +EXAMPLE_DIRS += server_example_dynamic +EXAMPLE_DIRS += server_example_complex_array +EXAMPLE_DIRS += server_example_61400_25 +EXAMPLE_DIRS += server_example_threadless +EXAMPLE_DIRS += server_example_setting_groups +EXAMPLE_DIRS += goose_subscriber +EXAMPLE_DIRS += goose_publisher +EXAMPLE_DIRS += mms_utility + +MODEL_DIRS += server_example1 +MODEL_DIRS += server_example2 +MODEL_DIRS += server_example3 +MODEL_DIRS += server_example4 +MODEL_DIRS += server_example5 +MODEL_DIRS += server_example_goose +MODEL_DIRS += server_example_control +MODEL_DIRS += server_example_config_file +MODEL_DIRS += server_example_complex_array +MODEL_DIRS += server_example_61400_25 +MODEL_DIRS += server_example_threadless +MODEL_DIRS += server_example_setting_groups + +all: examples + +model: + -for d in $(MODEL_DIRS); do(cd $$d && $(MAKE) model); done + +examples: + -for d in $(EXAMPLE_DIRS); do(cd $$d && $(MAKE)); done + +clean: + -for d in $(EXAMPLE_DIRS); do(cd $$d && $(MAKE) clean); done + diff --git a/examples/goose_publisher/Makefile b/examples/goose_publisher/Makefile new file mode 100644 index 0000000..f3d5a8f --- /dev/null +++ b/examples/goose_publisher/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = goose_publisher_example +PROJECT_SOURCES = goose_publisher_example.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/goose_publisher/goose_publisher_example.c b/examples/goose_publisher/goose_publisher_example.c new file mode 100644 index 0000000..1b6c010 --- /dev/null +++ b/examples/goose_publisher/goose_publisher_example.c @@ -0,0 +1,60 @@ +/* + * goose_publisher_example.c + */ + +#include +#include +#include +#include +#include +#include + +#include "mms_value.h" +#include "goose_publisher.h" +#include "hal_thread.h" + +// has to be executed as root! +int +main(int argc, char** argv) +{ + + LinkedList dataSetValues = LinkedList_create(); + + LinkedList_add(dataSetValues, MmsValue_newIntegerFromInt32(1234)); + LinkedList_add(dataSetValues, MmsValue_newBinaryTime(false)); + LinkedList_add(dataSetValues, MmsValue_newIntegerFromInt32(5678)); + + CommParameters gooseCommParameters; + + gooseCommParameters.appId = 1000; + gooseCommParameters.dstAddress[0] = 0x01; + gooseCommParameters.dstAddress[1] = 0x0c; + gooseCommParameters.dstAddress[2] = 0xcd; + gooseCommParameters.dstAddress[3] = 0x01; + gooseCommParameters.dstAddress[4] = 0x00; + gooseCommParameters.dstAddress[5] = 0x01; + gooseCommParameters.vlanId = 0; + gooseCommParameters.vlanPriority = 4; + + GoosePublisher publisher = GoosePublisher_create(&gooseCommParameters, "eth0"); + + GoosePublisher_setGoCbRef(publisher, "simpleIOGenericIO/LLN0$GO$gcbAnalogValues"); + GoosePublisher_setConfRev(publisher, 1); + GoosePublisher_setDataSetRef(publisher, "simpleIOGenericIO/LLN0$AnalogValues"); + + int i = 0; + + for (i = 0; i < 3; i++) { + Thread_sleep(1000); + + if (GoosePublisher_publish(publisher, dataSetValues) == -1) { + printf("Error sending message!\n"); + } + } + + GoosePublisher_destroy(publisher); +} + + + + diff --git a/examples/goose_subscriber/CMakeLists.txt b/examples/goose_subscriber/CMakeLists.txt new file mode 100644 index 0000000..91724d2 --- /dev/null +++ b/examples/goose_subscriber/CMakeLists.txt @@ -0,0 +1,34 @@ + +set(goose_subscriber_example_SRCS + goose_subscriber_example.c +) + +IF(WIN32) + +IF(WITH_WPCAP) + +set_source_files_properties(${goose_subscriber_example_SRCS} + PROPERTIES LANGUAGE CXX) +add_executable(goose_subscriber_example + ${goose_subscriber_example_SRCS} +) + +target_link_libraries(goose_subscriber_example + iec61850 +) + +ENDIF(WITH_WPCAP) + +ELSE(WIN32) + +add_executable(goose_subscriber_example + ${goose_subscriber_example_SRCS} +) + +target_link_libraries(goose_subscriber_example + iec61850 +) + +ENDIF(WIN32) + + diff --git a/examples/goose_subscriber/Makefile b/examples/goose_subscriber/Makefile new file mode 100644 index 0000000..db54412 --- /dev/null +++ b/examples/goose_subscriber/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = goose_subscriber_example +PROJECT_SOURCES = goose_subscriber_example.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/goose_subscriber/goose_subscriber_example.c b/examples/goose_subscriber/goose_subscriber_example.c new file mode 100644 index 0000000..4295f47 --- /dev/null +++ b/examples/goose_subscriber/goose_subscriber_example.c @@ -0,0 +1,81 @@ +/* + * goose_subscriber_example.c + * + * This is an example for a standalone GOOSE subscriber + * + * Has to be started as root in Linux. + */ + +#include "goose_receiver.h" +#include "hal_thread.h" + +#include +#include +#include + + +static int running = 1; + +void sigint_handler(int signalId) +{ + running = 0; +} + +void +gooseListener(GooseSubscriber subscriber, void* parameter) +{ + printf("GOOSE event:\n"); + printf(" stNum: %u sqNum: %u\n", GooseSubscriber_getStNum(subscriber), + GooseSubscriber_getSqNum(subscriber)); + printf(" timeToLive: %u\n", GooseSubscriber_getTimeAllowedToLive(subscriber)); + printf(" timestamp: %llu\n", GooseSubscriber_getTimestamp(subscriber)); + + MmsValue* values = GooseSubscriber_getDataSetValues(subscriber); + + char buffer[1024]; + + MmsValue_printToBuffer(values, buffer, 1024); + + printf("%s\n", buffer); +} + +int +main(int argc, char** argv) +{ + MmsValue* dataSetValues = MmsValue_createEmptyArray(4); + + int i; + for (i = 0; i < 4; i++) { + MmsValue* dataSetEntry = MmsValue_newBoolean(false); + MmsValue_setElement(dataSetValues, i, dataSetEntry); + } + + GooseReceiver receiver = GooseReceiver_create(); + + if (argc > 1) { + printf("Set interface id: %s\n", argv[1]); + GooseReceiver_setInterfaceId(receiver, argv[1]); + } + else { + printf("Using interface eth0\n"); + GooseReceiver_setInterfaceId(receiver, "eth0"); + } + + GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL); + + GooseSubscriber_setAppId(subscriber, 1000); + + GooseSubscriber_setListener(subscriber, gooseListener, NULL); + + GooseReceiver_addSubscriber(receiver, subscriber); + + GooseReceiver_start(receiver); + + signal(SIGINT, sigint_handler); + + while (running) { + Thread_sleep(100); + } + + GooseSubscriber_destroy(subscriber); +} diff --git a/examples/iec61850_client_example1/CMakeLists.txt b/examples/iec61850_client_example1/CMakeLists.txt new file mode 100644 index 0000000..7d8b750 --- /dev/null +++ b/examples/iec61850_client_example1/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example1_SRCS + client_example1.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example1_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example1 + ${iec61850_client_example1_SRCS} +) + +target_link_libraries(iec61850_client_example1 + iec61850 +) diff --git a/examples/iec61850_client_example1/Makefile b/examples/iec61850_client_example1/Makefile new file mode 100644 index 0000000..4e15977 --- /dev/null +++ b/examples/iec61850_client_example1/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example1 +PROJECT_SOURCES = client_example1.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example1/client_example1.c b/examples/iec61850_client_example1/client_example1.c new file mode 100644 index 0000000..1eb9444 --- /dev/null +++ b/examples/iec61850_client_example1/client_example1.c @@ -0,0 +1,131 @@ +/* + * client_example1.c + * + * This example is intended to be used with server_example3 or server_example_goose. + */ + +#include "iec61850_client.h" + +#include +#include + +#include "hal_thread.h" + +void +reportCallbackFunction(void* parameter, ClientReport report) +{ + MmsValue* dataSetValues = ClientReport_getDataSetValues(report); + + printf("received report for %s\n", ClientReport_getRcbReference(report)); + + int i; + for (i = 0; i < 4; i++) { + ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i); + + if (reason != REASON_NOT_INCLUDED) { + printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i, + MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason); + } + } +} + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + /* read an analog measurement value from server */ + MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX); + + if (value != NULL) { + float fval = MmsValue_toFloat(value); + printf("read float value: %f\n", fval); + MmsValue_delete(value); + } + + /* write a variable to the server */ + value = MmsValue_newVisibleString("libiec61850.com"); + IedConnection_writeObject(con, &error, "simpleIOGenericIO/GGIO1.NamPlt.vendor", IEC61850_FC_DC, value); + + if (error != IED_ERROR_OK) + printf("failed to write simpleIOGenericIO/GGIO1.NamPlt.vendor!\n"); + else + MmsValue_delete(value); + + + /* read data set */ + ClientDataSet clientDataSet = IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.Events", NULL); + + if (clientDataSet == NULL) + printf("failed to read dataset\n"); + + /* Read RCB values */ + ClientReportControlBlock rcb = + IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL); + + + bool rptEna = ClientReportControlBlock_getRptEna(rcb); + + printf("RptEna = %i\n", rptEna); + + /* Install handler for reports */ + IedConnection_installReportHandler(con, "simpleIOGenericIO/LLN0.RP.EventsRCB01", + ClientReportControlBlock_getRptId(rcb), reportCallbackFunction, NULL); + + /* Set trigger options and enable report */ + ClientReportControlBlock_setTrgOps(rcb, TRG_OPT_DATA_UPDATE | TRG_OPT_INTEGRITY | TRG_OPT_GI); + ClientReportControlBlock_setRptEna(rcb, true); + ClientReportControlBlock_setIntgPd(rcb, 5000); + IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_TRG_OPS | RCB_ELEMENT_INTG_PD, true); + + if (error != IED_ERROR_OK) + printf("report activation failed (code: %i)\n", error); + + Thread_sleep(1000); + + /* trigger GI report */ + ClientReportControlBlock_setGI(rcb, true); + IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_GI, true); + + if (error != IED_ERROR_OK) + printf("Error triggering a GI report (code: %i)\n", error); + + Thread_sleep(60000); + + /* disable reporting */ + ClientReportControlBlock_setRptEna(rcb, false); + IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA, true); + + if (error != IED_ERROR_OK) + printf("disable reporting failed (code: %i)\n", error); + + ClientDataSet_destroy(clientDataSet); + + close_connection: + + IedConnection_close(con); + } + else { + printf("Failed to connect to %s:%i\n", hostname, tcpPort); + } + + IedConnection_destroy(con); +} + + diff --git a/examples/iec61850_client_example2/CMakeLists.txt b/examples/iec61850_client_example2/CMakeLists.txt new file mode 100644 index 0000000..f9deba0 --- /dev/null +++ b/examples/iec61850_client_example2/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example2_SRCS + client_example2.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example2_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example2 + ${iec61850_client_example2_SRCS} +) + +target_link_libraries(iec61850_client_example2 + iec61850 +) diff --git a/examples/iec61850_client_example2/Makefile b/examples/iec61850_client_example2/Makefile new file mode 100644 index 0000000..10e5626 --- /dev/null +++ b/examples/iec61850_client_example2/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example2 +PROJECT_SOURCES = client_example2.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example2/client_example2.c b/examples/iec61850_client_example2/client_example2.c new file mode 100644 index 0000000..d199d0a --- /dev/null +++ b/examples/iec61850_client_example2/client_example2.c @@ -0,0 +1,202 @@ +/* + * client_example2.c + * + * This example shows how to browse the data model of an unknown device. + */ + +#include "iec61850_client.h" + +#include +#include + +void +printSpaces(int spaces) +{ + int i; + + for (i = 0; i < spaces; i++) + printf(" "); +} + +void +printDataDirectory(char* doRef, IedConnection con, int spaces) +{ + IedClientError error; + + LinkedList dataAttributes = IedConnection_getDataDirectory(con, &error, doRef); + + //LinkedList dataAttributes = IedConnection_getDataDirectoryByFC(con, &error, doRef, MX); + + if (dataAttributes != NULL) { + LinkedList dataAttribute = LinkedList_getNext(dataAttributes); + + while (dataAttribute != NULL) { + char* daName = (char*) dataAttribute->data; + + printSpaces(spaces); + printf("DA: %s\n", (char*) dataAttribute->data); + + dataAttribute = LinkedList_getNext(dataAttribute); + + char daRef[129]; + sprintf(daRef, "%s.%s", doRef, daName); + printDataDirectory(daRef, con, spaces + 2); + } + + } +} + +int +main(int argc, char** argv) +{ + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + printf("Get logical device list...\n"); + LinkedList deviceList = IedConnection_getLogicalDeviceList(con, &error); + + if (error != IED_ERROR_OK) { + printf("Failed to read device list (error code: %i)\n", error); + goto cleanup_and_exit; + } + + LinkedList device = LinkedList_getNext(deviceList); + + while (device != NULL) { + printf("LD: %s\n", (char*) device->data); + + LinkedList logicalNodes = IedConnection_getLogicalDeviceDirectory(con, &error, + (char*) device->data); + + LinkedList logicalNode = LinkedList_getNext(logicalNodes); + + while (logicalNode != NULL) { + printf(" LN: %s\n", (char*) logicalNode->data); + + char lnRef[129]; + + sprintf(lnRef, "%s/%s", (char*) device->data, (char*) logicalNode->data); + + LinkedList dataObjects = IedConnection_getLogicalNodeDirectory(con, &error, + lnRef, ACSI_CLASS_DATA_OBJECT); + + LinkedList dataObject = LinkedList_getNext(dataObjects); + + while (dataObject != NULL) { + char* dataObjectName = (char*) dataObject->data; + + printf(" DO: %s\n", dataObjectName); + + dataObject = LinkedList_getNext(dataObject); + + char doRef[129]; + + sprintf(doRef, "%s/%s.%s", (char*) device->data, (char*) logicalNode->data, dataObjectName); + + printDataDirectory(doRef, con, 6); + } + + LinkedList_destroy(dataObjects); + + LinkedList dataSets = IedConnection_getLogicalNodeDirectory(con, &error, lnRef, + ACSI_CLASS_DATA_SET); + + LinkedList dataSet = LinkedList_getNext(dataSets); + + while (dataSet != NULL) { + char* dataSetName = (char*) dataSet->data; + bool isDeletable; + char dataSetRef[129]; + sprintf(dataSetRef, "%s.%s", lnRef, dataSetName); + + LinkedList dataSetMembers = IedConnection_getDataSetDirectory(con, &error, dataSetRef, + &isDeletable); + + if (isDeletable) + printf(" Data set: %s (deletable)\n", dataSetName); + else + printf(" Data set: %s (not deletable)\n", dataSetName); + + LinkedList dataSetMemberRef = LinkedList_getNext(dataSetMembers); + + while (dataSetMemberRef != NULL) { + + char* memberRef = (char*) dataSetMemberRef->data; + + printf(" %s\n", memberRef); + + dataSetMemberRef = LinkedList_getNext(dataSetMemberRef); + } + + dataSet = LinkedList_getNext(dataSet); + } + + LinkedList_destroy(dataSets); + + LinkedList reports = IedConnection_getLogicalNodeDirectory(con, &error, lnRef, + ACSI_CLASS_URCB); + + LinkedList report = LinkedList_getNext(reports); + + while (report != NULL) { + char* reportName = (char*) report->data; + + printf(" RP: %s\n", reportName); + + report = LinkedList_getNext(report); + } + + LinkedList_destroy(reports); + + reports = IedConnection_getLogicalNodeDirectory(con, &error, lnRef, + ACSI_CLASS_BRCB); + + report = LinkedList_getNext(reports); + + while (report != NULL) { + char* reportName = (char*) report->data; + + printf(" BR: %s\n", reportName); + + report = LinkedList_getNext(report); + } + + LinkedList_destroy(reports); + + logicalNode = LinkedList_getNext(logicalNode); + } + + LinkedList_destroy(logicalNodes); + + device = LinkedList_getNext(device); + } + + LinkedList_destroy(deviceList); + + IedConnection_close(con); + } + else { + printf("Connection failed!\n"); + } + +cleanup_and_exit: + IedConnection_destroy(con); +} + diff --git a/examples/iec61850_client_example3/CMakeLists.txt b/examples/iec61850_client_example3/CMakeLists.txt new file mode 100644 index 0000000..37b61ff --- /dev/null +++ b/examples/iec61850_client_example3/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example3_SRCS + client_example3.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example3_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example3 + ${iec61850_client_example3_SRCS} +) + +target_link_libraries(iec61850_client_example3 + iec61850 +) diff --git a/examples/iec61850_client_example3/Makefile b/examples/iec61850_client_example3/Makefile new file mode 100644 index 0000000..138d497 --- /dev/null +++ b/examples/iec61850_client_example3/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example3 +PROJECT_SOURCES = client_example3.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example3/client_example3.c b/examples/iec61850_client_example3/client_example3.c new file mode 100644 index 0000000..9c2e014 --- /dev/null +++ b/examples/iec61850_client_example3/client_example3.c @@ -0,0 +1,217 @@ +/* + * client_example3.c + * + * How to control a device ... intended to be used with server_example_control + */ + +#include "iec61850_client.h" +#include "hal_thread.h" + +#include +#include + +static void commandTerminationHandler(void *parameter, ControlObjectClient connection) +{ + + + LastApplError lastApplError = ControlObjectClient_getLastApplError(connection); + + // if lastApplError.error != 0 this indicates a CommandTermination- + if (lastApplError.error != 0) { + printf("Received CommandTermination-.\n"); + printf(" LastApplError: %i\n", lastApplError.error); + printf(" addCause: %i\n", lastApplError.addCause); + } + else + printf("Received CommandTermination+.\n"); +} + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + + /************************ + * Direct control + ***********************/ + + ControlObjectClient control + = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO1", con); + + MmsValue* ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO1 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO1\n"); + } + + MmsValue_delete(ctlVal); + + ControlObjectClient_destroy(control); + + /* Check if status value has changed */ + + MmsValue* stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO1.stVal", IEC61850_FC_ST); + + if (error == IED_ERROR_OK) { + bool state = MmsValue_getBoolean(stVal); + MmsValue_delete(stVal); + + printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state); + } + else { + printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO1 failed!\n"); + } + + + /************************ + * Select before operate + ***********************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO2", con); + + if (ControlObjectClient_select(control)) { + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO2 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO2!\n"); + } + + MmsValue_delete(ctlVal); + } + else { + printf("failed to select simpleIOGenericIO/GGIO1.SPCSO2!\n"); + } + + ControlObjectClient_destroy(control); + + + /**************************************** + * Direct control with enhanced security + ****************************************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO3", con); + + ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL); + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO3 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO3\n"); + } + + MmsValue_delete(ctlVal); + + /* Wait for command termination message */ + Thread_sleep(1000); + + ControlObjectClient_destroy(control); + + /* Check if status value has changed */ + + stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", IEC61850_FC_ST); + + if (error == IED_ERROR_OK) { + bool state = MmsValue_getBoolean(stVal); + + printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state); + + MmsValue_delete(stVal); + } + else { + printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n"); + } + + /*********************************************** + * Select before operate with enhanced security + ***********************************************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO4", con); + + ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL); + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_selectWithValue(control, ctlVal)) { + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO4 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO4!\n"); + } + + } + else { + printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n"); + } + + MmsValue_delete(ctlVal); + + /* Wait for command termination message */ + Thread_sleep(1000); + + ControlObjectClient_destroy(control); + + + /********************************************************************* + * Direct control with enhanced security (expect CommandTermination-) + *********************************************************************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO9", con); + + ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL); + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n"); + } + + MmsValue_delete(ctlVal); + + /* Wait for command termination message */ + Thread_sleep(1000); + + ControlObjectClient_destroy(control); + + + IedConnection_close(con); + } + else { + printf("Connection failed!\n"); + } + + IedConnection_destroy(con); +} + + diff --git a/examples/iec61850_client_example4/CMakeLists.txt b/examples/iec61850_client_example4/CMakeLists.txt new file mode 100644 index 0000000..2c14b05 --- /dev/null +++ b/examples/iec61850_client_example4/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example4_SRCS + client_example4.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example4_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example4 + ${iec61850_client_example4_SRCS} +) + +target_link_libraries(iec61850_client_example4 + iec61850 +) diff --git a/examples/iec61850_client_example4/Makefile b/examples/iec61850_client_example4/Makefile new file mode 100644 index 0000000..9e62f3b --- /dev/null +++ b/examples/iec61850_client_example4/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example4 +PROJECT_SOURCES = client_example4.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example4/client_example4.c b/examples/iec61850_client_example4/client_example4.c new file mode 100644 index 0000000..1b1d461 --- /dev/null +++ b/examples/iec61850_client_example4/client_example4.c @@ -0,0 +1,92 @@ +/* + * client_example4.c + * + * How to create and delete data sets at a remote server. + * + * This example is intended to be used with server_example3 or server_example_goose. + */ + +#include "iec61850_client.h" + +#include +#include + +#include "hal_thread.h" + +static void +printDataSetValues(MmsValue* dataSet) +{ + int i; + for (i = 0; i < 4; i++) { + printf(" GGIO1.AnIn%i.mag.f: %f\n", i, + MmsValue_toFloat(MmsValue_getElement(MmsValue_getElement( + MmsValue_getElement(dataSet, i), 0), 0))); + } +} + +void +reportCallbackFunction(void* parameter, ClientReport report) +{ + MmsValue* dataSetValues = (MmsValue*) parameter; + + printf("received report\n"); + + printDataSetValues(dataSetValues); +} + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + /* Create a new data set at the remote server */ + LinkedList newDataSetEntries = LinkedList_create(); + + LinkedList_add(newDataSetEntries, "simpleIOGenericIO/GGIO1.AnIn1[MX]"); + LinkedList_add(newDataSetEntries, "simpleIOGenericIO/GGIO1.AnIn2[MX]"); + LinkedList_add(newDataSetEntries, "simpleIOGenericIO/GGIO1.AnIn3[MX]"); + LinkedList_add(newDataSetEntries, "simpleIOGenericIO/GGIO1.AnIn4[MX]"); + + IedConnection_createDataSet(con, &error, "simpleIOGenericIO/LLN0.AnalogueValues", newDataSetEntries); + + LinkedList_destroyStatic(newDataSetEntries); + + printf("error: %i\n", error); + + /* read data set */ + ClientDataSet clientDataSet; + + clientDataSet = IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.AnalogueValues", NULL); + + printDataSetValues(ClientDataSet_getValues(clientDataSet)); + + Thread_sleep(1000); + + IedConnection_deleteDataSet(con, &error, "simpleIOGenericIO/LLN0.AnalogueValues"); + + IedConnection_close(con); + } + else { + printf("Failed to connect to %s:%i\n", hostname, tcpPort); + } + + IedConnection_destroy(con); +} + + diff --git a/examples/iec61850_client_example5/CMakeLists.txt b/examples/iec61850_client_example5/CMakeLists.txt new file mode 100644 index 0000000..9c18a24 --- /dev/null +++ b/examples/iec61850_client_example5/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example5_SRCS + client_example5.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example5_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example5 + ${iec61850_client_example5_SRCS} +) + +target_link_libraries(iec61850_client_example5 + iec61850 +) diff --git a/examples/iec61850_client_example5/Makefile b/examples/iec61850_client_example5/Makefile new file mode 100644 index 0000000..8a1449b --- /dev/null +++ b/examples/iec61850_client_example5/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example5 +PROJECT_SOURCES = client_example5.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example5/client_example5.c b/examples/iec61850_client_example5/client_example5.c new file mode 100644 index 0000000..f49c0ab --- /dev/null +++ b/examples/iec61850_client_example5/client_example5.c @@ -0,0 +1,85 @@ +/* + * client_example5.c + * + * - How to change connection parameters of the lower layers of MMS + * - How to use password authentication + * + */ + +#include "iec61850_client.h" + +#include +#include + +#include "hal_thread.h" + + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + /* To change MMS parameters you need to get access to the underlying MmsConnection */ + MmsConnection mmsConnection = IedConnection_getMmsConnection(con); + + /* Get the container for the parameters */ + IsoConnectionParameters parameters = MmsConnection_getIsoConnectionParameters(mmsConnection); + + /* set remote AP-Title according to SCL file example from IEC 61850-8-1 */ + IsoConnectionParameters_setRemoteApTitle(parameters, "1.3.9999.13", 12); + + /* just some arbitrary numbers */ + IsoConnectionParameters_setLocalApTitle(parameters, "1.2.1200.15.3", 1); + + /* use this to skip AP-Title completely - this may be required by some "obscure" servers */ +// IsoConnectionParameters_setRemoteApTitle(parameters, NULL, 0); +// IsoConnectionParameters_setLocalApTitle(parameters, NULL, 0); + + TSelector localTSelector = { 3, { 0x00, 0x01, 0x02 } }; + TSelector remoteTSelector = { 2, { 0x00, 0x01 } }; + + /* change parameters for presentation, session and transport layers */ + IsoConnectionParameters_setRemoteAddresses(parameters, 0x12345678, 12, localTSelector); + IsoConnectionParameters_setLocalAddresses(parameters, 0x87654321, 1234 , remoteTSelector); + + char* password = "top secret"; + + /* use authentication */ + AcseAuthenticationParameter auth = (AcseAuthenticationParameter) calloc(1, sizeof(struct sAcseAuthenticationParameter)); + auth->mechanism = ACSE_AUTH_PASSWORD; + auth->value.password.octetString = (uint8_t*) password; + auth->value.password.passwordLength = strlen(password); + + IsoConnectionParameters_setAcseAuthenticationParameter(parameters, auth); + + IedConnection_setConnectTimeout(con, 10000); + + /* call connect when all parameters are set */ + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + Thread_sleep(1000); + + IedConnection_abort(con, &error); + } + else { + printf("Failed to connect to %s:%i\n", hostname, tcpPort); + } + + IedConnection_destroy(con); +} + + diff --git a/examples/iec61850_client_example_files/CMakeLists.txt b/examples/iec61850_client_example_files/CMakeLists.txt new file mode 100644 index 0000000..10b7ab0 --- /dev/null +++ b/examples/iec61850_client_example_files/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example_files_SRCS + client_example_files.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example_files_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example_files + ${iec61850_client_example_files_SRCS} +) + +target_link_libraries(iec61850_client_example_files + iec61850 +) diff --git a/examples/iec61850_client_example_files/Makefile b/examples/iec61850_client_example_files/Makefile new file mode 100644 index 0000000..eea5d9f --- /dev/null +++ b/examples/iec61850_client_example_files/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example_files +PROJECT_SOURCES = client_example_files.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example_files/client_example_files.c b/examples/iec61850_client_example_files/client_example_files.c new file mode 100644 index 0000000..33c6750 --- /dev/null +++ b/examples/iec61850_client_example_files/client_example_files.c @@ -0,0 +1,104 @@ +/* + * client_example_files.c + * + * This example demonstrates the usage of the file services + * + * - How to browse the file system of the server + * - How to download a file from the server + * + * Note: intended to be used with server_example3 + * + */ + +#include "iec61850_client.h" + +#include +#include + +#include "hal_thread.h" + +#define MAX_BUFFER_SIZE 2000000 + +static uint8_t downloadBuffer[MAX_BUFFER_SIZE]; +static int bufferPosition = 0; + +static bool +downloadHandler(void* parameter, uint8_t* buffer, uint32_t bytesRead) +{ + printf("received %i bytes\n", bytesRead); + + if (bufferPosition + bytesRead < MAX_BUFFER_SIZE) { + memcpy(downloadBuffer + bufferPosition, buffer, bytesRead); + return true; + } + else + return false; +} + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + /* Get the root directory */ + LinkedList rootDirectory = + IedConnection_getFileDirectory(con, &error, NULL); + + if (error != IED_ERROR_OK) { + printf("Error retrieving file directory\n"); + goto abort_connection; + } + + + LinkedList directoryEntry = LinkedList_getNext(rootDirectory); + + while (directoryEntry != NULL) { + + FileDirectoryEntry entry = (FileDirectoryEntry) directoryEntry->data; + + printf("%s %i\n", FileDirectoryEntry_getFileName(entry), FileDirectoryEntry_getFileSize(entry)); + + directoryEntry = LinkedList_getNext(directoryEntry); + } + + + /* Download a file from the server */ + IedConnection_getFile(con, &error, "IEDSERVER.BIN", downloadHandler, NULL); + + if (error != IED_ERROR_OK) + printf("Failed to get file!\n"); + + /* Delete file at server */ + IedConnection_deleteFile(con, &error, "IEDSERVER.BIN"); + + if (error != IED_ERROR_OK) + printf("Failed to delete file! (code=%i)\n", error); + + abort_connection: + + IedConnection_abort(con, &error); + } + else { + printf("Failed to connect to %s:%i\n", hostname, tcpPort); + } + + IedConnection_destroy(con); +} + + diff --git a/examples/iec61850_client_example_reporting/CMakeLists.txt b/examples/iec61850_client_example_reporting/CMakeLists.txt new file mode 100644 index 0000000..621f129 --- /dev/null +++ b/examples/iec61850_client_example_reporting/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(iec61850_client_example_reporting_SRCS + client_example_reporting.c +) + +IF(WIN32) +set_source_files_properties(${iec61850_client_example_reporting_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(iec61850_client_example_reporting + ${iec61850_client_example_reporting_SRCS} +) + +target_link_libraries(iec61850_client_example_reporting + iec61850 +) diff --git a/examples/iec61850_client_example_reporting/Makefile b/examples/iec61850_client_example_reporting/Makefile new file mode 100644 index 0000000..44d9bc1 --- /dev/null +++ b/examples/iec61850_client_example_reporting/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = client_example_reporting +PROJECT_SOURCES = client_example_reporting.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/iec61850_client_example_reporting/client_example_reporting.c b/examples/iec61850_client_example_reporting/client_example_reporting.c new file mode 100644 index 0000000..ba119f0 --- /dev/null +++ b/examples/iec61850_client_example_reporting/client_example_reporting.c @@ -0,0 +1,168 @@ +/* + * client_example_reporting.c + * + * This example is intended to be used with server_example3 or server_example_goose. + */ + +#include "iec61850_client.h" + +#include +#include +#include +#include + +#include "hal_thread.h" + +static int running = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + + +void +reportCallbackFunction(void* parameter, ClientReport report) +{ + LinkedList dataSetDirectory = (LinkedList) parameter; + + MmsValue* dataSetValues = ClientReport_getDataSetValues(report); + + printf("received report for %s with rptId %s\n", ClientReport_getRcbReference(report), ClientReport_getRptId(report)); + + if (ClientReport_hasTimestamp(report)) { + time_t unixTime = ClientReport_getTimestamp(report) / 1000; + +#ifdef WIN32 + char* timeBuf = ctime(&unixTime); +#else + char timeBuf[30]; + ctime_r(&unixTime, timeBuf); +#endif + + printf(" report contains timestamp (%u):", (unsigned int) unixTime); + printf("%s \n", timeBuf); + } + + int i; + for (i = 0; i < LinkedList_size(dataSetDirectory); i++) { + ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i); + + if (reason != REASON_NOT_INCLUDED) { + + LinkedList entry = LinkedList_get(dataSetDirectory, i); + + char* entryName = (char*) entry->data; + + printf(" %s (included for reason %i)\n", entryName, reason); + } + } +} + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + running = 1; + + signal(SIGINT, sigint_handler); + + IedClientError error; + + IedConnection con = IedConnection_create(); + + IedConnection_connect(con, &error, hostname, tcpPort); + + if (error == IED_ERROR_OK) { + + /* read data set directory */ + LinkedList dataSetDirectory = + IedConnection_getDataSetDirectory(con, &error, "simpleIOGenericIO/LLN0.Events", NULL); + + if (error != IED_ERROR_OK) { + printf("Reading data set directory failed!\n"); + goto exit_error; + } + + /* read data set */ + ClientDataSet clientDataSet; + + clientDataSet = IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.Events", NULL); + + if (clientDataSet == NULL) { + printf("failed to read dataset\n"); + goto exit_error; + } + + /* Read RCB values */ + ClientReportControlBlock rcb = + IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL); + + if (error != IED_ERROR_OK) { + printf("getRCBValues service error!\n"); + goto exit_error; + } + + /* prepare the parameters of the RCP */ + ClientReportControlBlock_setResv(rcb, true); + ClientReportControlBlock_setDataSetReference(rcb, "simpleIOGenericIO/LLN0$Events"); /* NOTE the "$" instead of "." ! */ + ClientReportControlBlock_setRptEna(rcb, true); + + /* Configure the report receiver */ + IedConnection_installReportHandler(con, "simpleIOGenericIO/LLN0.RP.EventsRCB", ClientReportControlBlock_getRptId(rcb), reportCallbackFunction, + (void*) dataSetDirectory); + + /* Write RCB parameters and enable report */ + IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_RPT_ENA, true); + + if (error != IED_ERROR_OK) { + printf("setRCBValues service error!\n"); + goto exit_error; + } + + Thread_sleep(1000); + + IedConnection_triggerGIReport(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01"); + + if (error != IED_ERROR_OK) { + printf("Error triggering a GI report (code: %i)\n", error); + } + + while (running) { + Thread_sleep(10); + + IedConnectionState conState = IedConnection_getState(con); + + if (conState != IED_STATE_CONNECTED) { + printf("Connection closed by server!\n"); + running = 0; + } + } + + exit_error: + + /* disable reporting */ + ClientReportControlBlock_setRptEna(rcb, false); + IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA, true); + + ClientDataSet_destroy(clientDataSet); + + IedConnection_close(con); + } + else { + printf("Failed to connect to %s:%i\n", hostname, tcpPort); + } + + IedConnection_destroy(con); +} + + diff --git a/examples/mms_client_example1/CMakeLists.txt b/examples/mms_client_example1/CMakeLists.txt new file mode 100644 index 0000000..5f5a027 --- /dev/null +++ b/examples/mms_client_example1/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(mms_client_example1_SRCS + mms_client_example1.c +) + +IF(WIN32) +set_source_files_properties(${mms_client_example1_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(mms_client_example1 + ${mms_client_example1_SRCS} +) + +target_link_libraries(mms_client_example1 + iec61850 +) diff --git a/examples/mms_client_example1/Makefile b/examples/mms_client_example1/Makefile new file mode 100644 index 0000000..0e1aeff --- /dev/null +++ b/examples/mms_client_example1/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = mms_client_example1 +PROJECT_SOURCES = mms_client_example1.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/mms_client_example1/mms_client_example1.c b/examples/mms_client_example1/mms_client_example1.c new file mode 100644 index 0000000..d8ad47c --- /dev/null +++ b/examples/mms_client_example1/mms_client_example1.c @@ -0,0 +1,51 @@ +/* + * mms_client_example.c + * + * This is the most simple example. It illustrates how to create an MmsConnection + * object and connect to a MMS server. + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include +#include "mms_client_connection.h" +#include "hal_thread.h" + +int main(int argc, char** argv) { + + MmsConnection con = MmsConnection_create(); + + MmsError mmsError; + + if (MmsConnection_connect(con, &mmsError, "localhost", 102)) { + // add application code here + + Thread_sleep(1000); + + printf("Send abort\n"); + MmsConnection_abort(con, &mmsError); + } + else + printf("Connect to server failed!\n"); + + MmsConnection_destroy(con); +} + diff --git a/examples/mms_client_example2/CMakeLists.txt b/examples/mms_client_example2/CMakeLists.txt new file mode 100644 index 0000000..b56f7a5 --- /dev/null +++ b/examples/mms_client_example2/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(mms_client_example2_SRCS + mms_client_example2.c +) + +IF(WIN32) +set_source_files_properties(${mms_client_example2_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(mms_client_example2 + ${mms_client_example2_SRCS} +) + +target_link_libraries(mms_client_example2 + iec61850 +) diff --git a/examples/mms_client_example2/Makefile b/examples/mms_client_example2/Makefile new file mode 100644 index 0000000..47f3467 --- /dev/null +++ b/examples/mms_client_example2/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = mms_client_example2 +PROJECT_SOURCES = mms_client_example2.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/mms_client_example2/mms_client_example2.c b/examples/mms_client_example2/mms_client_example2.c new file mode 100644 index 0000000..908cb91 --- /dev/null +++ b/examples/mms_client_example2/mms_client_example2.c @@ -0,0 +1,64 @@ + +#include +#include +#include "mms_client_connection.h" + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + MmsConnection con = MmsConnection_create(); + + MmsError mmsError; + + /* Set maximum MMS PDU size (local detail) to 2000 byte */ + MmsConnection_setLocalDetail(con, 2000); + + if (!MmsConnection_connect(con, &mmsError, hostname, tcpPort)) { + printf("MMS connect failed!\n"); + goto exit; + } + else + printf("MMS connected.\n\n"); + + printf("Domains present on server:\n--------------------------\n"); + LinkedList nameList = MmsConnection_getDomainNames(con, &mmsError); + LinkedList_printStringList(nameList); + printf("\n"); + + LinkedList element = nameList; + + while ((element = LinkedList_getNext(element)) != NULL) { + printf("\nNamed variables in domain: %s\n-------------------------------------------------\n", (char*) element->data); + + LinkedList variableList = MmsConnection_getDomainVariableNames(con, &mmsError, (char*) element->data); + + LinkedList_printStringList(variableList); + + LinkedList_destroy(variableList); + + printf("\nNamed variable lists (data sets) in domain: %s\n", (char*) element->data); + + LinkedList dataSetList = MmsConnection_getDomainVariableListNames(con, &mmsError, (char*) element->data); + + LinkedList_printStringList(dataSetList); + + LinkedList_destroy(dataSetList); + + } + + LinkedList_destroy(nameList); + +exit: + MmsConnection_destroy(con); +} + diff --git a/examples/mms_client_example3/CMakeLists.txt b/examples/mms_client_example3/CMakeLists.txt new file mode 100644 index 0000000..4a5cab0 --- /dev/null +++ b/examples/mms_client_example3/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(mms_client_example3_SRCS + mms_client_example3.c +) + +IF(WIN32) +set_source_files_properties(${mms_client_example3_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(mms_client_example3 + ${mms_client_example3_SRCS} +) + +target_link_libraries(mms_client_example3 + iec61850 +) diff --git a/examples/mms_client_example3/Makefile b/examples/mms_client_example3/Makefile new file mode 100644 index 0000000..eb6fa6c --- /dev/null +++ b/examples/mms_client_example3/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = mms_client_example3 +PROJECT_SOURCES = mms_client_example3.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/mms_client_example3/mms_client_example3.c b/examples/mms_client_example3/mms_client_example3.c new file mode 100644 index 0000000..eb04c1c --- /dev/null +++ b/examples/mms_client_example3/mms_client_example3.c @@ -0,0 +1,41 @@ + +#include +#include +#include "mms_client_connection.h" + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + MmsConnection con = MmsConnection_create(); + + MmsError error; + + if (!MmsConnection_connect(con, &error, hostname, tcpPort)) { + printf("MMS connect failed!\n"); + goto exit; + } + else + printf("MMS connected.\n\n"); + + MmsValue* value = + MmsConnection_readVariable(con, &error, "simpleIOGenericIO", "LLN0$GO"); + + if (value == NULL) + printf("reading value failed!\n"); + else + MmsValue_delete(value); + +exit: + MmsConnection_destroy(con); +} + diff --git a/examples/mms_client_example4/CMakeLists.txt b/examples/mms_client_example4/CMakeLists.txt new file mode 100644 index 0000000..6335c59 --- /dev/null +++ b/examples/mms_client_example4/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(mms_client_example4_SRCS + mms_client_example4.c +) + +IF(WIN32) +set_source_files_properties(${mms_client_example4_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(mms_client_example4 + ${mms_client_example4_SRCS} +) + +target_link_libraries(mms_client_example4 + iec61850 +) diff --git a/examples/mms_client_example4/Makefile b/examples/mms_client_example4/Makefile new file mode 100644 index 0000000..30451ce --- /dev/null +++ b/examples/mms_client_example4/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = mms_client_example4 +PROJECT_SOURCES = mms_client_example4.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/mms_client_example4/mms_client_example4.c b/examples/mms_client_example4/mms_client_example4.c new file mode 100644 index 0000000..13a8d22 --- /dev/null +++ b/examples/mms_client_example4/mms_client_example4.c @@ -0,0 +1,87 @@ +/* + * mms_client_example.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include +#include "mms_client_connection.h" + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + MmsConnection con = MmsConnection_create(); + + MmsError mmsError; + + char* password = "testpw"; + + /* use authentication */ + AcseAuthenticationParameter auth = (AcseAuthenticationParameter) calloc(1, sizeof(struct sAcseAuthenticationParameter)); + auth->mechanism = ACSE_AUTH_PASSWORD; + auth->value.password.octetString= (uint8_t*) password; + auth->value.password.passwordLength = strlen(password); + + IsoConnectionParameters connectionParameters = + MmsConnection_getIsoConnectionParameters(con); + + IsoConnectionParameters_setAcseAuthenticationParameter(connectionParameters, auth); + + if (!MmsConnection_connect(con, &mmsError, hostname, tcpPort)) { + printf("MMS connect failed!\n"); + goto exit; + } + else + printf("MMS connected.\n\n"); + + printf("Domains present on server:\n--------------------------\n"); + LinkedList nameList = MmsConnection_getDomainNames(con, &mmsError); + LinkedList_printStringList(nameList); + LinkedList_destroy(nameList); + printf("\n"); + + + printf("Named variables for domain SampleIEDDevice1:\n--------------------------------------------\n"); + nameList = MmsConnection_getDomainVariableNames(con, &mmsError, "SampleIEDDevice1"); + LinkedList_printStringList(nameList); + LinkedList_destroy(nameList); + printf("\n"); + + printf("Data sets for domain SampleIEDDevice1:\n--------------------------------------------\n"); + nameList = MmsConnection_getDomainVariableListNames(con, &mmsError, "SampleIEDDevice1"); + LinkedList_printStringList(nameList); + LinkedList_destroy(nameList); + printf("\n"); + +exit: + MmsConnection_destroy(con); +} + diff --git a/examples/mms_client_example5/CMakeLists.txt b/examples/mms_client_example5/CMakeLists.txt new file mode 100644 index 0000000..fdc6f0a --- /dev/null +++ b/examples/mms_client_example5/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(mms_client_example5_SRCS + mms_client_example5.c +) + +IF(WIN32) +set_source_files_properties(${mms_client_example5_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(mms_client_example5 + ${mms_client_example5_SRCS} +) + +target_link_libraries(mms_client_example5 + iec61850 +) diff --git a/examples/mms_client_example5/Makefile b/examples/mms_client_example5/Makefile new file mode 100644 index 0000000..72d220c --- /dev/null +++ b/examples/mms_client_example5/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = mms_client_example5 +PROJECT_SOURCES = mms_client_example5.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/mms_client_example5/mms_client_example5.c b/examples/mms_client_example5/mms_client_example5.c new file mode 100644 index 0000000..ae05040 --- /dev/null +++ b/examples/mms_client_example5/mms_client_example5.c @@ -0,0 +1,50 @@ + +#include +#include +#include "mms_client_connection.h" + +int main(int argc, char** argv) { + + char* hostname; + int tcpPort = 102; + + if (argc > 1) + hostname = argv[1]; + else + hostname = "localhost"; + + if (argc > 2) + tcpPort = atoi(argv[2]); + + MmsConnection con = MmsConnection_create(); + + MmsError error; + + if (!MmsConnection_connect(con, &error, hostname, tcpPort)) { + printf("MMS connect failed!\n"); + goto exit; + } + else + printf("MMS connected.\n\n"); + + LinkedList dataSetEntries = LinkedList_create(); + + MmsVariableAccessSpecification* dataSetEntry = + MmsVariableAccessSpecification_create("BayControllerQ", "QA1CSWI1$ST$Pos"); + + LinkedList_add(dataSetEntries, (void*) dataSetEntry); + + dataSetEntry = + MmsVariableAccessSpecification_create("BayControllerQ", "QA1XCBR1$ST$Pos"); + + LinkedList_add(dataSetEntries, (void*) dataSetEntry); + + MmsConnection_defineNamedVariableList(con, &error, "BayControllerQ", "LLN0$LIBIEC61850_CLIENT", dataSetEntries); + + /* delete list and all elements */ + LinkedList_destroy(dataSetEntries); + +exit: + MmsConnection_destroy(con); +} + diff --git a/examples/mms_utility/CMakeLists.txt b/examples/mms_utility/CMakeLists.txt new file mode 100644 index 0000000..ddc157e --- /dev/null +++ b/examples/mms_utility/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(mms_utility_SRCS + mms_utility.c +) + +IF(WIN32) +set_source_files_properties(${mms_utility_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(mms_utility + ${mms_utility_SRCS} +) + +target_link_libraries(mms_utility + iec61850 +) diff --git a/examples/mms_utility/Makefile b/examples/mms_utility/Makefile new file mode 100644 index 0000000..0adeacc --- /dev/null +++ b/examples/mms_utility/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = mms_utility +PROJECT_SOURCES = mms_utility.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/mms_utility/mms_utility.c b/examples/mms_utility/mms_utility.c new file mode 100644 index 0000000..b59d333 --- /dev/null +++ b/examples/mms_utility/mms_utility.c @@ -0,0 +1,115 @@ + +#include +#include +#include +#include "string_utilities.h" +#include "mms_client_connection.h" + +static void +print_help() +{ + printf("MMS utility (libiec61850 v0.5) options:\n"); + printf("-h specify hostname\n"); + printf("-p specify port\n"); + printf("-l specify maximum PDU size\n"); + printf("-d show list of MMS domains\n"); + printf("-i show server identity\n"); + printf("-t show domain directory\n"); +} + +int main(int argc, char** argv) { + + char* hostname = copyString("localhost"); + int tcpPort = 102; + int maxPduSize = 65000; + + char* domainName = NULL; + + int readDeviceList = 0; + int getDeviceDirectory = 0; + int identifyDevice = 0; + + int c; + + while ((c = getopt(argc, argv, "idh:p:l:t:")) != -1) + switch (c) { + case 'h': + hostname = copyString(optarg); + break; + case 'p': + tcpPort = atoi(optarg); + break; + case 'l': + maxPduSize = atoi(optarg); + break; + case 'd': + readDeviceList = 1; + break; + case 'i': + identifyDevice = 1; + break; + case 't': + getDeviceDirectory = 1; + domainName = copyString(optarg); + break; + default: + print_help(); + return 0; + } + + MmsConnection con = MmsConnection_create(); + + MmsError error; + + /* Set maximum MMS PDU size (local detail) to 2000 byte */ + MmsConnection_setLocalDetail(con, maxPduSize); + + if (!MmsConnection_connect(con, &error, hostname, tcpPort)) { + printf("MMS connect failed!\n"); + goto exit; + } + else + printf("MMS connected.\n"); + + if (identifyDevice) { + MmsServerIdentity* identity = + MmsConnection_identify(con, &error); + + if (identity != NULL) { + printf("\nServer identity:\n----------------\n"); + printf(" vendor:\t%s\n", identity->vendorName); + printf(" model:\t%s\n", identity->modelName); + printf(" revision:\t%s\n", identity->revision); + } + else + printf("Reading server identity failed!\n"); + } + + if (readDeviceList) { + printf("\nDomains present on server:\n--------------------------\n"); + LinkedList nameList = MmsConnection_getDomainNames(con, &error); + LinkedList_printStringList(nameList); + LinkedList_destroy(nameList); + } + + if (getDeviceDirectory) { + LinkedList variableList = MmsConnection_getDomainVariableNames(con, &error, + domainName); + + LinkedList element = variableList; + + printf("\nMMS domain variables for domain %s\n", domainName); + + while ((element = LinkedList_getNext(element)) != NULL) { + char* name = (char*) element->data; + + if (strchr(name, '$') == NULL) + printf(" %s\n", name); + } + + } + +exit: + MmsConnection_destroy(con); +} + diff --git a/examples/server_example1/CMakeLists.txt b/examples/server_example1/CMakeLists.txt new file mode 100644 index 0000000..3521090 --- /dev/null +++ b/examples/server_example1/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example1_SRCS + server_example1.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example1_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example1 + ${server_example1_SRCS} +) + +target_link_libraries(server_example1 + iec61850 +) diff --git a/examples/server_example1/Makefile b/examples/server_example1/Makefile new file mode 100644 index 0000000..0643046 --- /dev/null +++ b/examples/server_example1/Makefile @@ -0,0 +1,25 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example1 +PROJECT_SOURCES = server_example1.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = sampleModel_with_dataset.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example1/sampleModel_with_dataset.icd b/examples/server_example1/sampleModel_with_dataset.icd new file mode 100644 index 0000000..9b2c0fc --- /dev/null +++ b/examples/server_example1/sampleModel_with_dataset.icd @@ -0,0 +1,184 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + diff --git a/examples/server_example1/server_example1.c b/examples/server_example1/server_example1.c new file mode 100644 index 0000000..14a0b2a --- /dev/null +++ b/examples/server_example1/server_example1.c @@ -0,0 +1,78 @@ +/* + * server_example1.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + +int main(int argc, char** argv) { + + int tcpPort = 102; + + if (argc > 1) { + tcpPort = atoi(argv[1]); + } + + IedServer iedServer = IedServer_create(&iedModel); + + // get stored values from persistent storage + + // set initial measurement and status values from process + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, tcpPort); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + while (running) { + Thread_sleep(1); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example1/static_model.c b/examples/server_example1/static_model.c new file mode 100644 index 0000000..88e51ab --- /dev/null +++ b/examples/server_example1/static_model.c @@ -0,0 +1,1754 @@ +/* + * static_model.c + * + * automatically generated from sampleModel_with_dataset.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_Device1; +extern LogicalNode iedModel_Device1_LLN0; +extern DataObject iedModel_Device1_LLN0_Mod; +extern DataAttribute iedModel_Device1_LLN0_Mod_q; +extern DataAttribute iedModel_Device1_LLN0_Mod_t; +extern DataAttribute iedModel_Device1_LLN0_Mod_ctlModel; +extern DataObject iedModel_Device1_LLN0_Beh; +extern DataAttribute iedModel_Device1_LLN0_Beh_stVal; +extern DataAttribute iedModel_Device1_LLN0_Beh_q; +extern DataAttribute iedModel_Device1_LLN0_Beh_t; +extern DataObject iedModel_Device1_LLN0_Health; +extern DataAttribute iedModel_Device1_LLN0_Health_stVal; +extern DataAttribute iedModel_Device1_LLN0_Health_q; +extern DataAttribute iedModel_Device1_LLN0_Health_t; +extern DataObject iedModel_Device1_LLN0_NamPlt; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_d; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Device1_LPHD1; +extern DataObject iedModel_Device1_LPHD1_PhyNam; +extern DataAttribute iedModel_Device1_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Device1_LPHD1_PhyHealth; +extern DataAttribute iedModel_Device1_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Device1_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Device1_LPHD1_PhyHealth_t; +extern DataObject iedModel_Device1_LPHD1_Proxy; +extern DataAttribute iedModel_Device1_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Device1_LPHD1_Proxy_q; +extern DataAttribute iedModel_Device1_LPHD1_Proxy_t; +extern LogicalNode iedModel_Device1_DGEN1; +extern DataObject iedModel_Device1_DGEN1_Mod; +extern DataAttribute iedModel_Device1_DGEN1_Mod_q; +extern DataAttribute iedModel_Device1_DGEN1_Mod_t; +extern DataAttribute iedModel_Device1_DGEN1_Mod_ctlModel; +extern DataObject iedModel_Device1_DGEN1_Beh; +extern DataAttribute iedModel_Device1_DGEN1_Beh_stVal; +extern DataAttribute iedModel_Device1_DGEN1_Beh_q; +extern DataAttribute iedModel_Device1_DGEN1_Beh_t; +extern DataObject iedModel_Device1_DGEN1_Health; +extern DataAttribute iedModel_Device1_DGEN1_Health_stVal; +extern DataAttribute iedModel_Device1_DGEN1_Health_q; +extern DataAttribute iedModel_Device1_DGEN1_Health_t; +extern DataObject iedModel_Device1_DGEN1_NamPlt; +extern DataAttribute iedModel_Device1_DGEN1_NamPlt_vendor; +extern DataAttribute iedModel_Device1_DGEN1_NamPlt_swRev; +extern DataAttribute iedModel_Device1_DGEN1_NamPlt_d; +extern DataObject iedModel_Device1_DGEN1_OpTmh; +extern DataAttribute iedModel_Device1_DGEN1_OpTmh_stVal; +extern DataAttribute iedModel_Device1_DGEN1_OpTmh_q; +extern DataAttribute iedModel_Device1_DGEN1_OpTmh_t; +extern DataObject iedModel_Device1_DGEN1_GnOpSt; +extern DataAttribute iedModel_Device1_DGEN1_GnOpSt_stVal; +extern DataAttribute iedModel_Device1_DGEN1_GnOpSt_q; +extern DataAttribute iedModel_Device1_DGEN1_GnOpSt_t; +extern DataObject iedModel_Device1_DGEN1_OpTmsRs; +extern DataAttribute iedModel_Device1_DGEN1_OpTmsRs_stVal; +extern DataAttribute iedModel_Device1_DGEN1_OpTmsRs_q; +extern DataAttribute iedModel_Device1_DGEN1_OpTmsRs_t; +extern DataObject iedModel_Device1_DGEN1_TotWh; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_mag; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_mag_f; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_q; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_t; +extern LogicalNode iedModel_Device1_DSCH1; +extern DataObject iedModel_Device1_DSCH1_Mod; +extern DataAttribute iedModel_Device1_DSCH1_Mod_q; +extern DataAttribute iedModel_Device1_DSCH1_Mod_t; +extern DataAttribute iedModel_Device1_DSCH1_Mod_ctlModel; +extern DataObject iedModel_Device1_DSCH1_Beh; +extern DataAttribute iedModel_Device1_DSCH1_Beh_stVal; +extern DataAttribute iedModel_Device1_DSCH1_Beh_q; +extern DataAttribute iedModel_Device1_DSCH1_Beh_t; +extern DataObject iedModel_Device1_DSCH1_Health; +extern DataAttribute iedModel_Device1_DSCH1_Health_stVal; +extern DataAttribute iedModel_Device1_DSCH1_Health_q; +extern DataAttribute iedModel_Device1_DSCH1_Health_t; +extern DataObject iedModel_Device1_DSCH1_NamPlt; +extern DataAttribute iedModel_Device1_DSCH1_NamPlt_vendor; +extern DataAttribute iedModel_Device1_DSCH1_NamPlt_swRev; +extern DataAttribute iedModel_Device1_DSCH1_NamPlt_d; +extern DataObject iedModel_Device1_DSCH1_SchdSt; +extern DataAttribute iedModel_Device1_DSCH1_SchdSt_stVal; +extern DataAttribute iedModel_Device1_DSCH1_SchdSt_q; +extern DataAttribute iedModel_Device1_DSCH1_SchdSt_t; +extern DataObject iedModel_Device1_DSCH1_SchdId; +extern DataObject iedModel_Device1_DSCH1_SchdCat; +extern DataObject iedModel_Device1_DSCH1_SchdTyp; +extern DataObject iedModel_Device1_DSCH1_SchdAbsTm; +extern DataAttribute iedModel_Device1_DSCH1_SchdAbsTm_val; +extern DataAttribute iedModel_Device1_DSCH1_SchdAbsTm_time; +extern LogicalNode iedModel_Device1_MMXU1; +extern DataObject iedModel_Device1_MMXU1_Mod; +extern DataAttribute iedModel_Device1_MMXU1_Mod_q; +extern DataAttribute iedModel_Device1_MMXU1_Mod_t; +extern DataAttribute iedModel_Device1_MMXU1_Mod_ctlModel; +extern DataObject iedModel_Device1_MMXU1_Beh; +extern DataAttribute iedModel_Device1_MMXU1_Beh_stVal; +extern DataAttribute iedModel_Device1_MMXU1_Beh_q; +extern DataAttribute iedModel_Device1_MMXU1_Beh_t; +extern DataObject iedModel_Device1_MMXU1_Health; +extern DataAttribute iedModel_Device1_MMXU1_Health_stVal; +extern DataAttribute iedModel_Device1_MMXU1_Health_q; +extern DataAttribute iedModel_Device1_MMXU1_Health_t; +extern DataObject iedModel_Device1_MMXU1_NamPlt; +extern DataAttribute iedModel_Device1_MMXU1_NamPlt_vendor; +extern DataAttribute iedModel_Device1_MMXU1_NamPlt_swRev; +extern DataAttribute iedModel_Device1_MMXU1_NamPlt_d; +extern LogicalNode iedModel_Device1_MMXU2; +extern DataObject iedModel_Device1_MMXU2_Mod; +extern DataAttribute iedModel_Device1_MMXU2_Mod_q; +extern DataAttribute iedModel_Device1_MMXU2_Mod_t; +extern DataAttribute iedModel_Device1_MMXU2_Mod_ctlModel; +extern DataObject iedModel_Device1_MMXU2_Beh; +extern DataAttribute iedModel_Device1_MMXU2_Beh_stVal; +extern DataAttribute iedModel_Device1_MMXU2_Beh_q; +extern DataAttribute iedModel_Device1_MMXU2_Beh_t; +extern DataObject iedModel_Device1_MMXU2_Health; +extern DataAttribute iedModel_Device1_MMXU2_Health_stVal; +extern DataAttribute iedModel_Device1_MMXU2_Health_q; +extern DataAttribute iedModel_Device1_MMXU2_Health_t; +extern DataObject iedModel_Device1_MMXU2_NamPlt; +extern DataAttribute iedModel_Device1_MMXU2_NamPlt_vendor; +extern DataAttribute iedModel_Device1_MMXU2_NamPlt_swRev; +extern DataAttribute iedModel_Device1_MMXU2_NamPlt_d; +extern DataObject iedModel_Device1_MMXU2_TotW; +extern DataAttribute iedModel_Device1_MMXU2_TotW_mag; +extern DataAttribute iedModel_Device1_MMXU2_TotW_mag_f; +extern DataAttribute iedModel_Device1_MMXU2_TotW_q; +extern DataAttribute iedModel_Device1_MMXU2_TotW_t; + +extern DataSet ds_Device1_LLN0_dataset1; + + +extern DataSetEntry ds_Device1_LLN0_dataset1_fcda0; +extern DataSetEntry ds_Device1_LLN0_dataset1_fcda1; +extern DataSetEntry ds_Device1_LLN0_dataset1_fcda2; + +DataSetEntry ds_Device1_LLN0_dataset1_fcda0 = { + "Device1", + false, + "LLN0$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Device1_LLN0_dataset1_fcda1 +}; + +DataSetEntry ds_Device1_LLN0_dataset1_fcda1 = { + "Device1", + false, + "MMXU1$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Device1_LLN0_dataset1_fcda2 +}; + +DataSetEntry ds_Device1_LLN0_dataset1_fcda2 = { + "Device1", + false, + "MMXU1$CF$Mod$ctlModel", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_Device1_LLN0_dataset1 = { + "Device1", + "LLN0$dataset1", + 3, + &ds_Device1_LLN0_dataset1_fcda0, + NULL +}; + +LogicalDevice iedModel_Device1 = { + LogicalDeviceModelType, + "Device1", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_Device1_LLN0 +}; + +LogicalNode iedModel_Device1_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Device1, + (ModelNode*) &iedModel_Device1_LPHD1, + (ModelNode*) &iedModel_Device1_LLN0_Mod, +}; + +DataObject iedModel_Device1_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Device1_LLN0, + (ModelNode*) &iedModel_Device1_LLN0_Beh, + (ModelNode*) &iedModel_Device1_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Device1_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_LLN0_Mod, + (ModelNode*) &iedModel_Device1_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_LLN0_Mod, + (ModelNode*) &iedModel_Device1_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Device1_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Device1_LLN0, + (ModelNode*) &iedModel_Device1_LLN0_Health, + (ModelNode*) &iedModel_Device1_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Device1_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_LLN0_Beh, + (ModelNode*) &iedModel_Device1_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_LLN0_Beh, + (ModelNode*) &iedModel_Device1_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Device1_LLN0, + (ModelNode*) &iedModel_Device1_LLN0_NamPlt, + (ModelNode*) &iedModel_Device1_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Device1_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_LLN0_Health, + (ModelNode*) &iedModel_Device1_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_LLN0_Health, + (ModelNode*) &iedModel_Device1_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Device1_LLN0, + NULL, + (ModelNode*) &iedModel_Device1_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Device1_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Device1_LLN0_NamPlt, + (ModelNode*) &iedModel_Device1_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Device1_LLN0_NamPlt, + (ModelNode*) &iedModel_Device1_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Device1_LLN0_NamPlt, + (ModelNode*) &iedModel_Device1_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Device1_LLN0_NamPlt, + (ModelNode*) &iedModel_Device1_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Device1_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Device1_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Device1, + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_LPHD1_PhyNam, +}; + +DataObject iedModel_Device1_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Device1_LPHD1, + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Device1_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Device1_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Device1_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Device1_LPHD1, + (ModelNode*) &iedModel_Device1_LPHD1_Proxy, + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Device1_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Device1_LPHD1, + NULL, + (ModelNode*) &iedModel_Device1_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Device1_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_LPHD1_Proxy, + (ModelNode*) &iedModel_Device1_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_LPHD1_Proxy, + (ModelNode*) &iedModel_Device1_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Device1_DGEN1 = { + LogicalNodeModelType, + "DGEN1", + (ModelNode*) &iedModel_Device1, + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DGEN1_Mod, +}; + +DataObject iedModel_Device1_DGEN1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_Beh, + (ModelNode*) &iedModel_Device1_DGEN1_Mod_q, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_Mod, + (ModelNode*) &iedModel_Device1_DGEN1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_Mod, + (ModelNode*) &iedModel_Device1_DGEN1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Device1_DGEN1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_Health, + (ModelNode*) &iedModel_Device1_DGEN1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DGEN1_Beh, + (ModelNode*) &iedModel_Device1_DGEN1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_Beh, + (ModelNode*) &iedModel_Device1_DGEN1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt, + (ModelNode*) &iedModel_Device1_DGEN1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DGEN1_Health, + (ModelNode*) &iedModel_Device1_DGEN1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_Health, + (ModelNode*) &iedModel_Device1_DGEN1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh, + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt, + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt, + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Device1_DGEN1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_OpTmh = { + DataObjectModelType, + "OpTmh", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_OpTmh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_OpTmh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_OpTmh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_OpTmh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_GnOpSt = { + DataObjectModelType, + "GnOpSt", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs, + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_GnOpSt_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt, + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_GnOpSt_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt, + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_GnOpSt_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_GnOpSt, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_OpTmsRs = { + DataObjectModelType, + "OpTmsRs", + (ModelNode*) &iedModel_Device1_DGEN1, + (ModelNode*) &iedModel_Device1_DGEN1_TotWh, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_OpTmsRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_OpTmsRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs, + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_OpTmsRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_OpTmsRs, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DGEN1_TotWh = { + DataObjectModelType, + "TotWh", + (ModelNode*) &iedModel_Device1_DGEN1, + NULL, + (ModelNode*) &iedModel_Device1_DGEN1_TotWh_mag, + 0 +}; + +DataAttribute iedModel_Device1_DGEN1_TotWh_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Device1_DGEN1_TotWh, + (ModelNode*) &iedModel_Device1_DGEN1_TotWh_q, + (ModelNode*) &iedModel_Device1_DGEN1_TotWh_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_TotWh_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Device1_DGEN1_TotWh_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_TotWh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DGEN1_TotWh, + (ModelNode*) &iedModel_Device1_DGEN1_TotWh_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DGEN1_TotWh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DGEN1_TotWh, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Device1_DSCH1 = { + LogicalNodeModelType, + "DSCH1", + (ModelNode*) &iedModel_Device1, + (ModelNode*) &iedModel_Device1_MMXU1, + (ModelNode*) &iedModel_Device1_DSCH1_Mod, +}; + +DataObject iedModel_Device1_DSCH1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_Beh, + (ModelNode*) &iedModel_Device1_DSCH1_Mod_q, + 0 +}; + +DataAttribute iedModel_Device1_DSCH1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DSCH1_Mod, + (ModelNode*) &iedModel_Device1_DSCH1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DSCH1_Mod, + (ModelNode*) &iedModel_Device1_DSCH1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Device1_DSCH1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DSCH1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_Health, + (ModelNode*) &iedModel_Device1_DSCH1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DSCH1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DSCH1_Beh, + (ModelNode*) &iedModel_Device1_DSCH1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DSCH1_Beh, + (ModelNode*) &iedModel_Device1_DSCH1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DSCH1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DSCH1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt, + (ModelNode*) &iedModel_Device1_DSCH1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DSCH1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DSCH1_Health, + (ModelNode*) &iedModel_Device1_DSCH1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DSCH1_Health, + (ModelNode*) &iedModel_Device1_DSCH1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DSCH1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DSCH1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt, + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Device1_DSCH1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt, + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt, + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Device1_DSCH1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DSCH1_SchdSt = { + DataObjectModelType, + "SchdSt", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_SchdId, + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt_stVal, + 0 +}; + +DataAttribute iedModel_Device1_DSCH1_SchdSt_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt, + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_SchdSt_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt, + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_SchdSt_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_DSCH1_SchdSt, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_DSCH1_SchdId = { + DataObjectModelType, + "SchdId", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_SchdCat, + NULL, + 0 +}; + +DataObject iedModel_Device1_DSCH1_SchdCat = { + DataObjectModelType, + "SchdCat", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_SchdTyp, + NULL, + 0 +}; + +DataObject iedModel_Device1_DSCH1_SchdTyp = { + DataObjectModelType, + "SchdTyp", + (ModelNode*) &iedModel_Device1_DSCH1, + (ModelNode*) &iedModel_Device1_DSCH1_SchdAbsTm, + NULL, + 0 +}; + +DataObject iedModel_Device1_DSCH1_SchdAbsTm = { + DataObjectModelType, + "SchdAbsTm", + (ModelNode*) &iedModel_Device1_DSCH1, + NULL, + (ModelNode*) &iedModel_Device1_DSCH1_SchdAbsTm_val, + 0 +}; + +DataAttribute iedModel_Device1_DSCH1_SchdAbsTm_val = { + DataAttributeModelType, + "val", + (ModelNode*) &iedModel_Device1_DSCH1_SchdAbsTm, + (ModelNode*) &iedModel_Device1_DSCH1_SchdAbsTm_time, + NULL, + 255, + IEC61850_FC_SP, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_DSCH1_SchdAbsTm_time = { + DataAttributeModelType, + "time", + (ModelNode*) &iedModel_Device1_DSCH1_SchdAbsTm, + NULL, + NULL, + 255, + IEC61850_FC_SP, + TIMESTAMP, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +LogicalNode iedModel_Device1_MMXU1 = { + LogicalNodeModelType, + "MMXU1", + (ModelNode*) &iedModel_Device1, + (ModelNode*) &iedModel_Device1_MMXU2, + (ModelNode*) &iedModel_Device1_MMXU1_Mod, +}; + +DataObject iedModel_Device1_MMXU1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Device1_MMXU1, + (ModelNode*) &iedModel_Device1_MMXU1_Beh, + (ModelNode*) &iedModel_Device1_MMXU1_Mod_q, + 0 +}; + +DataAttribute iedModel_Device1_MMXU1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU1_Mod, + (ModelNode*) &iedModel_Device1_MMXU1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU1_Mod, + (ModelNode*) &iedModel_Device1_MMXU1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Device1_MMXU1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Device1_MMXU1, + (ModelNode*) &iedModel_Device1_MMXU1_Health, + (ModelNode*) &iedModel_Device1_MMXU1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Device1_MMXU1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_MMXU1_Beh, + (ModelNode*) &iedModel_Device1_MMXU1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU1_Beh, + (ModelNode*) &iedModel_Device1_MMXU1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Device1_MMXU1, + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt, + (ModelNode*) &iedModel_Device1_MMXU1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Device1_MMXU1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_MMXU1_Health, + (ModelNode*) &iedModel_Device1_MMXU1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU1_Health, + (ModelNode*) &iedModel_Device1_MMXU1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Device1_MMXU1, + NULL, + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Device1_MMXU1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt, + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt, + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Device1_MMXU1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Device1_MMXU2 = { + LogicalNodeModelType, + "MMXU2", + (ModelNode*) &iedModel_Device1, + NULL, + (ModelNode*) &iedModel_Device1_MMXU2_Mod, +}; + +DataObject iedModel_Device1_MMXU2_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Device1_MMXU2, + (ModelNode*) &iedModel_Device1_MMXU2_Beh, + (ModelNode*) &iedModel_Device1_MMXU2_Mod_q, + 0 +}; + +DataAttribute iedModel_Device1_MMXU2_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU2_Mod, + (ModelNode*) &iedModel_Device1_MMXU2_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU2_Mod, + (ModelNode*) &iedModel_Device1_MMXU2_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Device1_MMXU2_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU2_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Device1_MMXU2, + (ModelNode*) &iedModel_Device1_MMXU2_Health, + (ModelNode*) &iedModel_Device1_MMXU2_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Device1_MMXU2_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_MMXU2_Beh, + (ModelNode*) &iedModel_Device1_MMXU2_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU2_Beh, + (ModelNode*) &iedModel_Device1_MMXU2_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU2_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU2_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Device1_MMXU2, + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt, + (ModelNode*) &iedModel_Device1_MMXU2_Health_stVal, + 0 +}; + +DataAttribute iedModel_Device1_MMXU2_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Device1_MMXU2_Health, + (ModelNode*) &iedModel_Device1_MMXU2_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU2_Health, + (ModelNode*) &iedModel_Device1_MMXU2_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU2_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU2_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Device1_MMXU2, + (ModelNode*) &iedModel_Device1_MMXU2_TotW, + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Device1_MMXU2_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt, + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt, + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Device1_MMXU2_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Device1_MMXU2_TotW = { + DataObjectModelType, + "TotW", + (ModelNode*) &iedModel_Device1_MMXU2, + NULL, + (ModelNode*) &iedModel_Device1_MMXU2_TotW_mag, + 0 +}; + +DataAttribute iedModel_Device1_MMXU2_TotW_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Device1_MMXU2_TotW, + (ModelNode*) &iedModel_Device1_MMXU2_TotW_q, + (ModelNode*) &iedModel_Device1_MMXU2_TotW_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_TotW_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Device1_MMXU2_TotW_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_TotW_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Device1_MMXU2_TotW, + (ModelNode*) &iedModel_Device1_MMXU2_TotW_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Device1_MMXU2_TotW_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Device1_MMXU2_TotW, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_Device1_LLN0_report0; + +ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep01", "LLN0$RP$brcbEV1", true, "dataset1", 1, 9, 239, 50, 900000, NULL}; + + + + +IedModel iedModel = { + "SampleIED", + &iedModel_Device1, + &ds_Device1_LLN0_dataset1, + &iedModel_Device1_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_Device1_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Device1_DGEN1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Device1_DSCH1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Device1_MMXU1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Device1_MMXU2_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); +} diff --git a/examples/server_example1/static_model.h b/examples/server_example1/static_model.h new file mode 100644 index 0000000..208787e --- /dev/null +++ b/examples/server_example1/static_model.h @@ -0,0 +1,281 @@ +/* + * static_model.h + * + * automatically generated from sampleModel_with_dataset.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_Device1; +extern LogicalNode iedModel_Device1_LLN0; +extern DataObject iedModel_Device1_LLN0_Mod; +extern DataAttribute iedModel_Device1_LLN0_Mod_q; +extern DataAttribute iedModel_Device1_LLN0_Mod_t; +extern DataAttribute iedModel_Device1_LLN0_Mod_ctlModel; +extern DataObject iedModel_Device1_LLN0_Beh; +extern DataAttribute iedModel_Device1_LLN0_Beh_stVal; +extern DataAttribute iedModel_Device1_LLN0_Beh_q; +extern DataAttribute iedModel_Device1_LLN0_Beh_t; +extern DataObject iedModel_Device1_LLN0_Health; +extern DataAttribute iedModel_Device1_LLN0_Health_stVal; +extern DataAttribute iedModel_Device1_LLN0_Health_q; +extern DataAttribute iedModel_Device1_LLN0_Health_t; +extern DataObject iedModel_Device1_LLN0_NamPlt; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_d; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Device1_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Device1_LPHD1; +extern DataObject iedModel_Device1_LPHD1_PhyNam; +extern DataAttribute iedModel_Device1_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Device1_LPHD1_PhyHealth; +extern DataAttribute iedModel_Device1_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Device1_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Device1_LPHD1_PhyHealth_t; +extern DataObject iedModel_Device1_LPHD1_Proxy; +extern DataAttribute iedModel_Device1_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Device1_LPHD1_Proxy_q; +extern DataAttribute iedModel_Device1_LPHD1_Proxy_t; +extern LogicalNode iedModel_Device1_DGEN1; +extern DataObject iedModel_Device1_DGEN1_Mod; +extern DataAttribute iedModel_Device1_DGEN1_Mod_q; +extern DataAttribute iedModel_Device1_DGEN1_Mod_t; +extern DataAttribute iedModel_Device1_DGEN1_Mod_ctlModel; +extern DataObject iedModel_Device1_DGEN1_Beh; +extern DataAttribute iedModel_Device1_DGEN1_Beh_stVal; +extern DataAttribute iedModel_Device1_DGEN1_Beh_q; +extern DataAttribute iedModel_Device1_DGEN1_Beh_t; +extern DataObject iedModel_Device1_DGEN1_Health; +extern DataAttribute iedModel_Device1_DGEN1_Health_stVal; +extern DataAttribute iedModel_Device1_DGEN1_Health_q; +extern DataAttribute iedModel_Device1_DGEN1_Health_t; +extern DataObject iedModel_Device1_DGEN1_NamPlt; +extern DataAttribute iedModel_Device1_DGEN1_NamPlt_vendor; +extern DataAttribute iedModel_Device1_DGEN1_NamPlt_swRev; +extern DataAttribute iedModel_Device1_DGEN1_NamPlt_d; +extern DataObject iedModel_Device1_DGEN1_OpTmh; +extern DataAttribute iedModel_Device1_DGEN1_OpTmh_stVal; +extern DataAttribute iedModel_Device1_DGEN1_OpTmh_q; +extern DataAttribute iedModel_Device1_DGEN1_OpTmh_t; +extern DataObject iedModel_Device1_DGEN1_GnOpSt; +extern DataAttribute iedModel_Device1_DGEN1_GnOpSt_stVal; +extern DataAttribute iedModel_Device1_DGEN1_GnOpSt_q; +extern DataAttribute iedModel_Device1_DGEN1_GnOpSt_t; +extern DataObject iedModel_Device1_DGEN1_OpTmsRs; +extern DataAttribute iedModel_Device1_DGEN1_OpTmsRs_stVal; +extern DataAttribute iedModel_Device1_DGEN1_OpTmsRs_q; +extern DataAttribute iedModel_Device1_DGEN1_OpTmsRs_t; +extern DataObject iedModel_Device1_DGEN1_TotWh; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_mag; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_mag_f; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_q; +extern DataAttribute iedModel_Device1_DGEN1_TotWh_t; +extern LogicalNode iedModel_Device1_DSCH1; +extern DataObject iedModel_Device1_DSCH1_Mod; +extern DataAttribute iedModel_Device1_DSCH1_Mod_q; +extern DataAttribute iedModel_Device1_DSCH1_Mod_t; +extern DataAttribute iedModel_Device1_DSCH1_Mod_ctlModel; +extern DataObject iedModel_Device1_DSCH1_Beh; +extern DataAttribute iedModel_Device1_DSCH1_Beh_stVal; +extern DataAttribute iedModel_Device1_DSCH1_Beh_q; +extern DataAttribute iedModel_Device1_DSCH1_Beh_t; +extern DataObject iedModel_Device1_DSCH1_Health; +extern DataAttribute iedModel_Device1_DSCH1_Health_stVal; +extern DataAttribute iedModel_Device1_DSCH1_Health_q; +extern DataAttribute iedModel_Device1_DSCH1_Health_t; +extern DataObject iedModel_Device1_DSCH1_NamPlt; +extern DataAttribute iedModel_Device1_DSCH1_NamPlt_vendor; +extern DataAttribute iedModel_Device1_DSCH1_NamPlt_swRev; +extern DataAttribute iedModel_Device1_DSCH1_NamPlt_d; +extern DataObject iedModel_Device1_DSCH1_SchdSt; +extern DataAttribute iedModel_Device1_DSCH1_SchdSt_stVal; +extern DataAttribute iedModel_Device1_DSCH1_SchdSt_q; +extern DataAttribute iedModel_Device1_DSCH1_SchdSt_t; +extern DataObject iedModel_Device1_DSCH1_SchdId; +extern DataObject iedModel_Device1_DSCH1_SchdCat; +extern DataObject iedModel_Device1_DSCH1_SchdTyp; +extern DataObject iedModel_Device1_DSCH1_SchdAbsTm; +extern DataAttribute iedModel_Device1_DSCH1_SchdAbsTm_val; +extern DataAttribute iedModel_Device1_DSCH1_SchdAbsTm_time; +extern LogicalNode iedModel_Device1_MMXU1; +extern DataObject iedModel_Device1_MMXU1_Mod; +extern DataAttribute iedModel_Device1_MMXU1_Mod_q; +extern DataAttribute iedModel_Device1_MMXU1_Mod_t; +extern DataAttribute iedModel_Device1_MMXU1_Mod_ctlModel; +extern DataObject iedModel_Device1_MMXU1_Beh; +extern DataAttribute iedModel_Device1_MMXU1_Beh_stVal; +extern DataAttribute iedModel_Device1_MMXU1_Beh_q; +extern DataAttribute iedModel_Device1_MMXU1_Beh_t; +extern DataObject iedModel_Device1_MMXU1_Health; +extern DataAttribute iedModel_Device1_MMXU1_Health_stVal; +extern DataAttribute iedModel_Device1_MMXU1_Health_q; +extern DataAttribute iedModel_Device1_MMXU1_Health_t; +extern DataObject iedModel_Device1_MMXU1_NamPlt; +extern DataAttribute iedModel_Device1_MMXU1_NamPlt_vendor; +extern DataAttribute iedModel_Device1_MMXU1_NamPlt_swRev; +extern DataAttribute iedModel_Device1_MMXU1_NamPlt_d; +extern LogicalNode iedModel_Device1_MMXU2; +extern DataObject iedModel_Device1_MMXU2_Mod; +extern DataAttribute iedModel_Device1_MMXU2_Mod_q; +extern DataAttribute iedModel_Device1_MMXU2_Mod_t; +extern DataAttribute iedModel_Device1_MMXU2_Mod_ctlModel; +extern DataObject iedModel_Device1_MMXU2_Beh; +extern DataAttribute iedModel_Device1_MMXU2_Beh_stVal; +extern DataAttribute iedModel_Device1_MMXU2_Beh_q; +extern DataAttribute iedModel_Device1_MMXU2_Beh_t; +extern DataObject iedModel_Device1_MMXU2_Health; +extern DataAttribute iedModel_Device1_MMXU2_Health_stVal; +extern DataAttribute iedModel_Device1_MMXU2_Health_q; +extern DataAttribute iedModel_Device1_MMXU2_Health_t; +extern DataObject iedModel_Device1_MMXU2_NamPlt; +extern DataAttribute iedModel_Device1_MMXU2_NamPlt_vendor; +extern DataAttribute iedModel_Device1_MMXU2_NamPlt_swRev; +extern DataAttribute iedModel_Device1_MMXU2_NamPlt_d; +extern DataObject iedModel_Device1_MMXU2_TotW; +extern DataAttribute iedModel_Device1_MMXU2_TotW_mag; +extern DataAttribute iedModel_Device1_MMXU2_TotW_mag_f; +extern DataAttribute iedModel_Device1_MMXU2_TotW_q; +extern DataAttribute iedModel_Device1_MMXU2_TotW_t; + + + +#define IEDMODEL_Device1 (&iedModel_Device1) +#define IEDMODEL_Device1_LLN0 (&iedModel_Device1_LLN0) +#define IEDMODEL_Device1_LLN0_Mod (&iedModel_Device1_LLN0_Mod) +#define IEDMODEL_Device1_LLN0_Mod_q (&iedModel_Device1_LLN0_Mod_q) +#define IEDMODEL_Device1_LLN0_Mod_t (&iedModel_Device1_LLN0_Mod_t) +#define IEDMODEL_Device1_LLN0_Mod_ctlModel (&iedModel_Device1_LLN0_Mod_ctlModel) +#define IEDMODEL_Device1_LLN0_Beh (&iedModel_Device1_LLN0_Beh) +#define IEDMODEL_Device1_LLN0_Beh_stVal (&iedModel_Device1_LLN0_Beh_stVal) +#define IEDMODEL_Device1_LLN0_Beh_q (&iedModel_Device1_LLN0_Beh_q) +#define IEDMODEL_Device1_LLN0_Beh_t (&iedModel_Device1_LLN0_Beh_t) +#define IEDMODEL_Device1_LLN0_Health (&iedModel_Device1_LLN0_Health) +#define IEDMODEL_Device1_LLN0_Health_stVal (&iedModel_Device1_LLN0_Health_stVal) +#define IEDMODEL_Device1_LLN0_Health_q (&iedModel_Device1_LLN0_Health_q) +#define IEDMODEL_Device1_LLN0_Health_t (&iedModel_Device1_LLN0_Health_t) +#define IEDMODEL_Device1_LLN0_NamPlt (&iedModel_Device1_LLN0_NamPlt) +#define IEDMODEL_Device1_LLN0_NamPlt_vendor (&iedModel_Device1_LLN0_NamPlt_vendor) +#define IEDMODEL_Device1_LLN0_NamPlt_swRev (&iedModel_Device1_LLN0_NamPlt_swRev) +#define IEDMODEL_Device1_LLN0_NamPlt_d (&iedModel_Device1_LLN0_NamPlt_d) +#define IEDMODEL_Device1_LLN0_NamPlt_configRev (&iedModel_Device1_LLN0_NamPlt_configRev) +#define IEDMODEL_Device1_LLN0_NamPlt_ldNs (&iedModel_Device1_LLN0_NamPlt_ldNs) +#define IEDMODEL_Device1_LPHD1 (&iedModel_Device1_LPHD1) +#define IEDMODEL_Device1_LPHD1_PhyNam (&iedModel_Device1_LPHD1_PhyNam) +#define IEDMODEL_Device1_LPHD1_PhyNam_vendor (&iedModel_Device1_LPHD1_PhyNam_vendor) +#define IEDMODEL_Device1_LPHD1_PhyHealth (&iedModel_Device1_LPHD1_PhyHealth) +#define IEDMODEL_Device1_LPHD1_PhyHealth_stVal (&iedModel_Device1_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Device1_LPHD1_PhyHealth_q (&iedModel_Device1_LPHD1_PhyHealth_q) +#define IEDMODEL_Device1_LPHD1_PhyHealth_t (&iedModel_Device1_LPHD1_PhyHealth_t) +#define IEDMODEL_Device1_LPHD1_Proxy (&iedModel_Device1_LPHD1_Proxy) +#define IEDMODEL_Device1_LPHD1_Proxy_stVal (&iedModel_Device1_LPHD1_Proxy_stVal) +#define IEDMODEL_Device1_LPHD1_Proxy_q (&iedModel_Device1_LPHD1_Proxy_q) +#define IEDMODEL_Device1_LPHD1_Proxy_t (&iedModel_Device1_LPHD1_Proxy_t) +#define IEDMODEL_Device1_DGEN1 (&iedModel_Device1_DGEN1) +#define IEDMODEL_Device1_DGEN1_Mod (&iedModel_Device1_DGEN1_Mod) +#define IEDMODEL_Device1_DGEN1_Mod_q (&iedModel_Device1_DGEN1_Mod_q) +#define IEDMODEL_Device1_DGEN1_Mod_t (&iedModel_Device1_DGEN1_Mod_t) +#define IEDMODEL_Device1_DGEN1_Mod_ctlModel (&iedModel_Device1_DGEN1_Mod_ctlModel) +#define IEDMODEL_Device1_DGEN1_Beh (&iedModel_Device1_DGEN1_Beh) +#define IEDMODEL_Device1_DGEN1_Beh_stVal (&iedModel_Device1_DGEN1_Beh_stVal) +#define IEDMODEL_Device1_DGEN1_Beh_q (&iedModel_Device1_DGEN1_Beh_q) +#define IEDMODEL_Device1_DGEN1_Beh_t (&iedModel_Device1_DGEN1_Beh_t) +#define IEDMODEL_Device1_DGEN1_Health (&iedModel_Device1_DGEN1_Health) +#define IEDMODEL_Device1_DGEN1_Health_stVal (&iedModel_Device1_DGEN1_Health_stVal) +#define IEDMODEL_Device1_DGEN1_Health_q (&iedModel_Device1_DGEN1_Health_q) +#define IEDMODEL_Device1_DGEN1_Health_t (&iedModel_Device1_DGEN1_Health_t) +#define IEDMODEL_Device1_DGEN1_NamPlt (&iedModel_Device1_DGEN1_NamPlt) +#define IEDMODEL_Device1_DGEN1_NamPlt_vendor (&iedModel_Device1_DGEN1_NamPlt_vendor) +#define IEDMODEL_Device1_DGEN1_NamPlt_swRev (&iedModel_Device1_DGEN1_NamPlt_swRev) +#define IEDMODEL_Device1_DGEN1_NamPlt_d (&iedModel_Device1_DGEN1_NamPlt_d) +#define IEDMODEL_Device1_DGEN1_OpTmh (&iedModel_Device1_DGEN1_OpTmh) +#define IEDMODEL_Device1_DGEN1_OpTmh_stVal (&iedModel_Device1_DGEN1_OpTmh_stVal) +#define IEDMODEL_Device1_DGEN1_OpTmh_q (&iedModel_Device1_DGEN1_OpTmh_q) +#define IEDMODEL_Device1_DGEN1_OpTmh_t (&iedModel_Device1_DGEN1_OpTmh_t) +#define IEDMODEL_Device1_DGEN1_GnOpSt (&iedModel_Device1_DGEN1_GnOpSt) +#define IEDMODEL_Device1_DGEN1_GnOpSt_stVal (&iedModel_Device1_DGEN1_GnOpSt_stVal) +#define IEDMODEL_Device1_DGEN1_GnOpSt_q (&iedModel_Device1_DGEN1_GnOpSt_q) +#define IEDMODEL_Device1_DGEN1_GnOpSt_t (&iedModel_Device1_DGEN1_GnOpSt_t) +#define IEDMODEL_Device1_DGEN1_OpTmsRs (&iedModel_Device1_DGEN1_OpTmsRs) +#define IEDMODEL_Device1_DGEN1_OpTmsRs_stVal (&iedModel_Device1_DGEN1_OpTmsRs_stVal) +#define IEDMODEL_Device1_DGEN1_OpTmsRs_q (&iedModel_Device1_DGEN1_OpTmsRs_q) +#define IEDMODEL_Device1_DGEN1_OpTmsRs_t (&iedModel_Device1_DGEN1_OpTmsRs_t) +#define IEDMODEL_Device1_DGEN1_TotWh (&iedModel_Device1_DGEN1_TotWh) +#define IEDMODEL_Device1_DGEN1_TotWh_mag (&iedModel_Device1_DGEN1_TotWh_mag) +#define IEDMODEL_Device1_DGEN1_TotWh_mag_f (&iedModel_Device1_DGEN1_TotWh_mag_f) +#define IEDMODEL_Device1_DGEN1_TotWh_q (&iedModel_Device1_DGEN1_TotWh_q) +#define IEDMODEL_Device1_DGEN1_TotWh_t (&iedModel_Device1_DGEN1_TotWh_t) +#define IEDMODEL_Device1_DSCH1 (&iedModel_Device1_DSCH1) +#define IEDMODEL_Device1_DSCH1_Mod (&iedModel_Device1_DSCH1_Mod) +#define IEDMODEL_Device1_DSCH1_Mod_q (&iedModel_Device1_DSCH1_Mod_q) +#define IEDMODEL_Device1_DSCH1_Mod_t (&iedModel_Device1_DSCH1_Mod_t) +#define IEDMODEL_Device1_DSCH1_Mod_ctlModel (&iedModel_Device1_DSCH1_Mod_ctlModel) +#define IEDMODEL_Device1_DSCH1_Beh (&iedModel_Device1_DSCH1_Beh) +#define IEDMODEL_Device1_DSCH1_Beh_stVal (&iedModel_Device1_DSCH1_Beh_stVal) +#define IEDMODEL_Device1_DSCH1_Beh_q (&iedModel_Device1_DSCH1_Beh_q) +#define IEDMODEL_Device1_DSCH1_Beh_t (&iedModel_Device1_DSCH1_Beh_t) +#define IEDMODEL_Device1_DSCH1_Health (&iedModel_Device1_DSCH1_Health) +#define IEDMODEL_Device1_DSCH1_Health_stVal (&iedModel_Device1_DSCH1_Health_stVal) +#define IEDMODEL_Device1_DSCH1_Health_q (&iedModel_Device1_DSCH1_Health_q) +#define IEDMODEL_Device1_DSCH1_Health_t (&iedModel_Device1_DSCH1_Health_t) +#define IEDMODEL_Device1_DSCH1_NamPlt (&iedModel_Device1_DSCH1_NamPlt) +#define IEDMODEL_Device1_DSCH1_NamPlt_vendor (&iedModel_Device1_DSCH1_NamPlt_vendor) +#define IEDMODEL_Device1_DSCH1_NamPlt_swRev (&iedModel_Device1_DSCH1_NamPlt_swRev) +#define IEDMODEL_Device1_DSCH1_NamPlt_d (&iedModel_Device1_DSCH1_NamPlt_d) +#define IEDMODEL_Device1_DSCH1_SchdSt (&iedModel_Device1_DSCH1_SchdSt) +#define IEDMODEL_Device1_DSCH1_SchdSt_stVal (&iedModel_Device1_DSCH1_SchdSt_stVal) +#define IEDMODEL_Device1_DSCH1_SchdSt_q (&iedModel_Device1_DSCH1_SchdSt_q) +#define IEDMODEL_Device1_DSCH1_SchdSt_t (&iedModel_Device1_DSCH1_SchdSt_t) +#define IEDMODEL_Device1_DSCH1_SchdId (&iedModel_Device1_DSCH1_SchdId) +#define IEDMODEL_Device1_DSCH1_SchdCat (&iedModel_Device1_DSCH1_SchdCat) +#define IEDMODEL_Device1_DSCH1_SchdTyp (&iedModel_Device1_DSCH1_SchdTyp) +#define IEDMODEL_Device1_DSCH1_SchdAbsTm (&iedModel_Device1_DSCH1_SchdAbsTm) +#define IEDMODEL_Device1_DSCH1_SchdAbsTm_val (&iedModel_Device1_DSCH1_SchdAbsTm_val) +#define IEDMODEL_Device1_DSCH1_SchdAbsTm_time (&iedModel_Device1_DSCH1_SchdAbsTm_time) +#define IEDMODEL_Device1_MMXU1 (&iedModel_Device1_MMXU1) +#define IEDMODEL_Device1_MMXU1_Mod (&iedModel_Device1_MMXU1_Mod) +#define IEDMODEL_Device1_MMXU1_Mod_q (&iedModel_Device1_MMXU1_Mod_q) +#define IEDMODEL_Device1_MMXU1_Mod_t (&iedModel_Device1_MMXU1_Mod_t) +#define IEDMODEL_Device1_MMXU1_Mod_ctlModel (&iedModel_Device1_MMXU1_Mod_ctlModel) +#define IEDMODEL_Device1_MMXU1_Beh (&iedModel_Device1_MMXU1_Beh) +#define IEDMODEL_Device1_MMXU1_Beh_stVal (&iedModel_Device1_MMXU1_Beh_stVal) +#define IEDMODEL_Device1_MMXU1_Beh_q (&iedModel_Device1_MMXU1_Beh_q) +#define IEDMODEL_Device1_MMXU1_Beh_t (&iedModel_Device1_MMXU1_Beh_t) +#define IEDMODEL_Device1_MMXU1_Health (&iedModel_Device1_MMXU1_Health) +#define IEDMODEL_Device1_MMXU1_Health_stVal (&iedModel_Device1_MMXU1_Health_stVal) +#define IEDMODEL_Device1_MMXU1_Health_q (&iedModel_Device1_MMXU1_Health_q) +#define IEDMODEL_Device1_MMXU1_Health_t (&iedModel_Device1_MMXU1_Health_t) +#define IEDMODEL_Device1_MMXU1_NamPlt (&iedModel_Device1_MMXU1_NamPlt) +#define IEDMODEL_Device1_MMXU1_NamPlt_vendor (&iedModel_Device1_MMXU1_NamPlt_vendor) +#define IEDMODEL_Device1_MMXU1_NamPlt_swRev (&iedModel_Device1_MMXU1_NamPlt_swRev) +#define IEDMODEL_Device1_MMXU1_NamPlt_d (&iedModel_Device1_MMXU1_NamPlt_d) +#define IEDMODEL_Device1_MMXU2 (&iedModel_Device1_MMXU2) +#define IEDMODEL_Device1_MMXU2_Mod (&iedModel_Device1_MMXU2_Mod) +#define IEDMODEL_Device1_MMXU2_Mod_q (&iedModel_Device1_MMXU2_Mod_q) +#define IEDMODEL_Device1_MMXU2_Mod_t (&iedModel_Device1_MMXU2_Mod_t) +#define IEDMODEL_Device1_MMXU2_Mod_ctlModel (&iedModel_Device1_MMXU2_Mod_ctlModel) +#define IEDMODEL_Device1_MMXU2_Beh (&iedModel_Device1_MMXU2_Beh) +#define IEDMODEL_Device1_MMXU2_Beh_stVal (&iedModel_Device1_MMXU2_Beh_stVal) +#define IEDMODEL_Device1_MMXU2_Beh_q (&iedModel_Device1_MMXU2_Beh_q) +#define IEDMODEL_Device1_MMXU2_Beh_t (&iedModel_Device1_MMXU2_Beh_t) +#define IEDMODEL_Device1_MMXU2_Health (&iedModel_Device1_MMXU2_Health) +#define IEDMODEL_Device1_MMXU2_Health_stVal (&iedModel_Device1_MMXU2_Health_stVal) +#define IEDMODEL_Device1_MMXU2_Health_q (&iedModel_Device1_MMXU2_Health_q) +#define IEDMODEL_Device1_MMXU2_Health_t (&iedModel_Device1_MMXU2_Health_t) +#define IEDMODEL_Device1_MMXU2_NamPlt (&iedModel_Device1_MMXU2_NamPlt) +#define IEDMODEL_Device1_MMXU2_NamPlt_vendor (&iedModel_Device1_MMXU2_NamPlt_vendor) +#define IEDMODEL_Device1_MMXU2_NamPlt_swRev (&iedModel_Device1_MMXU2_NamPlt_swRev) +#define IEDMODEL_Device1_MMXU2_NamPlt_d (&iedModel_Device1_MMXU2_NamPlt_d) +#define IEDMODEL_Device1_MMXU2_TotW (&iedModel_Device1_MMXU2_TotW) +#define IEDMODEL_Device1_MMXU2_TotW_mag (&iedModel_Device1_MMXU2_TotW_mag) +#define IEDMODEL_Device1_MMXU2_TotW_mag_f (&iedModel_Device1_MMXU2_TotW_mag_f) +#define IEDMODEL_Device1_MMXU2_TotW_q (&iedModel_Device1_MMXU2_TotW_q) +#define IEDMODEL_Device1_MMXU2_TotW_t (&iedModel_Device1_MMXU2_TotW_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example2/CMakeLists.txt b/examples/server_example2/CMakeLists.txt new file mode 100644 index 0000000..994caae --- /dev/null +++ b/examples/server_example2/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example2_SRCS + server_example2.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example2_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example2 + ${server_example2_SRCS} +) + +target_link_libraries(server_example2 + iec61850 +) diff --git a/examples/server_example2/Makefile b/examples/server_example2/Makefile new file mode 100644 index 0000000..3781758 --- /dev/null +++ b/examples/server_example2/Makefile @@ -0,0 +1,24 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example2 +PROJECT_SOURCES = server_example2.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = complexModel.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDFLAGS) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + diff --git a/examples/server_example2/complexModel.icd b/examples/server_example2/complexModel.icd new file mode 100644 index 0000000..9d5ccea --- /dev/null +++ b/examples/server_example2/complexModel.icd @@ -0,0 +1,347 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + + rad + sr + m + Gy + q + °C + Sv + F + C + S + H + V + kg + ohm + J + N + Hz + Ix + Lm + Wb + T + W + Pa + s + m² + m³ + m/s + m/s² + m³/s + m/m³ + M + kg/m³ + m²/s + A + W/m K + J/K + ppm + 1/s + rad/s + K + VA + Watts + VAr + theta + cos(theta) + Vs + V² + As + A² + mol + A²t + VAh + Wh + VArh + V/Hz + cd + deg + + + Yocto + Zepto + Atto + Femto + Pico + Nano + Micro + Milli + Centi + Deci + zeroNoValue + Deca + Hecto + Kilo + Mega + Giga + Tera + Petra + Exa + Zetta + Yotta + + + normal + high + low + high-high + low-low + + + diff --git a/examples/server_example2/server_example2.c b/examples/server_example2/server_example2.c new file mode 100644 index 0000000..6d7f351 --- /dev/null +++ b/examples/server_example2/server_example2.c @@ -0,0 +1,91 @@ +/* + * server_example2.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + + +/* Include the generated header with the model access handles */ +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + +int +main(int argc, char** argv) +{ + IedServer iedServer = IedServer_create(&iedModel); + + // TODO get stored values from persistent storage + + // TODO set initial measurement and status values from process + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float power = 500.f; + + while (running) { + + uint64_t timeval = Hal_getTimeInMs(); + + IedServer_lockDataModel(iedServer); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_Inverter_MMXU1_TotW_t, timeval); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_Inverter_MMXU1_TotW_mag_f, power); + + IedServer_unlockDataModel(iedServer); + + power += 0.1f; + + Thread_sleep(500); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); + + return 0; +} /* main() */ diff --git a/examples/server_example2/static_model.c b/examples/server_example2/static_model.c new file mode 100644 index 0000000..fdc336c --- /dev/null +++ b/examples/server_example2/static_model.c @@ -0,0 +1,3912 @@ +/* + * static_model.c + * + * automatically generated from complexModel.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_Inverter; +extern LogicalNode iedModel_Inverter_LLN0; +extern DataObject iedModel_Inverter_LLN0_Mod; +extern DataAttribute iedModel_Inverter_LLN0_Mod_q; +extern DataAttribute iedModel_Inverter_LLN0_Mod_t; +extern DataAttribute iedModel_Inverter_LLN0_Mod_ctlModel; +extern DataObject iedModel_Inverter_LLN0_Beh; +extern DataAttribute iedModel_Inverter_LLN0_Beh_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Beh_q; +extern DataAttribute iedModel_Inverter_LLN0_Beh_t; +extern DataObject iedModel_Inverter_LLN0_Health; +extern DataAttribute iedModel_Inverter_LLN0_Health_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Health_q; +extern DataAttribute iedModel_Inverter_LLN0_Health_t; +extern DataObject iedModel_Inverter_LLN0_NamPlt; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_d; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Inverter_LPHD1; +extern DataObject iedModel_Inverter_LPHD1_PhyNam; +extern DataAttribute iedModel_Inverter_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Inverter_LPHD1_PhyHealth; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_t; +extern DataObject iedModel_Inverter_LPHD1_Proxy; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_q; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_t; +extern LogicalNode iedModel_Inverter_ZINV1; +extern DataObject iedModel_Inverter_ZINV1_Mod; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_q; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_t; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_ctlModel; +extern DataObject iedModel_Inverter_ZINV1_Beh; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_q; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_t; +extern DataObject iedModel_Inverter_ZINV1_Health; +extern DataAttribute iedModel_Inverter_ZINV1_Health_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Health_q; +extern DataAttribute iedModel_Inverter_ZINV1_Health_t; +extern DataObject iedModel_Inverter_ZINV1_NamPlt; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_d; +extern DataObject iedModel_Inverter_ZINV1_WRtg; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_VarRtg; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_ACTyp; +extern DataAttribute iedModel_Inverter_ZINV1_ACTyp_setVal; +extern DataObject iedModel_Inverter_ZINV1_OutWSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_OutVarSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit; +extern LogicalNode iedModel_Inverter_MMXU1; +extern DataObject iedModel_Inverter_MMXU1_Mod; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_q; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_t; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_ctlModel; +extern DataObject iedModel_Inverter_MMXU1_Beh; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_q; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_t; +extern DataObject iedModel_Inverter_MMXU1_Health; +extern DataAttribute iedModel_Inverter_MMXU1_Health_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Health_q; +extern DataAttribute iedModel_Inverter_MMXU1_Health_t; +extern DataObject iedModel_Inverter_MMXU1_NamPlt; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_d; +extern DataObject iedModel_Inverter_MMXU1_TotW; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_t; +extern DataObject iedModel_Inverter_MMXU1_TotVAr; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_t; +extern DataObject iedModel_Inverter_MMXU1_TotVA; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_t; +extern DataObject iedModel_Inverter_MMXU1_Hz; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_q; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_t; +extern DataObject iedModel_Inverter_MMXU1_PhV; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_neut; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_t; +extern DataObject iedModel_Inverter_MMXU1_A; +extern DataObject iedModel_Inverter_MMXU1_A_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_A_neut; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_t; +extern DataObject iedModel_Inverter_MMXU1_W; +extern DataObject iedModel_Inverter_MMXU1_W_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_t; +extern LogicalDevice iedModel_Battery; +extern LogicalNode iedModel_Battery_LLN0; +extern DataObject iedModel_Battery_LLN0_Mod; +extern DataAttribute iedModel_Battery_LLN0_Mod_q; +extern DataAttribute iedModel_Battery_LLN0_Mod_t; +extern DataAttribute iedModel_Battery_LLN0_Mod_ctlModel; +extern DataObject iedModel_Battery_LLN0_Beh; +extern DataAttribute iedModel_Battery_LLN0_Beh_stVal; +extern DataAttribute iedModel_Battery_LLN0_Beh_q; +extern DataAttribute iedModel_Battery_LLN0_Beh_t; +extern DataObject iedModel_Battery_LLN0_Health; +extern DataAttribute iedModel_Battery_LLN0_Health_stVal; +extern DataAttribute iedModel_Battery_LLN0_Health_q; +extern DataAttribute iedModel_Battery_LLN0_Health_t; +extern DataObject iedModel_Battery_LLN0_NamPlt; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_d; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Battery_LPHD1; +extern DataObject iedModel_Battery_LPHD1_PhyNam; +extern DataAttribute iedModel_Battery_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Battery_LPHD1_PhyHealth; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_t; +extern DataObject iedModel_Battery_LPHD1_Proxy; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_q; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_t; +extern LogicalNode iedModel_Battery_ZBAT1; +extern DataObject iedModel_Battery_ZBAT1_Mod; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_q; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_t; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBAT1_Beh; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_q; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_t; +extern DataObject iedModel_Battery_ZBAT1_Health; +extern DataAttribute iedModel_Battery_ZBAT1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Health_q; +extern DataAttribute iedModel_Battery_ZBAT1_Health_t; +extern DataObject iedModel_Battery_ZBAT1_NamPlt; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_d; +extern DataObject iedModel_Battery_ZBAT1_Vol; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_q; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_t; +extern DataObject iedModel_Battery_ZBAT1_Amp; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_q; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_t; +extern LogicalNode iedModel_Battery_ZBTC1; +extern DataObject iedModel_Battery_ZBTC1_Mod; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_q; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_t; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBTC1_Beh; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_q; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_t; +extern DataObject iedModel_Battery_ZBTC1_Health; +extern DataAttribute iedModel_Battery_ZBTC1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Health_q; +extern DataAttribute iedModel_Battery_ZBTC1_Health_t; +extern DataObject iedModel_Battery_ZBTC1_NamPlt; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_d; +extern DataObject iedModel_Battery_ZBTC1_BatChaSt; +extern DataObject iedModel_Battery_ZBTC1_BatChaPwr; +extern DataObject iedModel_Battery_ZBTC1_BatChaMod; +extern DataObject iedModel_Battery_ZBTC1_ChaV; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_t; +extern DataObject iedModel_Battery_ZBTC1_ChaA; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_t; +extern LogicalDevice iedModel_Physical_Measurements; +extern LogicalNode iedModel_Physical_Measurements_LLN0; +extern DataObject iedModel_Physical_Measurements_LLN0_Mod; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_t; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_ctlModel; +extern DataObject iedModel_Physical_Measurements_LLN0_Beh; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_t; +extern DataObject iedModel_Physical_Measurements_LLN0_Health; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_t; +extern DataObject iedModel_Physical_Measurements_LLN0_NamPlt; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_d; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Physical_Measurements_LPHD1; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyNam; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyHealth; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_t; +extern DataObject iedModel_Physical_Measurements_LPHD1_Proxy; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t; + +extern DataSet ds_Inverter_LLN0_dataset1; + + +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda0; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda1; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda2; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda3; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda4; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda0 = { + "Inverter", + false, + "LLN0$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda1 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda1 = { + "Battery", + false, + "LLN0$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda2 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda2 = { + "Inverter", + false, + "MMXU1$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda3 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda3 = { + "Inverter", + false, + "MMXU1$CF$Mod$ctlModel", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda4 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda4 = { + "Inverter", + false, + "MMXU1$MX$TotW$mag", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_Inverter_LLN0_dataset1 = { + "Inverter", + "LLN0$dataset1", + 5, + &ds_Inverter_LLN0_dataset1_fcda0, + NULL +}; + +LogicalDevice iedModel_Inverter = { + LogicalDeviceModelType, + "Inverter", + (ModelNode*) &iedModel, + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Inverter_LLN0 +}; + +LogicalNode iedModel_Inverter_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Inverter, + (ModelNode*) &iedModel_Inverter_LPHD1, + (ModelNode*) &iedModel_Inverter_LLN0_Mod, +}; + +DataObject iedModel_Inverter_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Inverter_LLN0, + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + (ModelNode*) &iedModel_Inverter_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LLN0_Mod, + (ModelNode*) &iedModel_Inverter_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LLN0_Mod, + (ModelNode*) &iedModel_Inverter_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Inverter_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Inverter_LLN0, + (ModelNode*) &iedModel_Inverter_LLN0_Health, + (ModelNode*) &iedModel_Inverter_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + (ModelNode*) &iedModel_Inverter_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + (ModelNode*) &iedModel_Inverter_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Inverter_LLN0, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LLN0_Health, + (ModelNode*) &iedModel_Inverter_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LLN0_Health, + (ModelNode*) &iedModel_Inverter_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Inverter_LLN0, + NULL, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Inverter_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Inverter, + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyNam, +}; + +DataObject iedModel_Inverter_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Inverter_LPHD1, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Inverter_LPHD1, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Inverter_LPHD1, + NULL, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Inverter_ZINV1 = { + LogicalNodeModelType, + "ZINV1", + (ModelNode*) &iedModel_Inverter, + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, +}; + +DataObject iedModel_Inverter_ZINV1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod_q, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + (ModelNode*) &iedModel_Inverter_ZINV1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + (ModelNode*) &iedModel_Inverter_ZINV1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + (ModelNode*) &iedModel_Inverter_ZINV1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_WRtg = { + DataObjectModelType, + "WRtg", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_units, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_VarRtg = { + DataObjectModelType, + "VarRtg", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_ACTyp, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_units, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_ACTyp = { + DataObjectModelType, + "ACTyp", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet, + (ModelNode*) &iedModel_Inverter_ZINV1_ACTyp_setVal, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_ACTyp_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_Inverter_ZINV1_ACTyp, + NULL, + NULL, + 0, + IEC61850_FC_SP, + INT32, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_OutWSet = { + DataObjectModelType, + "OutWSet", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_units, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_OutVarSet = { + DataObjectModelType, + "OutVarSet", + (ModelNode*) &iedModel_Inverter_ZINV1, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_units, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +LogicalNode iedModel_Inverter_MMXU1 = { + LogicalNodeModelType, + "MMXU1", + (ModelNode*) &iedModel_Inverter, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, +}; + +DataObject iedModel_Inverter_MMXU1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod_q, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + (ModelNode*) &iedModel_Inverter_MMXU1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + (ModelNode*) &iedModel_Inverter_MMXU1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + (ModelNode*) &iedModel_Inverter_MMXU1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_TotW = { + DataObjectModelType, + "TotW", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_q, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_TotVAr = { + DataObjectModelType, + "TotVAr", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_q, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_TotVA = { + DataObjectModelType, + "TotVA", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_Hz = { + DataObjectModelType, + "Hz", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_q, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV = { + DataObjectModelType, + "PhV", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + 0 +}; + +DataObject iedModel_Inverter_MMXU1_PhV_phsA = { + DataObjectModelType, + "phsA", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV_phsB = { + DataObjectModelType, + "phsB", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV_phsC = { + DataObjectModelType, + "phsC", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV_neut = { + DataObjectModelType, + "neut", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A = { + DataObjectModelType, + "A", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_W, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + 0 +}; + +DataObject iedModel_Inverter_MMXU1_A_phsA = { + DataObjectModelType, + "phsA", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A_phsB = { + DataObjectModelType, + "phsB", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A_phsC = { + DataObjectModelType, + "phsC", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A_neut = { + DataObjectModelType, + "neut", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_W = { + DataObjectModelType, + "W", + (ModelNode*) &iedModel_Inverter_MMXU1, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + 0 +}; + +DataObject iedModel_Inverter_MMXU1_W_phsA = { + DataObjectModelType, + "phsA", + (ModelNode*) &iedModel_Inverter_MMXU1_W, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_W_phsB = { + DataObjectModelType, + "phsB", + (ModelNode*) &iedModel_Inverter_MMXU1_W, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_q, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_W_phsC = { + DataObjectModelType, + "phsC", + (ModelNode*) &iedModel_Inverter_MMXU1_W, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_q, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + + +LogicalDevice iedModel_Battery = { + LogicalDeviceModelType, + "Battery", + (ModelNode*) &iedModel, + (ModelNode*) &iedModel_Physical_Measurements, + (ModelNode*) &iedModel_Battery_LLN0 +}; + +LogicalNode iedModel_Battery_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Battery_LPHD1, + (ModelNode*) &iedModel_Battery_LLN0_Mod, +}; + +DataObject iedModel_Battery_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Battery_LLN0, + (ModelNode*) &iedModel_Battery_LLN0_Beh, + (ModelNode*) &iedModel_Battery_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LLN0_Mod, + (ModelNode*) &iedModel_Battery_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LLN0_Mod, + (ModelNode*) &iedModel_Battery_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Battery_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Battery_LLN0, + (ModelNode*) &iedModel_Battery_LLN0_Health, + (ModelNode*) &iedModel_Battery_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LLN0_Beh, + (ModelNode*) &iedModel_Battery_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LLN0_Beh, + (ModelNode*) &iedModel_Battery_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Battery_LLN0, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LLN0_Health, + (ModelNode*) &iedModel_Battery_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LLN0_Health, + (ModelNode*) &iedModel_Battery_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Battery_LLN0, + NULL, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Battery_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_LPHD1_PhyNam, +}; + +DataObject iedModel_Battery_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Battery_LPHD1, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Battery_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Battery_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Battery_LPHD1, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Battery_LPHD1, + NULL, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Battery_ZBAT1 = { + LogicalNodeModelType, + "ZBAT1", + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, +}; + +DataObject iedModel_Battery_ZBAT1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod_q, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBAT1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + (ModelNode*) &iedModel_Battery_ZBAT1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + (ModelNode*) &iedModel_Battery_ZBAT1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Vol = { + DataObjectModelType, + "Vol", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_q, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Amp = { + DataObjectModelType, + "Amp", + (ModelNode*) &iedModel_Battery_ZBAT1, + NULL, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_q, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Battery_ZBTC1 = { + LogicalNodeModelType, + "ZBTC1", + (ModelNode*) &iedModel_Battery, + NULL, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, +}; + +DataObject iedModel_Battery_ZBTC1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod_q, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBTC1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + (ModelNode*) &iedModel_Battery_ZBTC1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + (ModelNode*) &iedModel_Battery_ZBTC1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_BatChaSt, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_BatChaSt = { + DataObjectModelType, + "BatChaSt", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_BatChaPwr, + NULL, + 0 +}; + +DataObject iedModel_Battery_ZBTC1_BatChaPwr = { + DataObjectModelType, + "BatChaPwr", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_BatChaMod, + NULL, + 0 +}; + +DataObject iedModel_Battery_ZBTC1_BatChaMod = { + DataObjectModelType, + "BatChaMod", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + NULL, + 0 +}; + +DataObject iedModel_Battery_ZBTC1_ChaV = { + DataObjectModelType, + "ChaV", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_q, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_ChaA = { + DataObjectModelType, + "ChaA", + (ModelNode*) &iedModel_Battery_ZBTC1, + NULL, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_q, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + + +LogicalDevice iedModel_Physical_Measurements = { + LogicalDeviceModelType, + "Physical_Measurements", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LLN0 +}; + +LogicalNode iedModel_Physical_Measurements_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Physical_Measurements, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, +}; + +DataObject iedModel_Physical_Measurements_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Physical_Measurements_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Physical_Measurements, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyNam, +}; + +DataObject iedModel_Physical_Measurements_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_Inverter_LLN0_report0; + +ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb101", "ID", false, "dataset1", 0, 3, 32, 0, 0, NULL}; + + + + +IedModel iedModel = { + "ied1", + &iedModel_Inverter, + &ds_Inverter_LLN0_dataset1, + &iedModel_Inverter_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_Inverter_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Inverter_ZINV1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Inverter_MMXU1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Battery_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Battery_ZBAT1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Battery_ZBTC1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Physical_Measurements_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); +} diff --git a/examples/server_example2/static_model.h b/examples/server_example2/static_model.h new file mode 100644 index 0000000..34623f8 --- /dev/null +++ b/examples/server_example2/static_model.h @@ -0,0 +1,609 @@ +/* + * static_model.h + * + * automatically generated from complexModel.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_Inverter; +extern LogicalNode iedModel_Inverter_LLN0; +extern DataObject iedModel_Inverter_LLN0_Mod; +extern DataAttribute iedModel_Inverter_LLN0_Mod_q; +extern DataAttribute iedModel_Inverter_LLN0_Mod_t; +extern DataAttribute iedModel_Inverter_LLN0_Mod_ctlModel; +extern DataObject iedModel_Inverter_LLN0_Beh; +extern DataAttribute iedModel_Inverter_LLN0_Beh_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Beh_q; +extern DataAttribute iedModel_Inverter_LLN0_Beh_t; +extern DataObject iedModel_Inverter_LLN0_Health; +extern DataAttribute iedModel_Inverter_LLN0_Health_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Health_q; +extern DataAttribute iedModel_Inverter_LLN0_Health_t; +extern DataObject iedModel_Inverter_LLN0_NamPlt; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_d; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Inverter_LPHD1; +extern DataObject iedModel_Inverter_LPHD1_PhyNam; +extern DataAttribute iedModel_Inverter_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Inverter_LPHD1_PhyHealth; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_t; +extern DataObject iedModel_Inverter_LPHD1_Proxy; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_q; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_t; +extern LogicalNode iedModel_Inverter_ZINV1; +extern DataObject iedModel_Inverter_ZINV1_Mod; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_q; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_t; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_ctlModel; +extern DataObject iedModel_Inverter_ZINV1_Beh; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_q; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_t; +extern DataObject iedModel_Inverter_ZINV1_Health; +extern DataAttribute iedModel_Inverter_ZINV1_Health_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Health_q; +extern DataAttribute iedModel_Inverter_ZINV1_Health_t; +extern DataObject iedModel_Inverter_ZINV1_NamPlt; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_d; +extern DataObject iedModel_Inverter_ZINV1_WRtg; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_VarRtg; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_ACTyp; +extern DataAttribute iedModel_Inverter_ZINV1_ACTyp_setVal; +extern DataObject iedModel_Inverter_ZINV1_OutWSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_OutVarSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit; +extern LogicalNode iedModel_Inverter_MMXU1; +extern DataObject iedModel_Inverter_MMXU1_Mod; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_q; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_t; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_ctlModel; +extern DataObject iedModel_Inverter_MMXU1_Beh; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_q; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_t; +extern DataObject iedModel_Inverter_MMXU1_Health; +extern DataAttribute iedModel_Inverter_MMXU1_Health_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Health_q; +extern DataAttribute iedModel_Inverter_MMXU1_Health_t; +extern DataObject iedModel_Inverter_MMXU1_NamPlt; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_d; +extern DataObject iedModel_Inverter_MMXU1_TotW; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_t; +extern DataObject iedModel_Inverter_MMXU1_TotVAr; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_t; +extern DataObject iedModel_Inverter_MMXU1_TotVA; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_t; +extern DataObject iedModel_Inverter_MMXU1_Hz; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_q; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_t; +extern DataObject iedModel_Inverter_MMXU1_PhV; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_neut; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_t; +extern DataObject iedModel_Inverter_MMXU1_A; +extern DataObject iedModel_Inverter_MMXU1_A_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_A_neut; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_t; +extern DataObject iedModel_Inverter_MMXU1_W; +extern DataObject iedModel_Inverter_MMXU1_W_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_t; +extern LogicalDevice iedModel_Battery; +extern LogicalNode iedModel_Battery_LLN0; +extern DataObject iedModel_Battery_LLN0_Mod; +extern DataAttribute iedModel_Battery_LLN0_Mod_q; +extern DataAttribute iedModel_Battery_LLN0_Mod_t; +extern DataAttribute iedModel_Battery_LLN0_Mod_ctlModel; +extern DataObject iedModel_Battery_LLN0_Beh; +extern DataAttribute iedModel_Battery_LLN0_Beh_stVal; +extern DataAttribute iedModel_Battery_LLN0_Beh_q; +extern DataAttribute iedModel_Battery_LLN0_Beh_t; +extern DataObject iedModel_Battery_LLN0_Health; +extern DataAttribute iedModel_Battery_LLN0_Health_stVal; +extern DataAttribute iedModel_Battery_LLN0_Health_q; +extern DataAttribute iedModel_Battery_LLN0_Health_t; +extern DataObject iedModel_Battery_LLN0_NamPlt; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_d; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Battery_LPHD1; +extern DataObject iedModel_Battery_LPHD1_PhyNam; +extern DataAttribute iedModel_Battery_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Battery_LPHD1_PhyHealth; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_t; +extern DataObject iedModel_Battery_LPHD1_Proxy; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_q; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_t; +extern LogicalNode iedModel_Battery_ZBAT1; +extern DataObject iedModel_Battery_ZBAT1_Mod; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_q; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_t; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBAT1_Beh; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_q; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_t; +extern DataObject iedModel_Battery_ZBAT1_Health; +extern DataAttribute iedModel_Battery_ZBAT1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Health_q; +extern DataAttribute iedModel_Battery_ZBAT1_Health_t; +extern DataObject iedModel_Battery_ZBAT1_NamPlt; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_d; +extern DataObject iedModel_Battery_ZBAT1_Vol; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_q; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_t; +extern DataObject iedModel_Battery_ZBAT1_Amp; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_q; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_t; +extern LogicalNode iedModel_Battery_ZBTC1; +extern DataObject iedModel_Battery_ZBTC1_Mod; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_q; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_t; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBTC1_Beh; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_q; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_t; +extern DataObject iedModel_Battery_ZBTC1_Health; +extern DataAttribute iedModel_Battery_ZBTC1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Health_q; +extern DataAttribute iedModel_Battery_ZBTC1_Health_t; +extern DataObject iedModel_Battery_ZBTC1_NamPlt; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_d; +extern DataObject iedModel_Battery_ZBTC1_BatChaSt; +extern DataObject iedModel_Battery_ZBTC1_BatChaPwr; +extern DataObject iedModel_Battery_ZBTC1_BatChaMod; +extern DataObject iedModel_Battery_ZBTC1_ChaV; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_t; +extern DataObject iedModel_Battery_ZBTC1_ChaA; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_t; +extern LogicalDevice iedModel_Physical_Measurements; +extern LogicalNode iedModel_Physical_Measurements_LLN0; +extern DataObject iedModel_Physical_Measurements_LLN0_Mod; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_t; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_ctlModel; +extern DataObject iedModel_Physical_Measurements_LLN0_Beh; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_t; +extern DataObject iedModel_Physical_Measurements_LLN0_Health; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_t; +extern DataObject iedModel_Physical_Measurements_LLN0_NamPlt; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_d; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Physical_Measurements_LPHD1; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyNam; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyHealth; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_t; +extern DataObject iedModel_Physical_Measurements_LPHD1_Proxy; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t; + + + +#define IEDMODEL_Inverter (&iedModel_Inverter) +#define IEDMODEL_Inverter_LLN0 (&iedModel_Inverter_LLN0) +#define IEDMODEL_Inverter_LLN0_Mod (&iedModel_Inverter_LLN0_Mod) +#define IEDMODEL_Inverter_LLN0_Mod_q (&iedModel_Inverter_LLN0_Mod_q) +#define IEDMODEL_Inverter_LLN0_Mod_t (&iedModel_Inverter_LLN0_Mod_t) +#define IEDMODEL_Inverter_LLN0_Mod_ctlModel (&iedModel_Inverter_LLN0_Mod_ctlModel) +#define IEDMODEL_Inverter_LLN0_Beh (&iedModel_Inverter_LLN0_Beh) +#define IEDMODEL_Inverter_LLN0_Beh_stVal (&iedModel_Inverter_LLN0_Beh_stVal) +#define IEDMODEL_Inverter_LLN0_Beh_q (&iedModel_Inverter_LLN0_Beh_q) +#define IEDMODEL_Inverter_LLN0_Beh_t (&iedModel_Inverter_LLN0_Beh_t) +#define IEDMODEL_Inverter_LLN0_Health (&iedModel_Inverter_LLN0_Health) +#define IEDMODEL_Inverter_LLN0_Health_stVal (&iedModel_Inverter_LLN0_Health_stVal) +#define IEDMODEL_Inverter_LLN0_Health_q (&iedModel_Inverter_LLN0_Health_q) +#define IEDMODEL_Inverter_LLN0_Health_t (&iedModel_Inverter_LLN0_Health_t) +#define IEDMODEL_Inverter_LLN0_NamPlt (&iedModel_Inverter_LLN0_NamPlt) +#define IEDMODEL_Inverter_LLN0_NamPlt_vendor (&iedModel_Inverter_LLN0_NamPlt_vendor) +#define IEDMODEL_Inverter_LLN0_NamPlt_swRev (&iedModel_Inverter_LLN0_NamPlt_swRev) +#define IEDMODEL_Inverter_LLN0_NamPlt_d (&iedModel_Inverter_LLN0_NamPlt_d) +#define IEDMODEL_Inverter_LLN0_NamPlt_configRev (&iedModel_Inverter_LLN0_NamPlt_configRev) +#define IEDMODEL_Inverter_LLN0_NamPlt_ldNs (&iedModel_Inverter_LLN0_NamPlt_ldNs) +#define IEDMODEL_Inverter_LPHD1 (&iedModel_Inverter_LPHD1) +#define IEDMODEL_Inverter_LPHD1_PhyNam (&iedModel_Inverter_LPHD1_PhyNam) +#define IEDMODEL_Inverter_LPHD1_PhyNam_vendor (&iedModel_Inverter_LPHD1_PhyNam_vendor) +#define IEDMODEL_Inverter_LPHD1_PhyHealth (&iedModel_Inverter_LPHD1_PhyHealth) +#define IEDMODEL_Inverter_LPHD1_PhyHealth_stVal (&iedModel_Inverter_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Inverter_LPHD1_PhyHealth_q (&iedModel_Inverter_LPHD1_PhyHealth_q) +#define IEDMODEL_Inverter_LPHD1_PhyHealth_t (&iedModel_Inverter_LPHD1_PhyHealth_t) +#define IEDMODEL_Inverter_LPHD1_Proxy (&iedModel_Inverter_LPHD1_Proxy) +#define IEDMODEL_Inverter_LPHD1_Proxy_stVal (&iedModel_Inverter_LPHD1_Proxy_stVal) +#define IEDMODEL_Inverter_LPHD1_Proxy_q (&iedModel_Inverter_LPHD1_Proxy_q) +#define IEDMODEL_Inverter_LPHD1_Proxy_t (&iedModel_Inverter_LPHD1_Proxy_t) +#define IEDMODEL_Inverter_ZINV1 (&iedModel_Inverter_ZINV1) +#define IEDMODEL_Inverter_ZINV1_Mod (&iedModel_Inverter_ZINV1_Mod) +#define IEDMODEL_Inverter_ZINV1_Mod_q (&iedModel_Inverter_ZINV1_Mod_q) +#define IEDMODEL_Inverter_ZINV1_Mod_t (&iedModel_Inverter_ZINV1_Mod_t) +#define IEDMODEL_Inverter_ZINV1_Mod_ctlModel (&iedModel_Inverter_ZINV1_Mod_ctlModel) +#define IEDMODEL_Inverter_ZINV1_Beh (&iedModel_Inverter_ZINV1_Beh) +#define IEDMODEL_Inverter_ZINV1_Beh_stVal (&iedModel_Inverter_ZINV1_Beh_stVal) +#define IEDMODEL_Inverter_ZINV1_Beh_q (&iedModel_Inverter_ZINV1_Beh_q) +#define IEDMODEL_Inverter_ZINV1_Beh_t (&iedModel_Inverter_ZINV1_Beh_t) +#define IEDMODEL_Inverter_ZINV1_Health (&iedModel_Inverter_ZINV1_Health) +#define IEDMODEL_Inverter_ZINV1_Health_stVal (&iedModel_Inverter_ZINV1_Health_stVal) +#define IEDMODEL_Inverter_ZINV1_Health_q (&iedModel_Inverter_ZINV1_Health_q) +#define IEDMODEL_Inverter_ZINV1_Health_t (&iedModel_Inverter_ZINV1_Health_t) +#define IEDMODEL_Inverter_ZINV1_NamPlt (&iedModel_Inverter_ZINV1_NamPlt) +#define IEDMODEL_Inverter_ZINV1_NamPlt_vendor (&iedModel_Inverter_ZINV1_NamPlt_vendor) +#define IEDMODEL_Inverter_ZINV1_NamPlt_swRev (&iedModel_Inverter_ZINV1_NamPlt_swRev) +#define IEDMODEL_Inverter_ZINV1_NamPlt_d (&iedModel_Inverter_ZINV1_NamPlt_d) +#define IEDMODEL_Inverter_ZINV1_WRtg (&iedModel_Inverter_ZINV1_WRtg) +#define IEDMODEL_Inverter_ZINV1_WRtg_setMag (&iedModel_Inverter_ZINV1_WRtg_setMag) +#define IEDMODEL_Inverter_ZINV1_WRtg_setMag_f (&iedModel_Inverter_ZINV1_WRtg_setMag_f) +#define IEDMODEL_Inverter_ZINV1_WRtg_units (&iedModel_Inverter_ZINV1_WRtg_units) +#define IEDMODEL_Inverter_ZINV1_WRtg_units_SIUnit (&iedModel_Inverter_ZINV1_WRtg_units_SIUnit) +#define IEDMODEL_Inverter_ZINV1_VarRtg (&iedModel_Inverter_ZINV1_VarRtg) +#define IEDMODEL_Inverter_ZINV1_VarRtg_setMag (&iedModel_Inverter_ZINV1_VarRtg_setMag) +#define IEDMODEL_Inverter_ZINV1_VarRtg_setMag_f (&iedModel_Inverter_ZINV1_VarRtg_setMag_f) +#define IEDMODEL_Inverter_ZINV1_VarRtg_units (&iedModel_Inverter_ZINV1_VarRtg_units) +#define IEDMODEL_Inverter_ZINV1_VarRtg_units_SIUnit (&iedModel_Inverter_ZINV1_VarRtg_units_SIUnit) +#define IEDMODEL_Inverter_ZINV1_ACTyp (&iedModel_Inverter_ZINV1_ACTyp) +#define IEDMODEL_Inverter_ZINV1_ACTyp_setVal (&iedModel_Inverter_ZINV1_ACTyp_setVal) +#define IEDMODEL_Inverter_ZINV1_OutWSet (&iedModel_Inverter_ZINV1_OutWSet) +#define IEDMODEL_Inverter_ZINV1_OutWSet_setMag (&iedModel_Inverter_ZINV1_OutWSet_setMag) +#define IEDMODEL_Inverter_ZINV1_OutWSet_setMag_f (&iedModel_Inverter_ZINV1_OutWSet_setMag_f) +#define IEDMODEL_Inverter_ZINV1_OutWSet_units (&iedModel_Inverter_ZINV1_OutWSet_units) +#define IEDMODEL_Inverter_ZINV1_OutWSet_units_SIUnit (&iedModel_Inverter_ZINV1_OutWSet_units_SIUnit) +#define IEDMODEL_Inverter_ZINV1_OutVarSet (&iedModel_Inverter_ZINV1_OutVarSet) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_setMag (&iedModel_Inverter_ZINV1_OutVarSet_setMag) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f (&iedModel_Inverter_ZINV1_OutVarSet_setMag_f) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_units (&iedModel_Inverter_ZINV1_OutVarSet_units) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_units_SIUnit (&iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit) +#define IEDMODEL_Inverter_MMXU1 (&iedModel_Inverter_MMXU1) +#define IEDMODEL_Inverter_MMXU1_Mod (&iedModel_Inverter_MMXU1_Mod) +#define IEDMODEL_Inverter_MMXU1_Mod_q (&iedModel_Inverter_MMXU1_Mod_q) +#define IEDMODEL_Inverter_MMXU1_Mod_t (&iedModel_Inverter_MMXU1_Mod_t) +#define IEDMODEL_Inverter_MMXU1_Mod_ctlModel (&iedModel_Inverter_MMXU1_Mod_ctlModel) +#define IEDMODEL_Inverter_MMXU1_Beh (&iedModel_Inverter_MMXU1_Beh) +#define IEDMODEL_Inverter_MMXU1_Beh_stVal (&iedModel_Inverter_MMXU1_Beh_stVal) +#define IEDMODEL_Inverter_MMXU1_Beh_q (&iedModel_Inverter_MMXU1_Beh_q) +#define IEDMODEL_Inverter_MMXU1_Beh_t (&iedModel_Inverter_MMXU1_Beh_t) +#define IEDMODEL_Inverter_MMXU1_Health (&iedModel_Inverter_MMXU1_Health) +#define IEDMODEL_Inverter_MMXU1_Health_stVal (&iedModel_Inverter_MMXU1_Health_stVal) +#define IEDMODEL_Inverter_MMXU1_Health_q (&iedModel_Inverter_MMXU1_Health_q) +#define IEDMODEL_Inverter_MMXU1_Health_t (&iedModel_Inverter_MMXU1_Health_t) +#define IEDMODEL_Inverter_MMXU1_NamPlt (&iedModel_Inverter_MMXU1_NamPlt) +#define IEDMODEL_Inverter_MMXU1_NamPlt_vendor (&iedModel_Inverter_MMXU1_NamPlt_vendor) +#define IEDMODEL_Inverter_MMXU1_NamPlt_swRev (&iedModel_Inverter_MMXU1_NamPlt_swRev) +#define IEDMODEL_Inverter_MMXU1_NamPlt_d (&iedModel_Inverter_MMXU1_NamPlt_d) +#define IEDMODEL_Inverter_MMXU1_TotW (&iedModel_Inverter_MMXU1_TotW) +#define IEDMODEL_Inverter_MMXU1_TotW_mag (&iedModel_Inverter_MMXU1_TotW_mag) +#define IEDMODEL_Inverter_MMXU1_TotW_mag_f (&iedModel_Inverter_MMXU1_TotW_mag_f) +#define IEDMODEL_Inverter_MMXU1_TotW_q (&iedModel_Inverter_MMXU1_TotW_q) +#define IEDMODEL_Inverter_MMXU1_TotW_t (&iedModel_Inverter_MMXU1_TotW_t) +#define IEDMODEL_Inverter_MMXU1_TotVAr (&iedModel_Inverter_MMXU1_TotVAr) +#define IEDMODEL_Inverter_MMXU1_TotVAr_mag (&iedModel_Inverter_MMXU1_TotVAr_mag) +#define IEDMODEL_Inverter_MMXU1_TotVAr_mag_f (&iedModel_Inverter_MMXU1_TotVAr_mag_f) +#define IEDMODEL_Inverter_MMXU1_TotVAr_q (&iedModel_Inverter_MMXU1_TotVAr_q) +#define IEDMODEL_Inverter_MMXU1_TotVAr_t (&iedModel_Inverter_MMXU1_TotVAr_t) +#define IEDMODEL_Inverter_MMXU1_TotVA (&iedModel_Inverter_MMXU1_TotVA) +#define IEDMODEL_Inverter_MMXU1_TotVA_mag (&iedModel_Inverter_MMXU1_TotVA_mag) +#define IEDMODEL_Inverter_MMXU1_TotVA_mag_f (&iedModel_Inverter_MMXU1_TotVA_mag_f) +#define IEDMODEL_Inverter_MMXU1_TotVA_q (&iedModel_Inverter_MMXU1_TotVA_q) +#define IEDMODEL_Inverter_MMXU1_TotVA_t (&iedModel_Inverter_MMXU1_TotVA_t) +#define IEDMODEL_Inverter_MMXU1_Hz (&iedModel_Inverter_MMXU1_Hz) +#define IEDMODEL_Inverter_MMXU1_Hz_mag (&iedModel_Inverter_MMXU1_Hz_mag) +#define IEDMODEL_Inverter_MMXU1_Hz_mag_f (&iedModel_Inverter_MMXU1_Hz_mag_f) +#define IEDMODEL_Inverter_MMXU1_Hz_q (&iedModel_Inverter_MMXU1_Hz_q) +#define IEDMODEL_Inverter_MMXU1_Hz_t (&iedModel_Inverter_MMXU1_Hz_t) +#define IEDMODEL_Inverter_MMXU1_PhV (&iedModel_Inverter_MMXU1_PhV) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA (&iedModel_Inverter_MMXU1_PhV_phsA) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_cVal (&iedModel_Inverter_MMXU1_PhV_phsA_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_cVal_mag (&iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_q (&iedModel_Inverter_MMXU1_PhV_phsA_q) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_t (&iedModel_Inverter_MMXU1_PhV_phsA_t) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB (&iedModel_Inverter_MMXU1_PhV_phsB) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_cVal (&iedModel_Inverter_MMXU1_PhV_phsB_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_cVal_mag (&iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_q (&iedModel_Inverter_MMXU1_PhV_phsB_q) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_t (&iedModel_Inverter_MMXU1_PhV_phsB_t) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC (&iedModel_Inverter_MMXU1_PhV_phsC) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_cVal (&iedModel_Inverter_MMXU1_PhV_phsC_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_cVal_mag (&iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_q (&iedModel_Inverter_MMXU1_PhV_phsC_q) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_t (&iedModel_Inverter_MMXU1_PhV_phsC_t) +#define IEDMODEL_Inverter_MMXU1_PhV_neut (&iedModel_Inverter_MMXU1_PhV_neut) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_cVal (&iedModel_Inverter_MMXU1_PhV_neut_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_cVal_mag (&iedModel_Inverter_MMXU1_PhV_neut_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_q (&iedModel_Inverter_MMXU1_PhV_neut_q) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_t (&iedModel_Inverter_MMXU1_PhV_neut_t) +#define IEDMODEL_Inverter_MMXU1_A (&iedModel_Inverter_MMXU1_A) +#define IEDMODEL_Inverter_MMXU1_A_phsA (&iedModel_Inverter_MMXU1_A_phsA) +#define IEDMODEL_Inverter_MMXU1_A_phsA_cVal (&iedModel_Inverter_MMXU1_A_phsA_cVal) +#define IEDMODEL_Inverter_MMXU1_A_phsA_cVal_mag (&iedModel_Inverter_MMXU1_A_phsA_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_phsA_cVal_mag_f (&iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_phsA_q (&iedModel_Inverter_MMXU1_A_phsA_q) +#define IEDMODEL_Inverter_MMXU1_A_phsA_t (&iedModel_Inverter_MMXU1_A_phsA_t) +#define IEDMODEL_Inverter_MMXU1_A_phsB (&iedModel_Inverter_MMXU1_A_phsB) +#define IEDMODEL_Inverter_MMXU1_A_phsB_cVal (&iedModel_Inverter_MMXU1_A_phsB_cVal) +#define IEDMODEL_Inverter_MMXU1_A_phsB_cVal_mag (&iedModel_Inverter_MMXU1_A_phsB_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_phsB_cVal_mag_f (&iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_phsB_q (&iedModel_Inverter_MMXU1_A_phsB_q) +#define IEDMODEL_Inverter_MMXU1_A_phsB_t (&iedModel_Inverter_MMXU1_A_phsB_t) +#define IEDMODEL_Inverter_MMXU1_A_phsC (&iedModel_Inverter_MMXU1_A_phsC) +#define IEDMODEL_Inverter_MMXU1_A_phsC_cVal (&iedModel_Inverter_MMXU1_A_phsC_cVal) +#define IEDMODEL_Inverter_MMXU1_A_phsC_cVal_mag (&iedModel_Inverter_MMXU1_A_phsC_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_phsC_cVal_mag_f (&iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_phsC_q (&iedModel_Inverter_MMXU1_A_phsC_q) +#define IEDMODEL_Inverter_MMXU1_A_phsC_t (&iedModel_Inverter_MMXU1_A_phsC_t) +#define IEDMODEL_Inverter_MMXU1_A_neut (&iedModel_Inverter_MMXU1_A_neut) +#define IEDMODEL_Inverter_MMXU1_A_neut_cVal (&iedModel_Inverter_MMXU1_A_neut_cVal) +#define IEDMODEL_Inverter_MMXU1_A_neut_cVal_mag (&iedModel_Inverter_MMXU1_A_neut_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_neut_cVal_mag_f (&iedModel_Inverter_MMXU1_A_neut_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_neut_q (&iedModel_Inverter_MMXU1_A_neut_q) +#define IEDMODEL_Inverter_MMXU1_A_neut_t (&iedModel_Inverter_MMXU1_A_neut_t) +#define IEDMODEL_Inverter_MMXU1_W (&iedModel_Inverter_MMXU1_W) +#define IEDMODEL_Inverter_MMXU1_W_phsA (&iedModel_Inverter_MMXU1_W_phsA) +#define IEDMODEL_Inverter_MMXU1_W_phsA_cVal (&iedModel_Inverter_MMXU1_W_phsA_cVal) +#define IEDMODEL_Inverter_MMXU1_W_phsA_cVal_mag (&iedModel_Inverter_MMXU1_W_phsA_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_W_phsA_cVal_mag_f (&iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_W_phsA_q (&iedModel_Inverter_MMXU1_W_phsA_q) +#define IEDMODEL_Inverter_MMXU1_W_phsA_t (&iedModel_Inverter_MMXU1_W_phsA_t) +#define IEDMODEL_Inverter_MMXU1_W_phsB (&iedModel_Inverter_MMXU1_W_phsB) +#define IEDMODEL_Inverter_MMXU1_W_phsB_cVal (&iedModel_Inverter_MMXU1_W_phsB_cVal) +#define IEDMODEL_Inverter_MMXU1_W_phsB_cVal_mag (&iedModel_Inverter_MMXU1_W_phsB_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_W_phsB_cVal_mag_f (&iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_W_phsB_q (&iedModel_Inverter_MMXU1_W_phsB_q) +#define IEDMODEL_Inverter_MMXU1_W_phsB_t (&iedModel_Inverter_MMXU1_W_phsB_t) +#define IEDMODEL_Inverter_MMXU1_W_phsC (&iedModel_Inverter_MMXU1_W_phsC) +#define IEDMODEL_Inverter_MMXU1_W_phsC_cVal (&iedModel_Inverter_MMXU1_W_phsC_cVal) +#define IEDMODEL_Inverter_MMXU1_W_phsC_cVal_mag (&iedModel_Inverter_MMXU1_W_phsC_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_W_phsC_cVal_mag_f (&iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_W_phsC_q (&iedModel_Inverter_MMXU1_W_phsC_q) +#define IEDMODEL_Inverter_MMXU1_W_phsC_t (&iedModel_Inverter_MMXU1_W_phsC_t) +#define IEDMODEL_Battery (&iedModel_Battery) +#define IEDMODEL_Battery_LLN0 (&iedModel_Battery_LLN0) +#define IEDMODEL_Battery_LLN0_Mod (&iedModel_Battery_LLN0_Mod) +#define IEDMODEL_Battery_LLN0_Mod_q (&iedModel_Battery_LLN0_Mod_q) +#define IEDMODEL_Battery_LLN0_Mod_t (&iedModel_Battery_LLN0_Mod_t) +#define IEDMODEL_Battery_LLN0_Mod_ctlModel (&iedModel_Battery_LLN0_Mod_ctlModel) +#define IEDMODEL_Battery_LLN0_Beh (&iedModel_Battery_LLN0_Beh) +#define IEDMODEL_Battery_LLN0_Beh_stVal (&iedModel_Battery_LLN0_Beh_stVal) +#define IEDMODEL_Battery_LLN0_Beh_q (&iedModel_Battery_LLN0_Beh_q) +#define IEDMODEL_Battery_LLN0_Beh_t (&iedModel_Battery_LLN0_Beh_t) +#define IEDMODEL_Battery_LLN0_Health (&iedModel_Battery_LLN0_Health) +#define IEDMODEL_Battery_LLN0_Health_stVal (&iedModel_Battery_LLN0_Health_stVal) +#define IEDMODEL_Battery_LLN0_Health_q (&iedModel_Battery_LLN0_Health_q) +#define IEDMODEL_Battery_LLN0_Health_t (&iedModel_Battery_LLN0_Health_t) +#define IEDMODEL_Battery_LLN0_NamPlt (&iedModel_Battery_LLN0_NamPlt) +#define IEDMODEL_Battery_LLN0_NamPlt_vendor (&iedModel_Battery_LLN0_NamPlt_vendor) +#define IEDMODEL_Battery_LLN0_NamPlt_swRev (&iedModel_Battery_LLN0_NamPlt_swRev) +#define IEDMODEL_Battery_LLN0_NamPlt_d (&iedModel_Battery_LLN0_NamPlt_d) +#define IEDMODEL_Battery_LLN0_NamPlt_configRev (&iedModel_Battery_LLN0_NamPlt_configRev) +#define IEDMODEL_Battery_LLN0_NamPlt_ldNs (&iedModel_Battery_LLN0_NamPlt_ldNs) +#define IEDMODEL_Battery_LPHD1 (&iedModel_Battery_LPHD1) +#define IEDMODEL_Battery_LPHD1_PhyNam (&iedModel_Battery_LPHD1_PhyNam) +#define IEDMODEL_Battery_LPHD1_PhyNam_vendor (&iedModel_Battery_LPHD1_PhyNam_vendor) +#define IEDMODEL_Battery_LPHD1_PhyHealth (&iedModel_Battery_LPHD1_PhyHealth) +#define IEDMODEL_Battery_LPHD1_PhyHealth_stVal (&iedModel_Battery_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Battery_LPHD1_PhyHealth_q (&iedModel_Battery_LPHD1_PhyHealth_q) +#define IEDMODEL_Battery_LPHD1_PhyHealth_t (&iedModel_Battery_LPHD1_PhyHealth_t) +#define IEDMODEL_Battery_LPHD1_Proxy (&iedModel_Battery_LPHD1_Proxy) +#define IEDMODEL_Battery_LPHD1_Proxy_stVal (&iedModel_Battery_LPHD1_Proxy_stVal) +#define IEDMODEL_Battery_LPHD1_Proxy_q (&iedModel_Battery_LPHD1_Proxy_q) +#define IEDMODEL_Battery_LPHD1_Proxy_t (&iedModel_Battery_LPHD1_Proxy_t) +#define IEDMODEL_Battery_ZBAT1 (&iedModel_Battery_ZBAT1) +#define IEDMODEL_Battery_ZBAT1_Mod (&iedModel_Battery_ZBAT1_Mod) +#define IEDMODEL_Battery_ZBAT1_Mod_q (&iedModel_Battery_ZBAT1_Mod_q) +#define IEDMODEL_Battery_ZBAT1_Mod_t (&iedModel_Battery_ZBAT1_Mod_t) +#define IEDMODEL_Battery_ZBAT1_Mod_ctlModel (&iedModel_Battery_ZBAT1_Mod_ctlModel) +#define IEDMODEL_Battery_ZBAT1_Beh (&iedModel_Battery_ZBAT1_Beh) +#define IEDMODEL_Battery_ZBAT1_Beh_stVal (&iedModel_Battery_ZBAT1_Beh_stVal) +#define IEDMODEL_Battery_ZBAT1_Beh_q (&iedModel_Battery_ZBAT1_Beh_q) +#define IEDMODEL_Battery_ZBAT1_Beh_t (&iedModel_Battery_ZBAT1_Beh_t) +#define IEDMODEL_Battery_ZBAT1_Health (&iedModel_Battery_ZBAT1_Health) +#define IEDMODEL_Battery_ZBAT1_Health_stVal (&iedModel_Battery_ZBAT1_Health_stVal) +#define IEDMODEL_Battery_ZBAT1_Health_q (&iedModel_Battery_ZBAT1_Health_q) +#define IEDMODEL_Battery_ZBAT1_Health_t (&iedModel_Battery_ZBAT1_Health_t) +#define IEDMODEL_Battery_ZBAT1_NamPlt (&iedModel_Battery_ZBAT1_NamPlt) +#define IEDMODEL_Battery_ZBAT1_NamPlt_vendor (&iedModel_Battery_ZBAT1_NamPlt_vendor) +#define IEDMODEL_Battery_ZBAT1_NamPlt_swRev (&iedModel_Battery_ZBAT1_NamPlt_swRev) +#define IEDMODEL_Battery_ZBAT1_NamPlt_d (&iedModel_Battery_ZBAT1_NamPlt_d) +#define IEDMODEL_Battery_ZBAT1_Vol (&iedModel_Battery_ZBAT1_Vol) +#define IEDMODEL_Battery_ZBAT1_Vol_mag (&iedModel_Battery_ZBAT1_Vol_mag) +#define IEDMODEL_Battery_ZBAT1_Vol_mag_f (&iedModel_Battery_ZBAT1_Vol_mag_f) +#define IEDMODEL_Battery_ZBAT1_Vol_q (&iedModel_Battery_ZBAT1_Vol_q) +#define IEDMODEL_Battery_ZBAT1_Vol_t (&iedModel_Battery_ZBAT1_Vol_t) +#define IEDMODEL_Battery_ZBAT1_Amp (&iedModel_Battery_ZBAT1_Amp) +#define IEDMODEL_Battery_ZBAT1_Amp_mag (&iedModel_Battery_ZBAT1_Amp_mag) +#define IEDMODEL_Battery_ZBAT1_Amp_mag_f (&iedModel_Battery_ZBAT1_Amp_mag_f) +#define IEDMODEL_Battery_ZBAT1_Amp_q (&iedModel_Battery_ZBAT1_Amp_q) +#define IEDMODEL_Battery_ZBAT1_Amp_t (&iedModel_Battery_ZBAT1_Amp_t) +#define IEDMODEL_Battery_ZBTC1 (&iedModel_Battery_ZBTC1) +#define IEDMODEL_Battery_ZBTC1_Mod (&iedModel_Battery_ZBTC1_Mod) +#define IEDMODEL_Battery_ZBTC1_Mod_q (&iedModel_Battery_ZBTC1_Mod_q) +#define IEDMODEL_Battery_ZBTC1_Mod_t (&iedModel_Battery_ZBTC1_Mod_t) +#define IEDMODEL_Battery_ZBTC1_Mod_ctlModel (&iedModel_Battery_ZBTC1_Mod_ctlModel) +#define IEDMODEL_Battery_ZBTC1_Beh (&iedModel_Battery_ZBTC1_Beh) +#define IEDMODEL_Battery_ZBTC1_Beh_stVal (&iedModel_Battery_ZBTC1_Beh_stVal) +#define IEDMODEL_Battery_ZBTC1_Beh_q (&iedModel_Battery_ZBTC1_Beh_q) +#define IEDMODEL_Battery_ZBTC1_Beh_t (&iedModel_Battery_ZBTC1_Beh_t) +#define IEDMODEL_Battery_ZBTC1_Health (&iedModel_Battery_ZBTC1_Health) +#define IEDMODEL_Battery_ZBTC1_Health_stVal (&iedModel_Battery_ZBTC1_Health_stVal) +#define IEDMODEL_Battery_ZBTC1_Health_q (&iedModel_Battery_ZBTC1_Health_q) +#define IEDMODEL_Battery_ZBTC1_Health_t (&iedModel_Battery_ZBTC1_Health_t) +#define IEDMODEL_Battery_ZBTC1_NamPlt (&iedModel_Battery_ZBTC1_NamPlt) +#define IEDMODEL_Battery_ZBTC1_NamPlt_vendor (&iedModel_Battery_ZBTC1_NamPlt_vendor) +#define IEDMODEL_Battery_ZBTC1_NamPlt_swRev (&iedModel_Battery_ZBTC1_NamPlt_swRev) +#define IEDMODEL_Battery_ZBTC1_NamPlt_d (&iedModel_Battery_ZBTC1_NamPlt_d) +#define IEDMODEL_Battery_ZBTC1_BatChaSt (&iedModel_Battery_ZBTC1_BatChaSt) +#define IEDMODEL_Battery_ZBTC1_BatChaPwr (&iedModel_Battery_ZBTC1_BatChaPwr) +#define IEDMODEL_Battery_ZBTC1_BatChaMod (&iedModel_Battery_ZBTC1_BatChaMod) +#define IEDMODEL_Battery_ZBTC1_ChaV (&iedModel_Battery_ZBTC1_ChaV) +#define IEDMODEL_Battery_ZBTC1_ChaV_mag (&iedModel_Battery_ZBTC1_ChaV_mag) +#define IEDMODEL_Battery_ZBTC1_ChaV_mag_f (&iedModel_Battery_ZBTC1_ChaV_mag_f) +#define IEDMODEL_Battery_ZBTC1_ChaV_q (&iedModel_Battery_ZBTC1_ChaV_q) +#define IEDMODEL_Battery_ZBTC1_ChaV_t (&iedModel_Battery_ZBTC1_ChaV_t) +#define IEDMODEL_Battery_ZBTC1_ChaA (&iedModel_Battery_ZBTC1_ChaA) +#define IEDMODEL_Battery_ZBTC1_ChaA_mag (&iedModel_Battery_ZBTC1_ChaA_mag) +#define IEDMODEL_Battery_ZBTC1_ChaA_mag_f (&iedModel_Battery_ZBTC1_ChaA_mag_f) +#define IEDMODEL_Battery_ZBTC1_ChaA_q (&iedModel_Battery_ZBTC1_ChaA_q) +#define IEDMODEL_Battery_ZBTC1_ChaA_t (&iedModel_Battery_ZBTC1_ChaA_t) +#define IEDMODEL_Physical_Measurements (&iedModel_Physical_Measurements) +#define IEDMODEL_Physical_Measurements_LLN0 (&iedModel_Physical_Measurements_LLN0) +#define IEDMODEL_Physical_Measurements_LLN0_Mod (&iedModel_Physical_Measurements_LLN0_Mod) +#define IEDMODEL_Physical_Measurements_LLN0_Mod_q (&iedModel_Physical_Measurements_LLN0_Mod_q) +#define IEDMODEL_Physical_Measurements_LLN0_Mod_t (&iedModel_Physical_Measurements_LLN0_Mod_t) +#define IEDMODEL_Physical_Measurements_LLN0_Mod_ctlModel (&iedModel_Physical_Measurements_LLN0_Mod_ctlModel) +#define IEDMODEL_Physical_Measurements_LLN0_Beh (&iedModel_Physical_Measurements_LLN0_Beh) +#define IEDMODEL_Physical_Measurements_LLN0_Beh_stVal (&iedModel_Physical_Measurements_LLN0_Beh_stVal) +#define IEDMODEL_Physical_Measurements_LLN0_Beh_q (&iedModel_Physical_Measurements_LLN0_Beh_q) +#define IEDMODEL_Physical_Measurements_LLN0_Beh_t (&iedModel_Physical_Measurements_LLN0_Beh_t) +#define IEDMODEL_Physical_Measurements_LLN0_Health (&iedModel_Physical_Measurements_LLN0_Health) +#define IEDMODEL_Physical_Measurements_LLN0_Health_stVal (&iedModel_Physical_Measurements_LLN0_Health_stVal) +#define IEDMODEL_Physical_Measurements_LLN0_Health_q (&iedModel_Physical_Measurements_LLN0_Health_q) +#define IEDMODEL_Physical_Measurements_LLN0_Health_t (&iedModel_Physical_Measurements_LLN0_Health_t) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt (&iedModel_Physical_Measurements_LLN0_NamPlt) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_vendor (&iedModel_Physical_Measurements_LLN0_NamPlt_vendor) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_swRev (&iedModel_Physical_Measurements_LLN0_NamPlt_swRev) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_d (&iedModel_Physical_Measurements_LLN0_NamPlt_d) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_configRev (&iedModel_Physical_Measurements_LLN0_NamPlt_configRev) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_ldNs (&iedModel_Physical_Measurements_LLN0_NamPlt_ldNs) +#define IEDMODEL_Physical_Measurements_LPHD1 (&iedModel_Physical_Measurements_LPHD1) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyNam (&iedModel_Physical_Measurements_LPHD1_PhyNam) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyNam_vendor (&iedModel_Physical_Measurements_LPHD1_PhyNam_vendor) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth (&iedModel_Physical_Measurements_LPHD1_PhyHealth) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth_stVal (&iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth_q (&iedModel_Physical_Measurements_LPHD1_PhyHealth_q) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth_t (&iedModel_Physical_Measurements_LPHD1_PhyHealth_t) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy (&iedModel_Physical_Measurements_LPHD1_Proxy) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy_stVal (&iedModel_Physical_Measurements_LPHD1_Proxy_stVal) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy_q (&iedModel_Physical_Measurements_LPHD1_Proxy_q) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy_t (&iedModel_Physical_Measurements_LPHD1_Proxy_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example3/CMakeLists.txt b/examples/server_example3/CMakeLists.txt new file mode 100644 index 0000000..e3dbe43 --- /dev/null +++ b/examples/server_example3/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example3_SRCS + server_example3.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example3_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example3 + ${server_example3_SRCS} +) + +target_link_libraries(server_example3 + iec61850 +) diff --git a/examples/server_example3/Makefile b/examples/server_example3/Makefile new file mode 100644 index 0000000..65e2509 --- /dev/null +++ b/examples/server_example3/Makefile @@ -0,0 +1,31 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example3 +PROJECT_SOURCES = server_example3.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = simpleIO_direct_control.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +LDLIBS += -lm + +CP = cp + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + $(CP) $(PROJECT_BINARY_NAME) vmd-filestore/IEDSERVER.BIN + +clean: + rm -f $(PROJECT_BINARY_NAME) + rm -f vmd-filestore/IEDSERVER.BIN + + diff --git a/examples/server_example3/server_example3.c b/examples/server_example3/server_example3.c new file mode 100644 index 0000000..2352bc6 --- /dev/null +++ b/examples/server_example3/server_example3.c @@ -0,0 +1,167 @@ +/* + * server_example3.c + * + * - How to use simple control models + * - How to serve analog measurement data + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; +static IedServer iedServer = NULL; + +void +sigint_handler(int signalId) +{ + running = 0; +} + +static ControlHandlerResult +controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) +{ + if (test) + return CONTROL_RESULT_FAILED; + + if (MmsValue_getType(value) == MMS_BOOLEAN) { + printf("received binary control command: "); + + if (MmsValue_getBoolean(value)) + printf("on\n"); + else + printf("off\n"); + } + else + return CONTROL_RESULT_FAILED; + + uint64_t timeStamp = Hal_getTimeInMs(); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + } + + return CONTROL_RESULT_OK; +} + + +static void +connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter) +{ + if (connected) + printf("Connection opened\n"); + else + printf("Connection closed\n"); +} + +int +main(int argc, char** argv) +{ + printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString()); + + iedServer = IedServer_create(&iedModel); + + /* Install handler for operate command */ + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float t = 0.f; + + while (running) { + uint64_t timestamp = Hal_getTimeInMs(); + + t += 0.1f; + + float an1 = sinf(t); + float an2 = sinf(t + 1.f); + float an3 = sinf(t + 2.f); + float an4 = sinf(t + 3.f); + + IedServer_lockDataModel(iedServer); + + Timestamp iecTimestamp; + + Timestamp_clearFlags(&iecTimestamp); + Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp); + Timestamp_setLeapSecondKnown(&iecTimestamp, true); + + /* toggle clock-not-synchronized flag in timestamp */ + if (((int) t % 2) == 0) + Timestamp_setClockNotSynchronized(&iecTimestamp, true); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4); + + IedServer_unlockDataModel(iedServer); + + Thread_sleep(100); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); + +} /* main() */ diff --git a/examples/server_example3/simpleIO_direct_control.icd b/examples/server_example3/simpleIO_direct_control.icd new file mode 100644 index 0000000..df5636b --- /dev/null +++ b/examples/server_example3/simpleIO_direct_control.icd @@ -0,0 +1,273 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + MZ Automation + + + 0.7.3 + + + libiec61850 server example + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example3/simpleIO_sbo_control.icd b/examples/server_example3/simpleIO_sbo_control.icd new file mode 100644 index 0000000..5f65ff6 --- /dev/null +++ b/examples/server_example3/simpleIO_sbo_control.icd @@ -0,0 +1,287 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + sbo-with-normal-security + + + 30000 + + + operate-once + + + + + sbo-with-normal-security + + + 30000 + + + operate-once + + + + + sbo-with-normal-security + + + 30000 + + + operate-once + + + + + sbo-with-normal-security + + + 30000 + + + operate-once + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + operate-once + operate-many + + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example3/static_model.c b/examples/server_example3/static_model.c new file mode 100644 index 0000000..9208a9f --- /dev/null +++ b/examples/server_example3/static_model.c @@ -0,0 +1,1989 @@ +/* + * static_model.c + * + * automatically generated from simpleIO_direct_control.icd + */ +#include "static_model.h" + +static void initializeValues(); + +extern DataSet iedModelds_GenericIO_LLN0_Events; +extern DataSet iedModelds_GenericIO_LLN0_Events2; +extern DataSet iedModelds_GenericIO_LLN0_Measurements; + + +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$stVal", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Events = { + "GenericIO", + "LLN0$Events", + 4, + &iedModelds_GenericIO_LLN0_Events_fcda0, + &iedModelds_GenericIO_LLN0_Events2 +}; + +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events2_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events2_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events2_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Events2 = { + "GenericIO", + "LLN0$Events2", + 4, + &iedModelds_GenericIO_LLN0_Events2_fcda0, + &iedModelds_GenericIO_LLN0_Measurements +}; + +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0 = { + "GenericIO", + false, + "GGIO1$MX$AnIn1$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1 = { + "GenericIO", + false, + "GGIO1$MX$AnIn1$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2 = { + "GenericIO", + false, + "GGIO1$MX$AnIn2$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3 = { + "GenericIO", + false, + "GGIO1$MX$AnIn2$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda4 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4 = { + "GenericIO", + false, + "GGIO1$MX$AnIn3$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda5 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5 = { + "GenericIO", + false, + "GGIO1$MX$AnIn3$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda6 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6 = { + "GenericIO", + false, + "GGIO1$MX$AnIn4$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda7 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7 = { + "GenericIO", + false, + "GGIO1$MX$AnIn4$q", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Measurements = { + "GenericIO", + "LLN0$Measurements", + 8, + &iedModelds_GenericIO_LLN0_Measurements_fcda0, + NULL +}; + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0 +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, +}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, +}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO4 = { + DataObjectModelType, + "SPCSO4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_GenericIO_LLN0_report0; +extern ReportControlBlock iedModel_GenericIO_LLN0_report1; +extern ReportControlBlock iedModel_GenericIO_LLN0_report2; +extern ReportControlBlock iedModel_GenericIO_LLN0_report3; +extern ReportControlBlock iedModel_GenericIO_LLN0_report4; +extern ReportControlBlock iedModel_GenericIO_LLN0_report5; +extern ReportControlBlock iedModel_GenericIO_LLN0_report6; + +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; +ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2}; +ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3}; +ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report4}; +ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 0, 111, 50, 1000, &iedModel_GenericIO_LLN0_report5}; +ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 0, 111, 50, 1000, &iedModel_GenericIO_LLN0_report6}; +ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 0, 111, 50, 1000, NULL}; + + + + +IedModel iedModel = { + "simpleIO", + &iedModel_GenericIO, + &iedModelds_GenericIO_LLN0_Events, + &iedModel_GenericIO_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_LLN0_NamPlt_vendor.mmsValue = MmsValue_newVisibleString("MZ Automation"); + +iedModel_GenericIO_LLN0_NamPlt_swRev.mmsValue = MmsValue_newVisibleString("0.7.3"); + +iedModel_GenericIO_LLN0_NamPlt_d.mmsValue = MmsValue_newVisibleString("libiec61850 server example"); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); +} diff --git a/examples/server_example3/static_model.h b/examples/server_example3/static_model.h new file mode 100644 index 0000000..b5670e9 --- /dev/null +++ b/examples/server_example3/static_model.h @@ -0,0 +1,301 @@ +/* + * static_model.h + * + * automatically generated from simpleIO_direct_control.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example3/vmd-filestore/SYSTEM.BIN b/examples/server_example3/vmd-filestore/SYSTEM.BIN new file mode 100644 index 0000000..e69de29 diff --git a/examples/server_example4/CMakeLists.txt b/examples/server_example4/CMakeLists.txt new file mode 100644 index 0000000..d738b0f --- /dev/null +++ b/examples/server_example4/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example4_SRCS + server_example4.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example4_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example4 + ${server_example4_SRCS} +) + +target_link_libraries(server_example4 + iec61850 +) diff --git a/examples/server_example4/Makefile b/examples/server_example4/Makefile new file mode 100644 index 0000000..4907673 --- /dev/null +++ b/examples/server_example4/Makefile @@ -0,0 +1,25 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example4 +PROJECT_SOURCES = server_example4.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = simpleIO_direct_control.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example4/server_example4.c b/examples/server_example4/server_example4.c new file mode 100644 index 0000000..b3aa07f --- /dev/null +++ b/examples/server_example4/server_example4.c @@ -0,0 +1,157 @@ +/* + * server_example4.c + * + * Example server application with password authentication. + * + * - How to use a authenticator with password authentication + * - How to distinguish between different clients for control actions and set points + * + * The server accepts only connections by clients using one of the two passwords: + * + * user1@testpw + * user2@testpw + * + * Only clients using the second password are allowed to perform control actions. + */ + +#include "iec61850_server.h" +#include "static_model.h" +#include "hal_thread.h" +#include +#include +#include + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; + +static IedServer iedServer; + +void sigint_handler(int signalId) +{ + running = 0; +} + +/* password "database" */ +static char* password1 = "user1@testpw"; +static char* password2 = "user2@testpw"; + +/** + * This is the AcseAuthenticator callback function that is invoked on each client connection attempt. + * When returning true the server stack accepts the client. Otherwise the connection is rejected. + */ +static bool +clientAuthenticator(void* parameter, AcseAuthenticationParameter authParameter, void** securityToken) +{ + if (authParameter->mechanism == ACSE_AUTH_PASSWORD) { + if (authParameter->value.password.passwordLength == strlen(password1)) { + if (memcmp(authParameter->value.password.octetString, password1, + authParameter->value.password.passwordLength) == 0) + { + *securityToken = (void*) password1; + return true; + } + + } + if (authParameter->value.password.passwordLength == strlen(password2)) { + if (memcmp(authParameter->value.password.octetString, password2, + authParameter->value.password.passwordLength) == 0) + { + *securityToken = (void*) password2; + return true; + } + } + } + + return false; +} + +static CheckHandlerResult +performCheckHandler (void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, ClientConnection connection) +{ + void* securityToken = ClientConnection_getSecurityToken(connection); + + if (securityToken == password2) + return CONTROL_ACCEPTED; + else + return CONTROL_OBJECT_ACCESS_DENIED; +} + +static void +controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) +{ + MmsValue* timeStamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs()); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + } + + MmsValue_delete(timeStamp); +} + +int main(int argc, char** argv) { + + iedServer = IedServer_create(&iedModel); + + /* Activate authentication */ + IedServer_setAuthenticator(iedServer, clientAuthenticator, NULL); + + /* Set handler for control permission check for each control object */ + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlPerformCheckHandler) performCheckHandler, NULL); + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlPerformCheckHandler) performCheckHandler, NULL); + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlPerformCheckHandler) performCheckHandler, NULL); + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, + (ControlPerformCheckHandler) performCheckHandler, NULL); + + /* Set control handler for each control object */ + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO1); + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO2); + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO3); + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, + (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO4); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + while (running) + Thread_sleep(100); + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example4/simpleIO_direct_control.icd b/examples/server_example4/simpleIO_direct_control.icd new file mode 100644 index 0000000..3081dff --- /dev/null +++ b/examples/server_example4/simpleIO_direct_control.icd @@ -0,0 +1,223 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example4/static_model.c b/examples/server_example4/static_model.c new file mode 100644 index 0000000..c391fde --- /dev/null +++ b/examples/server_example4/static_model.c @@ -0,0 +1,1948 @@ +/* + * static_model.c + * + * automatically generated from simpleIO_direct_control.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + +extern DataSet ds_GenericIO_LLN0_Events; + + +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda0; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda1; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda1 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda2 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda3 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$stVal", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_GenericIO_LLN0_Events = { + "GenericIO", + "LLN0$Events", + 4, + &ds_GenericIO_LLN0_Events_fcda0, + NULL +}; + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0 +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, +}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, +}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO4 = { + DataObjectModelType, + "SPCSO4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_GenericIO_LLN0_report0; + +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL}; + + + + +IedModel iedModel = { + "simpleIO", + &iedModel_GenericIO, + &ds_GenericIO_LLN0_Events, + &iedModel_GenericIO_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); +} diff --git a/examples/server_example4/static_model.h b/examples/server_example4/static_model.h new file mode 100644 index 0000000..58dd28b --- /dev/null +++ b/examples/server_example4/static_model.h @@ -0,0 +1,299 @@ +/* + * static_model.h + * + * automatically generated from simpleIO_direct_control.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example5/CMakeLists.txt b/examples/server_example5/CMakeLists.txt new file mode 100644 index 0000000..8ca7c4c --- /dev/null +++ b/examples/server_example5/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example5_SRCS + server_example5.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example5_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example5 + ${server_example5_SRCS} +) + +target_link_libraries(server_example5 + iec61850 +) diff --git a/examples/server_example5/Makefile b/examples/server_example5/Makefile new file mode 100644 index 0000000..4a2c419 --- /dev/null +++ b/examples/server_example5/Makefile @@ -0,0 +1,25 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example5 +PROJECT_SOURCES = server_example5.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = complexModel.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example5/complexModel.icd b/examples/server_example5/complexModel.icd new file mode 100644 index 0000000..9d5ccea --- /dev/null +++ b/examples/server_example5/complexModel.icd @@ -0,0 +1,347 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + + rad + sr + m + Gy + q + °C + Sv + F + C + S + H + V + kg + ohm + J + N + Hz + Ix + Lm + Wb + T + W + Pa + s + m² + m³ + m/s + m/s² + m³/s + m/m³ + M + kg/m³ + m²/s + A + W/m K + J/K + ppm + 1/s + rad/s + K + VA + Watts + VAr + theta + cos(theta) + Vs + V² + As + A² + mol + A²t + VAh + Wh + VArh + V/Hz + cd + deg + + + Yocto + Zepto + Atto + Femto + Pico + Nano + Micro + Milli + Centi + Deci + zeroNoValue + Deca + Hecto + Kilo + Mega + Giga + Tera + Petra + Exa + Zetta + Yotta + + + normal + high + low + high-high + low-low + + + diff --git a/examples/server_example5/server_example5.c b/examples/server_example5/server_example5.c new file mode 100644 index 0000000..1d6d90e --- /dev/null +++ b/examples/server_example5/server_example5.c @@ -0,0 +1,78 @@ +/* + * server_example5.c + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; +static IedServer iedServer = NULL; + +void sigint_handler(int signalId) +{ + running = 0; +} + +static MmsDataAccessError +writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter) +{ + if (dataAttribute == IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f) { + + float newValue = MmsValue_toFloat(value); + + printf("New value for OutVarSet_setMag_f = %f\n", newValue); + + /* Check if value is inside of valid range */ + if ((newValue >= 0.f) && (newValue <= 1000.1f)) + return DATA_ACCESS_ERROR_SUCCESS; + else + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + + } + + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; +} + +int main(int argc, char** argv) { + + iedServer = IedServer_create(&iedModel); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + /* Don't allow access to SP variables by default */ + IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_SP, ACCESS_POLICY_DENY); + + /* Instruct the server that we will be informed if a clients writes to a + * certain variables we are interested in. + */ + IedServer_handleWriteAccess(iedServer, IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f, writeAccessHandler, NULL); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + while (running) { + Thread_sleep(1); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example5/static_model.c b/examples/server_example5/static_model.c new file mode 100644 index 0000000..fdc336c --- /dev/null +++ b/examples/server_example5/static_model.c @@ -0,0 +1,3912 @@ +/* + * static_model.c + * + * automatically generated from complexModel.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_Inverter; +extern LogicalNode iedModel_Inverter_LLN0; +extern DataObject iedModel_Inverter_LLN0_Mod; +extern DataAttribute iedModel_Inverter_LLN0_Mod_q; +extern DataAttribute iedModel_Inverter_LLN0_Mod_t; +extern DataAttribute iedModel_Inverter_LLN0_Mod_ctlModel; +extern DataObject iedModel_Inverter_LLN0_Beh; +extern DataAttribute iedModel_Inverter_LLN0_Beh_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Beh_q; +extern DataAttribute iedModel_Inverter_LLN0_Beh_t; +extern DataObject iedModel_Inverter_LLN0_Health; +extern DataAttribute iedModel_Inverter_LLN0_Health_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Health_q; +extern DataAttribute iedModel_Inverter_LLN0_Health_t; +extern DataObject iedModel_Inverter_LLN0_NamPlt; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_d; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Inverter_LPHD1; +extern DataObject iedModel_Inverter_LPHD1_PhyNam; +extern DataAttribute iedModel_Inverter_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Inverter_LPHD1_PhyHealth; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_t; +extern DataObject iedModel_Inverter_LPHD1_Proxy; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_q; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_t; +extern LogicalNode iedModel_Inverter_ZINV1; +extern DataObject iedModel_Inverter_ZINV1_Mod; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_q; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_t; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_ctlModel; +extern DataObject iedModel_Inverter_ZINV1_Beh; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_q; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_t; +extern DataObject iedModel_Inverter_ZINV1_Health; +extern DataAttribute iedModel_Inverter_ZINV1_Health_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Health_q; +extern DataAttribute iedModel_Inverter_ZINV1_Health_t; +extern DataObject iedModel_Inverter_ZINV1_NamPlt; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_d; +extern DataObject iedModel_Inverter_ZINV1_WRtg; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_VarRtg; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_ACTyp; +extern DataAttribute iedModel_Inverter_ZINV1_ACTyp_setVal; +extern DataObject iedModel_Inverter_ZINV1_OutWSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_OutVarSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit; +extern LogicalNode iedModel_Inverter_MMXU1; +extern DataObject iedModel_Inverter_MMXU1_Mod; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_q; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_t; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_ctlModel; +extern DataObject iedModel_Inverter_MMXU1_Beh; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_q; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_t; +extern DataObject iedModel_Inverter_MMXU1_Health; +extern DataAttribute iedModel_Inverter_MMXU1_Health_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Health_q; +extern DataAttribute iedModel_Inverter_MMXU1_Health_t; +extern DataObject iedModel_Inverter_MMXU1_NamPlt; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_d; +extern DataObject iedModel_Inverter_MMXU1_TotW; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_t; +extern DataObject iedModel_Inverter_MMXU1_TotVAr; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_t; +extern DataObject iedModel_Inverter_MMXU1_TotVA; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_t; +extern DataObject iedModel_Inverter_MMXU1_Hz; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_q; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_t; +extern DataObject iedModel_Inverter_MMXU1_PhV; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_neut; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_t; +extern DataObject iedModel_Inverter_MMXU1_A; +extern DataObject iedModel_Inverter_MMXU1_A_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_A_neut; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_t; +extern DataObject iedModel_Inverter_MMXU1_W; +extern DataObject iedModel_Inverter_MMXU1_W_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_t; +extern LogicalDevice iedModel_Battery; +extern LogicalNode iedModel_Battery_LLN0; +extern DataObject iedModel_Battery_LLN0_Mod; +extern DataAttribute iedModel_Battery_LLN0_Mod_q; +extern DataAttribute iedModel_Battery_LLN0_Mod_t; +extern DataAttribute iedModel_Battery_LLN0_Mod_ctlModel; +extern DataObject iedModel_Battery_LLN0_Beh; +extern DataAttribute iedModel_Battery_LLN0_Beh_stVal; +extern DataAttribute iedModel_Battery_LLN0_Beh_q; +extern DataAttribute iedModel_Battery_LLN0_Beh_t; +extern DataObject iedModel_Battery_LLN0_Health; +extern DataAttribute iedModel_Battery_LLN0_Health_stVal; +extern DataAttribute iedModel_Battery_LLN0_Health_q; +extern DataAttribute iedModel_Battery_LLN0_Health_t; +extern DataObject iedModel_Battery_LLN0_NamPlt; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_d; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Battery_LPHD1; +extern DataObject iedModel_Battery_LPHD1_PhyNam; +extern DataAttribute iedModel_Battery_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Battery_LPHD1_PhyHealth; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_t; +extern DataObject iedModel_Battery_LPHD1_Proxy; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_q; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_t; +extern LogicalNode iedModel_Battery_ZBAT1; +extern DataObject iedModel_Battery_ZBAT1_Mod; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_q; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_t; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBAT1_Beh; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_q; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_t; +extern DataObject iedModel_Battery_ZBAT1_Health; +extern DataAttribute iedModel_Battery_ZBAT1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Health_q; +extern DataAttribute iedModel_Battery_ZBAT1_Health_t; +extern DataObject iedModel_Battery_ZBAT1_NamPlt; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_d; +extern DataObject iedModel_Battery_ZBAT1_Vol; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_q; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_t; +extern DataObject iedModel_Battery_ZBAT1_Amp; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_q; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_t; +extern LogicalNode iedModel_Battery_ZBTC1; +extern DataObject iedModel_Battery_ZBTC1_Mod; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_q; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_t; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBTC1_Beh; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_q; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_t; +extern DataObject iedModel_Battery_ZBTC1_Health; +extern DataAttribute iedModel_Battery_ZBTC1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Health_q; +extern DataAttribute iedModel_Battery_ZBTC1_Health_t; +extern DataObject iedModel_Battery_ZBTC1_NamPlt; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_d; +extern DataObject iedModel_Battery_ZBTC1_BatChaSt; +extern DataObject iedModel_Battery_ZBTC1_BatChaPwr; +extern DataObject iedModel_Battery_ZBTC1_BatChaMod; +extern DataObject iedModel_Battery_ZBTC1_ChaV; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_t; +extern DataObject iedModel_Battery_ZBTC1_ChaA; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_t; +extern LogicalDevice iedModel_Physical_Measurements; +extern LogicalNode iedModel_Physical_Measurements_LLN0; +extern DataObject iedModel_Physical_Measurements_LLN0_Mod; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_t; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_ctlModel; +extern DataObject iedModel_Physical_Measurements_LLN0_Beh; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_t; +extern DataObject iedModel_Physical_Measurements_LLN0_Health; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_t; +extern DataObject iedModel_Physical_Measurements_LLN0_NamPlt; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_d; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Physical_Measurements_LPHD1; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyNam; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyHealth; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_t; +extern DataObject iedModel_Physical_Measurements_LPHD1_Proxy; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t; + +extern DataSet ds_Inverter_LLN0_dataset1; + + +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda0; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda1; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda2; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda3; +extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda4; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda0 = { + "Inverter", + false, + "LLN0$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda1 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda1 = { + "Battery", + false, + "LLN0$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda2 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda2 = { + "Inverter", + false, + "MMXU1$ST$Mod$q", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda3 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda3 = { + "Inverter", + false, + "MMXU1$CF$Mod$ctlModel", + -1, + NULL, + NULL, + &ds_Inverter_LLN0_dataset1_fcda4 +}; + +DataSetEntry ds_Inverter_LLN0_dataset1_fcda4 = { + "Inverter", + false, + "MMXU1$MX$TotW$mag", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_Inverter_LLN0_dataset1 = { + "Inverter", + "LLN0$dataset1", + 5, + &ds_Inverter_LLN0_dataset1_fcda0, + NULL +}; + +LogicalDevice iedModel_Inverter = { + LogicalDeviceModelType, + "Inverter", + (ModelNode*) &iedModel, + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Inverter_LLN0 +}; + +LogicalNode iedModel_Inverter_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Inverter, + (ModelNode*) &iedModel_Inverter_LPHD1, + (ModelNode*) &iedModel_Inverter_LLN0_Mod, +}; + +DataObject iedModel_Inverter_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Inverter_LLN0, + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + (ModelNode*) &iedModel_Inverter_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LLN0_Mod, + (ModelNode*) &iedModel_Inverter_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LLN0_Mod, + (ModelNode*) &iedModel_Inverter_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Inverter_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Inverter_LLN0, + (ModelNode*) &iedModel_Inverter_LLN0_Health, + (ModelNode*) &iedModel_Inverter_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + (ModelNode*) &iedModel_Inverter_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + (ModelNode*) &iedModel_Inverter_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Inverter_LLN0, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LLN0_Health, + (ModelNode*) &iedModel_Inverter_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LLN0_Health, + (ModelNode*) &iedModel_Inverter_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Inverter_LLN0, + NULL, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Inverter_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Inverter_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Inverter, + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyNam, +}; + +DataObject iedModel_Inverter_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Inverter_LPHD1, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Inverter_LPHD1, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Inverter_LPHD1, + NULL, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Inverter_ZINV1 = { + LogicalNodeModelType, + "ZINV1", + (ModelNode*) &iedModel_Inverter, + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, +}; + +DataObject iedModel_Inverter_ZINV1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod_q, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, + (ModelNode*) &iedModel_Inverter_ZINV1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Inverter_ZINV1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + (ModelNode*) &iedModel_Inverter_ZINV1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_ZINV1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + (ModelNode*) &iedModel_Inverter_ZINV1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + (ModelNode*) &iedModel_Inverter_ZINV1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + (ModelNode*) &iedModel_Inverter_ZINV1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_ZINV1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Inverter_ZINV1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_WRtg = { + DataObjectModelType, + "WRtg", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_units, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_WRtg_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_WRtg_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_VarRtg = { + DataObjectModelType, + "VarRtg", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_ACTyp, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_units, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_VarRtg_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_VarRtg_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_ACTyp = { + DataObjectModelType, + "ACTyp", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet, + (ModelNode*) &iedModel_Inverter_ZINV1_ACTyp_setVal, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_ACTyp_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_Inverter_ZINV1_ACTyp, + NULL, + NULL, + 0, + IEC61850_FC_SP, + INT32, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_OutWSet = { + DataObjectModelType, + "OutWSet", + (ModelNode*) &iedModel_Inverter_ZINV1, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_units, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutWSet_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_OutWSet_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_ZINV1_OutVarSet = { + DataObjectModelType, + "OutVarSet", + (ModelNode*) &iedModel_Inverter_ZINV1, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_setMag, + 0 +}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_units, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_setMag_f, + 0, + IEC61850_FC_SP, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SP, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units = { + DataAttributeModelType, + "units", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet, + NULL, + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit, + 0, + IEC61850_FC_CF, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit = { + DataAttributeModelType, + "SIUnit", + (ModelNode*) &iedModel_Inverter_ZINV1_OutVarSet_units, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +LogicalNode iedModel_Inverter_MMXU1 = { + LogicalNodeModelType, + "MMXU1", + (ModelNode*) &iedModel_Inverter, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, +}; + +DataObject iedModel_Inverter_MMXU1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod_q, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, + (ModelNode*) &iedModel_Inverter_MMXU1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Inverter_MMXU1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + (ModelNode*) &iedModel_Inverter_MMXU1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + (ModelNode*) &iedModel_Inverter_MMXU1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + (ModelNode*) &iedModel_Inverter_MMXU1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + (ModelNode*) &iedModel_Inverter_MMXU1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Inverter_MMXU1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_TotW = { + DataObjectModelType, + "TotW", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_q, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + (ModelNode*) &iedModel_Inverter_MMXU1_TotW_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotW_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_TotW, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_TotVAr = { + DataObjectModelType, + "TotVAr", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_q, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVAr_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVAr, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_TotVA = { + DataObjectModelType, + "TotVA", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_TotVA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_TotVA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_Hz = { + DataObjectModelType, + "Hz", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_mag, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_q, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + (ModelNode*) &iedModel_Inverter_MMXU1_Hz_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_Hz_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_Hz, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV = { + DataObjectModelType, + "PhV", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + 0 +}; + +DataObject iedModel_Inverter_MMXU1_PhV_phsA = { + DataObjectModelType, + "phsA", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV_phsB = { + DataObjectModelType, + "phsB", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsB, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV_phsC = { + DataObjectModelType, + "phsC", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_phsC, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_PhV_neut = { + DataObjectModelType, + "neut", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_q, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_PhV_neut_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_PhV_neut, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A = { + DataObjectModelType, + "A", + (ModelNode*) &iedModel_Inverter_MMXU1, + (ModelNode*) &iedModel_Inverter_MMXU1_W, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + 0 +}; + +DataObject iedModel_Inverter_MMXU1_A_phsA = { + DataObjectModelType, + "phsA", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A_phsB = { + DataObjectModelType, + "phsB", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsB_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsB, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A_phsC = { + DataObjectModelType, + "phsC", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_phsC_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_phsC, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_A_neut = { + DataObjectModelType, + "neut", + (ModelNode*) &iedModel_Inverter_MMXU1_A, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_q, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_A_neut_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_A_neut, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_W = { + DataObjectModelType, + "W", + (ModelNode*) &iedModel_Inverter_MMXU1, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + 0 +}; + +DataObject iedModel_Inverter_MMXU1_W_phsA = { + DataObjectModelType, + "phsA", + (ModelNode*) &iedModel_Inverter_MMXU1_W, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_q, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_W_phsB = { + DataObjectModelType, + "phsB", + (ModelNode*) &iedModel_Inverter_MMXU1_W, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_q, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsB_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsB, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Inverter_MMXU1_W_phsC = { + DataObjectModelType, + "phsC", + (ModelNode*) &iedModel_Inverter_MMXU1_W, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal, + 0 +}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_q, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal, + NULL, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Inverter_MMXU1_W_phsC_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Inverter_MMXU1_W_phsC, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + + +LogicalDevice iedModel_Battery = { + LogicalDeviceModelType, + "Battery", + (ModelNode*) &iedModel, + (ModelNode*) &iedModel_Physical_Measurements, + (ModelNode*) &iedModel_Battery_LLN0 +}; + +LogicalNode iedModel_Battery_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Battery_LPHD1, + (ModelNode*) &iedModel_Battery_LLN0_Mod, +}; + +DataObject iedModel_Battery_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Battery_LLN0, + (ModelNode*) &iedModel_Battery_LLN0_Beh, + (ModelNode*) &iedModel_Battery_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LLN0_Mod, + (ModelNode*) &iedModel_Battery_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LLN0_Mod, + (ModelNode*) &iedModel_Battery_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Battery_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Battery_LLN0, + (ModelNode*) &iedModel_Battery_LLN0_Health, + (ModelNode*) &iedModel_Battery_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LLN0_Beh, + (ModelNode*) &iedModel_Battery_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LLN0_Beh, + (ModelNode*) &iedModel_Battery_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Battery_LLN0, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LLN0_Health, + (ModelNode*) &iedModel_Battery_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LLN0_Health, + (ModelNode*) &iedModel_Battery_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Battery_LLN0, + NULL, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + (ModelNode*) &iedModel_Battery_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Battery_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Battery_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_LPHD1_PhyNam, +}; + +DataObject iedModel_Battery_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Battery_LPHD1, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Battery_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Battery_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Battery_LPHD1, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Battery_LPHD1, + NULL, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Battery_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + (ModelNode*) &iedModel_Battery_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Battery_ZBAT1 = { + LogicalNodeModelType, + "ZBAT1", + (ModelNode*) &iedModel_Battery, + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, +}; + +DataObject iedModel_Battery_ZBAT1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod_q, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, + (ModelNode*) &iedModel_Battery_ZBAT1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Battery_ZBAT1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + (ModelNode*) &iedModel_Battery_ZBAT1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBAT1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + (ModelNode*) &iedModel_Battery_ZBAT1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + (ModelNode*) &iedModel_Battery_ZBAT1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Battery_ZBAT1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Vol = { + DataObjectModelType, + "Vol", + (ModelNode*) &iedModel_Battery_ZBAT1, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_q, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + (ModelNode*) &iedModel_Battery_ZBAT1_Vol_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Vol_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Vol, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBAT1_Amp = { + DataObjectModelType, + "Amp", + (ModelNode*) &iedModel_Battery_ZBAT1, + NULL, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_q, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + (ModelNode*) &iedModel_Battery_ZBAT1_Amp_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBAT1_Amp_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBAT1_Amp, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_Battery_ZBTC1 = { + LogicalNodeModelType, + "ZBTC1", + (ModelNode*) &iedModel_Battery, + NULL, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, +}; + +DataObject iedModel_Battery_ZBTC1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod_q, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, + (ModelNode*) &iedModel_Battery_ZBTC1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Battery_ZBTC1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + (ModelNode*) &iedModel_Battery_ZBTC1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBTC1_Health_stVal, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + (ModelNode*) &iedModel_Battery_ZBTC1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + (ModelNode*) &iedModel_Battery_ZBTC1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_BatChaSt, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Battery_ZBTC1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_BatChaSt = { + DataObjectModelType, + "BatChaSt", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_BatChaPwr, + NULL, + 0 +}; + +DataObject iedModel_Battery_ZBTC1_BatChaPwr = { + DataObjectModelType, + "BatChaPwr", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_BatChaMod, + NULL, + 0 +}; + +DataObject iedModel_Battery_ZBTC1_BatChaMod = { + DataObjectModelType, + "BatChaMod", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + NULL, + 0 +}; + +DataObject iedModel_Battery_ZBTC1_ChaV = { + DataObjectModelType, + "ChaV", + (ModelNode*) &iedModel_Battery_ZBTC1, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_q, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaV_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaV, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Battery_ZBTC1_ChaA = { + DataObjectModelType, + "ChaA", + (ModelNode*) &iedModel_Battery_ZBTC1, + NULL, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_mag, + 0 +}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_q, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Battery_ZBTC1_ChaA_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Battery_ZBTC1_ChaA, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + + +LogicalDevice iedModel_Physical_Measurements = { + LogicalDeviceModelType, + "Physical_Measurements", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LLN0 +}; + +LogicalNode iedModel_Physical_Measurements_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_Physical_Measurements, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, +}; + +DataObject iedModel_Physical_Measurements_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_Physical_Measurements_LLN0, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_Physical_Measurements_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_Physical_Measurements_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_Physical_Measurements, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyNam, +}; + +DataObject iedModel_Physical_Measurements_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_Physical_Measurements_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1, + NULL, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_Physical_Measurements_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_Inverter_LLN0_report0; + +ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb101", "ID", false, "dataset1", 0, 3, 32, 0, 0, NULL}; + + + + +IedModel iedModel = { + "ied1", + &iedModel_Inverter, + &ds_Inverter_LLN0_dataset1, + &iedModel_Inverter_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_Inverter_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Inverter_ZINV1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Inverter_MMXU1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Battery_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Battery_ZBAT1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Battery_ZBTC1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_Physical_Measurements_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); +} diff --git a/examples/server_example5/static_model.h b/examples/server_example5/static_model.h new file mode 100644 index 0000000..34623f8 --- /dev/null +++ b/examples/server_example5/static_model.h @@ -0,0 +1,609 @@ +/* + * static_model.h + * + * automatically generated from complexModel.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_Inverter; +extern LogicalNode iedModel_Inverter_LLN0; +extern DataObject iedModel_Inverter_LLN0_Mod; +extern DataAttribute iedModel_Inverter_LLN0_Mod_q; +extern DataAttribute iedModel_Inverter_LLN0_Mod_t; +extern DataAttribute iedModel_Inverter_LLN0_Mod_ctlModel; +extern DataObject iedModel_Inverter_LLN0_Beh; +extern DataAttribute iedModel_Inverter_LLN0_Beh_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Beh_q; +extern DataAttribute iedModel_Inverter_LLN0_Beh_t; +extern DataObject iedModel_Inverter_LLN0_Health; +extern DataAttribute iedModel_Inverter_LLN0_Health_stVal; +extern DataAttribute iedModel_Inverter_LLN0_Health_q; +extern DataAttribute iedModel_Inverter_LLN0_Health_t; +extern DataObject iedModel_Inverter_LLN0_NamPlt; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_d; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Inverter_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Inverter_LPHD1; +extern DataObject iedModel_Inverter_LPHD1_PhyNam; +extern DataAttribute iedModel_Inverter_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Inverter_LPHD1_PhyHealth; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Inverter_LPHD1_PhyHealth_t; +extern DataObject iedModel_Inverter_LPHD1_Proxy; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_q; +extern DataAttribute iedModel_Inverter_LPHD1_Proxy_t; +extern LogicalNode iedModel_Inverter_ZINV1; +extern DataObject iedModel_Inverter_ZINV1_Mod; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_q; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_t; +extern DataAttribute iedModel_Inverter_ZINV1_Mod_ctlModel; +extern DataObject iedModel_Inverter_ZINV1_Beh; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_q; +extern DataAttribute iedModel_Inverter_ZINV1_Beh_t; +extern DataObject iedModel_Inverter_ZINV1_Health; +extern DataAttribute iedModel_Inverter_ZINV1_Health_stVal; +extern DataAttribute iedModel_Inverter_ZINV1_Health_q; +extern DataAttribute iedModel_Inverter_ZINV1_Health_t; +extern DataObject iedModel_Inverter_ZINV1_NamPlt; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_ZINV1_NamPlt_d; +extern DataObject iedModel_Inverter_ZINV1_WRtg; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_WRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_VarRtg; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units; +extern DataAttribute iedModel_Inverter_ZINV1_VarRtg_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_ACTyp; +extern DataAttribute iedModel_Inverter_ZINV1_ACTyp_setVal; +extern DataObject iedModel_Inverter_ZINV1_OutWSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutWSet_units_SIUnit; +extern DataObject iedModel_Inverter_ZINV1_OutVarSet; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_setMag_f; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units; +extern DataAttribute iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit; +extern LogicalNode iedModel_Inverter_MMXU1; +extern DataObject iedModel_Inverter_MMXU1_Mod; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_q; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_t; +extern DataAttribute iedModel_Inverter_MMXU1_Mod_ctlModel; +extern DataObject iedModel_Inverter_MMXU1_Beh; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_q; +extern DataAttribute iedModel_Inverter_MMXU1_Beh_t; +extern DataObject iedModel_Inverter_MMXU1_Health; +extern DataAttribute iedModel_Inverter_MMXU1_Health_stVal; +extern DataAttribute iedModel_Inverter_MMXU1_Health_q; +extern DataAttribute iedModel_Inverter_MMXU1_Health_t; +extern DataObject iedModel_Inverter_MMXU1_NamPlt; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_vendor; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_swRev; +extern DataAttribute iedModel_Inverter_MMXU1_NamPlt_d; +extern DataObject iedModel_Inverter_MMXU1_TotW; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotW_t; +extern DataObject iedModel_Inverter_MMXU1_TotVAr; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVAr_t; +extern DataObject iedModel_Inverter_MMXU1_TotVA; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_q; +extern DataAttribute iedModel_Inverter_MMXU1_TotVA_t; +extern DataObject iedModel_Inverter_MMXU1_Hz; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_q; +extern DataAttribute iedModel_Inverter_MMXU1_Hz_t; +extern DataObject iedModel_Inverter_MMXU1_PhV; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_PhV_neut; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_PhV_neut_t; +extern DataObject iedModel_Inverter_MMXU1_A; +extern DataObject iedModel_Inverter_MMXU1_A_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_A_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_phsC_t; +extern DataObject iedModel_Inverter_MMXU1_A_neut; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_q; +extern DataAttribute iedModel_Inverter_MMXU1_A_neut_t; +extern DataObject iedModel_Inverter_MMXU1_W; +extern DataObject iedModel_Inverter_MMXU1_W_phsA; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsA_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsB; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsB_t; +extern DataObject iedModel_Inverter_MMXU1_W_phsC; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_q; +extern DataAttribute iedModel_Inverter_MMXU1_W_phsC_t; +extern LogicalDevice iedModel_Battery; +extern LogicalNode iedModel_Battery_LLN0; +extern DataObject iedModel_Battery_LLN0_Mod; +extern DataAttribute iedModel_Battery_LLN0_Mod_q; +extern DataAttribute iedModel_Battery_LLN0_Mod_t; +extern DataAttribute iedModel_Battery_LLN0_Mod_ctlModel; +extern DataObject iedModel_Battery_LLN0_Beh; +extern DataAttribute iedModel_Battery_LLN0_Beh_stVal; +extern DataAttribute iedModel_Battery_LLN0_Beh_q; +extern DataAttribute iedModel_Battery_LLN0_Beh_t; +extern DataObject iedModel_Battery_LLN0_Health; +extern DataAttribute iedModel_Battery_LLN0_Health_stVal; +extern DataAttribute iedModel_Battery_LLN0_Health_q; +extern DataAttribute iedModel_Battery_LLN0_Health_t; +extern DataObject iedModel_Battery_LLN0_NamPlt; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_d; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Battery_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Battery_LPHD1; +extern DataObject iedModel_Battery_LPHD1_PhyNam; +extern DataAttribute iedModel_Battery_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Battery_LPHD1_PhyHealth; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Battery_LPHD1_PhyHealth_t; +extern DataObject iedModel_Battery_LPHD1_Proxy; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_q; +extern DataAttribute iedModel_Battery_LPHD1_Proxy_t; +extern LogicalNode iedModel_Battery_ZBAT1; +extern DataObject iedModel_Battery_ZBAT1_Mod; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_q; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_t; +extern DataAttribute iedModel_Battery_ZBAT1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBAT1_Beh; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_q; +extern DataAttribute iedModel_Battery_ZBAT1_Beh_t; +extern DataObject iedModel_Battery_ZBAT1_Health; +extern DataAttribute iedModel_Battery_ZBAT1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBAT1_Health_q; +extern DataAttribute iedModel_Battery_ZBAT1_Health_t; +extern DataObject iedModel_Battery_ZBAT1_NamPlt; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBAT1_NamPlt_d; +extern DataObject iedModel_Battery_ZBAT1_Vol; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_q; +extern DataAttribute iedModel_Battery_ZBAT1_Vol_t; +extern DataObject iedModel_Battery_ZBAT1_Amp; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_mag_f; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_q; +extern DataAttribute iedModel_Battery_ZBAT1_Amp_t; +extern LogicalNode iedModel_Battery_ZBTC1; +extern DataObject iedModel_Battery_ZBTC1_Mod; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_q; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_t; +extern DataAttribute iedModel_Battery_ZBTC1_Mod_ctlModel; +extern DataObject iedModel_Battery_ZBTC1_Beh; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_q; +extern DataAttribute iedModel_Battery_ZBTC1_Beh_t; +extern DataObject iedModel_Battery_ZBTC1_Health; +extern DataAttribute iedModel_Battery_ZBTC1_Health_stVal; +extern DataAttribute iedModel_Battery_ZBTC1_Health_q; +extern DataAttribute iedModel_Battery_ZBTC1_Health_t; +extern DataObject iedModel_Battery_ZBTC1_NamPlt; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_vendor; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_swRev; +extern DataAttribute iedModel_Battery_ZBTC1_NamPlt_d; +extern DataObject iedModel_Battery_ZBTC1_BatChaSt; +extern DataObject iedModel_Battery_ZBTC1_BatChaPwr; +extern DataObject iedModel_Battery_ZBTC1_BatChaMod; +extern DataObject iedModel_Battery_ZBTC1_ChaV; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaV_t; +extern DataObject iedModel_Battery_ZBTC1_ChaA; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_mag_f; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_q; +extern DataAttribute iedModel_Battery_ZBTC1_ChaA_t; +extern LogicalDevice iedModel_Physical_Measurements; +extern LogicalNode iedModel_Physical_Measurements_LLN0; +extern DataObject iedModel_Physical_Measurements_LLN0_Mod; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_t; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Mod_ctlModel; +extern DataObject iedModel_Physical_Measurements_LLN0_Beh; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Beh_t; +extern DataObject iedModel_Physical_Measurements_LLN0_Health; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_stVal; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_q; +extern DataAttribute iedModel_Physical_Measurements_LLN0_Health_t; +extern DataObject iedModel_Physical_Measurements_LLN0_NamPlt; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_d; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_Physical_Measurements_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_Physical_Measurements_LPHD1; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyNam; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyNam_vendor; +extern DataObject iedModel_Physical_Measurements_LPHD1_PhyHealth; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_PhyHealth_t; +extern DataObject iedModel_Physical_Measurements_LPHD1_Proxy; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_q; +extern DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t; + + + +#define IEDMODEL_Inverter (&iedModel_Inverter) +#define IEDMODEL_Inverter_LLN0 (&iedModel_Inverter_LLN0) +#define IEDMODEL_Inverter_LLN0_Mod (&iedModel_Inverter_LLN0_Mod) +#define IEDMODEL_Inverter_LLN0_Mod_q (&iedModel_Inverter_LLN0_Mod_q) +#define IEDMODEL_Inverter_LLN0_Mod_t (&iedModel_Inverter_LLN0_Mod_t) +#define IEDMODEL_Inverter_LLN0_Mod_ctlModel (&iedModel_Inverter_LLN0_Mod_ctlModel) +#define IEDMODEL_Inverter_LLN0_Beh (&iedModel_Inverter_LLN0_Beh) +#define IEDMODEL_Inverter_LLN0_Beh_stVal (&iedModel_Inverter_LLN0_Beh_stVal) +#define IEDMODEL_Inverter_LLN0_Beh_q (&iedModel_Inverter_LLN0_Beh_q) +#define IEDMODEL_Inverter_LLN0_Beh_t (&iedModel_Inverter_LLN0_Beh_t) +#define IEDMODEL_Inverter_LLN0_Health (&iedModel_Inverter_LLN0_Health) +#define IEDMODEL_Inverter_LLN0_Health_stVal (&iedModel_Inverter_LLN0_Health_stVal) +#define IEDMODEL_Inverter_LLN0_Health_q (&iedModel_Inverter_LLN0_Health_q) +#define IEDMODEL_Inverter_LLN0_Health_t (&iedModel_Inverter_LLN0_Health_t) +#define IEDMODEL_Inverter_LLN0_NamPlt (&iedModel_Inverter_LLN0_NamPlt) +#define IEDMODEL_Inverter_LLN0_NamPlt_vendor (&iedModel_Inverter_LLN0_NamPlt_vendor) +#define IEDMODEL_Inverter_LLN0_NamPlt_swRev (&iedModel_Inverter_LLN0_NamPlt_swRev) +#define IEDMODEL_Inverter_LLN0_NamPlt_d (&iedModel_Inverter_LLN0_NamPlt_d) +#define IEDMODEL_Inverter_LLN0_NamPlt_configRev (&iedModel_Inverter_LLN0_NamPlt_configRev) +#define IEDMODEL_Inverter_LLN0_NamPlt_ldNs (&iedModel_Inverter_LLN0_NamPlt_ldNs) +#define IEDMODEL_Inverter_LPHD1 (&iedModel_Inverter_LPHD1) +#define IEDMODEL_Inverter_LPHD1_PhyNam (&iedModel_Inverter_LPHD1_PhyNam) +#define IEDMODEL_Inverter_LPHD1_PhyNam_vendor (&iedModel_Inverter_LPHD1_PhyNam_vendor) +#define IEDMODEL_Inverter_LPHD1_PhyHealth (&iedModel_Inverter_LPHD1_PhyHealth) +#define IEDMODEL_Inverter_LPHD1_PhyHealth_stVal (&iedModel_Inverter_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Inverter_LPHD1_PhyHealth_q (&iedModel_Inverter_LPHD1_PhyHealth_q) +#define IEDMODEL_Inverter_LPHD1_PhyHealth_t (&iedModel_Inverter_LPHD1_PhyHealth_t) +#define IEDMODEL_Inverter_LPHD1_Proxy (&iedModel_Inverter_LPHD1_Proxy) +#define IEDMODEL_Inverter_LPHD1_Proxy_stVal (&iedModel_Inverter_LPHD1_Proxy_stVal) +#define IEDMODEL_Inverter_LPHD1_Proxy_q (&iedModel_Inverter_LPHD1_Proxy_q) +#define IEDMODEL_Inverter_LPHD1_Proxy_t (&iedModel_Inverter_LPHD1_Proxy_t) +#define IEDMODEL_Inverter_ZINV1 (&iedModel_Inverter_ZINV1) +#define IEDMODEL_Inverter_ZINV1_Mod (&iedModel_Inverter_ZINV1_Mod) +#define IEDMODEL_Inverter_ZINV1_Mod_q (&iedModel_Inverter_ZINV1_Mod_q) +#define IEDMODEL_Inverter_ZINV1_Mod_t (&iedModel_Inverter_ZINV1_Mod_t) +#define IEDMODEL_Inverter_ZINV1_Mod_ctlModel (&iedModel_Inverter_ZINV1_Mod_ctlModel) +#define IEDMODEL_Inverter_ZINV1_Beh (&iedModel_Inverter_ZINV1_Beh) +#define IEDMODEL_Inverter_ZINV1_Beh_stVal (&iedModel_Inverter_ZINV1_Beh_stVal) +#define IEDMODEL_Inverter_ZINV1_Beh_q (&iedModel_Inverter_ZINV1_Beh_q) +#define IEDMODEL_Inverter_ZINV1_Beh_t (&iedModel_Inverter_ZINV1_Beh_t) +#define IEDMODEL_Inverter_ZINV1_Health (&iedModel_Inverter_ZINV1_Health) +#define IEDMODEL_Inverter_ZINV1_Health_stVal (&iedModel_Inverter_ZINV1_Health_stVal) +#define IEDMODEL_Inverter_ZINV1_Health_q (&iedModel_Inverter_ZINV1_Health_q) +#define IEDMODEL_Inverter_ZINV1_Health_t (&iedModel_Inverter_ZINV1_Health_t) +#define IEDMODEL_Inverter_ZINV1_NamPlt (&iedModel_Inverter_ZINV1_NamPlt) +#define IEDMODEL_Inverter_ZINV1_NamPlt_vendor (&iedModel_Inverter_ZINV1_NamPlt_vendor) +#define IEDMODEL_Inverter_ZINV1_NamPlt_swRev (&iedModel_Inverter_ZINV1_NamPlt_swRev) +#define IEDMODEL_Inverter_ZINV1_NamPlt_d (&iedModel_Inverter_ZINV1_NamPlt_d) +#define IEDMODEL_Inverter_ZINV1_WRtg (&iedModel_Inverter_ZINV1_WRtg) +#define IEDMODEL_Inverter_ZINV1_WRtg_setMag (&iedModel_Inverter_ZINV1_WRtg_setMag) +#define IEDMODEL_Inverter_ZINV1_WRtg_setMag_f (&iedModel_Inverter_ZINV1_WRtg_setMag_f) +#define IEDMODEL_Inverter_ZINV1_WRtg_units (&iedModel_Inverter_ZINV1_WRtg_units) +#define IEDMODEL_Inverter_ZINV1_WRtg_units_SIUnit (&iedModel_Inverter_ZINV1_WRtg_units_SIUnit) +#define IEDMODEL_Inverter_ZINV1_VarRtg (&iedModel_Inverter_ZINV1_VarRtg) +#define IEDMODEL_Inverter_ZINV1_VarRtg_setMag (&iedModel_Inverter_ZINV1_VarRtg_setMag) +#define IEDMODEL_Inverter_ZINV1_VarRtg_setMag_f (&iedModel_Inverter_ZINV1_VarRtg_setMag_f) +#define IEDMODEL_Inverter_ZINV1_VarRtg_units (&iedModel_Inverter_ZINV1_VarRtg_units) +#define IEDMODEL_Inverter_ZINV1_VarRtg_units_SIUnit (&iedModel_Inverter_ZINV1_VarRtg_units_SIUnit) +#define IEDMODEL_Inverter_ZINV1_ACTyp (&iedModel_Inverter_ZINV1_ACTyp) +#define IEDMODEL_Inverter_ZINV1_ACTyp_setVal (&iedModel_Inverter_ZINV1_ACTyp_setVal) +#define IEDMODEL_Inverter_ZINV1_OutWSet (&iedModel_Inverter_ZINV1_OutWSet) +#define IEDMODEL_Inverter_ZINV1_OutWSet_setMag (&iedModel_Inverter_ZINV1_OutWSet_setMag) +#define IEDMODEL_Inverter_ZINV1_OutWSet_setMag_f (&iedModel_Inverter_ZINV1_OutWSet_setMag_f) +#define IEDMODEL_Inverter_ZINV1_OutWSet_units (&iedModel_Inverter_ZINV1_OutWSet_units) +#define IEDMODEL_Inverter_ZINV1_OutWSet_units_SIUnit (&iedModel_Inverter_ZINV1_OutWSet_units_SIUnit) +#define IEDMODEL_Inverter_ZINV1_OutVarSet (&iedModel_Inverter_ZINV1_OutVarSet) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_setMag (&iedModel_Inverter_ZINV1_OutVarSet_setMag) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_setMag_f (&iedModel_Inverter_ZINV1_OutVarSet_setMag_f) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_units (&iedModel_Inverter_ZINV1_OutVarSet_units) +#define IEDMODEL_Inverter_ZINV1_OutVarSet_units_SIUnit (&iedModel_Inverter_ZINV1_OutVarSet_units_SIUnit) +#define IEDMODEL_Inverter_MMXU1 (&iedModel_Inverter_MMXU1) +#define IEDMODEL_Inverter_MMXU1_Mod (&iedModel_Inverter_MMXU1_Mod) +#define IEDMODEL_Inverter_MMXU1_Mod_q (&iedModel_Inverter_MMXU1_Mod_q) +#define IEDMODEL_Inverter_MMXU1_Mod_t (&iedModel_Inverter_MMXU1_Mod_t) +#define IEDMODEL_Inverter_MMXU1_Mod_ctlModel (&iedModel_Inverter_MMXU1_Mod_ctlModel) +#define IEDMODEL_Inverter_MMXU1_Beh (&iedModel_Inverter_MMXU1_Beh) +#define IEDMODEL_Inverter_MMXU1_Beh_stVal (&iedModel_Inverter_MMXU1_Beh_stVal) +#define IEDMODEL_Inverter_MMXU1_Beh_q (&iedModel_Inverter_MMXU1_Beh_q) +#define IEDMODEL_Inverter_MMXU1_Beh_t (&iedModel_Inverter_MMXU1_Beh_t) +#define IEDMODEL_Inverter_MMXU1_Health (&iedModel_Inverter_MMXU1_Health) +#define IEDMODEL_Inverter_MMXU1_Health_stVal (&iedModel_Inverter_MMXU1_Health_stVal) +#define IEDMODEL_Inverter_MMXU1_Health_q (&iedModel_Inverter_MMXU1_Health_q) +#define IEDMODEL_Inverter_MMXU1_Health_t (&iedModel_Inverter_MMXU1_Health_t) +#define IEDMODEL_Inverter_MMXU1_NamPlt (&iedModel_Inverter_MMXU1_NamPlt) +#define IEDMODEL_Inverter_MMXU1_NamPlt_vendor (&iedModel_Inverter_MMXU1_NamPlt_vendor) +#define IEDMODEL_Inverter_MMXU1_NamPlt_swRev (&iedModel_Inverter_MMXU1_NamPlt_swRev) +#define IEDMODEL_Inverter_MMXU1_NamPlt_d (&iedModel_Inverter_MMXU1_NamPlt_d) +#define IEDMODEL_Inverter_MMXU1_TotW (&iedModel_Inverter_MMXU1_TotW) +#define IEDMODEL_Inverter_MMXU1_TotW_mag (&iedModel_Inverter_MMXU1_TotW_mag) +#define IEDMODEL_Inverter_MMXU1_TotW_mag_f (&iedModel_Inverter_MMXU1_TotW_mag_f) +#define IEDMODEL_Inverter_MMXU1_TotW_q (&iedModel_Inverter_MMXU1_TotW_q) +#define IEDMODEL_Inverter_MMXU1_TotW_t (&iedModel_Inverter_MMXU1_TotW_t) +#define IEDMODEL_Inverter_MMXU1_TotVAr (&iedModel_Inverter_MMXU1_TotVAr) +#define IEDMODEL_Inverter_MMXU1_TotVAr_mag (&iedModel_Inverter_MMXU1_TotVAr_mag) +#define IEDMODEL_Inverter_MMXU1_TotVAr_mag_f (&iedModel_Inverter_MMXU1_TotVAr_mag_f) +#define IEDMODEL_Inverter_MMXU1_TotVAr_q (&iedModel_Inverter_MMXU1_TotVAr_q) +#define IEDMODEL_Inverter_MMXU1_TotVAr_t (&iedModel_Inverter_MMXU1_TotVAr_t) +#define IEDMODEL_Inverter_MMXU1_TotVA (&iedModel_Inverter_MMXU1_TotVA) +#define IEDMODEL_Inverter_MMXU1_TotVA_mag (&iedModel_Inverter_MMXU1_TotVA_mag) +#define IEDMODEL_Inverter_MMXU1_TotVA_mag_f (&iedModel_Inverter_MMXU1_TotVA_mag_f) +#define IEDMODEL_Inverter_MMXU1_TotVA_q (&iedModel_Inverter_MMXU1_TotVA_q) +#define IEDMODEL_Inverter_MMXU1_TotVA_t (&iedModel_Inverter_MMXU1_TotVA_t) +#define IEDMODEL_Inverter_MMXU1_Hz (&iedModel_Inverter_MMXU1_Hz) +#define IEDMODEL_Inverter_MMXU1_Hz_mag (&iedModel_Inverter_MMXU1_Hz_mag) +#define IEDMODEL_Inverter_MMXU1_Hz_mag_f (&iedModel_Inverter_MMXU1_Hz_mag_f) +#define IEDMODEL_Inverter_MMXU1_Hz_q (&iedModel_Inverter_MMXU1_Hz_q) +#define IEDMODEL_Inverter_MMXU1_Hz_t (&iedModel_Inverter_MMXU1_Hz_t) +#define IEDMODEL_Inverter_MMXU1_PhV (&iedModel_Inverter_MMXU1_PhV) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA (&iedModel_Inverter_MMXU1_PhV_phsA) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_cVal (&iedModel_Inverter_MMXU1_PhV_phsA_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_cVal_mag (&iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_phsA_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_q (&iedModel_Inverter_MMXU1_PhV_phsA_q) +#define IEDMODEL_Inverter_MMXU1_PhV_phsA_t (&iedModel_Inverter_MMXU1_PhV_phsA_t) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB (&iedModel_Inverter_MMXU1_PhV_phsB) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_cVal (&iedModel_Inverter_MMXU1_PhV_phsB_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_cVal_mag (&iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_phsB_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_q (&iedModel_Inverter_MMXU1_PhV_phsB_q) +#define IEDMODEL_Inverter_MMXU1_PhV_phsB_t (&iedModel_Inverter_MMXU1_PhV_phsB_t) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC (&iedModel_Inverter_MMXU1_PhV_phsC) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_cVal (&iedModel_Inverter_MMXU1_PhV_phsC_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_cVal_mag (&iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_phsC_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_q (&iedModel_Inverter_MMXU1_PhV_phsC_q) +#define IEDMODEL_Inverter_MMXU1_PhV_phsC_t (&iedModel_Inverter_MMXU1_PhV_phsC_t) +#define IEDMODEL_Inverter_MMXU1_PhV_neut (&iedModel_Inverter_MMXU1_PhV_neut) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_cVal (&iedModel_Inverter_MMXU1_PhV_neut_cVal) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_cVal_mag (&iedModel_Inverter_MMXU1_PhV_neut_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_cVal_mag_f (&iedModel_Inverter_MMXU1_PhV_neut_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_q (&iedModel_Inverter_MMXU1_PhV_neut_q) +#define IEDMODEL_Inverter_MMXU1_PhV_neut_t (&iedModel_Inverter_MMXU1_PhV_neut_t) +#define IEDMODEL_Inverter_MMXU1_A (&iedModel_Inverter_MMXU1_A) +#define IEDMODEL_Inverter_MMXU1_A_phsA (&iedModel_Inverter_MMXU1_A_phsA) +#define IEDMODEL_Inverter_MMXU1_A_phsA_cVal (&iedModel_Inverter_MMXU1_A_phsA_cVal) +#define IEDMODEL_Inverter_MMXU1_A_phsA_cVal_mag (&iedModel_Inverter_MMXU1_A_phsA_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_phsA_cVal_mag_f (&iedModel_Inverter_MMXU1_A_phsA_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_phsA_q (&iedModel_Inverter_MMXU1_A_phsA_q) +#define IEDMODEL_Inverter_MMXU1_A_phsA_t (&iedModel_Inverter_MMXU1_A_phsA_t) +#define IEDMODEL_Inverter_MMXU1_A_phsB (&iedModel_Inverter_MMXU1_A_phsB) +#define IEDMODEL_Inverter_MMXU1_A_phsB_cVal (&iedModel_Inverter_MMXU1_A_phsB_cVal) +#define IEDMODEL_Inverter_MMXU1_A_phsB_cVal_mag (&iedModel_Inverter_MMXU1_A_phsB_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_phsB_cVal_mag_f (&iedModel_Inverter_MMXU1_A_phsB_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_phsB_q (&iedModel_Inverter_MMXU1_A_phsB_q) +#define IEDMODEL_Inverter_MMXU1_A_phsB_t (&iedModel_Inverter_MMXU1_A_phsB_t) +#define IEDMODEL_Inverter_MMXU1_A_phsC (&iedModel_Inverter_MMXU1_A_phsC) +#define IEDMODEL_Inverter_MMXU1_A_phsC_cVal (&iedModel_Inverter_MMXU1_A_phsC_cVal) +#define IEDMODEL_Inverter_MMXU1_A_phsC_cVal_mag (&iedModel_Inverter_MMXU1_A_phsC_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_phsC_cVal_mag_f (&iedModel_Inverter_MMXU1_A_phsC_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_phsC_q (&iedModel_Inverter_MMXU1_A_phsC_q) +#define IEDMODEL_Inverter_MMXU1_A_phsC_t (&iedModel_Inverter_MMXU1_A_phsC_t) +#define IEDMODEL_Inverter_MMXU1_A_neut (&iedModel_Inverter_MMXU1_A_neut) +#define IEDMODEL_Inverter_MMXU1_A_neut_cVal (&iedModel_Inverter_MMXU1_A_neut_cVal) +#define IEDMODEL_Inverter_MMXU1_A_neut_cVal_mag (&iedModel_Inverter_MMXU1_A_neut_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_A_neut_cVal_mag_f (&iedModel_Inverter_MMXU1_A_neut_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_A_neut_q (&iedModel_Inverter_MMXU1_A_neut_q) +#define IEDMODEL_Inverter_MMXU1_A_neut_t (&iedModel_Inverter_MMXU1_A_neut_t) +#define IEDMODEL_Inverter_MMXU1_W (&iedModel_Inverter_MMXU1_W) +#define IEDMODEL_Inverter_MMXU1_W_phsA (&iedModel_Inverter_MMXU1_W_phsA) +#define IEDMODEL_Inverter_MMXU1_W_phsA_cVal (&iedModel_Inverter_MMXU1_W_phsA_cVal) +#define IEDMODEL_Inverter_MMXU1_W_phsA_cVal_mag (&iedModel_Inverter_MMXU1_W_phsA_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_W_phsA_cVal_mag_f (&iedModel_Inverter_MMXU1_W_phsA_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_W_phsA_q (&iedModel_Inverter_MMXU1_W_phsA_q) +#define IEDMODEL_Inverter_MMXU1_W_phsA_t (&iedModel_Inverter_MMXU1_W_phsA_t) +#define IEDMODEL_Inverter_MMXU1_W_phsB (&iedModel_Inverter_MMXU1_W_phsB) +#define IEDMODEL_Inverter_MMXU1_W_phsB_cVal (&iedModel_Inverter_MMXU1_W_phsB_cVal) +#define IEDMODEL_Inverter_MMXU1_W_phsB_cVal_mag (&iedModel_Inverter_MMXU1_W_phsB_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_W_phsB_cVal_mag_f (&iedModel_Inverter_MMXU1_W_phsB_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_W_phsB_q (&iedModel_Inverter_MMXU1_W_phsB_q) +#define IEDMODEL_Inverter_MMXU1_W_phsB_t (&iedModel_Inverter_MMXU1_W_phsB_t) +#define IEDMODEL_Inverter_MMXU1_W_phsC (&iedModel_Inverter_MMXU1_W_phsC) +#define IEDMODEL_Inverter_MMXU1_W_phsC_cVal (&iedModel_Inverter_MMXU1_W_phsC_cVal) +#define IEDMODEL_Inverter_MMXU1_W_phsC_cVal_mag (&iedModel_Inverter_MMXU1_W_phsC_cVal_mag) +#define IEDMODEL_Inverter_MMXU1_W_phsC_cVal_mag_f (&iedModel_Inverter_MMXU1_W_phsC_cVal_mag_f) +#define IEDMODEL_Inverter_MMXU1_W_phsC_q (&iedModel_Inverter_MMXU1_W_phsC_q) +#define IEDMODEL_Inverter_MMXU1_W_phsC_t (&iedModel_Inverter_MMXU1_W_phsC_t) +#define IEDMODEL_Battery (&iedModel_Battery) +#define IEDMODEL_Battery_LLN0 (&iedModel_Battery_LLN0) +#define IEDMODEL_Battery_LLN0_Mod (&iedModel_Battery_LLN0_Mod) +#define IEDMODEL_Battery_LLN0_Mod_q (&iedModel_Battery_LLN0_Mod_q) +#define IEDMODEL_Battery_LLN0_Mod_t (&iedModel_Battery_LLN0_Mod_t) +#define IEDMODEL_Battery_LLN0_Mod_ctlModel (&iedModel_Battery_LLN0_Mod_ctlModel) +#define IEDMODEL_Battery_LLN0_Beh (&iedModel_Battery_LLN0_Beh) +#define IEDMODEL_Battery_LLN0_Beh_stVal (&iedModel_Battery_LLN0_Beh_stVal) +#define IEDMODEL_Battery_LLN0_Beh_q (&iedModel_Battery_LLN0_Beh_q) +#define IEDMODEL_Battery_LLN0_Beh_t (&iedModel_Battery_LLN0_Beh_t) +#define IEDMODEL_Battery_LLN0_Health (&iedModel_Battery_LLN0_Health) +#define IEDMODEL_Battery_LLN0_Health_stVal (&iedModel_Battery_LLN0_Health_stVal) +#define IEDMODEL_Battery_LLN0_Health_q (&iedModel_Battery_LLN0_Health_q) +#define IEDMODEL_Battery_LLN0_Health_t (&iedModel_Battery_LLN0_Health_t) +#define IEDMODEL_Battery_LLN0_NamPlt (&iedModel_Battery_LLN0_NamPlt) +#define IEDMODEL_Battery_LLN0_NamPlt_vendor (&iedModel_Battery_LLN0_NamPlt_vendor) +#define IEDMODEL_Battery_LLN0_NamPlt_swRev (&iedModel_Battery_LLN0_NamPlt_swRev) +#define IEDMODEL_Battery_LLN0_NamPlt_d (&iedModel_Battery_LLN0_NamPlt_d) +#define IEDMODEL_Battery_LLN0_NamPlt_configRev (&iedModel_Battery_LLN0_NamPlt_configRev) +#define IEDMODEL_Battery_LLN0_NamPlt_ldNs (&iedModel_Battery_LLN0_NamPlt_ldNs) +#define IEDMODEL_Battery_LPHD1 (&iedModel_Battery_LPHD1) +#define IEDMODEL_Battery_LPHD1_PhyNam (&iedModel_Battery_LPHD1_PhyNam) +#define IEDMODEL_Battery_LPHD1_PhyNam_vendor (&iedModel_Battery_LPHD1_PhyNam_vendor) +#define IEDMODEL_Battery_LPHD1_PhyHealth (&iedModel_Battery_LPHD1_PhyHealth) +#define IEDMODEL_Battery_LPHD1_PhyHealth_stVal (&iedModel_Battery_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Battery_LPHD1_PhyHealth_q (&iedModel_Battery_LPHD1_PhyHealth_q) +#define IEDMODEL_Battery_LPHD1_PhyHealth_t (&iedModel_Battery_LPHD1_PhyHealth_t) +#define IEDMODEL_Battery_LPHD1_Proxy (&iedModel_Battery_LPHD1_Proxy) +#define IEDMODEL_Battery_LPHD1_Proxy_stVal (&iedModel_Battery_LPHD1_Proxy_stVal) +#define IEDMODEL_Battery_LPHD1_Proxy_q (&iedModel_Battery_LPHD1_Proxy_q) +#define IEDMODEL_Battery_LPHD1_Proxy_t (&iedModel_Battery_LPHD1_Proxy_t) +#define IEDMODEL_Battery_ZBAT1 (&iedModel_Battery_ZBAT1) +#define IEDMODEL_Battery_ZBAT1_Mod (&iedModel_Battery_ZBAT1_Mod) +#define IEDMODEL_Battery_ZBAT1_Mod_q (&iedModel_Battery_ZBAT1_Mod_q) +#define IEDMODEL_Battery_ZBAT1_Mod_t (&iedModel_Battery_ZBAT1_Mod_t) +#define IEDMODEL_Battery_ZBAT1_Mod_ctlModel (&iedModel_Battery_ZBAT1_Mod_ctlModel) +#define IEDMODEL_Battery_ZBAT1_Beh (&iedModel_Battery_ZBAT1_Beh) +#define IEDMODEL_Battery_ZBAT1_Beh_stVal (&iedModel_Battery_ZBAT1_Beh_stVal) +#define IEDMODEL_Battery_ZBAT1_Beh_q (&iedModel_Battery_ZBAT1_Beh_q) +#define IEDMODEL_Battery_ZBAT1_Beh_t (&iedModel_Battery_ZBAT1_Beh_t) +#define IEDMODEL_Battery_ZBAT1_Health (&iedModel_Battery_ZBAT1_Health) +#define IEDMODEL_Battery_ZBAT1_Health_stVal (&iedModel_Battery_ZBAT1_Health_stVal) +#define IEDMODEL_Battery_ZBAT1_Health_q (&iedModel_Battery_ZBAT1_Health_q) +#define IEDMODEL_Battery_ZBAT1_Health_t (&iedModel_Battery_ZBAT1_Health_t) +#define IEDMODEL_Battery_ZBAT1_NamPlt (&iedModel_Battery_ZBAT1_NamPlt) +#define IEDMODEL_Battery_ZBAT1_NamPlt_vendor (&iedModel_Battery_ZBAT1_NamPlt_vendor) +#define IEDMODEL_Battery_ZBAT1_NamPlt_swRev (&iedModel_Battery_ZBAT1_NamPlt_swRev) +#define IEDMODEL_Battery_ZBAT1_NamPlt_d (&iedModel_Battery_ZBAT1_NamPlt_d) +#define IEDMODEL_Battery_ZBAT1_Vol (&iedModel_Battery_ZBAT1_Vol) +#define IEDMODEL_Battery_ZBAT1_Vol_mag (&iedModel_Battery_ZBAT1_Vol_mag) +#define IEDMODEL_Battery_ZBAT1_Vol_mag_f (&iedModel_Battery_ZBAT1_Vol_mag_f) +#define IEDMODEL_Battery_ZBAT1_Vol_q (&iedModel_Battery_ZBAT1_Vol_q) +#define IEDMODEL_Battery_ZBAT1_Vol_t (&iedModel_Battery_ZBAT1_Vol_t) +#define IEDMODEL_Battery_ZBAT1_Amp (&iedModel_Battery_ZBAT1_Amp) +#define IEDMODEL_Battery_ZBAT1_Amp_mag (&iedModel_Battery_ZBAT1_Amp_mag) +#define IEDMODEL_Battery_ZBAT1_Amp_mag_f (&iedModel_Battery_ZBAT1_Amp_mag_f) +#define IEDMODEL_Battery_ZBAT1_Amp_q (&iedModel_Battery_ZBAT1_Amp_q) +#define IEDMODEL_Battery_ZBAT1_Amp_t (&iedModel_Battery_ZBAT1_Amp_t) +#define IEDMODEL_Battery_ZBTC1 (&iedModel_Battery_ZBTC1) +#define IEDMODEL_Battery_ZBTC1_Mod (&iedModel_Battery_ZBTC1_Mod) +#define IEDMODEL_Battery_ZBTC1_Mod_q (&iedModel_Battery_ZBTC1_Mod_q) +#define IEDMODEL_Battery_ZBTC1_Mod_t (&iedModel_Battery_ZBTC1_Mod_t) +#define IEDMODEL_Battery_ZBTC1_Mod_ctlModel (&iedModel_Battery_ZBTC1_Mod_ctlModel) +#define IEDMODEL_Battery_ZBTC1_Beh (&iedModel_Battery_ZBTC1_Beh) +#define IEDMODEL_Battery_ZBTC1_Beh_stVal (&iedModel_Battery_ZBTC1_Beh_stVal) +#define IEDMODEL_Battery_ZBTC1_Beh_q (&iedModel_Battery_ZBTC1_Beh_q) +#define IEDMODEL_Battery_ZBTC1_Beh_t (&iedModel_Battery_ZBTC1_Beh_t) +#define IEDMODEL_Battery_ZBTC1_Health (&iedModel_Battery_ZBTC1_Health) +#define IEDMODEL_Battery_ZBTC1_Health_stVal (&iedModel_Battery_ZBTC1_Health_stVal) +#define IEDMODEL_Battery_ZBTC1_Health_q (&iedModel_Battery_ZBTC1_Health_q) +#define IEDMODEL_Battery_ZBTC1_Health_t (&iedModel_Battery_ZBTC1_Health_t) +#define IEDMODEL_Battery_ZBTC1_NamPlt (&iedModel_Battery_ZBTC1_NamPlt) +#define IEDMODEL_Battery_ZBTC1_NamPlt_vendor (&iedModel_Battery_ZBTC1_NamPlt_vendor) +#define IEDMODEL_Battery_ZBTC1_NamPlt_swRev (&iedModel_Battery_ZBTC1_NamPlt_swRev) +#define IEDMODEL_Battery_ZBTC1_NamPlt_d (&iedModel_Battery_ZBTC1_NamPlt_d) +#define IEDMODEL_Battery_ZBTC1_BatChaSt (&iedModel_Battery_ZBTC1_BatChaSt) +#define IEDMODEL_Battery_ZBTC1_BatChaPwr (&iedModel_Battery_ZBTC1_BatChaPwr) +#define IEDMODEL_Battery_ZBTC1_BatChaMod (&iedModel_Battery_ZBTC1_BatChaMod) +#define IEDMODEL_Battery_ZBTC1_ChaV (&iedModel_Battery_ZBTC1_ChaV) +#define IEDMODEL_Battery_ZBTC1_ChaV_mag (&iedModel_Battery_ZBTC1_ChaV_mag) +#define IEDMODEL_Battery_ZBTC1_ChaV_mag_f (&iedModel_Battery_ZBTC1_ChaV_mag_f) +#define IEDMODEL_Battery_ZBTC1_ChaV_q (&iedModel_Battery_ZBTC1_ChaV_q) +#define IEDMODEL_Battery_ZBTC1_ChaV_t (&iedModel_Battery_ZBTC1_ChaV_t) +#define IEDMODEL_Battery_ZBTC1_ChaA (&iedModel_Battery_ZBTC1_ChaA) +#define IEDMODEL_Battery_ZBTC1_ChaA_mag (&iedModel_Battery_ZBTC1_ChaA_mag) +#define IEDMODEL_Battery_ZBTC1_ChaA_mag_f (&iedModel_Battery_ZBTC1_ChaA_mag_f) +#define IEDMODEL_Battery_ZBTC1_ChaA_q (&iedModel_Battery_ZBTC1_ChaA_q) +#define IEDMODEL_Battery_ZBTC1_ChaA_t (&iedModel_Battery_ZBTC1_ChaA_t) +#define IEDMODEL_Physical_Measurements (&iedModel_Physical_Measurements) +#define IEDMODEL_Physical_Measurements_LLN0 (&iedModel_Physical_Measurements_LLN0) +#define IEDMODEL_Physical_Measurements_LLN0_Mod (&iedModel_Physical_Measurements_LLN0_Mod) +#define IEDMODEL_Physical_Measurements_LLN0_Mod_q (&iedModel_Physical_Measurements_LLN0_Mod_q) +#define IEDMODEL_Physical_Measurements_LLN0_Mod_t (&iedModel_Physical_Measurements_LLN0_Mod_t) +#define IEDMODEL_Physical_Measurements_LLN0_Mod_ctlModel (&iedModel_Physical_Measurements_LLN0_Mod_ctlModel) +#define IEDMODEL_Physical_Measurements_LLN0_Beh (&iedModel_Physical_Measurements_LLN0_Beh) +#define IEDMODEL_Physical_Measurements_LLN0_Beh_stVal (&iedModel_Physical_Measurements_LLN0_Beh_stVal) +#define IEDMODEL_Physical_Measurements_LLN0_Beh_q (&iedModel_Physical_Measurements_LLN0_Beh_q) +#define IEDMODEL_Physical_Measurements_LLN0_Beh_t (&iedModel_Physical_Measurements_LLN0_Beh_t) +#define IEDMODEL_Physical_Measurements_LLN0_Health (&iedModel_Physical_Measurements_LLN0_Health) +#define IEDMODEL_Physical_Measurements_LLN0_Health_stVal (&iedModel_Physical_Measurements_LLN0_Health_stVal) +#define IEDMODEL_Physical_Measurements_LLN0_Health_q (&iedModel_Physical_Measurements_LLN0_Health_q) +#define IEDMODEL_Physical_Measurements_LLN0_Health_t (&iedModel_Physical_Measurements_LLN0_Health_t) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt (&iedModel_Physical_Measurements_LLN0_NamPlt) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_vendor (&iedModel_Physical_Measurements_LLN0_NamPlt_vendor) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_swRev (&iedModel_Physical_Measurements_LLN0_NamPlt_swRev) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_d (&iedModel_Physical_Measurements_LLN0_NamPlt_d) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_configRev (&iedModel_Physical_Measurements_LLN0_NamPlt_configRev) +#define IEDMODEL_Physical_Measurements_LLN0_NamPlt_ldNs (&iedModel_Physical_Measurements_LLN0_NamPlt_ldNs) +#define IEDMODEL_Physical_Measurements_LPHD1 (&iedModel_Physical_Measurements_LPHD1) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyNam (&iedModel_Physical_Measurements_LPHD1_PhyNam) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyNam_vendor (&iedModel_Physical_Measurements_LPHD1_PhyNam_vendor) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth (&iedModel_Physical_Measurements_LPHD1_PhyHealth) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth_stVal (&iedModel_Physical_Measurements_LPHD1_PhyHealth_stVal) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth_q (&iedModel_Physical_Measurements_LPHD1_PhyHealth_q) +#define IEDMODEL_Physical_Measurements_LPHD1_PhyHealth_t (&iedModel_Physical_Measurements_LPHD1_PhyHealth_t) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy (&iedModel_Physical_Measurements_LPHD1_Proxy) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy_stVal (&iedModel_Physical_Measurements_LPHD1_Proxy_stVal) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy_q (&iedModel_Physical_Measurements_LPHD1_Proxy_q) +#define IEDMODEL_Physical_Measurements_LPHD1_Proxy_t (&iedModel_Physical_Measurements_LPHD1_Proxy_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_61400_25/CMakeLists.txt b/examples/server_example_61400_25/CMakeLists.txt new file mode 100644 index 0000000..1f90cc8 --- /dev/null +++ b/examples/server_example_61400_25/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example_61400_25_SRCS + server_example_61400_25.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example_61400_25_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_61400_25 + ${server_example_61400_25_SRCS} +) + +target_link_libraries(server_example_61400_25 + iec61850 +) diff --git a/examples/server_example_61400_25/Makefile b/examples/server_example_61400_25/Makefile new file mode 100644 index 0000000..28ab208 --- /dev/null +++ b/examples/server_example_61400_25/Makefile @@ -0,0 +1,25 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_61400_25 +PROJECT_SOURCES = server_example_61400_25.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = wtur.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example_61400_25/server_example_61400_25.c b/examples/server_example_61400_25/server_example_61400_25.c new file mode 100644 index 0000000..c066411 --- /dev/null +++ b/examples/server_example_61400_25/server_example_61400_25.c @@ -0,0 +1,102 @@ +/* + * server_example1.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static IedServer iedServer; + +static int running = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + + +bool +controlHandlerForIntegerOutput(void* parameter, MmsValue* value, bool test) +{ + if (MmsValue_getType(value) != MMS_INTEGER) + return false; + + printf("Received integer control value: %i\n", MmsValue_toInt32(value)); + + uint64_t timeStamp = Hal_getTimeInMs(); + + if (parameter == IEDMODEL_WTG_WTUR1_SetTurOp_actSt) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_WTG_WTUR1_SetTurOp_actSt_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_WTG_WTUR1_SetTurOp_actSt_stVal, value); + } + + return true; +} + +int main(int argc, char** argv) { + + int tcpPort = 102; + + if (argc > 1) { + tcpPort = atoi(argv[1]); + } + + iedServer = IedServer_create(&iedModel); + + /* set control model for WTUR1.SetTurOp.actSt to direct-control-with-normal-security */ + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_WTG_WTUR1_SetTurOp_actSt_ctlModel, 1); + + IedServer_setControlHandler(iedServer, IEDMODEL_WTG_WTUR1_SetTurOp_actSt, + (ControlHandler) controlHandlerForIntegerOutput, + IEDMODEL_WTG_WTUR1_SetTurOp_actSt); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, tcpPort); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + while (running) { + Thread_sleep(1); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example_61400_25/static_model.c b/examples/server_example_61400_25/static_model.c new file mode 100644 index 0000000..ba022fd --- /dev/null +++ b/examples/server_example_61400_25/static_model.c @@ -0,0 +1,4482 @@ +/* + * static_model.c + * + * automatically generated from wtur.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_WTG; +extern LogicalNode iedModel_WTG_LLN0; +extern DataObject iedModel_WTG_LLN0_Mod; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_ctlVal; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_operTm; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_ctlNum; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_T; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_Test; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_Check; +extern DataAttribute iedModel_WTG_LLN0_Mod_stVal; +extern DataAttribute iedModel_WTG_LLN0_Mod_q; +extern DataAttribute iedModel_WTG_LLN0_Mod_t; +extern DataAttribute iedModel_WTG_LLN0_Mod_ctlModel; +extern DataObject iedModel_WTG_LLN0_Beh; +extern DataAttribute iedModel_WTG_LLN0_Beh_stVal; +extern DataAttribute iedModel_WTG_LLN0_Beh_q; +extern DataAttribute iedModel_WTG_LLN0_Beh_t; +extern DataObject iedModel_WTG_LLN0_Health; +extern DataAttribute iedModel_WTG_LLN0_Health_stVal; +extern DataAttribute iedModel_WTG_LLN0_Health_q; +extern DataAttribute iedModel_WTG_LLN0_Health_t; +extern DataObject iedModel_WTG_LLN0_NamPlt; +extern DataAttribute iedModel_WTG_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_WTG_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_WTG_LLN0_NamPlt_configRev; +extern LogicalNode iedModel_WTG_LPHD1; +extern DataObject iedModel_WTG_LPHD1_NamPlt; +extern DataAttribute iedModel_WTG_LPHD1_NamPlt_vendor; +extern DataAttribute iedModel_WTG_LPHD1_NamPlt_swRev; +extern DataAttribute iedModel_WTG_LPHD1_NamPlt_configRev; +extern DataObject iedModel_WTG_LPHD1_PhyNam; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_vendor; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_hwRev; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_swRev; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_serNum; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_model; +extern DataObject iedModel_WTG_LPHD1_PhyHealth; +extern DataAttribute iedModel_WTG_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_WTG_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_WTG_LPHD1_PhyHealth_t; +extern DataObject iedModel_WTG_LPHD1_Proxy; +extern DataAttribute iedModel_WTG_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_WTG_LPHD1_Proxy_q; +extern DataAttribute iedModel_WTG_LPHD1_Proxy_t; +extern LogicalNode iedModel_WTG_WTUR1; +extern DataObject iedModel_WTG_WTUR1_NamPlt; +extern DataAttribute iedModel_WTG_WTUR1_NamPlt_vendor; +extern DataAttribute iedModel_WTG_WTUR1_NamPlt_swRev; +extern DataAttribute iedModel_WTG_WTUR1_NamPlt_configRev; +extern DataObject iedModel_WTG_WTUR1_TotWh; +extern DataObject iedModel_WTG_WTUR1_TotWh_manRs; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_TotWh_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_TotWh_actCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_t; +extern DataObject iedModel_WTG_WTUR1_TotWh_oldCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_t; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_ctTot; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_dly; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_mly; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_yly; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_tot; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_rsPer; +extern DataObject iedModel_WTG_WTUR1_TurSt; +extern DataObject iedModel_WTG_WTUR1_TurSt_actSt; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_oldSt; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_manRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_actTmVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_tmTot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_dly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_mly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_yly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_tot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_rsPer; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_manRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_actCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_ctTot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_dly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_mly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_yly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_tot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_rsPer; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_preTmms; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_pstTmms; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_smpTmms; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_datSetMx; +extern DataObject iedModel_WTG_WTUR1_W; +extern DataAttribute iedModel_WTG_WTUR1_W_instMag; +extern DataAttribute iedModel_WTG_WTUR1_W_instMag_i; +extern DataAttribute iedModel_WTG_WTUR1_W_instMag_f; +extern DataAttribute iedModel_WTG_WTUR1_W_mag; +extern DataAttribute iedModel_WTG_WTUR1_W_mag_i; +extern DataAttribute iedModel_WTG_WTUR1_W_mag_f; +extern DataAttribute iedModel_WTG_WTUR1_W_q; +extern DataAttribute iedModel_WTG_WTUR1_W_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_actSt; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_ctlModel; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_oldSt; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_tmTot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_dly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_mly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_yly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_tot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_rsPer; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_ctTot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_dly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_mly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_yly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_tot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_rsPer; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs; + + + +LogicalDevice iedModel_WTG = { + LogicalDeviceModelType, + "WTG", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_WTG_LLN0 +}; + +LogicalNode iedModel_WTG_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_WTG, + (ModelNode*) &iedModel_WTG_LPHD1, + (ModelNode*) &iedModel_WTG_LLN0_Mod, +}; + +DataObject iedModel_WTG_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_WTG_LLN0, + (ModelNode*) &iedModel_WTG_LLN0_Beh, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + 0 +}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_LLN0_Mod, + (ModelNode*) &iedModel_WTG_LLN0_Mod_stVal, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_origin, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_LLN0_Mod_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_LLN0_Mod, + (ModelNode*) &iedModel_WTG_LLN0_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_LLN0_Mod, + (ModelNode*) &iedModel_WTG_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_LLN0_Mod, + (ModelNode*) &iedModel_WTG_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_WTG_LLN0, + (ModelNode*) &iedModel_WTG_LLN0_Health, + (ModelNode*) &iedModel_WTG_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_WTG_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_LLN0_Beh, + (ModelNode*) &iedModel_WTG_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_LLN0_Beh, + (ModelNode*) &iedModel_WTG_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_WTG_LLN0, + (ModelNode*) &iedModel_WTG_LLN0_NamPlt, + (ModelNode*) &iedModel_WTG_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_WTG_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_LLN0_Health, + (ModelNode*) &iedModel_WTG_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_LLN0_Health, + (ModelNode*) &iedModel_WTG_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_WTG_LLN0, + NULL, + (ModelNode*) &iedModel_WTG_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_WTG_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_WTG_LLN0_NamPlt, + (ModelNode*) &iedModel_WTG_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_WTG_LLN0_NamPlt, + (ModelNode*) &iedModel_WTG_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_WTG_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_WTG_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_WTG, + (ModelNode*) &iedModel_WTG_WTUR1, + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt, +}; + +DataObject iedModel_WTG_LPHD1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_WTG_LPHD1, + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam, + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_WTG_LPHD1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt, + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt, + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_WTG_LPHD1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_WTG_LPHD1, + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth, + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_WTG_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam, + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam_hwRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_PhyNam_hwRev = { + DataAttributeModelType, + "hwRev", + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam, + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_PhyNam_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam, + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam_serNum, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_PhyNam_serNum = { + DataAttributeModelType, + "serNum", + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam, + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam_model, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_PhyNam_model = { + DataAttributeModelType, + "model", + (ModelNode*) &iedModel_WTG_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_WTG_LPHD1, + (ModelNode*) &iedModel_WTG_LPHD1_Proxy, + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_WTG_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth, + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth, + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_WTG_LPHD1, + NULL, + (ModelNode*) &iedModel_WTG_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_WTG_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_LPHD1_Proxy, + (ModelNode*) &iedModel_WTG_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_LPHD1_Proxy, + (ModelNode*) &iedModel_WTG_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_WTG_WTUR1 = { + LogicalNodeModelType, + "WTUR1", + (ModelNode*) &iedModel_WTG, + NULL, + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt, +}; + +DataObject iedModel_WTG_WTUR1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_WTG_WTUR1, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt, + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt, + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_WTG_WTUR1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TotWh = { + DataObjectModelType, + "TotWh", + (ModelNode*) &iedModel_WTG_WTUR1, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + 0 +}; + +DataObject iedModel_WTG_WTUR1_TotWh_manRs = { + DataObjectModelType, + "manRs", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_sboTimeout, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_sboTimeout = { + DataAttributeModelType, + "sboTimeout", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs_sboClass, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_sboClass = { + DataAttributeModelType, + "sboClass", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_manRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TotWh_hisRs = { + DataObjectModelType, + "hisRs", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_hisRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TotWh_actCtVal = { + DataObjectModelType, + "actCtVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_actCtVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TotWh_oldCtVal = { + DataObjectModelType, + "oldCtVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_ctTot, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_oldCtVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_ctTot = { + DataAttributeModelType, + "ctTot", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_dly, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_dly = { + DataAttributeModelType, + "dly", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_mly, + NULL, + 32, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_mly = { + DataAttributeModelType, + "mly", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_yly, + NULL, + 13, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_yly = { + DataAttributeModelType, + "yly", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_tot, + NULL, + 21, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_tot = { + DataAttributeModelType, + "tot", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + (ModelNode*) &iedModel_WTG_WTUR1_TotWh_rsPer, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TotWh_rsPer = { + DataAttributeModelType, + "rsPer", + (ModelNode*) &iedModel_WTG_WTUR1_TotWh, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt = { + DataObjectModelType, + "TurSt", + (ModelNode*) &iedModel_WTG_WTUR1, + (ModelNode*) &iedModel_WTG_WTUR1_W, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt, + 0 +}; + +DataObject iedModel_WTG_WTUR1_TurSt_actSt = { + DataObjectModelType, + "actSt", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_actSt, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_oldSt = { + DataObjectModelType, + "oldSt", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_oldSt, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stTm = { + DataObjectModelType, + "stTm", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + 0 +}; + +DataObject iedModel_WTG_WTUR1_TurSt_stTm_manRs = { + DataObjectModelType, + "manRs", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboTimeout, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboTimeout = { + DataAttributeModelType, + "sboTimeout", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboClass, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboClass = { + DataAttributeModelType, + "sboClass", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_manRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stTm_hisRs = { + DataObjectModelType, + "hisRs", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_hisRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stTm_actTmVal = { + DataObjectModelType, + "actTmVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_actTmVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal = { + DataObjectModelType, + "oldTmVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_tmTot, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_tmTot = { + DataAttributeModelType, + "tmTot", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_dly, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_dly = { + DataAttributeModelType, + "dly", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_mly, + NULL, + 32, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_mly = { + DataAttributeModelType, + "mly", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_yly, + NULL, + 13, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_yly = { + DataAttributeModelType, + "yly", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_tot, + NULL, + 21, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_tot = { + DataAttributeModelType, + "tot", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm_rsPer, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_rsPer = { + DataAttributeModelType, + "rsPer", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stTm, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stCt = { + DataObjectModelType, + "stCt", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_preTmms, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + 0 +}; + +DataObject iedModel_WTG_WTUR1_TurSt_stCt_manRs = { + DataObjectModelType, + "manRs", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboTimeout, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboTimeout = { + DataAttributeModelType, + "sboTimeout", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboClass, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboClass = { + DataAttributeModelType, + "sboClass", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_manRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stCt_hisRs = { + DataObjectModelType, + "hisRs", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_hisRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stCt_actCtVal = { + DataObjectModelType, + "actCtVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_actCtVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal = { + DataObjectModelType, + "oldCtVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_ctTot, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_ctTot = { + DataAttributeModelType, + "ctTot", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_dly, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_dly = { + DataAttributeModelType, + "dly", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_mly, + NULL, + 32, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_mly = { + DataAttributeModelType, + "mly", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_yly, + NULL, + 13, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_yly = { + DataAttributeModelType, + "yly", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_tot, + NULL, + 21, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_tot = { + DataAttributeModelType, + "tot", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt_rsPer, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_rsPer = { + DataAttributeModelType, + "rsPer", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_stCt, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_preTmms = { + DataAttributeModelType, + "preTmms", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_pstTmms, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_pstTmms = { + DataAttributeModelType, + "pstTmms", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_smpTmms, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_smpTmms = { + DataAttributeModelType, + "smpTmms", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + (ModelNode*) &iedModel_WTG_WTUR1_TurSt_datSetMx, + NULL, + 0, + IEC61850_FC_CF, + INT16U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_TurSt_datSetMx = { + DataAttributeModelType, + "datSetMx", + (ModelNode*) &iedModel_WTG_WTUR1_TurSt, + NULL, + NULL, + 0, + IEC61850_FC_CF, + VISIBLE_STRING_129, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_W = { + DataObjectModelType, + "W", + (ModelNode*) &iedModel_WTG_WTUR1, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp, + (ModelNode*) &iedModel_WTG_WTUR1_W_instMag, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_W_instMag = { + DataAttributeModelType, + "instMag", + (ModelNode*) &iedModel_WTG_WTUR1_W, + (ModelNode*) &iedModel_WTG_WTUR1_W_mag, + (ModelNode*) &iedModel_WTG_WTUR1_W_instMag_i, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_instMag_i = { + DataAttributeModelType, + "i", + (ModelNode*) &iedModel_WTG_WTUR1_W_instMag, + (ModelNode*) &iedModel_WTG_WTUR1_W_instMag_f, + NULL, + 0, + IEC61850_FC_MX, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_instMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_WTG_WTUR1_W_instMag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_WTG_WTUR1_W, + (ModelNode*) &iedModel_WTG_WTUR1_W_q, + (ModelNode*) &iedModel_WTG_WTUR1_W_mag_i, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_mag_i = { + DataAttributeModelType, + "i", + (ModelNode*) &iedModel_WTG_WTUR1_W_mag, + (ModelNode*) &iedModel_WTG_WTUR1_W_mag_f, + NULL, + 0, + IEC61850_FC_MX, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_WTG_WTUR1_W_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_W, + (ModelNode*) &iedModel_WTG_WTUR1_W_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_W_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_W, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp = { + DataObjectModelType, + "SetTurOp", + (ModelNode*) &iedModel_WTG_WTUR1, + NULL, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt, + 0 +}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_actSt = { + DataObjectModelType, + "actSt", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_actSt, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_oldSt = { + DataObjectModelType, + "oldSt", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_oldSt, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm = { + DataObjectModelType, + "cmTm", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + 0 +}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs = { + DataObjectModelType, + "manRs", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboTimeout, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboTimeout = { + DataAttributeModelType, + "sboTimeout", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboClass, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboClass = { + DataAttributeModelType, + "sboClass", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs = { + DataObjectModelType, + "hisRs", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal = { + DataObjectModelType, + "actTmVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal = { + DataObjectModelType, + "oldTmVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_tmTot, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_tmTot = { + DataAttributeModelType, + "tmTot", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_dly, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_dly = { + DataAttributeModelType, + "dly", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_mly, + NULL, + 32, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_mly = { + DataAttributeModelType, + "mly", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_yly, + NULL, + 13, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_yly = { + DataAttributeModelType, + "yly", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_tot, + NULL, + 21, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_tot = { + DataAttributeModelType, + "tot", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm_rsPer, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_rsPer = { + DataAttributeModelType, + "rsPer", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmTm, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt = { + DataObjectModelType, + "cmCt", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmAcs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + 0 +}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs = { + DataObjectModelType, + "manRs", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboTimeout, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboTimeout = { + DataAttributeModelType, + "sboTimeout", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboClass, + NULL, + 0, + IEC61850_FC_CF, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboClass = { + DataAttributeModelType, + "sboClass", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs = { + DataObjectModelType, + "hisRs", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_stVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + INT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlNum, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal = { + DataObjectModelType, + "actCtVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal = { + DataObjectModelType, + "oldCtVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_ctTot, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_stVal, + 0 +}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_ctTot = { + DataAttributeModelType, + "ctTot", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_dly, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_dly = { + DataAttributeModelType, + "dly", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_mly, + NULL, + 32, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_mly = { + DataAttributeModelType, + "mly", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_yly, + NULL, + 13, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_yly = { + DataAttributeModelType, + "yly", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_tot, + NULL, + 21, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_tot = { + DataAttributeModelType, + "tot", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt_rsPer, + NULL, + 0, + IEC61850_FC_ST, + INT32U, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_rsPer = { + DataAttributeModelType, + "rsPer", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp_cmCt, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs = { + DataAttributeModelType, + "cmAcs", + (ModelNode*) &iedModel_WTG_WTUR1_SetTurOp, + NULL, + NULL, + 0, + IEC61850_FC_CF, + INT8U, + 0, + NULL, + 0}; + + + + + + +IedModel iedModel = { + "WIND", + &iedModel_WTG, + NULL, + NULL, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ +} diff --git a/examples/server_example_61400_25/static_model.h b/examples/server_example_61400_25/static_model.h new file mode 100644 index 0000000..c19af1c --- /dev/null +++ b/examples/server_example_61400_25/static_model.h @@ -0,0 +1,681 @@ +/* + * static_model.h + * + * automatically generated from wtur.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_WTG; +extern LogicalNode iedModel_WTG_LLN0; +extern DataObject iedModel_WTG_LLN0_Mod; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_ctlVal; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_operTm; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_ctlNum; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_T; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_Test; +extern DataAttribute iedModel_WTG_LLN0_Mod_Oper_Check; +extern DataAttribute iedModel_WTG_LLN0_Mod_stVal; +extern DataAttribute iedModel_WTG_LLN0_Mod_q; +extern DataAttribute iedModel_WTG_LLN0_Mod_t; +extern DataAttribute iedModel_WTG_LLN0_Mod_ctlModel; +extern DataObject iedModel_WTG_LLN0_Beh; +extern DataAttribute iedModel_WTG_LLN0_Beh_stVal; +extern DataAttribute iedModel_WTG_LLN0_Beh_q; +extern DataAttribute iedModel_WTG_LLN0_Beh_t; +extern DataObject iedModel_WTG_LLN0_Health; +extern DataAttribute iedModel_WTG_LLN0_Health_stVal; +extern DataAttribute iedModel_WTG_LLN0_Health_q; +extern DataAttribute iedModel_WTG_LLN0_Health_t; +extern DataObject iedModel_WTG_LLN0_NamPlt; +extern DataAttribute iedModel_WTG_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_WTG_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_WTG_LLN0_NamPlt_configRev; +extern LogicalNode iedModel_WTG_LPHD1; +extern DataObject iedModel_WTG_LPHD1_NamPlt; +extern DataAttribute iedModel_WTG_LPHD1_NamPlt_vendor; +extern DataAttribute iedModel_WTG_LPHD1_NamPlt_swRev; +extern DataAttribute iedModel_WTG_LPHD1_NamPlt_configRev; +extern DataObject iedModel_WTG_LPHD1_PhyNam; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_vendor; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_hwRev; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_swRev; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_serNum; +extern DataAttribute iedModel_WTG_LPHD1_PhyNam_model; +extern DataObject iedModel_WTG_LPHD1_PhyHealth; +extern DataAttribute iedModel_WTG_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_WTG_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_WTG_LPHD1_PhyHealth_t; +extern DataObject iedModel_WTG_LPHD1_Proxy; +extern DataAttribute iedModel_WTG_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_WTG_LPHD1_Proxy_q; +extern DataAttribute iedModel_WTG_LPHD1_Proxy_t; +extern LogicalNode iedModel_WTG_WTUR1; +extern DataObject iedModel_WTG_WTUR1_NamPlt; +extern DataAttribute iedModel_WTG_WTUR1_NamPlt_vendor; +extern DataAttribute iedModel_WTG_WTUR1_NamPlt_swRev; +extern DataAttribute iedModel_WTG_WTUR1_NamPlt_configRev; +extern DataObject iedModel_WTG_WTUR1_TotWh; +extern DataObject iedModel_WTG_WTUR1_TotWh_manRs; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_TotWh_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_TotWh_actCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_actCtVal_t; +extern DataObject iedModel_WTG_WTUR1_TotWh_oldCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_oldCtVal_t; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_ctTot; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_dly; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_mly; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_yly; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_tot; +extern DataAttribute iedModel_WTG_WTUR1_TotWh_rsPer; +extern DataObject iedModel_WTG_WTUR1_TurSt; +extern DataObject iedModel_WTG_WTUR1_TurSt_actSt; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_actSt_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_oldSt; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_oldSt_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_manRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_actTmVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_tmTot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_dly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_mly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_yly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_tot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stTm_rsPer; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_manRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_actCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_t; +extern DataObject iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_t; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_ctTot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_dly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_mly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_yly; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_tot; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_stCt_rsPer; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_preTmms; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_pstTmms; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_smpTmms; +extern DataAttribute iedModel_WTG_WTUR1_TurSt_datSetMx; +extern DataObject iedModel_WTG_WTUR1_W; +extern DataAttribute iedModel_WTG_WTUR1_W_instMag; +extern DataAttribute iedModel_WTG_WTUR1_W_instMag_i; +extern DataAttribute iedModel_WTG_WTUR1_W_instMag_f; +extern DataAttribute iedModel_WTG_WTUR1_W_mag; +extern DataAttribute iedModel_WTG_WTUR1_W_mag_i; +extern DataAttribute iedModel_WTG_WTUR1_W_mag_f; +extern DataAttribute iedModel_WTG_WTUR1_W_q; +extern DataAttribute iedModel_WTG_WTUR1_W_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_actSt; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_actSt_ctlModel; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_oldSt; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_oldSt_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_tmTot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_dly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_mly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_yly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_tot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmTm_rsPer; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_ctlModel; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboTimeout; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboClass; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_operTm; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orCat; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orIdent; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlNum; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_T; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Test; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Check; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_ctlModel; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_t; +extern DataObject iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_stVal; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_q; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_t; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_ctTot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_dly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_mly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_yly; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_tot; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmCt_rsPer; +extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs; + + + +#define IEDMODEL_WTG (&iedModel_WTG) +#define IEDMODEL_WTG_LLN0 (&iedModel_WTG_LLN0) +#define IEDMODEL_WTG_LLN0_Mod (&iedModel_WTG_LLN0_Mod) +#define IEDMODEL_WTG_LLN0_Mod_Oper (&iedModel_WTG_LLN0_Mod_Oper) +#define IEDMODEL_WTG_LLN0_Mod_Oper_ctlVal (&iedModel_WTG_LLN0_Mod_Oper_ctlVal) +#define IEDMODEL_WTG_LLN0_Mod_Oper_operTm (&iedModel_WTG_LLN0_Mod_Oper_operTm) +#define IEDMODEL_WTG_LLN0_Mod_Oper_origin (&iedModel_WTG_LLN0_Mod_Oper_origin) +#define IEDMODEL_WTG_LLN0_Mod_Oper_origin_orCat (&iedModel_WTG_LLN0_Mod_Oper_origin_orCat) +#define IEDMODEL_WTG_LLN0_Mod_Oper_origin_orIdent (&iedModel_WTG_LLN0_Mod_Oper_origin_orIdent) +#define IEDMODEL_WTG_LLN0_Mod_Oper_ctlNum (&iedModel_WTG_LLN0_Mod_Oper_ctlNum) +#define IEDMODEL_WTG_LLN0_Mod_Oper_T (&iedModel_WTG_LLN0_Mod_Oper_T) +#define IEDMODEL_WTG_LLN0_Mod_Oper_Test (&iedModel_WTG_LLN0_Mod_Oper_Test) +#define IEDMODEL_WTG_LLN0_Mod_Oper_Check (&iedModel_WTG_LLN0_Mod_Oper_Check) +#define IEDMODEL_WTG_LLN0_Mod_stVal (&iedModel_WTG_LLN0_Mod_stVal) +#define IEDMODEL_WTG_LLN0_Mod_q (&iedModel_WTG_LLN0_Mod_q) +#define IEDMODEL_WTG_LLN0_Mod_t (&iedModel_WTG_LLN0_Mod_t) +#define IEDMODEL_WTG_LLN0_Mod_ctlModel (&iedModel_WTG_LLN0_Mod_ctlModel) +#define IEDMODEL_WTG_LLN0_Beh (&iedModel_WTG_LLN0_Beh) +#define IEDMODEL_WTG_LLN0_Beh_stVal (&iedModel_WTG_LLN0_Beh_stVal) +#define IEDMODEL_WTG_LLN0_Beh_q (&iedModel_WTG_LLN0_Beh_q) +#define IEDMODEL_WTG_LLN0_Beh_t (&iedModel_WTG_LLN0_Beh_t) +#define IEDMODEL_WTG_LLN0_Health (&iedModel_WTG_LLN0_Health) +#define IEDMODEL_WTG_LLN0_Health_stVal (&iedModel_WTG_LLN0_Health_stVal) +#define IEDMODEL_WTG_LLN0_Health_q (&iedModel_WTG_LLN0_Health_q) +#define IEDMODEL_WTG_LLN0_Health_t (&iedModel_WTG_LLN0_Health_t) +#define IEDMODEL_WTG_LLN0_NamPlt (&iedModel_WTG_LLN0_NamPlt) +#define IEDMODEL_WTG_LLN0_NamPlt_vendor (&iedModel_WTG_LLN0_NamPlt_vendor) +#define IEDMODEL_WTG_LLN0_NamPlt_swRev (&iedModel_WTG_LLN0_NamPlt_swRev) +#define IEDMODEL_WTG_LLN0_NamPlt_configRev (&iedModel_WTG_LLN0_NamPlt_configRev) +#define IEDMODEL_WTG_LPHD1 (&iedModel_WTG_LPHD1) +#define IEDMODEL_WTG_LPHD1_NamPlt (&iedModel_WTG_LPHD1_NamPlt) +#define IEDMODEL_WTG_LPHD1_NamPlt_vendor (&iedModel_WTG_LPHD1_NamPlt_vendor) +#define IEDMODEL_WTG_LPHD1_NamPlt_swRev (&iedModel_WTG_LPHD1_NamPlt_swRev) +#define IEDMODEL_WTG_LPHD1_NamPlt_configRev (&iedModel_WTG_LPHD1_NamPlt_configRev) +#define IEDMODEL_WTG_LPHD1_PhyNam (&iedModel_WTG_LPHD1_PhyNam) +#define IEDMODEL_WTG_LPHD1_PhyNam_vendor (&iedModel_WTG_LPHD1_PhyNam_vendor) +#define IEDMODEL_WTG_LPHD1_PhyNam_hwRev (&iedModel_WTG_LPHD1_PhyNam_hwRev) +#define IEDMODEL_WTG_LPHD1_PhyNam_swRev (&iedModel_WTG_LPHD1_PhyNam_swRev) +#define IEDMODEL_WTG_LPHD1_PhyNam_serNum (&iedModel_WTG_LPHD1_PhyNam_serNum) +#define IEDMODEL_WTG_LPHD1_PhyNam_model (&iedModel_WTG_LPHD1_PhyNam_model) +#define IEDMODEL_WTG_LPHD1_PhyHealth (&iedModel_WTG_LPHD1_PhyHealth) +#define IEDMODEL_WTG_LPHD1_PhyHealth_stVal (&iedModel_WTG_LPHD1_PhyHealth_stVal) +#define IEDMODEL_WTG_LPHD1_PhyHealth_q (&iedModel_WTG_LPHD1_PhyHealth_q) +#define IEDMODEL_WTG_LPHD1_PhyHealth_t (&iedModel_WTG_LPHD1_PhyHealth_t) +#define IEDMODEL_WTG_LPHD1_Proxy (&iedModel_WTG_LPHD1_Proxy) +#define IEDMODEL_WTG_LPHD1_Proxy_stVal (&iedModel_WTG_LPHD1_Proxy_stVal) +#define IEDMODEL_WTG_LPHD1_Proxy_q (&iedModel_WTG_LPHD1_Proxy_q) +#define IEDMODEL_WTG_LPHD1_Proxy_t (&iedModel_WTG_LPHD1_Proxy_t) +#define IEDMODEL_WTG_WTUR1 (&iedModel_WTG_WTUR1) +#define IEDMODEL_WTG_WTUR1_NamPlt (&iedModel_WTG_WTUR1_NamPlt) +#define IEDMODEL_WTG_WTUR1_NamPlt_vendor (&iedModel_WTG_WTUR1_NamPlt_vendor) +#define IEDMODEL_WTG_WTUR1_NamPlt_swRev (&iedModel_WTG_WTUR1_NamPlt_swRev) +#define IEDMODEL_WTG_WTUR1_NamPlt_configRev (&iedModel_WTG_WTUR1_NamPlt_configRev) +#define IEDMODEL_WTG_WTUR1_TotWh (&iedModel_WTG_WTUR1_TotWh) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs (&iedModel_WTG_WTUR1_TotWh_manRs) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper (&iedModel_WTG_WTUR1_TotWh_manRs_Oper) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_ctlVal (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_operTm (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_origin (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_ctlNum (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_T (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_Test (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_Oper_Check (&iedModel_WTG_WTUR1_TotWh_manRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_stVal (&iedModel_WTG_WTUR1_TotWh_manRs_stVal) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_q (&iedModel_WTG_WTUR1_TotWh_manRs_q) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_t (&iedModel_WTG_WTUR1_TotWh_manRs_t) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_ctlModel (&iedModel_WTG_WTUR1_TotWh_manRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_sboTimeout (&iedModel_WTG_WTUR1_TotWh_manRs_sboTimeout) +#define IEDMODEL_WTG_WTUR1_TotWh_manRs_sboClass (&iedModel_WTG_WTUR1_TotWh_manRs_sboClass) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs (&iedModel_WTG_WTUR1_TotWh_hisRs) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_ctlVal (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_operTm (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_origin (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_ctlNum (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_T (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_Test (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_Oper_Check (&iedModel_WTG_WTUR1_TotWh_hisRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_stVal (&iedModel_WTG_WTUR1_TotWh_hisRs_stVal) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_q (&iedModel_WTG_WTUR1_TotWh_hisRs_q) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_t (&iedModel_WTG_WTUR1_TotWh_hisRs_t) +#define IEDMODEL_WTG_WTUR1_TotWh_hisRs_ctlModel (&iedModel_WTG_WTUR1_TotWh_hisRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_TotWh_actCtVal (&iedModel_WTG_WTUR1_TotWh_actCtVal) +#define IEDMODEL_WTG_WTUR1_TotWh_actCtVal_stVal (&iedModel_WTG_WTUR1_TotWh_actCtVal_stVal) +#define IEDMODEL_WTG_WTUR1_TotWh_actCtVal_q (&iedModel_WTG_WTUR1_TotWh_actCtVal_q) +#define IEDMODEL_WTG_WTUR1_TotWh_actCtVal_t (&iedModel_WTG_WTUR1_TotWh_actCtVal_t) +#define IEDMODEL_WTG_WTUR1_TotWh_oldCtVal (&iedModel_WTG_WTUR1_TotWh_oldCtVal) +#define IEDMODEL_WTG_WTUR1_TotWh_oldCtVal_stVal (&iedModel_WTG_WTUR1_TotWh_oldCtVal_stVal) +#define IEDMODEL_WTG_WTUR1_TotWh_oldCtVal_q (&iedModel_WTG_WTUR1_TotWh_oldCtVal_q) +#define IEDMODEL_WTG_WTUR1_TotWh_oldCtVal_t (&iedModel_WTG_WTUR1_TotWh_oldCtVal_t) +#define IEDMODEL_WTG_WTUR1_TotWh_ctTot (&iedModel_WTG_WTUR1_TotWh_ctTot) +#define IEDMODEL_WTG_WTUR1_TotWh_dly (&iedModel_WTG_WTUR1_TotWh_dly) +#define IEDMODEL_WTG_WTUR1_TotWh_mly (&iedModel_WTG_WTUR1_TotWh_mly) +#define IEDMODEL_WTG_WTUR1_TotWh_yly (&iedModel_WTG_WTUR1_TotWh_yly) +#define IEDMODEL_WTG_WTUR1_TotWh_tot (&iedModel_WTG_WTUR1_TotWh_tot) +#define IEDMODEL_WTG_WTUR1_TotWh_rsPer (&iedModel_WTG_WTUR1_TotWh_rsPer) +#define IEDMODEL_WTG_WTUR1_TurSt (&iedModel_WTG_WTUR1_TurSt) +#define IEDMODEL_WTG_WTUR1_TurSt_actSt (&iedModel_WTG_WTUR1_TurSt_actSt) +#define IEDMODEL_WTG_WTUR1_TurSt_actSt_stVal (&iedModel_WTG_WTUR1_TurSt_actSt_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_actSt_q (&iedModel_WTG_WTUR1_TurSt_actSt_q) +#define IEDMODEL_WTG_WTUR1_TurSt_actSt_t (&iedModel_WTG_WTUR1_TurSt_actSt_t) +#define IEDMODEL_WTG_WTUR1_TurSt_oldSt (&iedModel_WTG_WTUR1_TurSt_oldSt) +#define IEDMODEL_WTG_WTUR1_TurSt_oldSt_stVal (&iedModel_WTG_WTUR1_TurSt_oldSt_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_oldSt_q (&iedModel_WTG_WTUR1_TurSt_oldSt_q) +#define IEDMODEL_WTG_WTUR1_TurSt_oldSt_t (&iedModel_WTG_WTUR1_TurSt_oldSt_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm (&iedModel_WTG_WTUR1_TurSt_stTm) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs (&iedModel_WTG_WTUR1_TurSt_stTm_manRs) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlVal (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_operTm (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlNum (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_T (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_Test (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_Oper_Check (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_stVal (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_q (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_t (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_ctlModel (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_sboTimeout (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboTimeout) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_manRs_sboClass (&iedModel_WTG_WTUR1_TurSt_stTm_manRs_sboClass) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlVal (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_operTm (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlNum (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_T (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Test (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Check (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_stVal (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_q (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_t (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_hisRs_ctlModel (&iedModel_WTG_WTUR1_TurSt_stTm_hisRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_actTmVal (&iedModel_WTG_WTUR1_TurSt_stTm_actTmVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_actTmVal_stVal (&iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_actTmVal_q (&iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_actTmVal_t (&iedModel_WTG_WTUR1_TurSt_stTm_actTmVal_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_oldTmVal (&iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_oldTmVal_stVal (&iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_oldTmVal_q (&iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_oldTmVal_t (&iedModel_WTG_WTUR1_TurSt_stTm_oldTmVal_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_tmTot (&iedModel_WTG_WTUR1_TurSt_stTm_tmTot) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_dly (&iedModel_WTG_WTUR1_TurSt_stTm_dly) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_mly (&iedModel_WTG_WTUR1_TurSt_stTm_mly) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_yly (&iedModel_WTG_WTUR1_TurSt_stTm_yly) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_tot (&iedModel_WTG_WTUR1_TurSt_stTm_tot) +#define IEDMODEL_WTG_WTUR1_TurSt_stTm_rsPer (&iedModel_WTG_WTUR1_TurSt_stTm_rsPer) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt (&iedModel_WTG_WTUR1_TurSt_stCt) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs (&iedModel_WTG_WTUR1_TurSt_stCt_manRs) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlVal (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_operTm (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlNum (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_T (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_Test (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_Oper_Check (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_stVal (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_q (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_t (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_ctlModel (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_sboTimeout (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboTimeout) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_manRs_sboClass (&iedModel_WTG_WTUR1_TurSt_stCt_manRs_sboClass) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlVal (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_operTm (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlNum (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_T (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Test (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Check (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_stVal (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_q (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_t (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_hisRs_ctlModel (&iedModel_WTG_WTUR1_TurSt_stCt_hisRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_actCtVal (&iedModel_WTG_WTUR1_TurSt_stCt_actCtVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_actCtVal_stVal (&iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_actCtVal_q (&iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_actCtVal_t (&iedModel_WTG_WTUR1_TurSt_stCt_actCtVal_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_oldCtVal (&iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_oldCtVal_stVal (&iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_stVal) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_oldCtVal_q (&iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_q) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_oldCtVal_t (&iedModel_WTG_WTUR1_TurSt_stCt_oldCtVal_t) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_ctTot (&iedModel_WTG_WTUR1_TurSt_stCt_ctTot) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_dly (&iedModel_WTG_WTUR1_TurSt_stCt_dly) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_mly (&iedModel_WTG_WTUR1_TurSt_stCt_mly) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_yly (&iedModel_WTG_WTUR1_TurSt_stCt_yly) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_tot (&iedModel_WTG_WTUR1_TurSt_stCt_tot) +#define IEDMODEL_WTG_WTUR1_TurSt_stCt_rsPer (&iedModel_WTG_WTUR1_TurSt_stCt_rsPer) +#define IEDMODEL_WTG_WTUR1_TurSt_preTmms (&iedModel_WTG_WTUR1_TurSt_preTmms) +#define IEDMODEL_WTG_WTUR1_TurSt_pstTmms (&iedModel_WTG_WTUR1_TurSt_pstTmms) +#define IEDMODEL_WTG_WTUR1_TurSt_smpTmms (&iedModel_WTG_WTUR1_TurSt_smpTmms) +#define IEDMODEL_WTG_WTUR1_TurSt_datSetMx (&iedModel_WTG_WTUR1_TurSt_datSetMx) +#define IEDMODEL_WTG_WTUR1_W (&iedModel_WTG_WTUR1_W) +#define IEDMODEL_WTG_WTUR1_W_instMag (&iedModel_WTG_WTUR1_W_instMag) +#define IEDMODEL_WTG_WTUR1_W_instMag_i (&iedModel_WTG_WTUR1_W_instMag_i) +#define IEDMODEL_WTG_WTUR1_W_instMag_f (&iedModel_WTG_WTUR1_W_instMag_f) +#define IEDMODEL_WTG_WTUR1_W_mag (&iedModel_WTG_WTUR1_W_mag) +#define IEDMODEL_WTG_WTUR1_W_mag_i (&iedModel_WTG_WTUR1_W_mag_i) +#define IEDMODEL_WTG_WTUR1_W_mag_f (&iedModel_WTG_WTUR1_W_mag_f) +#define IEDMODEL_WTG_WTUR1_W_q (&iedModel_WTG_WTUR1_W_q) +#define IEDMODEL_WTG_WTUR1_W_t (&iedModel_WTG_WTUR1_W_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp (&iedModel_WTG_WTUR1_SetTurOp) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt (&iedModel_WTG_WTUR1_SetTurOp_actSt) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_ctlVal (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_operTm (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_origin (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orCat (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orIdent (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_ctlNum (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_T (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_T) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_Test (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Test) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_Oper_Check (&iedModel_WTG_WTUR1_SetTurOp_actSt_Oper_Check) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_stVal (&iedModel_WTG_WTUR1_SetTurOp_actSt_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_q (&iedModel_WTG_WTUR1_SetTurOp_actSt_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_t (&iedModel_WTG_WTUR1_SetTurOp_actSt_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_actSt_ctlModel (&iedModel_WTG_WTUR1_SetTurOp_actSt_ctlModel) +#define IEDMODEL_WTG_WTUR1_SetTurOp_oldSt (&iedModel_WTG_WTUR1_SetTurOp_oldSt) +#define IEDMODEL_WTG_WTUR1_SetTurOp_oldSt_stVal (&iedModel_WTG_WTUR1_SetTurOp_oldSt_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_oldSt_q (&iedModel_WTG_WTUR1_SetTurOp_oldSt_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_oldSt_t (&iedModel_WTG_WTUR1_SetTurOp_oldSt_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm (&iedModel_WTG_WTUR1_SetTurOp_cmTm) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_operTm (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlNum (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_T (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Test (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Check (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_q (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_t (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_ctlModel (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_sboTimeout (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboTimeout) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_manRs_sboClass (&iedModel_WTG_WTUR1_SetTurOp_cmTm_manRs_sboClass) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_operTm (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlNum (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_T (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Test (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Check (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_q (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_t (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_hisRs_ctlModel (&iedModel_WTG_WTUR1_SetTurOp_cmTm_hisRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_actTmVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_actTmVal_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_actTmVal_q (&iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_actTmVal_t (&iedModel_WTG_WTUR1_SetTurOp_cmTm_actTmVal_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_oldTmVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_q (&iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_t (&iedModel_WTG_WTUR1_SetTurOp_cmTm_oldTmVal_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_tmTot (&iedModel_WTG_WTUR1_SetTurOp_cmTm_tmTot) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_dly (&iedModel_WTG_WTUR1_SetTurOp_cmTm_dly) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_mly (&iedModel_WTG_WTUR1_SetTurOp_cmTm_mly) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_yly (&iedModel_WTG_WTUR1_SetTurOp_cmTm_yly) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_tot (&iedModel_WTG_WTUR1_SetTurOp_cmTm_tot) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmTm_rsPer (&iedModel_WTG_WTUR1_SetTurOp_cmTm_rsPer) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt (&iedModel_WTG_WTUR1_SetTurOp_cmCt) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_operTm (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlNum (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_T (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Test (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Check (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_q (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_t (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_ctlModel (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_sboTimeout (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboTimeout) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_manRs_sboClass (&iedModel_WTG_WTUR1_SetTurOp_cmCt_manRs_sboClass) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_operTm (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_operTm) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orCat (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orCat) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orIdent (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_origin_orIdent) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlNum (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_ctlNum) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_T (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_T) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Test (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Test) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Check (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_Oper_Check) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_q (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_t (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_hisRs_ctlModel (&iedModel_WTG_WTUR1_SetTurOp_cmCt_hisRs_ctlModel) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_actCtVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_actCtVal_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_actCtVal_q (&iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_actCtVal_t (&iedModel_WTG_WTUR1_SetTurOp_cmCt_actCtVal_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_oldCtVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_stVal (&iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_stVal) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_q (&iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_q) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_t (&iedModel_WTG_WTUR1_SetTurOp_cmCt_oldCtVal_t) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_ctTot (&iedModel_WTG_WTUR1_SetTurOp_cmCt_ctTot) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_dly (&iedModel_WTG_WTUR1_SetTurOp_cmCt_dly) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_mly (&iedModel_WTG_WTUR1_SetTurOp_cmCt_mly) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_yly (&iedModel_WTG_WTUR1_SetTurOp_cmCt_yly) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_tot (&iedModel_WTG_WTUR1_SetTurOp_cmCt_tot) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmCt_rsPer (&iedModel_WTG_WTUR1_SetTurOp_cmCt_rsPer) +#define IEDMODEL_WTG_WTUR1_SetTurOp_cmAcs (&iedModel_WTG_WTUR1_SetTurOp_cmAcs) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_61400_25/wtur.icd b/examples/server_example_61400_25/wtur.icd new file mode 100644 index 0000000..b7322a2 --- /dev/null +++ b/examples/server_example_61400_25/wtur.icd @@ -0,0 +1,352 @@ + + + + + +
+ + + +
+ + + +
+

1 3 9999 33

+

33

+

00 00 00 01

+

00 01

+

00 01

+

102

+

10.0.2.2

+

255.255.255.0

+

10.0.2.2

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + operate-once + operate-many + + + pulse + persistent + + + dly + wly + mly + yly + manual + + + normal + high + low + high-high + low-low + + + none + m + kg + s + A + K + mol + cd + deg + rad + sr + Gy + q + °C + Sv + F + C + S + H + V + ohm + J + N + Hz + lx + Lm + Wb + T + W + Pa + m² + m³ + m/s + m/s² + m³/s + m/m³ + M + kg/m³ + m²/s + W/m K + J/K + ppm + 1/s + rad/s + VA + Watts + VAr + theta + cos(theta) + Vs + V² + As + A² + A²t + VAh + Wh + VArh + V/Hz + + + Yocto + Zepto + Atto + Femto + Pico + Nano + Micro + Milli + Centi + Deci + zeroNoValue + Deca + Hecto + Kilo + Mega + Giga + Tera + Petra + Exa + Zetta + Yotta + + +
diff --git a/examples/server_example_complex_array/CMakeLists.txt b/examples/server_example_complex_array/CMakeLists.txt new file mode 100644 index 0000000..32a1f96 --- /dev/null +++ b/examples/server_example_complex_array/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example_ca_SRCS + server_example_ca.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example_ca_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_ca + ${server_example_ca_SRCS} +) + +target_link_libraries(server_example_ca + iec61850 +) diff --git a/examples/server_example_complex_array/Makefile b/examples/server_example_complex_array/Makefile new file mode 100644 index 0000000..124da8d --- /dev/null +++ b/examples/server_example_complex_array/Makefile @@ -0,0 +1,26 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_ca +PROJECT_SOURCES = server_example_ca.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = mhai_array.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example_complex_array/mhai_array.icd b/examples/server_example_complex_array/mhai_array.icd new file mode 100644 index 0000000..e6f09be --- /dev/null +++ b/examples/server_example_complex_array/mhai_array.icd @@ -0,0 +1,294 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + 16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + operate-once + operate-many + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example_complex_array/server_example_ca.c b/examples/server_example_complex_array/server_example_ca.c new file mode 100644 index 0000000..23d729a --- /dev/null +++ b/examples/server_example_complex_array/server_example_ca.c @@ -0,0 +1,129 @@ +/* + * server_example_ca.c + * + * This example shows how to handle complex arrays (arrays of data objects). + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + +#include "static_model.h" + +#include + +/* import IEC 61850 device model created from ICD-File */ +extern IedModel iedModel; + +static int running = 0; + +static void +sigint_handler(int signalId) +{ + running = 0; +} + +static void +updateCMVArrayElement(MmsValue* cval, int index, float magnitude, float angle, Quality quality, Timestamp timestamp) +{ + MmsValue* cmv = MmsValue_getElement(cval, index); + + MmsValue* cValElement = MmsValue_getElement(cmv, 0); + + assert(MmsValue_getArraySize(cValElement) == 2); + + MmsValue* cValElement_mag_f = MmsValue_getElement(MmsValue_getElement(cValElement, 0), 0); + + MmsValue* cValElement_ang_f = MmsValue_getElement(MmsValue_getElement(cValElement, 1), 0); + + MmsValue_setFloat(cValElement_mag_f, magnitude); + MmsValue_setFloat(cValElement_ang_f, angle); + + MmsValue* q = MmsValue_getElement(cmv, 1); + MmsValue_setBitStringFromInteger(q, (int) quality); + + MmsValue* t = MmsValue_getElement(cmv, 2); + MmsValue_setUtcTimeByBuffer(t, timestamp.val); +} + +int main(int argc, char** argv) { + + int tcpPort = 102; + + if (argc > 1) { + tcpPort = atoi(argv[1]); + } + + IedServer iedServer = IedServer_create(&iedModel); + + /* Get access to the MHAI1.HA data object handle - for static and dynamic model*/ + DataObject* mhai1_ha_phsAHar = (DataObject*) + IedModel_getModelNodeByObjectReference(&iedModel, "testComplexArray/MHAI1.HA.phsAHar"); + + /* alternative: only for static model */ +// DataObject* mhai1_ha_phsAHar = IEDMODEL_ComplexArray_MHAI1_HA_phsAHar; + + assert(mhai1_ha_phsAHar != NULL); + + /* Get access to the corresponding MMS value data structure - the MX(FC) part of the data object */ + MmsValue* mhai1_ha_phsAHar_mx = IedServer_getFunctionalConstrainedData(iedServer, mhai1_ha_phsAHar, IEC61850_FC_MX); + + + /* assuming the array has 16 elements */ + float mag = 200.f; + float angle = 0.01f; + + Quality quality = QUALITY_VALIDITY_GOOD; + Timestamp timestamp; + + Timestamp_setTimeInMilliseconds(×tamp, Hal_getTimeInMs()); + + int i; + for (i = 0; i < 16; i++) { + updateCMVArrayElement(mhai1_ha_phsAHar_mx, i, mag, angle, quality, timestamp); + mag += 1.f; + angle += 0.01f; + } + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, tcpPort); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + int counter = 0; + + while (running) { + Thread_sleep(1000); + + Timestamp_setTimeInMilliseconds(×tamp, Hal_getTimeInMs()); + + IedServer_lockDataModel(iedServer); + for (i = 0; i < 16; i++) { + updateCMVArrayElement(mhai1_ha_phsAHar_mx, i, mag, angle, quality, timestamp); + } + IedServer_unlockDataModel(iedServer); + + if (counter == 10) { + /* Now a problem occurs - measurements are invalid */ + quality = QUALITY_VALIDITY_INVALID | QUALITY_DETAIL_FAILURE; + } + + counter++; + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example_complex_array/static_model.c b/examples/server_example_complex_array/static_model.c new file mode 100644 index 0000000..458b189 --- /dev/null +++ b/examples/server_example_complex_array/static_model.c @@ -0,0 +1,610 @@ +/* + * static_model.c + * + * automatically generated from mhai_array.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_ComplexArray; +extern LogicalNode iedModel_ComplexArray_LLN0; +extern DataObject iedModel_ComplexArray_LLN0_Mod; +extern DataAttribute iedModel_ComplexArray_LLN0_Mod_q; +extern DataAttribute iedModel_ComplexArray_LLN0_Mod_t; +extern DataAttribute iedModel_ComplexArray_LLN0_Mod_ctlModel; +extern DataObject iedModel_ComplexArray_LLN0_Beh; +extern DataAttribute iedModel_ComplexArray_LLN0_Beh_stVal; +extern DataAttribute iedModel_ComplexArray_LLN0_Beh_q; +extern DataAttribute iedModel_ComplexArray_LLN0_Beh_t; +extern DataObject iedModel_ComplexArray_LLN0_Health; +extern DataAttribute iedModel_ComplexArray_LLN0_Health_stVal; +extern DataAttribute iedModel_ComplexArray_LLN0_Health_q; +extern DataAttribute iedModel_ComplexArray_LLN0_Health_t; +extern DataObject iedModel_ComplexArray_LLN0_NamPlt; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_d; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_ComplexArray_LPHD1; +extern DataObject iedModel_ComplexArray_LPHD1_PhyNam; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyNam_vendor; +extern DataObject iedModel_ComplexArray_LPHD1_PhyHealth; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_t; +extern DataObject iedModel_ComplexArray_LPHD1_Proxy; +extern DataAttribute iedModel_ComplexArray_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_ComplexArray_LPHD1_Proxy_q; +extern DataAttribute iedModel_ComplexArray_LPHD1_Proxy_t; +extern LogicalNode iedModel_ComplexArray_MHAI1; +extern DataObject iedModel_ComplexArray_MHAI1_HA; +extern DataObject iedModel_ComplexArray_MHAI1_HA_phsAHar; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag_f; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang_f; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_q; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_t; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_numHar; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_numCyc; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_evalTm; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency; + + + +LogicalDevice iedModel_ComplexArray = { + LogicalDeviceModelType, + "ComplexArray", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_ComplexArray_LLN0 +}; + +LogicalNode iedModel_ComplexArray_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_ComplexArray, + (ModelNode*) &iedModel_ComplexArray_LPHD1, + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod, +}; + +DataObject iedModel_ComplexArray_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_ComplexArray_LLN0, + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh, + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_ComplexArray_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod, + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod, + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_ComplexArray_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_ComplexArray_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_ComplexArray_LLN0, + (ModelNode*) &iedModel_ComplexArray_LLN0_Health, + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_ComplexArray_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh, + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh, + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_ComplexArray_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_ComplexArray_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_ComplexArray_LLN0, + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt, + (ModelNode*) &iedModel_ComplexArray_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_ComplexArray_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_ComplexArray_LLN0_Health, + (ModelNode*) &iedModel_ComplexArray_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_ComplexArray_LLN0_Health, + (ModelNode*) &iedModel_ComplexArray_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_ComplexArray_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_ComplexArray_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_ComplexArray_LLN0, + NULL, + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_ComplexArray_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt, + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt, + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt, + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt, + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_ComplexArray_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_ComplexArray_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_ComplexArray, + (ModelNode*) &iedModel_ComplexArray_MHAI1, + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyNam, +}; + +DataObject iedModel_ComplexArray_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_ComplexArray_LPHD1, + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth, + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_ComplexArray_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_ComplexArray_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_ComplexArray_LPHD1, + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy, + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth, + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth, + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_ComplexArray_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_ComplexArray_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_ComplexArray_LPHD1, + NULL, + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_ComplexArray_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy, + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy, + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_ComplexArray_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_ComplexArray_MHAI1 = { + LogicalNodeModelType, + "MHAI1", + (ModelNode*) &iedModel_ComplexArray, + NULL, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA, +}; + +DataObject iedModel_ComplexArray_MHAI1_HA = { + DataObjectModelType, + "HA", + (ModelNode*) &iedModel_ComplexArray_MHAI1, + NULL, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar, + 0 +}; + +DataObject iedModel_ComplexArray_MHAI1_HA_phsAHar = { + DataObjectModelType, + "phsAHar", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_numHar, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal, + 16 +}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal = { + DataAttributeModelType, + "cVal", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_q, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED + TRG_OPT_DATA_UPDATE, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED + TRG_OPT_DATA_UPDATE, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED + TRG_OPT_DATA_UPDATE, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang = { + DataAttributeModelType, + "ang", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal, + NULL, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED + TRG_OPT_DATA_UPDATE, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED + TRG_OPT_DATA_UPDATE, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_phsAHar, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_numHar = { + DataAttributeModelType, + "numHar", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_numCyc, + NULL, + 0, + IEC61850_FC_CF, + INT16U, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_numCyc = { + DataAttributeModelType, + "numCyc", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_evalTm, + NULL, + 0, + IEC61850_FC_CF, + INT16U, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_evalTm = { + DataAttributeModelType, + "evalTm", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA, + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA_frequency, + NULL, + 0, + IEC61850_FC_CF, + INT16U, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency = { + DataAttributeModelType, + "frequency", + (ModelNode*) &iedModel_ComplexArray_MHAI1_HA, + NULL, + NULL, + 0, + IEC61850_FC_CF, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + + + + + + +IedModel iedModel = { + "test", + &iedModel_ComplexArray, + NULL, + NULL, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_ComplexArray_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_ComplexArray_MHAI1_HA_numHar.mmsValue = MmsValue_newUnsignedFromUint32(16); +} diff --git a/examples/server_example_complex_array/static_model.h b/examples/server_example_complex_array/static_model.h new file mode 100644 index 0000000..0999d58 --- /dev/null +++ b/examples/server_example_complex_array/static_model.h @@ -0,0 +1,109 @@ +/* + * static_model.h + * + * automatically generated from mhai_array.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_ComplexArray; +extern LogicalNode iedModel_ComplexArray_LLN0; +extern DataObject iedModel_ComplexArray_LLN0_Mod; +extern DataAttribute iedModel_ComplexArray_LLN0_Mod_q; +extern DataAttribute iedModel_ComplexArray_LLN0_Mod_t; +extern DataAttribute iedModel_ComplexArray_LLN0_Mod_ctlModel; +extern DataObject iedModel_ComplexArray_LLN0_Beh; +extern DataAttribute iedModel_ComplexArray_LLN0_Beh_stVal; +extern DataAttribute iedModel_ComplexArray_LLN0_Beh_q; +extern DataAttribute iedModel_ComplexArray_LLN0_Beh_t; +extern DataObject iedModel_ComplexArray_LLN0_Health; +extern DataAttribute iedModel_ComplexArray_LLN0_Health_stVal; +extern DataAttribute iedModel_ComplexArray_LLN0_Health_q; +extern DataAttribute iedModel_ComplexArray_LLN0_Health_t; +extern DataObject iedModel_ComplexArray_LLN0_NamPlt; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_d; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_ComplexArray_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_ComplexArray_LPHD1; +extern DataObject iedModel_ComplexArray_LPHD1_PhyNam; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyNam_vendor; +extern DataObject iedModel_ComplexArray_LPHD1_PhyHealth; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_ComplexArray_LPHD1_PhyHealth_t; +extern DataObject iedModel_ComplexArray_LPHD1_Proxy; +extern DataAttribute iedModel_ComplexArray_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_ComplexArray_LPHD1_Proxy_q; +extern DataAttribute iedModel_ComplexArray_LPHD1_Proxy_t; +extern LogicalNode iedModel_ComplexArray_MHAI1; +extern DataObject iedModel_ComplexArray_MHAI1_HA; +extern DataObject iedModel_ComplexArray_MHAI1_HA_phsAHar; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag_f; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang_f; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_q; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_phsAHar_t; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_numHar; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_numCyc; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_evalTm; +extern DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency; + + + +#define IEDMODEL_ComplexArray (&iedModel_ComplexArray) +#define IEDMODEL_ComplexArray_LLN0 (&iedModel_ComplexArray_LLN0) +#define IEDMODEL_ComplexArray_LLN0_Mod (&iedModel_ComplexArray_LLN0_Mod) +#define IEDMODEL_ComplexArray_LLN0_Mod_q (&iedModel_ComplexArray_LLN0_Mod_q) +#define IEDMODEL_ComplexArray_LLN0_Mod_t (&iedModel_ComplexArray_LLN0_Mod_t) +#define IEDMODEL_ComplexArray_LLN0_Mod_ctlModel (&iedModel_ComplexArray_LLN0_Mod_ctlModel) +#define IEDMODEL_ComplexArray_LLN0_Beh (&iedModel_ComplexArray_LLN0_Beh) +#define IEDMODEL_ComplexArray_LLN0_Beh_stVal (&iedModel_ComplexArray_LLN0_Beh_stVal) +#define IEDMODEL_ComplexArray_LLN0_Beh_q (&iedModel_ComplexArray_LLN0_Beh_q) +#define IEDMODEL_ComplexArray_LLN0_Beh_t (&iedModel_ComplexArray_LLN0_Beh_t) +#define IEDMODEL_ComplexArray_LLN0_Health (&iedModel_ComplexArray_LLN0_Health) +#define IEDMODEL_ComplexArray_LLN0_Health_stVal (&iedModel_ComplexArray_LLN0_Health_stVal) +#define IEDMODEL_ComplexArray_LLN0_Health_q (&iedModel_ComplexArray_LLN0_Health_q) +#define IEDMODEL_ComplexArray_LLN0_Health_t (&iedModel_ComplexArray_LLN0_Health_t) +#define IEDMODEL_ComplexArray_LLN0_NamPlt (&iedModel_ComplexArray_LLN0_NamPlt) +#define IEDMODEL_ComplexArray_LLN0_NamPlt_vendor (&iedModel_ComplexArray_LLN0_NamPlt_vendor) +#define IEDMODEL_ComplexArray_LLN0_NamPlt_swRev (&iedModel_ComplexArray_LLN0_NamPlt_swRev) +#define IEDMODEL_ComplexArray_LLN0_NamPlt_d (&iedModel_ComplexArray_LLN0_NamPlt_d) +#define IEDMODEL_ComplexArray_LLN0_NamPlt_configRev (&iedModel_ComplexArray_LLN0_NamPlt_configRev) +#define IEDMODEL_ComplexArray_LLN0_NamPlt_ldNs (&iedModel_ComplexArray_LLN0_NamPlt_ldNs) +#define IEDMODEL_ComplexArray_LPHD1 (&iedModel_ComplexArray_LPHD1) +#define IEDMODEL_ComplexArray_LPHD1_PhyNam (&iedModel_ComplexArray_LPHD1_PhyNam) +#define IEDMODEL_ComplexArray_LPHD1_PhyNam_vendor (&iedModel_ComplexArray_LPHD1_PhyNam_vendor) +#define IEDMODEL_ComplexArray_LPHD1_PhyHealth (&iedModel_ComplexArray_LPHD1_PhyHealth) +#define IEDMODEL_ComplexArray_LPHD1_PhyHealth_stVal (&iedModel_ComplexArray_LPHD1_PhyHealth_stVal) +#define IEDMODEL_ComplexArray_LPHD1_PhyHealth_q (&iedModel_ComplexArray_LPHD1_PhyHealth_q) +#define IEDMODEL_ComplexArray_LPHD1_PhyHealth_t (&iedModel_ComplexArray_LPHD1_PhyHealth_t) +#define IEDMODEL_ComplexArray_LPHD1_Proxy (&iedModel_ComplexArray_LPHD1_Proxy) +#define IEDMODEL_ComplexArray_LPHD1_Proxy_stVal (&iedModel_ComplexArray_LPHD1_Proxy_stVal) +#define IEDMODEL_ComplexArray_LPHD1_Proxy_q (&iedModel_ComplexArray_LPHD1_Proxy_q) +#define IEDMODEL_ComplexArray_LPHD1_Proxy_t (&iedModel_ComplexArray_LPHD1_Proxy_t) +#define IEDMODEL_ComplexArray_MHAI1 (&iedModel_ComplexArray_MHAI1) +#define IEDMODEL_ComplexArray_MHAI1_HA (&iedModel_ComplexArray_MHAI1_HA) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar (&iedModel_ComplexArray_MHAI1_HA_phsAHar) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_cVal (&iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_cVal_mag (&iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_cVal_mag_f (&iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_mag_f) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_cVal_ang (&iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_cVal_ang_f (&iedModel_ComplexArray_MHAI1_HA_phsAHar_cVal_ang_f) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_q (&iedModel_ComplexArray_MHAI1_HA_phsAHar_q) +#define IEDMODEL_ComplexArray_MHAI1_HA_phsAHar_t (&iedModel_ComplexArray_MHAI1_HA_phsAHar_t) +#define IEDMODEL_ComplexArray_MHAI1_HA_numHar (&iedModel_ComplexArray_MHAI1_HA_numHar) +#define IEDMODEL_ComplexArray_MHAI1_HA_numCyc (&iedModel_ComplexArray_MHAI1_HA_numCyc) +#define IEDMODEL_ComplexArray_MHAI1_HA_evalTm (&iedModel_ComplexArray_MHAI1_HA_evalTm) +#define IEDMODEL_ComplexArray_MHAI1_HA_frequency (&iedModel_ComplexArray_MHAI1_HA_frequency) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_config_file/CMakeLists.txt b/examples/server_example_config_file/CMakeLists.txt new file mode 100644 index 0000000..e56ea25 --- /dev/null +++ b/examples/server_example_config_file/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories( + . +) + +set(server_example_config_file_SRCS + server_example_config_file.c +) + +IF(WIN32) +set_source_files_properties(${server_example_config_file_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_config_file + ${server_example_config_file_SRCS} +) + +target_link_libraries(server_example_config_file + iec61850 +) diff --git a/examples/server_example_config_file/Makefile b/examples/server_example_config_file/Makefile new file mode 100644 index 0000000..687747f --- /dev/null +++ b/examples/server_example_config_file/Makefile @@ -0,0 +1,24 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_config_file +PROJECT_SOURCES = server_example_config_file.c + +PROJECT_ICD_FILE = simpleIO_direct_control_goose.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genconfig.jar $(PROJECT_ICD_FILE) > vmd-filestore/model.cfg + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example_config_file/server_example_config_file.c b/examples/server_example_config_file/server_example_config_file.c new file mode 100644 index 0000000..924707b --- /dev/null +++ b/examples/server_example_config_file/server_example_config_file.c @@ -0,0 +1,139 @@ +/* + * server_example_config_file.c + * + * This example shows how to use dynamic server data model with a configuration file. + * + * - How to open and parse the model configuration file + * - How to access data attributes by object reference strings + * - How to access data attributes by short addresses + * + * Note: If building with cmake the vmd-filestore folder containing the configuration file + * (model.cfg) has to be copied to the folder where the example is executed! + * The configuration file can be created from the SCL(ICD) file with the Java tool genconfig.jar + * that is included in the source distribution of libiec61580. + * + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + +#include "hal_filesystem.h" +#include "iec61850_config_file_parser.h" + +static int running = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + +int +main(int argc, char** argv) +{ + int tcpPort = 102; + + if (argc > 1) { + tcpPort = atoi(argv[1]); + } + + /* open configuration file */ + FileHandle configFile = FileSystem_openFile("model.cfg", false); + + if (configFile == NULL) { + printf("Error opening config file!\n"); + return 1; + } + + /* parse the configuration file and create the data model */ + IedModel* model = ConfigFileParser_createModelFromConfigFile(configFile); + + FileSystem_closeFile(configFile); + + if (model == NULL) { + printf("Error parsing config file!\n"); + return 1; + } + + IedServer iedServer = IedServer_create(model); + + /* Access to data attributes by object reference */ + + DataAttribute* anIn1_mag_f = (DataAttribute*) + IedModel_getModelNodeByObjectReference(model, "simpleIOGenericIO/GGIO1.AnIn1.mag.f"); + + DataAttribute* anIn1_t = (DataAttribute*) + IedModel_getModelNodeByObjectReference(model, "simpleIOGenericIO/GGIO1.AnIn1.t"); + + if (anIn1_mag_f == NULL) + printf("Error getting AnIn1.mag.f data attribute!\n"); + + /* Access to data attributes by short address */ + DataAttribute* anIn2_mag = (DataAttribute*) + IedModel_getModelNodeByShortAddress(model, 101); + + DataAttribute* anIn2_t = (DataAttribute*) + IedModel_getModelNodeByShortAddress(model, 102); + + DataAttribute* anIn2_mag_f = NULL; + + if (anIn2_mag == NULL) + printf("Error getting AnIn2.mag data attribute!\n"); + else + anIn2_mag_f = (DataAttribute*) ModelNode_getChild((ModelNode*) anIn2_mag, "f"); + + IedServer_start(iedServer, tcpPort); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float val = 0.f; + + MmsValue* floatValue = MmsValue_newFloat(val); + + while (running) { + + if (anIn1_mag_f != NULL) { + MmsValue_setFloat(floatValue, val); + + IedServer_lockDataModel(iedServer); + + MmsValue_setUtcTimeMs(anIn1_t->mmsValue, Hal_getTimeInMs()); + IedServer_updateAttributeValue(iedServer, anIn1_mag_f, floatValue); + + IedServer_unlockDataModel(iedServer); + } + + if (anIn2_mag_f != NULL) { + MmsValue_setFloat(floatValue, 0.f - val); + + IedServer_lockDataModel(iedServer); + + MmsValue_setUtcTimeMs(anIn2_t->mmsValue, Hal_getTimeInMs()); + IedServer_updateAttributeValue(iedServer, anIn2_mag_f, floatValue); + + IedServer_unlockDataModel(iedServer); + } + + val += 0.1f; + + Thread_sleep(100); + } + + MmsValue_delete(floatValue); + + IedServer_stop(iedServer); + + IedServer_destroy(iedServer); + + IedModel_destroy(model); +} /* main() */ diff --git a/examples/server_example_config_file/simpleIO_direct_control_goose.icd b/examples/server_example_config_file/simpleIO_direct_control_goose.icd new file mode 100644 index 0000000..e66f9a9 --- /dev/null +++ b/examples/server_example_config_file/simpleIO_direct_control_goose.icd @@ -0,0 +1,247 @@ + + +
+
+ + + Station bus + + +
+

111

+

4

+

01-0c-cd-01-00-01

+

1000

+
+
+ +
+

111

+

4

+

01-0c-cd-01-00-01

+

1000

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example_config_file/vmd-filestore/model.cfg b/examples/server_example_config_file/vmd-filestore/model.cfg new file mode 100644 index 0000000..bcd616e --- /dev/null +++ b/examples/server_example_config_file/vmd-filestore/model.cfg @@ -0,0 +1,206 @@ +Dynamic model generator +parse data type templates ... +parse IED section ... +parse communication section ... +Found connectedAP accessPoint1 for IED simpleIO +MODEL(simpleIO){ +LD(GenericIO){ +LN(LLN0){ +DO(Mod 0){ +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +DA(ctlModel 0 12 4 0 0)=0; +} +DO(Beh 0){ +DA(stVal 0 3 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(Health 0){ +DA(stVal 0 3 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(NamPlt 0){ +DA(vendor 0 20 5 0 0); +DA(swRev 0 20 5 0 0); +DA(d 0 20 5 0 0); +DA(configRev 0 20 5 0 0); +DA(ldNs 0 20 11 0 0); +} +DS(Events){ +DE(GGIO1$ST$SPCSO1$stVal); +DE(GGIO1$ST$SPCSO2$stVal); +DE(GGIO1$ST$SPCSO3$stVal); +DE(GGIO1$ST$SPCSO4$stVal); +} +DS(AnalogValues){ +DE(GGIO1$MX$AnIn1); +DE(GGIO1$MX$AnIn2); +DE(GGIO1$MX$AnIn3); +DE(GGIO1$MX$AnIn4); +} +RC(EventsRCB01 Events 0 Events 1 8 111 50 1000); +RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 8 111 50 1000); +GC(gcbEvents events Events 2 0 -1 -1 ){ +PA(4 111 1000 010ccd010001); +} +GC(gcbAnalogValues analog AnalogValues 2 0 -1 -1 ){ +PA(4 111 1000 010ccd010001); +} +} +LN(LPHD1){ +DO(PhyNam 0){ +DA(vendor 0 20 5 0 0); +} +DO(PhyHealth 0){ +DA(stVal 0 3 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(Proxy 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +} +LN(GGIO1){ +DO(Mod 0){ +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +DA(ctlModel 0 12 4 0 0)=0; +} +DO(Beh 0){ +DA(stVal 0 3 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(Health 0){ +DA(stVal 0 3 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(NamPlt 0){ +DA(vendor 0 20 5 0 0); +DA(swRev 0 20 5 0 0); +DA(d 0 20 5 0 0); +} +DO(AnIn1 0){ +DA(mag 0 27 1 1 0){ +DA(f 0 10 1 1 0); +} +DA(q 0 23 1 2 0); +DA(t 0 22 1 0 0); +} +DO(AnIn2 0){ +DA(mag 0 27 1 1 101){ +DA(f 0 10 1 1 0); +} +DA(q 0 23 1 2 0); +DA(t 0 22 1 0 102); +} +DO(AnIn3 0){ +DA(mag 0 27 1 1 0){ +DA(f 0 10 1 1 0); +} +DA(q 0 23 1 2 0); +DA(t 0 22 1 0 0); +} +DO(AnIn4 0){ +DA(mag 0 27 1 1 0){ +DA(f 0 10 1 1 0); +} +DA(q 0 23 1 2 0); +DA(t 0 22 1 0 0); +} +DO(SPCSO1 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(Oper 0 27 12 0 0){ +DA(ctlVal 0 0 12 0 0); +DA(origin 0 27 12 0 0){ +DA(orCat 0 12 12 0 0); +DA(orIdent 0 13 12 0 0); +} +DA(ctlNum 0 6 12 0 0); +DA(T 0 22 12 0 0); +DA(Test 0 0 12 0 0); +DA(Check 0 24 12 0 0); +} +DA(ctlModel 0 12 4 0 0)=1; +DA(t 0 22 0 0 0); +} +DO(SPCSO2 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(Oper 0 27 12 0 0){ +DA(ctlVal 0 0 12 0 0); +DA(origin 0 27 12 0 0){ +DA(orCat 0 12 12 0 0); +DA(orIdent 0 13 12 0 0); +} +DA(ctlNum 0 6 12 0 0); +DA(T 0 22 12 0 0); +DA(Test 0 0 12 0 0); +DA(Check 0 24 12 0 0); +} +DA(ctlModel 0 12 4 0 0)=1; +DA(t 0 22 0 0 0); +} +DO(SPCSO3 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(Oper 0 27 12 0 0){ +DA(ctlVal 0 0 12 0 0); +DA(origin 0 27 12 0 0){ +DA(orCat 0 12 12 0 0); +DA(orIdent 0 13 12 0 0); +} +DA(ctlNum 0 6 12 0 0); +DA(T 0 22 12 0 0); +DA(Test 0 0 12 0 0); +DA(Check 0 24 12 0 0); +} +DA(ctlModel 0 12 4 0 0)=1; +DA(t 0 22 0 0 0); +} +DO(SPCSO4 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(Oper 0 27 12 0 0){ +DA(ctlVal 0 0 12 0 0); +DA(origin 0 27 12 0 0){ +DA(orCat 0 12 12 0 0); +DA(orIdent 0 13 12 0 0); +} +DA(ctlNum 0 6 12 0 0); +DA(T 0 22 12 0 0); +DA(Test 0 0 12 0 0); +DA(Check 0 24 12 0 0); +} +DA(ctlModel 0 12 4 0 0)=1; +DA(t 0 22 0 0 0); +} +DO(Ind1 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(Ind2 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(Ind3 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +DO(Ind4 0){ +DA(stVal 0 0 0 1 0); +DA(q 0 23 0 2 0); +DA(t 0 22 0 0 0); +} +} +} +} diff --git a/examples/server_example_control/CMakeLists.txt b/examples/server_example_control/CMakeLists.txt new file mode 100644 index 0000000..da6f9c6 --- /dev/null +++ b/examples/server_example_control/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example_control_SRCS + server_example_control.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example_control_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_control + ${server_example_control_SRCS} +) + +target_link_libraries(server_example_control + iec61850 +) diff --git a/examples/server_example_control/Makefile b/examples/server_example_control/Makefile new file mode 100644 index 0000000..f537715 --- /dev/null +++ b/examples/server_example_control/Makefile @@ -0,0 +1,26 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_control +PROJECT_SOURCES = server_example_control.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = simpleIO_control_tests.icd + + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example_control/server_example_control.c b/examples/server_example_control/server_example_control.c new file mode 100644 index 0000000..24aa7c3 --- /dev/null +++ b/examples/server_example_control/server_example_control.c @@ -0,0 +1,144 @@ +/* + * server_example_control.c + * + * How to use the different control handlers (TBD) + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; +static IedServer iedServer = NULL; + +void +sigint_handler(int signalId) +{ + running = 0; +} + +static CheckHandlerResult +checkHandler(void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, ClientConnection connection) +{ + printf("check handler called!\n"); + + if (interlockCheck) + printf(" with interlock check bit set!\n"); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) + return CONTROL_ACCEPTED; + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) + return CONTROL_ACCEPTED; + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) + return CONTROL_ACCEPTED; + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) + return CONTROL_ACCEPTED; + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO9) + return CONTROL_ACCEPTED; + + return CONTROL_OBJECT_UNDEFINED; +} + +static ControlHandlerResult +controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) +{ + uint64_t timestamp = Hal_getTimeInMs(); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); + } + + else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); + } + + else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); + } + + else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + } + else + return CONTROL_RESULT_FAILED; + + return CONTROL_RESULT_OK; +} + +int +main(int argc, char** argv) +{ + + iedServer = IedServer_create(&iedModel); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + /* this is optional - performs operative checks */ + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, checkHandler, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + /* this is optional - performs operative checks */ + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, checkHandler, + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO9, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO9); + + /* this is optional - performs operative checks */ + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO9, checkHandler, + IEDMODEL_GenericIO_GGIO1_SPCSO9); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + while (running) { + Thread_sleep(1); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example_control/simpleIO_control_tests.icd b/examples/server_example_control/simpleIO_control_tests.icd new file mode 100644 index 0000000..6bfd88c --- /dev/null +++ b/examples/server_example_control/simpleIO_control_tests.icd @@ -0,0 +1,308 @@ + + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + sbo-with-normal-security + + + + + direct-with-enhanced-security + + + + + sbo-with-enhanced-security + + + + + direct-with-normal-security + + + + + sbo-with-normal-security + + + + + direct-with-enhanced-security + + + + + sbo-with-enhanced-security + + + + + direct-with-enhanced-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + operate-once + operate-many + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example_control/static_model.c b/examples/server_example_control/static_model.c new file mode 100644 index 0000000..fe05859 --- /dev/null +++ b/examples/server_example_control/static_model.c @@ -0,0 +1,4220 @@ +/* + * static_model.c + * + * automatically generated from simpleIO_control_tests.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_SBO; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboClass; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO5; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_Test; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO6; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_SBO; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO7; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO8; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO9; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0 +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, +}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, +}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_SBO, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_SBO = { + DataAttributeModelType, + "SBO", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + IEC61850_FC_CO, + VISIBLE_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_sboClass, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboClass = { + DataAttributeModelType, + "sboClass", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO4 = { + DataObjectModelType, + "SPCSO4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw = { + DataAttributeModelType, + "SBOw", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_SBOw, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO5 = { + DataObjectModelType, + "SPCSO5", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO5_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO6 = { + DataObjectModelType, + "SPCSO6", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_SBO, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_SBO = { + DataAttributeModelType, + "SBO", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + NULL, + 0, + IEC61850_FC_CO, + VISIBLE_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO6, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO7 = { + DataObjectModelType, + "SPCSO7", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO7, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO8 = { + DataObjectModelType, + "SPCSO8", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw = { + DataAttributeModelType, + "SBOw", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_operTm, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_origin_orCat, + 0, + IEC61850_FC_ST, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_origin_orIdent, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_origin, + NULL, + NULL, + 0, + IEC61850_FC_ST, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_stVal, + NULL, + 0, + IEC61850_FC_ST, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO9 = { + DataObjectModelType, + "SPCSO9", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + NULL, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + + + + + + +IedModel iedModel = { + "simpleIO", + &iedModel_GenericIO, + NULL, + NULL, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(2); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); + +iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(4); + +iedModel_GenericIO_GGIO1_SPCSO5_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO6_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(2); + +iedModel_GenericIO_GGIO1_SPCSO7_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); + +iedModel_GenericIO_GGIO1_SPCSO8_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(4); + +iedModel_GenericIO_GGIO1_SPCSO9_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); +} diff --git a/examples/server_example_control/static_model.h b/examples/server_example_control/static_model.h new file mode 100644 index 0000000..67c3967 --- /dev/null +++ b/examples/server_example_control/static_model.h @@ -0,0 +1,633 @@ +/* + * static_model.h + * + * automatically generated from simpleIO_control_tests.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_SBO; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboClass; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO5; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO5_Cancel_Test; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO6; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_SBO; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO6_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO7; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO7_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO8; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_operTm; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO9; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_SBO (&iedModel_GenericIO_GGIO1_SPCSO2_SBO) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_sboClass (&iedModel_GenericIO_GGIO1_SPCSO2_sboClass) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_origin (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_T (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_Test (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_SBOw_Check (&iedModel_GenericIO_GGIO1_SPCSO4_SBOw_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5 (&iedModel_GenericIO_GGIO1_SPCSO5) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper (&iedModel_GenericIO_GGIO1_SPCSO5_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_operTm (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO5_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_stVal (&iedModel_GenericIO_GGIO1_SPCSO5_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_q (&iedModel_GenericIO_GGIO1_SPCSO5_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_t (&iedModel_GenericIO_GGIO1_SPCSO5_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO5_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO5_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO5_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6 (&iedModel_GenericIO_GGIO1_SPCSO6) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_SBO (&iedModel_GenericIO_GGIO1_SPCSO6_SBO) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper (&iedModel_GenericIO_GGIO1_SPCSO6_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_operTm (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO6_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_operTm (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO6_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_stVal (&iedModel_GenericIO_GGIO1_SPCSO6_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_q (&iedModel_GenericIO_GGIO1_SPCSO6_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_t (&iedModel_GenericIO_GGIO1_SPCSO6_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO6_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO6_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7 (&iedModel_GenericIO_GGIO1_SPCSO7) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper (&iedModel_GenericIO_GGIO1_SPCSO7_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_operTm (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO7_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_operTm (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO7_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_stVal (&iedModel_GenericIO_GGIO1_SPCSO7_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_q (&iedModel_GenericIO_GGIO1_SPCSO7_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_t (&iedModel_GenericIO_GGIO1_SPCSO7_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO7_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO7_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8 (&iedModel_GenericIO_GGIO1_SPCSO8) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_operTm (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_origin (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_T (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_Test (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_SBOw_Check (&iedModel_GenericIO_GGIO1_SPCSO8_SBOw_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper (&iedModel_GenericIO_GGIO1_SPCSO8_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_operTm (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO8_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_operTm (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_operTm) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO8_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_origin (&iedModel_GenericIO_GGIO1_SPCSO8_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO8_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO8_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO8_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_stVal (&iedModel_GenericIO_GGIO1_SPCSO8_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_q (&iedModel_GenericIO_GGIO1_SPCSO8_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_t (&iedModel_GenericIO_GGIO1_SPCSO8_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO8_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO8_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9 (&iedModel_GenericIO_GGIO1_SPCSO9) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper (&iedModel_GenericIO_GGIO1_SPCSO9_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_stVal (&iedModel_GenericIO_GGIO1_SPCSO9_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_q (&iedModel_GenericIO_GGIO1_SPCSO9_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_t (&iedModel_GenericIO_GGIO1_SPCSO9_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO9_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_dynamic/CMakeLists.txt b/examples/server_example_dynamic/CMakeLists.txt new file mode 100644 index 0000000..ebc14fc --- /dev/null +++ b/examples/server_example_dynamic/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories( + . +) + +set(server_example_dynamic_SRCS + server_example_dynamic.c +) + +IF(WIN32) +set_source_files_properties(${server_example_dynamic_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_dynamic + ${server_example_dynamic_SRCS} +) + +target_link_libraries(server_example_dynamic + iec61850 +) diff --git a/examples/server_example_dynamic/Makefile b/examples/server_example_dynamic/Makefile new file mode 100644 index 0000000..5db8d54 --- /dev/null +++ b/examples/server_example_dynamic/Makefile @@ -0,0 +1,19 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_dynamic +PROJECT_SOURCES = server_example_dynamic.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example_dynamic/server_example_dynamic.c b/examples/server_example_dynamic/server_example_dynamic.c new file mode 100644 index 0000000..49dccbc --- /dev/null +++ b/examples/server_example_dynamic/server_example_dynamic.c @@ -0,0 +1,103 @@ +/* + * server_example_dynamic.c + * + * This example shows how to build a data model at runtime by API calls. + * + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + + +static int running = 0; + +void sigint_handler(int signalId) +{ + running = 0; +} + +int main(int argc, char** argv) { + + int tcpPort = 102; + + if (argc > 1) { + tcpPort = atoi(argv[1]); + } + + /********************* + * Setup data model + ********************/ + + IedModel* model = IedModel_create("testmodel"); + + LogicalDevice* lDevice1 = LogicalDevice_create("SENSORS", model); + + LogicalNode* lln0 = LogicalNode_create("LLN0", lDevice1); + + DataObject* lln0_mod = CDC_ENS_create("Mod", (ModelNode*) lln0, 0); + DataObject* lln0_health = CDC_ENS_create("Health", (ModelNode*) lln0, 0); + + SettingGroupControlBlock_create(lln0, 1, 1); + + /* Add a temperature sensor LN */ + LogicalNode* ttmp1 = LogicalNode_create("TTMP1", lDevice1); + DataObject* ttmp1_tmpsv = CDC_SAV_create("TmpSv", (ModelNode*) ttmp1, 0, false); + + DataAttribute* temperatureValue = (DataAttribute*) ModelNode_getChild((ModelNode*) ttmp1_tmpsv, "instMag.f"); + DataAttribute* temperatureTimestamp = (DataAttribute*) ModelNode_getChild((ModelNode*) ttmp1_tmpsv, "t"); + + DataSet* dataSet = DataSet_create("events", lln0); + DataSetEntry_create(dataSet, "TTMP1$MX$TmpSv$instMag$f", -1, NULL); + + uint8_t rptOptions = RPT_OPT_SEQ_NUM | RPT_OPT_TIME_STAMP | RPT_OPT_REASON_FOR_INCLUSION; + + ReportControlBlock_create("events01", lln0, "events01", false, NULL, 1, TRG_OPT_DATA_CHANGED, rptOptions, 50, 0); + ReportControlBlock_create("events02", lln0, "events02", false, NULL, 1, TRG_OPT_DATA_CHANGED, rptOptions, 50, 0); + + /********************* + * run server + ********************/ + + IedServer iedServer = IedServer_create(model); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, tcpPort); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float val = 0.f; + + while (running) { + IedServer_lockDataModel(iedServer); + + MmsValue_setFloat(temperatureValue->mmsValue, val); + MmsValue_setUtcTimeMs(temperatureTimestamp->mmsValue, Hal_getTimeInMs()); + IedServer_updateAttributeValue(iedServer, temperatureValue, temperatureValue->mmsValue); + + IedServer_unlockDataModel(iedServer); + + val += 0.1f; + + Thread_sleep(100); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); + + /* destroy dynamic data model */ + IedModel_destroy(model); +} /* main() */ diff --git a/examples/server_example_goose/CMakeLists.txt b/examples/server_example_goose/CMakeLists.txt new file mode 100644 index 0000000..7265858 --- /dev/null +++ b/examples/server_example_goose/CMakeLists.txt @@ -0,0 +1,23 @@ +include_directories( + . +) + +set(server_example_goose_SRCS + server_example_goose.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example_goose_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_goose + ${server_example_goose_SRCS} +) + +target_link_libraries(server_example_goose + iec61850 +) + + diff --git a/examples/server_example_goose/Makefile b/examples/server_example_goose/Makefile new file mode 100644 index 0000000..25b326c --- /dev/null +++ b/examples/server_example_goose/Makefile @@ -0,0 +1,25 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_goose +PROJECT_SOURCES = server_example_goose.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = simpleIO_direct_control_goose.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/server_example_goose/server_example_goose.c b/examples/server_example_goose/server_example_goose.c new file mode 100644 index 0000000..7f0681d --- /dev/null +++ b/examples/server_example_goose/server_example_goose.c @@ -0,0 +1,114 @@ +/* + * server_example_goose.c + * + * This example demonstrates how to use GOOSE publishing, Reporting and the + * control model. + * + */ + +#include "iec61850_server.h" +#include "hal_thread.h" /* for Thread_sleep() */ +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; +static IedServer iedServer = NULL; + +void sigint_handler(int signalId) +{ + running = 0; +} + +void +controlHandlerForBinaryOutput(void* parameter, MmsValue* value) +{ + uint64_t timestamp = Hal_getTimeInMs(); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timestamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + } +} + +int main(int argc, char** argv) { + + iedServer = IedServer_create(&iedModel); + + if (argc > 1) { + char* ethernetIfcID = argv[1]; + + printf("Using GOOSE interface: %s\n", ethernetIfcID); + IedServer_setGooseInterfaceId(iedServer, ethernetIfcID); + } + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + /* Start GOOSE publishing */ + IedServer_enableGoosePublishing(iedServer); + + running = 1; + + signal(SIGINT, sigint_handler); + + float anIn1 = 0.f; + + while (running) { + + IedServer_lockDataModel(iedServer); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, Hal_getTimeInMs()); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, anIn1); + + IedServer_unlockDataModel(iedServer); + + anIn1 += 0.1; + + Thread_sleep(1000); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example_goose/simpleIO_direct_control_goose.icd b/examples/server_example_goose/simpleIO_direct_control_goose.icd new file mode 100644 index 0000000..4adbf3f --- /dev/null +++ b/examples/server_example_goose/simpleIO_direct_control_goose.icd @@ -0,0 +1,261 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+ +
+

1

+

4

+

01-0c-cd-01-00-01

+

1000

+
+
+ +
+

1

+

4

+

01-0c-cd-01-00-01

+

1000

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example_goose/static_model.c b/examples/server_example_goose/static_model.c new file mode 100644 index 0000000..8c60853 --- /dev/null +++ b/examples/server_example_goose/static_model.c @@ -0,0 +1,2024 @@ +/* + * static_model.c + * + * automatically generated from simpleIO_direct_control_goose.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + +extern DataSet ds_GenericIO_LLN0_Events; +extern DataSet ds_GenericIO_LLN0_AnalogValues; + + +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda0; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda1; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda1 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda2 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda3 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$stVal", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_GenericIO_LLN0_Events = { + "GenericIO", + "LLN0$Events", + 4, + &ds_GenericIO_LLN0_Events_fcda0, + &ds_GenericIO_LLN0_AnalogValues +}; + +extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda0; +extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda1; +extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2; +extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3; + +DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda0 = { + "GenericIO", + false, + "GGIO1$MX$AnIn1", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_AnalogValues_fcda1 +}; + +DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda1 = { + "GenericIO", + false, + "GGIO1$MX$AnIn2", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_AnalogValues_fcda2 +}; + +DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2 = { + "GenericIO", + false, + "GGIO1$MX$AnIn3", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_AnalogValues_fcda3 +}; + +DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3 = { + "GenericIO", + false, + "GGIO1$MX$AnIn4", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_GenericIO_LLN0_AnalogValues = { + "GenericIO", + "LLN0$AnalogValues", + 4, + &ds_GenericIO_LLN0_AnalogValues_fcda0, + NULL +}; + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0 +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, +}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, +}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO4 = { + DataObjectModelType, + "SPCSO4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_GenericIO_LLN0_report0; +extern ReportControlBlock iedModel_GenericIO_LLN0_report1; + +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; +ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "AnalogValuesRCB01", "AnalogValues", false, "AnalogValues", 1, 8, 111, 50, 1000, NULL}; + +extern GSEControlBlock iedModel_GenericIO_LLN0_gse0; +extern GSEControlBlock iedModel_GenericIO_LLN0_gse1; + +static PhyComAddress iedModel_GenericIO_LLN0_gse0_address = { + 4, + 1, + 1000, + {0x1, 0xc, 0xcd, 0x1, 0x0, 0x1} +}; + +GSEControlBlock iedModel_GenericIO_LLN0_gse0 = {&iedModel_GenericIO_LLN0, "gcbEvents", "events", "Events", 2, false, &iedModel_GenericIO_LLN0_gse0_address, 1000, 3000, &iedModel_GenericIO_LLN0_gse1}; + +static PhyComAddress iedModel_GenericIO_LLN0_gse1_address = { + 4, + 1, + 1000, + {0x1, 0xc, 0xcd, 0x1, 0x0, 0x1} +}; + +GSEControlBlock iedModel_GenericIO_LLN0_gse1 = {&iedModel_GenericIO_LLN0, "gcbAnalogValues", "analog", "AnalogValues", 2, false, &iedModel_GenericIO_LLN0_gse1_address, -1, -1, NULL}; + + + +IedModel iedModel = { + "simpleIO", + &iedModel_GenericIO, + &ds_GenericIO_LLN0_Events, + &iedModel_GenericIO_LLN0_report0, + &iedModel_GenericIO_LLN0_gse0, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); +} diff --git a/examples/server_example_goose/static_model.h b/examples/server_example_goose/static_model.h new file mode 100644 index 0000000..5e827db --- /dev/null +++ b/examples/server_example_goose/static_model.h @@ -0,0 +1,299 @@ +/* + * static_model.h + * + * automatically generated from simpleIO_direct_control_goose.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_setting_groups/CMakeLists.txt b/examples/server_example_setting_groups/CMakeLists.txt new file mode 100644 index 0000000..cb2d3cf --- /dev/null +++ b/examples/server_example_setting_groups/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example_sg_SRCS + server_example_sg.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example_sg_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_sg + ${server_example_sg_SRCS} +) + +target_link_libraries(server_example_sg + iec61850 +) diff --git a/examples/server_example_setting_groups/Makefile b/examples/server_example_setting_groups/Makefile new file mode 100644 index 0000000..236aff4 --- /dev/null +++ b/examples/server_example_setting_groups/Makefile @@ -0,0 +1,24 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_sg +PROJECT_SOURCES = server_example_sg.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = sg_demo.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDFLAGS) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + diff --git a/examples/server_example_setting_groups/server_example_sg.c b/examples/server_example_setting_groups/server_example_sg.c new file mode 100644 index 0000000..eb588f8 --- /dev/null +++ b/examples/server_example_setting_groups/server_example_sg.c @@ -0,0 +1,149 @@ +/* + * server_example_sg.c + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include + + +/* Include the generated header with the model access handles */ +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static IedServer iedServer; +static int running = 0; + +typedef struct { + float strVal; + int opDlTmms; + int rsDlTmms; + int rstTms; +} PTOC1Settings; + + +static PTOC1Settings ptoc1Settings[] = { + {1.0f, 500, 500, 500}, + {2.0f, 1500, 2500, 750}, + {3.0f, 500, 1500, 750}, + {3.5f, 1250, 1750, 500}, + {3.75f, 1250, 1750, 750} +}; + +void sigint_handler(int signalId) +{ + running = 0; +} + +static void +loadActiveSgValues (int actSG) +{ + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_PROT_PTOC1_StrVal_setMag_f, ptoc1Settings[actSG - 1].strVal); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_PROT_PTOC1_OpDlTmms_setVal, ptoc1Settings[actSG - 1].opDlTmms); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_PROT_PTOC1_RsDlTmms_setVal, ptoc1Settings[actSG - 1].rsDlTmms); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_PROT_PTOC1_RstTms_setVal, ptoc1Settings[actSG - 1].rstTms); +} + +static void +loadEditSgValues (int editSG) +{ + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_SE_PROT_PTOC1_StrVal_setMag_f, ptoc1Settings[editSG - 1].strVal); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_SE_PROT_PTOC1_OpDlTmms_setVal, ptoc1Settings[editSG - 1].opDlTmms); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_SE_PROT_PTOC1_RsDlTmms_setVal, ptoc1Settings[editSG - 1].rsDlTmms); + IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_SE_PROT_PTOC1_RstTms_setVal, ptoc1Settings[editSG - 1].rstTms); +} + +static bool +activeSgChangedHandler (void* parameter, SettingGroupControlBlock* sgcb, + uint8_t newActSg, ClientConnection connection) +{ + printf("Switch to setting group %i\n", (int) newActSg); + + loadActiveSgValues(newActSg); + + return true; +} + +static bool +editSgChangedHandler (void* parameter, SettingGroupControlBlock* sgcb, + uint8_t newEditSg, ClientConnection connection) +{ + printf("Set edit setting group to %i\n", (int) newEditSg); + + loadEditSgValues(newEditSg); + + return true; +} + +static void +editSgConfirmedHandler(void* parameter, SettingGroupControlBlock* sgcb, + uint8_t editSg) +{ + printf("Received edit sg confirm for sg %i\n", editSg); + + ptoc1Settings[editSg - 1].strVal = MmsValue_toFloat(IEDMODEL_SE_PROT_PTOC1_StrVal_setMag_f->mmsValue); + ptoc1Settings[editSg - 1].opDlTmms = MmsValue_toInt32(IEDMODEL_SE_PROT_PTOC1_OpDlTmms_setVal->mmsValue); + ptoc1Settings[editSg - 1].rsDlTmms = MmsValue_toInt32(IEDMODEL_SE_PROT_PTOC1_RsDlTmms_setVal->mmsValue); + ptoc1Settings[editSg - 1].rstTms = MmsValue_toInt32(IEDMODEL_SE_PROT_PTOC1_RstTms_setVal->mmsValue); + + if (IedServer_getActiveSettingGroup(iedServer, sgcb) == editSg) { + loadActiveSgValues(editSg); + } +} + + +int +main(int argc, char** argv) +{ + iedServer = IedServer_create(&iedModel); + + LogicalDevice* ld = IEDMODEL_PROT; + + SettingGroupControlBlock* sgcb = LogicalDevice_getSettingGroupControlBlock(ld); + + loadActiveSgValues(sgcb->actSG); + + IedServer_setActiveSettingGroupChangedHandler(iedServer, sgcb, activeSgChangedHandler, NULL); + IedServer_setEditSettingGroupChangedHandler(iedServer, sgcb, editSgChangedHandler, NULL); + IedServer_setEditSettingGroupConfirmationHandler(iedServer, sgcb, editSgConfirmedHandler, NULL); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_start(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float power = 500.f; + + while (running) { + + uint64_t timeval = Hal_getTimeInMs(); + + IedServer_lockDataModel(iedServer); + + IedServer_unlockDataModel(iedServer); + + power += 0.1f; + + Thread_sleep(500); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); + + return 0; +} /* main() */ diff --git a/examples/server_example_setting_groups/sg_demo.icd b/examples/server_example_setting_groups/sg_demo.icd new file mode 100644 index 0000000..ef3bef8 --- /dev/null +++ b/examples/server_example_setting_groups/sg_demo.icd @@ -0,0 +1,437 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + MZ Automation + + + 1.0 + + + 1 + + + Setting group demo + + + + IEC 61850-7-4:2007 + + + + + + + + + + MZ Automation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + m + kg + s + A + K + mol + cd + deg + rad + sr + Gy + q + °C + Sv + F + C + S + H + V + ohm + J + N + Hz + lx + Lm + Wb + T + W + Pa + m² + m³ + m/s + m/s² + m³/s + m/m³ + M + kg/m³ + m²/s + W/m K + J/K + ppm + 1/s + rad/s + VA + Watts + VAr + phi + cos_phi + Vs + V² + As + A² + A²t + VAh + Wh + VArh + V/Hz + + + + y + z + a + f + p + n + µ + m + c + d + + da + h + k + M + G + T + P + E + Z + Y + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + ok + warning + alarm + + + + not-supported + reserved1 + station-control + remote-control + reserved2 + automatic-station + automatic-remote + maintenance + process + + + + + normal + high + low + high-high + low-low + + + + on + on-blocked + test + test/blocked + off + + + + unknown + forward + backward + both + + + + e1 + e2 + e3 + e4 + e5 + + + + diff --git a/examples/server_example_setting_groups/static_model.c b/examples/server_example_setting_groups/static_model.c new file mode 100644 index 0000000..af84056 --- /dev/null +++ b/examples/server_example_setting_groups/static_model.c @@ -0,0 +1,1229 @@ +/* + * static_model.c + * + * automatically generated from sg_demo.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_PROT; +extern LogicalNode iedModel_PROT_LLN0; +extern DataObject iedModel_PROT_LLN0_Mod; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_ctlVal; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_operTm; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin_orCat; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin_orIdent; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_ctlNum; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_T; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_Test; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_Check; +extern DataAttribute iedModel_PROT_LLN0_Mod_stVal; +extern DataAttribute iedModel_PROT_LLN0_Mod_q; +extern DataAttribute iedModel_PROT_LLN0_Mod_t; +extern DataAttribute iedModel_PROT_LLN0_Mod_ctlModel; +extern DataObject iedModel_PROT_LLN0_Beh; +extern DataAttribute iedModel_PROT_LLN0_Beh_stVal; +extern DataAttribute iedModel_PROT_LLN0_Beh_q; +extern DataAttribute iedModel_PROT_LLN0_Beh_t; +extern DataObject iedModel_PROT_LLN0_Health; +extern DataAttribute iedModel_PROT_LLN0_Health_stVal; +extern DataAttribute iedModel_PROT_LLN0_Health_q; +extern DataAttribute iedModel_PROT_LLN0_Health_t; +extern DataObject iedModel_PROT_LLN0_NamPlt; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_d; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_PROT_LPHD1; +extern DataObject iedModel_PROT_LPHD1_PhyNam; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_vendor; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_hwRev; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_swRev; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_serNum; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_model; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_location; +extern DataObject iedModel_PROT_LPHD1_PhyHealth; +extern DataAttribute iedModel_PROT_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_PROT_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_PROT_LPHD1_PhyHealth_t; +extern DataObject iedModel_PROT_LPHD1_Proxy; +extern DataAttribute iedModel_PROT_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_PROT_LPHD1_Proxy_q; +extern DataAttribute iedModel_PROT_LPHD1_Proxy_t; +extern LogicalNode iedModel_PROT_PTOC1; +extern DataObject iedModel_PROT_PTOC1_Beh; +extern DataAttribute iedModel_PROT_PTOC1_Beh_stVal; +extern DataAttribute iedModel_PROT_PTOC1_Beh_q; +extern DataAttribute iedModel_PROT_PTOC1_Beh_t; +extern DataObject iedModel_PROT_PTOC1_Mod; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_ctlVal; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_operTm; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin_orCat; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin_orIdent; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_ctlNum; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_T; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_Test; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_Check; +extern DataAttribute iedModel_PROT_PTOC1_Mod_stVal; +extern DataAttribute iedModel_PROT_PTOC1_Mod_q; +extern DataAttribute iedModel_PROT_PTOC1_Mod_t; +extern DataAttribute iedModel_PROT_PTOC1_Mod_ctlModel; +extern DataObject iedModel_PROT_PTOC1_Str; +extern DataAttribute iedModel_PROT_PTOC1_Str_general; +extern DataAttribute iedModel_PROT_PTOC1_Str_dirGeneral; +extern DataAttribute iedModel_PROT_PTOC1_Str_q; +extern DataAttribute iedModel_PROT_PTOC1_Str_t; +extern DataObject iedModel_PROT_PTOC1_Op; +extern DataAttribute iedModel_PROT_PTOC1_Op_general; +extern DataAttribute iedModel_PROT_PTOC1_Op_q; +extern DataAttribute iedModel_PROT_PTOC1_Op_t; +extern DataObject iedModel_PROT_PTOC1_StrVal; +extern DataAttribute iedModel_PROT_PTOC1_StrVal_setMag; +extern DataAttribute iedModel_PROT_PTOC1_StrVal_setMag_f; +extern DataAttribute iedModel_SE_PROT_PTOC1_StrVal_setMag; +extern DataAttribute iedModel_SE_PROT_PTOC1_StrVal_setMag_f; +extern DataObject iedModel_PROT_PTOC1_OpDlTmms; +extern DataAttribute iedModel_PROT_PTOC1_OpDlTmms_setVal; +extern DataAttribute iedModel_SE_PROT_PTOC1_OpDlTmms_setVal; +extern DataObject iedModel_PROT_PTOC1_RsDlTmms; +extern DataAttribute iedModel_PROT_PTOC1_RsDlTmms_setVal; +extern DataAttribute iedModel_SE_PROT_PTOC1_RsDlTmms_setVal; +extern DataObject iedModel_PROT_PTOC1_RstTms; +extern DataAttribute iedModel_PROT_PTOC1_RstTms_setVal; +extern DataAttribute iedModel_SE_PROT_PTOC1_RstTms_setVal; + + + +LogicalDevice iedModel_PROT = { + LogicalDeviceModelType, + "PROT", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_PROT_LLN0 +}; + +LogicalNode iedModel_PROT_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_PROT, + (ModelNode*) &iedModel_PROT_LPHD1, + (ModelNode*) &iedModel_PROT_LLN0_Mod, +}; + +DataObject iedModel_PROT_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_PROT_LLN0, + (ModelNode*) &iedModel_PROT_LLN0_Beh, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + 0 +}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_PROT_LLN0_Mod, + (ModelNode*) &iedModel_PROT_LLN0_Mod_stVal, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_ctlNum, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_origin, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_PROT_LLN0_Mod_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_LLN0_Mod, + (ModelNode*) &iedModel_PROT_LLN0_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_LLN0_Mod, + (ModelNode*) &iedModel_PROT_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_LLN0_Mod, + (ModelNode*) &iedModel_PROT_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_PROT_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_PROT_LLN0, + (ModelNode*) &iedModel_PROT_LLN0_Health, + (ModelNode*) &iedModel_PROT_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_PROT_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_LLN0_Beh, + (ModelNode*) &iedModel_PROT_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_LLN0_Beh, + (ModelNode*) &iedModel_PROT_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_PROT_LLN0, + (ModelNode*) &iedModel_PROT_LLN0_NamPlt, + (ModelNode*) &iedModel_PROT_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_PROT_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_LLN0_Health, + (ModelNode*) &iedModel_PROT_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_LLN0_Health, + (ModelNode*) &iedModel_PROT_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_PROT_LLN0, + NULL, + (ModelNode*) &iedModel_PROT_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_PROT_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_PROT_LLN0_NamPlt, + (ModelNode*) &iedModel_PROT_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_PROT_LLN0_NamPlt, + (ModelNode*) &iedModel_PROT_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_PROT_LLN0_NamPlt, + (ModelNode*) &iedModel_PROT_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_PROT_LLN0_NamPlt, + (ModelNode*) &iedModel_PROT_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_PROT_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_PROT_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_PROT, + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, +}; + +DataObject iedModel_PROT_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_PROT_LPHD1, + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_PROT_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam_hwRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyNam_hwRev = { + DataAttributeModelType, + "hwRev", + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyNam_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam_serNum, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyNam_serNum = { + DataAttributeModelType, + "serNum", + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam_model, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyNam_model = { + DataAttributeModelType, + "model", + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam_location, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyNam_location = { + DataAttributeModelType, + "location", + (ModelNode*) &iedModel_PROT_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_PROT_LPHD1, + (ModelNode*) &iedModel_PROT_LPHD1_Proxy, + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_PROT_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth, + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth, + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_PROT_LPHD1, + NULL, + (ModelNode*) &iedModel_PROT_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_PROT_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_LPHD1_Proxy, + (ModelNode*) &iedModel_PROT_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_LPHD1_Proxy, + (ModelNode*) &iedModel_PROT_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_PROT_PTOC1 = { + LogicalNodeModelType, + "PTOC1", + (ModelNode*) &iedModel_PROT, + NULL, + (ModelNode*) &iedModel_PROT_PTOC1_Beh, +}; + +DataObject iedModel_PROT_PTOC1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_Mod, + (ModelNode*) &iedModel_PROT_PTOC1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_PTOC1_Beh, + (ModelNode*) &iedModel_PROT_PTOC1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_PTOC1_Beh, + (ModelNode*) &iedModel_PROT_PTOC1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_PTOC1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_Str, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_PROT_PTOC1_Mod, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_stVal, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_operTm, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_operTm = { + DataAttributeModelType, + "operTm", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_ctlNum, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_origin, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_PROT_PTOC1_Mod_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_PROT_PTOC1_Mod, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_PTOC1_Mod, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_PTOC1_Mod, + (ModelNode*) &iedModel_PROT_PTOC1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_PROT_PTOC1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_Str = { + DataObjectModelType, + "Str", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_Op, + (ModelNode*) &iedModel_PROT_PTOC1_Str_general, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_Str_general = { + DataAttributeModelType, + "general", + (ModelNode*) &iedModel_PROT_PTOC1_Str, + (ModelNode*) &iedModel_PROT_PTOC1_Str_dirGeneral, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Str_dirGeneral = { + DataAttributeModelType, + "dirGeneral", + (ModelNode*) &iedModel_PROT_PTOC1_Str, + (ModelNode*) &iedModel_PROT_PTOC1_Str_q, + NULL, + 0, + IEC61850_FC_ST, + ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Str_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_PTOC1_Str, + (ModelNode*) &iedModel_PROT_PTOC1_Str_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Str_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_PTOC1_Str, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_Op = { + DataObjectModelType, + "Op", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_StrVal, + (ModelNode*) &iedModel_PROT_PTOC1_Op_general, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_Op_general = { + DataAttributeModelType, + "general", + (ModelNode*) &iedModel_PROT_PTOC1_Op, + (ModelNode*) &iedModel_PROT_PTOC1_Op_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Op_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_PROT_PTOC1_Op, + (ModelNode*) &iedModel_PROT_PTOC1_Op_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_Op_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_PROT_PTOC1_Op, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_StrVal = { + DataObjectModelType, + "StrVal", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_OpDlTmms, + (ModelNode*) &iedModel_PROT_PTOC1_StrVal_setMag, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_StrVal_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_PROT_PTOC1_StrVal, + (ModelNode*) &iedModel_SE_PROT_PTOC1_StrVal_setMag, + (ModelNode*) &iedModel_PROT_PTOC1_StrVal_setMag_f, + 0, + IEC61850_FC_SG, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_PROT_PTOC1_StrVal_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_PROT_PTOC1_StrVal_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SG, + FLOAT32, + 0, + NULL, + 0}; + +DataAttribute iedModel_SE_PROT_PTOC1_StrVal_setMag = { + DataAttributeModelType, + "setMag", + (ModelNode*) &iedModel_PROT_PTOC1_StrVal, + NULL, + (ModelNode*) &iedModel_SE_PROT_PTOC1_StrVal_setMag_f, + 0, + IEC61850_FC_SE, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_SE_PROT_PTOC1_StrVal_setMag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_SE_PROT_PTOC1_StrVal_setMag, + NULL, + NULL, + 0, + IEC61850_FC_SE, + FLOAT32, + 0, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_OpDlTmms = { + DataObjectModelType, + "OpDlTmms", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_RsDlTmms, + (ModelNode*) &iedModel_PROT_PTOC1_OpDlTmms_setVal, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_OpDlTmms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_PROT_PTOC1_OpDlTmms, + (ModelNode*) &iedModel_SE_PROT_PTOC1_OpDlTmms_setVal, + NULL, + 0, + IEC61850_FC_SG, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_SE_PROT_PTOC1_OpDlTmms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_PROT_PTOC1_OpDlTmms, + NULL, + NULL, + 0, + IEC61850_FC_SE, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_RsDlTmms = { + DataObjectModelType, + "RsDlTmms", + (ModelNode*) &iedModel_PROT_PTOC1, + (ModelNode*) &iedModel_PROT_PTOC1_RstTms, + (ModelNode*) &iedModel_PROT_PTOC1_RsDlTmms_setVal, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_RsDlTmms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_PROT_PTOC1_RsDlTmms, + (ModelNode*) &iedModel_SE_PROT_PTOC1_RsDlTmms_setVal, + NULL, + 0, + IEC61850_FC_SG, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_SE_PROT_PTOC1_RsDlTmms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_PROT_PTOC1_RsDlTmms, + NULL, + NULL, + 0, + IEC61850_FC_SE, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataObject iedModel_PROT_PTOC1_RstTms = { + DataObjectModelType, + "RstTms", + (ModelNode*) &iedModel_PROT_PTOC1, + NULL, + (ModelNode*) &iedModel_PROT_PTOC1_RstTms_setVal, + 0 +}; + +DataAttribute iedModel_PROT_PTOC1_RstTms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_PROT_PTOC1_RstTms, + (ModelNode*) &iedModel_SE_PROT_PTOC1_RstTms_setVal, + NULL, + 0, + IEC61850_FC_SG, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_SE_PROT_PTOC1_RstTms_setVal = { + DataAttributeModelType, + "setVal", + (ModelNode*) &iedModel_PROT_PTOC1_RstTms, + NULL, + NULL, + 0, + IEC61850_FC_SE, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + + + + +extern SettingGroupControlBlock iedModel_PROT_LLN0_sgcb; + +SettingGroupControlBlock iedModel_PROT_LLN0_sgcb = {&iedModel_PROT_LLN0, 1, 5, 0, false, 0, 0, NULL}; + + +IedModel iedModel = { + "DEMO", + &iedModel_PROT, + NULL, + NULL, + NULL, + &iedModel_PROT_LLN0_sgcb, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_PROT_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_PROT_LLN0_NamPlt_vendor.mmsValue = MmsValue_newVisibleString("MZ Automation"); + +iedModel_PROT_LLN0_NamPlt_swRev.mmsValue = MmsValue_newVisibleString("1.0"); + +iedModel_PROT_LLN0_NamPlt_d.mmsValue = MmsValue_newVisibleString("Setting group demo"); + +iedModel_PROT_LLN0_NamPlt_configRev.mmsValue = MmsValue_newVisibleString("1"); + +iedModel_PROT_LLN0_NamPlt_ldNs.mmsValue = MmsValue_newVisibleString("IEC 61850-7-4:2007"); + +iedModel_PROT_LPHD1_PhyNam_vendor.mmsValue = MmsValue_newVisibleString("MZ Automation"); +} diff --git a/examples/server_example_setting_groups/static_model.h b/examples/server_example_setting_groups/static_model.h new file mode 100644 index 0000000..06cf0b8 --- /dev/null +++ b/examples/server_example_setting_groups/static_model.h @@ -0,0 +1,199 @@ +/* + * static_model.h + * + * automatically generated from sg_demo.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_PROT; +extern LogicalNode iedModel_PROT_LLN0; +extern DataObject iedModel_PROT_LLN0_Mod; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_ctlVal; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_operTm; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin_orCat; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_origin_orIdent; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_ctlNum; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_T; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_Test; +extern DataAttribute iedModel_PROT_LLN0_Mod_Oper_Check; +extern DataAttribute iedModel_PROT_LLN0_Mod_stVal; +extern DataAttribute iedModel_PROT_LLN0_Mod_q; +extern DataAttribute iedModel_PROT_LLN0_Mod_t; +extern DataAttribute iedModel_PROT_LLN0_Mod_ctlModel; +extern DataObject iedModel_PROT_LLN0_Beh; +extern DataAttribute iedModel_PROT_LLN0_Beh_stVal; +extern DataAttribute iedModel_PROT_LLN0_Beh_q; +extern DataAttribute iedModel_PROT_LLN0_Beh_t; +extern DataObject iedModel_PROT_LLN0_Health; +extern DataAttribute iedModel_PROT_LLN0_Health_stVal; +extern DataAttribute iedModel_PROT_LLN0_Health_q; +extern DataAttribute iedModel_PROT_LLN0_Health_t; +extern DataObject iedModel_PROT_LLN0_NamPlt; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_d; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_PROT_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_PROT_LPHD1; +extern DataObject iedModel_PROT_LPHD1_PhyNam; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_vendor; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_hwRev; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_swRev; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_serNum; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_model; +extern DataAttribute iedModel_PROT_LPHD1_PhyNam_location; +extern DataObject iedModel_PROT_LPHD1_PhyHealth; +extern DataAttribute iedModel_PROT_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_PROT_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_PROT_LPHD1_PhyHealth_t; +extern DataObject iedModel_PROT_LPHD1_Proxy; +extern DataAttribute iedModel_PROT_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_PROT_LPHD1_Proxy_q; +extern DataAttribute iedModel_PROT_LPHD1_Proxy_t; +extern LogicalNode iedModel_PROT_PTOC1; +extern DataObject iedModel_PROT_PTOC1_Beh; +extern DataAttribute iedModel_PROT_PTOC1_Beh_stVal; +extern DataAttribute iedModel_PROT_PTOC1_Beh_q; +extern DataAttribute iedModel_PROT_PTOC1_Beh_t; +extern DataObject iedModel_PROT_PTOC1_Mod; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_ctlVal; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_operTm; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin_orCat; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_origin_orIdent; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_ctlNum; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_T; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_Test; +extern DataAttribute iedModel_PROT_PTOC1_Mod_Oper_Check; +extern DataAttribute iedModel_PROT_PTOC1_Mod_stVal; +extern DataAttribute iedModel_PROT_PTOC1_Mod_q; +extern DataAttribute iedModel_PROT_PTOC1_Mod_t; +extern DataAttribute iedModel_PROT_PTOC1_Mod_ctlModel; +extern DataObject iedModel_PROT_PTOC1_Str; +extern DataAttribute iedModel_PROT_PTOC1_Str_general; +extern DataAttribute iedModel_PROT_PTOC1_Str_dirGeneral; +extern DataAttribute iedModel_PROT_PTOC1_Str_q; +extern DataAttribute iedModel_PROT_PTOC1_Str_t; +extern DataObject iedModel_PROT_PTOC1_Op; +extern DataAttribute iedModel_PROT_PTOC1_Op_general; +extern DataAttribute iedModel_PROT_PTOC1_Op_q; +extern DataAttribute iedModel_PROT_PTOC1_Op_t; +extern DataObject iedModel_PROT_PTOC1_StrVal; +extern DataAttribute iedModel_PROT_PTOC1_StrVal_setMag; +extern DataAttribute iedModel_PROT_PTOC1_StrVal_setMag_f; +extern DataAttribute iedModel_SE_PROT_PTOC1_StrVal_setMag; +extern DataAttribute iedModel_SE_PROT_PTOC1_StrVal_setMag_f; +extern DataObject iedModel_PROT_PTOC1_OpDlTmms; +extern DataAttribute iedModel_PROT_PTOC1_OpDlTmms_setVal; +extern DataAttribute iedModel_SE_PROT_PTOC1_OpDlTmms_setVal; +extern DataObject iedModel_PROT_PTOC1_RsDlTmms; +extern DataAttribute iedModel_PROT_PTOC1_RsDlTmms_setVal; +extern DataAttribute iedModel_SE_PROT_PTOC1_RsDlTmms_setVal; +extern DataObject iedModel_PROT_PTOC1_RstTms; +extern DataAttribute iedModel_PROT_PTOC1_RstTms_setVal; +extern DataAttribute iedModel_SE_PROT_PTOC1_RstTms_setVal; + + + +#define IEDMODEL_PROT (&iedModel_PROT) +#define IEDMODEL_PROT_LLN0 (&iedModel_PROT_LLN0) +#define IEDMODEL_PROT_LLN0_Mod (&iedModel_PROT_LLN0_Mod) +#define IEDMODEL_PROT_LLN0_Mod_Oper (&iedModel_PROT_LLN0_Mod_Oper) +#define IEDMODEL_PROT_LLN0_Mod_Oper_ctlVal (&iedModel_PROT_LLN0_Mod_Oper_ctlVal) +#define IEDMODEL_PROT_LLN0_Mod_Oper_operTm (&iedModel_PROT_LLN0_Mod_Oper_operTm) +#define IEDMODEL_PROT_LLN0_Mod_Oper_origin (&iedModel_PROT_LLN0_Mod_Oper_origin) +#define IEDMODEL_PROT_LLN0_Mod_Oper_origin_orCat (&iedModel_PROT_LLN0_Mod_Oper_origin_orCat) +#define IEDMODEL_PROT_LLN0_Mod_Oper_origin_orIdent (&iedModel_PROT_LLN0_Mod_Oper_origin_orIdent) +#define IEDMODEL_PROT_LLN0_Mod_Oper_ctlNum (&iedModel_PROT_LLN0_Mod_Oper_ctlNum) +#define IEDMODEL_PROT_LLN0_Mod_Oper_T (&iedModel_PROT_LLN0_Mod_Oper_T) +#define IEDMODEL_PROT_LLN0_Mod_Oper_Test (&iedModel_PROT_LLN0_Mod_Oper_Test) +#define IEDMODEL_PROT_LLN0_Mod_Oper_Check (&iedModel_PROT_LLN0_Mod_Oper_Check) +#define IEDMODEL_PROT_LLN0_Mod_stVal (&iedModel_PROT_LLN0_Mod_stVal) +#define IEDMODEL_PROT_LLN0_Mod_q (&iedModel_PROT_LLN0_Mod_q) +#define IEDMODEL_PROT_LLN0_Mod_t (&iedModel_PROT_LLN0_Mod_t) +#define IEDMODEL_PROT_LLN0_Mod_ctlModel (&iedModel_PROT_LLN0_Mod_ctlModel) +#define IEDMODEL_PROT_LLN0_Beh (&iedModel_PROT_LLN0_Beh) +#define IEDMODEL_PROT_LLN0_Beh_stVal (&iedModel_PROT_LLN0_Beh_stVal) +#define IEDMODEL_PROT_LLN0_Beh_q (&iedModel_PROT_LLN0_Beh_q) +#define IEDMODEL_PROT_LLN0_Beh_t (&iedModel_PROT_LLN0_Beh_t) +#define IEDMODEL_PROT_LLN0_Health (&iedModel_PROT_LLN0_Health) +#define IEDMODEL_PROT_LLN0_Health_stVal (&iedModel_PROT_LLN0_Health_stVal) +#define IEDMODEL_PROT_LLN0_Health_q (&iedModel_PROT_LLN0_Health_q) +#define IEDMODEL_PROT_LLN0_Health_t (&iedModel_PROT_LLN0_Health_t) +#define IEDMODEL_PROT_LLN0_NamPlt (&iedModel_PROT_LLN0_NamPlt) +#define IEDMODEL_PROT_LLN0_NamPlt_vendor (&iedModel_PROT_LLN0_NamPlt_vendor) +#define IEDMODEL_PROT_LLN0_NamPlt_swRev (&iedModel_PROT_LLN0_NamPlt_swRev) +#define IEDMODEL_PROT_LLN0_NamPlt_d (&iedModel_PROT_LLN0_NamPlt_d) +#define IEDMODEL_PROT_LLN0_NamPlt_configRev (&iedModel_PROT_LLN0_NamPlt_configRev) +#define IEDMODEL_PROT_LLN0_NamPlt_ldNs (&iedModel_PROT_LLN0_NamPlt_ldNs) +#define IEDMODEL_PROT_LPHD1 (&iedModel_PROT_LPHD1) +#define IEDMODEL_PROT_LPHD1_PhyNam (&iedModel_PROT_LPHD1_PhyNam) +#define IEDMODEL_PROT_LPHD1_PhyNam_vendor (&iedModel_PROT_LPHD1_PhyNam_vendor) +#define IEDMODEL_PROT_LPHD1_PhyNam_hwRev (&iedModel_PROT_LPHD1_PhyNam_hwRev) +#define IEDMODEL_PROT_LPHD1_PhyNam_swRev (&iedModel_PROT_LPHD1_PhyNam_swRev) +#define IEDMODEL_PROT_LPHD1_PhyNam_serNum (&iedModel_PROT_LPHD1_PhyNam_serNum) +#define IEDMODEL_PROT_LPHD1_PhyNam_model (&iedModel_PROT_LPHD1_PhyNam_model) +#define IEDMODEL_PROT_LPHD1_PhyNam_location (&iedModel_PROT_LPHD1_PhyNam_location) +#define IEDMODEL_PROT_LPHD1_PhyHealth (&iedModel_PROT_LPHD1_PhyHealth) +#define IEDMODEL_PROT_LPHD1_PhyHealth_stVal (&iedModel_PROT_LPHD1_PhyHealth_stVal) +#define IEDMODEL_PROT_LPHD1_PhyHealth_q (&iedModel_PROT_LPHD1_PhyHealth_q) +#define IEDMODEL_PROT_LPHD1_PhyHealth_t (&iedModel_PROT_LPHD1_PhyHealth_t) +#define IEDMODEL_PROT_LPHD1_Proxy (&iedModel_PROT_LPHD1_Proxy) +#define IEDMODEL_PROT_LPHD1_Proxy_stVal (&iedModel_PROT_LPHD1_Proxy_stVal) +#define IEDMODEL_PROT_LPHD1_Proxy_q (&iedModel_PROT_LPHD1_Proxy_q) +#define IEDMODEL_PROT_LPHD1_Proxy_t (&iedModel_PROT_LPHD1_Proxy_t) +#define IEDMODEL_PROT_PTOC1 (&iedModel_PROT_PTOC1) +#define IEDMODEL_PROT_PTOC1_Beh (&iedModel_PROT_PTOC1_Beh) +#define IEDMODEL_PROT_PTOC1_Beh_stVal (&iedModel_PROT_PTOC1_Beh_stVal) +#define IEDMODEL_PROT_PTOC1_Beh_q (&iedModel_PROT_PTOC1_Beh_q) +#define IEDMODEL_PROT_PTOC1_Beh_t (&iedModel_PROT_PTOC1_Beh_t) +#define IEDMODEL_PROT_PTOC1_Mod (&iedModel_PROT_PTOC1_Mod) +#define IEDMODEL_PROT_PTOC1_Mod_Oper (&iedModel_PROT_PTOC1_Mod_Oper) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_ctlVal (&iedModel_PROT_PTOC1_Mod_Oper_ctlVal) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_operTm (&iedModel_PROT_PTOC1_Mod_Oper_operTm) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_origin (&iedModel_PROT_PTOC1_Mod_Oper_origin) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_origin_orCat (&iedModel_PROT_PTOC1_Mod_Oper_origin_orCat) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_origin_orIdent (&iedModel_PROT_PTOC1_Mod_Oper_origin_orIdent) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_ctlNum (&iedModel_PROT_PTOC1_Mod_Oper_ctlNum) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_T (&iedModel_PROT_PTOC1_Mod_Oper_T) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_Test (&iedModel_PROT_PTOC1_Mod_Oper_Test) +#define IEDMODEL_PROT_PTOC1_Mod_Oper_Check (&iedModel_PROT_PTOC1_Mod_Oper_Check) +#define IEDMODEL_PROT_PTOC1_Mod_stVal (&iedModel_PROT_PTOC1_Mod_stVal) +#define IEDMODEL_PROT_PTOC1_Mod_q (&iedModel_PROT_PTOC1_Mod_q) +#define IEDMODEL_PROT_PTOC1_Mod_t (&iedModel_PROT_PTOC1_Mod_t) +#define IEDMODEL_PROT_PTOC1_Mod_ctlModel (&iedModel_PROT_PTOC1_Mod_ctlModel) +#define IEDMODEL_PROT_PTOC1_Str (&iedModel_PROT_PTOC1_Str) +#define IEDMODEL_PROT_PTOC1_Str_general (&iedModel_PROT_PTOC1_Str_general) +#define IEDMODEL_PROT_PTOC1_Str_dirGeneral (&iedModel_PROT_PTOC1_Str_dirGeneral) +#define IEDMODEL_PROT_PTOC1_Str_q (&iedModel_PROT_PTOC1_Str_q) +#define IEDMODEL_PROT_PTOC1_Str_t (&iedModel_PROT_PTOC1_Str_t) +#define IEDMODEL_PROT_PTOC1_Op (&iedModel_PROT_PTOC1_Op) +#define IEDMODEL_PROT_PTOC1_Op_general (&iedModel_PROT_PTOC1_Op_general) +#define IEDMODEL_PROT_PTOC1_Op_q (&iedModel_PROT_PTOC1_Op_q) +#define IEDMODEL_PROT_PTOC1_Op_t (&iedModel_PROT_PTOC1_Op_t) +#define IEDMODEL_PROT_PTOC1_StrVal (&iedModel_PROT_PTOC1_StrVal) +#define IEDMODEL_PROT_PTOC1_StrVal_setMag (&iedModel_PROT_PTOC1_StrVal_setMag) +#define IEDMODEL_PROT_PTOC1_StrVal_setMag_f (&iedModel_PROT_PTOC1_StrVal_setMag_f) +#define IEDMODEL_SE_PROT_PTOC1_StrVal_setMag (&iedModel_SE_PROT_PTOC1_StrVal_setMag) +#define IEDMODEL_SE_PROT_PTOC1_StrVal_setMag_f (&iedModel_SE_PROT_PTOC1_StrVal_setMag_f) +#define IEDMODEL_PROT_PTOC1_OpDlTmms (&iedModel_PROT_PTOC1_OpDlTmms) +#define IEDMODEL_PROT_PTOC1_OpDlTmms_setVal (&iedModel_PROT_PTOC1_OpDlTmms_setVal) +#define IEDMODEL_SE_PROT_PTOC1_OpDlTmms_setVal (&iedModel_SE_PROT_PTOC1_OpDlTmms_setVal) +#define IEDMODEL_PROT_PTOC1_RsDlTmms (&iedModel_PROT_PTOC1_RsDlTmms) +#define IEDMODEL_PROT_PTOC1_RsDlTmms_setVal (&iedModel_PROT_PTOC1_RsDlTmms_setVal) +#define IEDMODEL_SE_PROT_PTOC1_RsDlTmms_setVal (&iedModel_SE_PROT_PTOC1_RsDlTmms_setVal) +#define IEDMODEL_PROT_PTOC1_RstTms (&iedModel_PROT_PTOC1_RstTms) +#define IEDMODEL_PROT_PTOC1_RstTms_setVal (&iedModel_PROT_PTOC1_RstTms_setVal) +#define IEDMODEL_SE_PROT_PTOC1_RstTms_setVal (&iedModel_SE_PROT_PTOC1_RstTms_setVal) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_threadless/CMakeLists.txt b/examples/server_example_threadless/CMakeLists.txt new file mode 100644 index 0000000..388f715 --- /dev/null +++ b/examples/server_example_threadless/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example_threadless_SRCS + server_example_threadless.c + static_model.c +) + +IF(WIN32) +set_source_files_properties(${server_example_threadless_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(WIN32) + +add_executable(server_example_threadless + ${server_example_threadless_SRCS} +) + +target_link_libraries(server_example_threadless + iec61850 +) diff --git a/examples/server_example_threadless/Makefile b/examples/server_example_threadless/Makefile new file mode 100644 index 0000000..c0490fd --- /dev/null +++ b/examples/server_example_threadless/Makefile @@ -0,0 +1,31 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_threadless +PROJECT_SOURCES = server_example_threadless.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = simpleIO_direct_control.icd + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +LDLIBS += -lm + +CP = cp + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + $(CP) $(PROJECT_BINARY_NAME) vmd-filestore/IEDSERVER.BIN + +clean: + rm -f $(PROJECT_BINARY_NAME) + rm -f vmd-filestore/IEDSERVER.BIN + + diff --git a/examples/server_example_threadless/server_example_threadless.c b/examples/server_example_threadless/server_example_threadless.c new file mode 100644 index 0000000..7f1f5c8 --- /dev/null +++ b/examples/server_example_threadless/server_example_threadless.c @@ -0,0 +1,153 @@ +/* + * server_example_single_threaded.c + * + * - How to use the single-threaded execution model + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include +#include + +#include "static_model.h" + +/* import IEC 61850 device model created from SCL-File */ +extern IedModel iedModel; + +static int running = 0; +static IedServer iedServer = NULL; + +void +sigint_handler(int signalId) +{ + running = 0; +} + +ControlHandlerResult +controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) +{ + + if (MmsValue_getType(value) == MMS_BOOLEAN) { + printf("received binary control command: "); + + if (MmsValue_getBoolean(value)) + printf("on\n"); + else + printf("off\n"); + } + else + return CONTROL_RESULT_FAILED; + + uint64_t timeStamp = Hal_getTimeInMs(); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + } + + return CONTROL_RESULT_OK; +} + +int +main(int argc, char** argv) +{ + + iedServer = IedServer_create(&iedModel); + + /* Install handler for operate command */ + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + /* MMS server will be instructed to start listening to client connections. */ + IedServer_startThreadless(iedServer, 102); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float t = 0.f; + + uint64_t lastTimestamp = Hal_getTimeInMs(); + + while (running) { + uint64_t timestamp = Hal_getTimeInMs(); + + if (timestamp - lastTimestamp >= 100) { + + t += 0.1f; + + float an1 = sinf(t); + float an2 = sinf(t + 1.f); + float an3 = sinf(t + 2.f); + float an4 = sinf(t + 3.f); + + IedServer_lockDataModel(iedServer); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, timestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, timestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, timestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3); + + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, timestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4); + + IedServer_unlockDataModel(iedServer); + + lastTimestamp = timestamp; + } + + /* Has to be called whenever the TCP stack receives data */ + IedServer_processIncomingData(iedServer); + + /* Has to be called periodically */ + IedServer_performPeriodicTasks(iedServer); + + Thread_sleep(1); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stopThreadless(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); +} /* main() */ diff --git a/examples/server_example_threadless/simpleIO_direct_control.icd b/examples/server_example_threadless/simpleIO_direct_control.icd new file mode 100644 index 0000000..d17242c --- /dev/null +++ b/examples/server_example_threadless/simpleIO_direct_control.icd @@ -0,0 +1,255 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + MZ Automation + + + 0.7.3 + + + libiec61850 server example + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/examples/server_example_threadless/static_model.c b/examples/server_example_threadless/static_model.c new file mode 100644 index 0000000..10cab57 --- /dev/null +++ b/examples/server_example_threadless/static_model.c @@ -0,0 +1,2028 @@ +/* + * static_model.c + * + * automatically generated from simpleIO_direct_control.icd + */ +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +static void initializeValues(); +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + +extern DataSet ds_GenericIO_LLN0_Events; +extern DataSet ds_GenericIO_LLN0_Events2; + + +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda0; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda1; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; +extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda1 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda2 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events_fcda3 +}; + +DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$stVal", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_GenericIO_LLN0_Events = { + "GenericIO", + "LLN0$Events", + 4, + &ds_GenericIO_LLN0_Events_fcda0, + &ds_GenericIO_LLN0_Events2 +}; + +extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda0; +extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda1; +extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda2; +extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda3; + +DataSetEntry ds_GenericIO_LLN0_Events2_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events2_fcda1 +}; + +DataSetEntry ds_GenericIO_LLN0_Events2_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events2_fcda2 +}; + +DataSetEntry ds_GenericIO_LLN0_Events2_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3", + -1, + NULL, + NULL, + &ds_GenericIO_LLN0_Events2_fcda3 +}; + +DataSetEntry ds_GenericIO_LLN0_Events2_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4", + -1, + NULL, + NULL, + NULL +}; + +DataSet ds_GenericIO_LLN0_Events2 = { + "GenericIO", + "LLN0$Events2", + 4, + &ds_GenericIO_LLN0_Events2_fcda0, + NULL +}; + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0 +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, +}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_EX, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, +}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + IEC61850_FC_ST, + INT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + IEC61850_FC_DC, + VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + IEC61850_FC_MX, + CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + IEC61850_FC_MX, + FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + IEC61850_FC_MX, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + IEC61850_FC_MX, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO4 = { + DataObjectModelType, + "SPCSO4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat, + 0, + IEC61850_FC_CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent, + NULL, + 0, + IEC61850_FC_CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + NULL, + 0, + IEC61850_FC_CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T, + NULL, + 0, + IEC61850_FC_CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test, + NULL, + 0, + IEC61850_FC_CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check, + NULL, + 0, + IEC61850_FC_CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + NULL, + 0, + IEC61850_FC_CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t, + NULL, + 0, + IEC61850_FC_CF, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + IEC61850_FC_ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + IEC61850_FC_ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + IEC61850_FC_ST, + TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_GenericIO_LLN0_report0; +extern ReportControlBlock iedModel_GenericIO_LLN0_report1; +extern ReportControlBlock iedModel_GenericIO_LLN0_report2; +extern ReportControlBlock iedModel_GenericIO_LLN0_report3; + +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; +ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2}; +ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3}; +ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 8, 111, 50, 1000, NULL}; + + + + +IedModel iedModel = { + "simpleIO", + &iedModel_GenericIO, + &ds_GenericIO_LLN0_Events, + &iedModel_GenericIO_LLN0_report0, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_LLN0_NamPlt_vendor.mmsValue = MmsValue_newVisibleString("MZ Automation"); + +iedModel_GenericIO_LLN0_NamPlt_swRev.mmsValue = MmsValue_newVisibleString("0.7.3"); + +iedModel_GenericIO_LLN0_NamPlt_d.mmsValue = MmsValue_newVisibleString("libiec61850 server example"); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); +} diff --git a/examples/server_example_threadless/static_model.h b/examples/server_example_threadless/static_model.h new file mode 100644 index 0000000..b5670e9 --- /dev/null +++ b/examples/server_example_threadless/static_model.h @@ -0,0 +1,301 @@ +/* + * static_model.h + * + * automatically generated from simpleIO_direct_control.icd + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/examples/server_example_threadless/vmd-filestore/SYSTEM.BIN b/examples/server_example_threadless/vmd-filestore/SYSTEM.BIN new file mode 100644 index 0000000..e69de29 diff --git a/make/common_targets.mk b/make/common_targets.mk new file mode 100644 index 0000000..6e5fb1f --- /dev/null +++ b/make/common_targets.mk @@ -0,0 +1,7 @@ +$(LIB_NAME): + cd $(LIBIEC_HOME); $(MAKE) -f Makefile + +lib: $(LIB_NAME) + +libclean: clean + cd $(LIBIEC_HOME); $(MAKE) -f Makefile clean diff --git a/make/stack_includes.mk b/make/stack_includes.mk new file mode 100644 index 0000000..28e1291 --- /dev/null +++ b/make/stack_includes.mk @@ -0,0 +1,9 @@ +INCLUDES = -I$(LIBIEC_HOME)/config +INCLUDES += -I$(LIBIEC_HOME)/src/common/inc +INCLUDES += -I$(LIBIEC_HOME)/src/mms/inc +INCLUDES += -I$(LIBIEC_HOME)/src/mms/inc_private +INCLUDES += -I$(LIBIEC_HOME)/src/mms/asn1 +INCLUDES += -I$(LIBIEC_HOME)/src/iec61850/inc +INCLUDES += -I$(LIBIEC_HOME)/src/iec61850/inc_private +INCLUDES += -I$(LIBIEC_HOME)/src/hal/inc +INCLUDES += -I$(LIBIEC_HOME)/src/goose diff --git a/make/target_system.mk b/make/target_system.mk new file mode 100644 index 0000000..c7edf35 --- /dev/null +++ b/make/target_system.mk @@ -0,0 +1,169 @@ +UNAME := $(shell uname) + +MIPSEL_TOOLCHAIN_PREFIX=mipsel-openwrt-linux- +# ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +#ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi- +#ARM_TOOLCHAIN_PREFIX=arm-poky-linux-gnueabi- +ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi- +UCLINUX_ARM_TOOLCHAIN_PREFIX=arm-uclinux-elf- +MINGW_TOOLCHAIN_PREFIX=i586-mingw32msvc- +#MINGW_TOOLCHAIN_PREFIX=x86_64-w64-mingw32- +MINGW64_TOOLCHAIN_PREFIX=x86_64-w64-mingw32- + +#POWERPC_TOOLCHAIN_PREFIX=powerpc-poky-linux- +POWERPC_TOOLCHAIN_PREFIX=powerpc-linux-gnu- + +ifndef TARGET +ifeq ($(UNAME), Linux) +TARGET=POSIX +else ifeq ($(findstring MINGW,$(UNAME)), MINGW) +TARGET=WIN32 +else ifeq ($(UNAME), Darwin) +TARGET=BSD +else ifeq ($(UNAME), FreeBSD) +TARGET=BSD +endif +endif + +ifeq ($(TARGET), WIN32) +WINDOWS=1 +endif + +ifeq ($(TARGET), WIN64) +WINDOWS=1 +endif + +ifdef WINDOWS +ifeq ($(UNAME), Linux) +ifeq ($(TARGET), WIN32) +TOOLCHAIN_PREFIX=$(MINGW_TOOLCHAIN_PREFIX) +endif +ifeq ($(TARGET), WIN64) +TOOLCHAIN_PREFIX=$(MINGW64_TOOLCHAIN_PREFIX) +endif +else +TOOLCHAIN_PREFIX= +endif +endif + +ifeq ($(TARGET), LINUX-POWERPC) +TOOLCHAIN_PREFIX=$(POWERPC_TOOLCHAIN_PREFIX) +endif + +ifeq ($(TARGET), LINUX-MIPSEL) +TOOLCHAIN_PREFIX=$(MIPSEL_TOOLCHAIN_PREFIX) +endif + +ifeq ($(TARGET), LINUX-ARM) +TOOLCHAIN_PREFIX=$(ARM_TOOLCHAIN_PREFIX) +endif + +ifeq ($(TARGET), UCLINUX-WAGO) +TOOLCHAIN_PREFIX=$(UCLINUX_ARM_TOOLCHAIN_PREFIX) +CFLAGS += -msoft-float +CFLAGS += -Wall +CFLAGS += -DEMBED +CFLAGS += -Dlinux -D__linux__ -Dunix +CFLAGS += -D__uClinux__ +CFLAGS += -DTARGET=UCLINUX-WAGO +LDFLAGS += -Wl,-move-rodata -Wl,-elf2flt +endif + +ifdef WINDOWS +HAL_IMPL = WIN32 +LIB_OBJS_DIR = $(LIBIEC_HOME)/build_win32 +CFLAGS=-g -DWIN32 + +ifeq ($(TARGET), WIN32) +CFLAGS+=-m32 +endif + +ifeq ($(TARGET), WIN64) +CFLAGS+=-m64 +endif + +LDLIBS=-lws2_32 +DYNLIB_LDFLAGS=-Wl,-no-undefined -Wl,--enable-runtime-pseudo-reloc -Wl,--output-def,libiec61850.def,--out-implib,libiec61850.a + + +# on Windows: only compile with ethernet support if winpcap files are in third_party/winpcap! +ifneq (, $(wildcard $(LIBIEC_HOME)/third_party/winpcap/Include/.)) + +ifeq ($(TARGET), WIN64) +LDFLAGS += -L$(LIBIEC_HOME)/third_party/winpcap/Lib/x64 +else +LDFLAGS += -L$(LIBIEC_HOME)/third_party/winpcap/Lib +endif + +LDLIBS+=-liphlpapi -lwpcap +else +$(warning winpcap not found - will build without GOOSE support!) +CFLAGS += -DEXCLUDE_ETHERNET_WINDOWS +EXCLUDE_ETHERNET_WINDOWS = 1 +endif + + +else +ifeq ($(TARGET), BSD) +HAL_IMPL = BSD +else +HAL_IMPL = POSIX +endif + +LDLIBS = -lpthread + +ifeq ($(TARGET), LINUX-MIPSEL) +LIB_OBJS_DIR = $(LIBIEC_HOME)/build-mipsel +else ifeq ($(TARGET), LINUX-ARM) +LIB_OBJS_DIR = $(LIBIEC_HOME)/build-arm +else ifeq ($(TARGET), UCLINUX-WAGO) +LIB_OBJS_DIR = $(LIBIEC_HOME)/build-wago +CFLAGS += -DTARGET_SYSTEM_UCLINUX_WAGO +else ifeq ($(TARGET), LINUX-POWERPC) +LIB_OBJS_DIR = $(LIBIEC_HOME)/build-powerpc +else +LIB_OBJS_DIR = $(LIBIEC_HOME)/build +endif + +CFLAGS += -g +#CFLAGS += -Os + +DYNLIB_LDFLAGS=-lpthread +endif + +ifneq ($(TARGET), CLANG-CHECK) +CC=$(TOOLCHAIN_PREFIX)gcc +CPP=$(TOOLCHAIN_PREFIX)g++ +endif + +ifeq ($(TARGET), BSD) +CC=cc +CPP=c++ +endif + +AR=$(TOOLCHAIN_PREFIX)ar +RANLIB=$(TOOLCHAIN_PREFIX)ranlib + + +ifeq ($(TARGET), WIN32) +PROJECT_BINARY_NAME := $(PROJECT_BINARY_NAME).exe +endif + +LIB_NAME = $(LIB_OBJS_DIR)/libiec61850.a + +ifeq ($(TARGET), BSD) +CFLAGS += -arch i386 +LDFLAGS += -arch i386 +endif + +ifeq ($(TARGET), WIN32) +DYN_LIB_NAME = $(LIB_OBJS_DIR)/iec61850.dll +else + +ifeq ($(TARGET), BSD) +DYN_LIB_NAME = $(LIB_OBJS_DIR)/libiec61850.dylib +else +DYN_LIB_NAME = $(LIB_OBJS_DIR)/libiec61850.so +endif + +endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..46dbfae --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,337 @@ + +set (lib_common_SRCS +./common/string_map.c +./common/array_list.c +./common/map.c +./common/linked_list.c +./common/byte_buffer.c +./common/lib_memory.c +./common/string_utilities.c +./common/buffer_chain.c +./common/conversions.c +./common/mem_alloc_linked_list.c +./common/simple_allocator.c +./mms/iso_server/iso_connection.c +./mms/iso_server/iso_server.c +./mms/iso_acse/acse.c +./mms/iso_mms/common/mms_type_spec.c +./mms/iso_mms/common/mms_value.c +./mms/iso_mms/common/mms_common_msg.c +./mms/iso_mms/client/mms_client_initiate.c +./mms/iso_mms/client/mms_client_write.c +./mms/iso_mms/client/mms_client_identify.c +./mms/iso_mms/client/mms_client_status.c +./mms/iso_mms/client/mms_client_named_variable_list.c +./mms/iso_mms/client/mms_client_connection.c +./mms/iso_mms/client/mms_client_files.c +./mms/iso_mms/client/mms_client_get_namelist.c +./mms/iso_mms/client/mms_client_get_var_access.c +./mms/iso_mms/client/mms_client_common.c +./mms/iso_mms/client/mms_client_read.c +./mms/iso_mms/server/mms_read_service.c +./mms/iso_mms/server/mms_file_service.c +./mms/iso_mms/server/mms_association_service.c +./mms/iso_mms/server/mms_identify_service.c +./mms/iso_mms/server/mms_status_service.c +./mms/iso_mms/server/mms_named_variable_list_service.c +./mms/iso_mms/server/mms_value_cache.c +./mms/iso_mms/server/mms_get_namelist_service.c +./mms/iso_mms/server/mms_access_result.c +./mms/iso_mms/server/mms_server.c +./mms/iso_mms/server/mms_server_common.c +./mms/iso_mms/server/mms_named_variable_list.c +./mms/iso_mms/server/mms_domain.c +./mms/iso_mms/server/mms_device.c +./mms/iso_mms/server/mms_information_report.c +./mms/iso_mms/server/mms_server_connection.c +./mms/iso_mms/server/mms_write_service.c +./mms/iso_mms/server/mms_get_var_access_service.c +./mms/iso_cotp/cotp.c +./mms/iso_presentation/iso_presentation.c +./mms/asn1/ber_decode.c +./mms/asn1/asn1_ber_primitive_value.c +./mms/asn1/ber_encoder.c +./mms/asn1/ber_integer.c +./mms/iso_client/iso_client_connection.c +./mms/iso_common/iso_connection_parameters.c +./mms/iso_session/iso_session.c +./iec61850/client/client_control.c +./iec61850/client/client_report_control.c +./iec61850/client/client_goose_control.c +./iec61850/client/client_report.c +./iec61850/client/ied_connection.c +./iec61850/common/iec61850_common.c +./iec61850/server/impl/ied_server.c +./iec61850/server/impl/client_connection.c +./iec61850/server/model/model.c +./iec61850/server/model/dynamic_model.c +./iec61850/server/model/cdc.c +./iec61850/server/model/config_file_parser.c +./iec61850/server/mms_mapping/control.c +./iec61850/server/mms_mapping/mms_mapping.c +./iec61850/server/mms_mapping/reporting.c +./iec61850/server/mms_mapping/mms_goose.c + +) + +set (lib_asn1c_SRCS +./mms/iso_mms/asn1c/DataAccessError.c +./mms/iso_mms/asn1c/DeleteNamedVariableListRequest.c +./mms/iso_mms/asn1c/constr_SET_OF.c +./mms/iso_mms/asn1c/MmsPdu.c +./mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.c +./mms/iso_mms/asn1c/BIT_STRING.c +./mms/iso_mms/asn1c/ber_tlv_tag.c +./mms/iso_mms/asn1c/constr_SEQUENCE_OF.c +./mms/iso_mms/asn1c/asn_SET_OF.c +./mms/iso_mms/asn1c/ReadResponse.c +./mms/iso_mms/asn1c/InformationReport.c +./mms/iso_mms/asn1c/ConfirmedServiceRequest.c +./mms/iso_mms/asn1c/DeleteNamedVariableListResponse.c +./mms/iso_mms/asn1c/asn_SEQUENCE_OF.c +./mms/iso_mms/asn1c/VariableAccessSpecification.c +./mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.c +./mms/iso_mms/asn1c/xer_support.c +./mms/iso_mms/asn1c/ObjectName.c +./mms/iso_mms/asn1c/NativeEnumerated.c +./mms/iso_mms/asn1c/per_encoder.c +./mms/iso_mms/asn1c/constr_SEQUENCE.c +./mms/iso_mms/asn1c/GetNameListResponse.c +./mms/iso_mms/asn1c/MMSString.c +./mms/iso_mms/asn1c/InitiateErrorPdu.c +./mms/iso_mms/asn1c/IndexRangeSeq.c +./mms/iso_mms/asn1c/ConfirmedErrorPDU.c +./mms/iso_mms/asn1c/UnconfirmedService.c +./mms/iso_mms/asn1c/UTF8String.c +./mms/iso_mms/asn1c/ServiceError.c +./mms/iso_mms/asn1c/TimeOfDay.c +./mms/iso_mms/asn1c/GetNameListRequest.c +./mms/iso_mms/asn1c/asn_codecs_prim.c +./mms/iso_mms/asn1c/Data.c +./mms/iso_mms/asn1c/ScatteredAccessDescription.c +./mms/iso_mms/asn1c/ReadRequest.c +./mms/iso_mms/asn1c/per_decoder.c +./mms/iso_mms/asn1c/Identifier.c +./mms/iso_mms/asn1c/ServiceSupportOptions.c +./mms/iso_mms/asn1c/Integer8.c +./mms/iso_mms/asn1c/ConfirmedServiceResponse.c +./mms/iso_mms/asn1c/ParameterSupportOptions.c +./mms/iso_mms/asn1c/Integer16.c +./mms/iso_mms/asn1c/ber_tlv_length.c +./mms/iso_mms/asn1c/OCTET_STRING.c +./mms/iso_mms/asn1c/DefineNamedVariableListRequest.c +./mms/iso_mms/asn1c/FloatingPoint.c +./mms/iso_mms/asn1c/xer_encoder.c +./mms/iso_mms/asn1c/Unsigned8.c +./mms/iso_mms/asn1c/BOOLEAN.c +./mms/iso_mms/asn1c/INTEGER.c +./mms/iso_mms/asn1c/UnconfirmedPDU.c +./mms/iso_mms/asn1c/DataSequence.c +./mms/iso_mms/asn1c/constraints.c +./mms/iso_mms/asn1c/der_encoder.c +./mms/iso_mms/asn1c/VisibleString.c +./mms/iso_mms/asn1c/InitiateResponsePdu.c +./mms/iso_mms/asn1c/StructComponent.c +./mms/iso_mms/asn1c/Address.c +./mms/iso_mms/asn1c/Unsigned16.c +./mms/iso_mms/asn1c/ber_decoder.c +./mms/iso_mms/asn1c/per_support.c +./mms/iso_mms/asn1c/WriteResponse.c +./mms/iso_mms/asn1c/InitRequestDetail.c +./mms/iso_mms/asn1c/InitiateRequestPdu.c +./mms/iso_mms/asn1c/DefineNamedVariableListResponse.c +./mms/iso_mms/asn1c/NULL.c +./mms/iso_mms/asn1c/ListOfVariableSeq.c +./mms/iso_mms/asn1c/UtcTime.c +./mms/iso_mms/asn1c/ConcludeResponsePDU.c +./mms/iso_mms/asn1c/AccessResult.c +./mms/iso_mms/asn1c/Integer32.c +./mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.c +./mms/iso_mms/asn1c/VariableSpecification.c +./mms/iso_mms/asn1c/Unsigned32.c +./mms/iso_mms/asn1c/constr_CHOICE.c +./mms/iso_mms/asn1c/AlternateAccess.c +./mms/iso_mms/asn1c/ObjectClass.c +./mms/iso_mms/asn1c/InitResponseDetail.c +./mms/iso_mms/asn1c/ConfirmedResponsePdu.c +./mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.c +./mms/iso_mms/asn1c/NativeInteger.c +./mms/iso_mms/asn1c/xer_decoder.c +./mms/iso_mms/asn1c/AlternateAccessSelection.c +./mms/iso_mms/asn1c/ConfirmedRequestPdu.c +./mms/iso_mms/asn1c/ConcludeRequestPDU.c +./mms/iso_mms/asn1c/WriteRequest.c +./mms/iso_mms/asn1c/RejectPDU.c +./mms/iso_mms/asn1c/TypeSpecification.c +./mms/iso_mms/asn1c/constr_TYPE.c +./mms/iso_mms/asn1c/GeneralizedTime.c +) + +set (lib_goose_SRCS +./goose/goose_subscriber.c +./goose/goose_receiver.c +./goose/goose_publisher.c +) + +set (lib_linux_SRCS +./hal/socket/linux/socket_linux.c +./hal/ethernet/linux/ethernet_linux.c +./hal/thread/linux/thread_linux.c +./hal/filesystem/linux/file_provider_linux.c +./hal/time/unix/time.c +) + +set (lib_windows_SRCS +./hal/socket/win32/socket_win32.c +./hal/ethernet/win32/ethernet_win32.c +./hal/thread/win32/thread_win32.c +./hal/filesystem/win32/file_provider_win32.c +./hal/time/win32/time.c +) + +set (lib_bsd_SRCS +./hal/socket/bsd/socket_bsd.c +./hal/ethernet/bsd/ethernet_bsd.c +./hal/thread/linux/thread_linux.c +./hal/filesystem/linux/file_provider_linux.c +./hal/time/unix/time.c +) + +IF(WIN32) + +if(EXISTS "../third_party/winpcap/Lib/wpcap.lib") +message("Found winpcap -> can compile with GOOSE support") +set(WITH_WPCAP 1) +endif() + +set_source_files_properties(${lib_asn1c_SRCS} + PROPERTIES LANGUAGE C) + +set_source_files_properties(${lib_common_SRCS} ${lib_windows_SRCS} + PROPERTIES LANGUAGE CXX) + +IF(WITH_WPCAP) +set_source_files_properties(${lib_goose_SRCS} + PROPERTIES LANGUAGE CXX) +ELSE() +add_definitions(-DEXCLUDE_ETHERNET_WINDOWS) +ENDIF() + +set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}\"/DEF:${CMAKE_CURRENT_SOURCE_DIR}/vs/libiec61850.def\"") + +include_directories( + ../third_party/winpcap/include +) + +IF(WITH_WPCAP) +set (library_SRCS + ${lib_common_SRCS} + ${lib_asn1c_SRCS} + ${lib_goose_SRCS} + ${lib_windows_SRCS} +) + +ELSE() +set (library_SRCS + ${lib_common_SRCS} + ${lib_asn1c_SRCS} + ${lib_windows_SRCS} +) + +ENDIF(WITH_WPCAP) + +ELSEIF(UNIX) +IF(APPLE) +set (library_SRCS + ${lib_common_SRCS} + ${lib_asn1c_SRCS} + ${lib_goose_SRCS} + ${lib_bsd_SRCS} +) +ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") +set (library_SRCS + ${lib_common_SRCS} + ${lib_asn1c_SRCS} + ${lib_goose_SRCS} + ${lib_bsd_SRCS} +) +ELSE() +set (library_SRCS + ${lib_common_SRCS} + ${lib_asn1c_SRCS} + ${lib_goose_SRCS} + ${lib_linux_SRCS} +) +ENDIF(APPLE) +ENDIF(WIN32) + + +include (GenerateExportHeader) + +add_library (iec61850-shared SHARED ${library_SRCS} ) + +set_target_properties(iec61850-shared PROPERTIES + OUTPUT_NAME iec61850 + SOVERSION "${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}" +) + + +GENERATE_EXPORT_HEADER(iec61850-shared + BASE_NAME iec61850-shared + EXPORT_MACRO_NAME iec61850-shared_EXPORT + EXPORT_FILE_NAME iec61850-shared_export.h + STATIC_DEFINE iec61850-shared_BUILT_AS_STATIC +) + +add_library (iec61850 STATIC ${library_SRCS}) + +IF(UNIX) + IF (CONFIG_SYSTEM_HAS_CLOCK_GETTIME) + target_link_libraries (iec61850 + -lpthread + -lm + -lrt + ) + ELSE () + target_link_libraries (iec61850 + -lpthread + -lm + ) + ENDIF (CONFIG_SYSTEM_HAS_CLOCK_GETTIME) +ENDIF(UNIX) + + +iF(WITH_WPCAP) +target_link_libraries(iec61850 + ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/lib/wpcap.lib + ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/lib/packet.lib +) +target_link_libraries(iec61850-shared + ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/lib/wpcap.lib + ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/lib/packet.lib +) + + +if(MSVC) + set_target_properties(iec61850-shared PROPERTIES + LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_SOURCE_DIR}/vs/libiec61850.def\"" + ) +endif() + + +ELSE(WITH_WPCAP) +if(MSVC) + set_target_properties(iec61850-shared PROPERTIES + LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_SOURCE_DIR}/vs/libiec61850-wo-goose.def\"" + ) +endif() +ENDIF(WITH_WPCAP) + + + +install (TARGETS iec61850 iec61850-shared + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib +) + diff --git a/src/common/array_list.c b/src/common/array_list.c new file mode 100644 index 0000000..ba9eb96 --- /dev/null +++ b/src/common/array_list.c @@ -0,0 +1,35 @@ +/* + * array_list.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "array_list.h" + +int +ArrayList_listSize(void** list) +{ + int size = 0; + + while (list[size] != NULL) + size++; + return size; +} diff --git a/src/common/buffer_chain.c b/src/common/buffer_chain.c new file mode 100644 index 0000000..9604314 --- /dev/null +++ b/src/common/buffer_chain.c @@ -0,0 +1,93 @@ +/* + * buffer_chain.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "buffer_chain.h" + +void +BufferChain_init(BufferChain self, int length, int partLength, BufferChain nextPart, uint8_t* buffer) +{ + self->length = length; + self->partLength = partLength; + self->partMaxLength = partLength; + self->nextPart = nextPart; + self->buffer = buffer; +} + +void +BufferChain_destroy(BufferChain self) +{ + BufferChain currentChainElement = self; + + while (currentChainElement != NULL) { + BufferChain nextChainElement = currentChainElement->nextPart; + GLOBAL_FREEMEM(currentChainElement); + currentChainElement = nextChainElement; + } +} + +int /* returns the number of bytes written to the buffer */ +BufferChain_dumpToBuffer(BufferChain self, uint8_t* buffer, int bufferMaxSize) +{ + if (self->length > bufferMaxSize) + return 0; + + BufferChain currentChain = self; + + int currentBufferIndex = 0; + + do { + int currentChainIndex = 0; + int currentPartLength = self->partLength; + + while (currentChainIndex < currentPartLength) + buffer[currentBufferIndex++] = self->buffer[currentChainIndex++]; + + currentChain = currentChain->nextPart; + } while (currentChain != NULL); + + return currentBufferIndex; +} + +void +MemoryArea_initialize(MemoryArea* self, uint8_t* memory, int size) +{ + self->memory = memory; + self->size = size; + self->currentPos = 0; +} + +uint8_t* +MemoryArea_getNextBlock(MemoryArea* self, int size) +{ + if ((self->size - self->currentPos) >= size) { + uint8_t* newBlock = self->memory + self->currentPos; + + self->currentPos += size; + return newBlock; + } + else + return NULL; + +} diff --git a/src/common/byte_buffer.c b/src/common/byte_buffer.c new file mode 100644 index 0000000..9c1a4f9 --- /dev/null +++ b/src/common/byte_buffer.c @@ -0,0 +1,123 @@ +/* + * byte_buffer.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "byte_buffer.h" + +ByteBuffer* +ByteBuffer_create(ByteBuffer* self, int maxSize) +{ + if (self == NULL) { + self = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + } + + self->buffer = (uint8_t*) GLOBAL_CALLOC(maxSize, sizeof(uint8_t)); + self->maxSize = maxSize; + self->size = 0; + + return self; +} + +void +ByteBuffer_destroy(ByteBuffer* self) +{ + GLOBAL_FREEMEM(self->buffer); + GLOBAL_FREEMEM(self); +} + +void +ByteBuffer_wrap(ByteBuffer* self, uint8_t* buf, int size, int maxSize) +{ + self->buffer = buf; + self->size = size; + self->maxSize = maxSize; +} + +int +ByteBuffer_append(ByteBuffer* self, uint8_t* data, int dataSize) +{ + if (self->size + dataSize <= self->maxSize) { + memcpy(self->buffer + self->size, data, dataSize); + self->size += dataSize; + return dataSize; + } + else + return -1; +} + +int +ByteBuffer_appendByte(ByteBuffer* self, uint8_t byte) +{ + if (self->size < self->maxSize) { + self->buffer[self->size] = byte; + self->size ++; + return 1; + } + else + return 0; +} + + +uint8_t* +ByteBuffer_getBuffer(ByteBuffer* self) +{ + return self->buffer; +} + +int +ByteBuffer_getMaxSize(ByteBuffer* self) +{ + return self->maxSize; +} + +int +ByteBuffer_getSize(ByteBuffer* self) +{ + return self->size; +} + +int +ByteBuffer_setSize(ByteBuffer* self, int size) +{ + if (size <= self->maxSize) + self->size = size; + + return self->size; +} + +#if 0 +void +ByteBuffer_print(ByteBuffer* self, char* message) +{ + printf("\n%s (size = %i):\n", message, self->size); + + int i; + for (i = 0; i < self->size; i++) { + printf("%02x ", self->buffer[i]); + if (((i + 1) % 16) == 0) printf("\n"); + else if (((i + 1) % 8) == 0) printf("| "); + + } + printf("\n"); +} +#endif diff --git a/src/common/conversions.c b/src/common/conversions.c new file mode 100644 index 0000000..9512722 --- /dev/null +++ b/src/common/conversions.c @@ -0,0 +1,280 @@ +/* + * conversions.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "conversions.h" + +#include + +#if defined TARGET +#if (TARGET == UCLINUX-WAGO) +time_t timegm (struct tm *tm) +{ + time_t ret; + char *tz; + + tz = getenv ("TZ"); + setenv ("TZ", "", 1); + tzset (); + ret = mktime (tm); + if (tz) + setenv ("TZ", tz, 1); + else + unsetenv ("TZ"); + tzset (); + return ret; +} + +#endif +#endif + +#ifdef _WIN32 + +time_t +timegm(struct tm* tm_time) +{ + return mktime(tm_time) - _timezone; +} + +#if defined(__MINGW32__) + +static inline // assuming gmtime is thread safe in windows! +struct tm* gmtime_r(const time_t* timep, struct tm* result) +{ + struct tm* t; + + t = gmtime(timep); + + if (t != NULL) + memcpy(result, t, sizeof (struct tm)); + + return result; +} + +#else + +#if defined(_MSC_VER) + +static inline +struct tm* gmtime_r(const time_t* timep, struct tm* result) +{ + gmtime_s(result, timep); + + return result; +} + +#else +#error "No gmtime_r available for platform!" +#endif + + +#endif + + +#endif + +void +Conversions_intToStringBuffer(int intValue, int numberOfDigits, uint8_t* buffer) +{ + int digitBase = 1; + + int i = 1; + + while (i < numberOfDigits) { + digitBase = digitBase * 10; + i++; + } + + int remainder = intValue; + + for (i = 0; i < numberOfDigits; i++) { + int digit = remainder / digitBase; + + buffer[i] = (uint8_t) (digit + 48); + + remainder = remainder % digitBase; + + digitBase = digitBase / 10; + } + + buffer[i] = 0; +} + +void +Conversions_msTimeToGeneralizedTime(uint64_t msTime, uint8_t* buffer) +{ + int msPart = (msTime % 1000); + + time_t unixTime = (msTime / 1000); + + struct tm tmTime; + + gmtime_r(&unixTime, &tmTime); + + Conversions_intToStringBuffer(tmTime.tm_year + 1900, 4, buffer); + + Conversions_intToStringBuffer(tmTime.tm_mon + 1, 2, buffer + 4); + Conversions_intToStringBuffer(tmTime.tm_mday, 2, buffer + 6); + Conversions_intToStringBuffer(tmTime.tm_hour, 2, buffer + 8); + Conversions_intToStringBuffer(tmTime.tm_min, 2, buffer + 10); + Conversions_intToStringBuffer(tmTime.tm_sec, 2, buffer + 12); + + buffer[14] = '.'; + + Conversions_intToStringBuffer(msPart, 3, buffer + 15); + + buffer[18] = 'Z'; + + buffer[19] = 0; +} + +static int +getSecondsOffset(const char* offsetString) +{ + int hourOffset = StringUtils_digitsToInt(offsetString, 2); + + if (hourOffset < 0) + return -1; + + int minOffset = StringUtils_digitsToInt(offsetString + 2, 2); + + if (minOffset < 0) + return -1; + + int secondsOffset = (hourOffset * (60 * 60)) + (minOffset * 60); + + return secondsOffset; +} + +uint64_t +Conversions_generalizedTimeToMsTime(const char* gtString) +{ + int gtStringLen = strlen(gtString); + + if (gtStringLen < 14) return -1; + + int year = StringUtils_digitsToInt(gtString, 4); + + if (year < 0) return -1; + + int month = StringUtils_digitsToInt(gtString + 4, 2); + + if (month < 0) return -1; + + int day = StringUtils_digitsToInt(gtString + 6, 2); + + if (day < 0) return -1; + + int hour = StringUtils_digitsToInt(gtString + 8, 2); + + if (hour < 0) return -1; + + int min = StringUtils_digitsToInt(gtString + 10, 2); + + if (min < 0) return -1; + + int seconds = StringUtils_digitsToInt(gtString + 12, 2); + if (seconds < 0) return -1; + + struct tm tmTime; + tmTime.tm_year = year - 1900; + tmTime.tm_mon = month - 1; + tmTime.tm_mday = day; + tmTime.tm_hour = hour; + tmTime.tm_min = min; + tmTime.tm_sec = seconds; + + int msOffset = 0; + + const char* parsePos = gtString + 14; + + /* parse optional fraction of second field */ + if (*(parsePos) == '.') { + parsePos++; + const char* fractionOfSecondStart = parsePos; + + int fractionOfSecondLen = 0; + + int secondValue = 1; + + while (StringUtils_isDigit(fractionOfSecondStart[fractionOfSecondLen])) { + fractionOfSecondLen++; + + secondValue = secondValue * 10; + } + + if (fractionOfSecondLen > 0) { + int fractionOfSecond = StringUtils_digitsToInt(fractionOfSecondStart, fractionOfSecondLen); + msOffset = (fractionOfSecond * 1000) / secondValue; + } + + parsePos += fractionOfSecondLen; + } + + + time_t t = 0; + + switch (*parsePos) { + case 0: /* treat time as localtime */ + t = mktime(&tmTime); + break; + case 'Z': /* treat time as GMT(UTC) time */ + t = timegm(&tmTime); + break; + case '+': /* subtract offset */ + { + t = timegm(&tmTime); + int secondsOffset = getSecondsOffset(parsePos + 1); + t = t - secondsOffset; + } + break; + case '-': /* add offset */ + { + t = timegm(&tmTime); + int secondsOffset = getSecondsOffset(parsePos + 1); + t = t + secondsOffset; + } + break; + default: + return -1; + } + + uint64_t msTime = t * 1000; + + msTime += msOffset; + + return msTime; +} + +void +memcpyReverseByteOrder(uint8_t* dst, const uint8_t* src, int size) +{ + int i = 0; + for (i = 0; i < size; i++) { + dst[i] = src[size - i - 1]; + } +} + + + + diff --git a/src/common/inc/array_list.h b/src/common/inc/array_list.h new file mode 100644 index 0000000..50245c9 --- /dev/null +++ b/src/common/inc/array_list.h @@ -0,0 +1,31 @@ +/* + * array_list.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ARRAY_LIST_H_ +#define ARRAY_LIST_H_ + +int +ArrayList_listSize(void** list); + + +#endif /* ARRAY_LIST_H_ */ diff --git a/src/common/inc/buffer_chain.h b/src/common/inc/buffer_chain.h new file mode 100644 index 0000000..9c335a8 --- /dev/null +++ b/src/common/inc/buffer_chain.h @@ -0,0 +1,75 @@ +/* + * buffer_chain.h + * + * Created on: Nov 10, 2013 + * Author: mzillgit + */ + +#ifndef BUFFER_CHAIN_H_ +#define BUFFER_CHAIN_H_ + +typedef struct sBufferChain* BufferChain; + +struct sBufferChain { + int length; + int partLength; + int partMaxLength; + uint8_t* buffer; + BufferChain nextPart; +}; + +void +BufferChain_init(BufferChain self, int length, int partLength, BufferChain nextPart, uint8_t* buffer); + +void +BufferChain_destroy(BufferChain self); + +int /* returns the number of bytes written to the buffer */ +BufferChain_dumpToBuffer(BufferChain self, uint8_t* buffer, int bufferMaxSize); + + +typedef struct { + uint8_t* memory; + int currentPos; + int size; +} MemoryArea; + +void +MemoryArea_initialize(MemoryArea* self, uint8_t* memory, int size); + +uint8_t* +MemoryArea_getNextBlock(MemoryArea* self, int size); + +#if 0 + +typedef struct sMemoryPool* MemoryPool; + +typedef struct sMemoryChunk MemoryChunk; + +struct sMemoryPool { + uint8_t* memory; + int size; + MemoryChunk firstChunk; +}; + +struct sMemoryChunk { + MemoryChunk previous; + MemoryChunk next; + uint8_t* data; + uint8_t free; + int size; +}; + +MemoryPool +MemoryPool_create(uint8_t* memoryAddress, int size); + +void +MemoryPool_destroy(MemoryPool self); + +MemoryChunk +MemoryPool_allocateChunk(MemoryPool self, int size); +MemoryPool_freeChunk(MemoryPool self, MemoryChunk chunk); + +#endif + +#endif /* BUFFER_CHAIN_H_ */ diff --git a/src/common/inc/byte_buffer.h b/src/common/inc/byte_buffer.h new file mode 100644 index 0000000..0358a9a --- /dev/null +++ b/src/common/inc/byte_buffer.h @@ -0,0 +1,74 @@ +/* + * byte_buffer.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef BYTE_BUFFER_H_ +#define BYTE_BUFFER_H_ + +#include "libiec61850_common_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint8_t* buffer; + int maxSize; + int size; +} ByteBuffer; + +ByteBuffer* +ByteBuffer_create(ByteBuffer* self, int maxSize); + +void +ByteBuffer_destroy(ByteBuffer* self); + +void +ByteBuffer_wrap(ByteBuffer* self, uint8_t* buf, int size, int maxSize); + +int +ByteBuffer_append(ByteBuffer* self, uint8_t* data, int dataSize); + +int +ByteBuffer_appendByte(ByteBuffer* self, uint8_t byte); + +uint8_t* +ByteBuffer_getBuffer(ByteBuffer* self); + +int +ByteBuffer_getSize(ByteBuffer* self); + +int +ByteBuffer_getMaxSize(ByteBuffer* self); + +int +ByteBuffer_setSize(ByteBuffer* self, int size); + +void +ByteBuffer_print(ByteBuffer* self, char* message); + +#ifdef __cplusplus +} +#endif + + +#endif /* BYTE_BUFFER_H_ */ diff --git a/src/common/inc/conversions.h b/src/common/inc/conversions.h new file mode 100644 index 0000000..03b1269 --- /dev/null +++ b/src/common/inc/conversions.h @@ -0,0 +1,43 @@ +/* + * conversions.h + * + * Some helper functions to convert data. + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef CONVERSIONS_H_ +#define CONVERSIONS_H_ + +#include "libiec61850_platform_includes.h" + +void +Conversions_intToStringBuffer(int intValue, int numberOfDigits, uint8_t* buffer); + +void +Conversions_msTimeToGeneralizedTime(uint64_t msTime, uint8_t* buffer); + +uint64_t +Conversions_generalizedTimeToMsTime(const char* gtString); + +void +memcpyReverseByteOrder(uint8_t* dst, const uint8_t* src, int size); + +#endif /* CONVERSIONS_H_ */ diff --git a/src/common/inc/lib_memory.h b/src/common/inc/lib_memory.h new file mode 100644 index 0000000..506a24c --- /dev/null +++ b/src/common/inc/lib_memory.h @@ -0,0 +1,65 @@ +/* + * memory.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#define CALLOC(nmemb, size) Memory_calloc(nmemb, size) +#define MALLOC(size) Memory_malloc(size) +#define REALLOC(oldptr, size) Memory_realloc(oldptr, size) +#define FREEMEM(ptr) Memory_free(ptr) + +#define GLOBAL_CALLOC(nmemb, size) Memory_calloc(nmemb, size) +#define GLOBAL_MALLOC(size) Memory_malloc(size) +#define GLOBAL_REALLOC(oldptr, size) Memory_realloc(oldptr, size) +#define GLOBAL_FREEMEM(ptr) Memory_free(ptr) + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef void +(*MemoryExceptionHandler) (void* parameter); + +void +Memory_installExceptionHandler(MemoryExceptionHandler handler, void* parameter); + +void* +Memory_malloc(size_t size); + +void* +Memory_calloc(size_t nmemb, size_t size); + +void * +Memory_realloc(void *ptr, size_t size); + +void +Memory_free(void* memb); + +#ifdef __cplusplus +} +#endif + +#endif /* MEMORY_H_ */ diff --git a/src/common/inc/libiec61850_common_api.h b/src/common/inc/libiec61850_common_api.h new file mode 100644 index 0000000..eb82865 --- /dev/null +++ b/src/common/inc/libiec61850_common_api.h @@ -0,0 +1,23 @@ +/* + * libiec61850_common_api_includes.h + */ + +#ifndef LIBIEC61850_COMMON_API_INCLUDES_H_ +#define LIBIEC61850_COMMON_API_INCLUDES_H_ + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#define ATTRIBUTE_PACKED __attribute__ ((__packed__)) +#else +#define ATTRIBUTE_PACKED +#endif + +#include "hal_time.h" +#include "mms_value.h" + +#endif /* LIBIEC61850_COMMON_API_INCLUDES_H_ */ diff --git a/src/common/inc/libiec61850_platform_includes.h b/src/common/inc/libiec61850_platform_includes.h new file mode 100644 index 0000000..9a9f909 --- /dev/null +++ b/src/common/inc/libiec61850_platform_includes.h @@ -0,0 +1,40 @@ +/* + * libiec61850_platform_includes.h + */ + +#ifndef LIBIEC61850_PLATFORM_INCLUDES_H_ +#define LIBIEC61850_PLATFORM_INCLUDES_H_ + +#include "libiec61850_common_api.h" + +#include "string_utilities.h" +#include +#include +#include +#include + +#include "platform_endian.h" + +#define LIBIEC61850_VERSION "0.8.7" + +#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME +#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" +#endif + +#ifndef CONFIG_DEFAULT_MMS_MODEL_NAME +#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" +#endif + +#ifndef CONFIG_DEFAULT_MMS_REVISION +#define CONFIG_DEFAULT_MMS_REVISION LIBIEC61850_VERSION +#endif + +#if (DEBUG != 1) +#define NDEBUG 1 +#endif + +#include + +#include "lib_memory.h" + +#endif /* LIBIEC61850_PLATFORM_INCLUDES_H_ */ diff --git a/src/common/inc/linked_list.h b/src/common/inc/linked_list.h new file mode 100644 index 0000000..4309e9a --- /dev/null +++ b/src/common/inc/linked_list.h @@ -0,0 +1,180 @@ +/* + * linked_list.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef LINKED_LIST_H_ +#define LINKED_LIST_H_ + +#include "libiec61850_common_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup common_api_group + */ +/**@{*/ + +/** + * \defgroup LINKED_LIST LinkedList data type definition and handling functions + */ +/**@{*/ + + +struct sLinkedList { + void* data; + struct sLinkedList* next; +}; + +/** + * \brief Reference to a linked list or to a linked list element. + */ +typedef struct sLinkedList* LinkedList; + +/** + * \brief Create a new LinkedList object + * + * \return the newly created LinkedList instance + */ +LinkedList +LinkedList_create(void); + +/** + * \brief Delete a LinkedList object + * + * This function destroy the LinkedList object. It will free all data structures used by the LinkedList + * instance. It will call free for all elements of the linked list. This function should only be used if + * simple objects (like dynamically allocated strings) are stored in the linked list. + * + * \param self the LinkedList instance + */ +void +LinkedList_destroy(LinkedList self); + + +typedef void (*LinkedListValueDeleteFunction) (void*); + +/** + * \brief Delete a LinkedList object + * + * This function destroy the LinkedList object. It will free all data structures used by the LinkedList + * instance. It will call a user provided function for each data element. This user provided function is + * responsible to properly free the data element. + * + * \param self the LinkedList instance + * \param valueDeleteFunction a function that is called for each data element of the LinkedList with the pointer + * to the linked list data element. + */ +void +LinkedList_destroyDeep(LinkedList self, LinkedListValueDeleteFunction valueDeleteFunction); + +/** + * \brief Delete a LinkedList object without freeing the element data + * + * This function should be used statically allocated data objects are stored in the LinkedList instance. + * Other use cases would be if the data elements in the list should not be deleted. + * + * \param self the LinkedList instance + */ +void +LinkedList_destroyStatic(LinkedList self); + +/** + * \brief Add a new element to the list + * + * This function will add a new data element to the list. The new element will the last element in the + * list. + * + * \param self the LinkedList instance + * \param data data to append to the LinkedList instance + */ +void +LinkedList_add(LinkedList self, void* data); + +/** + * \brief Removed the specified element from the list + * + * \param self the LinkedList instance + * \param data data to remove from the LinkedList instance + */ +bool +LinkedList_remove(LinkedList self, void* data); + +/** + * \brief Get the list element specified by index (starting with 0). + * + * \param self the LinkedList instance + * \param index index of the requested element. + */ +LinkedList +LinkedList_get(LinkedList self, int index); + +/** + * \brief Get the next element in the list (iterator). + * + * \param self the LinkedList instance + */ +LinkedList +LinkedList_getNext(LinkedList self); + +/** + * \brief Get the last element in the list. + * + * \param listElement the LinkedList instance + */ +LinkedList +LinkedList_getLastElement(LinkedList self); + +/** + * \brief Insert a new element int the list + * + * \param listElement the LinkedList instance + */ +LinkedList +LinkedList_insertAfter(LinkedList listElement, void* data); + +/** + * \brief Get the size of the list + * + * \param self the LinkedList instance + * + * \return number of data elements stored in the list + */ +int +LinkedList_size(LinkedList self); + +void* +LinkedList_getData(LinkedList self); + +void +LinkedList_printStringList(LinkedList self); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LINKED_LIST_H_ */ diff --git a/src/common/inc/map.h b/src/common/inc/map.h new file mode 100644 index 0000000..9b34014 --- /dev/null +++ b/src/common/inc/map.h @@ -0,0 +1,64 @@ +/* + * map.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MAP_H_ +#define MAP_H_ + +#include "libiec61850_platform_includes.h" +#include "linked_list.h" + +typedef struct sMap* Map; + +struct sMap { + LinkedList entries; + + /* client provided function to compare two keys */ + int (*compareKeys)(void* key1, void* key2); +}; + +Map +Map_create(void); + +int +Map_size(Map map); + +void* +Map_addEntry(Map map, void* key, void* value); + +void* +Map_removeEntry(Map map, void* key, bool deleteKey); + +void* +Map_getEntry(Map map, void* key); + +void +Map_delete(Map map, bool deleteKey); + +void +Map_deleteStatic(Map map, bool deleteKey); + +void +Map_deleteDeep(Map map, bool deleteKey, void (*valueDeleteFunction) (void*)); + + +#endif /* MAP_H_ */ diff --git a/src/common/inc/mem_alloc_linked_list.h b/src/common/inc/mem_alloc_linked_list.h new file mode 100644 index 0000000..df88f88 --- /dev/null +++ b/src/common/inc/mem_alloc_linked_list.h @@ -0,0 +1,50 @@ +/* + * mem_alloc_linked_list.h + * + * Implementation of linked list (LinkedList) that uses the provided memory buffer as + * memory pool for storage allocation. + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MEM_ALLOC_LINKED_LIST_H_ +#define MEM_ALLOC_LINKED_LIST_H_ + +#include "libiec61850_common_api.h" +#include "linked_list.h" +#include "simple_allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sMemAllocLinkedList* MemAllocLinkedList; + +MemAllocLinkedList +MemAllocLinkedList_create(MemoryAllocator* ma); + +LinkedList +MemAllocLinkedList_add(MemAllocLinkedList list, void* data); + +#endif /* MEM_ALLOC_LINKED_LIST_H_ */ + +#ifdef __cplusplus +} +#endif diff --git a/src/common/inc/simple_allocator.h b/src/common/inc/simple_allocator.h new file mode 100644 index 0000000..7158ac7 --- /dev/null +++ b/src/common/inc/simple_allocator.h @@ -0,0 +1,39 @@ +/* + * simple_allocator.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef SIMPLE_ALLOCATOR_H_ +#define SIMPLE_ALLOCATOR_H_ + +typedef struct { + char* memoryBlock; + char* currentPtr; + int size; +} MemoryAllocator; + +void +MemoryAllocator_init(MemoryAllocator* self, char* memoryBlock, int size); + +char* +MemoryAllocator_allocate(MemoryAllocator* self, int size); + +#endif /* SIMPLE_ALLOCATOR_H_ */ diff --git a/src/common/inc/string_map.h b/src/common/inc/string_map.h new file mode 100644 index 0000000..499778b --- /dev/null +++ b/src/common/inc/string_map.h @@ -0,0 +1,28 @@ +/* + * string_map.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "map.h" + +Map +StringMap_create(void); + diff --git a/src/common/inc/string_utilities.h b/src/common/inc/string_utilities.h new file mode 100644 index 0000000..7c46d67 --- /dev/null +++ b/src/common/inc/string_utilities.h @@ -0,0 +1,110 @@ +/* + * string_utilities.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef STRING_UTILITIES_H_ +#define STRING_UTILITIES_H_ + +#include "libiec61850_platform_includes.h" +#include "linked_list.h" + +char* +copyString(const char* string); + +char* +copyStringToBuffer(const char* string, char* buffer); + +char* +copySubString(char* startPos, char* endPos); + +/** + * \brief Concatenate strings. count indicates the number of strings + * to concatenate. + */ +char* +createString(int count, ...); + +/** + * \brief Concatenate strings in user provided buffer. count indicates the number of strings + * to concatenate. + */ +char* +StringUtils_createStringInBuffer(char* buffer, int count, ...); + +char* +createStringFromBuffer(const uint8_t* buf, int size); + +char* +StringUtils_createStringFromBufferInBuffer(char* newString, const uint8_t* buf, int size); + +void +StringUtils_replace(char* string, char oldChar, char newChar); + +bool +StringUtils_isDigit(char character); + +int +StringUtils_digitToInt(char digit); + +int +StringUtils_digitsToInt(const char* digits, int count); + +int +StringUtils_createBufferFromHexString(char* hexString, uint8_t* buffer); + +/** + * \brief test if string starts with prefix + */ +bool +StringUtils_startsWith(char* string, char* prefix); + +/** + * \brief Compare to characters using the collation order as defined in ISO 9506-2 7.5.2 + * + * \param a the first string + * \param b the second string + * + * \returns 0 if a equals b; a positive number if b > a; a negative number if b < a + */ +int +StringUtils_compareChars(char a, char b); + +/** + * \brief Compare to strings using the collation order as defined in ISO 9506-2 7.5.2 + * + * \param a the first string + * \param b the second string + * + * \returns 0 if a equals b; a positive number if b > a; a negative number if b < a + */ +int +StringUtils_compareStrings(const char* a, const char* b); + +/** + * \brief sort a list of strings alphabetically (according to the MMS identifier collation order) + * + * \param list a list that contains string elements + */ +void +StringUtils_sortList(LinkedList list); + +#endif /* STRING_UTILITIES_H_ */ diff --git a/src/common/lib_memory.c b/src/common/lib_memory.c new file mode 100644 index 0000000..0a4106b --- /dev/null +++ b/src/common/lib_memory.c @@ -0,0 +1,83 @@ +/* + * lib_memory.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +static MemoryExceptionHandler exceptionHandler = NULL; +static void* exceptionHandlerParameter = NULL; + +static void +noMemoryAvailableHandler(void) +{ + if (exceptionHandler != NULL) + exceptionHandler(exceptionHandlerParameter); +} + +void +Memory_installExceptionHandler(MemoryExceptionHandler handler, void* parameter) +{ + exceptionHandler = handler; + exceptionHandlerParameter = parameter; +} + +void* +Memory_malloc(size_t size) +{ + void* memory = malloc(size); + + if (memory == NULL) + noMemoryAvailableHandler(); + + return memory; +} + + +void* +Memory_calloc(size_t nmemb, size_t size) +{ + void* memory = calloc(nmemb, size); + + if (memory == NULL) + noMemoryAvailableHandler(); + + return memory; +} + + +void * +Memory_realloc(void *ptr, size_t size) +{ + void* memory = realloc(ptr, size); + + if (memory == NULL) + noMemoryAvailableHandler(); + + return memory; +} + +void +Memory_free(void* memb) +{ + free(memb); +} + diff --git a/src/common/linked_list.c b/src/common/linked_list.c new file mode 100644 index 0000000..65c88bd --- /dev/null +++ b/src/common/linked_list.c @@ -0,0 +1,200 @@ +/* + * linked_list.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "linked_list.h" + +LinkedList +LinkedList_getLastElement(LinkedList list) +{ + while (list->next != NULL) { + list = list->next; + } + return list; +} + +LinkedList +LinkedList_create() +{ + LinkedList newList; + + newList = (LinkedList) GLOBAL_MALLOC(sizeof(struct sLinkedList)); + newList->data = NULL; + newList->next = NULL; + + return newList; +} + +/** + * Destroy list (free). Also frees element data with helper function. + */ +void +LinkedList_destroyDeep(LinkedList list, LinkedListValueDeleteFunction valueDeleteFunction) +{ + LinkedList nextElement = list; + LinkedList currentElement; + + do { + currentElement = nextElement; + nextElement = currentElement->next; + + if (currentElement->data != NULL) + valueDeleteFunction(currentElement->data); + + GLOBAL_FREEMEM(currentElement); + } + while (nextElement != NULL); +} + +void +LinkedList_destroy(LinkedList list) +{ + LinkedList_destroyDeep(list, Memory_free); +} + +/** + * Destroy list (free) without freeing the element data + */ +void +LinkedList_destroyStatic(LinkedList list) +{ + LinkedList nextElement = list; + LinkedList currentElement; + + do { + currentElement = nextElement; + nextElement = currentElement->next; + GLOBAL_FREEMEM(currentElement); + } + while (nextElement != NULL); +} + +int +LinkedList_size(LinkedList list) +{ + LinkedList nextElement = list; + int size = 0; + + while (nextElement->next != NULL) { + nextElement = nextElement->next; + size++; + } + + return size; +} + +void +LinkedList_add(LinkedList list, void* data) +{ + LinkedList newElement = LinkedList_create(); + + newElement->data = data; + + LinkedList listEnd = LinkedList_getLastElement(list); + + listEnd->next = newElement; +} + +bool +LinkedList_remove(LinkedList list, void* data) +{ + LinkedList lastElement = list; + + LinkedList currentElement = list->next; + + while (currentElement != NULL) { + if (currentElement->data == data) { + lastElement->next = currentElement->next; + GLOBAL_FREEMEM(currentElement); + return true; + } + + lastElement = currentElement; + currentElement = currentElement->next; + } + + return false; +} + +LinkedList +LinkedList_insertAfter(LinkedList list, void* data) +{ + LinkedList originalNextElement = LinkedList_getNext(list); + + LinkedList newElement = LinkedList_create(); + + newElement->data = data; + newElement->next = originalNextElement; + + list->next = newElement; + + return newElement; +} + +LinkedList +LinkedList_getNext(LinkedList list) +{ + return list->next; +} + +LinkedList +LinkedList_get(LinkedList list, int index) +{ + LinkedList element = LinkedList_getNext(list); + + int i = 0; + + while (i < index) { + element = LinkedList_getNext(element); + + if (element == NULL) + return NULL; + + i++; + } + + return element; +} + +void* +LinkedList_getData(LinkedList self) +{ + return self->data; +} + +void +LinkedList_printStringList(LinkedList list) +{ + LinkedList element = list; + + int elementCount = 0; + + while ((element = LinkedList_getNext(element)) != NULL) { + char* str = (char*) (element->data); + printf("%s\n", str); + elementCount++; + } +} + + + diff --git a/src/common/map.c b/src/common/map.c new file mode 100644 index 0000000..d0ab9e3 --- /dev/null +++ b/src/common/map.c @@ -0,0 +1,159 @@ +/* + * map.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "map.h" + +typedef struct sMapEntry +{ + void* key; + void* value; +} MapEntry; + +static int +comparePointerKeys(void* key1, void* key2) +{ + if (key2 == key1) + return 0; + else + return -1; +} + +Map +Map_create() +{ + Map map = (Map) GLOBAL_CALLOC(1, sizeof(struct sMap)); + map->entries = LinkedList_create(); + map->compareKeys = comparePointerKeys; + return map; +} + +int +Map_size(Map map) +{ + return LinkedList_size(map->entries); +} + +void* +Map_addEntry(Map map, void* key, void* value) +{ + MapEntry* entry = (MapEntry*) GLOBAL_MALLOC(sizeof(MapEntry)); + entry->key = key; + entry->value = value; + LinkedList_add(map->entries, entry); + + return entry->key; +} + +void* +Map_removeEntry(Map map, void* key, bool deleteKey) +{ + LinkedList element = map->entries; + LinkedList lastElement = element; + MapEntry* entry; + void* value = NULL; + + while ((element = LinkedList_getNext(element)) != NULL) { + entry = (MapEntry*) element->data; + + if (map->compareKeys(key, entry->key) == 0) { + lastElement->next = element->next; + value = entry->value; + + if (deleteKey == true) + GLOBAL_FREEMEM(entry->key); + GLOBAL_FREEMEM(entry); + GLOBAL_FREEMEM(element); + + break; + } + + lastElement = element; + } + + return value; +} + +void* +Map_getEntry(Map map, void* key) +{ + LinkedList element = map->entries; + + while ((element = LinkedList_getNext(element)) != NULL) { + MapEntry* entry = (MapEntry*) element->data; + if (map->compareKeys(key, entry->key) == 0) { + return entry->value; + }; + } + + return NULL; +} + +void +Map_delete(Map map, bool deleteKey) +{ + LinkedList element = map->entries; + + while ((element = LinkedList_getNext(element)) != NULL) { + MapEntry* entry = (MapEntry*) element->data; + if (deleteKey == true) + GLOBAL_FREEMEM(entry->key); + GLOBAL_FREEMEM(entry->value); + } + + LinkedList_destroy(map->entries); + GLOBAL_FREEMEM(map); +} + +void +Map_deleteStatic(Map map, bool deleteKey) +{ + LinkedList element = map->entries; + + if (deleteKey == true) { + while ((element = LinkedList_getNext(element)) != NULL) { + MapEntry* entry = (MapEntry*) element->data; + GLOBAL_FREEMEM(entry->key); + } + } + + LinkedList_destroy(map->entries); + GLOBAL_FREEMEM(map); +} + +void +Map_deleteDeep(Map map, bool deleteKey, void +(*valueDeleteFunction)(void*)) +{ + LinkedList element = map->entries; + + while ((element = LinkedList_getNext(element)) != NULL) { + MapEntry* entry = (MapEntry*) element->data; + if (deleteKey == true) + GLOBAL_FREEMEM(entry->key); + valueDeleteFunction(entry->value); + } + + LinkedList_destroy(map->entries); + GLOBAL_FREEMEM(map); +} diff --git a/src/common/mem_alloc_linked_list.c b/src/common/mem_alloc_linked_list.c new file mode 100644 index 0000000..76e5ad8 --- /dev/null +++ b/src/common/mem_alloc_linked_list.c @@ -0,0 +1,67 @@ +/* + * mem_alloc_linked_list.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mem_alloc_linked_list.h" + +struct sMemAllocLinkedList { + void* data; + struct sLinkedList* next; + MemoryAllocator* ma; +}; + +MemAllocLinkedList +MemAllocLinkedList_create(MemoryAllocator* ma) +{ + MemAllocLinkedList self = + (MemAllocLinkedList) MemoryAllocator_allocate(ma, sizeof(struct sMemAllocLinkedList)); + + if (self == NULL) + return NULL; + + self->ma = ma; + self->data = NULL; + self->next = NULL; + + return self; +} + +LinkedList +MemAllocLinkedList_add(MemAllocLinkedList self, void* data) +{ + LinkedList newElement = (LinkedList) + MemoryAllocator_allocate(self->ma, sizeof(struct sLinkedList)); + + if (newElement == NULL) + return NULL; + + newElement->data = data; + newElement->next = NULL; + + LinkedList listEnd = LinkedList_getLastElement((LinkedList) self); + + listEnd->next = newElement; + + return newElement; +} + diff --git a/src/common/simple_allocator.c b/src/common/simple_allocator.c new file mode 100644 index 0000000..89c9940 --- /dev/null +++ b/src/common/simple_allocator.c @@ -0,0 +1,56 @@ +/* + * simple_allocator.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "simple_allocator.h" + +void +MemoryAllocator_init(MemoryAllocator* self, char* memoryBlock, int size) +{ + self->memoryBlock = memoryBlock; + self->currentPtr = memoryBlock; + self->size = size; +} + +static int +getAlignedSize(int size) +{ + if ((size % sizeof(void*)) > 0) + return sizeof(void*) * ((size + sizeof(void*) - 1) / sizeof(void*)); + else + return size; +} + +char* +MemoryAllocator_allocate(MemoryAllocator* self, int size) +{ + size = getAlignedSize(size); + + if (((self->currentPtr - self->memoryBlock) + size) <= self->size) { + char* ptr = self->currentPtr; + self->currentPtr += size; + return ptr; + } + else + return NULL; +} diff --git a/src/common/string_map.c b/src/common/string_map.c new file mode 100644 index 0000000..1528218 --- /dev/null +++ b/src/common/string_map.c @@ -0,0 +1,32 @@ +/* + * string_map.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "string_map.h" + +Map +StringMap_create() { + Map map = Map_create(); + map->compareKeys = (int (*) (void*, void*)) strcmp; + return map; +} diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c new file mode 100644 index 0000000..b33a3f7 --- /dev/null +++ b/src/common/string_utilities.c @@ -0,0 +1,363 @@ +/* + * string_utilities.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +char* +copySubString(char* startPos, char* endPos) +{ + int newStringLength = endPos - startPos; + + char* newString = (char*) GLOBAL_MALLOC(newStringLength) + 1; + + memcpy(newString, startPos, newStringLength); + + newString[newStringLength] = 0; + + return newString; +} + +char* +copyString(const char* string) +{ + int newStringLength = strlen(string) + 1; + + char* newString = (char*) GLOBAL_MALLOC(newStringLength); + + memcpy(newString, string, newStringLength); + + return newString; +} + +char* +copyStringToBuffer(const char* string, char* buffer) +{ + int newStringLength = strlen(string) + 1; + + memcpy(buffer, string, newStringLength); + + return buffer; +} + + +char* +createStringFromBuffer(const uint8_t* buf, int size) +{ + char* newStr = (char*) GLOBAL_MALLOC(size + 1); + + memcpy(newStr, buf, size); + newStr[size] = 0; + + return newStr; +} + +char* +StringUtils_createStringFromBufferInBuffer(char* newString, const uint8_t* buf, int size) +{ + memcpy(newString, buf, size); + newString[size] = 0; + + return newString; +} + + +char* +StringUtils_createStringInBuffer(char* newStr, int count, ...) +{ + va_list ap; + char* currentPos = newStr; + int i; + + va_start(ap, count); + for (i = 0; i < count; i++) { + char* str = va_arg(ap, char*); + strcpy(currentPos, str); + currentPos += strlen(str); + } + va_end(ap); + + *currentPos = 0; + + return newStr; +} + +char* +createString(int count, ...) +{ + va_list ap; + char* newStr; + char* currentPos; + int newStringLength = 0; + int i; + + /* Calculate new string length */ + va_start(ap, count); + for (i = 0; i < count; i++) { + char* str = va_arg(ap, char*); + + newStringLength += strlen(str); + } + va_end(ap); + + newStr = (char*) GLOBAL_MALLOC(newStringLength + 1); + currentPos = newStr; + + + va_start(ap, count); + for (i = 0; i < count; i++) { + char* str = va_arg(ap, char*); + strcpy(currentPos, str); + currentPos += strlen(str); + } + va_end(ap); + + *currentPos = 0; + + return newStr; +} + +void +StringUtils_replace(char* string, char oldChar, char newChar) +{ + int len = strlen(string); + int i; + + for (i = 0; i < len; i++){ + if (string[i] == oldChar) + string[i] = newChar; + } +} + +bool +StringUtils_isDigit(char character) +{ + if ((character > 47) && (character < 58)) + return true; + else + return false; +} + +int +StringUtils_digitToInt(char digit) +{ + if (StringUtils_isDigit(digit)) { + return (digit - 48); + } + else + return -1; +} + +int +StringUtils_digitsToInt(const char* digits, int count) +{ + int i = 0; + int value = 0; + + while (i < count) { + value = value * 10; + + int digitValue = StringUtils_digitToInt(*(digits + i)); + + if (digitValue == -1) + return -1; + + value += digitValue; + + i++; + } + + return value; +} + +static int +toInt(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + return -1; +} + +int +StringUtils_createBufferFromHexString(char* hexString, uint8_t* buffer) +{ + int hexStringLen = strlen(hexString); + int i; + int bytesCount = 0; + + if (hexStringLen % 2 != 0) + return -1; + + for (i = 0; i < (hexStringLen/2); i++) { + int high = toInt(hexString[i * 2]); + if (high == -1) return -1; + + int low = toInt(hexString[(i * 2) + 1]); + if (low == -1) return -1; + + buffer[i] = (uint8_t) (high * 16 + low); + bytesCount += 1; + } + + return bytesCount; +} + +bool +StringUtils_startsWith(char* string, char* prefix) +{ + int index = 0; + + while ((string[index] != 0) && (prefix[index] != 0)) { + if (string[index] != prefix[index]) + return false; + + index++; + } + + if (prefix[index] == 0) + return true; + + return false; +} + +#define LT_MAX_CHARS 128 + +static int +getCharWeight(int c) +{ + static bool initialized = false; + static char lookupTable[LT_MAX_CHARS + 1]; + static char* charOrder = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz$_0123456789"; + + if (!initialized) { + int ltIndex; + int weight = 1; + + for (ltIndex = 1; ltIndex < LT_MAX_CHARS; ltIndex++) { + if (strchr(charOrder, ltIndex)) continue; + lookupTable[ltIndex] = weight; + weight++; + } + + int charIndex; + + for (charIndex = 0; charOrder[charIndex]; charIndex++) { + lookupTable[(int)charOrder[charIndex]] = weight; + weight++; + } + + initialized = true; + } + + if ((c < 1) || (c > LT_MAX_CHARS)) + return c; + else + return lookupTable[c]; +} + +int +StringUtils_compareChars(char a, char b) +{ + return (getCharWeight(a) - getCharWeight(b)); +} + +int +StringUtils_compareStrings(const char* a, const char* b) +{ + int diff = StringUtils_compareChars(*a, *b); + + while (diff == 0) { + if ((*a == 0) || (*b == 0)) { + return b - a; + } + + diff = StringUtils_compareChars(*++a, *++b); + } + + return diff; +} + +void +StringUtils_sortList(LinkedList list) +{ + LinkedList selectedElement = list->next; + + if (selectedElement == NULL) /* list is empty */ + return; + + list->next = selectedElement->next; + selectedElement->next = NULL; + + struct sLinkedList sortedListData; + + LinkedList sortedList = &sortedListData; + + sortedList->next = selectedElement; + + selectedElement = list->next; + + while (selectedElement != NULL) { + + list->next = selectedElement->next; + selectedElement->next = NULL; + + char* str1 = (char*) LinkedList_getData(selectedElement); + + LinkedList prevElement = sortedList; + + while (true) { + + if (prevElement->next == NULL) { + prevElement->next = selectedElement; + break; + } + + char* str2 = (char*) LinkedList_getData(prevElement->next); + + if (StringUtils_compareStrings(str1, str2) < 0) { + + /* insert "nextElement" before */ + if (sortedList == prevElement) { + selectedElement->next = sortedList->next; + sortedList->next = selectedElement; + } + else { + selectedElement->next = prevElement->next; + prevElement->next = selectedElement; + } + + break; + } + + prevElement = prevElement->next; + } + + selectedElement = list->next; + + if (selectedElement == NULL) + break; + } + + list->next = sortedList->next; +} + diff --git a/src/doxygen.config b/src/doxygen.config new file mode 100644 index 0000000..f627595 --- /dev/null +++ b/src/doxygen.config @@ -0,0 +1,1150 @@ +# Doxyfile 1.7.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +DOXYFILE_ENCODING = UTF-8 + +PROJECT_NAME = "libIEC61850" + +PROJECT_NUMBER = 0.8.7 + +PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE server and client library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../doxydoc + +CREATE_SUBDIRS = NO + +OUTPUT_LANGUAGE = English + +BRIEF_MEMBER_DESC = YES + +REPEAT_BRIEF = YES + +ABBREVIATE_BRIEF = + +ALWAYS_DETAILED_SEC = NO + +INLINE_INHERITED_MEMB = NO + +FULL_PATH_NAMES = YES + +STRIP_FROM_PATH = + +STRIP_FROM_INC_PATH = + +SHORT_NAMES = NO + +JAVADOC_AUTOBRIEF = NO + +QT_AUTOBRIEF = NO + +MULTILINE_CPP_IS_BRIEF = NO + +INHERIT_DOCS = YES + +SEPARATE_MEMBER_PAGES = NO + +TAB_SIZE = 8 + +ALIASES = + +TCL_SUBST = + +OPTIMIZE_OUTPUT_FOR_C = YES. + +OPTIMIZE_OUTPUT_JAVA = NO + +OPTIMIZE_FOR_FORTRAN = NO + +OPTIMIZE_OUTPUT_VHDL = NO + +EXTENSION_MAPPING = + +BUILTIN_STL_SUPPORT = NO + +CPP_CLI_SUPPORT = NO + +SIP_SUPPORT = NO + +IDL_PROPERTY_SUPPORT = YES + +DISTRIBUTE_GROUP_DOC = NO + +SUBGROUPING = YES + +INLINE_GROUPED_CLASSES = NO + +INLINE_SIMPLE_STRUCTS = NO + +TYPEDEF_HIDES_STRUCT = YES + +SYMBOL_CACHE_SIZE = 0 + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +EXTRACT_ALL = YES + +EXTRACT_PRIVATE = NO + +EXTRACT_STATIC = NO + +EXTRACT_LOCAL_CLASSES = YES + +EXTRACT_LOCAL_METHODS = NO + +EXTRACT_ANON_NSPACES = NO + +HIDE_UNDOC_MEMBERS = NO + +HIDE_UNDOC_CLASSES = NO + +HIDE_FRIEND_COMPOUNDS = NO + +HIDE_IN_BODY_DOCS = NO + +INTERNAL_DOCS = NO + +CASE_SENSE_NAMES = YES + +HIDE_SCOPE_NAMES = NO + +SHOW_INCLUDE_FILES = YES + +FORCE_LOCAL_INCLUDES = NO + +INLINE_INFO = YES + +SORT_MEMBER_DOCS = YES + +SORT_BRIEF_DOCS = NO + +SORT_MEMBERS_CTORS_1ST = NO + +SORT_GROUP_NAMES = NO + +SORT_BY_SCOPE_NAME = NO + +STRICT_PROTO_MATCHING = NO + +GENERATE_TODOLIST = YES + +GENERATE_TESTLIST = YES + +GENERATE_BUGLIST = YES + +GENERATE_DEPRECATEDLIST= YES + +ENABLED_SECTIONS = + +MAX_INITIALIZER_LINES = 30 + +SHOW_USED_FILES = YES + +SHOW_DIRECTORIES = NO + +SHOW_FILES = YES + +SHOW_NAMESPACES = YES + +FILE_VERSION_FILTER = + +LAYOUT_FILE = doxygen/DoxygenLayout.xml + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +QUIET = NO + +WARNINGS = YES + +WARN_IF_UNDOCUMENTED = YES + +WARN_IF_DOC_ERROR = YES + +WARN_NO_PARAMDOC = NO + +WARN_FORMAT = "$file:$line: $text" + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "iec61850/inc/iec61850_client.h" +INPUT += "mms/inc/mms_value.h" +INPUT += "common/inc/linked_list.h" +INPUT += "doxygen/mainpage.doxygen" +INPUT += "iec61850/inc/iec61850_server.h" +INPUT += "iec61850/inc/iec61850_common.h" +INPUT += "iec61850/inc/iec61850_model.h" +INPUT += "iec61850/inc/iec61850_dynamic_model.h" +INPUT += "iec61850/inc/iec61850_config_file_parser.h" +INPUT += "iec61850/inc/iec61850_cdc.h" +INPUT += "goose/goose_subscriber.h" +INPUT += "goose/goose_receiver.h" +INPUT += "mms/inc/mms_device_model.h" +INPUT += "mms/inc/mms_types.h" +INPUT += "mms/inc/mms_common.h" +INPUT += "mms/inc/mms_server.h" +INPUT += "mms/inc/iso_server.h" +INPUT += "mms/inc/mms_named_variable_list.h" +INPUT += "mms/inc/mms_type_spec.h" +INPUT += "mms/inc/mms_types.h" +INPUT += "mms/inc/mms_client_connection.h" +INPUT += "mms/inc/iso_connection_parameters.h" +INPUT += "hal/inc/hal_socket.h" +INPUT += "hal/inc/hal_thread.h" +INPUT += "hal/inc/hal_ethernet.h" +INPUT += "hal/inc/hal_filesystem.h" +INPUT += "hal/inc/hal_time.h" + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +RECURSIVE = NO + +EXCLUDE = + +EXCLUDE_SYMLINKS = NO + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = doxygen/header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = doxygen/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = doxygen/doxygen.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +ALLEXTERNALS = NO + +EXTERNAL_GROUPS = YES + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +CLASS_DIAGRAMS = YES + +MSCGEN_PATH = + +HIDE_UNDOC_RELATIONS = YES + +HAVE_DOT = NO + +DOT_NUM_THREADS = 0 + +DOT_FONTNAME = Helvetica + +DOT_FONTSIZE = 10 + +DOT_FONTPATH = + +CLASS_GRAPH = YES + +COLLABORATION_GRAPH = YES + +GROUP_GRAPHS = YES + +UML_LOOK = NO + +TEMPLATE_RELATIONS = NO + +INCLUDE_GRAPH = YES + +INCLUDED_BY_GRAPH = YES + +CALL_GRAPH = NO + +CALLER_GRAPH = NO + +GRAPHICAL_HIERARCHY = YES + +DIRECTORY_GRAPH = YES + +DOT_IMAGE_FORMAT = png + +INTERACTIVE_SVG = NO + +DOT_PATH = + +DOTFILE_DIRS = + +MSCFILE_DIRS = + +DOT_GRAPH_MAX_NODES = 50 + +MAX_DOT_GRAPH_DEPTH = 0 + +DOT_TRANSPARENT = NO + +DOT_MULTI_TARGETS = YES + +GENERATE_LEGEND = YES + +DOT_CLEANUP = YES diff --git a/src/doxygen/DoxygenLayout.xml b/src/doxygen/DoxygenLayout.xml new file mode 100644 index 0000000..5040ea3 --- /dev/null +++ b/src/doxygen/DoxygenLayout.xml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/doxygen/doxygen.css b/src/doxygen/doxygen.css new file mode 100644 index 0000000..cee0d06 --- /dev/null +++ b/src/doxygen/doxygen.css @@ -0,0 +1,949 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4CFE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 2px 5px; + background-color: #FBFCFD; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/src/doxygen/doxygen.mod.css b/src/doxygen/doxygen.mod.css new file mode 100644 index 0000000..cee0d06 --- /dev/null +++ b/src/doxygen/doxygen.mod.css @@ -0,0 +1,949 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4CFE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 2px 5px; + background-color: #FBFCFD; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/src/doxygen/footer.html b/src/doxygen/footer.html new file mode 100644 index 0000000..d2068a5 --- /dev/null +++ b/src/doxygen/footer.html @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/src/doxygen/header.html b/src/doxygen/header.html new file mode 100644 index 0000000..ff71641 --- /dev/null +++ b/src/doxygen/header.html @@ -0,0 +1,56 @@ + + + + + + + + +$projectname: $title +$title + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/src/doxygen/libIEC61850_server.png b/src/doxygen/libIEC61850_server.png new file mode 100644 index 0000000..9bc4908 Binary files /dev/null and b/src/doxygen/libIEC61850_server.png differ diff --git a/src/doxygen/mainpage.doxygen b/src/doxygen/mainpage.doxygen new file mode 100644 index 0000000..b45a9a2 --- /dev/null +++ b/src/doxygen/mainpage.doxygen @@ -0,0 +1,85 @@ +/*! \mainpage API Reference Manual + * + * \section intro_sec Introduction + * + * This is the reference manual of libIEC61850. + * libIEC61850 is an open-source (GPLv3) implementation of an IEC 61850 client and server library. It is implemented + * in C to provide maximum portability. It can be used to implement IEC 61850 + * compatible client and server applications on embedded systems and PCs running Linux and Windows. Included + * is a set of simple example applications that can be used as a starting point to implement your own IEC 61850 + * compatible devices or to communicate with IEC 61850 devices. + * There is also an open-source implementation of IEC 61850 in Java (see http://openmuc.org). + * + * The library implements the most important parts of IEC 61850 on top of the MMS mapping. It provides the MMS protocol stack + * on top of TCP/IP as well as GOOSE for real-time data transfer inside of substations. + * + * The API of libIEC61850 can be divided into a client and a server part. Both parts also + * share common elements. For both client and server there exist two different APIs. There is a + * "low-level" MMS API and the more high-level IEC 61850 API. + * + * \section iec_client_api IEC 61850 client API + * + * The IEC 61850 client API is a high-level API to access IEC 61850 compliant devices. The API provides + * access to MMS services that are supported by IEC 61850. It also contains a GOOSE subscriber. + * + * \section client_api MMS client API + * + * This client API is not IEC 61850 specific but is a generic MMS client API that provides + * only the features required by the IEC 61850 MMS Mapping. This API can be used if low-level access + * to MMS services is required. + * + * \section server_api IEC 61850 Server API + * + * Server support for IEC 61850 includes the generation of the MMS device model out of the static IEC 61850 + * data model and the generation of reports. Also the IEC 61850 server API provides support for the + * IEC 61850 control model. The server API is designed to add very low overhead and can be used to create very + * small IEC 61850 compliant MMS server applications. The server does not parse the SCD(XML) file + * at runtime. The SCD file will be parsed at build time by a tool that generates C code for the + * definition of the IEC 61850 data model and other settings of the SCD file. This will free the + * server code from the burden of an XML file parser. Also the target system does not require a + * file system to store the SCD file. This design simplifies the usage of the server on very + * small embedded systems. + * + * \section mms_server_api MMS Server API + * + * The MMS server API provides a generic MMS API. There is no support for IEC 61850 specific + * functions in this API. If you want to implement IEC 61850 compliant devices you should use + * the IEC 61850 server API instead. + * + * \section hal Hardware/OS abstraction layer + * + * libIEC61850 provides a hardware/OS abstraction layer (HAL) to hide the dependencies to the + * underlying platform. Currently this layer consists of thread, socket and time abstractions. If + * you want to port the library to a new platform you need to implement the functions defined + * by this API. At the moment implementations for POSIX(Linux, Mac OS X ...) and Win32 exists. This API + * consists of the three files hal/hal.h, hal/socket/socket.h and + * hal/thread/thread.h. + * + * \section examples Building the library and the examples + * + * To build the library you can simply execute make in the main folder of the + * source distribution. It is assumed that a GCC toolchain and the Make tool is installed. + * To cross-compile for another platform you can specify the TARGET variable when executing + * make. To cross-compile for Windows you can call make TARGET=WIN32. To cross-compile + * for ARM Linux you can call make TARGET=LINUX-ARM. It is assumed that a proper + * GCC cross-compiler toolchain (like MinGW or arm-linux-gcc) is installed. Probably you + * need to adjust the toolchain prefix variables at the beginning of the Makefile. + * + * To build the examples change to the main directory of the source distribution. On the command line type + *
+ * make examples + * + * This will build the examples for the host environment (currently Linux and Windows with MinGW are + * supported). You can also cross-compile if the target system is different from the host system. + * To test the server examples you can use the mms_client_example binary. You can + * also use third-party tools like Omicron IEDScout or the openIEC61850 client example to + * test the examples. + * + * \section Licenses + * + * libIEC61850 itself is released under the GPLv3. The asn1 code parts contain code of asn1c that is + * under a BSD style license (see http://lionet.info/asn1c/blog/). + * + * You can contact the author via info@libiec61850.com + */ + diff --git a/src/doxygen/stylesheet.css b/src/doxygen/stylesheet.css new file mode 100644 index 0000000..dabaff2 --- /dev/null +++ b/src/doxygen/stylesheet.css @@ -0,0 +1,1184 @@ +/* The standard CSS for doxygen 1.8.3.1 */ + +body, table, div, p, dl { + font: 400 14px/19px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 4px; + margin: 4px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: bold; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view when not used as main index */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 5px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 2px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c new file mode 100644 index 0000000..d5ebe97 --- /dev/null +++ b/src/goose/goose_publisher.c @@ -0,0 +1,382 @@ +/* + * goose_publisher.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "goose_publisher.h" +#include "hal_ethernet.h" +#include "ber_encoder.h" +#include "mms_server_internal.h" +#include "mms_value_internal.h" + +#ifndef DEBUG_GOOSE_PUBLISHER +#define DEBUG_GOOSE_PUBLISHER 0 +#endif + +#define GOOSE_MAX_MESSAGE_SIZE 1518 + +static void +prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID); + +struct sGoosePublisher { + uint8_t* buffer; + //uint16_t appId; + EthernetSocket ethernetSocket; + int lengthField; + int payloadStart; + + char* goID; + char* goCBRef; + char* dataSetRef; + + //uint16_t minTime; + //uint16_t maxTime; + //bool fixedOffs; + + uint32_t confRev; + uint32_t stNum; + uint32_t sqNum; + uint32_t timeAllowedToLive; + bool needsCommission; + bool simulation; + + MmsValue* timestamp; /* time when stNum is increased */ +}; + + +GoosePublisher +GoosePublisher_create(CommParameters* parameters, const char* interfaceID) +{ + GoosePublisher self = (GoosePublisher) GLOBAL_CALLOC(1, sizeof(struct sGoosePublisher)); + + prepareGooseBuffer(self, parameters, interfaceID); + + self->timestamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs()); + + GoosePublisher_reset(self); + + return self; +} + +void +GoosePublisher_destroy(GoosePublisher self) +{ + Ethernet_destroySocket(self->ethernetSocket); + + MmsValue_delete(self->timestamp); + + if (self->goID != NULL) + GLOBAL_FREEMEM(self->goID); + + if (self->goCBRef != NULL) + GLOBAL_FREEMEM(self->goCBRef); + + if (self->dataSetRef != NULL) + GLOBAL_FREEMEM(self->dataSetRef); + + GLOBAL_FREEMEM(self->buffer); + GLOBAL_FREEMEM(self); +} + +void +GoosePublisher_setGoID(GoosePublisher self, char* goID) +{ + self->goID = copyString(goID); +} + +void +GoosePublisher_setGoCbRef(GoosePublisher self, char* goCbRef) +{ + self->goCBRef = copyString(goCbRef); +} + +void +GoosePublisher_setDataSetRef(GoosePublisher self, char* dataSetRef) +{ + self->dataSetRef = copyString(dataSetRef); +} + +void +GoosePublisher_setConfRev(GoosePublisher self, uint32_t confRev) +{ + self->confRev = confRev; +} + +void +GoosePublisher_setSimulation(GoosePublisher self, bool simulation) +{ + self->simulation = simulation; +} + +void +GoosePublisher_setNeedsCommission(GoosePublisher self, bool ndsCom) +{ + self->needsCommission = ndsCom; +} + +uint64_t +GoosePublisher_increaseStNum(GoosePublisher self) +{ + uint64_t currentTime = Hal_getTimeInMs(); + + MmsValue_setUtcTimeMs(self->timestamp, currentTime); + + self->stNum++; + self->sqNum = 0; + + return currentTime; +} + +void +GoosePublisher_reset(GoosePublisher self) { + self->sqNum = 0; + self->stNum = 1; +} + +void +GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToLive) +{ + self->timeAllowedToLive = timeAllowedToLive; +} + +static void +prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID) +{ + uint8_t srcAddr[6]; + + if (interfaceID != NULL) + Ethernet_getInterfaceMACAddress(interfaceID, srcAddr); + else + Ethernet_getInterfaceMACAddress(CONFIG_ETHERNET_INTERFACE_ID, srcAddr); + + uint8_t defaultDstAddr[] = CONFIG_GOOSE_DEFAULT_DST_ADDRESS; + + uint8_t* dstAddr; + uint8_t priority; + uint16_t vlanId; + uint16_t appId; + + if (parameters == NULL) { + dstAddr = defaultDstAddr; + priority = CONFIG_GOOSE_DEFAULT_PRIORITY; + vlanId = CONFIG_GOOSE_DEFAULT_VLAN_ID; + appId = CONFIG_GOOSE_DEFAULT_APPID; + } + else { + dstAddr = parameters->dstAddress; + priority = parameters->vlanPriority; + vlanId = parameters->vlanId; + appId = parameters->appId; + } + + if (interfaceID != NULL) + self->ethernetSocket = Ethernet_createSocket(interfaceID, dstAddr); + else + self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr); + + self->buffer = (uint8_t*) GLOBAL_MALLOC(GOOSE_MAX_MESSAGE_SIZE); + + memcpy(self->buffer, dstAddr, 6); + memcpy(self->buffer + 6, srcAddr, 6); + + int bufPos = 12; + +#if 1 + /* Priority tag - IEEE 802.1Q */ + self->buffer[bufPos++] = 0x81; + self->buffer[bufPos++] = 0x00; + + uint8_t tci1 = priority << 5; + tci1 += vlanId / 256; + + uint8_t tci2 = vlanId % 256; + + self->buffer[bufPos++] = tci1; /* Priority + VLAN-ID */ + self->buffer[bufPos++] = tci2; /* VLAN-ID */ +#endif + + /* EtherType GOOSE */ + self->buffer[bufPos++] = 0x88; + self->buffer[bufPos++] = 0xB8; + + /* APPID */ + self->buffer[bufPos++] = appId / 256; + self->buffer[bufPos++] = appId % 256; + + self->lengthField = bufPos; + + /* Length */ + self->buffer[bufPos++] = 0x00; + self->buffer[bufPos++] = 0x08; + + /* Reserved1 */ + self->buffer[bufPos++] = 0x00; + self->buffer[bufPos++] = 0x00; + + /* Reserved2 */ + self->buffer[bufPos++] = 0x00; + self->buffer[bufPos++] = 0x00; + + self->payloadStart = bufPos; +} + +static int32_t +createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffer, size_t maxPayloadSize) { + + /* Step 1 - calculate length fields */ + uint32_t goosePduLength = 0; + + goosePduLength += BerEncoder_determineEncodedStringSize(self->goCBRef); + + goosePduLength += BerEncoder_determineEncodedStringSize(self->dataSetRef); + + if (self->goID != NULL) + goosePduLength += BerEncoder_determineEncodedStringSize(self->goID); + else + goosePduLength += BerEncoder_determineEncodedStringSize(self->goCBRef); + + uint32_t timeAllowedToLive = self->timeAllowedToLive; + + goosePduLength += 2 + BerEncoder_UInt32determineEncodedSize(timeAllowedToLive); + + goosePduLength += 2 + 8; /* for T (UTCTIME) */ + + goosePduLength += 2 + BerEncoder_UInt32determineEncodedSize(self->sqNum); + + goosePduLength += 2 + BerEncoder_UInt32determineEncodedSize(self->stNum); + + goosePduLength += 2 + BerEncoder_UInt32determineEncodedSize(self->confRev); + + goosePduLength += 6; /* for ndsCom and simulation */ + + uint32_t numberOfDataSetEntries = LinkedList_size(dataSetValues); + + goosePduLength += 2 + BerEncoder_UInt32determineEncodedSize(numberOfDataSetEntries); + + uint32_t dataSetSize = 0; + + LinkedList element = LinkedList_getNext(dataSetValues); + + while (element != NULL) { + MmsValue* dataSetEntry = (MmsValue*) element->data; + + dataSetSize += mmsServer_encodeAccessResult(dataSetEntry, NULL, 0, false); + + element = LinkedList_getNext(element); + } + + uint32_t allDataSize = dataSetSize + BerEncoder_determineLengthSize(dataSetSize) + 1; + + goosePduLength += allDataSize; + + if (goosePduLength > maxPayloadSize) + return -1; + + /* Step 2 - encode to buffer */ + + int32_t bufPos = 0; + + /* Encode GOOSE PDU */ + bufPos = BerEncoder_encodeTL(0x61, goosePduLength, buffer, bufPos); + + /* Encode gocbRef */ + bufPos = BerEncoder_encodeStringWithTag(0x80, self->goCBRef, buffer, bufPos); + + /* Encode timeAllowedToLive */ + bufPos = BerEncoder_encodeUInt32WithTL(0x81, timeAllowedToLive, buffer, bufPos); + + /* Encode datSet reference */ + bufPos = BerEncoder_encodeStringWithTag(0x82, self->dataSetRef, buffer, bufPos); + + /* Encode goID */ + if (self->goID != NULL) + bufPos = BerEncoder_encodeStringWithTag(0x83, self->goID, buffer, bufPos); + else + bufPos = BerEncoder_encodeStringWithTag(0x83, self->goCBRef, buffer, bufPos); + + /* Encode t */ + bufPos = BerEncoder_encodeOctetString(0x84, self->timestamp->value.utcTime, 8, buffer, bufPos); + + /* Encode stNum */ + bufPos = BerEncoder_encodeUInt32WithTL(0x85, self->stNum, buffer, bufPos); + + /* Encode sqNum */ + bufPos = BerEncoder_encodeUInt32WithTL(0x86, self->sqNum, buffer, bufPos); + + /* Encode simulation */ + bufPos = BerEncoder_encodeBoolean(0x87, self->simulation, buffer, bufPos); + + /* Encode confRef */ + bufPos = BerEncoder_encodeUInt32WithTL(0x88, self->confRev, buffer, bufPos); + + /* Encode ndsCom */ + bufPos = BerEncoder_encodeBoolean(0x89, self->needsCommission, buffer, bufPos); + + /* Encode numDatSetEntries */ + bufPos = BerEncoder_encodeUInt32WithTL(0x8a, numberOfDataSetEntries, buffer, bufPos); + + /* Encode all data */ + bufPos = BerEncoder_encodeTL(0xab, dataSetSize, buffer, bufPos); + + /* Encode data set entries */ + element = LinkedList_getNext(dataSetValues); + + while (element != NULL) { + MmsValue* dataSetEntry = (MmsValue*) element->data; + + bufPos = mmsServer_encodeAccessResult(dataSetEntry, buffer, bufPos, true); + + element = LinkedList_getNext(element); + } + + return bufPos; +} + +int +GoosePublisher_publish(GoosePublisher self, LinkedList dataSet) +{ + uint8_t* buffer = self->buffer + self->payloadStart; + + size_t maxPayloadSize = GOOSE_MAX_MESSAGE_SIZE - self->payloadStart; + + int32_t payloadLength = createGoosePayload(self, dataSet, buffer, maxPayloadSize); + + self->sqNum++; + + if (payloadLength == -1) + return -1; + + int lengthIndex = self->lengthField; + + size_t gooseLength = payloadLength + 8; + + self->buffer[lengthIndex] = gooseLength / 256; + self->buffer[lengthIndex + 1] = gooseLength & 0xff; + + if (DEBUG_GOOSE_PUBLISHER) + printf("GOOSE_PUBLISHER: send GOOSE message\n"); + + Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + payloadLength); + + return 0; +} diff --git a/src/goose/goose_publisher.h b/src/goose/goose_publisher.h new file mode 100644 index 0000000..29ed6c6 --- /dev/null +++ b/src/goose/goose_publisher.h @@ -0,0 +1,83 @@ +/* + * goose_publisher.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef GOOSE_PUBLISHER_H_ +#define GOOSE_PUBLISHER_H_ + +#include "linked_list.h" +#include "mms_value.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sCommParameters { + uint8_t vlanPriority; + uint16_t vlanId; + uint16_t appId; + uint8_t dstAddress[6]; +} CommParameters; + +typedef struct sGoosePublisher* GoosePublisher; + +GoosePublisher +GoosePublisher_create(CommParameters* parameters, const char* interfaceID); + +void +GoosePublisher_destroy(GoosePublisher self); + +int +GoosePublisher_publish(GoosePublisher self, LinkedList dataSet); + +void +GoosePublisher_setGoID(GoosePublisher self, char* goID); + +void +GoosePublisher_setGoCbRef(GoosePublisher self, char* goCbRef); + +void +GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToLive); + +void +GoosePublisher_setDataSetRef(GoosePublisher self, char* dataSetRef); + +void +GoosePublisher_setConfRev(GoosePublisher self, uint32_t confRev); + +void +GoosePublisher_setSimulation(GoosePublisher self, bool simulation); + +void +GoosePublisher_setNeedsCommission(GoosePublisher self, bool ndsCom); + +uint64_t +GoosePublisher_increaseStNum(GoosePublisher self); + +void +GoosePublisher_reset(GoosePublisher self); + +#ifdef __cplusplus +} +#endif + +#endif /* GOOSE_PUBLISHER_H_ */ diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c new file mode 100644 index 0000000..960073a --- /dev/null +++ b/src/goose/goose_receiver.c @@ -0,0 +1,785 @@ +/* + * goose_receiver.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" +#include "goose_subscriber.h" +#include "hal_ethernet.h" +#include "hal_thread.h" + +#include "ber_decode.h" + +#include "mms_value.h" +#include "mms_value_internal.h" +#include "linked_list.h" + +#include "goose_receiver.h" +#include "goose_receiver_internal.h" + +#ifndef DEBUG_GOOSE_SUBSCRIBER +#define DEBUG_GOOSE_SUBSCRIBER 0 +#endif + +#define ETH_BUFFER_LENGTH 1518 + +#define ETH_P_GOOSE 0x88b8 + +struct sGooseReceiver { + bool running; + bool stopped; + char* interfaceId; + uint8_t* buffer; + EthernetSocket ethSocket; + LinkedList subscriberList; +}; + + +GooseReceiver +GooseReceiver_create() +{ + GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver)); + + if (self != NULL) { + self->running = false; + self->interfaceId = NULL; + self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH); + self->ethSocket = NULL; + self->subscriberList = LinkedList_create(); + } + + return self; +} + +void +GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber) +{ + LinkedList_add(self->subscriberList, (void*) subscriber); +} + +void +GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber) +{ + LinkedList_remove(self->subscriberList, (void*) subscriber); +} + + +void +GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId) +{ + if (self->interfaceId != NULL) + GLOBAL_FREEMEM(self->interfaceId); + + self->interfaceId = copyString(interfaceId); +} + +static void +createNewStringFromBufferElement(MmsValue* value, uint8_t* bufferSrc, int elementLength) +{ + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(elementLength + 1); + memcpy(value->value.visibleString.buf, bufferSrc, elementLength); + value->value.visibleString.buf[elementLength] = 0; + value->value.visibleString.size = elementLength; +} + +static int +parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) +{ + int bufPos = 0; + int elementLength = 0; + + int elementIndex = 0; + + int maxIndex = MmsValue_getArraySize(dataSetValues) - 1; + + while (bufPos < allDataLength) { + uint8_t tag = buffer[bufPos++]; + + if (elementIndex > maxIndex) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: too much elements!\n"); + return 0; + } + + MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex); + + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + + if (bufPos + elementLength > allDataLength) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + return 0; + } + + switch (tag) { + case 0x80: /* reserved for access result */ + printf("GOOSE_SUBSCRIBER: found reserved value (tag 0x80)!\n"); + break; + case 0xa1: /* array */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); + if (MmsValue_getType(value) == MMS_ARRAY) { + if (!parseAllData(buffer + bufPos, elementLength, value)) + return -1; + } + break; + case 0xa2: /* structure */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); + if (MmsValue_getType(value) == MMS_STRUCTURE) { + if (!parseAllData(buffer + bufPos, elementLength, value)) + return -1; + } + break; + case 0x83: /* boolean */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n"); + + if (MmsValue_getType(value) == MMS_BOOLEAN) { + MmsValue_setBoolean(value, BerDecoder_decodeBoolean(buffer, bufPos)); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: message contains value of wrong type!\n"); + + break; + + case 0x84: /* BIT STRING */ + if (MmsValue_getType(value) == MMS_BIT_STRING) { + int padding = buffer[bufPos]; + int bitStringLength = (8 * (elementLength - 1)) - padding; + if (bitStringLength == value->value.bitString.size) { + memcpy(value->value.bitString.buf, buffer + bufPos + 1, + elementLength - 1); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) + printf("bit-string is of wrong size"); + } + break; + case 0x85: /* integer */ + if (MmsValue_getType(value) == MMS_INTEGER) { + if (elementLength <= value->value.integer->maxSize) { + value->value.integer->size = elementLength; + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + } + } + break; + case 0x86: /* unsigned integer */ + if (MmsValue_getType(value) == MMS_UNSIGNED) { + if (elementLength <= value->value.integer->maxSize) { + value->value.integer->size = elementLength; + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + } + } + break; + case 0x87: /* Float */ + if (MmsValue_getType(value) == MMS_FLOAT) { + if (elementLength == 9) { + MmsValue_setDouble(value, BerDecoder_decodeDouble(buffer, bufPos)); + } + else if (elementLength == 5) { + MmsValue_setFloat(value, BerDecoder_decodeFloat(buffer, bufPos)); + } + } + break; + + case 0x89: /* octet string */ + if (MmsValue_getType(value) == MMS_OCTET_STRING) { + if (elementLength <= value->value.octetString.maxSize) { + value->value.octetString.size = elementLength; + memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); + } + } + break; + case 0x8a: /* visible string */ + if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { + + if (value->value.visibleString.buf != NULL) { + if ((int32_t) value->value.visibleString.size >= elementLength) { + memcpy(value->value.visibleString.buf, buffer + bufPos, elementLength); + value->value.visibleString.buf[elementLength] = 0; + } + else { + GLOBAL_FREEMEM(value->value.visibleString.buf); + + createNewStringFromBufferElement(value, buffer + bufPos, elementLength); + } + } + else + createNewStringFromBufferElement(value, buffer + bufPos, elementLength); + + } + break; + case 0x8c: /* binary time */ + if (MmsValue_getType(value) == MMS_BINARY_TIME) { + if ((elementLength == 4) || (elementLength == 6)) { + memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); + } + } + break; + case 0x91: /* Utctime */ + if (elementLength == 8) { + if (MmsValue_getType(value) == MMS_UTC_TIME) { + MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: message contains value of wrong type!\n"); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); + break; + default: + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); + break; + } + + bufPos += elementLength; + + elementIndex++; + } + + return 1; +} + +static MmsValue* +parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure) +{ + int bufPos = 0; + int elementLength = 0; + + int elementIndex = 0; + + MmsValue* dataSetValues = NULL; + + while (bufPos < allDataLength) { + uint8_t tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + + if (bufPos + elementLength > allDataLength) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + goto exit_with_error; + } + + switch (tag) { + case 0x80: /* reserved for access result */ + break; + case 0xa1: /* array */ + break; + case 0xa2: /* structure */ + break; + case 0x83: /* boolean */ + break; + case 0x84: /* BIT STRING */ + break; + case 0x85: /* integer */ + break; + case 0x86: /* unsigned integer */ + break; + case 0x87: /* Float */ + break; + case 0x89: /* octet string */ + break; + case 0x8a: /* visible string */ + break; + case 0x8c: /* binary time */ + break; + case 0x91: /* Utctime */ + break; + default: + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); + goto exit_with_error; + } + + bufPos += elementLength; + + elementIndex++; + } + + if (isStructure) + dataSetValues = MmsValue_createEmptyStructure(elementIndex); + else + dataSetValues = MmsValue_createEmptyArray(elementIndex); + + elementIndex = 0; + bufPos = 0; + + while (bufPos < allDataLength) { + uint8_t tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + + if (bufPos + elementLength > allDataLength) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + goto exit_with_error; + } + + MmsValue* value = NULL; + + switch (tag) { + case 0xa1: /* array */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); + + value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false); + + if (value == NULL) + goto exit_with_error; + + break; + case 0xa2: /* structure */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); + + value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true); + + if (value == NULL) + goto exit_with_error; + + break; + case 0x83: /* boolean */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n"); + value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos)); + + break; + + case 0x84: /* BIT STRING */ + { + int padding = buffer[bufPos]; + int bitStringLength = (8 * (elementLength - 1)) - padding; + value = MmsValue_newBitString(bitStringLength); + memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); + + } + break; + case 0x85: /* integer */ + value = MmsValue_newInteger(elementLength * 8); + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + value->value.integer->size = elementLength; + break; + case 0x86: /* unsigned integer */ + value = MmsValue_newUnsigned(elementLength * 8); + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + value->value.integer->size = elementLength; + break; + case 0x87: /* Float */ + if (elementLength == 9) + value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos)); + else if (elementLength == 5) + value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos)); + break; + + case 0x89: /* octet string */ + value = MmsValue_newOctetString(elementLength, elementLength); + memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); + break; + case 0x8a: /* visible string */ + value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength); + break; + case 0x8c: /* binary time */ + if (elementLength == 4) + value = MmsValue_newBinaryTime(true); + else if (elementLength == 6) + value = MmsValue_newBinaryTime(false); + + if ((elementLength == 4) || (elementLength == 6)) + memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); + + break; + case 0x91: /* Utctime */ + if (elementLength == 8) { + value = MmsValue_newUtcTime(0); + MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); + break; + default: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); + goto exit_with_error; + } + + bufPos += elementLength; + + if (value != NULL) { + MmsValue_setElement(dataSetValues, elementIndex, value); + elementIndex++; + } + } + + self->dataSetValuesSelfAllocated = true; + + return dataSetValues; + +exit_with_error: + + if (dataSetValues != NULL) + MmsValue_delete(dataSetValues); + + return NULL; +} + + +static int +parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) +{ + int bufPos = 0; + uint32_t timeAllowedToLive = 0; + uint32_t stNum = 0; + uint32_t sqNum = 0; + uint32_t confRev; + bool simulation = false; + bool ndsCom = false; + GooseSubscriber matchingSubscriber = NULL; + uint8_t* timestampBufPos = NULL; + uint8_t* dataSetBufferAddress = NULL; + int dataSetBufferLength = 0; + + uint32_t numberOfDatSetEntries = 0; + + if (buffer[bufPos++] == 0x61) { + int gooseLength; + bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); + + int gooseEnd = bufPos + gooseLength; + + while (bufPos < gooseEnd) { + int elementLength; + + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); + + if (bufPos + elementLength > apduLength) { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + + goto exit_with_fault; + } + + if (bufPos == -1) + goto exit_with_fault; + + switch(tag) { + case 0x80: /* gocbRef */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found gocbRef\n"); + + { + LinkedList element = LinkedList_getNext(self->subscriberList); + + while (element != NULL) { + GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); + + if (subscriber->goCBRefLen == elementLength) { + if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n"); + matchingSubscriber = subscriber; + break; + } + } + + element = LinkedList_getNext(element); + } + + if (matchingSubscriber == NULL) + return 0; + } + + break; + + case 0x81: /* timeAllowedToLive */ + + timeAllowedToLive = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timeAllowedToLive %u\n", timeAllowedToLive); + + break; + + case 0x82: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found dataSet\n"); + break; + + case 0x83: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found goId\n"); + break; + + case 0x84: + timestampBufPos = buffer + bufPos; + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timestamp\n"); + break; + + case 0x85: + stNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found stNum: %u\n", stNum); + break; + + case 0x86: + sqNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found sqNum: %u\n", sqNum); + break; + + case 0x87: + simulation = BerDecoder_decodeBoolean(buffer, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found simulation: %i\n", simulation); + break; + + case 0x88: + confRev = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found confRev: %u\n", confRev); + break; + + case 0x89: + ndsCom = BerDecoder_decodeBoolean(buffer, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found ndsCom: %i\n", ndsCom); + break; + + case 0x8a: + numberOfDatSetEntries = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found number of entries: %u\n", numberOfDatSetEntries); + break; + + case 0xab: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found all data with length: %i\n", elementLength); + dataSetBufferAddress = buffer + bufPos; + dataSetBufferLength = elementLength; + break; + + default: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Unknown tag %02x\n", tag); + break; + } + + bufPos += elementLength; + } + + if (matchingSubscriber != NULL) { + + matchingSubscriber->timeAllowedToLive = timeAllowedToLive; + matchingSubscriber->confRev = confRev; + matchingSubscriber->ndsCom = ndsCom; + matchingSubscriber->simulation = simulation; + MmsValue_setUtcTimeByBuffer(matchingSubscriber->timestamp, timestampBufPos); + + if (matchingSubscriber->dataSetValues == NULL) + matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false); + else + parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues); + + bool isValid = true; + + if (matchingSubscriber->stNum == stNum) { + if (matchingSubscriber->sqNum >= sqNum) { + isValid = false; + } + } + + matchingSubscriber->stateValid = isValid; + + matchingSubscriber->stNum = stNum; + matchingSubscriber->sqNum = sqNum; + + matchingSubscriber->invalidityTime = Hal_getTimeInMs() + timeAllowedToLive; + + if (matchingSubscriber->listener != NULL) + matchingSubscriber->listener(matchingSubscriber, matchingSubscriber->listenerParameter); + + return 1; + } + + return 0; + } + +exit_with_fault: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Invalid goose payload\n"); + return -1; +} + + +static void +parseGooseMessage(GooseReceiver self, int numbytes) +{ + int bufPos; + bool subscriberFound = false; + uint8_t* buffer = self->buffer; + + if (numbytes < 22) return; + + /* skip ethernet addresses */ + bufPos = 12; + int headerLength = 14; + + /* check for VLAN tag */ + if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) { + bufPos += 4; /* skip VLAN tag */ + headerLength += 4; + } + + /* check for GOOSE Ethertype */ + if (buffer[bufPos++] != 0x88) + return; + if (buffer[bufPos++] != 0xb8) + return; + + uint16_t appId; + + appId = buffer[bufPos++] * 0x100; + appId += buffer[bufPos++]; + + uint16_t length; + + length = buffer[bufPos++] * 0x100; + length += buffer[bufPos++]; + + /* skip reserved fields */ + bufPos += 4; + + int apduLength = length - 8; + + if (numbytes < length + headerLength) { + if (DEBUG) + printf("GOOSE_SUBSCRIBER: Invalid PDU size\n"); + return; + } + + if (DEBUG_GOOSE_SUBSCRIBER) { + printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n"); + printf("GOOSE_SUBSCRIBER: APPID: %u\n", appId); + printf("GOOSE_SUBSCRIBER: LENGTH: %u\n", length); + printf("GOOSE_SUBSCRIBER: APDU length: %i\n", apduLength); + } + + + // check if there is an interested subscriber + LinkedList element = LinkedList_getNext(self->subscriberList); + + while (element != NULL) { + GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); + + if (subscriber->appId == appId) { + subscriberFound = true; + break; + } + + element = LinkedList_getNext(element); + } + + if (subscriberFound) + parseGoosePayload(self, buffer + bufPos, apduLength); + else { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: GOOSE message ignored due to unknown APPID value\n"); + } +} + + +static void +gooseReceiverLoop(void* threadParameter) +{ + GooseReceiver self = (GooseReceiver) threadParameter; + + self->running = true; + self->stopped = false; + + GooseReceiver_startThreadless(self); + + while (self->running) { + + if (GooseReceiver_tick(self) == false) + Thread_sleep(1); + } + + GooseReceiver_stopThreadless(self); + + self->stopped = true; +} + + +// start GOOSE receiver in a separate thread +void +GooseReceiver_start(GooseReceiver self) +{ + Thread thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, true); + + if (thread != NULL) { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: GOOSE receiver started for interface %s\n", self->interfaceId); + + Thread_start(thread); + } + else { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: Starting GOOSE receiver failed for interface %s\n", self->interfaceId); + } + +} + +void +GooseReceiver_stop(GooseReceiver self) +{ + self->running = false; + + while (self->stopped == false) + Thread_sleep(1); +} + +void +GooseReceiver_destroy(GooseReceiver self) +{ + LinkedList_destroyDeep(self->subscriberList, + (LinkedListValueDeleteFunction) GooseSubscriber_destroy); + + GLOBAL_FREEMEM(self->buffer); + GLOBAL_FREEMEM(self); +} + +/*************************************** + * Functions for non-threaded operation + ***************************************/ +void +GooseReceiver_startThreadless(GooseReceiver self) +{ + if (self->interfaceId == NULL) + self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); + else + self->ethSocket = Ethernet_createSocket(self->interfaceId, NULL); + + Ethernet_setProtocolFilter(self->ethSocket, ETH_P_GOOSE); + + self->running = true; +} + +void +GooseReceiver_stopThreadless(GooseReceiver self) +{ + Ethernet_destroySocket(self->ethSocket); + + self->running = false; +} + +// call after reception of ethernet frame and periodically to to house keeping tasks +bool +GooseReceiver_tick(GooseReceiver self) +{ + int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); + + if (packetSize > 0) { + parseGooseMessage(self, packetSize); + return true; + } + else + return false; +} diff --git a/src/goose/goose_receiver.h b/src/goose/goose_receiver.h new file mode 100644 index 0000000..b313f2b --- /dev/null +++ b/src/goose/goose_receiver.h @@ -0,0 +1,125 @@ +/* + * goose_receiver.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef GOOSE_RECEIVER_H_ +#define GOOSE_RECEIVER_H_ + +#include + +/** + * \addtogroup goose_api_group + */ +/**@{*/ + + +typedef struct sGooseReceiver* GooseReceiver; + +/** + * \brief Create a new receiver instance + * + * A GooseReceiver instance is used to handle all GOOSE messages received on a specific + * network interface. + * + * \return the new GooseReceiver instance + */ +GooseReceiver +GooseReceiver_create(void); + +/** + * \brief sets the interface for the GOOSE receiver + * + * \param self the GooseReceiver instance + * \param interfaceId + */ +void +GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId); + +/** + * \brief Add a subscriber to this receiver instance + * + * NOTE: Do not call this function while the receiver is running (after GooseReceiver_start + * has been called)! + * + * \param self the GooseReceiver instance + * \param subscriber the GooseSubscriber instance to add + */ +void +GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber); + +/** + * \brief Remove a subscriber from this receiver instance + * + * NOTE: Do not call this function while the receiver is running (after GooseReceiver_start + * has been called)! + * + * \param self the GooseReceiver instance + * \param subscriber the GooseSubscriber instance to remove + */ +void +GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber); + +/** + * \brief start the GOOSE receiver in a separate thread + * + * \param self the GooseReceiver instance + */ +void +GooseReceiver_start(GooseReceiver self); + +/** + * \brief stop the GOOSE receiver running in a speparate thread + * + * This function is used to stop the receiver thread started with GooseReceiver_start + * + * \param self the GooseReceiver instance + */ +void +GooseReceiver_stop(GooseReceiver self); + +void +GooseReceiver_destroy(GooseReceiver self); + +/*************************************** + * Functions for non-threaded operation + ***************************************/ +void +GooseReceiver_startThreadless(GooseReceiver self); + +void +GooseReceiver_stopThreadless(GooseReceiver self); + +/** + * \brief Parse GOOSE messages if they are available + * + * Call after reception of ethernet frame and periodically to to house keeping tasks + * + * \param self the receiver object + * + * \return true if a message was available and has been parsed, false otherwise + */ +bool +GooseReceiver_tick(GooseReceiver self); + +/**@}*/ + +#endif /* GOOSE_RECEIVER_H_ */ diff --git a/src/goose/goose_receiver_internal.h b/src/goose/goose_receiver_internal.h new file mode 100644 index 0000000..e595da0 --- /dev/null +++ b/src/goose/goose_receiver_internal.h @@ -0,0 +1,62 @@ +/* + * goose_receiver_internal.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef GOOSE_RECEIVER_INTERNAL_H_ +#define GOOSE_RECEIVER_INTERNAL_H_ + + +#define ETH_BUFFER_LENGTH 1518 + +#define ETH_P_GOOSE 0x88b8 + +#ifndef DEBUG_GOOSE_SUBSCRIBER +#define DEBUG_GOOSE_SUBSCRIBER 0 +#endif + + +struct sGooseSubscriber { + char* goCBRef; + int goCBRefLen; + uint32_t timeAllowedToLive; + uint32_t stNum; + uint32_t sqNum; + uint32_t confRev; + MmsValue* timestamp; + bool simulation; + bool ndsCom; + + uint64_t invalidityTime; + bool stateValid; + + int32_t appId; /* APPID or -1 if APPID should be ignored */ + + MmsValue* dataSetValues; + bool dataSetValuesSelfAllocated; + + GooseListener listener; + void* listenerParameter; +}; + + + +#endif /* GOOSE_RECEIVER_INTERNAL_H_ */ diff --git a/src/goose/goose_subscriber.c b/src/goose/goose_subscriber.c new file mode 100644 index 0000000..f1d1e8e --- /dev/null +++ b/src/goose/goose_subscriber.c @@ -0,0 +1,142 @@ +/* + * goose_subscriber.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" +#include "goose_subscriber.h" +#include "hal_ethernet.h" +#include "hal_thread.h" + +#include "ber_decode.h" + +#include "mms_value.h" +#include "mms_value_internal.h" + +#include "goose_receiver_internal.h" + +GooseSubscriber +GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues) +{ + GooseSubscriber self = (GooseSubscriber) GLOBAL_CALLOC(1, sizeof(struct sGooseSubscriber)); + + self->goCBRef = copyString(goCbRef); + self->goCBRefLen = strlen(goCbRef); + self->timestamp = MmsValue_newUtcTime(0); + self->dataSetValues = dataSetValues; + + if (dataSetValues != NULL) + self->dataSetValuesSelfAllocated = false; + + self->appId = -1; + + return self; +} + +bool +GooseSubscriber_isValid(GooseSubscriber self) +{ + if (self->stateValid == false) + return false; + + if (Hal_getTimeInMs() > self->invalidityTime) + return false; + + return true; +} + +void +GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId) +{ + self->appId = (int32_t) appId; +} + +void +GooseSubscriber_destroy(GooseSubscriber self) +{ + GLOBAL_FREEMEM(self->goCBRef); + + MmsValue_delete(self->timestamp); + + if (self->dataSetValuesSelfAllocated) + MmsValue_delete(self->dataSetValues); + + GLOBAL_FREEMEM(self); +} + +void +GooseSubscriber_setListener(GooseSubscriber self, GooseListener listener, void* parameter) +{ + self->listener = listener; + self->listenerParameter = parameter; +} + +uint32_t +GooseSubscriber_getStNum(GooseSubscriber self) +{ + return self->stNum; +} + +uint32_t +GooseSubscriber_getSqNum(GooseSubscriber self) +{ + return self->sqNum; +} + +bool +GooseSubscriber_isTest(GooseSubscriber self) +{ + return self->simulation; +} + +bool +GooseSubscriber_needsCommission(GooseSubscriber self) +{ + return self->ndsCom; +} + +uint32_t +GooseSubscriber_getTimeAllowedToLive(GooseSubscriber self) +{ + return self->timeAllowedToLive; +} + +uint64_t +GooseSubscriber_getTimestamp(GooseSubscriber self) +{ + return MmsValue_getUtcTimeInMs(self->timestamp); +} + +MmsValue* +GooseSubscriber_getDataSetValues(GooseSubscriber self) +{ + return self->dataSetValues; +} + + + + + + + + diff --git a/src/goose/goose_subscriber.h b/src/goose/goose_subscriber.h new file mode 100644 index 0000000..db35050 --- /dev/null +++ b/src/goose/goose_subscriber.h @@ -0,0 +1,158 @@ +/* + * goose_subscriber.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef GOOSE_SUBSCRIBER_H_ +#define GOOSE_SUBSCRIBER_H_ + +#include "libiec61850_common_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup goose_api_group IEC 61850 GOOSE subscriber API + */ +/**@{*/ + +#include "mms_value.h" + +typedef struct sGooseSubscriber* GooseSubscriber; + +/** + * \brief user provided callback function that will be invoked when a GOOSE message is received. + * + * \param subscriber the subscriber object that invoked the callback function, + * \param parameter a user provided parameter that will be passed to the callback function + */ +typedef void (*GooseListener)(GooseSubscriber subscriber, void* parameter); + +/** + * \brief create a new GOOSE subscriber instance. + * + * A new GOOSE subscriber will be created and connected to a specific GOOSE control block reference. + * + * The parameter goCbRef has to be given in MMS like notation (as it also will appear in the GOOSE message + * sent by the publisher). An example could be "simpleIOGenericIO/LLN0$GO$gcbEvents". + * + * The data set values contained in a GOOSE message will be written to the optionally provided MmsValue instance. + * The MmsValue object has to be of type MMS_ARRAY. The array elements need to be of the same type as + * the data set elements. It is intended that the provided MmsValue instance has been created by the + * IedConnection_getDataSet() method before. + * + * If NULL is given as dataSetValues it will be created the first time when a appropriate GOOSE message + * is received. + * + * \param goCbRef a string containing the object reference of the GOOSE Control Block (GoCB) in MMS notation the + * GOOSE publisher uses. + * \param dataSetValues the MmsValue object where the data set values will be written or NULL. + */ +GooseSubscriber +GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues); + +//char* +//GooseSubscriber_getGoCbRef(GooseSubscriber self); + +/** + * \brief set the APPID used by the subscriber to filter relevant messages. + * + * If APPID is set the subscriber will ignore all messages with other APPID values. + * + * \param self GooseSubscriber instance to operate on. + * \param the APPID value the subscriber should use to filter messages + */ +void +GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId); + +/** + * \brief Check if subscriber state is valid + * + * A GOOSE subscriber is valid if TimeAllowedToLive timeout is not elapsed and GOOSE + * message were received with correct state and sequence ID. + * + */ +bool +GooseSubscriber_isValid(GooseSubscriber self); + +//uint16_t +//GooseSubscriber_getAppId(GooseSubscriber self); + +void +GooseSubscriber_setGoId(GooseSubscriber self, const char* goId); + +//char* +//GooseSubscriber_getGoId(GooseSubscriber self); + +void +GooseSubscriber_destroy(GooseSubscriber self); + +/** + * \brief set a callback function that will be invoked when a GOOSE message has been received. + * + * \param self GooseSubscriber instance to operate on. + * \param listener user provided callback function + * \param parameter a user provided parameter that will be passed to the callback function + */ +void +GooseSubscriber_setListener(GooseSubscriber self, GooseListener listener, void* parameter); + +uint32_t +GooseSubscriber_getStNum(GooseSubscriber self); + +uint32_t +GooseSubscriber_getSqNum(GooseSubscriber self); + +bool +GooseSubscriber_isTest(GooseSubscriber self); + +bool +GooseSubscriber_needsCommission(GooseSubscriber self); + +uint32_t +GooseSubscriber_getTimeAllowedToLive(GooseSubscriber self); + +uint64_t +GooseSubscriber_getTimestamp(GooseSubscriber self); + +/** + * \brief get the data set values received with the last report + * + * Note: To prevent data corruption. The MmsValue instance received should + * only be used inside of the callback function, when the GOOSE receiver is + * running in a separate thread. + * + * \param self GooseSubscriber instance to operate on. + * + * \return MmsValue instance of the report data set + */ +MmsValue* +GooseSubscriber_getDataSetValues(GooseSubscriber self); + +#ifdef __cplusplus +} +#endif + + +/**@}*/ + +#endif /* GOOSE_SUBSCRIBER_H_ */ diff --git a/src/goose/iec61850_goose.asn b/src/goose/iec61850_goose.asn new file mode 100644 index 0000000..2677c28 --- /dev/null +++ b/src/goose/iec61850_goose.asn @@ -0,0 +1,65 @@ +IEC61850 DEFINITIONS ::= BEGIN + +IEC61850SpecificProtocol ::= CHOICE { + -- gseMngtPdu [APPLICATION 0] IMPLICIT GSEMngtPdu, + goosePdu [APPLICATION 1] IMPLICIT IECGoosePdu +} + +IECGoosePdu ::= SEQUENCE { + gocbRef [0] IMPLICIT VisibleString, + timeAllowedtoLive [1] IMPLICIT INTEGER, + datSet [2] IMPLICIT VisibleString, + goID [3] IMPLICIT VisibleString OPTIONAL, + t [4] IMPLICIT UtcTime, + stNum [5] IMPLICIT INTEGER, + sqNum [6] IMPLICIT INTEGER, + simulation [7] IMPLICIT BOOLEAN DEFAULT FALSE, + confRev [8] IMPLICIT INTEGER, + ndsCom [9] IMPLICIT BOOLEAN DEFAULT FALSE, + numDatSetEntries [10] IMPLICIT INTEGER, + allData [11] IMPLICIT SEQUENCE OF Data +} + +Data ::= CHOICE + { + -- context tag 0 is reserved for AccessResult + array [1] IMPLICIT DataSequence, + structure [2] IMPLICIT DataSequence, + boolean [3] IMPLICIT BOOLEAN, + bitstring [4] IMPLICIT BIT STRING, + integer [5] IMPLICIT INTEGER, + unsigned [6] IMPLICIT INTEGER, -- shall not be negative + floatingpoint [7] IMPLICIT FloatingPoint, + -- [8] is reserved + octetstring [9] IMPLICIT OCTET STRING, + visiblestring [10] IMPLICIT VisibleString, + generalizedtime [11] IMPLICIT GeneralizedTime, + binarytime [12] IMPLICIT TimeOfDay, + bcd [13] IMPLICIT INTEGER, + booleanArray [14] IMPLICIT BIT STRING, + --objId [15] IMPLICIT OBJECT IDENTIFIER + mMSString [16] IMPLICIT MMSString, -- unicode string + utctime [17] IMPLICIT UtcTime --UTC Time + } + +DataSequence ::= SEQUENCE OF Data + +FloatingPoint ::= OCTET STRING + +UtcTime ::= OCTET STRING + +MMSString ::= UTF8String + +TimeOfDay ::= OCTET STRING -- (SIZE (4 | 6)) + +END + + + + + + + + + + diff --git a/src/hal/ethernet/bsd/ethernet_bsd.c b/src/hal/ethernet/bsd/ethernet_bsd.c new file mode 100644 index 0000000..fe60199 --- /dev/null +++ b/src/hal/ethernet/bsd/ethernet_bsd.c @@ -0,0 +1,360 @@ +/* + * ethernet_bsd.c + * + * Copyright 2013 Michael Zillgith, contributed to the project by Michael Clausen (School of engineering Valais). + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "libiec61850_platform_includes.h" +#include "hal_ethernet.h" + +struct sEthernetSocket { + int bpf; // BPF device handle. + uint8_t *bpfBuffer; // Pointer to the BPF reception buffer. + int bpfBufferSize; // Actual size of the BPF reception buffer. + uint8_t *bpfPositon; // Actual read pointer on the BPF reception buffer. + uint8_t *bpfEnd; // Pointer to the end of the BPF reception buffer. + struct bpf_program bpfProgram; // BPF filter machine code program. +}; + +int _Ethernet_activateBpdFilter(EthernetSocket self) +{ + return ioctl(self->bpf, BIOCSETF, &self->bpfProgram); +} + +int _Ethernet_setBpfEthernetAddressFilter(EthernetSocket self, uint8_t *addr) +{ + if (addr) + { + // Enable Ethernet address filter. + self->bpfProgram.bf_insns[0].k = 1; + + // Copy the address into the filter code. + memcpy((void *)&self->bpfProgram.bf_insns[3].k, &addr[2], 4); + memcpy((void *)&self->bpfProgram.bf_insns[5].k, &addr, 2); + + return _Ethernet_activateBpdFilter(self); + } + else + { + // Disable Ethernet address filter. + self->bpfProgram.bf_insns[0].k = 0; + + return _Ethernet_activateBpdFilter(self); + } +} + +int _Ethernet_setBpfEthertypeFilter(EthernetSocket self, uint16_t etherType) +{ + if (etherType) + { + // Enable Ethertype filter. + self->bpfProgram.bf_insns[6].k = 1; + + // Set protocol. + self->bpfProgram.bf_insns[9].k = etherType; + + return _Ethernet_activateBpdFilter(self); + } + else + { + // Disable Ethertype filter. + self->bpfProgram.bf_insns[6].k = 0; + + return _Ethernet_activateBpdFilter(self); + } +} + +void +Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr) +{ + struct ifaddrs *ifap, *ifc; + struct sockaddr_dl* link; + + /* Get info about all local network interfaces. */ + if (getifaddrs(&ifap)) + { + printf("Error getting network interfaces list!"); + return; + } + + /* Try to find the selected interface. */ + ifc = ifap; + while (ifc) + { + if (strcmp(ifc->ifa_name, interfaceId) == 0 && + ifc->ifa_addr->sa_family == AF_LINK && ifc->ifa_addr) + break; + ifc = ifc->ifa_next; + } + + // If we found the interface, extract MAC address from the info and copy to the destination. + if (ifc) + { + link = (struct sockaddr_dl *)ifc->ifa_addr; + memcpy(addr, LLADDR(link), link->sdl_alen); + } + else + printf("Could not find the network interface %s!", interfaceId); + + // Free network interface info structure. + freeifaddrs(ifap); +} + +EthernetSocket +Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress) +{ + char bpfFileStringBuffer[11] = { 0 }; + int i; + struct ifreq ifr; + int optval; + struct bpf_insn destAddrFiltCode[] = + { + // Load 0 into accumulator. Change to 1 to enable ethernet address filter. + {0x00, 0, 0, 0x00000000}, // A0: ld #0 + {0x15, 4, 0, 0x00000000}, // jeq #0, P0, A1 + + // Load 4 bytes starting at offest 2 into the accu and compare it with 4 bytes of the destination address. + {0x20, 0, 0, 0x00000002}, // A1: ld [2] + {0x15, 0, 7, 0x00000000}, // jeq #0, A2, KO + + // Load 2 bytes starting at offest 0 into the accu and compare it with 2 bytes of the destination address. + {0x28, 0, 0, 0x00000000}, // A2: ldh [0] + {0x15, 0, 5, 0x00000000}, // jeq #0, P0, KO + + // Load 0 into accumulator. Change to 1 to enable ethernet protocol filter. + {0x00, 0, 0, 0x00000000}, // P0: ld #0 + {0x15, 2, 0, 0x00000000}, // jeq #0, OK, P1 + + // Load 2 bytes starting at offset 12 into the accu and compare it with the given ethertype. + {0x28, 0, 0, 0x0000000c}, // P1: ldh [12] + {0x15, 0, 1, 0x00000000}, // jeq #0, OK, KO + + // Accept packet. + {0x6, 0, 0, 0x0000ffff}, // OK: ret #65535 + + // Drop packet. + {0x6, 0, 0, 0x00000000} // KO: ret #0 + + /* The whole BPF VM assembler program compiled with bpfc into the machine code above: + * + * A0: ld #0 + * jeq #0, P0, A1 + * A1: ld [2] + * jeq #0, A2, KO + * A2: ldh [0] + * jeq #0, P0, KO + * P0: ld #0 + * jeq #0, OK, P1 + * P1: ldh [12] + * jeq #0, OK, KO + * OK: ret #65535 + * KO: ret #0 + */ + }; + + EthernetSocket self = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket)); + if (!self) + { + printf("Could not allocate socket descriptor!\n"); + return NULL; + } + + // Copy default BPF filter program into descriptor. + self->bpfProgram.bf_insns = GLOBAL_CALLOC(1, sizeof(destAddrFiltCode)); + if (!self->bpfProgram.bf_insns) + { + printf("Could not allocate memory for BPF filter program!\n"); + return NULL; + } + memcpy(self->bpfProgram.bf_insns, &destAddrFiltCode, sizeof(destAddrFiltCode)); + self->bpfProgram.bf_len = 12; + + // Find the first unused BPF device node. + self->bpf = -1; + for (i = 0; i < 99; ++i) + { + sprintf(bpfFileStringBuffer, "/dev/bpf%i", i); + self->bpf = open(bpfFileStringBuffer, O_RDWR); + + if (self->bpf != -1) break; + } + + // Did not found any unused, fail. + if (self->bpf == -1) + { + printf("Error opening BPF file handle!\n"); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); + return NULL; + } + + // Activate non-blocking operation. + optval = ioctl(self->bpf, F_GETFL); + optval |= O_NONBLOCK; + if (fcntl(self->bpf, F_SETFL, &optval) == -1) + { + printf("Unable to change to non-blocking mode!\n"); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); + return NULL; + } + + // Select the network interface for the BPF. + strncpy(ifr.ifr_name, interfaceId, IFNAMSIZ); + if (ioctl(self->bpf, BIOCSETIF, &ifr)) + { + printf("Unable to select interface %s!\n", interfaceId); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); + return NULL; + } + + // Activate immediate mode. + if (ioctl(self->bpf, BIOCIMMEDIATE, &self->bpfBufferSize) == -1) + { + printf("Unable to activate immediate mode!\n"); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); + return NULL; + } + + // Get the buffer length from the BPF handle. + if (ioctl(self->bpf, BIOCGBLEN, &self->bpfBufferSize) == -1) + { + printf("Unable to get BPF buffer lenght!\n"); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); + return NULL; + } + + // Allocate a buffer for the message reception. + self->bpfBuffer = GLOBAL_CALLOC(1, self->bpfBufferSize); + if (!self->bpfBuffer) + { + printf("Unable to allocate BPF RX buffer!\n"); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); + return NULL; + } + self->bpfPositon = self->bpfBuffer; + self->bpfEnd = self->bpfBuffer; + + // Set BPF into promiscous mode. + optval = 1; + if (ioctl(self->bpf, BIOCPROMISC, &optval) == -1) + { + printf("Unable to activate promiscous mode!\n"); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self->bpfBuffer); + GLOBAL_FREEMEM(self); + return NULL; + } + + return self; +} + +void Ethernet_setProtocolFilter(EthernetSocket self, uint16_t etherType) +{ + if (!self || !self->bpfProgram.bf_insns || _Ethernet_setBpfEthertypeFilter(self, etherType)) + printf("Unable to set ethertype filter!\n"); +} + +int Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) +{ + // If the actual buffer is empty, make a read call to the BSP device in order to get new data. + if (self->bpfEnd - self->bpfPositon < 4) + { + // Position the read pointer to the start of the buffer. + self->bpfPositon = self->bpfBuffer; + + // Read one or more frames from the BPF handle. + int size = read(self->bpf, self->bpfBuffer, self->bpfBufferSize); + + // Set the end pointer to the end of the received data or to 0 if no data at all was received. + if (size >= 0) + self->bpfEnd = self->bpfBuffer + size; + else + self->bpfEnd = NULL; + } + + // Do we actually have at least one ethernet frame received? + if (self->bpfPositon < self->bpfEnd) + { + // BPF adds a header to each packet, so we have to interpret it. + struct bpf_hdr *header = (struct bpf_hdr *)(self->bpfPositon); + + // Check if the target buffer is big enough to hold the received ethernet frame. + if ((unsigned int) bufferSize >= header->bh_caplen) + { + // Copy the frame to the target buffer. + memcpy(buffer, self->bpfPositon + header->bh_hdrlen, header->bh_caplen); + + // Move the read pointer to the next ethernet frame header WORD ALIGNED (Took me a while to find that out). + self->bpfPositon += BPF_WORDALIGN(header->bh_hdrlen + header->bh_caplen); + + // Return the number of bytes copied to the target buffer. + return header->bh_caplen; + } + else + // The buffer is too small, return an error. + // TODO: Would be there a standard error number to signal that the target buffer is too small? + return -1; + } + else + // We did not get any ethernet frames, so return 0. + return 0; +} + +void Ethernet_sendPacket(EthernetSocket self, uint8_t* buffer, int packetSize) +{ + // Just send the packet as it is. + write(self->bpf, buffer, packetSize); +} + +void Ethernet_destroySocket(EthernetSocket self) +{ + // Close the BPF device. + close(self->bpf); + + // Free all dynamic resources used by the ethernet socket. + GLOBAL_FREEMEM(self->bpfBuffer); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); +} + +bool +Ethernet_isSupported() +{ + return true; +} + diff --git a/src/hal/ethernet/linux/ethernet_linux.c b/src/hal/ethernet/linux/ethernet_linux.c new file mode 100644 index 0000000..cff4f06 --- /dev/null +++ b/src/hal/ethernet/linux/ethernet_linux.c @@ -0,0 +1,171 @@ +/* + * ethernet_linux.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libiec61850_platform_includes.h" +#include "hal_ethernet.h" + +struct sEthernetSocket { + int rawSocket; + bool isBind; + struct sockaddr_ll socketAddress; +}; + +static int +getInterfaceIndex(int sock, const char* deviceName) +{ + struct ifreq ifr; + + strncpy(ifr.ifr_name, deviceName, IFNAMSIZ); + + if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) { + perror("ETHERNET_LINUX: Failed to get interface index -> exit"); + exit(1); + } + + int interfaceIndex = ifr.ifr_ifindex; + + if (ioctl (sock, SIOCGIFFLAGS, &ifr) == -1) + { + perror ("ETHERNET_LINUX: Problem getting device flags -> exit"); + exit (1); + } + + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1) + { + perror ("ETHERNET_LINUX: Setting device to promiscuous mode failed -> exit"); + exit (1); + } + + return interfaceIndex; +} + + +void +Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr) +{ + struct ifreq buffer; + + int sock = socket(PF_INET, SOCK_DGRAM, 0); + + memset(&buffer, 0x00, sizeof(buffer)); + + strcpy(buffer.ifr_name, interfaceId); + + ioctl(sock, SIOCGIFHWADDR, &buffer); + + close(sock); + + int i; + + for(i = 0; i < 6; i++ ) + { + addr[i] = (unsigned char)buffer.ifr_hwaddr.sa_data[i]; + } +} + + +EthernetSocket +Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress) +{ + EthernetSocket ethernetSocket = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket)); + + ethernetSocket->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + if (ethernetSocket->rawSocket == -1) { + printf("Error creating raw socket!\n"); + GLOBAL_FREEMEM(ethernetSocket); + return NULL; + } + + ethernetSocket->socketAddress.sll_family = PF_PACKET; + ethernetSocket->socketAddress.sll_protocol = htons(ETH_P_IP); + + ethernetSocket->socketAddress.sll_ifindex = getInterfaceIndex(ethernetSocket->rawSocket, interfaceId); + + ethernetSocket->socketAddress.sll_hatype = ARPHRD_ETHER; + ethernetSocket->socketAddress.sll_pkttype = PACKET_OTHERHOST; + + ethernetSocket->socketAddress.sll_halen = ETH_ALEN; + + memset(ethernetSocket->socketAddress.sll_addr, 0, 8); + + if (destAddress != NULL) + memcpy(ethernetSocket->socketAddress.sll_addr, destAddress, 6); + + ethernetSocket->isBind = false; + + return ethernetSocket; +} + +void +Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType) +{ + ethSocket->socketAddress.sll_protocol = htons(etherType); +} + + +/* non-blocking receive */ +int +Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) +{ + if (self->isBind == false) { + if (bind(self->rawSocket, (struct sockaddr*) &self->socketAddress, sizeof(self->socketAddress)) == 0) + self->isBind = true; + else + return 0; + } + + return recvfrom(self->rawSocket, buffer, bufferSize, MSG_DONTWAIT, 0, 0); +} + +void +Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize) +{ + sendto(ethSocket->rawSocket, buffer, packetSize, + 0, (struct sockaddr*) &(ethSocket->socketAddress), sizeof(ethSocket->socketAddress)); +} + +void +Ethernet_destroySocket(EthernetSocket ethSocket) +{ + close(ethSocket->rawSocket); + GLOBAL_FREEMEM(ethSocket); +} + +bool +Ethernet_isSupported() +{ + return true; +} + diff --git a/src/hal/ethernet/win32/ethernet_win32.c b/src/hal/ethernet/win32/ethernet_win32.c new file mode 100644 index 0000000..432c36c --- /dev/null +++ b/src/hal/ethernet/win32/ethernet_win32.c @@ -0,0 +1,365 @@ +/* + * ethernet_win32.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "stack_config.h" + +#include + +#include "hal_ethernet.h" + +#include "libiec61850_platform_includes.h" + +#if (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1) + + +#include + +#include +#include + +#ifndef __GNUC__ +#pragma comment (lib, "IPHLPAPI.lib") +#endif + +#define HAVE_REMOTE + +#include "pcap.h" + +struct sEthernetSocket { + pcap_t* rawSocket; + struct bpf_program etherTypeFilter; +}; + +#ifdef __GNUC__ /* detect MINGW */ + +#ifndef __MINGW64_VERSION_MAJOR + +#define MAX_ADAPTER_ADDRESS_LENGTH 8 + +typedef struct _IP_ADAPTER_ADDRESSES { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD IfIndex; + }; + }; + struct _IP_ADAPTER_ADDRESSES *Next; + PCHAR AdapterName; + void* FirstUnicastAddress; + void* FirstAnycastAddress; + void* FirstMulticastAddress; + void* FirstDnsServerAddress; + PWCHAR DnsSuffix; + PWCHAR Description; + PWCHAR FriendlyName; + BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; + DWORD PhysicalAddressLength; + DWORD Flags; + DWORD Mtu; + DWORD IfType; +} IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES; + + +typedef ULONG (WINAPI* pgetadaptersaddresses)(ULONG family, ULONG flags, PVOID reserved, PIP_ADAPTER_ADDRESSES AdapterAddresses, + PULONG SizePointer); + +static pgetadaptersaddresses GetAdaptersAddresses; + + +static bool dllLoaded = false; + +static void +loadDLLs(void) +{ + HINSTANCE hDll = LoadLibrary("iphlpapi.dll"); + + if (hDll == NULL) { + printf("Error loading iphlpapi.dll!\n"); + return; + } + + + GetAdaptersAddresses = (pgetadaptersaddresses) GetProcAddress(hDll, + "GetAdaptersAddresses"); + + if (GetAdaptersAddresses == NULL) + printf("Error loading GetAdaptersAddresses from iphlpapi.dll (%d)\n", (int) GetLastError()); +} + +#endif /* __MINGW64_VERSION_MAJOR */ + +#endif /* __GNUC__ */ + + +static char* +getInterfaceName(int interfaceIndex) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char* interfaceName = NULL; + + pcap_if_t *devices; + pcap_if_t *device; + + /* Get the ethernet device list */ + if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &devices, errbuf) == -1) + { + printf("pcap_findalldevs_ex: %s\n", errbuf); + return NULL; + } + + bool ifaceFound = false; + + /* Search device list for requested interface) */ + int i = 0; + for(device = devices; device != NULL; device= device->next) + { + if (i == interfaceIndex) { + interfaceName = (char*) malloc(strlen(device->name) + 1); + strcpy(interfaceName, device->name); + printf("Use interface (%s)\n", interfaceName); + ifaceFound = true; + break; + } + + i++; + } + + if (!ifaceFound) + { + printf("No ethernet interfaces found! Make sure WinPcap is installed.\n"); + return NULL; + } + + pcap_freealldevs(devices); + + return interfaceName; +} + +static void +getAdapterMacAddress(char* pcapAdapterName, uint8_t* macAddress) +{ + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + ULONG outBufLen = 0; + + pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(65000); + + if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { + free(pAddresses); + pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(outBufLen); + } + + if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR) { + PIP_ADAPTER_ADDRESSES pAddress = pAddresses; + + while (pAddress != NULL) { + + DWORD addressLength = pAddress->PhysicalAddressLength; + + if (addressLength == 6) { + + int i; + + printf("Adapter %s: ", pAddress->AdapterName); + + for (i = 0; i < (int) addressLength; i++) { + printf("%02x ", pAddress->PhysicalAddress[i]); + } + + if (strstr(pcapAdapterName, pAddress->AdapterName) != 0) { + printf(" requested found!"); + + for (i = 0; i < (int) addressLength; i++) { + macAddress[i] = pAddress->PhysicalAddress[i]; + } + } + + printf("\n"); + } + + pAddress = pAddress->Next; + } + + free(pAddresses); + } + else { + printf("Error getting device addresses!\n"); + } +} + + + +void +Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr) +{ +#ifdef __GNUC__ +#ifndef __MINGW64_VERSION_MAJOR + if (!dllLoaded) { + loadDLLs(); + dllLoaded = true; + } +#endif +#endif + + char* endPtr; + + long interfaceIndex = strtol(interfaceId, &endPtr, 10); + + if (endPtr != NULL) { + printf("Ethernet_getInterfaceMACAddress: invalid interface number %s\n", interfaceId); + return; + } + + char* interfaceName = getInterfaceName((int) interfaceIndex); + + getAdapterMacAddress(interfaceName, addr); +} + + +EthernetSocket +Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress) +{ + pcap_t *pcapSocket; + char errbuf[PCAP_ERRBUF_SIZE]; + + int interfaceIndex = atoi(interfaceId); + + char* interfaceName = getInterfaceName(interfaceIndex); + + if ((pcapSocket = pcap_open_live(interfaceName, 65536, PCAP_OPENFLAG_PROMISCUOUS, 10, errbuf)) == NULL) + { + printf("Open ethernet socket failed for device %s\n", interfaceName); + return NULL; + } + + EthernetSocket ethernetSocket = (EthernetSocket) calloc(1, sizeof(struct sEthernetSocket)); + + ethernetSocket->rawSocket = pcapSocket; + + return ethernetSocket; +} + +void +Ethernet_destroySocket(EthernetSocket ethSocket) +{ + pcap_close(ethSocket->rawSocket); + free(ethSocket); +} + +void +Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize) +{ + if (pcap_sendpacket(ethSocket->rawSocket, buffer, packetSize) != 0) + printf("Error sending the packet: %s\n", pcap_geterr(ethSocket->rawSocket)); +} + +void +Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType) +{ + char filterString[100]; + + sprintf(filterString, "(ether proto 0x%04x) or (vlan and ether proto 0x%04x)", etherType, etherType); + + if (pcap_compile(ethSocket->rawSocket, &(ethSocket->etherTypeFilter), filterString, 1, 0) < 0) { + printf("Compiling packet filter failed!\n"); + return; + } + + if (pcap_setfilter(ethSocket->rawSocket, &(ethSocket->etherTypeFilter)) < 0) { + printf("Setting packet filter failed!\n"); + } +} + +int +Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) +{ + struct pcap_pkthdr* header; + uint8_t* packetData; + + int pcapCode = pcap_next_ex(self->rawSocket, &header, (const unsigned char**) &packetData); + + if (pcapCode > 0) { + int packetSize = header->caplen; + + if (packetSize > bufferSize) + packetSize = bufferSize; + + memcpy(buffer, packetData, packetSize); + + return packetSize; + } + else { + if (pcapCode < 0) + printf("winpcap error\n"); + + return 0; + } +} + +bool +Ethernet_isSupported() +{ + return true; +} + +#else + +bool +Ethernet_isSupported() +{ + return false; +} + +void +Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr) +{ +} + +EthernetSocket +Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress) +{ + return NULL; +} + +void +Ethernet_destroySocket(EthernetSocket ethSocket) +{ +} + +void +Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize) +{ +} + +void +Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType) +{ +} + +int +Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) +{ + return 0; +} + +#endif /* (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1) */ diff --git a/src/hal/filesystem/linux/file_provider_linux.c b/src/hal/filesystem/linux/file_provider_linux.c new file mode 100644 index 0000000..c973dd2 --- /dev/null +++ b/src/hal/filesystem/linux/file_provider_linux.c @@ -0,0 +1,214 @@ +/* + * file_provider_linux.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include + +#include +#include +#include + +#include "libiec61850_platform_includes.h" + +#include "hal_filesystem.h" + +#include "stack_config.h" + +#ifndef CONFIG_VIRTUAL_FILESTORE_BASEPATH +#define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/" +#endif + +static char* fileBasePath = CONFIG_VIRTUAL_FILESTORE_BASEPATH; + +struct sDirectoryHandle { + DIR* handle; +}; + +static void +createFullPathFromFileName(char* fullPath, char* filename) +{ + strcpy(fullPath, fileBasePath); + + if (filename != NULL) + strcat(fullPath, filename); +} + + +void +FileSystem_setBasePath(char* basePath) +{ + fileBasePath = basePath; +} + +FileHandle +FileSystem_openFile(char* fileName, bool readWrite) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(fullPath, fileName); + + FileHandle newHandle = NULL; + + if (readWrite) + newHandle = (FileHandle) fopen(fullPath, "w"); + else + newHandle = (FileHandle) fopen(fullPath, "r"); + + return newHandle; +} + +int +FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize) +{ + return fread(buffer, maxSize, 1, (FILE*) handle); +} + +void +FileSystem_closeFile(FileHandle handle) +{ + fclose((FILE*) handle); +} + +bool +FileSystem_deleteFile(char* filename) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(fullPath, filename); + + if (remove(fullPath) == 0) + return true; + else + return false; +} + +bool +FileSystem_renameFile(char* oldFilename, char* newFilename) +{ + char oldFullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + char newFullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(oldFullPath, oldFilename); + createFullPathFromFileName(newFullPath, newFilename); + + if (rename(oldFullPath, newFullPath) == 0) + return true; + else + return false; +} + + +bool +FileSystem_getFileInfo(char* filename, uint32_t* fileSize, uint64_t* lastModificationTimestamp) +{ + struct stat fileStats; + + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + + createFullPathFromFileName(fullPath, filename); + + if (stat(fullPath, &fileStats) == -1) + return false; + + if (lastModificationTimestamp != NULL) + *lastModificationTimestamp = (uint64_t) (fileStats.st_mtime) * 1000LL; + // does not work on older systems --> *lastModificationTimestamp = (uint64_t) (fileStats.st_ctim.tv_sec) * 1000LL; + + if (fileSize != NULL) + *fileSize = fileStats.st_size; + + return true; +} + +DirectoryHandle +FileSystem_openDirectory(char* directoryName) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(fullPath, directoryName); + + DIR* dirHandle = opendir(fullPath); + + DirectoryHandle handle = NULL; + + if (dirHandle != NULL) { + handle = GLOBAL_MALLOC(sizeof(struct sDirectoryHandle)); + handle->handle = dirHandle; + } + + return handle; +} + +char* +FileSystem_readDirectory(DirectoryHandle directory, bool* isDirectory) +{ + struct dirent *dir; + + dir = readdir(directory->handle); + + if (dir != NULL) { + if (dir->d_name[0] == '.') + return FileSystem_readDirectory(directory, isDirectory); + else { + if (isDirectory != NULL) { + if (dir->d_type == DT_DIR) + *isDirectory = true; + else + *isDirectory = false; + } + + return dir->d_name; + } + } + else + return NULL; +} + +void +FileSystem_closeDirectory(DirectoryHandle directory) +{ + closedir(directory->handle); + GLOBAL_FREEMEM(directory); +} + +#if 0 +int +main(int argc, char** argv) +{ + DirectoryHandle directory = FileSystem_openDirectory("/"); + + if (directory != NULL) { + char* fileName = FileSystem_readDirectory(directory); + + + while (fileName != NULL) { + printf("FILE: (%s)\n", fileName); + fileName = FileSystem_readDirectory(directory); + } + + FileSystem_closeDirectory(directory); + } + else + printf("Error opening directory!\n"); +} +#endif diff --git a/src/hal/filesystem/win32/file_provider_win32.c b/src/hal/filesystem/win32/file_provider_win32.c new file mode 100644 index 0000000..9f25d23 --- /dev/null +++ b/src/hal/filesystem/win32/file_provider_win32.c @@ -0,0 +1,242 @@ +/* + * file_provider_win32.c + * + * Copyright 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include +#include + +#include +#include + +#include "hal_filesystem.h" + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" + +#include + +#include + +#ifndef CONFIG_VIRTUAL_FILESTORE_BASEPATH +#define CONFIG_VIRTUAL_FILESTORE_BASEPATH ".\\vmd-filestore\\" +#endif + +static char* fileBasePath = CONFIG_VIRTUAL_FILESTORE_BASEPATH; + +struct sDirectoryHandle { + HANDLE handle; + WIN32_FIND_DATAW findData; + char utf8Filename[MAX_PATH * 3 + 1]; + bool available; +}; + +static void +createFullPathFromFileName(char* fullPath, char* filename) +{ + strcpy(fullPath, fileBasePath); + + if (filename != NULL) + strcat(fullPath, filename); +} + +void +FileSystem_setBasePath(char* basePath) +{ + fileBasePath = basePath; +} + +FileHandle +FileSystem_openFile(char* fileName, bool readWrite) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(fullPath, fileName); + + FileHandle newHandle = NULL; + + if (readWrite) + newHandle = (FileHandle) fopen(fullPath, "wb"); + else + newHandle = (FileHandle) fopen(fullPath, "rb"); + + return newHandle; +} + +int +FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize) +{ + return fread(buffer, maxSize, 1, (FILE*) handle); +} + +void +FileSystem_closeFile(FileHandle handle) +{ + fclose((FILE*) handle); +} + +bool +FileSystem_getFileInfo(char* filename, uint32_t* fileSize, uint64_t* lastModificationTimestamp) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + + createFullPathFromFileName(fullPath, filename); + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (GetFileAttributesEx(fullPath, GetFileExInfoStandard, &fad) == 0) + return false; + + if (lastModificationTimestamp != NULL) { + FILETIME lastModTime = fad.ftLastWriteTime; + + uint64_t now; + + static const uint64_t DIFF_TO_UNIXTIME = 11644473600000LL; + + now = (LONGLONG) lastModTime.dwLowDateTime + ((LONGLONG)(lastModTime.dwHighDateTime) << 32LL); + + *lastModificationTimestamp = (now / 10000LL) - DIFF_TO_UNIXTIME; + } + + if (fileSize != NULL) + *fileSize = (uint32_t) fad.nFileSizeLow; + + return true; +} + +DirectoryHandle +FileSystem_openDirectory(char* directoryName) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(fullPath, directoryName); + + DirectoryHandle dirHandle = (DirectoryHandle) GLOBAL_CALLOC(1, sizeof(struct sDirectoryHandle)); + + strcat(fullPath, "\\*"); + + /* convert UTF-8 path name to WCHAR */ + WCHAR unicodeFullPath[MAX_PATH + 1]; + MultiByteToWideChar(CP_UTF8, 0, fullPath, -1, unicodeFullPath, MAX_PATH); + + dirHandle->handle = FindFirstFileW(unicodeFullPath, &(dirHandle->findData)); + + if (dirHandle->handle != NULL) { + dirHandle->available = true; + + /* convert WCHAR to UTF-8 */ + WideCharToMultiByte(CP_UTF8, 0, dirHandle->findData.cFileName, -1, dirHandle->utf8Filename, (MAX_PATH * 3) + 1, NULL, NULL); + } + + if (dirHandle->handle == INVALID_HANDLE_VALUE) { + GLOBAL_FREEMEM(dirHandle); + return NULL; + } + else + return dirHandle; +} + +static char* +getNextDirectoryEntry(DirectoryHandle directory, bool* isDirectory) +{ + if (directory->available == true) { + directory->available = false; + + if (directory->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + *isDirectory = true; + else + *isDirectory = false; + + return directory->utf8Filename; + } + else { + + if (FindNextFileW(directory->handle, &(directory->findData)) != 0) { + + if (directory->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + *isDirectory = true; + else + *isDirectory = false; + + /* convert WCHAR to UTF-8 */ + WideCharToMultiByte(CP_UTF8, 0, directory->findData.cFileName, -1, directory->utf8Filename, (MAX_PATH * 3) + 1, NULL, NULL); + + return directory->utf8Filename; + } + else + return NULL; + } +} + + +bool +FileSystem_deleteFile(char* filename) +{ + char fullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(fullPath, filename); + + if (remove(fullPath) == 0) + return true; + else + return false; +} + +bool +FileSystem_renameFile(char* oldFilename, char* newFilename) +{ + char oldFullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + char newFullPath[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255]; + + createFullPathFromFileName(oldFullPath, oldFilename); + createFullPathFromFileName(newFullPath, newFilename); + + if (rename(oldFullPath, newFullPath) == 0) + return true; + else + return false; +} + + +char* +FileSystem_readDirectory(DirectoryHandle directory, bool* isDirectory) +{ + char* fileName = getNextDirectoryEntry(directory, isDirectory); + + if (fileName != NULL) { + if (fileName[0] == '.') + return FileSystem_readDirectory(directory, isDirectory); + else + return fileName; + } + + return NULL; +} + +void +FileSystem_closeDirectory(DirectoryHandle directory) +{ + FindClose(directory->handle); + GLOBAL_FREEMEM(directory); +} + diff --git a/src/hal/inc/hal_ethernet.h b/src/hal/inc/hal_ethernet.h new file mode 100644 index 0000000..137e717 --- /dev/null +++ b/src/hal/inc/hal_ethernet.h @@ -0,0 +1,120 @@ +/* + * ethernet_hal.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ETHERNET_HAL_H_ +#define ETHERNET_HAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup hal + * + * @{ + */ + +/** + * @defgroup HAL_ETHERNET Direct access to the ethernet layer (optional - required by GOOSE and Sampled Values) + * + * @{ + */ + + +/** + * \brief Opaque handle that represents an Ethernet "socket". + */ +typedef struct sEthernetSocket* EthernetSocket; + +/** + * \brief Return the MAC address of an Ethernet interface. + * + * The result are the six bytes that make up the Ethernet MAC address. + * + * \param interfaceId the ID of the Ethernet interface + * \param addr pointer to a buffer to store the MAC address + */ +void +Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr); + +/** + * \brief Create an Ethernet socket using the specified interface and + * destination MAC address. + * + * \param interfaceId the ID of the Ethernet interface + * \param destAddress byte array that contains the Ethernet MAC address + */ +EthernetSocket +Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress); + +/** + * \brief destroy the ethernet socket + * + * \param ethSocket the ethernet socket handle + */ +void +Ethernet_destroySocket(EthernetSocket ethSocket); + +void +Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize); + +/* + * \brief set a protocol filter for the specified etherType + * + * \param ethSocket the ethernet socket handle + * \param etherType the ether type of messages to accept + */ +void +Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType); + +/** + * \brief receive an ethernet packet (non-blocking) + * + * \param ethSocket the ethernet socket handle + * \param buffer the buffer to copy the message to + * \param the maximum size of the buffer + * + * \return size of message received in bytes + */ +int +Ethernet_receivePacket(EthernetSocket ethSocket, uint8_t* buffer, int bufferSize); + +/** + * \brief Indicates if runtime provides support for direct Ethernet access + * + * \return true if Ethernet support is available, false otherwise + */ +bool +Ethernet_isSupported(void); + +/*! @} */ + +/*! @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ETHERNET_HAL_H_ */ diff --git a/src/hal/inc/hal_filesystem.h b/src/hal/inc/hal_filesystem.h new file mode 100644 index 0000000..f18f674 --- /dev/null +++ b/src/hal/inc/hal_filesystem.h @@ -0,0 +1,177 @@ +/* + * filesystem_hal.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef FILESYSTEM_HAL_H_ +#define FILESYSTEM_HAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup hal + * + * @{ + */ + +/** + * @defgroup HAL_FILESYSTEM Interface to the native file system (optional) + * + * @{ + */ + +typedef void* FileHandle; +typedef struct sDirectoryHandle* DirectoryHandle; + +#ifndef CONFIG_SYSTEM_FILE_SEPARATOR +#define CONFIG_SYSTEM_FILE_SEPARATOR '/' +#endif + +/** + * \brief open a file + * + * \param pathName full name (path + filename) of the file + * \param readWrite true opens the file with read and write access - false opens for read access only + * + * \return a handle for the file. Has to be used by subsequent calls to file functions to identify the file or + * NULL if opening fails + */ +FileHandle +FileSystem_openFile(char* pathName, bool readWrite); + +/** + * \brief read from an open file + * + * This function will read the next block of the file. The maximum number of bytes to read + * is given. A call to this function will move the file position by the number of bytes read. + * If the file position reaches the end of file then subseqeuent calls of this function shall + * return 0. + * + * \param handle the file handle to identify the file + * \param buffer the buffer to write the read data + * \param maxSize maximum number of bytes to read + * + * \return the number of bytes actually read + */ +int +FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize); + +/** + * \brief close an open file + * + * \param handle the file handle to identify the file + */ +void +FileSystem_closeFile(FileHandle handle); + +/** + * \brief return attributes of the given file + * + * This function is used by the MMS layer to determine basic file attributes. + * The size of the file has to be returned in bytes. The timestamp of the last modification has + * to be returned as milliseconds since Unix epoch - or 0 if this function is not supported. + * + * \param pathName full name (path + filename) of the file + * \param fileSize a pointer where to store the file size + * \param lastModificationTimestamp is used to store the timestamp of last modification of the file + * + * \return true if file exists, false if not + */ +bool +FileSystem_getFileInfo(char* filename, uint32_t* fileSize, uint64_t* lastModificationTimestamp); + +/** + * \brief delete a file + * + * \param pathName full name (path + filename) of the file + * + * \return true on success, false on error + */ +bool +FileSystem_deleteFile(char* filename); + +/** + * \brief rename a file + * + * \param oldFileName current full name (path + filename) of the file + * \param newFileName new full name (path + filename) of the file + * + * \return true on success, false on error + */ +bool +FileSystem_renameFile(char* oldFilename, char* newFilename); + +/** + * \brief open the directoy with the specified name + * + * \param directoryName + * + * \return a handle for the opened directory to be used in subsequent calls to identify the directory + */ +DirectoryHandle +FileSystem_openDirectory(char* directoryName); + +/** + * \brief read the next directory entry + * + * This function returns the next directory entry. The entry is only a valid pointer as long as the + * FileSystem_closeDirectory or another FileSystem_readDirectory function is not called for the given + * DirectoryHandle. + * + * \param directory the handle to identify the directory + * \param isDirectory return value that indicates if the directory entry is itself a directory (true) + * + * \return the name of the directory entry + */ +char* +FileSystem_readDirectory(DirectoryHandle directory, bool* isDirectory); + + +/** + * \brief close a directory + * + * \param directory the handle to identify the directory + */ +void +FileSystem_closeDirectory(DirectoryHandle directory); + +/** + * \brief set local file system base path for the MMS VMD + * + * NOTE: the meaning of this functions is platform specific. It was introduced to + * simplify the configuration of the VMD base path at runtime. It may not be supported + * on all platform. Also it is not called by the MMS protocol stack. + * + * \param basePath the local base path of the MMS VMD + */ +void +FileSystem_setBasePath(char* basePath); + +/*! @} */ + +/*! @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* FILESYSTEM_HAL_H_ */ diff --git a/src/hal/inc/hal_socket.h b/src/hal/inc/hal_socket.h new file mode 100644 index 0000000..a6d64c0 --- /dev/null +++ b/src/hal/inc/hal_socket.h @@ -0,0 +1,263 @@ +/* + * socket_hal.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef SOCKET_HAL_H_ +#define SOCKET_HAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup hal Platform (Hardware/OS) abstraction layer + * + * @{ + */ + +/** + * @defgroup HAL_SOCKET Interface to the TCP/IP stack (abstract socket layer) + * + * Thread and Socket abstraction layer. This functions have to be implemented to + * port libIEC61850 to a new hardware/OS platform. + * + * @{ + */ + +/** Opaque reference for a server socket instance */ +typedef struct sServerSocket* ServerSocket; + +/** Opaque reference for a client or connection socket instance */ +typedef struct sSocket* Socket; + +/** Opaque reference for a set of server and socket handles */ +typedef struct sHandleSet* HandleSet; + +/** + * \brief Create a new connection handle set (HandleSet) + * + * \return new HandleSet instance + */ +HandleSet +Handleset_new(void); + +/** + * \brief add a soecket to an existing handle set + * + * \param self the HandleSet instance + * \param sock the socket to add + */ +void +Handleset_addSocket(HandleSet self, const Socket sock); + + +/** + * \brief wait for a socket to become ready + * + * This function is corresponding to the BSD socket select function. + * It returns the number of sockets on which data is pending or 0 if no data is pending + * on any of the monitored connections. The function will return after "timeout" ms if no + * data is pending. + * The function shall return -1 if a socket error occures. + * + * \param self the HandleSet instance + * \param timeout in milliseconds (ms) + */ +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs); + +/** + * \brief destroy the HandleSet instance + * + * \param self the HandleSet instance to destroy + */ +void +Handleset_destroy(HandleSet self); + +/** + * \brief Create a new TcpServerSocket instance + * + * Implementation of this function is MANDATORY if server functionality is required. + * + * \param address ip address or hostname to listen on + * \param port the TCP port to listen on + * + * \return the newly create TcpServerSocket instance + */ +ServerSocket +TcpServerSocket_create(const char* address, int port); + + +void +ServerSocket_listen(ServerSocket self); + +/** + * \brief accept a new incoming connection (non-blocking) + * + * This function shall accept a new incoming connection. It is non-blocking and has to + * return NULL if no new connection is pending. + * + * Implementation of this function is MANDATORY if server functionality is required. + * + * NOTE: The behaviour of this function changed with version 0.8! + * + * \param self server socket instance + * + * \return handle of the new connection socket or NULL if no new connection is available + */ +Socket +ServerSocket_accept(ServerSocket self); + + +/** + * \brief set the maximum number of pending connection in the queue + * + * Implementation of this function is OPTIONAL. + * + * \param self the server socket instance + * \param backlog the number of pending connections in the queue + * + */ +void +ServerSocket_setBacklog(ServerSocket self, int backlog); + +/** + * \brief destroy a server socket instance + * + * Free all resources allocated by this server socket instance. + * + * Implementation of this function is MANDATORY if server functionality is required. + * + * \param self server socket instance + */ +void +ServerSocket_destroy(ServerSocket self); + +/** + * \brief create a TCP client socket + * + * Implementation of this function is MANDATORY if client functionality is required. + * + * \return a new client socket instance. + */ +Socket +TcpSocket_create(void); + +/** + * \brief set the timeout to establish a new connection + * + * \param self the client socket instance + * \param timeoutInMs the timeout in ms + */ +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs); + +/** + * \brief connect to a server + * + * Connect to a server application identified by the address and port parameter. + * + * The "address" parameter may either be a hostname or an IP address. The IP address + * has to be provided as a C string (e.g. "10.0.2.1"). + * + * Implementation of this function is MANDATORY if client functionality is required. + * + * NOTE: return type changed from int to bool with version 0.8 + * + * \param self the client socket instance + * \param address the IP address or hostname as C string + * \param port the TCP port of the application to connect to + * + * \return a new client socket instance. + */ +bool +Socket_connect(Socket self, const char* address, int port); + +/** + * \brief read from socket to local buffer (non-blocking) + * + * The function shall return immediately if no data is available. In this case + * the function returns 0. If an error happens the function shall return -1. + * + * Implementation of this function is MANDATORY + * + * NOTE: The behaviour of this function changed with version 0.8! + * + * \param self the client, connection or server socket instance + * \param buf the buffer where the read bytes are copied to + * \param size the maximum number of bytes to read (size of the provided buffer) + * + * \return the number of bytes read or -1 if an error occurred + */ +int +Socket_read(Socket self, uint8_t* buf, int size); + +/** + * \brief send a message through the socket + * + * Implementation of this function is MANDATORY + * + * \param self client, connection or server socket instance + * + * \return number of bytes transmitted of -1 in case of an error + */ +int +Socket_write(Socket self, uint8_t* buf, int size); + +/** + * \brief Get the address of the peer application (IP address and port number) + * + * The peer address has to be returned as + * + * Implementation of this function is MANDATORY + * + * \param self the client, connection or server socket instance + * + * \return the IP address and port number as strings separated by the ':' character. + */ +char* +Socket_getPeerAddress(Socket self); + +/** + * \brief destroy a socket (close the socket if a connection is established) + * + * This function shall close the connection (if one is established) and free all + * resources allocated by the socket. + * + * Implementation of this function is MANDATORY + * + * \param self the client, connection or server socket instance + */ +void +Socket_destroy(Socket self); + +/*! @} */ + +/*! @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* SOCKET_HAL_H_ */ diff --git a/src/hal/inc/hal_thread.h b/src/hal/inc/hal_thread.h new file mode 100644 index 0000000..7d719f9 --- /dev/null +++ b/src/hal/inc/hal_thread.h @@ -0,0 +1,115 @@ +/* + * thread_hal.h + * + * Multi-threading abstraction layer + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef THREAD_HAL_H_ +#define THREAD_HAL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \addtogroup hal + * + * @{ + */ + +/** + * @defgroup HAL_THREAD Threading and synchronization API + * + * @{ + */ + +/** Opaque reference of a Thread instance */ +typedef struct sThread* Thread; + +/** Qpaque reference of a Semaphore instance */ +typedef void* Semaphore; + +/** Reference to a function that is called when starting the thread */ +typedef void* (*ThreadExecutionFunction) (void*); + +/** + * \brief Create a new Thread instance + * + * \param function the entry point of the thread + * \param parameter a parameter that is passed to the threads start function + * \param autodestroy the thread is automatically destroyed if the ThreadExecutionFunction has finished. + * + * \return the newly created Thread instance + */ +Thread +Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy); + +/** + * \brief Start a Thread. + * + * This function invokes the start function of the thread. The thread terminates when + * the start function returns. + * + * \param thread the Thread instance to start + */ +void +Thread_start(Thread thread); + +/** + * \brief Destroy a Thread and free all related resources. + * + * \param thread the Thread instance to destroy + */ +void +Thread_destroy(Thread thread); + +/** + * \brief Suspend execution of the Thread for the specified number of milliseconds + */ +void +Thread_sleep(int millies); + +Semaphore +Semaphore_create(int initialValue); + +/* Wait until semaphore value is greater than zero. Then decrease the semaphore value. */ +void +Semaphore_wait(Semaphore self); + +void +Semaphore_post(Semaphore self); + +void +Semaphore_destroy(Semaphore self); + +/*! @} */ + +/*! @} */ + +#ifdef __cplusplus +} +#endif + + +#endif /* THREAD_HAL_H_ */ diff --git a/src/hal/inc/hal_time.h b/src/hal/inc/hal_time.h new file mode 100644 index 0000000..50fcf50 --- /dev/null +++ b/src/hal/inc/hal_time.h @@ -0,0 +1,62 @@ +/* + * time.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef HAL_C_ +#define HAL_C_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \addtogroup hal + * + * @{ + */ + +/** + * @defgroup HAL_TIME Time related functions + * + * @{ + */ + +/** + * Get the system time in milliseconds. + * + * The time value returned as 64-bit unsigned integer should represent the milliseconds + * since the UNIX epoch (1970/01/01 00:00 UTC). + * + * \return the system time with millisecond resolution. + */ +uint64_t Hal_getTimeInMs(void); + +/*! @} */ + +/*! @} */ + +#ifdef __cplusplus +} +#endif + + +#endif /* HAL_C_ */ diff --git a/src/hal/inc/platform_endian.h b/src/hal/inc/platform_endian.h new file mode 100644 index 0000000..9bc7a5a --- /dev/null +++ b/src/hal/inc/platform_endian.h @@ -0,0 +1,53 @@ +/* + * endian.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ENDIAN_H_ +#define ENDIAN_H_ + +#include "stack_config.h" + +#ifndef PLATFORM_IS_BIGENDIAN +#ifdef __GNUC__ +#ifdef __BYTE_ORDER__ +#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define PLATFORM_IS_BIGENDIAN 1 +#endif + +#else + +/* older versions of GCC have __BYTE_ORDER__ not defined! */ +#ifdef __PPC__ +#define PLATFORM_IS_BIGENDIAN 1 +#endif + +#endif /* __BYTE_ORDER__ */ +#endif /* __GNUC__ */ +#endif + +#if (PLATFORM_IS_BIGENDIAN == 1) +# define ORDER_LITTLE_ENDIAN 0 +#else +# define ORDER_LITTLE_ENDIAN 1 +#endif + +#endif /* ENDIAN_H_ */ diff --git a/src/hal/socket/bsd/socket_bsd.c b/src/hal/socket/bsd/socket_bsd.c new file mode 100644 index 0000000..800ee42 --- /dev/null +++ b/src/hal/socket/bsd/socket_bsd.c @@ -0,0 +1,404 @@ +/* + * socket_bsd.c + * + * Copyright 2013, 2014 Michael Zillgith, contributions by Michael Clausen (School of engineering Valais). + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "hal_socket.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include // required for TCP keepalive + +#include "hal_thread.h" + +#include "libiec61850_platform_includes.h" + +#ifndef DEBUG_SOCKET +#define DEBUG_SOCKET 0 +#endif + +struct sSocket { + int fd; + uint32_t connectTimeout; +}; + +struct sServerSocket { + int fd; + int backLog; +}; + +struct sHandleSet { + fd_set handles; + int maxHandle; +}; + +HandleSet +Handleset_new(void) +{ + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = -1; + } + return result; +} + +void +Handleset_addSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != -1) { + FD_SET(sock->fd, &self->handles); + if (sock->fd > self->maxHandle) { + self->maxHandle = sock->fd; + } + } +} + +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs) +{ + int result; + + if (self != NULL && self->maxHandle >= 0) { + struct timeval timeout; + + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; + result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); + } else { + result = -1; + } + + return result; +} + +void +Handleset_destroy(HandleSet self) +{ + GLOBAL_FREEMEM(self); +} + +static void +activateKeepAlive(int sd) +{ +#if defined SO_KEEPALIVE + int optval; + socklen_t optlen = sizeof(optval); + + optval = CONFIG_TCP_KEEPALIVE_IDLE; + setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); + optval = 1; + setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, optlen); + +#if defined TCP_KEEPCNT + optval = CONFIG_TCP_KEEPALIVE_INTERVAL; + setsockopt(sd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen); + + optval = CONFIG_TCP_KEEPALIVE_CNT; + setsockopt(sd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen); +#endif /* TCP_KEEPCNT */ + +#endif /* SO_KEEPALIVE */ +} + +static bool +prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) +{ + + memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); + + if (address != NULL) { + struct hostent *server; + server = gethostbyname(address); + + if (server == NULL) return false; + + memcpy((char *) &sockaddr->sin_addr.s_addr, (char *) server->h_addr, server->h_length); + } + else + sockaddr->sin_addr.s_addr = htonl(INADDR_ANY); + + sockaddr->sin_family = AF_INET; + sockaddr->sin_port = htons(port); + + return true; +} + +static void +setSocketNonBlocking(Socket self) +{ + int flags = fcntl(self->fd, F_GETFL, 0); + fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); +} + +ServerSocket +TcpServerSocket_create(const char* address, int port) +{ + ServerSocket serverSocket = NULL; + + int fd; + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) { + struct sockaddr_in serverAddress; + + if (!prepareServerAddress(address, port, &serverAddress)) { + close(fd); + return NULL; + } + + int optionReuseAddr = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int)); + + if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) { + serverSocket = GLOBAL_MALLOC(sizeof(struct sServerSocket)); + serverSocket->fd = fd; + serverSocket->backLog = 0; + } + else { + close(fd); + return NULL ; + } + +#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 + activateKeepAlive(fd); +#endif + + setSocketNonBlocking((Socket) serverSocket); + } + + return serverSocket; +} + +void +ServerSocket_listen(ServerSocket self) +{ + listen(self->fd, self->backLog); +} + +Socket +ServerSocket_accept(ServerSocket self) +{ + int fd; + + Socket conSocket = NULL; + + fd = accept(self->fd, NULL, NULL ); + + if (fd >= 0) { + conSocket = TcpSocket_create(); + conSocket->fd = fd; + } + + return conSocket; +} + +void +ServerSocket_setBacklog(ServerSocket self, int backlog) +{ + self->backLog = backlog; +} + +static void +closeAndShutdownSocket(int socketFd) +{ + if (socketFd != -1) { + + if (DEBUG_SOCKET) + printf("socket_linux.c: call shutdown for %i!\n", socketFd); + + // shutdown is required to unblock read or accept in another thread! + shutdown(socketFd, SHUT_RDWR); + + close(socketFd); + } +} + +void +ServerSocket_destroy(ServerSocket self) +{ + int fd = self->fd; + + self->fd = -1; + + closeAndShutdownSocket(fd); + + Thread_sleep(10); + + GLOBAL_FREEMEM(self); +} + +Socket +TcpSocket_create() +{ + Socket self = GLOBAL_MALLOC(sizeof(struct sSocket)); + + self->fd = -1; + + return self; +} + +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + + +bool +Socket_connect(Socket self, const char* address, int port) +{ + struct sockaddr_in serverAddress; + + if (DEBUG_SOCKET) + printf("Socket_connect: %s:%i\n", address, port); + + if (!prepareServerAddress(address, port, &serverAddress)) + return false; + + self->fd = socket(AF_INET, SOCK_STREAM, 0); + +#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 + activateKeepAlive(self->fd); +#endif + + fd_set fdSet; + FD_ZERO(&fdSet); + FD_SET(self->fd, &fdSet); + + fcntl(self->fd, F_SETFL, O_NONBLOCK); + + if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { + if (errno != EINPROGRESS) + return false; + } + + struct timeval timeout; + timeout.tv_sec = self->connectTimeout / 1000; + timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + + if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) <= 0) + return false; + else + return true; +} + +char* +Socket_getPeerAddress(Socket self) +{ + struct sockaddr_storage addr; + socklen_t addrLen = sizeof(addr); + + getpeername(self->fd, (struct sockaddr*) &addr, &addrLen); + + char addrString[INET6_ADDRSTRLEN + 7]; + int port; + + bool isIPv6; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr; + port = ntohs(ipv4Addr->sin_port); + inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN); + isIPv6 = false; + } + else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr; + port = ntohs(ipv6Addr->sin6_port); + inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN); + isIPv6 = true; + } + else + return NULL ; + + char* clientConnection = GLOBAL_MALLOC(strlen(addrString) + 9); + + + if (isIPv6) + sprintf(clientConnection, "[%s]:%i", addrString, port); + else + sprintf(clientConnection, "%s:%i", addrString, port); + + return clientConnection; +} + +int +Socket_read(Socket self, uint8_t* buf, int size) +{ + assert(self != NULL); + + if (self->fd == -1) + return -1; + + int read_bytes = recv(self->fd, buf, size, MSG_DONTWAIT); + + if (read_bytes == 0) + return -1; + + if (read_bytes == -1) { + int error = errno; + + switch (error) { + + case EAGAIN: + return 0; + case EBADF: + return -1; + + default: + return -1; + } + } + + return read_bytes; +} + +int +Socket_write(Socket self, uint8_t* buf, int size) +{ + if (self->fd == -1) + return -1; + + // MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket + return send(self->fd, buf, size, 0); +} + +void +Socket_destroy(Socket self) +{ + int fd = self->fd; + + self->fd = -1; + + closeAndShutdownSocket(fd); + + Thread_sleep(10); + + GLOBAL_FREEMEM(self); +} diff --git a/src/hal/socket/linux/socket_linux.c b/src/hal/socket/linux/socket_linux.c new file mode 100644 index 0000000..fc01f75 --- /dev/null +++ b/src/hal/socket/linux/socket_linux.c @@ -0,0 +1,433 @@ +/* + * socket_linux.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "hal_socket.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include // required for TCP keepalive + +#include "hal_thread.h" + +#include "libiec61850_platform_includes.h" + +#ifndef DEBUG_SOCKET +#define DEBUG_SOCKET 0 +#endif + +struct sSocket { + int fd; + uint32_t connectTimeout; +}; + +struct sServerSocket { + int fd; + int backLog; +}; + +struct sHandleSet { + fd_set handles; + int maxHandle; +}; + +HandleSet +Handleset_new(void) +{ + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = -1; + } + return result; +} + +void +Handleset_addSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != -1) { + FD_SET(sock->fd, &self->handles); + if (sock->fd > self->maxHandle) { + self->maxHandle = sock->fd; + } + } +} + +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs) +{ + int result; + + if ((self != NULL) && (self->maxHandle >= 0)) { + struct timeval timeout; + + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; + result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); + } else { + result = -1; + } + + return result; +} + +void +Handleset_destroy(HandleSet self) +{ + GLOBAL_FREEMEM(self); +} + +static void +activateKeepAlive(int sd) +{ +#if defined SO_KEEPALIVE + int optval; + socklen_t optlen = sizeof(optval); + + optval = 1; + setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); + +#if defined TCP_KEEPCNT + optval = CONFIG_TCP_KEEPALIVE_IDLE; + setsockopt(sd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen); + + optval = CONFIG_TCP_KEEPALIVE_INTERVAL; + setsockopt(sd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen); + + optval = CONFIG_TCP_KEEPALIVE_CNT; + setsockopt(sd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen); +#endif /* TCP_KEEPCNT */ + +#endif /* SO_KEEPALIVE */ +} + +static bool +prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) +{ + bool retVal = true; + + memset((char *) sockaddr, 0, sizeof(struct sockaddr_in)); + + if (address != NULL) { + struct addrinfo addressHints; + struct addrinfo *lookupResult; + int result; + + memset(&addressHints, 0, sizeof(struct addrinfo)); + addressHints.ai_family = AF_INET; + result = getaddrinfo(address, NULL, &addressHints, &lookupResult); + + if (result != 0) { + retVal = false; + goto exit_function; + } + + memcpy(sockaddr, lookupResult->ai_addr, sizeof(struct sockaddr_in)); + freeaddrinfo(lookupResult); + } + else + sockaddr->sin_addr.s_addr = htonl(INADDR_ANY); + + sockaddr->sin_family = AF_INET; + sockaddr->sin_port = htons(port); + +exit_function: + return retVal; +} + +static void +setSocketNonBlocking(Socket self) +{ + int flags = fcntl(self->fd, F_GETFL, 0); + fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); +} + +static void +activateTcpNoDelay(Socket self) +{ + /* activate TCP_NODELAY option - packets will be sent immediately */ + int flag = 1; + setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); +} + +ServerSocket +TcpServerSocket_create(const char* address, int port) +{ + ServerSocket serverSocket = NULL; + + int fd; + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) { + struct sockaddr_in serverAddress; + + if (!prepareServerAddress(address, port, &serverAddress)) { + close(fd); + return NULL; + } + + int optionReuseAddr = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int)); + + if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) { + serverSocket = GLOBAL_MALLOC(sizeof(struct sServerSocket)); + serverSocket->fd = fd; + serverSocket->backLog = 0; + + setSocketNonBlocking((Socket) serverSocket); + } + else { + close(fd); + return NULL ; + } + +#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 + activateKeepAlive(fd); +#endif + } + + return serverSocket; +} + +void +ServerSocket_listen(ServerSocket self) +{ + listen(self->fd, self->backLog); +} + + +/* CHANGED TO MAKE NON-BLOCKING --> RETURNS NULL IF NO CONNECTION IS PENDING */ +Socket +ServerSocket_accept(ServerSocket self) +{ + int fd; + + Socket conSocket = NULL; + + fd = accept(self->fd, NULL, NULL ); + + if (fd >= 0) { + conSocket = TcpSocket_create(); + conSocket->fd = fd; + + activateTcpNoDelay(conSocket); + } + + return conSocket; +} + +void +ServerSocket_setBacklog(ServerSocket self, int backlog) +{ + self->backLog = backlog; +} + +static void +closeAndShutdownSocket(int socketFd) +{ + if (socketFd != -1) { + + if (DEBUG_SOCKET) + printf("socket_linux.c: call shutdown for %i!\n", socketFd); + + // shutdown is required to unblock read or accept in another thread! + shutdown(socketFd, SHUT_RDWR); + + close(socketFd); + } +} + +void +ServerSocket_destroy(ServerSocket self) +{ + int fd = self->fd; + + self->fd = -1; + + closeAndShutdownSocket(fd); + + Thread_sleep(10); + + GLOBAL_FREEMEM(self); +} + +Socket +TcpSocket_create() +{ + Socket self = GLOBAL_MALLOC(sizeof(struct sSocket)); + + self->fd = -1; + self->connectTimeout = 5000; + + return self; +} + + +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + + +bool +Socket_connect(Socket self, const char* address, int port) +{ + struct sockaddr_in serverAddress; + + if (DEBUG_SOCKET) + printf("Socket_connect: %s:%i\n", address, port); + + if (!prepareServerAddress(address, port, &serverAddress)) + return false; + + self->fd = socket(AF_INET, SOCK_STREAM, 0); + + fd_set fdSet; + FD_ZERO(&fdSet); + FD_SET(self->fd, &fdSet); + + activateTcpNoDelay(self); + +#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 + activateKeepAlive(self->fd); +#endif + + fcntl(self->fd, F_SETFL, O_NONBLOCK); + + if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { + if (errno != EINPROGRESS) + return false; + } + + struct timeval timeout; + timeout.tv_sec = self->connectTimeout / 1000; + timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + + if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) <= 0) + return false; + else + return true; + +} + +char* +Socket_getPeerAddress(Socket self) +{ + struct sockaddr_storage addr; + socklen_t addrLen = sizeof(addr); + + getpeername(self->fd, (struct sockaddr*) &addr, &addrLen); + + char addrString[INET6_ADDRSTRLEN + 7]; + int port; + + bool isIPv6; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr; + port = ntohs(ipv4Addr->sin_port); + inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN); + isIPv6 = false; + } + else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr; + port = ntohs(ipv6Addr->sin6_port); + inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN); + isIPv6 = true; + } + else + return NULL ; + + char* clientConnection = GLOBAL_MALLOC(strlen(addrString) + 9); + + + if (isIPv6) + sprintf(clientConnection, "[%s]:%i", addrString, port); + else + sprintf(clientConnection, "%s:%i", addrString, port); + + return clientConnection; +} + +int +Socket_read(Socket self, uint8_t* buf, int size) +{ + assert(self != NULL); + + if (self->fd == -1) + return -1; + + int read_bytes = recv(self->fd, buf, size, MSG_DONTWAIT); + + if (read_bytes == 0) + return -1; + + if (read_bytes == -1) { + int error = errno; + + switch (error) { + + case EAGAIN: + return 0; + case EBADF: + return -1; + + default: + return -1; + } + } + + return read_bytes; +} + +int +Socket_write(Socket self, uint8_t* buf, int size) +{ + if (self->fd == -1) + return -1; + + // MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket + return send(self->fd, buf, size, MSG_NOSIGNAL); +} + +void +Socket_destroy(Socket self) +{ + int fd = self->fd; + + self->fd = -1; + + closeAndShutdownSocket(fd); + + Thread_sleep(10); + + GLOBAL_FREEMEM(self); +} diff --git a/src/hal/socket/win32/socket_win32.c b/src/hal/socket/win32/socket_win32.c new file mode 100644 index 0000000..8c0b084 --- /dev/null +++ b/src/hal/socket/win32/socket_win32.c @@ -0,0 +1,404 @@ +/* + * socket_win32.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include +#include + +#pragma comment (lib, "Ws2_32.lib") + +#include "libiec61850_platform_includes.h" +#include "hal_socket.h" +#include "stack_config.h" + + +#ifndef __MINGW64_VERSION_MAJOR +struct tcp_keepalive { + u_long onoff; + u_long keepalivetime; + u_long keepaliveinterval; +}; +#endif + +#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) + +struct sSocket { + SOCKET fd; + uint32_t connectTimeout; +}; + +struct sServerSocket { + SOCKET fd; + int backLog; +}; + +struct sHandleSet { + fd_set handles; + SOCKET maxHandle; +}; + +HandleSet +Handleset_new(void) +{ + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = INVALID_SOCKET; + } + return result; +} + +void +Handleset_addSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != INVALID_SOCKET) { + FD_SET(sock->fd, &self->handles); + + if ((sock->fd > self->maxHandle) || (self->maxHandle == INVALID_SOCKET)) + self->maxHandle = sock->fd; + } +} + +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs) +{ + int result; + + if (self != NULL && self->maxHandle >= 0) { + struct timeval timeout; + + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; + result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); + } else { + result = -1; + } + + return result; +} + +void +Handleset_destroy(HandleSet self) +{ + GLOBAL_FREEMEM(self); +} + +static void +activateKeepAlive(SOCKET s) +{ + struct tcp_keepalive keepalive; + DWORD retVal=0; + + keepalive.onoff = 1; + keepalive.keepalivetime = CONFIG_TCP_KEEPALIVE_IDLE * 1000; + keepalive.keepaliveinterval = CONFIG_TCP_KEEPALIVE_INTERVAL * 1000; + + if (WSAIoctl(s, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), + NULL, 0, &retVal, NULL, NULL) == SOCKET_ERROR) + { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: WSAIotcl(SIO_KEEPALIVE_VALS) failed: %d\n", + WSAGetLastError()); + } +} + +static void +setSocketNonBlocking(Socket self) +{ + unsigned long mode = 1; + if (ioctlsocket(self->fd, FIONBIO, &mode) != 0) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: failed to set socket non-blocking!\n"); + } + + /* activate TCP_NODELAY */ + + int tcpNoDelay = 1; + + setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&tcpNoDelay, sizeof(int)); +} + +static bool +prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) +{ + + memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); + + if (address != NULL) { + struct hostent *server; + server = gethostbyname(address); + + if (server == NULL) return false; + + memcpy((char *) &sockaddr->sin_addr.s_addr, (char *) server->h_addr, server->h_length); + } + else + sockaddr->sin_addr.s_addr = htonl(INADDR_ANY); + + sockaddr->sin_family = AF_INET; + sockaddr->sin_port = htons(port); + + return true; +} + +ServerSocket +TcpServerSocket_create(const char* address, int port) +{ + ServerSocket serverSocket = NULL; + int ec; + WSADATA wsa; + SOCKET listen_socket = INVALID_SOCKET; + + if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: winsock error: code %i\n", ec); + return NULL; + } + + struct sockaddr_in server_addr; + + if (!prepareServerAddress(address, port, &server_addr)) + return NULL; + + listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + +#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 + activateKeepAlive(listen_socket); +#endif + + if (listen_socket == INVALID_SOCKET) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: socket failed with error: %i\n", WSAGetLastError()); + WSACleanup(); + return NULL; + } + + int optionReuseAddr = 1; + setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&optionReuseAddr, sizeof(int)); + + ec = bind(listen_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)); + + if (ec == SOCKET_ERROR) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: bind failed with error:%i\n", WSAGetLastError()); + closesocket(listen_socket); + WSACleanup(); + return NULL; + } + + serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket)); + + serverSocket->fd = listen_socket; + serverSocket->backLog = 10; + + setSocketNonBlocking((Socket) serverSocket); + + return serverSocket; +} + +void +ServerSocket_listen(ServerSocket self) +{ + listen(self->fd, self->backLog); +} + +Socket +ServerSocket_accept(ServerSocket self) +{ + int fd; + + Socket conSocket = NULL; + + fd = accept(self->fd, NULL, NULL); + + if (fd >= 0) { + conSocket = TcpSocket_create(); + conSocket->fd = fd; + + setSocketNonBlocking(conSocket); + } + + return conSocket; +} + +void +ServerSocket_setBacklog(ServerSocket self, int backlog) +{ + self->backLog = backlog; +} + +void +ServerSocket_destroy(ServerSocket self) +{ + closesocket(self->fd); + WSACleanup(); + free(self); +} + +Socket +TcpSocket_create() +{ + Socket self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket)); + + self->fd = INVALID_SOCKET; + + return self; +} + +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + +bool +Socket_connect(Socket self, const char* address, int port) +{ + struct sockaddr_in serverAddress; + WSADATA wsa; + int ec; + + if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: winsock error: code %i\n", ec); + return false; + } + + if (!prepareServerAddress(address, port, &serverAddress)) + return false; + + self->fd = socket(AF_INET, SOCK_STREAM, 0); + +#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 + activateKeepAlive(self->fd); +#endif + + setSocketNonBlocking(self); + + fd_set fdSet; + FD_ZERO(&fdSet); + FD_SET(self->fd, &fdSet); + + if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return false; + } + + struct timeval timeout; + timeout.tv_sec = self->connectTimeout / 1000; + timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + + if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) <= 0) + return false; + else + return true; +} + +char* +Socket_getPeerAddress(Socket self) +{ + struct sockaddr_storage addr; + int addrLen = sizeof(addr); + + getpeername(self->fd, (struct sockaddr*) &addr, &addrLen); + + char addrString[INET6_ADDRSTRLEN + 7]; + int addrStringLen = INET6_ADDRSTRLEN + 7; + int port; + + bool isIPv6; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr; + port = ntohs(ipv4Addr->sin_port); + ipv4Addr->sin_port = 0; + WSAAddressToString((LPSOCKADDR) ipv4Addr, sizeof(struct sockaddr_storage), NULL, + (LPSTR) addrString, (LPDWORD) &addrStringLen); + isIPv6 = false; + } + else if (addr.ss_family == AF_INET6){ + struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr; + port = ntohs(ipv6Addr->sin6_port); + ipv6Addr->sin6_port = 0; + WSAAddressToString((LPSOCKADDR) ipv6Addr, sizeof(struct sockaddr_storage), NULL, + (LPSTR) addrString, (LPDWORD) &addrStringLen); + isIPv6 = true; + } + else + return NULL; + + char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9); + + if (isIPv6) + sprintf(clientConnection, "[%s]:%i", addrString, port); + else + sprintf(clientConnection, "%s:%i", addrString, port); + + return clientConnection; +} + +int +Socket_read(Socket self, uint8_t* buf, int size) +{ + int bytes_read = recv(self->fd, (char*) buf, size, 0); + + if (bytes_read == 0) // peer has closed socket + return -1; + + if (bytes_read == SOCKET_ERROR) { + if (WSAGetLastError() == WSAEWOULDBLOCK) + return 0; + else + return -1; + } + + return bytes_read; +} + +int +Socket_write(Socket self, uint8_t* buf, int size) +{ + int bytes_sent = send(self->fd, (char*) buf, size, 0); + + if (bytes_sent == SOCKET_ERROR) { + int errorCode = WSAGetLastError(); + + if (errorCode == WSAEWOULDBLOCK) + bytes_sent = 0; + else + bytes_sent = -1; + } + + return bytes_sent; +} + +void +Socket_destroy(Socket self) +{ + if (self->fd != INVALID_SOCKET) { + closesocket(self->fd); + } + + free(self); +} diff --git a/src/hal/thread/linux/thread_linux.c b/src/hal/thread/linux/thread_linux.c new file mode 100644 index 0000000..0fd19e5 --- /dev/null +++ b/src/hal/thread/linux/thread_linux.c @@ -0,0 +1,125 @@ +/* + * thread_linux.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + + +#include +#include +#include +#include "hal_thread.h" + +#include "libiec61850_platform_includes.h" + +struct sThread { + ThreadExecutionFunction function; + void* parameter; + pthread_t pthread; + int state; + bool autodestroy; +}; + +Semaphore +Semaphore_create(int initialValue) +{ + Semaphore self = GLOBAL_MALLOC(sizeof(sem_t)); + + sem_init((sem_t*) self, 0, initialValue); + + return self; +} + +/* Wait until semaphore value is more than zero. Then decrease the semaphore value. */ +void +Semaphore_wait(Semaphore self) +{ + sem_wait((sem_t*) self); +} + +void +Semaphore_post(Semaphore self) +{ + sem_post((sem_t*) self); +} + +void +Semaphore_destroy(Semaphore self) +{ + sem_destroy((sem_t*) self); + GLOBAL_FREEMEM(self); +} + +Thread +Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy) +{ + Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread)); + + if (thread != NULL) { + thread->parameter = parameter; + thread->function = function; + thread->state = 0; + thread->autodestroy = autodestroy; + } + + return thread; +} + +static void* +destroyAutomaticThread(void* parameter) +{ + Thread thread = (Thread) parameter; + + thread->function(thread->parameter); + + GLOBAL_FREEMEM(thread); + + pthread_exit(NULL); +} + +void +Thread_start(Thread thread) +{ + if (thread->autodestroy == true) { + pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); + pthread_detach(thread->pthread); + } + else + pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); + + thread->state = 1; +} + +void +Thread_destroy(Thread thread) +{ + if (thread->state == 1) { + pthread_join(thread->pthread, NULL); + } + + GLOBAL_FREEMEM(thread); +} + +void +Thread_sleep(int millies) +{ + usleep(millies * 1000); +} + diff --git a/src/hal/thread/win32/thread_win32.c b/src/hal/thread/win32/thread_win32.c new file mode 100644 index 0000000..0eb39f6 --- /dev/null +++ b/src/hal/thread/win32/thread_win32.c @@ -0,0 +1,126 @@ +/* + * thread_win32.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include +#include "libiec61850_platform_includes.h" +#include "hal_thread.h" + +struct sThread { + ThreadExecutionFunction function; + void* parameter; + HANDLE handle; + int state; + bool autodestroy; +}; + +static DWORD WINAPI +destroyAutomaticThreadRunner(LPVOID parameter) +{ + Thread thread = (Thread) parameter; + + thread->function(thread->parameter); + + thread->state = 0; + + Thread_destroy(thread); + + return 0; +} + +static DWORD WINAPI +threadRunner(LPVOID parameter) +{ + Thread thread = (Thread) parameter; + + return (UINT) thread->function(thread->parameter); +} + +Thread +Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy) +{ + DWORD threadId; + Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread)); + + thread->parameter = parameter; + thread->function = function; + thread->state = 0; + thread->autodestroy = autodestroy; + + if (autodestroy == true) + thread->handle = CreateThread(0, 0, destroyAutomaticThreadRunner, thread, CREATE_SUSPENDED, &threadId); + else + thread->handle = CreateThread(0, 0, threadRunner, thread, CREATE_SUSPENDED, &threadId); + + return thread; +} + +void +Thread_start(Thread thread) +{ + thread->state = 1; + ResumeThread(thread->handle); +} + +void +Thread_destroy(Thread thread) +{ + if (thread->state == 1) + WaitForSingleObject(thread->handle, INFINITE); + + CloseHandle(thread->handle); + + GLOBAL_FREEMEM(thread); +} + +void +Thread_sleep(int millies) +{ + Sleep(millies); +} + +Semaphore +Semaphore_create(int initialValue) +{ + HANDLE self = CreateSemaphore(NULL, 1, 1, NULL); + + return self; +} + +/* Wait until semaphore value is greater than zero. Then decrease the semaphore value. */ +void +Semaphore_wait(Semaphore self) +{ + WaitForSingleObject((HANDLE) self, INFINITE); +} + +void +Semaphore_post(Semaphore self) +{ + ReleaseSemaphore((HANDLE) self, 1, NULL); +} + +void +Semaphore_destroy(Semaphore self) +{ + CloseHandle((HANDLE) self); +} diff --git a/src/hal/time/unix/time.c b/src/hal/time/unix/time.c new file mode 100644 index 0000000..d4a1a2c --- /dev/null +++ b/src/hal/time/unix/time.c @@ -0,0 +1,56 @@ +/* + * time.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#include + +#ifdef CONFIG_SYSTEM_HAS_CLOCK_GETTIME +uint64_t +Hal_getTimeInMs() +{ + struct timespec tp; + + clock_gettime(CLOCK_REALTIME, &tp); + + return ((uint64_t) tp.tv_sec) * 1000LL + (tp.tv_nsec / 1000000); +} +#else + +#include + +uint64_t +Hal_getTimeInMs() +{ + struct timeval now; + + gettimeofday(&now, NULL); + + return ((uint64_t) now.tv_sec * 1000LL) + (now.tv_usec / 1000); +} + +#endif + diff --git a/src/hal/time/win32/time.c b/src/hal/time/win32/time.c new file mode 100644 index 0000000..1af39b5 --- /dev/null +++ b/src/hal/time/win32/time.c @@ -0,0 +1,46 @@ +/* + * time.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#include + +#include + +uint64_t +Hal_getTimeInMs() +{ + FILETIME ft; + uint64_t now; + + static const uint64_t DIFF_TO_UNIXTIME = 11644473600000LL; + + GetSystemTimeAsFileTime(&ft); + + now = (LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32LL); + + return (now / 10000LL) - DIFF_TO_UNIXTIME; +} diff --git a/src/iec61850/client/client_control.c b/src/iec61850/client/client_control.c new file mode 100644 index 0000000..ce2823e --- /dev/null +++ b/src/iec61850/client/client_control.c @@ -0,0 +1,874 @@ +/* + * client_control.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#include "iec61850_client.h" +#include "mms_client_connection.h" +#include "ied_connection_private.h" + +#if _MSC_VER +#define snprintf _snprintf +#endif + +#ifndef DEBUG_IED_CLIENT +#define DEBUG_IED_CLIENT 0 +#endif + +struct sControlObjectClient +{ + ControlModel ctlModel; + char* objectReference; + IedConnection connection; + bool test; + bool interlockCheck; + bool synchroCheck; + bool hasTimeActivatedMode; + + MmsValue* analogValue; /* for APC-CDCs */ + + int edition; /* 1 = Ed. 1 - 2 = Ed. 2 - to distinguish time stamp format */ + bool hasCtlNum; /* Check if ctlNum attribute is present - ctlNum is(/can be?) absent in edition 1 APC CDC */ + + bool useConstantT; /* some servers require a constant T parameter for select and operate */ + uint64_t constantT; /* timestamp of select/operate to be used when constant T option is selected */ + + LastApplError lastApplError; + + CommandTerminationHandler commandTerminationHandler; + void* commandTerminaionHandlerParameter; + + /* control operation parameters */ + MmsValue* ctlVal; + uint64_t opertime; + uint8_t ctlNum; + char* orIdent; + int orCat; +}; + +static void +convertToMmsAndInsertFC(char* newItemId, const char* originalObjectName, const char* fc) +{ + int originalLength = strlen(originalObjectName); + + int srcIndex = 0; + int dstIndex = 0; + + while (originalObjectName[srcIndex] != '.') { + newItemId[dstIndex] = originalObjectName[srcIndex]; + srcIndex++; + dstIndex++; + } + + newItemId[dstIndex++] = '$'; + newItemId[dstIndex++] = fc[0]; + newItemId[dstIndex++] = fc[1]; + newItemId[dstIndex++] = '$'; + srcIndex++; + + while (srcIndex < originalLength) { + if (originalObjectName[srcIndex] == '.') + newItemId[dstIndex] = '$'; + else + newItemId[dstIndex] = originalObjectName[srcIndex]; + + dstIndex++; + srcIndex++; + } + + newItemId[dstIndex] = 0; +} + +static void +resetLastApplError(ControlObjectClient self) +{ + self->lastApplError.error = 0; + self->lastApplError.addCause = ADD_CAUSE_UNKNOWN; + self->lastApplError.ctlNum = 0; +} + +ControlObjectClient +ControlObjectClient_create(const char* objectReference, IedConnection connection) +{ + ControlObjectClient self = NULL; + + /* request control model from server */ + char reference[129]; + + if (strlen(objectReference) < 121) { + strcpy(reference, objectReference); + strcat(reference, ".ctlModel"); + } + else + goto exit_function; + + IedClientError error; + + uint32_t ctlModel = IedConnection_readUnsigned32Value(connection, &error, reference, IEC61850_FC_CF); + + if (error != IED_ERROR_OK) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ControlObjectClient_create: failed to get %s from server\n", reference); + + goto exit_function; + } + + MmsVariableSpecification* ctlVarSpec = + IedConnection_getVariableSpecification(connection, &error, objectReference, IEC61850_FC_CO); + + if (error != IED_ERROR_OK) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ControlObjectClient_create: failed to get data directory of control object\n"); + + goto exit_function; + } + + /* check what control elements are available */ + bool hasOper = false; + bool hasTimeActivatedControl = false; + bool hasCtlNum = false; + MmsVariableSpecification* ctlVal = NULL; + MmsVariableSpecification* t = NULL; + + if (MmsVariableSpecification_getType(ctlVarSpec) == MMS_STRUCTURE) { + MmsVariableSpecification* oper = MmsVariableSpecification_getNamedVariableRecursive(ctlVarSpec, "Oper"); + + if (oper) + { + hasOper = true; + + MmsVariableSpecification* operTm = MmsVariableSpecification_getNamedVariableRecursive(oper, "operTm"); + + if (operTm) + hasTimeActivatedControl = true; + + MmsVariableSpecification* ctlNum = MmsVariableSpecification_getNamedVariableRecursive(oper, "ctlNum"); + + if (ctlNum) + hasCtlNum = true; + + ctlVal = MmsVariableSpecification_getNamedVariableRecursive(oper, "ctlVal"); + t = MmsVariableSpecification_getNamedVariableRecursive(oper, "T"); + } + } + + if (hasOper == false) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: control is missing required element \"Oper\"\n"); + + goto exit_function; + } + + if ((ctlVal == NULL) || (t == NULL)) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: \"Oper\" is missing required element\n"); + + goto free_varspec; + } + + self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient)); + + if (self == NULL) + goto exit_function; + + self->objectReference = copyString(objectReference); + self->connection = connection; + self->ctlModel = (ControlModel) ctlModel; + self->hasTimeActivatedMode = hasTimeActivatedControl; + self->hasCtlNum = hasCtlNum; + self->ctlVal = MmsValue_newDefaultValue(ctlVal); + + /* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */ + if (MmsVariableSpecification_getType(t) == MMS_BINARY_TIME) + self->edition = 1; + else + self->edition = 2; + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: Detected edition %i control\n", self->edition); + + private_IedConnection_addControlClient(connection, self); + +free_varspec: + MmsVariableSpecification_destroy(ctlVarSpec); + +exit_function: + return self; +} + + +#if 0 +ControlObjectClient +ControlObjectClient_create(const char* objectReference, IedConnection connection) +{ + ControlObjectClient self = NULL; + + /* request control model from server */ + char domainId[65]; + char itemId[129]; + + char* domainName = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainId); + + if (domainName == NULL) + goto exit_function; + + convertToMmsAndInsertFC(itemId, objectReference + strlen(domainId) + 1, "CF"); + + int controlObjectItemIdLen = strlen(itemId); + + strncat(itemId, "$ctlModel", 64 - controlObjectItemIdLen); + + MmsError mmsError; + + MmsValue* ctlModel = MmsConnection_readVariable(IedConnection_getMmsConnection(connection), + &mmsError, domainId, itemId); + + if (ctlModel == NULL) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ControlObjectClient_create: failed to get ctlModel from server\n"); + + goto exit_function; + } + + int ctlModelVal = MmsValue_toUint32(ctlModel); + + MmsValue_delete(ctlModel); + + IedClientError error; + + LinkedList dataDirectory = + IedConnection_getDataDirectory(connection, &error, objectReference); + + if (dataDirectory == NULL) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ControlObjectClient_create: failed to get data directory of control object\n"); + + goto exit_function; + } + + /* check what control elements are available */ + bool hasOper = false; + + LinkedList element = LinkedList_getNext(dataDirectory); + + while (element != NULL) { + char* objectName = (char*) element->data; + + if (strcmp(objectName, "Oper") == 0) + hasOper = true; + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(dataDirectory); + + if (hasOper == false) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: control is missing required element \"Oper\"\n"); + + goto exit_function; + } + + /* check for time activated control and ctlNum */ + bool hasTimeActivatedControl = false; + bool hasCtlNum = false; + + strcpy(itemId, objectReference); + strcat(itemId, ".Oper"); + dataDirectory = IedConnection_getDataDirectory(connection, &error, itemId); + + if (dataDirectory == NULL) + goto exit_function; + + element = LinkedList_getNext(dataDirectory); + + while (element != NULL) { + char* objectName = (char*) element->data; + + if (strcmp(objectName, "operTm") == 0) { + hasTimeActivatedControl = true; + } + else if (strcmp(objectName, "ctlNum") == 0) { + hasCtlNum = true; + } + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(dataDirectory); + + /* get default parameters for Oper control variable */ + + MmsValue* oper = IedConnection_readObject(connection, &error, itemId, IEC61850_FC_CO); + + if (oper == NULL) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: reading \"Oper\" failed!\n"); + + goto exit_function; + } + + self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient)); + + if (self == NULL) + goto exit_function; + + self->objectReference = copyString(objectReference); + self->connection = connection; + self->ctlModel = (ControlModel) ctlModelVal; + self->hasTimeActivatedMode = hasTimeActivatedControl; + self->hasCtlNum = hasCtlNum; + self->ctlVal = MmsValue_getElement(oper, 0); + + if (MmsValue_getType(self->ctlVal) == MMS_STRUCTURE) + self->analogValue = MmsValue_createEmptyStructure(1); + else + self->analogValue = NULL; + + + /* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */ + MmsValue* t; + + if (hasTimeActivatedControl) + t = MmsValue_getElement(oper, 4); + else + t = MmsValue_getElement(oper, 3); + + if (MmsValue_getType(t) == MMS_BINARY_TIME) + self->edition = 1; + else + self->edition = 2; + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: Detected edition %i control\n", self->edition); + + MmsValue_setElement(oper, 0, NULL); + MmsValue_delete(oper); + + private_IedConnection_addControlClient(connection, self); + +exit_function: + return self; +} +#endif + +void +ControlObjectClient_destroy(ControlObjectClient self) +{ + if (self != NULL) + { + GLOBAL_FREEMEM(self->objectReference); + + private_IedConnection_removeControlClient(self->connection, self); + + if (self->ctlVal != NULL) + MmsValue_delete(self->ctlVal); + + if (self->analogValue != NULL) + MmsValue_delete(self->analogValue); + + if (self->orIdent != NULL) + GLOBAL_FREEMEM(self->orIdent); + + GLOBAL_FREEMEM(self); + } +} + +void +ControlObjectClient_setCommandTerminationHandler(ControlObjectClient self, CommandTerminationHandler handler, + void* handlerParameter) +{ + self->commandTerminaionHandlerParameter = handlerParameter; + self->commandTerminationHandler = handler; +} + +char* +ControlObjectClient_getObjectReference(ControlObjectClient self) +{ + return self->objectReference; +} + +ControlModel +ControlObjectClient_getControlModel(ControlObjectClient self) +{ + return self->ctlModel; +} + +void +ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat) +{ + if (self->orIdent != NULL) + GLOBAL_FREEMEM(self->orIdent); + + self->orIdent = copyString(orIdent); + self->orCat = orCat; +} + +static MmsValue* +createOriginValue(ControlObjectClient self) +{ + MmsValue* origin = MmsValue_createEmptyStructure(2); + + if (origin == NULL) + goto exit_function; + + MmsValue* orCat = MmsValue_newIntegerFromInt16(self->orCat); + + if (orCat == NULL) + goto cleanup_on_error; + + MmsValue_setElement(origin, 0, orCat); + + MmsValue* orIdent; + + if (self->orIdent != NULL) { + int octetStringLen = strlen(self->orIdent); + orIdent = MmsValue_newOctetString(0, octetStringLen); + + if (orIdent == NULL) + goto cleanup_on_error; + + MmsValue_setOctetString(orIdent, (uint8_t*) self->orIdent, octetStringLen); + } + else + orIdent = MmsValue_newOctetString(0, 0); + + if (orIdent == NULL) + goto cleanup_on_error; + + MmsValue_setElement(origin, 1, orIdent); + + goto exit_function; + +cleanup_on_error: + MmsValue_delete(origin); + origin = NULL; + +exit_function: + return origin; +} + +bool +ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t operTime) +{ + bool success = false; + + if (ctlVal == NULL) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: operate - (ctlVal == NULL)!\n"); + + goto exit_function; + } + + resetLastApplError(self); + + MmsValue* operParameters; + + int operElementCount = 5; + + if (self->hasTimeActivatedMode) + operElementCount++; + + if (self->hasCtlNum) + operElementCount++; + + operParameters = MmsValue_createEmptyStructure(operElementCount); + + /* support simplified usage of APC controls - user doesn't need to create the structure */ + if (self->analogValue != NULL) { + if (MmsValue_getType(ctlVal) != MMS_STRUCTURE) { + MmsValue_setElement(self->analogValue, 0, ctlVal); + ctlVal = self->analogValue; + } + } + + MmsValue_setElement(operParameters, 0, ctlVal); + + int index = 1; + + if (self->hasTimeActivatedMode) { + MmsValue* operTm = MmsValue_newUtcTimeByMsTime(operTime); + MmsValue_setElement(operParameters, index++, operTm); + } + + MmsValue* origin = createOriginValue(self); + MmsValue_setElement(operParameters, index++, origin); + + if (!((self->ctlModel == CONTROL_MODEL_SBO_NORMAL) || + (self->ctlModel == CONTROL_MODEL_SBO_ENHANCED))) + { + self->ctlNum++; + } + + if (self->hasCtlNum) { + MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); + MmsValue_setElement(operParameters, index++, ctlNum); + } + + uint64_t timestamp; + + if ((self->ctlModel == CONTROL_MODEL_SBO_ENHANCED) && (self->useConstantT)) + timestamp = self->constantT; + else + timestamp = Hal_getTimeInMs(); + + if (self->useConstantT) + self->constantT = timestamp; + + MmsValue* ctlTime; + + if (self->edition == 2) + ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); + else { + ctlTime = MmsValue_newBinaryTime(false); + MmsValue_setBinaryTime(ctlTime, timestamp); + } + + MmsValue_setElement(operParameters, index++, ctlTime); + + MmsValue* ctlTest = MmsValue_newBoolean(self->test); + MmsValue_setElement(operParameters, index++, ctlTest); + + MmsValue* check = MmsValue_newBitString(2); + MmsValue_setBitStringBit(check, 1, self->interlockCheck); + MmsValue_setBitStringBit(check, 0, self->synchroCheck); + MmsValue_setElement(operParameters, index++, check); + + char domainId[65]; + char itemId[65]; + + MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); + + convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); + + int controlObjectItemIdLen = strlen(itemId); + + strncat(itemId, "$Oper", 64 - controlObjectItemIdLen); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId); + + MmsError mmsError; + + MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), + &mmsError, domainId, itemId, operParameters); + + MmsValue_setElement(operParameters, 0, NULL); + MmsValue_delete(operParameters); + + if (mmsError != MMS_ERROR_NONE) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: operate failed!\n"); + + goto exit_function; + } + + MmsValue_update(self->ctlVal, ctlVal); + + if (self->analogValue) + MmsValue_setElement(self->analogValue, 0, NULL); + + self->opertime = operTime; + + success = true; + +exit_function: + return success; +} + +bool +ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal) +{ + resetLastApplError(self); + + char domainId[65]; + char itemId[65]; + + MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); + + convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); + + strncat(itemId, "$SBOw", 64); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId); + + MmsError mmsError; + + int selValElementCount = 5; + + if (self->hasTimeActivatedMode) + selValElementCount++; + + if (self->hasCtlNum) + selValElementCount++; + + MmsValue* selValParameters = MmsValue_createEmptyStructure(selValElementCount); + + /* support simplified usage of APC controls - user doesn't need to create the structure */ + if (self->analogValue != NULL) { + if (MmsValue_getType(ctlVal) != MMS_STRUCTURE) { + MmsValue_setElement(self->analogValue, 0, ctlVal); + ctlVal = self->analogValue; + } + } + + MmsValue_setElement(selValParameters, 0, ctlVal); + + int index = 1; + + if (self->hasTimeActivatedMode) { + MmsValue* operTm = MmsValue_newUtcTimeByMsTime(0); + MmsValue_setElement(selValParameters, index++, operTm); + } + + MmsValue* origin = createOriginValue(self); + MmsValue_setElement(selValParameters, index++, origin); + + self->ctlNum++; + + if (self->hasCtlNum) { + MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); + MmsValue_setElement(selValParameters, index++, ctlNum); + } + + uint64_t timestamp = Hal_getTimeInMs(); + MmsValue* ctlTime; + + if (self->useConstantT) + self->constantT = timestamp; + + if (self->edition == 2) + ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); + else { + ctlTime = MmsValue_newBinaryTime(false); + MmsValue_setBinaryTime(ctlTime, timestamp); + } + + MmsValue_setElement(selValParameters, index++, ctlTime); + + MmsValue* ctlTest = MmsValue_newBoolean(self->test); + MmsValue_setElement(selValParameters, index++, ctlTest); + + MmsValue* check = MmsValue_newBitString(2); + MmsValue_setBitStringBit(check, 1, self->interlockCheck); + MmsValue_setBitStringBit(check, 0, self->synchroCheck); + MmsValue_setElement(selValParameters, index++, check); + + MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), + &mmsError, domainId, itemId, selValParameters); + + MmsValue_setElement(selValParameters, 0, NULL); + MmsValue_delete(selValParameters); + + if (mmsError != MMS_ERROR_NONE) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: select-with-value failed!\n"); + return false; + } + + MmsValue_update(self->ctlVal, ctlVal); + + if (self->analogValue) + MmsValue_setElement(self->analogValue, 0, NULL); + + return true; +} + +bool +ControlObjectClient_select(ControlObjectClient self) +{ + resetLastApplError(self); + + char domainId[65]; + char itemId[65]; + + MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); + + convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); + + strncat(itemId, "$SBO", 64); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: select: %s/%s\n", domainId, itemId); + + MmsError mmsError; + + MmsValue* value = MmsConnection_readVariable(IedConnection_getMmsConnection(self->connection), + &mmsError, domainId, itemId); + + bool selected = false; + + self->ctlNum++; + + if (value == NULL) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: select: read SBO failed!\n"); + goto exit_function; + } + + char sboReference[130]; + + snprintf(sboReference, 129, "%s/%s", domainId, itemId); + + if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { + if (strcmp(MmsValue_toString(value), "") == 0) { + if (DEBUG_IED_CLIENT) + printf("select-response-\n"); + } + else if (strcmp(MmsValue_toString(value), sboReference)) { + if (DEBUG_IED_CLIENT) + printf("select-response+: (%s)\n", MmsValue_toString(value)); + selected = true; + } + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: select-response: (%s)\n", MmsValue_toString(value)); + } + } + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: select: unexpected response from server!\n"); + } + + MmsValue_delete(value); + +exit_function: + return selected; +} + +bool +ControlObjectClient_cancel(ControlObjectClient self) +{ + resetLastApplError(self); + + MmsValue* cancelParameters; + + if (self->hasTimeActivatedMode) + cancelParameters = MmsValue_createEmptyStructure(6); + else + cancelParameters = MmsValue_createEmptyStructure(5); + + MmsValue_setElement(cancelParameters, 0, self->ctlVal); + + int index = 1; + + if (self->hasTimeActivatedMode) { + MmsValue* operTm = MmsValue_newUtcTimeByMsTime(self->opertime); + MmsValue_setElement(cancelParameters, index++, operTm); + } + + MmsValue* origin = createOriginValue(self); + + MmsValue_setElement(cancelParameters, index++, origin); + + MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); + MmsValue_setElement(cancelParameters, index++, ctlNum); + + uint64_t timestamp; + + if (self->useConstantT) + timestamp = self->constantT; + else + timestamp = Hal_getTimeInMs(); + + MmsValue* ctlTime; + + if (self->edition == 2) + ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); + else { + ctlTime = MmsValue_newBinaryTime(false); + MmsValue_setBinaryTime(ctlTime, timestamp); + } + MmsValue_setElement(cancelParameters, index++, ctlTime); + + MmsValue* ctlTest = MmsValue_newBoolean(self->test); + MmsValue_setElement(cancelParameters, index++, ctlTest); + + char domainId[65]; + char itemId[65]; + + MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); + + convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); + + strncat(itemId, "$Cancel", 64); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: cancel: %s/%s\n", domainId, itemId); + + MmsError mmsError; + + MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), + &mmsError, domainId, itemId, cancelParameters); + + MmsValue_setElement(cancelParameters, 0, NULL); + MmsValue_delete(cancelParameters); + + if (mmsError != MMS_ERROR_NONE) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: cancel failed!\n"); + return false; + } + + return true; +} + +void +ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT) +{ + self->useConstantT = useConstantT; +} + +void +ControlObjectClient_enableInterlockCheck(ControlObjectClient self) +{ + self->interlockCheck = true; +} + +void +ControlObjectClient_enableSynchroCheck(ControlObjectClient self) +{ + self->synchroCheck = true; +} + +void +ControlObjectClient_setLastApplError(ControlObjectClient self, LastApplError lastApplError) +{ + self->lastApplError = lastApplError; +} + +LastApplError +ControlObjectClient_getLastApplError(ControlObjectClient self) +{ + return self->lastApplError; +} + +void +private_ControlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self) +{ + if (self->commandTerminationHandler != NULL) + self->commandTerminationHandler(self->commandTerminaionHandlerParameter, self); +} diff --git a/src/iec61850/client/client_goose_control.c b/src/iec61850/client/client_goose_control.c new file mode 100644 index 0000000..65eec91 --- /dev/null +++ b/src/iec61850/client/client_goose_control.c @@ -0,0 +1,528 @@ +/* + * client_report_control.c + * + * Implementation of the ClientReportControlBlock class + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_client.h" + +#include "stack_config.h" + +#include "ied_connection_private.h" + +#include "libiec61850_platform_includes.h" + +struct sClientGooseControlBlock { + char* objectReference; + MmsValue* goEna; + MmsValue* goID; + MmsValue* datSet; + MmsValue* confRev; + MmsValue* ndsCom; + MmsValue* dstAddress; + MmsValue* minTime; + MmsValue* maxTime; + MmsValue* fixedOffs; +}; + +ClientGooseControlBlock +ClientGooseControlBlock_create(const char* objectReference) +{ + ClientGooseControlBlock self = (ClientGooseControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientGooseControlBlock)); + + self->objectReference = copyString(objectReference); + + return self; +} + +void +ClientGooseControlBlock_destroy(ClientGooseControlBlock self) +{ + GLOBAL_FREEMEM(self->objectReference); + + MmsValue_deleteIfNotNull(self->goEna); + MmsValue_deleteIfNotNull(self->goID); + MmsValue_deleteIfNotNull(self->datSet); + MmsValue_deleteIfNotNull(self->confRev); + MmsValue_deleteIfNotNull(self->ndsCom); + MmsValue_deleteIfNotNull(self->dstAddress); + MmsValue_deleteIfNotNull(self->minTime); + MmsValue_deleteIfNotNull(self->maxTime); + MmsValue_deleteIfNotNull(self->fixedOffs); + + GLOBAL_FREEMEM(self); +} + +bool +ClientGooseControlBlock_getGoEna(ClientGooseControlBlock self) +{ + if (self->goEna != NULL) + return MmsValue_getBoolean(self->goEna); + else + return false; +} + +void +ClientGooseControlBlock_setGoEna(ClientGooseControlBlock self, bool goEna) +{ + if (self->goEna == NULL) + self->goEna = MmsValue_newBoolean(goEna); + else + MmsValue_setBoolean(self->goEna, goEna); +} + +const char* +ClientGooseControlBlock_getGoID(ClientGooseControlBlock self) +{ + if (self->goID != NULL) + return MmsValue_toString(self->goID); + else + return NULL; +} + +void +ClientGooseControlBlock_setGoID(ClientGooseControlBlock self, const char* goID) +{ + if (self->goID == NULL) + self->goID = MmsValue_newVisibleString(goID); + else + MmsValue_setVisibleString(self->goID, goID); +} + +const char* +ClientGooseControlBlock_getDatSet(ClientGooseControlBlock self) +{ + if (self->datSet != NULL) + return MmsValue_toString(self->datSet); + else + return NULL; +} + +void +ClientGooseControlBlock_setDatSet(ClientGooseControlBlock self, const char* datSet) +{ + if (self->datSet == NULL) + self->datSet = MmsValue_newVisibleString(datSet); + else + MmsValue_setVisibleString(self->datSet, datSet); +} + +uint32_t +ClientGooseControlBlock_getConfRev(ClientGooseControlBlock self) +{ + if (self->confRev != NULL) + return MmsValue_toUint32(self->confRev); + else + return 0; +} + +bool +ClientGooseControlBlock_getNdsComm(ClientGooseControlBlock self) +{ + if (self->ndsCom != NULL) + return MmsValue_getBoolean(self->ndsCom); + else + return false; +} + +uint32_t +ClientGooseControlBlock_getMinTime(ClientGooseControlBlock self) +{ + if (self->minTime != NULL) + return MmsValue_toUint32(self->minTime); + else + return 0; +} + +uint32_t +ClientGooseControlBlock_getMaxTime(ClientGooseControlBlock self) +{ + if (self->maxTime != NULL) + return MmsValue_toUint32(self->maxTime); + else + return 0; +} + +bool +ClientGooseControlBlock_getFixedOffs(ClientGooseControlBlock self) +{ + if (self->fixedOffs != NULL) + return MmsValue_getBoolean(self->fixedOffs); + else + return false; +} + +static MmsValue* +newEmptyPhyCommAddress(void) { + MmsValue* self = MmsValue_createEmptyStructure(4); + + MmsValue_setElement(self, 0, MmsValue_newOctetString(6, 6)); + MmsValue_setElement(self, 1, MmsValue_newUnsigned(8)); + MmsValue_setElement(self, 2, MmsValue_newUnsigned(16)); + MmsValue_setElement(self, 3, MmsValue_newUnsigned(16)); + + return self; +} + +MmsValue* +ClientGooseControlBlock_getDstAddress_addr(ClientGooseControlBlock self) +{ + if (self->dstAddress != NULL) + return MmsValue_getElement(self->dstAddress, 0); + else + return NULL; +} + +void +ClientGooseControlBlock_setDstAddress_addr(ClientGooseControlBlock self, MmsValue* macAddr) +{ + if (self->dstAddress == NULL) + self->dstAddress = newEmptyPhyCommAddress(); + + MmsValue* addr = MmsValue_getElement(self->dstAddress, 0); + MmsValue_update(addr, macAddr); +} + +uint8_t +ClientGooseControlBlock_getDstAddress_priority(ClientGooseControlBlock self) +{ + if (self->dstAddress != NULL) + return (uint8_t) MmsValue_toUint32(MmsValue_getElement(self->dstAddress, 1)); + else + return 0; +} + +void +ClientGooseControlBlock_setDstAddress_priority(ClientGooseControlBlock self, uint8_t priorityValue) +{ + if (self->dstAddress == NULL) + self->dstAddress = newEmptyPhyCommAddress(); + + MmsValue* priority = MmsValue_getElement(self->dstAddress, 1); + MmsValue_setUint8(priority, priorityValue); +} + +uint16_t +ClientGooseControlBlock_getDstAddress_vid(ClientGooseControlBlock self) +{ + if (self->dstAddress != NULL) + return (uint16_t) MmsValue_toUint32(MmsValue_getElement(self->dstAddress, 2)); + else + return 0; +} + +void +ClientGooseControlBlock_setDstAddress_vid(ClientGooseControlBlock self, uint16_t vidValue) +{ + if (self->dstAddress == NULL) + self->dstAddress = newEmptyPhyCommAddress(); + + MmsValue* vid = MmsValue_getElement(self->dstAddress, 2); + MmsValue_setUint16(vid, vidValue); +} + +uint16_t +ClientGooseControlBlock_getDstAddress_appid(ClientGooseControlBlock self) +{ + if (self->dstAddress != NULL) + return (uint16_t) MmsValue_toUint32(MmsValue_getElement(self->dstAddress, 3)); + else + return 0; +} + +void +ClientGooseControlBlock_setDstAddress_appid(ClientGooseControlBlock self, uint16_t appidValue) +{ + if (self->dstAddress == NULL) + self->dstAddress = newEmptyPhyCommAddress(); + + MmsValue* appid = MmsValue_getElement(self->dstAddress, 3); + MmsValue_setUint16(appid, appidValue); +} + +static void +updateOrClone(MmsValue** valuePtr, MmsValue* values, int index) +{ + if (*valuePtr != NULL) + MmsValue_update(*valuePtr, MmsValue_getElement(values, index)); + else + *valuePtr = MmsValue_clone(MmsValue_getElement(values, index)); +} + +static bool +private_ClientGooseControlBlock_updateValues(ClientGooseControlBlock self, MmsValue* values) +{ + int elementCount = MmsValue_getArraySize(values); + + if (elementCount > 5) { + updateOrClone(&(self->goEna), values, 0); + updateOrClone(&(self->goID), values, 1); + updateOrClone(&(self->datSet), values, 2); + updateOrClone(&(self->confRev), values, 3); + updateOrClone(&(self->ndsCom), values, 4); + updateOrClone(&(self->dstAddress), values, 5); + } + else + return false; + + if (elementCount > 6) + updateOrClone(&(self->minTime), values, 6); + + if (elementCount > 7) + updateOrClone(&(self->maxTime), values, 7); + + if (elementCount > 8) + updateOrClone(&(self->fixedOffs), values, 8); + + return true; +} + +ClientGooseControlBlock +IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const char* goCBReference, ClientGooseControlBlock updateGoCB) +{ + MmsError mmsError = MMS_ERROR_NONE; + *error = IED_ERROR_OK; + + ClientGooseControlBlock returnGoCB = updateGoCB; + + char domainId[65]; + char itemId[129]; + + MmsMapping_getMmsDomainFromObjectReference(goCBReference, domainId); + + const char* itemIdStart = goCBReference + strlen(domainId) + 1; + + const char* separator = strchr(itemIdStart, '.'); + + if (separator == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + int separatorOffset = separator - itemIdStart; + + memcpy(itemId, itemIdStart, separatorOffset); + + itemId[separatorOffset] = '$'; + itemId[separatorOffset + 1] = 'G'; + itemId[separatorOffset + 2] = 'O'; + itemId[separatorOffset + 3] = '$'; + + strcpy(itemId + separatorOffset + 4, separator + 1); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: getGoCBValues for %s\n", goCBReference); + + MmsValue* goCB = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId); + + if (mmsError != MMS_ERROR_NONE) { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + + return NULL; + } + + if (goCB == NULL) { + *error = IED_ERROR_OBJECT_DOES_NOT_EXIST; + return NULL; + } + + if (MmsValue_getType(goCB) != MMS_STRUCTURE) { + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n"); + + MmsValue_delete(goCB); + + *error = IED_ERROR_UNKNOWN; + return NULL; + } + + if (returnGoCB == NULL) + returnGoCB = ClientGooseControlBlock_create(goCBReference); + + if (private_ClientGooseControlBlock_updateValues(returnGoCB, goCB)) + *error = IED_ERROR_OK; + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + + MmsValue_delete(goCB); + + return returnGoCB; +} + +void +IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGooseControlBlock goCB, + uint32_t parametersMask, bool singleRequest) +{ + *error = IED_ERROR_OK; + + MmsError mmsError = MMS_ERROR_NONE; + + char domainId[65]; + char itemId[129]; + + MmsMapping_getMmsDomainFromObjectReference(goCB->objectReference, domainId); + + char* itemIdStart = goCB->objectReference + strlen(domainId) + 1; + + char* separator = strchr(itemIdStart, '.'); + + if (separator == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return; + } + + int separatorOffset = separator - itemIdStart; + + memcpy(itemId, itemIdStart, separatorOffset); + + itemId[separatorOffset] = '$'; + itemId[separatorOffset + 1] = 'G'; + itemId[separatorOffset + 2] = 'O'; + itemId[separatorOffset + 3] = '$'; + + strcpy(itemId + separatorOffset + 4, separator + 1); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: setGoCBValues for %s\n", goCB->objectReference); + + int itemIdLen = strlen(itemId); + + /* create the list of requested itemIds references */ + LinkedList itemIds = LinkedList_create(); + LinkedList values = LinkedList_create(); + + /* add rGoEna as last element */ + if (parametersMask & GOCB_ELEMENT_GO_ID) { + strcpy(itemId + itemIdLen, "$GoID"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->goID); + } + + if (parametersMask & GOCB_ELEMENT_DATSET) { + strcpy(itemId + itemIdLen, "$DatSet"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->datSet); + } + + if (parametersMask & GOCB_ELEMENT_CONF_REV) { + strcpy(itemId + itemIdLen, "$ConfRev"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->confRev); + } + + if (parametersMask & GOCB_ELEMENT_NDS_COMM) { + strcpy(itemId + itemIdLen, "$NdsCom"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->ndsCom); + } + + if (parametersMask & GOCB_ELEMENT_DST_ADDRESS) { + strcpy(itemId + itemIdLen, "$DstAddress"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->dstAddress); + } + + if (parametersMask & GOCB_ELEMENT_MIN_TIME) { + strcpy(itemId + itemIdLen, "$MinTime"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->minTime); + } + + if (parametersMask & GOCB_ELEMENT_MAX_TIME) { + strcpy(itemId + itemIdLen, "$MaxTime"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->maxTime); + } + + if (parametersMask & GOCB_ELEMENT_FIXED_OFFS) { + strcpy(itemId + itemIdLen, "$FixedOffs"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->fixedOffs); + } + + + if (parametersMask & GOCB_ELEMENT_GO_ENA) { + strcpy(itemId + itemIdLen, "$GoEna"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, goCB->goEna); + } + + if (singleRequest) { + LinkedList accessResults = NULL; + + MmsConnection_writeMultipleVariables(self->connection, &mmsError, domainId, itemIds, values, &accessResults); + + if (accessResults != NULL) { + LinkedList element = LinkedList_getNext(accessResults); + + while (element != NULL) { + MmsValue* accessResult = (MmsValue*) element->data; + + if (MmsValue_getDataAccessError(accessResult) != DATA_ACCESS_ERROR_SUCCESS) { + mmsError = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; + break; + } + + element = LinkedList_getNext(element); + } + + LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete); + } + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + goto exit_function; + } + else { + LinkedList itemIdElement = LinkedList_getNext(itemIds); + LinkedList valueElement = LinkedList_getNext(values); + + while (itemIdElement != NULL) { + char* rcbItemId = (char*) itemIdElement->data; + MmsValue* value = (MmsValue*) valueElement->data; + + MmsConnection_writeVariable(self->connection, &mmsError, domainId, rcbItemId, value); + + if (mmsError != MMS_ERROR_NONE) + break; + + itemIdElement = LinkedList_getNext(itemIdElement); + valueElement = LinkedList_getNext(valueElement); + } + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + goto exit_function; + } + +exit_function: + LinkedList_destroy(itemIds); + LinkedList_destroyStatic(values); +} + diff --git a/src/iec61850/client/client_report.c b/src/iec61850/client/client_report.c new file mode 100644 index 0000000..f930c4c --- /dev/null +++ b/src/iec61850/client/client_report.c @@ -0,0 +1,596 @@ +/* + * client_report.c + * + * Client implementation for IEC 61850 reporting. + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_client.h" + +#include "stack_config.h" + +#include "ied_connection_private.h" + +#include "libiec61850_platform_includes.h" + +struct sClientReport +{ + ReportCallbackFunction callback; + void* callbackParameter; + char* rcbReference; + char* rptId; + + char* dataSetName; + int dataSetNameSize; /* size of the dataSetName buffer */ + + MmsValue* entryId; + MmsValue* dataReferences; + MmsValue* dataSetValues; + ReasonForInclusion* reasonForInclusion; + + /* Presence flags for optional elements */ + bool hasDataSetName; + bool hasReasonForInclusion; + bool hasSequenceNumber; + bool hasDataReference; + bool hasConfRev; + bool hasTimestamp; + bool hasBufOverflow; + + uint64_t timestamp; + uint16_t seqNum; + uint32_t confRev; + bool bufOverflow; +}; + +char* +ReasonForInclusion_getValueAsString(ReasonForInclusion reasonCode) +{ + switch (reasonCode) { + case REASON_NOT_INCLUDED: + return "not-included"; + case REASON_DATA_CHANGE: + return "data-change"; + case REASON_DATA_UPDATE: + return "data-update"; + case REASON_QUALITY_CHANGE: + return "quality-change"; + case REASON_GI: + return "GI"; + case REASON_INTEGRITY: + return "integrity"; + default: + return "unknown"; + } +} + +ClientReport +ClientReport_create() +{ + ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport)); + + return self; +} + +void +ClientReport_destroy(ClientReport self) +{ + if (self->entryId) + MmsValue_delete(self->entryId); + + GLOBAL_FREEMEM(self->rcbReference); + + if (self->rptId != NULL) + GLOBAL_FREEMEM(self->rptId); + + if (self->dataSetValues != NULL) + MmsValue_delete(self->dataSetValues); + + if (self->dataReferences != NULL) + MmsValue_delete(self->dataReferences); + + if (self->reasonForInclusion != NULL) + GLOBAL_FREEMEM(self->reasonForInclusion); + + if (self->dataSetName != NULL) + GLOBAL_FREEMEM((void*) self->dataSetName); + + GLOBAL_FREEMEM(self); +} + +char* +ClientReport_getRcbReference(ClientReport self) +{ + return self->rcbReference; +} + +char* +ClientReport_getRptId(ClientReport self) +{ + return self->rptId; +} + +ReasonForInclusion +ClientReport_getReasonForInclusion(ClientReport self, int elementIndex) +{ + if (self->reasonForInclusion != NULL) + return self->reasonForInclusion[elementIndex]; + else + return REASON_NOT_INCLUDED; +} + +MmsValue* +ClientReport_getEntryId(ClientReport self) +{ + return self->entryId; +} + +bool +ClientReport_hasTimestamp(ClientReport self) +{ + return self->hasTimestamp; +} + +uint64_t +ClientReport_getTimestamp(ClientReport self) +{ + return self->timestamp; +} + + +bool +ClientReport_hasSeqNum(ClientReport self) +{ + return self->hasSequenceNumber; +} + +uint16_t +ClientReport_getSeqNum(ClientReport self) +{ + return self->seqNum; +} + +bool +ClientReport_hasDataSetName(ClientReport self) +{ + return self->hasDataSetName; +} + +bool +ClientReport_hasReasonForInclusion(ClientReport self) +{ + return self->hasReasonForInclusion; +} + +bool +ClientReport_hasConfRev(ClientReport self) +{ + return self->hasConfRev; +} + +uint32_t +ClientReport_getConfRev(ClientReport self) +{ + return self->confRev; +} + +bool +ClientReport_hasBufOvfl(ClientReport self) +{ + return self->hasBufOverflow; +} + +bool +ClientReport_getBufOvfl(ClientReport self) +{ + return self->bufOverflow; +} + +bool +ClientReport_hasDataReference(ClientReport self) +{ + return self->hasDataReference; +} + +const char* +ClientReport_getDataReference(ClientReport self, int elementIndex) +{ + char* dataReference = NULL; + + if (self->dataReferences != NULL) { + MmsValue* dataRefValue = MmsValue_getElement(self->dataReferences, elementIndex); + + if (dataRefValue != NULL) { + if (MmsValue_getType(dataRefValue) == MMS_VISIBLE_STRING) { + return MmsValue_toString(dataRefValue); + } + } + } + + return dataReference; +} + +const char* +ClientReport_getDataSetName(ClientReport self) +{ + return self->dataSetName; +} + +MmsValue* +ClientReport_getDataSetValues(ClientReport self) +{ + return self->dataSetValues; +} + +static ClientReport +lookupReportHandler(IedConnection self, const char* rcbReference) +{ + LinkedList element = LinkedList_getNext(self->enabledReports); + + while (element != NULL) { + ClientReport report = (ClientReport) element->data; + + if (strcmp(report->rcbReference, rcbReference) == 0) + return report; + + element = LinkedList_getNext(element); + } + + return NULL; +} + +void +IedConnection_installReportHandler(IedConnection self, const char* rcbReference, const char* rptId, ReportCallbackFunction handler, + void* handlerParameter) +{ + ClientReport report = lookupReportHandler(self, rcbReference); + + if (report != NULL) { + IedConnection_uninstallReportHandler(self, rcbReference); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: Removed existing report callback handler for %s\n", rcbReference); + } + + report = ClientReport_create(); + report->callback = handler; + report->callbackParameter = handlerParameter; + report->rcbReference = copyString(rcbReference); + + if (rptId != NULL) + report->rptId = copyString(rptId); + else + report->rptId = NULL; + + Semaphore_wait(self->reportHandlerMutex); + LinkedList_add(self->enabledReports, report); + Semaphore_post(self->reportHandlerMutex); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: Installed new report callback handler for %s\n", rcbReference); +} + +void +IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReference) +{ + Semaphore_wait(self->reportHandlerMutex); + + ClientReport report = lookupReportHandler(self, rcbReference); + + if (report != NULL) { + LinkedList_remove(self->enabledReports, report); + ClientReport_destroy(report); + } + + Semaphore_post(self->reportHandlerMutex); +} + +void +IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const char* rcbReference) +{ + char domainId[65]; + char itemId[129]; + + MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId); + + strcpy(itemId, rcbReference + strlen(domainId) + 1); + + StringUtils_replace(itemId, '.', '$'); + + int itemIdLen = strlen(itemId); + + strcpy(itemId + itemIdLen, "$GI"); + + MmsConnection mmsCon = IedConnection_getMmsConnection(self); + + MmsError mmsError; + + MmsValue* gi = MmsValue_newBoolean(true); + + MmsConnection_writeVariable(mmsCon, &mmsError, domainId, itemId, gi); + + MmsValue_delete(gi); + + if (mmsError != MMS_ERROR_NONE) { + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: failed to trigger GI for %s!\n", rcbReference); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + } + else { + *error = IED_ERROR_OK; + } +} + +void +private_IedConnection_handleReport(IedConnection self, MmsValue* value) +{ + MmsValue* rptIdValue = MmsValue_getElement(value, 0); + + LinkedList element = LinkedList_getNext(self->enabledReports); + ClientReport matchingReport = NULL; + + while (element != NULL) { + ClientReport report = (ClientReport) element->data; + + char* rptId = report->rptId; + + if (rptId == NULL) + rptId = report->rcbReference; + + if (strcmp(MmsValue_toString(rptIdValue), rptId) == 0) { + matchingReport = report; + break; + } + + element = LinkedList_getNext(element); + } + + if (matchingReport == NULL) + goto exit_function; + + matchingReport->hasSequenceNumber = false; + matchingReport->hasTimestamp = false; + matchingReport->hasReasonForInclusion = false; + matchingReport->hasDataReference = false; + matchingReport->hasConfRev = false; + matchingReport->hasDataSetName = false; + matchingReport->hasBufOverflow = false; + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: received report with ID %s\n", MmsValue_toString(rptIdValue)); + + MmsValue* optFlds = MmsValue_getElement(value, 1); + + int inclusionIndex = 2; + + /* has sequence-number */ + if (MmsValue_getBitStringBit(optFlds, 1) == true) { + + MmsValue* seqNum = MmsValue_getElement(value, inclusionIndex); + + if (MmsValue_getType(seqNum) == MMS_UNSIGNED) { + matchingReport->seqNum = (uint16_t) MmsValue_toUint32(seqNum); + matchingReport->hasSequenceNumber = true; + } + + inclusionIndex++; + } + + /* has report-timestamp */ + if (MmsValue_getBitStringBit(optFlds, 2) == true) { + MmsValue* timeStampValue = MmsValue_getElement(value, inclusionIndex); + + if (MmsValue_getType(timeStampValue) == MMS_BINARY_TIME) { + matchingReport->hasTimestamp = true; + matchingReport->timestamp = MmsValue_getBinaryTimeAsUtcMs(timeStampValue); + } + + inclusionIndex++; + } + + /* check if data set name is present */ + if (MmsValue_getBitStringBit(optFlds, 4) == true) { + matchingReport->hasDataSetName = true; + + MmsValue* dataSetName = MmsValue_getElement(value, inclusionIndex); + + const char* dataSetNameStr = MmsValue_toString(dataSetName); + + if (matchingReport->dataSetName == NULL) { + matchingReport->dataSetName = (char*) GLOBAL_MALLOC(MmsValue_getStringSize(dataSetName) + 1); + matchingReport->dataSetNameSize = MmsValue_getStringSize(dataSetName) + 1; + } + else { + if (matchingReport->dataSetNameSize < MmsValue_getStringSize(dataSetName) + 1) { + GLOBAL_FREEMEM((void*) matchingReport->dataSetName); + + matchingReport->dataSetName = (char*) GLOBAL_MALLOC(MmsValue_getStringSize(dataSetName) + 1); + matchingReport->dataSetNameSize = MmsValue_getStringSize(dataSetName) + 1; + } + } + + strcpy(matchingReport->dataSetName, dataSetNameStr); + + inclusionIndex++; + } + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: Found enabled report!\n"); + + /* check bufOvfl */ + if (MmsValue_getBitStringBit(optFlds, 6) == true) { + MmsValue* bufOverflow = MmsValue_getElement(value, inclusionIndex); + + matchingReport->hasBufOverflow = true; + matchingReport->bufOverflow = MmsValue_getBoolean(bufOverflow); + + inclusionIndex++; + } + + /* check for entryId */ + if (MmsValue_getBitStringBit(optFlds, 7) == true) { + MmsValue* entryId = MmsValue_getElement(value, inclusionIndex); + + if (matchingReport->entryId != NULL) { + + if (!MmsValue_update(matchingReport->entryId, entryId)) { + MmsValue_delete(matchingReport->entryId); + matchingReport->entryId = MmsValue_clone(entryId); + } + } + else { + matchingReport->entryId = MmsValue_clone(entryId); + } + + inclusionIndex++; + } + + /* check for confRev */ + if (MmsValue_getBitStringBit(optFlds, 8) == true) { + MmsValue* confRev = MmsValue_getElement(value, inclusionIndex); + + if (MmsValue_getType(confRev) == MMS_UNSIGNED) { + matchingReport->confRev = MmsValue_toUint32(confRev); + matchingReport->hasConfRev = true; + } + + inclusionIndex++; + } + + + /* skip segmentation fields */ + if (MmsValue_getBitStringBit(optFlds, 9) == true) + inclusionIndex += 2; + + MmsValue* inclusion = MmsValue_getElement(value, inclusionIndex); + + int dataSetSize = MmsValue_getBitStringSize(inclusion); + + int includedElements = MmsValue_getNumberOfSetBits(inclusion); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: Report includes %i data set elements of %i\n", includedElements, + dataSetSize); + + int valueIndex = inclusionIndex + 1; + + /* parse data-references if required */ + if (MmsValue_getBitStringBit(optFlds, 5) == true) { + + if (matchingReport->dataReferences == NULL) + matchingReport->dataReferences = MmsValue_createEmptyArray(dataSetSize); + + matchingReport->hasDataReference = true; + + int elementIndex; + + for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++) { + if (MmsValue_getBitStringBit(inclusion, elementIndex) == true) { + MmsValue* dataSetElement = MmsValue_getElement(matchingReport->dataReferences, elementIndex); + + if (dataSetElement == NULL) { + dataSetElement = MmsValue_clone(MmsValue_getElement(value, valueIndex)); + + MmsValue_setElement(matchingReport->dataReferences, elementIndex, dataSetElement); + } + + valueIndex += 1; + } + } + + // valueIndex += includedElements; + } + + int i; + + if (matchingReport->dataSetValues == NULL) { + matchingReport->dataSetValues = MmsValue_createEmptyArray(dataSetSize); + matchingReport->reasonForInclusion = (ReasonForInclusion*) + GLOBAL_MALLOC(sizeof(ReasonForInclusion) * dataSetSize); + + int elementIndex; + + for (elementIndex = 0; elementIndex < dataSetSize; elementIndex++) + matchingReport->reasonForInclusion[elementIndex] = REASON_NOT_INCLUDED; + + } + + MmsValue* dataSetValues = matchingReport->dataSetValues; + + bool hasReasonForInclusion = MmsValue_getBitStringBit(optFlds, 3); + + if (hasReasonForInclusion) + matchingReport->hasReasonForInclusion = true; + + int reasonForInclusionIndex = valueIndex + includedElements; + + for (i = 0; i < dataSetSize; i++) { + if (MmsValue_getBitStringBit(inclusion, i) == true) { + + MmsValue* dataSetElement = MmsValue_getElement(dataSetValues, i); + + MmsValue* newElementValue = MmsValue_getElement(value, valueIndex); + + if (dataSetElement == NULL) + MmsValue_setElement(dataSetValues, i, MmsValue_clone(newElementValue)); + else + MmsValue_update(dataSetElement, newElementValue); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue)); + + valueIndex++; + + if (hasReasonForInclusion) { + MmsValue* reasonForInclusion = MmsValue_getElement(value, reasonForInclusionIndex); + + if (MmsValue_getBitStringBit(reasonForInclusion, 1) == true) + matchingReport->reasonForInclusion[i] = REASON_DATA_CHANGE; + else if (MmsValue_getBitStringBit(reasonForInclusion, 2) == true) + matchingReport->reasonForInclusion[i] = REASON_QUALITY_CHANGE; + else if (MmsValue_getBitStringBit(reasonForInclusion, 3) == true) + matchingReport->reasonForInclusion[i] = REASON_DATA_UPDATE; + else if (MmsValue_getBitStringBit(reasonForInclusion, 4) == true) + matchingReport->reasonForInclusion[i] = REASON_INTEGRITY; + else if (MmsValue_getBitStringBit(reasonForInclusion, 5) == true) + matchingReport->reasonForInclusion[i] = REASON_GI; + } + else { + matchingReport->reasonForInclusion[i] = REASON_UNKNOWN; + } + } + else { + matchingReport->reasonForInclusion[i] = REASON_NOT_INCLUDED; + } + } + + Semaphore_wait(self->reportHandlerMutex); + + if (matchingReport->callback != NULL) + matchingReport->callback(matchingReport->callbackParameter, matchingReport); + + Semaphore_post(self->reportHandlerMutex); + +exit_function: + return; +} + diff --git a/src/iec61850/client/client_report_control.c b/src/iec61850/client/client_report_control.c new file mode 100644 index 0000000..3d01def --- /dev/null +++ b/src/iec61850/client/client_report_control.c @@ -0,0 +1,681 @@ +/* + * client_report_control.c + * + * Implementation of the ClientReportControlBlock class + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_client.h" + +#include "stack_config.h" + +#include "ied_connection_private.h" + +#include "libiec61850_platform_includes.h" + +static bool +isBufferedRcb(const char* objectReference) +{ + const char* separator = strchr(objectReference, '.'); + + if (separator == NULL) + return false; //TODO report an error + + if (*(separator + 1) == 'B') + return true; + else + return false; +} + +ClientReportControlBlock +ClientReportControlBlock_create(const char* objectReference) +{ + ClientReportControlBlock self = (ClientReportControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock)); + + self->objectReference = copyString(objectReference); + self->isBuffered = isBufferedRcb(objectReference); + + return self; +} + +void +ClientReportControlBlock_destroy(ClientReportControlBlock self) +{ + GLOBAL_FREEMEM(self->objectReference); + + MmsValue_deleteIfNotNull(self->rptId); + MmsValue_deleteIfNotNull(self->rptEna); + MmsValue_deleteIfNotNull(self->resv); + MmsValue_deleteIfNotNull(self->datSet); + MmsValue_deleteIfNotNull(self->confRev); + MmsValue_deleteIfNotNull(self->optFlds); + MmsValue_deleteIfNotNull(self->bufTm); + MmsValue_deleteIfNotNull(self->sqNum); + MmsValue_deleteIfNotNull(self->trgOps); + MmsValue_deleteIfNotNull(self->intgPd); + MmsValue_deleteIfNotNull(self->gi); + MmsValue_deleteIfNotNull(self->purgeBuf); + MmsValue_deleteIfNotNull(self->entryId); + MmsValue_deleteIfNotNull(self->timeOfEntry); + MmsValue_deleteIfNotNull(self->resvTms); + MmsValue_deleteIfNotNull(self->owner); + + GLOBAL_FREEMEM(self); +} + +char* +ClientReportControlBlock_getObjectReference(ClientReportControlBlock self) +{ + return self->objectReference; +} + +bool +ClientReportControlBlock_isBuffered(ClientReportControlBlock self) +{ + return self->isBuffered; +} + +const char* +ClientReportControlBlock_getRptId(ClientReportControlBlock self) +{ + if (self->rptId != NULL) + return MmsValue_toString(self->rptId); + else + return NULL; +} + +void +ClientReportControlBlock_setRptId(ClientReportControlBlock self, const char* rptId) +{ + if (self->rptId == NULL) + self->rptId = MmsValue_newVisibleString(rptId); + else + MmsValue_setVisibleString(self->rptId, rptId); +} + + +bool +ClientReportControlBlock_getRptEna(ClientReportControlBlock self) +{ + if (self->rptEna != NULL) { + return MmsValue_getBoolean(self->rptEna); + } + else + return false; +} + +void +ClientReportControlBlock_setRptEna(ClientReportControlBlock self, bool rptEna) +{ + if (self->rptEna == NULL) + self->rptEna = MmsValue_newBoolean(rptEna); + else + MmsValue_setBoolean(self->rptEna, rptEna); +} + +bool +ClientReportControlBlock_getResv(ClientReportControlBlock self) +{ + if (self->resv != NULL) { + return MmsValue_getBoolean(self->resv); + } + else + return false; +} + +void +ClientReportControlBlock_setResv(ClientReportControlBlock self, bool resv) +{ + if (self->resv == NULL) + self->resv = MmsValue_newBoolean(resv); + else + MmsValue_setBoolean(self->resv, resv); +} + +const char* +ClientReportControlBlock_getDataSetReference(ClientReportControlBlock self) +{ + if (self->datSet != NULL) + return MmsValue_toString(self->datSet); + else + return NULL; +} + +void +ClientReportControlBlock_setDataSetReference(ClientReportControlBlock self, const char* dataSetReference) +{ + if (self->datSet == NULL) + self->datSet = MmsValue_newVisibleString(dataSetReference); + else + MmsValue_setVisibleString(self->datSet, dataSetReference); +} + +uint32_t +ClientReportControlBlock_getConfRev(ClientReportControlBlock self) +{ + if (self->confRev != NULL) + return MmsValue_toUint32(self->confRev); + else + return 0; +} + +int +ClientReportControlBlock_getOptFlds(ClientReportControlBlock self) +{ + return (MmsValue_getBitStringAsInteger(self->optFlds) / 2); +} + +void +ClientReportControlBlock_setOptFlds(ClientReportControlBlock self, int optFlds) +{ + if (self->optFlds == NULL) + self->optFlds = MmsValue_newBitString(10); + + MmsValue_setBitStringFromInteger(self->optFlds, optFlds * 2); /* bit 0 is reserved in MMS mapping */ +} + +uint32_t +ClientReportControlBlock_getBufTm(ClientReportControlBlock self) +{ + if (self->bufTm != NULL) + return MmsValue_toUint32(self->bufTm); + else + return 0; +} + +void +ClientReportControlBlock_setBufTm(ClientReportControlBlock self, uint32_t bufTm) +{ + if (self->bufTm == NULL) + self->bufTm = MmsValue_newUnsignedFromUint32(bufTm); + else + MmsValue_setUint32(self->bufTm, bufTm); +} + +uint16_t +ClientReportControlBlock_getSqNum(ClientReportControlBlock self) +{ + if (self->sqNum != NULL) + return (uint16_t) MmsValue_toUint32(self->sqNum); + else + return 0; +} + +int +ClientReportControlBlock_getTrgOps(ClientReportControlBlock self) +{ + int triggerOps = 0; + + if (self->trgOps != NULL) { + if (MmsValue_getBitStringBit(self->trgOps, 1)) + triggerOps += TRG_OPT_DATA_CHANGED; + if (MmsValue_getBitStringBit(self->trgOps, 2)) + triggerOps += TRG_OPT_QUALITY_CHANGED; + if (MmsValue_getBitStringBit(self->trgOps, 3)) + triggerOps += TRG_OPT_DATA_UPDATE; + if (MmsValue_getBitStringBit(self->trgOps, 4)) + triggerOps += TRG_OPT_INTEGRITY; + if (MmsValue_getBitStringBit(self->trgOps, 5)) + triggerOps += TRG_OPT_GI; + } + + return triggerOps; +} + +void +ClientReportControlBlock_setTrgOps(ClientReportControlBlock self, int trgOps) +{ + if (self->trgOps == NULL) + self->trgOps = MmsValue_newBitString(6); + + MmsValue_setBitStringFromInteger(self->trgOps, trgOps << 1); +} + +uint32_t +ClientReportControlBlock_getIntgPd(ClientReportControlBlock self) +{ + if (self->intgPd != NULL) + return MmsValue_toUint32(self->intgPd); + else + return 0; +} + +void +ClientReportControlBlock_setIntgPd(ClientReportControlBlock self, uint32_t intgPd) +{ + if (self->intgPd == NULL) + self->intgPd = MmsValue_newUnsignedFromUint32(intgPd); + else + MmsValue_setUint32(self->intgPd, intgPd); +} + +bool +ClientReportControlBlock_getGI(ClientReportControlBlock self) +{ + if (self->gi != NULL) + return MmsValue_getBoolean(self->gi); + else + return false; +} + +void +ClientReportControlBlock_setGI(ClientReportControlBlock self, bool gi) +{ + if (self->gi == NULL) + self->gi = MmsValue_newBoolean(gi); + else + MmsValue_setBoolean(self->gi, gi); +} + +bool +ClientReportControlBlock_getPurgeBuf(ClientReportControlBlock self) +{ + if (self->purgeBuf != NULL) + return MmsValue_getBoolean(self->purgeBuf); + else + return false; +} + +void +ClientReportControlBlock_setPurgeBuf(ClientReportControlBlock self, bool purgeBuf) +{ + if (self->purgeBuf == NULL) + self->purgeBuf = MmsValue_newBoolean(purgeBuf); + else + MmsValue_setBoolean(self->purgeBuf, purgeBuf); +} + +int16_t +ClientReportControlBlock_getResvTms(ClientReportControlBlock self) +{ + if (self->resvTms != NULL) + return (int16_t) MmsValue_toInt32(self->resvTms); + else + return 0; +} + +void +ClientReportControlBlock_setResvTms(ClientReportControlBlock self, int16_t resvTms) +{ + if (self->resvTms == NULL) + self->resvTms = MmsValue_newIntegerFromInt16(resvTms); + else + MmsValue_setInt32(self->resvTms, (int32_t) resvTms); +} + +MmsValue* +ClientReportControlBlock_getEntryId(ClientReportControlBlock self) +{ + return self->entryId; +} + +void +ClientReportControlBlock_setEntryId(ClientReportControlBlock self, MmsValue* entryId) +{ + if (self->entryId != NULL) { + MmsValue_update(self->entryId, entryId); + } + else { + if (MmsValue_getType(entryId) != MMS_OCTET_STRING) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ClientReportControlBlock_setEntryId invalid argument type\n"); + } + else + self->entryId = MmsValue_clone(entryId); + } +} + +uint64_t +ClientReportControlBlock_getEntryTime(ClientReportControlBlock self) +{ + if (self->timeOfEntry != NULL) + return MmsValue_getBinaryTimeAsUtcMs(self->timeOfEntry); + else + return 0; +} + +MmsValue* +ClientReportControlBlock_getOwner(ClientReportControlBlock self) +{ + return self->owner; +} + +static void +updateOrClone(MmsValue** valuePtr, MmsValue* values, int index) +{ + if (*valuePtr != NULL) + MmsValue_update(*valuePtr, MmsValue_getElement(values, index)); + else + *valuePtr = MmsValue_clone(MmsValue_getElement(values, index)); +} + +bool +private_ClientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* values) +{ + int rcbElementCount = MmsValue_getArraySize(values); + + updateOrClone(&(self->rptId), values, 0); + updateOrClone(&(self->rptEna), values, 1); + + if (self->isBuffered) { + updateOrClone(&(self->datSet), values, 2); + updateOrClone(&(self->confRev), values, 3); + updateOrClone(&(self->optFlds), values, 4); + updateOrClone(&(self->bufTm), values, 5); + updateOrClone(&(self->sqNum), values, 6); + updateOrClone(&(self->trgOps), values,7); + updateOrClone(&(self->intgPd), values, 8); + updateOrClone(&(self->gi), values, 9); + updateOrClone(&(self->purgeBuf), values, 10); + updateOrClone(&(self->entryId), values, 11); + updateOrClone(&(self->timeOfEntry), values, 12); + + if (rcbElementCount > 13) { + MmsValue* element13 = MmsValue_getElement(values, 13); + + if (MmsValue_getType(element13) == MMS_OCTET_STRING) + updateOrClone(&(self->owner), values, 13); + else { + updateOrClone(&(self->resvTms), values, 13); + + if (rcbElementCount > 14) + updateOrClone(&(self->owner), values, 14); + } + } + + } + else { + updateOrClone(&(self->resv), values, 2); + updateOrClone(&(self->datSet), values, 3); + updateOrClone(&(self->confRev), values, 4); + updateOrClone(&(self->optFlds), values, 5); + updateOrClone(&(self->bufTm), values, 6); + updateOrClone(&(self->sqNum), values, 7); + updateOrClone(&(self->trgOps), values, 8); + updateOrClone(&(self->intgPd), values, 9); + updateOrClone(&(self->gi), values, 10); + + if (rcbElementCount == 12) /* owner is optional */ + updateOrClone(&(self->owner), values, 11); + } + + return true; +} + + + +ClientReportControlBlock +IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char* rcbReference, + ClientReportControlBlock updateRcb) +{ + MmsError mmsError = MMS_ERROR_NONE; + + ClientReportControlBlock returnRcb = updateRcb; + + char domainId[65]; + char itemId[65]; + + char* domainName = MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId); + + if (domainName == NULL) + return NULL; + + strcpy(itemId, rcbReference + strlen(domainId) + 1); + + StringUtils_replace(itemId, '.', '$'); + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: readRCBValues for %s\n", rcbReference); + + MmsValue* rcb = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId); + + if (mmsError != MMS_ERROR_NONE) { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + + return NULL; + } + + if (rcb == NULL) { + *error = IED_ERROR_OBJECT_DOES_NOT_EXIST; + return NULL; + } + + if (MmsValue_getType(rcb) == MMS_DATA_ACCESS_ERROR) { + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: getRCBValues returned data-access-error!\n"); + + *error = iedConnection_mapDataAccessErrorToIedError( + MmsValue_getDataAccessError(rcb)); + + return NULL; + } + + if (MmsValue_getType(rcb) != MMS_STRUCTURE) { + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n"); + + MmsValue_delete(rcb); + + *error = IED_ERROR_UNKNOWN; + return NULL; + } + + if (returnRcb == NULL) + returnRcb = ClientReportControlBlock_create(rcbReference); + + private_ClientReportControlBlock_updateValues(returnRcb, rcb); + + MmsValue_delete(rcb); + + *error = IED_ERROR_OK; + + return returnRcb; +} + +void +IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientReportControlBlock rcb, + uint32_t parametersMask, bool singleRequest) +{ + *error = IED_ERROR_OK; + + MmsError mmsError = MMS_ERROR_NONE; + + bool isBuffered = ClientReportControlBlock_isBuffered(rcb); + + 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); + + /* 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, 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, copyString(itemId)); + LinkedList_add(values, rcb->resvTms); + } + + if (parametersMask & RCB_ELEMENT_RPT_ID) { + strcpy(itemId + itemIdLen, "$RptID"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->rptId); + } + + if (parametersMask & RCB_ELEMENT_DATSET) { + strcpy(itemId + itemIdLen, "$DatSet"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->datSet); + } + + if (parametersMask & RCB_ELEMENT_ENTRY_ID) { + strcpy(itemId + itemIdLen, "$EntryID"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->entryId); + } + + if (parametersMask & RCB_ELEMENT_OPT_FLDS) { + strcpy(itemId + itemIdLen, "$OptFlds"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->optFlds); + } + + if (parametersMask & RCB_ELEMENT_BUF_TM) { + strcpy(itemId + itemIdLen, "$BufTm"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->bufTm); + } + + if (parametersMask & RCB_ELEMENT_TRG_OPS) { + strcpy(itemId + itemIdLen, "$TrgOps"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->trgOps); + } + + if (parametersMask & RCB_ELEMENT_INTG_PD) { + strcpy(itemId + itemIdLen, "$IntgPd"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->intgPd); + } + + if (parametersMask & RCB_ELEMENT_GI) { + strcpy(itemId + itemIdLen, "$GI"); + + LinkedList_add(itemIds, 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, 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, copyString(itemId)); + LinkedList_add(values, rcb->timeOfEntry); + } + + if (parametersMask & RCB_ELEMENT_RPT_ENA) { + strcpy(itemId + itemIdLen, "$RptEna"); + + LinkedList_add(itemIds, copyString(itemId)); + LinkedList_add(values, rcb->rptEna); + } + + if (singleRequest) { + LinkedList accessResults = NULL; + + MmsConnection_writeMultipleVariables(self->connection, &mmsError, domainId, itemIds, values, &accessResults); + + if (accessResults != NULL) { + + LinkedList accessResult = LinkedList_getNext(accessResults); + + while (accessResult != NULL) { + MmsValue* dataAccessError = (MmsValue*) accessResult->data; + + if (MmsValue_getDataAccessError(dataAccessError) != DATA_ACCESS_ERROR_SUCCESS) { + *error = IED_ERROR_UNKNOWN; + break; + } + + accessResult = LinkedList_getNext(accessResult); + } + + LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete); + } + else + *error = iedConnection_mapMmsErrorToIedError(mmsError); + + goto exit_function; + } + else { + LinkedList itemIdElement = LinkedList_getNext(itemIds); + LinkedList valueElement = LinkedList_getNext(values); + + while (itemIdElement != NULL) { + char* rcbItemId = (char*) itemIdElement->data; + MmsValue* value = (MmsValue*) valueElement->data; + + MmsConnection_writeVariable(self->connection, &mmsError, domainId, rcbItemId, value); + + if (mmsError != MMS_ERROR_NONE) + break; + + itemIdElement = LinkedList_getNext(itemIdElement); + valueElement = LinkedList_getNext(valueElement); + } + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + goto exit_function; + } + + error_invalid_parameter: + *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; + + exit_function: + LinkedList_destroy(itemIds); + LinkedList_destroyStatic(values); +} diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c new file mode 100644 index 0000000..7c30568 --- /dev/null +++ b/src/iec61850/client/ied_connection.c @@ -0,0 +1,2223 @@ +/* + * ied_connection.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "iec61850_client.h" + +#include "stack_config.h" + +#include "mms_client_connection.h" + +#include "ied_connection_private.h" +#include "mms_value_internal.h" + +#define DEFAULT_CONNECTION_TIMEOUT 10000 +#define DATA_SET_MAX_NAME_LENGTH 64 /* is 32 according to standard! */ + +typedef struct sICLogicalDevice +{ + char* name; + LinkedList variables; + LinkedList dataSets; +} ICLogicalDevice; + +struct sClientDataSet +{ + char* dataSetReference; /* data set reference in MMS format */ + MmsValue* dataSetValues; /* MmsValue instance of type MMS_ARRAY */ +}; + +struct sFileDirectoryEntry { + char* fileName; + uint32_t fileSize; + uint64_t lastModified; +}; + +IedClientError +iedConnection_mapMmsErrorToIedError(MmsError mmsError) +{ + switch (mmsError) { + case MMS_ERROR_NONE: + return IED_ERROR_OK; + + case MMS_ERROR_CONNECTION_LOST: + return IED_ERROR_CONNECTION_LOST; + + case MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED: + return IED_ERROR_ACCESS_DENIED; + + case MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT: + return IED_ERROR_OBJECT_DOES_NOT_EXIST; + + case MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED: + return IED_ERROR_OBJECT_ACCESS_UNSUPPORTED; + + case MMS_ERROR_DEFINITION_OBJECT_EXISTS: + return IED_ERROR_OBJECT_EXISTS; + + case MMS_ERROR_DEFINITION_TYPE_INCONSISTENT: + return IED_ERROR_TYPE_INCONSISTENT; + + case MMS_ERROR_SERVICE_TIMEOUT: + return IED_ERROR_TIMEOUT; + + case MMS_ERROR_FILE_FILE_NON_EXISTENT: + return IED_ERROR_OBJECT_DOES_NOT_EXIST; + + case MMS_ERROR_CONNECTION_REJECTED: + return IED_ERROR_CONNECTION_REJECTED; + + case MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID: + return IED_ERROR_OBJECT_VALUE_INVALID; + + default: + return IED_ERROR_UNKNOWN; + } +} + +IedClientError +iedConnection_mapDataAccessErrorToIedError(MmsDataAccessError mmsError) +{ + switch (mmsError) { + + case DATA_ACCESS_ERROR_NO_RESPONSE: + return IED_ERROR_TIMEOUT; + + case DATA_ACCESS_ERROR_SUCCESS: + return IED_ERROR_OK; + + case DATA_ACCESS_ERROR_OBJECT_INVALIDATED: + return IED_ERROR_OBJECT_INVALIDATED; + + case DATA_ACCESS_ERROR_HARDWARE_FAULT: + return IED_ERROR_HARDWARE_FAULT; + + case DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE: + return IED_ERROR_TEMPORARILY_UNAVAILABLE; + + case DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED: + return IED_ERROR_ACCESS_DENIED; + + case DATA_ACCESS_ERROR_OBJECT_UNDEFINED: + return IED_ERROR_OBJECT_UNDEFINED; + + case DATA_ACCESS_ERROR_INVALID_ADDRESS: + return IED_ERROR_INVALID_ADDRESS; + + case DATA_ACCESS_ERROR_TYPE_UNSUPPORTED: + return IED_ERROR_TYPE_UNSUPPORTED; + + case DATA_ACCESS_ERROR_TYPE_INCONSISTENT: + return IED_ERROR_TYPE_INCONSISTENT; + + case DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT: + return IED_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + + case DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED: + return IED_ERROR_OBJECT_ACCESS_UNSUPPORTED; + + case DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT: + return IED_ERROR_OBJECT_DOES_NOT_EXIST; + + case DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID: + return IED_ERROR_OBJECT_VALUE_INVALID; + + default: + return IED_ERROR_UNKNOWN; + } +} + + +static ICLogicalDevice* +ICLogicalDevice_create(char* name) +{ + ICLogicalDevice* self = (ICLogicalDevice*) GLOBAL_CALLOC(1, sizeof(struct sICLogicalDevice)); + + self->name = copyString(name); + + return self; +} + +static void +ICLogicalDevice_setVariableList(ICLogicalDevice* self, LinkedList variables) +{ + self->variables = variables; +} + +static void +ICLogicalDevice_setDataSetList(ICLogicalDevice* self, LinkedList dataSets) +{ + self->dataSets = dataSets; +} + +static void +ICLogicalDevice_destroy(ICLogicalDevice* self) +{ + GLOBAL_FREEMEM(self->name); + + if (self->variables != NULL) + LinkedList_destroy(self->variables); + + if (self->dataSets != NULL) + LinkedList_destroy(self->dataSets); + + GLOBAL_FREEMEM(self); +} + +static ClientDataSet +ClientDataSet_create(const char* dataSetReference) +{ + ClientDataSet self = (ClientDataSet) GLOBAL_CALLOC(1, sizeof(struct sClientDataSet)); + + self->dataSetReference = copyString(dataSetReference); + StringUtils_replace(self->dataSetReference, '.', '$'); + + self->dataSetValues = NULL; + + return self; +} + +void +ClientDataSet_destroy(ClientDataSet self) +{ + if (self->dataSetValues != NULL) + MmsValue_delete(self->dataSetValues); + + GLOBAL_FREEMEM(self->dataSetReference); + + GLOBAL_FREEMEM(self); +} + +static void +ClientDataSet_setDataSetValues(ClientDataSet self, MmsValue* dataSetValues) +{ + self->dataSetValues = dataSetValues; +} + +MmsValue* +ClientDataSet_getValues(ClientDataSet self) +{ + return self->dataSetValues; +} + +char* +ClientDataSet_getReference(ClientDataSet self) +{ + return self->dataSetReference; +} + +int +ClientDataSet_getDataSetSize(ClientDataSet self) +{ + if (self->dataSetValues != NULL) { + return MmsValue_getArraySize(self->dataSetValues); + } + else + return 0; +} + +bool +private_IedConnection_doesControlObjectMatch(const char* objRef, const char* cntrlObj) +{ + int i = 0; + + while (objRef[i] != '/') { + if (objRef[i] != cntrlObj[i]) + return false; + + i++; + } + + if (cntrlObj[i] != '/') + return false; + + // --> LD is equal + + i++; + + while (objRef[i] != '.') { + if (objRef[i] != cntrlObj[i]) + return false; + i++; + } + + int j = i; + + if (cntrlObj[j++] != '$') + return false; + + // --> LN is equal + + if (cntrlObj[j++] != 'C') + return false; + if (cntrlObj[j++] != 'O') + return false; + if (cntrlObj[j++] != '$') + return false; + + // --> FC is ok + + i++; + + while (objRef[i] != 0) { + if (cntrlObj[j] == 0) + return false; + + if (objRef[i] == '.') { + if (cntrlObj[j] != '$') + return false; + } + else { + if (objRef[i] != cntrlObj[j]) + return false; + } + + i++; + j++; + } + + if ((cntrlObj[j] == 0) || (cntrlObj[j] == '$')) + return true; + else + return false; +} + +static bool +doesReportMatchControlObject(char* domainName, char* itemName, char* objectRef) +{ + int i = 0; + + while (domainName[i] != 0) { + if (domainName[i] != objectRef[i]) + return false; + + i++; + } + + if (objectRef[i] != '/') + return false; + + // --> LD is equal + + i++; + int j = 0; + + while (objectRef[i] != '.') { + if (objectRef[i] != itemName[j]) + return false; + j++; + i++; + } + + if (itemName[j++] != '$') + return false; + + // --> LN is equal + + if (itemName[j++] != 'C') + return false; + if (itemName[j++] != 'O') + return false; + if (itemName[j++] != '$') + return false; + + // --> FC is ok + + i++; + + while (objectRef[i] != 0) { + if (itemName[j] == 0) + return false; + + if (objectRef[i] == '.') { + if (itemName[j] != '$') + return false; + } + else { + if (objectRef[i] != itemName[j]) + return false; + } + + i++; + j++; + } + + if (itemName[j++] != '$') + return false; + + // --> object name is equal + + if (itemName[j++] != 'O') + return false; + if (itemName[j++] != 'p') + return false; + if (itemName[j++] != 'e') + return false; + if (itemName[j++] != 'r') + return false; + if (itemName[j++] != 0) + return false; + + return true; +} + +static void +handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError) +{ + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: received LastApplError\n"); + + if ((MmsValue_getType(lastApplError) != MMS_STRUCTURE) || (MmsValue_getArraySize(lastApplError) != 5)) + { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: LastApplError has wrong type!\n"); + + return; + } + + MmsValue* cntrlObj = MmsValue_getElement(lastApplError, 0); + MmsValue* error = MmsValue_getElement(lastApplError, 1); + //MmsValue* origin = MmsValue_getElement(lastApplError, 2); + MmsValue* ctlNum = MmsValue_getElement(lastApplError, 3); + MmsValue* addCause = MmsValue_getElement(lastApplError, 4); + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: CntrlObj: %s\n", MmsValue_toString(cntrlObj)); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ctlNum: %u\n", MmsValue_toUint32(ctlNum)); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: addCause: %i\n", MmsValue_toInt32(addCause)); + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: error: %i\n", MmsValue_toInt32(error)); + + self->lastApplError.ctlNum = MmsValue_toUint32(ctlNum); + self->lastApplError.addCause = (ControlAddCause) MmsValue_toInt32(addCause); + self->lastApplError.error = MmsValue_toInt32(error); + LinkedList control = LinkedList_getNext(self->clientControls); + while (control != NULL) { + ControlObjectClient object = (ControlObjectClient) control->data; + + const char* objectRef = ControlObjectClient_getObjectReference(object); + + if (private_IedConnection_doesControlObjectMatch(objectRef, MmsValue_toString(cntrlObj))) { + ControlObjectClient_setLastApplError(object, self->lastApplError); + } + + control = LinkedList_getNext(control); + } +} + +static void +informationReportHandler(void* parameter, char* domainName, + char* variableListName, MmsValue* value, bool isVariableListName) +{ + IedConnection self = (IedConnection) parameter; + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: received information report for %s\n", variableListName); + + if (domainName == NULL) { + + if (isVariableListName) { + private_IedConnection_handleReport(self, value); + } + else { + if (strcmp(variableListName, "LastApplError") == 0) + handleLastApplErrorMessage(self, value); + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: Received unknown variable list report for list: %s\n", variableListName); + } + } + } + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); + + LinkedList control = LinkedList_getNext(self->clientControls); + + while (control != NULL) { + ControlObjectClient object = (ControlObjectClient) control->data; + + char* objectRef = ControlObjectClient_getObjectReference(object); + + if (doesReportMatchControlObject(domainName, variableListName, objectRef)) + private_ControlObjectClient_invokeCommandTerminationHandler(object); + + control = LinkedList_getNext(control); + } + } + + MmsValue_delete(value); +} + +IedConnection +IedConnection_create() +{ + IedConnection self = (IedConnection) GLOBAL_CALLOC(1, sizeof(struct sIedConnection)); + + self->enabledReports = LinkedList_create(); + self->logicalDevices = NULL; + self->clientControls = LinkedList_create(); + + self->connection = MmsConnection_create(); + + self->state = IED_STATE_IDLE; + + self->stateMutex = Semaphore_create(1); + self->reportHandlerMutex = Semaphore_create(1); + + self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; + + return self; +} + +void +IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs) +{ + self->connectionTimeout = timeoutInMs; +} + +IedConnectionState +IedConnection_getState(IedConnection self) +{ + IedConnectionState state; + + Semaphore_wait(self->stateMutex); + state = self->state; + Semaphore_post(self->stateMutex); + + return state; +} + +static void +IedConnection_setState(IedConnection self, IedConnectionState newState) +{ + Semaphore_wait(self->stateMutex); + self->state = newState; + Semaphore_post(self->stateMutex); +} + +void +IedConnection_installConnectionClosedHandler(IedConnection self, IedConnectionClosedHandler handler, + void* parameter) +{ + self->connectionCloseHandler = handler; + self->connectionClosedParameter = parameter; +} + +static void +connectionLostHandler(MmsConnection connection, void* parameter) +{ + IedConnection self = (IedConnection) parameter; + + IedConnection_setState(self, IED_STATE_CLOSED); + + if (self->connectionCloseHandler != NULL) + self->connectionCloseHandler(self->connectionClosedParameter, self); + + if (DEBUG_IED_CLIENT) + printf("IedConnection closed!\n"); +} + +void +IedConnection_connect(IedConnection self, IedClientError* error, const char* hostname, int tcpPort) +{ + MmsError mmsError; + + if (IedConnection_getState(self) != IED_STATE_CONNECTED) { + + MmsConnection_setConnectionLostHandler(self->connection, connectionLostHandler, (void*) self); + MmsConnection_setInformationReportHandler(self->connection, informationReportHandler, self); + + MmsConnection_setConnectTimeout(self->connection, self->connectionTimeout); + + if (MmsConnection_connect(self->connection, &mmsError, hostname, tcpPort)) { + *error = IED_ERROR_OK; + IedConnection_setState(self, IED_STATE_CONNECTED); + } + else + *error = iedConnection_mapMmsErrorToIedError(mmsError); + } + else + *error = IED_ERROR_ALREADY_CONNECTED; +} + +void +IedConnection_abort(IedConnection self, IedClientError* error) +{ + if (IedConnection_getState(self) == IED_STATE_CONNECTED) { + IedConnection_setState(self, IED_STATE_CLOSED); + + MmsError mmsError; + + MmsConnection_abort(self->connection, &mmsError); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + } + else + *error = IED_ERROR_NOT_CONNECTED; +} + +void +IedConnection_release(IedConnection self, IedClientError* error) +{ + if (IedConnection_getState(self) == IED_STATE_CONNECTED) { + MmsError mmsError; + + MmsConnection_conclude(self->connection, &mmsError); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + } + else + *error = IED_ERROR_NOT_CONNECTED; +} + +void +IedConnection_close(IedConnection self) +{ + if (IedConnection_getState(self) == IED_STATE_CONNECTED) { + MmsConnection_close(self->connection); + IedConnection_setState(self, IED_STATE_CLOSED); + } +} + +void +IedConnection_destroy(IedConnection self) +{ + IedConnection_close(self); + + MmsConnection_destroy(self->connection); + + if (self->logicalDevices != NULL) + LinkedList_destroyDeep(self->logicalDevices, (LinkedListValueDeleteFunction) ICLogicalDevice_destroy); + + if (self->enabledReports != NULL) + LinkedList_destroyDeep(self->enabledReports, (LinkedListValueDeleteFunction) ClientReport_destroy); + + LinkedList_destroyStatic(self->clientControls); + + Semaphore_destroy(self->stateMutex); + Semaphore_destroy(self->reportHandlerMutex); + + GLOBAL_FREEMEM(self); +} + + +MmsVariableSpecification* +IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc) +{ + char domainIdBuffer[65]; + char itemIdBuffer[129]; + + char* domainId; + char* itemId; + + MmsError mmsError; + MmsVariableSpecification* varSpec = NULL; + + domainId = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainIdBuffer); + itemId = MmsMapping_createMmsVariableNameFromObjectReference(objectReference, fc, itemIdBuffer); + + if ((domainId == NULL) || (itemId == NULL)) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto cleanup_and_exit; + } + + varSpec = + MmsConnection_getVariableAccessAttributes(self->connection, &mmsError, domainId, itemId); + + if (varSpec != NULL) + *error = IED_ERROR_OK; + else + *error = iedConnection_mapMmsErrorToIedError(mmsError); + + cleanup_and_exit: + + return varSpec; +} + +MmsValue* +IedConnection_readObject(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc) +{ + char domainIdBuffer[65]; + char itemIdBuffer[65]; + MmsValue* value = NULL; + + char* domainId; + char* itemId; + + domainId = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainIdBuffer); + itemId = MmsMapping_createMmsVariableNameFromObjectReference(objectReference, fc, itemIdBuffer); + + if ((domainId == NULL) || (itemId == NULL)) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + MmsError mmsError; + + value = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId); + + if (value != NULL) + *error = IED_ERROR_OK; + else + *error = iedConnection_mapMmsErrorToIedError(mmsError); + + return value; +} + +bool +IedConnection_readBooleanValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + bool retVal = false; + + if (value != NULL) { + if (MmsValue_getType(value) == MMS_BOOLEAN) + retVal = MmsValue_getBoolean(value); + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + } + + return retVal; +} + +float +IedConnection_readFloatValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + float retVal = 0.f; + + if (value != NULL) { + if (MmsValue_getType(value) == MMS_FLOAT) + retVal = MmsValue_toFloat(value); + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + } + + return retVal; +} + +char* +IedConnection_readStringValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + char* retVal = NULL; + + if (value != NULL) { + if ((MmsValue_getType(value) == MMS_VISIBLE_STRING) || (MmsValue_getType(value) == MMS_STRING)) + retVal = copyString(MmsValue_toString(value)); + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + } + + return retVal; +} + +int32_t +IedConnection_readInt32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + int32_t retVal = 0.f; + + if (value != NULL) { + if ((MmsValue_getType(value) == MMS_INTEGER) || (MmsValue_getType(value) == MMS_UNSIGNED)) + retVal = MmsValue_toInt32(value); + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + } + + return retVal; +} + +uint32_t +IedConnection_readUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + uint32_t retVal = 0.f; + + if (value != NULL) { + if ((MmsValue_getType(value) == MMS_INTEGER) || (MmsValue_getType(value) == MMS_UNSIGNED)) + retVal = MmsValue_toUint32(value); + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + } + + return retVal; +} + +Timestamp* +IedConnection_readTimestampValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc, + Timestamp* timeStamp) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + Timestamp* retVal = timeStamp; + + if (value != NULL) { + if (MmsValue_getType(value) == MMS_UTC_TIME) { + + if (retVal == NULL) + retVal = (Timestamp*) GLOBAL_MALLOC(sizeof(Timestamp)); + + memcpy(retVal->val, value->value.utcTime, 8); + } + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + + } + + return retVal; +} + +Quality +IedConnection_readQualityValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) +{ + MmsValue* value = IedConnection_readObject(self, error, objectReference, fc); + + Quality quality = QUALITY_VALIDITY_GOOD; + + if (value != NULL) { + + if ((MmsValue_getType(value) == MMS_BIT_STRING) && (MmsValue_getBitStringSize(value) == 13)) { + quality = Quality_fromMmsValue(value); + } + else { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); + else + *error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED; + } + + MmsValue_delete(value); + + } + + return quality; +} + +void +IedConnection_writeObject(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, MmsValue* value) +{ + char domainIdBuffer[65]; + char itemIdBuffer[65]; + + char* domainId; + char* itemId; + + domainId = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainIdBuffer); + itemId = MmsMapping_createMmsVariableNameFromObjectReference(objectReference, fc, itemIdBuffer); + + if ((domainId == NULL) || (itemId == NULL)) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return; + } + + MmsError mmsError; + + MmsConnection_writeVariable(self->connection, &mmsError, domainId, itemId, value); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); +} + +void +IedConnection_writeBooleanValue(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, bool value) +{ + MmsValue mmsValue; + mmsValue.deleteValue = 0; + mmsValue.type = MMS_BOOLEAN; + mmsValue.value.boolean = value; + + IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); +} + +void +IedConnection_writeInt32Value(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, int32_t value) +{ + uint8_t valueBuffer[4]; + + Asn1PrimitiveValue pVal; + pVal.maxSize = 4; + pVal.size = 4; + pVal.octets = valueBuffer; + + MmsValue mmsValue; + mmsValue.type = MMS_INTEGER; + mmsValue.deleteValue = 0; + mmsValue.value.integer = &pVal; + + MmsValue_setInt32(&mmsValue, value); + + IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); +} + + +void +IedConnection_writeUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, uint32_t value) +{ + uint8_t valueBuffer[4]; + + Asn1PrimitiveValue pVal; + pVal.maxSize = 4; + pVal.size = 4; + pVal.octets = valueBuffer; + + MmsValue mmsValue; + mmsValue.type = MMS_UNSIGNED; + mmsValue.deleteValue = 0; + mmsValue.value.integer = &pVal; + + MmsValue_setUint32(&mmsValue, value); + + IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); +} + +void +IedConnection_writeFloatValue(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, float value) +{ + MmsValue mmsValue; + mmsValue.type = MMS_FLOAT; + mmsValue.value.floatingPoint.exponentWidth = 8; + mmsValue.value.floatingPoint.formatWidth = 32; + mmsValue.value.floatingPoint.buf = (uint8_t*) &value; + + IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); +} + +void +IedConnection_writeOctetString(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, uint8_t* value, int valueLength) +{ + MmsValue mmsValue; + mmsValue.type = MMS_OCTET_STRING; + mmsValue.value.octetString.buf = value; + mmsValue.value.octetString.size = valueLength; + mmsValue.value.octetString.size = valueLength; + + IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); +} + +void +IedConnection_writeVisibleStringValue(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, char* value) +{ + MmsValue mmsValue; + mmsValue.deleteValue = 0; + mmsValue.type = MMS_VISIBLE_STRING; + mmsValue.value.visibleString.buf = value; + + IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); +} + +void +IedConnection_getDeviceModelFromServer(IedConnection self, IedClientError* error) +{ + MmsError mmsError = MMS_ERROR_NONE; + *error = IED_ERROR_OK; + + LinkedList logicalDeviceNames = MmsConnection_getDomainNames(self->connection, &mmsError); + + if (logicalDeviceNames != NULL) { + + if (self->logicalDevices != NULL) { + LinkedList_destroyDeep(self->logicalDevices, (LinkedListValueDeleteFunction) ICLogicalDevice_destroy); + self->logicalDevices = NULL; + } + + LinkedList logicalDevice = LinkedList_getNext(logicalDeviceNames); + + LinkedList logicalDevices = LinkedList_create(); + + while (logicalDevice != NULL) { + char* name = (char*) logicalDevice->data; + + ICLogicalDevice* icLogicalDevice = ICLogicalDevice_create(name); + + LinkedList variables = MmsConnection_getDomainVariableNames(self->connection, + &mmsError, name); + + if (variables != NULL) + ICLogicalDevice_setVariableList(icLogicalDevice, variables); + else { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + break; + } + + LinkedList dataSets = MmsConnection_getDomainVariableListNames(self->connection, + &mmsError, name); + + if (dataSets != NULL) + ICLogicalDevice_setDataSetList(icLogicalDevice, dataSets); + else { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + break; + } + + LinkedList_add(logicalDevices, icLogicalDevice); + + logicalDevice = LinkedList_getNext(logicalDevice); + } + + self->logicalDevices = logicalDevices; + + LinkedList_destroy(logicalDeviceNames); + } + else + *error = iedConnection_mapMmsErrorToIedError(mmsError); +} + +LinkedList /**/ +IedConnection_getLogicalDeviceList(IedConnection self, IedClientError* error) +{ + *error = IED_ERROR_OK; + + if (self->logicalDevices == NULL) { + IedConnection_getDeviceModelFromServer(self, error); + + if (*error != IED_ERROR_OK) + return NULL; + } + + if (self->logicalDevices != NULL) { + LinkedList logicalDevice = LinkedList_getNext(self->logicalDevices); + + LinkedList logicalDeviceList = LinkedList_create(); + + while (logicalDevice != NULL) { + ICLogicalDevice* icLogicalDevice = (ICLogicalDevice*) logicalDevice->data; + + char* logicalDeviceName = copyString(icLogicalDevice->name); + + LinkedList_add(logicalDeviceList, logicalDeviceName); + + logicalDevice = LinkedList_getNext(logicalDevice); + } + + *error = IED_ERROR_OK; + return logicalDeviceList; + } + else { + *error = IED_ERROR_UNKNOWN; + return NULL; + } +} + + +static void +mmsFileDirectoryHandler(void* parameter, char* filename, uint32_t size, uint64_t lastModified) +{ + LinkedList fileNames = (LinkedList) parameter; + + FileDirectoryEntry newDirectoryEntry = FileDirectoryEntry_create(filename, size, lastModified); + + LinkedList_add(fileNames, (void*) newDirectoryEntry); +} + +LinkedList /**/ +IedConnection_getFileDirectory(IedConnection self, IedClientError* error, const char* directoryName) +{ + *error = IED_ERROR_OK; + + MmsError mmsError = MMS_ERROR_NONE; + + LinkedList fileNames = LinkedList_create(); + + char* continueAfter = NULL; + + bool moreFollows = false; + + do { + moreFollows = + MmsConnection_getFileDirectory(self->connection, &mmsError, directoryName, continueAfter, + mmsFileDirectoryHandler, fileNames); + + if (mmsError != MMS_ERROR_NONE) { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + LinkedList_destroyDeep(fileNames, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy); + + return NULL; + } + + if (moreFollows) { + FileDirectoryEntry lastDirectoryEntry = (FileDirectoryEntry) + LinkedList_getData(LinkedList_getLastElement(fileNames)); + + continueAfter = lastDirectoryEntry->fileName; + } + + } while (moreFollows == true); + + return fileNames; +} + + +struct sClientProvidedFileReadHandler { + IedClientGetFileHandler handler; + void* handlerParameter; + bool retVal; + uint32_t byteReceived; +}; + +static void +mmsFileReadHandler(void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t bytesReceived) +{ + struct sClientProvidedFileReadHandler* handler = (struct sClientProvidedFileReadHandler*) parameter; + + handler->retVal = handler->handler(handler->handlerParameter, buffer, bytesReceived); + + handler->byteReceived += bytesReceived; +} + +uint32_t +IedConnection_getFile(IedConnection self, IedClientError* error, const char* fileName, IedClientGetFileHandler handler, + void* handlerParameter) +{ + *error = IED_ERROR_OK; + + MmsError mmsError; + + uint32_t fileSize; + + int32_t frsmId = + MmsConnection_fileOpen(self->connection, &mmsError, fileName, 0, &fileSize, NULL); + + if (mmsError != MMS_ERROR_NONE) { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + return 0; + } + + struct sClientProvidedFileReadHandler clientFileReadHandler; + clientFileReadHandler.handler = handler; + clientFileReadHandler.handlerParameter = handlerParameter; + clientFileReadHandler.retVal = true; + clientFileReadHandler.byteReceived = 0; + + bool continueRead = true; + + while (continueRead == true) { + bool moreFollows = + MmsConnection_fileRead(self->connection, &mmsError, frsmId, mmsFileReadHandler, + &clientFileReadHandler); + + if (mmsError != MMS_ERROR_NONE) { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + return 0; + } + + if (clientFileReadHandler.retVal == false) { + *error = IED_ERROR_UNKNOWN; + break; + } + + if (moreFollows == false) + break; + } + + MmsConnection_fileClose(self->connection, &mmsError, frsmId); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + + return clientFileReadHandler.byteReceived; +} + +void +IedConnection_deleteFile(IedConnection self, IedClientError* error, const char* fileName) +{ + *error = IED_ERROR_OK; + + MmsError mmsError; + + MmsConnection_fileDelete(self->connection, &mmsError, fileName); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); +} + + +LinkedList /**/ +IedConnection_getServerDirectory(IedConnection self, IedClientError* error, bool getFileNames) +{ + if (getFileNames) + return IedConnection_getFileDirectory(self, error, NULL); + else + return IedConnection_getLogicalDeviceList(self, error); +} + +LinkedList /**/ +IedConnection_getLogicalDeviceDirectory(IedConnection self, IedClientError* error, + const char* logicalDeviceName) +{ + *error = IED_ERROR_OK; + + if (self->logicalDevices == NULL) + IedConnection_getDeviceModelFromServer(self, error); + + if (*error != IED_ERROR_OK) + return NULL; + + LinkedList logicalDevice = LinkedList_getNext(self->logicalDevices); + + while (logicalDevice != NULL) { + ICLogicalDevice* device = (ICLogicalDevice*) logicalDevice->data; + + if (strcmp(device->name, logicalDeviceName) == 0) { + LinkedList logicalNodeNames = LinkedList_create(); + + LinkedList variable = LinkedList_getNext(device->variables); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + if (strchr(variableName, '$') == NULL) + LinkedList_add(logicalNodeNames, copyString((char*) variable->data)); + + variable = LinkedList_getNext(variable); + } + + return logicalNodeNames; + } + + logicalDevice = LinkedList_getNext(logicalDevice); + } + + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + + return NULL; +} + +static bool +addToStringSet(LinkedList set, char* string) +{ + LinkedList element = set; + + while (LinkedList_getNext(element) != NULL) { + if (strcmp((char*) LinkedList_getNext(element)->data, string) == 0) + return false; + + element = LinkedList_getNext(element); + } + + LinkedList_insertAfter(element, string); + return true; +} + +static void +addVariablesWithFc(char* fc, char* lnName, LinkedList variables, LinkedList lnDirectory) +{ + LinkedList variable = LinkedList_getNext(variables); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + char* fcPos = strchr(variableName, '$'); + + if (fcPos != NULL) { + if (memcmp(fcPos + 1, fc, 2) != 0) + goto next_element; + + int lnNameLen = fcPos - variableName; + + if (strncmp(variableName, lnName, lnNameLen) == 0) { + char* fcEndPos = strchr(fcPos + 1, '$'); + + if (fcEndPos != NULL) { + char* nameEndPos = strchr(fcEndPos + 1, '$'); + + if (nameEndPos == NULL) + addToStringSet(lnDirectory, copyString(fcEndPos + 1)); + } + } + } + + next_element: + + variable = LinkedList_getNext(variable); + } +} + +LinkedList /**/ +IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, + const char* logicalNodeReference, ACSIClass acsiClass) +{ + *error = IED_ERROR_OK; + + if (strlen(logicalNodeReference) > 129) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + if (self->logicalDevices == NULL) + IedConnection_getDeviceModelFromServer(self, error); + + if (*error != IED_ERROR_OK) + return NULL; + + char lnRefCopy[130]; + + strncpy(lnRefCopy, logicalNodeReference, 129); + lnRefCopy[129] = 0; + + char* ldSep = strchr(lnRefCopy, '/'); + + if (ldSep == NULL) { + *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; + return NULL; + } + + *ldSep = 0; + + char* logicalDeviceName = lnRefCopy; + + char* logicalNodeName = ldSep + 1; + + /* search for logical device */ + + LinkedList device = LinkedList_getNext(self->logicalDevices); + + bool deviceFound = false; + + ICLogicalDevice* ld; + + while (device != NULL) { + ld = (ICLogicalDevice*) device->data; + + if (strcmp(logicalDeviceName, ld->name) == 0) { + deviceFound = true; + break; + } + + device = LinkedList_getNext(device); + } + + if (!deviceFound) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + LinkedList lnDirectory = LinkedList_create(); + + switch (acsiClass) { + + case ACSI_CLASS_DATA_OBJECT: + { + LinkedList variable = LinkedList_getNext(ld->variables); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + char* fcPos = strchr(variableName, '$'); + + if (fcPos != NULL) { + if (memcmp(fcPos + 1, "RP", 2) == 0) + goto next_element; + + if (memcmp(fcPos + 1, "BR", 2) == 0) + goto next_element; + + if (memcmp(fcPos + 1, "GO", 2) == 0) + goto next_element; + + int lnNameLen = fcPos - variableName; + + if (strncmp(variableName, logicalNodeName, lnNameLen) == 0) { + char* fcEndPos = strchr(fcPos + 1, '$'); + + if (fcEndPos != NULL) { + char* nameEndPos = strchr(fcEndPos + 1, '$'); + + if (nameEndPos == NULL) { + char* dataObjectName = copyString(fcEndPos + 1); + + if (!addToStringSet(lnDirectory, dataObjectName)) + GLOBAL_FREEMEM(dataObjectName); + } + } + } + } + + next_element: + + variable = LinkedList_getNext(variable); + } + } + break; + + case ACSI_CLASS_SGCB: + { + LinkedList variable = LinkedList_getNext(ld->variables); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + if (strcmp(variableName, "LLN0$SP$SGCB") == 0) + LinkedList_add(lnDirectory, (void*) copyString("SGCB")); + + variable = LinkedList_getNext(variable); + } + } + break; + + case ACSI_CLASS_BRCB: + addVariablesWithFc("BR", logicalNodeName, ld->variables, lnDirectory); + break; + + case ACSI_CLASS_URCB: + addVariablesWithFc("RP", logicalNodeName, ld->variables, lnDirectory); + break; + + case ACSI_CLASS_GoCB: + addVariablesWithFc("GO", logicalNodeName, ld->variables, lnDirectory); + break; + + case ACSI_CLASS_DATA_SET: + { + LinkedList dataSet = LinkedList_getNext(ld->dataSets); + + while (dataSet != NULL) { + char* dataSetName = (char*) dataSet->data; + + char* fcPos = strchr(dataSetName, '$'); + + if (fcPos == NULL) + goto next_data_set_element; + + size_t lnNameLen = fcPos - dataSetName; + + if (strlen(logicalNodeName) != lnNameLen) + goto next_data_set_element; + + if (memcmp(dataSetName, logicalNodeName, lnNameLen) != 0) + goto next_data_set_element; + + LinkedList_add(lnDirectory, copyString(fcPos + 1)); + + next_data_set_element: + + dataSet = LinkedList_getNext(dataSet); + } + } + break; + + default: + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: ACSI class not yet supported!\n"); + break; + } + + *error = IED_ERROR_OK; + return lnDirectory; +} + +LinkedList /**/ +IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, + const char* logicalNodeReference) +{ + *error = IED_ERROR_OK; + + if (strlen(logicalNodeReference) > 129) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + if (self->logicalDevices == NULL) + IedConnection_getDeviceModelFromServer(self, error); + + if (*error != IED_ERROR_OK) + return NULL; + + char lnRefCopy[130]; + + strncpy(lnRefCopy, logicalNodeReference, 129); + lnRefCopy[129] = 0; + + char* ldSep = strchr(lnRefCopy, '/'); + + if (ldSep == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + *ldSep = 0; + + char* logicalDeviceName = lnRefCopy; + + char* logicalNodeName = ldSep + 1; + + // search for logical device + + LinkedList device = LinkedList_getNext(self->logicalDevices); + + bool deviceFound = false; + + ICLogicalDevice* ld; + + while (device != NULL) { + ld = (ICLogicalDevice*) device->data; + + if (strcmp(logicalDeviceName, ld->name) == 0) { + deviceFound = true; + break; + } + + device = LinkedList_getNext(device); + } + + if (!deviceFound) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + if (DEBUG_IED_CLIENT) + printf("DEBUG_IED_CLIENT: Found LD %s search for variables of LN %s ...\n", logicalDeviceName, logicalNodeName); + + LinkedList variable = LinkedList_getNext(ld->variables); + + LinkedList lnDirectory = LinkedList_create(); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + char* fcPos = strchr(variableName, '$'); + + if (fcPos != NULL) { + int lnNameLen = fcPos - variableName; + + if (strncmp(variableName, logicalNodeName, lnNameLen) == 0) { + LinkedList_add(lnDirectory, copyString(fcPos + 1)); + } + } + + variable = LinkedList_getNext(variable); + } + + *error = IED_ERROR_OK; + return lnDirectory; +} + +static LinkedList +getDataDirectory(IedConnection self, IedClientError* error, + const char* dataReference, bool withFc) +{ + *error = IED_ERROR_OK; + + if (strlen(dataReference) > 129) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + if (self->logicalDevices == NULL) + IedConnection_getDeviceModelFromServer(self, error); + + if (*error != IED_ERROR_OK) + return NULL; + + char dataRefCopy[130]; + + strncpy(dataRefCopy, dataReference, 129); + dataRefCopy[129] = 0; + + char* ldSep = strchr(dataRefCopy, '/'); + + *ldSep = 0; + + char* logicalDeviceName = dataRefCopy; + + char* logicalNodeName = ldSep + 1; + + char* logicalNodeNameEnd = strchr(logicalNodeName, '.'); + + if (logicalNodeNameEnd == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + int logicalNodeNameLen = logicalNodeNameEnd - logicalNodeName; + + char* dataNamePart = logicalNodeNameEnd + 1; + + int dataNamePartLen = strlen(dataNamePart); + + if (dataNamePartLen < 1) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + StringUtils_replace(dataNamePart, '.', '$'); + + // search for logical device + + LinkedList device = LinkedList_getNext(self->logicalDevices); + + bool deviceFound = false; + + ICLogicalDevice* ld; + + while (device != NULL) { + ld = (ICLogicalDevice*) device->data; + + if (strcmp(logicalDeviceName, ld->name) == 0) { + deviceFound = true; + break; + } + + device = LinkedList_getNext(device); + } + + if (!deviceFound) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + LinkedList variable = LinkedList_getNext(ld->variables); + + LinkedList dataDirectory = LinkedList_create(); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + char* fcPos = strchr(variableName, '$'); + + if (fcPos != NULL) { + int lnNameLen = fcPos - variableName; + + if (logicalNodeNameLen == lnNameLen) { + + if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) { + + /* ok we are in the correct logical node */ + + /* skip FC */ + char* fcEnd = strchr(fcPos + 1, '$'); + + if (fcEnd == NULL) + goto next_variable; + + char* remainingPart = fcEnd + 1; + + int remainingLen = strlen(remainingPart); + + if (remainingLen <= dataNamePartLen) + goto next_variable; + + if (remainingPart[dataNamePartLen] == '$') { + + if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) { + + char* subElementName = remainingPart + dataNamePartLen + 1; + + char* subElementNameSep = strchr(subElementName, '$'); + + if (subElementNameSep != NULL) + goto next_variable; + + char* elementName; + + if (withFc) { + int elementNameLen = strlen(subElementName); + + elementName = (char*) GLOBAL_MALLOC(elementNameLen + 5); + memcpy(elementName, subElementName, elementNameLen); + elementName[elementNameLen] = '['; + elementName[elementNameLen + 1] = *(fcPos + 1); + elementName[elementNameLen + 2] = *(fcPos + 2); + elementName[elementNameLen + 3] = ']'; + elementName[elementNameLen + 4] = 0; + } + else + elementName = copyString(subElementName); + + if (!addToStringSet(dataDirectory, elementName)) + GLOBAL_FREEMEM(elementName); + } + } + } + } + } + + next_variable: + + variable = LinkedList_getNext(variable); + } + + *error = IED_ERROR_OK; + return dataDirectory; + +} + +LinkedList +IedConnection_getDataDirectory(IedConnection self, IedClientError* error, const char* dataReference) +{ + return getDataDirectory(self, error, dataReference, false); +} + +LinkedList +IedConnection_getDataDirectoryFC(IedConnection self, IedClientError* error, const char* dataReference) +{ + return getDataDirectory(self, error, dataReference, true); +} + +static LinkedList +getDataDirectoryByFc(IedConnection self, IedClientError* error, + const char* dataReference, FunctionalConstraint fc) +{ + *error = IED_ERROR_OK; + + if (strlen(dataReference) > 129) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + char* fcString = FunctionalConstraint_toString(fc); + + if (fcString == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + if (self->logicalDevices == NULL) + IedConnection_getDeviceModelFromServer(self, error); + + if (*error != IED_ERROR_OK) + return NULL; + + char dataRefCopy[130]; + + strncpy(dataRefCopy, dataReference, 129); + dataRefCopy[129] = 0; + + char* ldSep = strchr(dataRefCopy, '/'); + + *ldSep = 0; + + char* logicalDeviceName = dataRefCopy; + + char* logicalNodeName = ldSep + 1; + + char* logicalNodeNameEnd = strchr(logicalNodeName, '.'); + + if (logicalNodeNameEnd == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + int logicalNodeNameLen = logicalNodeNameEnd - logicalNodeName; + + char* dataNamePart = logicalNodeNameEnd + 1; + + int dataNamePartLen = strlen(dataNamePart); + + if (dataNamePartLen < 1) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + StringUtils_replace(dataNamePart, '.', '$'); + + // search for logical device + + LinkedList device = LinkedList_getNext(self->logicalDevices); + + bool deviceFound = false; + + ICLogicalDevice* ld; + + while (device != NULL) { + ld = (ICLogicalDevice*) device->data; + + if (strcmp(logicalDeviceName, ld->name) == 0) { + deviceFound = true; + break; + } + + device = LinkedList_getNext(device); + } + + if (!deviceFound) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } + + LinkedList variable = LinkedList_getNext(ld->variables); + + LinkedList dataDirectory = LinkedList_create(); + + while (variable != NULL) { + char* variableName = (char*) variable->data; + + char* fcPos = strchr(variableName, '$'); + + if (fcPos != NULL) { + int lnNameLen = fcPos - variableName; + + if (logicalNodeNameLen == lnNameLen) { + + if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) { + + /* ok we are in the correct logical node */ + + /* skip FC */ + char* fcEnd = strchr(fcPos + 1, '$'); + + if (fcEnd == NULL) + goto next_variable; + + if ((fcPos[1] != fcString[0]) || (fcPos[2] != fcString[1])) + goto next_variable; + + char* remainingPart = fcEnd + 1; + + int remainingLen = strlen(remainingPart); + + if (remainingLen <= dataNamePartLen) + goto next_variable; + + if (remainingPart[dataNamePartLen] == '$') { + + if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) { + + char* subElementName = remainingPart + dataNamePartLen + 1; + + char* subElementNameSep = strchr(subElementName, '$'); + + if (subElementNameSep != NULL) + goto next_variable; + + int elementNameLen = strlen(subElementName); + + char* elementName = (char*) GLOBAL_MALLOC(elementNameLen + 5); + memcpy(elementName, subElementName, elementNameLen); + elementName[elementNameLen] = '['; + elementName[elementNameLen + 1] = *(fcPos + 1); + elementName[elementNameLen + 2] = *(fcPos + 2); + elementName[elementNameLen + 3] = ']'; + elementName[elementNameLen + 4] = 0; + + if (!addToStringSet(dataDirectory, elementName)) + GLOBAL_FREEMEM(elementName); + } + } + } + } + } + + next_variable: + + variable = LinkedList_getNext(variable); + } + + *error = IED_ERROR_OK; + return dataDirectory; + +} + + +LinkedList +IedConnection_getDataDirectoryByFC(IedConnection self, IedClientError* error, const char* dataReference, FunctionalConstraint fc) +{ + return getDataDirectoryByFc(self, error, dataReference, fc); +} + +void +IedConnection_createDataSet(IedConnection self, IedClientError* error, const char* dataSetReference, + LinkedList /* */dataSetElements) +{ + + char domainIdBuffer[65]; + char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1]; + + const char* domainId; + const char* itemId; + bool isAssociationSpecific = false; + + if (dataSetReference[0] != '@') { + domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); + + if (domainId == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + int domainIdLength = strlen(domainId); + + if ((strlen(dataSetReference) - domainIdLength - 1) > 32) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + char* itemIdRef = copyStringToBuffer(dataSetReference + domainIdLength + 1, itemIdBuffer); + StringUtils_replace(itemIdRef, '.', '$'); + itemId = itemIdRef; + } + else { + itemId = dataSetReference + 1; + isAssociationSpecific = true; + } + + MmsError mmsError; + + LinkedList dataSetEntries = LinkedList_create(); + + LinkedList dataSetElement = LinkedList_getNext(dataSetElements); + + while (dataSetElement != NULL) { + + MmsVariableAccessSpecification* dataSetEntry = + MmsMapping_ObjectReferenceToVariableAccessSpec((char*) dataSetElement->data); + + if (dataSetEntry == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto cleanup_list; + } + + LinkedList_add(dataSetEntries, (void*) dataSetEntry); + + dataSetElement = LinkedList_getNext(dataSetElement); + } + + if (isAssociationSpecific) + MmsConnection_defineNamedVariableListAssociationSpecific(self->connection, &mmsError, + itemId, dataSetEntries); + else + MmsConnection_defineNamedVariableList(self->connection, &mmsError, + domainId, itemId, dataSetEntries); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + +cleanup_list: + /* delete list and all elements */ + LinkedList_destroyDeep(dataSetEntries, (LinkedListValueDeleteFunction) MmsVariableAccessSpecification_destroy); + +exit_function: + return; +} + +void +IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const char* dataSetReference) +{ + char domainId[65]; + char itemId[DATA_SET_MAX_NAME_LENGTH + 1]; + bool isAssociationSpecific = false; + + int dataSetReferenceLength = strlen(dataSetReference); + + if (dataSetReference[0] != '@') { + if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainId) == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + const char* itemIdString = dataSetReference + strlen(domainId) + 1; + + if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + copyStringToBuffer(itemIdString, itemId); + + StringUtils_replace(itemId, '.', '$'); + } + else { + if (dataSetReferenceLength > 33) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + strcpy(itemId, dataSetReference + 1); + + isAssociationSpecific = true; + } + + MmsError mmsError; + + if (isAssociationSpecific) + MmsConnection_deleteAssociationSpecificNamedVariableList(self->connection, &mmsError, itemId); + else + MmsConnection_deleteNamedVariableList(self->connection, &mmsError, domainId, itemId); + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + +exit_function: + return; +} + +LinkedList /* */ +IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, const char* dataSetReference, bool* isDeletable) +{ + bool deletable = false; + + LinkedList dataSetMembers = NULL; + + char domainIdBuffer[65]; + char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1]; + + const char* domainId = NULL; + const char* itemId = NULL; + + bool isAssociationSpecific = false; + + if (dataSetReference[0] != '@') { + domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); + + if (domainId == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + const char* itemIdRef = dataSetReference + strlen(domainId) + 1; + + if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + char* itemIdRefInBuffer = copyStringToBuffer(itemIdRef, itemIdBuffer); + StringUtils_replace(itemIdRefInBuffer, '.', '$'); + itemId = itemIdRefInBuffer; + } + else { + itemId = dataSetReference + 1; + isAssociationSpecific = true; + } + + MmsError mmsError; + + LinkedList entries; + + if (isAssociationSpecific) + entries = MmsConnection_readNamedVariableListDirectoryAssociationSpecific(self->connection, + &mmsError, itemId, &deletable); + else + entries = MmsConnection_readNamedVariableListDirectory(self->connection, + &mmsError, domainId, itemId, &deletable); + + if (mmsError == MMS_ERROR_NONE) { + + LinkedList entry = LinkedList_getNext(entries); + + dataSetMembers = LinkedList_create(); + + while (entry != NULL) { + MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*) entry->data; + + char* objectReference = MmsMapping_varAccessSpecToObjectReference(varAccessSpec); + + LinkedList_add(dataSetMembers, objectReference); + + entry = LinkedList_getNext(entry); + } + + if (isDeletable != NULL) + *isDeletable = deletable; + + LinkedList_destroyDeep(entries, (LinkedListValueDeleteFunction) MmsVariableAccessSpecification_destroy); + } + + *error = iedConnection_mapMmsErrorToIedError(mmsError); + +exit_function: + return dataSetMembers; +} + +ClientDataSet +IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference, + ClientDataSet dataSet) +{ + char domainIdBuffer[65]; + char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1]; + + const char* domainId = NULL; + const char* itemId = NULL; + + bool isAssociationSpecific = false; + + if (dataSetReference[0] != '@') { + domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); + + if (domainId == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; + + if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + char* itemIdRef = copyStringToBuffer(itemIdRefOrig, itemIdBuffer); + + StringUtils_replace(itemIdRef, '.', '$'); + itemId = itemIdRef; + } + else { + itemId = dataSetReference + 1; + isAssociationSpecific = true; + } + + MmsError mmsError; + + MmsValue* dataSetVal; + + if (isAssociationSpecific) + dataSetVal = MmsConnection_readNamedVariableListValuesAssociationSpecific(self->connection, + &mmsError, itemId, true); + else + dataSetVal= MmsConnection_readNamedVariableListValues(self->connection, &mmsError, + domainId, itemId, true); + + if (dataSetVal == NULL) { + *error = iedConnection_mapMmsErrorToIedError(mmsError); + goto exit_function; + } + else + *error = IED_ERROR_OK; + + if (dataSet == NULL) { + dataSet = ClientDataSet_create(dataSetReference); + ClientDataSet_setDataSetValues(dataSet, dataSetVal); + } + else { + MmsValue* dataSetValues = ClientDataSet_getValues(dataSet); + MmsValue_update(dataSetValues, dataSetVal); + MmsValue_delete(dataSetVal); + } + +exit_function: + return dataSet; +} + + +MmsConnection +IedConnection_getMmsConnection(IedConnection self) +{ + return self->connection; +} + +LastApplError +IedConnection_getLastApplError(IedConnection self) +{ + return self->lastApplError; +} + +void +private_IedConnection_addControlClient(IedConnection self, ControlObjectClient control) +{ + LinkedList_add(self->clientControls, control); +} + +void +private_IedConnection_removeControlClient(IedConnection self, ControlObjectClient control) +{ + LinkedList_remove(self->clientControls, control); +} + +FileDirectoryEntry +FileDirectoryEntry_create(const char* fileName, uint32_t fileSize, uint64_t lastModified) +{ + FileDirectoryEntry self = (FileDirectoryEntry) GLOBAL_CALLOC(1, sizeof(struct sFileDirectoryEntry)); + + self->fileName = copyString(fileName); + self->fileSize = fileSize; + self->lastModified = lastModified; + + return self; +} + +void +FileDirectoryEntry_destroy(FileDirectoryEntry self) +{ + GLOBAL_FREEMEM(self->fileName); + GLOBAL_FREEMEM(self); +} + +char* +FileDirectoryEntry_getFileName(FileDirectoryEntry self) +{ + return self->fileName; +} + +uint32_t +FileDirectoryEntry_getFileSize(FileDirectoryEntry self) +{ + return self->fileSize; +} + +uint64_t +FileDirectoryEntry_getLastModified(FileDirectoryEntry self) +{ + return self->lastModified; +} + diff --git a/src/iec61850/common/iec61850_common.c b/src/iec61850/common/iec61850_common.c new file mode 100644 index 0000000..53f8194 --- /dev/null +++ b/src/iec61850/common/iec61850_common.c @@ -0,0 +1,357 @@ +/* + * iec61850_common.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_common.h" + +#include "libiec61850_platform_includes.h" + +#include "conversions.h" + +Validity +Quality_getValidity(Quality* self) +{ + return (*self & 0x3); +} + +void +Quality_setValidity(Quality* self, Validity validity) +{ + *self = *self & (0xfffc); + *self = *self | validity; +} + +bool +Quality_isFlagSet(Quality* self, int flag) +{ + if ((*self & flag) > 0) + return true; + else + return false; +} + +void +Quality_setFlag(Quality* self, int flag) +{ + *self = *self | flag; +} + +void +Quality_unsetFlag(Quality* self, int flag) +{ + *self = *self & (~flag); +} + + +Quality +Quality_fromMmsValue(const MmsValue* mmsValue) +{ + return (Quality) MmsValue_getBitStringAsInteger(mmsValue); +} + +Dbpos +Dbpos_fromMmsValue(const MmsValue* mmsValue) +{ + return (Dbpos) MmsValue_getBitStringAsIntegerBigEndian(mmsValue); +} + +MmsValue* +Dbpos_toMmsValue(MmsValue* mmsValue, Dbpos dbpos) +{ + if (mmsValue == NULL) { + mmsValue = MmsValue_newBitString(2); + } + else { + if (MmsValue_getType(mmsValue) != MMS_BIT_STRING) + return NULL; + + if (MmsValue_getBitStringSize(mmsValue) != 2) + return NULL; + } + + assert((int) dbpos >= 0); + assert((int) dbpos < 4); + + MmsValue_setBitStringFromIntegerBigEndian(mmsValue, dbpos); + + return mmsValue; +} + +char* +FunctionalConstraint_toString(FunctionalConstraint fc) { + switch (fc) { + case IEC61850_FC_ST: + return "ST"; + case IEC61850_FC_MX: + return "MX"; + case IEC61850_FC_SP: + return "SP"; + case IEC61850_FC_SV: + return "SV"; + case IEC61850_FC_CF: + return "CF"; + case IEC61850_FC_DC: + return "DC"; + case IEC61850_FC_SG: + return "SG"; + case IEC61850_FC_SE: + return "SE"; + case IEC61850_FC_SR: + return "SR"; + case IEC61850_FC_OR: + return "OR"; + case IEC61850_FC_BL: + return "BL"; + case IEC61850_FC_EX: + return "EX"; + case IEC61850_FC_CO: + return "CO"; + default: + return NULL; + } +} + +FunctionalConstraint +FunctionalConstraint_fromString(const char* fcString) +{ + if (fcString[0] == 'S') { + if (fcString[1] == 'T') + return IEC61850_FC_ST; + if (fcString[1] == 'P') + return IEC61850_FC_SP; + if (fcString[1] == 'V') + return IEC61850_FC_SV; + if (fcString[1] == 'G') + return IEC61850_FC_SG; + if (fcString[1] == 'E') + return IEC61850_FC_SE; + if (fcString[1] == 'R') + return IEC61850_FC_SR; + + return IEC61850_FC_NONE; + } + + if (fcString[0] == 'M') { + if (fcString[1] == 'X') + return IEC61850_FC_MX; + return IEC61850_FC_NONE; + } + + if (fcString[0] == 'C') { + if (fcString[1] == 'F') + return IEC61850_FC_CF; + if (fcString[1] == 'O') + return IEC61850_FC_CO; + return IEC61850_FC_NONE; + } + + if (fcString[0] == 'D') { + if (fcString[1] == 'C') + return IEC61850_FC_DC; + return IEC61850_FC_NONE; + } + + if (fcString[0] == 'O') { + if (fcString[1] == 'R') + return IEC61850_FC_OR; + return IEC61850_FC_NONE; + } + + if (fcString[0] == 'B') { + if (fcString[1] == 'L') + return IEC61850_FC_BL; + return IEC61850_FC_NONE; + } + + if (fcString[0] == 'E') { + if (fcString[1] == 'X') + return IEC61850_FC_EX; + return IEC61850_FC_NONE; + } + + return IEC61850_FC_NONE; +} + +void +Timestamp_clearFlags(Timestamp* self) +{ + self->val[7] = 0; +} + +bool +Timestamp_isLeapSecondKnown(Timestamp* self) +{ + if (self->val[7] & 0x80) + return true; + else + return false; +} + +void +Timestamp_setLeapSecondKnown(Timestamp* self, bool value) +{ + if (value) + self->val[7] |= 0x80; + else + self->val[7] &= 0x7f; +} + +bool +Timestamp_hasClockFailure(Timestamp* self) +{ + if (self->val[7] & 0x40) + return true; + else + return false; +} + +void +Timestamp_setClockFailure(Timestamp* self, bool value) +{ + if (value) + self->val[7] |= 0x40; + else + self->val[7] &= 0xbf; +} + +bool +Timestamp_isClockNotSynchronized(Timestamp* self) +{ + if (self->val[7] & 0x20) + return true; + else + return false; +} + +void +Timestamp_setClockNotSynchronized(Timestamp* self, bool value) +{ + if (value) + self->val[7] |= 0x20; + else + self->val[7] &= 0xdf; +} + +int +Timestamp_getSubsecondPrecision(Timestamp* self) +{ + return (int) (self->val[7] & 0x1f); +} + +void +Timestamp_setSubsecondPrecision(Timestamp* self, int subsecondPrecision) +{ + uint8_t ssp = subsecondPrecision & 0x1f; + + self->val[7] &= 0xe0; + self->val[7] += ssp; +} + +void +Timestamp_setTimeInSeconds(Timestamp* self, uint32_t secondsSinceEpoch) +{ + uint8_t* timeArray = (uint8_t*) &secondsSinceEpoch; + uint8_t* valueArray = self->val; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(valueArray, timeArray, 4); +#else + memcpy(valueArray, timeArray, 4); +#endif + + self->val[4] = 0; + self->val[5] = 0; + self->val[6] = 0; + + /* don't touch time quality */ +} + +void +Timestamp_setTimeInMilliseconds(Timestamp* self, uint64_t millisSinceEpoch) +{ + uint32_t timeval32 = (millisSinceEpoch / 1000LL); + + uint8_t* timeArray = (uint8_t*) &timeval32; + uint8_t* valueArray = self->val; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(valueArray, timeArray, 4); +#else + memcpy(valueArray, timeArray, 4); +#endif + + uint32_t remainder = (millisSinceEpoch % 1000LL); + uint32_t fractionOfSecond = (remainder) * 16777 + ((remainder * 216) / 1000); + + /* encode fraction of second */ + valueArray[4] = ((fractionOfSecond >> 16) & 0xff); + valueArray[5] = ((fractionOfSecond >> 8) & 0xff); + valueArray[6] = (fractionOfSecond & 0xff); + + /* don't touch time quality */ +} + +uint32_t +Timestamp_getTimeInSeconds(Timestamp* self) +{ + uint32_t timeval32; + uint8_t* valueArray = self->val; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder((uint8_t*) &timeval32, valueArray, 4); +#else + memcpy((uint8_t*) &timeval32, valueArray, 4); +#endif + + return timeval32; +} + +uint64_t +Timestamp_getTimeInMs(Timestamp* self) +{ + uint32_t timeval32; + uint8_t* valueArray = self->val; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder((uint8_t*) &timeval32, valueArray, 4); +#else + memcpy((uint8_t*) &timeval32, valueArray, 4); +#endif + + uint32_t fractionOfSecond = 0; + + fractionOfSecond = (valueArray[4] << 16); + fractionOfSecond += (valueArray[5] << 8); + fractionOfSecond += (valueArray[6]); + + uint32_t remainder = fractionOfSecond / 16777; + + uint64_t msVal = (timeval32 * 1000LL) + remainder; + + return (uint64_t) msVal; +} + +char* +LibIEC61850_getVersionString() +{ + return LIBIEC61850_VERSION; +} diff --git a/src/iec61850/inc/iec61850_cdc.h b/src/iec61850/inc/iec61850_cdc.h new file mode 100644 index 0000000..6144bea --- /dev/null +++ b/src/iec61850/inc/iec61850_cdc.h @@ -0,0 +1,540 @@ +/* + * cdc.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef CDC_H_ +#define CDC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \addtogroup server_api_group + * @{ + */ + +/** + * @defgroup COMMON_DATA_CLASSES Helper functions to create common data classes (CDC) using the dynamic model API + * + * Currently supports CDCs from IEC 61850-7-3:2010 (Edition 2) + * + * @{ + */ + +/** + * \brief optional parts of CDCs + */ +#define CDC_OPTION_PICS_SUBST (1 << 0) +#define CDC_OPTION_BLK_ENA (1 << 1) +#define CDC_OPTION_DESC (1 << 2) +#define CDC_OPTION_DESC_UNICODE (1 << 3) + +#define CDC_OPTION_AC_DLNDA (1 << 4) +#define CDC_OPTION_AC_DLN (1 << 5) + +#define CDC_OPTION_UNIT (1 << 6) + +#define CDC_OPTION_FROZEN_VALUE (1 << 7) + +#define CDC_OPTION_ADDR (1 << 8) +#define CDC_OPTION_ADDINFO (1 << 9) + +#define CDC_OPTION_INST_MAG (1 << 10) +#define CDC_OPTION_RANGE (1 << 11) + +#define CDC_OPTION_UNIT_MULTIPLIER (1 << 12) + +#define CDC_OPTION_AC_SCAV (1 << 13) + +#define CDC_OPTION_MIN (1 << 14) +#define CDC_OPTION_MAX (1 << 15) + +#define CDC_OPTION_AC_CLC_O (1 << 16) + +#define CDC_OPTION_RANGE_ANG (1 << 17) + +#define CDC_OPTION_PHASE_A (1 << 18) +#define CDC_OPTION_PHASE_B (1 << 19) +#define CDC_OPTION_PHASE_C (1 << 20) + +#define CDC_OPTION_PHASE_NEUT (1 << 21) + +#define CDC_OPTION_PHASES_ABC (CDC_OPTION_PHASE_A | CDC_OPTION_PHASE_B | CDC_OPTION_PHASE_C) + +#define CDC_OPTION_PHASES_ALL (CDC_OPTION_PHASE_A | CDC_OPTION_PHASE_B | CDC_OPTION_PHASE_C | CDC_OPTION_PHASE_NEUT) + +#define CDC_OPTION_STEP_SIZE (1 << 22) + +#define CDC_OPTION_ANGLE_REF (1 << 23) + + +/** + * \brief Control model types + */ +#define CDC_CTL_MODEL_NONE 0 +#define CDC_CTL_MODEL_DIRECT_NORMAL 1 +#define CDC_CTL_MODEL_SBO_NORMAL 2 +#define CDC_CTL_MODEL_DIRECT_ENHANCED 3 +#define CDC_CTL_MODEL_SBO_ENHANCED 4 + +#define CDC_CTL_MODEL_HAS_CANCEL (1 << 4) +#define CDC_CTL_MODEL_IS_TIME_ACTIVATED (1 << 5) + +#define CDC_CTL_OPTION_ORIGIN (1 << 6) +#define CDC_CTL_OPTION_CTL_NUM (1 << 7) +#define CDC_CTL_OPTION_ST_SELD (1 << 8) +#define CDC_CTL_OPTION_OP_RCVD (1 << 9) +#define CDC_CTL_OPTION_OP_OK (1 << 10) +#define CDC_CTL_OPTION_T_OP_OK (1 << 11) +#define CDC_CTL_OPTION_SBO_TIMEOUT (1 << 12) +#define CDC_CTL_OPTION_SBO_CLASS (1 << 13) +#define CDC_CTL_OPTION_OPER_TIMEOUT (1 << 14) + +/**************************************************** + * Constructed Attribute Classes (CAC) + ***************************************************/ + +DataAttribute* +CAC_AnalogueValue_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, + bool isIntegerNotFloat); + + +/** + * \brief create a ValWithTrans constructed data attribute + * + * \param hasTransInd + */ +DataAttribute* +CAC_ValWithTrans_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasTransientIndicator); + + +/** + * CDC_OPTION_AC_CLC_O + */ +DataAttribute* +CAC_Vector_create(const char* name, ModelNode* parent, uint32_t options, FunctionalConstraint fc, uint8_t triggerOptions); + +DataAttribute* +CAC_Point_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasZVal); + +DataAttribute* +CAC_ScaledValueConfig_create(const char* name, ModelNode* parent); + +DataAttribute* +CAC_Unit_create(const char* name, ModelNode* parent, bool hasMagnitude); + +DataAttribute* +CDA_OperBoolean(ModelNode* parent, bool isTImeActivated); + +/**************************************************** + * Common Data Classes (CDC) + ***************************************************/ + +DataObject* +CDC_SPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +DataObject* +CDC_DPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +DataObject* +CDC_INS_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +DataObject* +CDC_ENS_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +DataObject* +CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + + + +/** + * \brief create a new SEC (Security violation) CDC instance (data object) + * + * Allowed parent types are LogicalNode and DataObject. + * + * options: + * standard (include standard optional elements like extension namespaces and descriptions (d, dU). + * + * CDC_OPTION_ADDR (address of the client causing the security violation) + * CDC_OPTION_ADDINFO (additional info text) + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + */ +DataObject* +CDC_SEC_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief create a new MV (Measured value) CDC instance (data object) + * + * Allowed parent types are LogicalNode and DataObject. + * + * possible options: + * CDC_OPTION_INST_MAG + * CDC_OPTION_RANGE + * CDC_OPTION_PICS_SUBST + * standard (include standard optional elements like extension namespaces and descriptions (d, dU). + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param isIntegerNotFloat if true the AnalogueValue instance have integer instead of float + * + */ +DataObject* +CDC_MV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat); + +/** + * CDC_OPTION_INST_MAG + * CDC_OPTION_RANGE + */ +DataObject* +CDC_CMV_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief create a new SAV (Sampled analog value) CDC instance (data object) + * + * Allowed parent types are LogicalNode and DataObject. + * + * possible options: + * CDC_OPTION_UNIT + * CDC_OPTION_AC_SCAV + * CDC_OPTION_MIN + * CDC_OPTION_MAX + * standard (include standard optional elements like extension namespaces and descriptions (d, dU). + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param isIntegerNotFloat if true the AnalogueValue instance have integer instead of float + * + */ +DataObject* +CDC_SAV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat); + + +DataObject* +CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +DataObject* +CDC_HST_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint16_t maxPts); + +/** + * \brief Directional protection activation information (ACD) + * + * Allowed parent types are LogicalNode and DataObject. + * + * possible options: + * CDC_OPTION_PHASE_A + * CDC_OPTION_PHASE_B + * CDC_OPTION_PHASE_C + * CDC_OPTION_PHASE_NEUT + * CDC_OPTION_PHASES_ABC + * CDC_OPTION_PHASES_ALL + * standard (include standard optional elements like extension namespaces and descriptions (d, dU). + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + */ +DataObject* +CDC_ACD_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief Protection activation information (ACT) + */ +DataObject* +CDC_ACT_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief Single point setting (SPG) + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + */ +DataObject* +CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief Enumerated status setting (ENG) + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + */ +DataObject* +CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief Integer status setting (ING) + * + * possible options: + * CDC_OPTION_UNIT + * CDC_OPTION_MIN + * CDC_OPTION_MAX + * CDC_OPTION_STEP_SIZE + * standard (include standard optional elements like extension namespaces and descriptions (d, dU). + * + */ +DataObject* +CDC_ING_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief Analogue Setting (ASG) + * + * possible options: + * CDC_OPTION_UNIT + * CDC_OPTION_MIN + * CDC_OPTION_MAX + * CDC_OPTION_STEP_SIZE + * standard (include standard optional elements like extension namespaces and descriptions (d, dU). + * + */ +DataObject* +CDC_ASG_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat); + +/** + * \brief Phase to ground/neutral related measured values of a three-phase system (WYE) + * + * possible options: + * CDC_OPTION_ANGLE_REF + */ +DataObject* +CDC_WYE_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/** + * \brief Phase to phase related measured values of a three-phase system (DEL) + * + * possible options: + * CDC_OPTION_ANGLE_REF + */ +DataObject* +CDC_DEL_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + +/*************************** + * Controls + ***************************/ + +/** + * \brief Controllable single point (SPC) + * + * \param controlOptions specify which control model to set as default and other control related options + */ +DataObject* +CDC_SPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions); + +/** + * \brief Controllable double point (DPC) + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param defaultControlModel specify which control model to set as default. + * + */ +DataObject* +CDC_DPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions); + +/** + * \brief Controllable integer status (INC) + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * CDC_OPTION_MIN + * CDC_OPTION_MAX + * CDC_OPTION_STEP_SIZE + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param defaultControlModel specify which control model to set as default. + * + */ +DataObject* +CDC_INC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions); + +/** + * \brief Controllable enumerated status (ENC) + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param defaultControlModel specify which control model to set as default. + * + */ +DataObject* +CDC_ENC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions); + +/** + * \brief Controllable enumerated status (ENC) + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param controlOptions specify which control model to set as default and other control specific options + * \param hasTransientIndicator specifies if the step position information contains the transient indicator + * + */ +DataObject* +CDC_BSC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool hasTransientIndicator); + +/** + * \brief Controllable analogue process value (APC) + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * \param controlOptions specify which control model to set as default and other control specific options + * \param isIntegerNotFloat + */ +DataObject* +CDC_APC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool isIntegerNotFloat); + +/** Minimum measured value */ +#define CDC_OPTION_61400_MIN_MX_VAL (1 << 10) + +/** Maximum measured value */ +#define CDC_OPTION_61400_MAX_MX_VAL (1 << 11) + +/** Total average value of data */ +#define CDC_OPTION_61400_TOT_AV_VAL (1 << 12) + +/** Standard deviation of data */ +#define CDC_OPTION_61400_SDV_VAL (1 << 13) + +/** Rate of increase */ +#define CDC_OPTION_61400_INC_RATE (1 << 14) + +/** Rate of decrease */ +#define CDC_OPTION_61400_DEC_RATE (1 << 15) + +/** Setpoint or parameter access level (low/medium/high) */ +#define CDC_OPTION_61400_SP_ACS (1 << 16) + +/** Time periodical reset (hourly/daily/weekly/monthly) */ +#define CDC_OPTION_61400_CHA_PER_RS (1 << 17) + +/** Command access level */ +#define CDC_OPTION_61400_CM_ACS (1 << 18) + +/** Total time duration of a state */ +#define CDC_OPTION_61400_TM_TOT (1 << 19) + +/** Daily counting data */ +#define CDC_OPTION_61400_COUNTING_DAILY (1 << 20) + +/** Monthly counting data */ +#define CDC_OPTION_61400_COUNTING_MONTHLY (1 << 21) + +/** Yearly counting data */ +#define CDC_OPTION_61400_COUNTING_YEARLY (1 << 22) + +/** Total counting data */ +#define CDC_OPTION_61400_COUNTING_TOTAL (1 << 23) + +/** All counting data */ +#define CDC_OPTION_61400_COUNTING_ALL (CDC_OPTION_61400_COUNTING_DAILY | CDC_OPTION_61400_COUNTING_MONTHLY | CDC_OPTION_61400_COUNTING_YEARLY | CDC_OPTION_61400_COUNTING_TOTAL) + +DataObject* +CDC_SPV_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasChaManRs); + +DataObject* +CDC_STV_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasOldStatus); + +DataObject* +CDC_CMD_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasOldStatus, + bool hasCmTm, + bool hasCmCt); + +DataObject* +CDC_ALM_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasOldStatus); + +DataObject* +CDC_CTE_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasHisRs); + +DataObject* +CDC_TMS_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasHisRs); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* CDC_H_ */ diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h new file mode 100644 index 0000000..f0b86f8 --- /dev/null +++ b/src/iec61850/inc/iec61850_client.h @@ -0,0 +1,1688 @@ +/* + * iec61850_client.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef IEC61850_CLIENT_H_ +#define IEC61850_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libiec61850_common_api.h" +#include "iec61850_common.h" +#include "goose_subscriber.h" +#include "mms_value.h" +#include "mms_client_connection.h" +#include "linked_list.h" + +/** + * * \defgroup iec61850_client_api_group IEC 61850/MMS client API + */ +/**@{*/ + +/** an opaque handle to the instance data of a ClientDataSet object */ +typedef struct sClientDataSet* ClientDataSet; + +/** an opaque handle to the instance data of a ClientReport object */ +typedef struct sClientReport* ClientReport; + +/** an opaque handle to the instance data of a ClientReportControlBlock object */ +typedef struct sClientReportControlBlock* ClientReportControlBlock; + +/** an opaque handle to the instance data of a ClientGooseControlBlock object */ +typedef struct sClientGooseControlBlock* ClientGooseControlBlock; + +/** + * @defgroup IEC61850_CLIENT_GENERAL General client side connection handling functions and data types + * + * @{ + */ + +/** An opaque handle to the instance data of the IedConnection object */ +typedef struct sIedConnection* IedConnection; + +/** Detailed description of the last application error of the client connection instance */ +typedef struct +{ + int ctlNum; + int error; + ControlAddCause addCause; +} LastApplError; + +/** Connection state of the IedConnection instance (either idle, connected or closed) */ +typedef enum +{ + IED_STATE_IDLE, + IED_STATE_CONNECTED, + IED_STATE_CLOSED +} IedConnectionState; + +/** used to describe the error reason for most client side service functions */ +typedef enum { + /* general errors */ + + /** No error occurred - service request has been successful */ + IED_ERROR_OK = 0, + + /** The service request can not be executed because the client is not yet connected */ + IED_ERROR_NOT_CONNECTED = 1, + + /** Connect service not execute because the client is already connected */ + IED_ERROR_ALREADY_CONNECTED = 2, + + /** The service request can not be executed caused by a loss of connection */ + IED_ERROR_CONNECTION_LOST = 3, + + /** The service or some given parameters are not supported by the client stack or by the server */ + IED_ERROR_SERVICE_NOT_SUPPORTED = 4, + + /** Connection rejected by server */ + IED_ERROR_CONNECTION_REJECTED = 5, + + /* client side errors */ + + /** API function has been called with an invalid argument */ + IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT = 10, + + IED_ERROR_ENABLE_REPORT_FAILED_DATASET_MISMATCH = 11, + + /** The object provided object reference is invalid (there is a syntactical error). */ + IED_ERROR_OBJECT_REFERENCE_INVALID = 12, + + /** Received object is of unexpected type */ + IED_ERROR_UNEXPECTED_VALUE_RECEIVED = 13, + + /* service error - error reported by server */ + + /** The communication to the server failed with a timeout */ + IED_ERROR_TIMEOUT = 20, + + /** The server rejected the access to the requested object/service due to access control */ + IED_ERROR_ACCESS_DENIED = 21, + + /** The server reported that the requested object does not exist (returned by server) */ + IED_ERROR_OBJECT_DOES_NOT_EXIST = 22, + + /** The server reported that the requested object already exists */ + IED_ERROR_OBJECT_EXISTS = 23, + + /** The server does not support the requested access method (returned by server) */ + IED_ERROR_OBJECT_ACCESS_UNSUPPORTED = 24, + + /** The server expected an object of another type (returned by server) */ + IED_ERROR_TYPE_INCONSISTENT = 25, + + /** The object or service is temporarily unavailable (returned by server) */ + IED_ERROR_TEMPORARILY_UNAVAILABLE = 26, + + /** The specified object is not defined in the server (returned by server) */ + IED_ERROR_OBJECT_UNDEFINED = 27, + + /** The specified address is invalid (returned by server) */ + IED_ERROR_INVALID_ADDRESS = 28, + + /** Service failed due to a hardware fault (returned by server) */ + IED_ERROR_HARDWARE_FAULT = 29, + + /** The requested data type is not supported by the server (returned by server) */ + IED_ERROR_TYPE_UNSUPPORTED = 30, + + /** The provided attributes are inconsistent (returned by server) */ + IED_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT = 31, + + /** The provided object value is invalid (returned by server) */ + IED_ERROR_OBJECT_VALUE_INVALID = 32, + + /** The object is invalidated (returned by server) */ + IED_ERROR_OBJECT_INVALIDATED = 33, + + /* unknown error */ + IED_ERROR_UNKNOWN = 99 +} IedClientError; + +/************************************************** + * Connection creation and destruction + **************************************************/ + +/** + * \brief create a new IedConnection instance + * + * This function creates a new IedConnection instance that is used to handle a connection to an IED. + * It allocated all required resources. The new connection is in the "idle" state. Before it can be used + * the connect method has to be called. + * + * \return the new IedConnection instance + */ +IedConnection +IedConnection_create(void); + +/** + * \brief destroy an IedConnection instance. + * + * The connection will be closed if it is in "connected" state. All allocated resources of the connection + * will be freed. + * + * \param self the connection object + */ +void +IedConnection_destroy(IedConnection self); + + +/** + * \brief set the connect timeout in ms + * + * Set the connect timeout for this connection. This function has to be called before IedConnection_connect + * is called. + * + * \param self the connection object + * \param timoutInMs the connection timeout in ms + */ +void +IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs); + +/************************************************** + * Association service + **************************************************/ + +/** + * \brief Connect to a server + * + * \param self the connection object + * \param error the error code if an error occurs + * \param hostname the host name or IP address of the server to connect to + * \param tcpPort the TCP port number of the server to connect to + */ +void +IedConnection_connect(IedConnection self, IedClientError* error, const char* hostname, int tcpPort); + +/** + * \brief Abort the connection + * + * This will close the MMS association by sending an ACSE abort message to the server. + * After sending the abort message the connection is closed immediately. + * The client can assume the connection to be closed when the function returns and the + * destroy method can be called. If the connection is not in "connected" state an + * IED_ERROR_NOT_CONNECTED error will be reported. + * + * \param self the connection object + * \param error the error code if an error occurs + */ +void +IedConnection_abort(IedConnection self, IedClientError* error); + +/** + * \brief Release the connection + * + * This will release the MMS association by sending an MMS conclude message to the server. + * The client can NOT assume the connection to be closed when the function returns, It can + * also fail if the server returns with a negative response. To be sure that the connection + * will be close the close or abort methods should be used. If the connection is not in "connected" state an + * IED_ERROR_NOT_CONNECTED error will be reported. + * + * \param self the connection object + * \param error the error code if an error occurs + */ +void +IedConnection_release(IedConnection self, IedClientError* error); + +/** + * \brief Close the connection + * + * This will close the MMS association and the underlying TCP connection. + * + * \param self the connection object + */ +void +IedConnection_close(IedConnection self); + +/** + * \brief return the state of the connection. + * + * This function can be used to determine if the connection is established or closed. + * + * \param self the connection object + * + * \return the connection state + */ +IedConnectionState +IedConnection_getState(IedConnection self); + +/** + * \brief Access to last application error received by the client connection + * + * \param self the connection object + * + * \return the LastApplError value + */ +LastApplError +IedConnection_getLastApplError(IedConnection self); + + +typedef void (*IedConnectionClosedHandler) (void* parameter, IedConnection connection); + +/** + * \brief Install a handler function that will be called when the connection is lost. + * + * \param self the connection object + * \param handler that callback function + * \param parameter the user provided parameter that is handed over to the callback function + */ +void +IedConnection_installConnectionClosedHandler(IedConnection self, IedConnectionClosedHandler handler, + void* parameter); + +/** + * \brief get a handle to the underlying MmsConnection + * + * Get access to the underlying MmsConnection instance used by this IedConnection. + * This can be used to set/change specific MmsConnection parameters or to call low-level MMS services/functions. + * + * \param self the connection object + * + * \return the MmsConnection instance used by this IedConnection. + */ +MmsConnection +IedConnection_getMmsConnection(IedConnection self); + +/** @} */ + +/** + * @defgroup IEC61850_CLIENT_GOOSE Client side GOOSE control block handling functions + * + * @{ + */ + +/********************************************************* + * GOOSE services handling (MMS part) + ********************************************************/ + +/** Enable GOOSE publisher GoCB block element */ +#define GOCB_ELEMENT_GO_ENA 1 + +/** GOOSE ID GoCB block element */ +#define GOCB_ELEMENT_GO_ID 2 + +/** Data set GoCB block element */ +#define GOCB_ELEMENT_DATSET 4 + +/** Configuration revision GoCB block element (this is usually read-only) */ +#define GOCB_ELEMENT_CONF_REV 8 + +/** Need commission GoCB block element (read-only according to 61850-7-2) */ +#define GOCB_ELEMENT_NDS_COMM 16 + +/** Destination address GoCB block element (read-only according to 61850-7-2) */ +#define GOCB_ELEMENT_DST_ADDRESS 32 + +/** Minimum time GoCB block element (read-only according to 61850-7-2) */ +#define GOCB_ELEMENT_MIN_TIME 64 + +/** Maximum time GoCB block element (read-only according to 61850-7-2) */ +#define GOCB_ELEMENT_MAX_TIME 128 + +/** Fixed offsets GoCB block element (read-only according to 61850-7-2) */ +#define GOCB_ELEMENT_FIXED_OFFS 256 + +/** select all elements of the GoCB */ +#define GOCB_ELEMENT_ALL 511 + + +/************************************************** + * ClientGooseControlBlock class + **************************************************/ + +ClientGooseControlBlock +ClientGooseControlBlock_create(const char* dataAttributeReference); + +void +ClientGooseControlBlock_destroy(ClientGooseControlBlock self); + +bool +ClientGooseControlBlock_getGoEna(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setGoEna(ClientGooseControlBlock self, bool goEna); + +const char* +ClientGooseControlBlock_getGoID(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setGoID(ClientGooseControlBlock self, const char* goID); + +const char* +ClientGooseControlBlock_getDatSet(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setDatSet(ClientGooseControlBlock self, const char* datSet); + +uint32_t +ClientGooseControlBlock_getConfRev(ClientGooseControlBlock self); + +bool +ClientGooseControlBlock_getNdsComm(ClientGooseControlBlock self); + +uint32_t +ClientGooseControlBlock_getMinTime(ClientGooseControlBlock self); + +uint32_t +ClientGooseControlBlock_getMaxTime(ClientGooseControlBlock self); + +bool +ClientGooseControlBlock_getFixedOffs(ClientGooseControlBlock self); + +MmsValue* /* MMS_OCTET_STRING */ +ClientGooseControlBlock_getDstAddress_addr(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setDstAddress_addr(ClientGooseControlBlock self, MmsValue* macAddr); + +uint8_t +ClientGooseControlBlock_getDstAddress_priority(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setDstAddress_priority(ClientGooseControlBlock self, uint8_t priorityValue); + +uint16_t +ClientGooseControlBlock_getDstAddress_vid(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setDstAddress_vid(ClientGooseControlBlock self, uint16_t vidValue); + +uint16_t +ClientGooseControlBlock_getDstAddress_appid(ClientGooseControlBlock self); + +void +ClientGooseControlBlock_setDstAddress_appid(ClientGooseControlBlock self, uint16_t appidValue); + + +/********************************************************* + * GOOSE services (access to GOOSE Control Blocks (GoCB)) + ********************************************************/ + +/** + * \brief Read access to attributes of a GOOSE control block (GoCB) at the connected server. A GoCB contains + * the configuration values for a single GOOSE publisher. + * + * The requested GoCB has to be specified by its object IEC 61850 ACSI object reference. E.g. + * + * "simpleIOGernericIO/LLN0.gcbEvents" + * + * This function is used to perform the actual read service for the GoCB values. + * To access the received values the functions of ClientGooseControlBlock have to be used. + * + * If called with a NULL argument for the updateGoCB parameter a new ClientGooseControlBlock instance is created + * and populated with the values received by the server. It is up to the user to release this object by + * calling the ClientGooseControlBlock_destroy function when the object is no longer needed. If called with a reference + * to an existing ClientGooseControlBlock instance the values of the attributes will be updated and no new instance + * will be created. + * + * Note: This function maps to a single MMS read request to retrieve the complete GoCB at once. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param goCBReference IEC 61850-7-2 ACSI object reference of the GOOSE control block + * \param updateRcb a reference to an existing ClientGooseControlBlock instance or NULL + * + * \return new ClientGooseControlBlock instance or the instance provided by the user with + * the updateRcb parameter. + */ +ClientGooseControlBlock +IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const char* goCBReference, ClientGooseControlBlock updateGoCB); + +/** + * \brief Write access to attributes of a GOOSE control block (GoCB) at the connected server + * + * The GoCB and the values to be written are specified with the goCB parameter. + * + * The parametersMask parameter specifies which attributes of the remote GoCB have to be set by this request. + * You can specify multiple attributes by ORing the defined bit values. If all attributes have to be written + * GOCB_ELEMENT_ALL can be used. + * + * The singleRequest parameter specifies the mapping to the corresponding MMS write request. Standard compliant + * servers should accept both variants. But some server accept only one variant. Then the value of this parameter + * will be of relevance. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param goCB ClientGooseControlBlock instance that actually holds the parameter + * values to be written. + * \param parametersMask specifies the parameters contained in the setGoCBValues request. + * \param singleRequest specifies if the seGoCBValues services is mapped to a single MMS write request containing + * multiple variables or to multiple MMS write requests. + */ +void +IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGooseControlBlock goCB, + uint32_t parametersMask, bool singleRequest); + +/** @} */ + +/******************************************** + * Reporting services + ********************************************/ + +/** + * @defgroup IEC61850_CLIENT_REPORTS Client side report handling services, functions, and data types + * + * @{ + */ + +/** + * \brief Read access to attributes of a report control block (RCB) at the connected server + * + * The requested RCB has to be specified by its object reference. E.g. + * + * "simpleIOGernericIO/LLN0.RP.EventsRCB01" + * + * or + * + * "simpleIOGenericIO/LLN0.BR.EventsBRCB01" + * + * Report control blocks have either "RP" or "BR" as part of their name following the logical node part. + * "RP" is part of the name of unbuffered RCBs whilst "BR" is part of the name of buffered RCBs. + * + * This function is used to perform the actual read service. To access the received values the functions + * of ClientReportControlBlock have to be used. + * + * If called with a NULL argument for the updateRcb parameter a new ClientReportControlBlock instance is created + * and populated with the values received by the server. It is up to the user to release this object by + * calling the ClientReportControlBlock_destroy function when the object is no longer needed. If called with a reference + * to an existing ClientReportControlBlock instance the values of the attributes will be updated and no new instance + * will be created. + * + * Note: This function maps to a single MMS read request to retrieve the complete RCB at once. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param rcbReference object reference of the report control block + * \param updateRcb a reference to an existing ClientReportControlBlock instance or NULL + * + * \return new ClientReportControlBlock instance or the instance provided by the user with + * the updateRcb parameter. + */ +ClientReportControlBlock +IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char* rcbReference, + ClientReportControlBlock updateRcb); + +/** Describes the reason for the inclusion of the element in the report */ +typedef enum { + /** the element is not included in the received report */ + REASON_NOT_INCLUDED = 0, + + /** the element is included due to a change of the data value */ + REASON_DATA_CHANGE = 1, + + /** the element is included due to a change in the quality of data */ + REASON_QUALITY_CHANGE = 2, + + /** the element is included due to an update of the data value */ + REASON_DATA_UPDATE = 3, + + /** the element is included due to a periodic integrity report task */ + REASON_INTEGRITY = 4, + + /** the element is included due to a general interrogation by the client */ + REASON_GI = 5, + + /** the reason for inclusion is unknown */ + REASON_UNKNOWN = 6 +} ReasonForInclusion; + + +/* Element encoding mask values for ClientReportControlBlock */ + +/** include the report ID into the setRCB request */ +#define RCB_ELEMENT_RPT_ID 1 + +/** include the report enable element into the setRCB request */ +#define RCB_ELEMENT_RPT_ENA 2 + +/** include the reservation element into the setRCB request (only available in unbuffered RCBs!) */ +#define RCB_ELEMENT_RESV 4 + +/** include the data set element into the setRCB request */ +#define RCB_ELEMENT_DATSET 8 + +/** include the configuration revision element into the setRCB request */ +#define RCB_ELEMENT_CONF_REV 16 + +/** include the option fields element into the setRCB request */ +#define RCB_ELEMENT_OPT_FLDS 32 + +/** include the bufTm (event buffering time) element into the setRCB request */ +#define RCB_ELEMENT_BUF_TM 64 + +/** include the sequence number element into the setRCB request (should be used!) */ +#define RCB_ELEMENT_SQ_NUM 128 + +/** include the trigger options element into the setRCB request */ +#define RCB_ELEMENT_TRG_OPS 256 + +/** include the integrity period element into the setRCB request */ +#define RCB_ELEMENT_INTG_PD 512 + +/** include the GI (general interrogation) element into the setRCB request */ +#define RCB_ELEMENT_GI 1024 + +/** include the purge buffer element into the setRCB request (only available in buffered RCBs) */ +#define RCB_ELEMENT_PURGE_BUF 2048 + +/** include the entry ID element into the setRCB request (only available in buffered RCBs) */ +#define RCB_ELEMENT_ENTRY_ID 4096 + +/** include the time of entry element into the setRCB request (only available in buffered RCBs) */ +#define RCB_ELEMENT_TIME_OF_ENTRY 8192 + +/** include the reservation time element into the setRCB request (only available in buffered RCBs) */ +#define RCB_ELEMENT_RESV_TMS 16384 + +/** include the owner element into the setRCB request */ +#define RCB_ELEMENT_OWNER 32768 + +/** + * \brief Write access to attributes of a report control block (RCB) at the connected server + * + * The requested RCB has to be specified by its object reference (see also IedConnection_getRCBValues). + * The object reference for the referenced RCB is contained in the provided ClientReportControlBlock instance. + * + * The parametersMask parameter specifies which attributes of the remote RCB have to be set by this request. + * You can specify multiple attributes by ORing the defined bit values. + * + * The singleRequest parameter specifies the mapping to the corresponding MMS write request. Standard compliant + * servers should accept both variants. But some server accept only one variant. Then the value of this parameter + * will be of relevance. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param rcb object reference of the ClientReportControlBlock instance that actually holds the parameter + * values to be written. + * \param parametersMask specifies the parameters contained in the setRCBValues request. + * \param singleRequest specifies if the setRCBValues services is mapped to a single MMS write request containing + * multiple variables or to multiple MMS write requests. + */ +void +IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientReportControlBlock rcb, + uint32_t parametersMask, bool singleRequest); + +/** + * \brief Callback function for receiving reports + * + * \param parameter a user provided parameter that is handed to the callback function + * \param report a ClientReport instance that holds the informations contained in the received report + */ +typedef void (*ReportCallbackFunction) (void* parameter, ClientReport report); + +/** + * \brief Install a report handler function for the specified report control block (RCB) + * + * This function will replace a report handler set earlier for the specified RCB. The report handler + * will be called whenever a report for the specified RCB is received. + * Please note that this function should be called whenever the RCB data set is changed or updated. + * Otherwise the internal data structures storing the received data set values will not be updated + * correctly. + * + * When replacing a report handler you only have to call this function. There is no separate call to + * IedConnection_uninstallReportHandler() required. + * + * \param self the connection object + * \param rcbReference object reference of the report control block + * \param rptId a string that identifies the report. If the rptId is not available then the + * rcbReference is used to identify the report. + * \param handler user provided callback function to be invoked when a report is received. + * \param handlerParameter user provided parameter that will be passed to the callback function + */ +void +IedConnection_installReportHandler(IedConnection self, const char* rcbReference, const char* rptId, ReportCallbackFunction handler, + void* handlerParameter); + +/** + * \brief uninstall a report handler function for the specified report control block (RCB) + * + * \param self the connection object + * \param rcbReference object reference of the report control block + */ +void +IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReference); + +/** + * \brief Trigger a general interrogation (GI) report for the specified report control block (RCB) + * + * The RCB must have been enabled and GI set as trigger option before this command can be performed. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param rcbReference object reference of the report control block + */ +void +IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const char* rcbReference); + +/**************************************** + * Access to received reports + ****************************************/ + +/** + * \brief Get the name of the report data set + * + * NOTE: the returned string is only valid as long as the ClientReport instance exists! + * + * \param self the ClientReport instance + * \return report data set name as 0 terminated string + */ +const char* +ClientReport_getDataSetName(ClientReport self); + +/** + * \brief return the received data set values of the report + * + * \param self the ClientReport instance + * \return an MmsValue array instance containing the data set values + */ +MmsValue* +ClientReport_getDataSetValues(ClientReport self); + +/** + * \brief return reference (name) of the server RCB associated with this ClientReport object + * + * \param self the ClientReport instance + * \return report control block reference as string + */ +char* +ClientReport_getRcbReference(ClientReport self); + +/** + * \brief return RptId of the server RCB associated with this ClientReport object + * + * \param self the ClientReport instance + * \return report control block reference as string + */ +char* +ClientReport_getRptId(ClientReport self); + +/** + * \brief get the reason code (reason for inclusion) for a specific report data set element + * + * \param self the ClientReport instance + * \param elementIndex index of the data set element (starting with 0) + * + * \return reason code for the inclusion of the specified element + */ +ReasonForInclusion +ClientReport_getReasonForInclusion(ClientReport self, int elementIndex); + +/** + * \brief get the entry ID of the report + * + * Returns the entryId of the report if included in the report. Otherwise returns NULL. + * + * \param self the ClientReport instance + * + * \return entryId or NULL + */ +MmsValue* +ClientReport_getEntryId(ClientReport self); + +/** + * \brief determine if the last received report contains a timestamp + * + * \param self the ClientReport instance + * + * \return true if the report contains a timestamp, false otherwise + */ +bool +ClientReport_hasTimestamp(ClientReport self); + +bool +ClientReport_hasSeqNum(ClientReport self); + +uint16_t +ClientReport_getSeqNum(ClientReport self); + +bool +ClientReport_hasDataSetName(ClientReport self); + +bool +ClientReport_hasReasonForInclusion(ClientReport self); + +bool +ClientReport_hasConfRev(ClientReport self); + +uint32_t +ClientReport_getConfRev(ClientReport self); + +/** + * \brief Indicates if the report contains the bufOvfl (buffer overflow) flag + * + * \param self the ClientReport instance + * + * \returns true if the report contains the bufOvfl flag, false otherwise + */ +bool +ClientReport_hasBufOvfl(ClientReport self); + +/** + * \brief Get the value of the bufOvfl flag + * + * \param self the ClientReport instance + * + * \returns true if bufOvfl is set, false otherwise + */ +bool +ClientReport_getBufOvfl(ClientReport self); + +/** + * \brief Indicates if the report contains data references for the reported data set members + * + * \param self the ClientReport instance + * + * \returns true if the report contains data-references, false otherwise + */ +bool +ClientReport_hasDataReference(ClientReport self); + +/** + * \brief get the data-reference of the element of the report data set + * + * This function will only return a non-NULL value if the received report contains data-references. + * This can be determined by the ClientReport_hasDataReference function. + * NOTE: The returned string is allocated and hold by the ClientReport instance and is only valid until + * the ClientReport instance exists! + * + * \param self the ClientReport instance + * \param elementIndex index of the data set element (starting with 0) + * + * \param the data reference as string as provided by the report or NULL if the data reference is not available + */ +const char* +ClientReport_getDataReference(ClientReport self, int elementIndex); + + +/** + * \brief get the timestamp of the report + * + * Returns the timestamp of the report if included in the report. Otherwise the value is undefined. + * Use the ClientReport_hasTimestamp function first to figure out if the timestamp is valid + * + * \param self the ClientReport instance + * + * \return the timestamp as milliseconds since 1.1.1970 UTC + */ +uint64_t +ClientReport_getTimestamp(ClientReport self); + +/** + * \brief get the reason for inclusion of as a human readable string + * + * \param reasonCode + * + * \return the reason for inclusion as static human readable string + */ +char* +ReasonForInclusion_getValueAsString(ReasonForInclusion reasonCode); + +/************************************************** + * ClientReportControlBlock access class + **************************************************/ + +ClientReportControlBlock +ClientReportControlBlock_create(const char* rcbReference); + +void +ClientReportControlBlock_destroy(ClientReportControlBlock self); + +char* +ClientReportControlBlock_getObjectReference(ClientReportControlBlock self); + +bool +ClientReportControlBlock_isBuffered(ClientReportControlBlock self); + +const char* +ClientReportControlBlock_getRptId(ClientReportControlBlock self); + +void +ClientReportControlBlock_setRptId(ClientReportControlBlock self, const char* rptId); + +bool +ClientReportControlBlock_getRptEna(ClientReportControlBlock self); + +void +ClientReportControlBlock_setRptEna(ClientReportControlBlock self, bool rptEna); + +bool +ClientReportControlBlock_getResv(ClientReportControlBlock self); + +void +ClientReportControlBlock_setResv(ClientReportControlBlock self, bool resv); + +const char* +ClientReportControlBlock_getDataSetReference(ClientReportControlBlock self); + +/** + * \brief set the data set to be observed by the RCB + * + * The data set reference is a mixture of MMS and IEC 61850 syntax! In general the reference has + * the form: + * LDName/LNName$DataSetName + * + * e.g. "simpleIOGenericIO/LLN0$Events" + * + * It is standard that data sets are defined in LN0 logical nodes. But this is not mandatory. + * + * Note: As a result of changing the data set the server will increase the confRev attribute of the RCB. + * + * \param self the RCB instance + * \param dataSetReference the reference of the data set + */ +void +ClientReportControlBlock_setDataSetReference(ClientReportControlBlock self, const char* dataSetReference); + +uint32_t +ClientReportControlBlock_getConfRev(ClientReportControlBlock self); + +int +ClientReportControlBlock_getOptFlds(ClientReportControlBlock self); + +void +ClientReportControlBlock_setOptFlds(ClientReportControlBlock self, int optFlds); + +uint32_t +ClientReportControlBlock_getBufTm(ClientReportControlBlock self); + +void +ClientReportControlBlock_setBufTm(ClientReportControlBlock self, uint32_t bufTm); + +uint16_t +ClientReportControlBlock_getSqNum(ClientReportControlBlock self); + +int +ClientReportControlBlock_getTrgOps(ClientReportControlBlock self); + +void +ClientReportControlBlock_setTrgOps(ClientReportControlBlock self, int trgOps); + +uint32_t +ClientReportControlBlock_getIntgPd(ClientReportControlBlock self); + +void +ClientReportControlBlock_setIntgPd(ClientReportControlBlock self, uint32_t intgPd); + +bool +ClientReportControlBlock_getGI(ClientReportControlBlock self); + +void +ClientReportControlBlock_setGI(ClientReportControlBlock self, bool gi); + +bool +ClientReportControlBlock_getPurgeBuf(ClientReportControlBlock self); + +void +ClientReportControlBlock_setPurgeBuf(ClientReportControlBlock self, bool purgeBuf); + +int16_t +ClientReportControlBlock_getResvTms(ClientReportControlBlock self); + +void +ClientReportControlBlock_setResvTms(ClientReportControlBlock self, int16_t resvTms); + +MmsValue* /* */ +ClientReportControlBlock_getEntryId(ClientReportControlBlock self); + +void +ClientReportControlBlock_setEntryId(ClientReportControlBlock self, MmsValue* entryId); + +uint64_t +ClientReportControlBlock_getEntryTime(ClientReportControlBlock self); + +MmsValue* /* */ +ClientReportControlBlock_getOwner(ClientReportControlBlock self); + + +/** @} */ + +/**************************************** + * Data model access services + ****************************************/ + +/** + * @defgroup IEC61850_CLIENT_DATA_ACCESS Client side data access (read/write) service functions + * + * @{ + */ + +/** + * \brief read a functional constrained data attribute (FCDA) or functional constrained data (FCD). + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the object/attribute to read + * \param fc the functional constraint of the data attribute or data object to read + * + * \return the MmsValue instance of the received value or NULL if the request failed + */ +MmsValue* +IedConnection_readObject(IedConnection self, IedClientError* error, const char* dataAttributeReference, FunctionalConstraint fc); + +/** + * \brief write a functional constrained data attribute (FCDA) or functional constrained data (FCD). + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the object/attribute to write + * \param fc the functional constraint of the data attribute or data object to write + * \param value the MmsValue to write (has to be of the correct type - MMS_STRUCTURE for FCD) + */ +void +IedConnection_writeObject(IedConnection self, IedClientError* error, const char* dataAttributeReference, FunctionalConstraint fc, + MmsValue* value); + + +/** + * \brief read a functional constrained data attribute (FCDA) of type boolean + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + */ +bool +IedConnection_readBooleanValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc); + +/** + * \brief read a functional constrained data attribute (FCDA) of type float + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + */ +float +IedConnection_readFloatValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc); + +/** + * \brief read a functional constrained data attribute (FCDA) of type VisibleString or MmsString + * + * NOTE: the returned char buffer is dynamically allocated and has to be freed by the caller! + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + * + * \return a C string representation of the value. Has to be freed by the caller! + */ +char* +IedConnection_readStringValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc); + +/** + * \brief read a functional constrained data attribute (FCDA) of type Integer or Unsigned and return the result as int32_t + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + * + * \return an int32_t value of the read data attributes + */ +int32_t +IedConnection_readInt32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc); + +/** + * \brief read a functional constrained data attribute (FCDA) of type Integer or Unsigned and return the result as uint32_t + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + * + * \return an uint32_t value of the read data attributes + */ +uint32_t +IedConnection_readUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc); + +/** + * \brief read a functional constrained data attribute (FCDA) of type Timestamp (UTC Time) + * + * NOTE: If the timestamp parameter is set to NULL the function allocates a new timestamp instance. Otherwise the + * return value is a pointer to the user provided timestamp instance. + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + * \param timestamp a pointer to a user provided timestamp instance or NULL + * + * \return the timestamp value + */ +Timestamp* +IedConnection_readTimestampValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc, + Timestamp* timeStamp); + +/** + * \brief read a functional constrained data attribute (FCDA) of type Quality + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute to read + * + * \return the timestamp value + */ +Quality +IedConnection_readQualityValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc); + +/** + * \brief write a functional constrained data attribute (FCDA) of type boolean + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute or data object to write + * \param value the boolean value to write + */ +void +IedConnection_writeBooleanValue(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, bool value); + +/** + * \brief write a functional constrained data attribute (FCDA) of type integer + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute or data object to write + * \param value the int32_t value to write + */ +void +IedConnection_writeInt32Value(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, int32_t value); + +/** + * \brief write a functional constrained data attribute (FCDA) of type unsigned (integer) + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute or data object to write + * \param value the uint32_t value to write + */ +void +IedConnection_writeUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, uint32_t value); + +/** + * \brief write a functional constrained data attribute (FCDA) of type float + * + * \param self the connection object to operate on + * \param error the error code if an error occurs + * \param object reference of the data attribute to read + * \param fc the functional constraint of the data attribute or data object to write + * \param value the float value to write + */ +void +IedConnection_writeFloatValue(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, float value); + +void +IedConnection_writeVisibleStringValue(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, char* value); + +void +IedConnection_writeOctetString(IedConnection self, IedClientError* error, const char* objectReference, + FunctionalConstraint fc, uint8_t* value, int valueLength); + +/** @} */ + +/**************************************** + * Data set handling + ****************************************/ + +/** + * @defgroup IEC61850_CLIENT_DATA_SET Client side data set service functions and data types + * + * @{ + */ + +/** + * \brief get data set values from a server device + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param dataSetReference object reference of the data set + * \param dataSet a data set instance where to store the retrieved values or NULL if a new instance + * shall be created. + * + * \return data set instance with retrieved values of NULL if an error occurred. + */ +ClientDataSet +IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference, ClientDataSet dataSet); + +/** + * \brief create a new data set at the connected server device + * + * This function creates a new data set at the server. The parameter dataSetReference is the name of the new data set + * to create. It is either in the form LDName/LNodeName.dataSetName or @dataSetName for an association specific data set. + * + * The dataSetElements parameter contains a linked list containing the object references of FCDs or FCDAs. The format of + * this object references is LDName/LNodeName.item(arrayIndex)component[FC]. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param dataSetReference object reference of the data set + * \param dataSetElements a list of object references defining the members of the new data set + * + */ +void +IedConnection_createDataSet(IedConnection self, IedClientError* error, const char* dataSetReference, LinkedList /* char* */ dataSetElements); + +/** + * \brief delete a deletable data set at the connected server device + * + * This function deletes a data set at the server. The parameter dataSetReference is the name of the data set + * to delete. It is either in the form LDName/LNodeName.dataSetName or @dataSetName for an association specific data set. + * + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param dataSetReference object reference of the data set + */ +void +IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const char* dataSetReference); + + +/** + * \brief returns the object references of the elements of a data set + * + * The return value contains a linked list containing the object references of FCDs or FCDAs. The format of + * this object references is LDName/LNodeName.item(arrayIndex)component[FC]. + * + * \param connection the connection object + * \param error the error code if an error occurs + * \param dataSetReference object reference of the data set + * \param isDeletable this is an output parameter indicating that the requested data set is deletable by clients. + * If this information is not required a NULL pointer can be used. + * + * \return LinkedList containing the data set elements as char* strings. + */ +LinkedList /* */ +IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, const char* dataSetReference, bool* isDeletable); + +/******************************************************** + * Data set object (local representation of a data set) + *******************************************************/ + +/** + * \brief destroy an ClientDataSet instance. Has to be called by the application. + * + * Note: A ClientDataSet cannot be created directly by the application but only by the IedConnection_readDataSetValues + * function. Therefore there is no public ClientDataSet_create function. + * + * \param self the ClientDataSet instance + */ +void +ClientDataSet_destroy(ClientDataSet self); + +/** + * \brief get the data set values locally stored in the ClientDataSet instance. + * + * This function returns a pointer to the locally stored MmsValue instance of this + * ClientDataSet instance. The MmsValue instance is of type MMS_ARRAY and contains one + * array element for each data set member. + * Note: This call does not invoke any interaction with the associated server. It will + * only provide access to already stored value. To update the values with the current values + * of the server the IecConnection_readDataSetValues function has to be called! + * + * \param self the ClientDataSet instance + * + * \return the locally stored data set values as MmsValue object of type MMS_ARRAY. + */ +MmsValue* +ClientDataSet_getValues(ClientDataSet self); + +/** + * \brief Get the object reference of the data set. + * + * \param self the ClientDataSet instance + * + * \return the object reference of the data set. + */ +char* +ClientDataSet_getReference(ClientDataSet self); + +/** + * \brief get the size of the data set (number of members) + * + * \param self the ClientDataSet instance + * + * \return the number of member contained in the data set. + */ +int +ClientDataSet_getDataSetSize(ClientDataSet self); + +/** @} */ + +/************************************ + * Control service functions + ************************************/ + +/** + * @defgroup IEC61850_CLIENT_CONTROL Client side control service functions + * + * @{ + */ + +typedef struct sControlObjectClient* ControlObjectClient; + +typedef enum { + CONTROL_MODEL_STATUS_ONLY, + CONTROL_MODEL_DIRECT_NORMAL, + CONTROL_MODEL_SBO_NORMAL, + CONTROL_MODEL_DIRECT_ENHANCED, + CONTROL_MODEL_SBO_ENHANCED +} ControlModel; + + +/** + * \brief Create a new client control object + * + * A client control object is used to handle all client side aspects of a controllable + * data object. + * + * \param objectReference the reference of the controllable data object + * \param connection the connection instance where the control object has to be reached + * + * \return the newly created instance or NULL if the creation failed + */ +ControlObjectClient +ControlObjectClient_create(const char* objectReference, IedConnection connection); + +void +ControlObjectClient_destroy(ControlObjectClient self); + +char* +ControlObjectClient_getObjectReference(ControlObjectClient self); + +ControlModel +ControlObjectClient_getControlModel(ControlObjectClient self); + +/** + * \brief Send an operate command to the server + * + * \param self the control object instance to use + * \param ctlVal the control value (for APC the value may be either AnalogueValue (MMS_STRUCT) or MMS_FLOAT/MMS_INTEGER + * \param operTime the time when the command has to be executed (for time activated control). If this value is 0 the command will be executed instantly. + * + * \return true if operation has been successful, false otherwise. + */ +bool +ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t operTime); + +bool +ControlObjectClient_select(ControlObjectClient self); + +/** + * \brief Send an select with value command to the server + * + * \param self the control object instance to use + * \param ctlVal the control value (for APC the value may be either AnalogueValue (MMS_STRUCT) or MMS_FLOAT/MMS_INTEGER + * + * \return true if select has been successful, false otherwise. + */ +bool +ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal); + +bool +ControlObjectClient_cancel(ControlObjectClient self); + +void +ControlObjectClient_setLastApplError(ControlObjectClient self, LastApplError lastAppIError); + +LastApplError +ControlObjectClient_getLastApplError(ControlObjectClient self); + +void +ControlObjectClient_setTestMode(ControlObjectClient self); + +void +ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat); + +/** + * \brief Use a constant T parameter for all command (select, operate, cancel) of a single control sequence + * + * NOTE: Some non-standard compliant servers may require this to accept oper/cancel requests + * + * \param self the ControlObjectClient instance + * \param useContantT enable this behaviour with true, disable with false + */ +void +ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT); + +void +ControlObjectClient_enableInterlockCheck(ControlObjectClient self); + +void +ControlObjectClient_enableSynchroCheck(ControlObjectClient self); + + +/** + * \brief Private a callback handler that is invoked when a command termination message is received. + * + * This callback is invoked whenever a CommandTermination+ or CommandTermination- message is received. + * To distinguish between a CommandTermination+ and CommandTermination- please use the + * ControlObjectClient_getLastApplError function. + * + * \param self the ControlObjectClient instance + * \param handler the callback function to be used + * \param handlerParameter an arbitrary parameter that is passed to the handler + */ +typedef void (*CommandTerminationHandler) (void* parameter, ControlObjectClient controlClient); + +void +ControlObjectClient_setCommandTerminationHandler(ControlObjectClient self, CommandTerminationHandler handler, + void* handlerParameter); + +/** @} */ + +/************************************* + * Model discovery services + ************************************/ + +/** + * @defgroup IEC61850_CLIENT_MODEL_DISCOVERY Model discovery services + * + * @{ + */ + +/** + * \brief Retrieve the device model from the server + * + * This function retrieves the complete device model from the server. The model is buffered an can be browsed + * by subsequent API calls. This API call is mapped to multiple ACSI services. + * + * \param self the connection object + * \param error the error code if an error occurs + * + */ +void +IedConnection_getDeviceModelFromServer(IedConnection self, IedClientError* error); + +/** + * \brief Get the list of logical devices available at the server (DEPRECATED) + * + * This function is mapped to the GetServerDirectory(LD) ACSI service. + * + * \param self the connection object + * \param error the error code if an error occurs + * + * \return LinkedList with string elements representing the logical device names + */ +LinkedList /**/ +IedConnection_getLogicalDeviceList(IedConnection self, IedClientError* error); + +/** + * \brief Get the list of logical devices or files available at the server + * + * GetServerDirectory ACSI service implementation. This function will either return the list of + * logical devices (LD) present at the server or the list of available files. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param getFileNames get list of files instead of logical device names (TO BE IMPLEMENTED) + * + * \return LinkedList with string elements representing the logical device names or file names + */ +LinkedList /**/ +IedConnection_getServerDirectory(IedConnection self, IedClientError* error, bool getFileNames); + +/** + * \brief Get the list of logical nodes (LN) of a logical device + * + * LGetLogicalDeviceDirectory ACSI service implementation. Returns the list of logical nodes present + * in a logical device. The list is returned as a linked list of type LinkedList where the elements + * are C style strings. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param getFileNames get list of files instead of logical device names (TO BE IMPLEMENTED) + * + * \return LinkedList with string elements representing the logical node names + */ +LinkedList /**/ +IedConnection_getLogicalDeviceDirectory(IedConnection self, IedClientError* error, const char* logicalDeviceName); + +typedef enum { + ACSI_CLASS_DATA_OBJECT, + ACSI_CLASS_DATA_SET, + ACSI_CLASS_BRCB, + ACSI_CLASS_URCB, + ACSI_CLASS_LCB, + ACSI_CLASS_LOG, + ACSI_CLASS_SGCB, + ACSI_CLASS_GoCB, + ACSI_CLASS_GsCB, + ACSI_CLASS_MSVCB, + ACSI_CLASS_USVCB +} ACSIClass; + +/** + * \brief returns a list of all MMS variables that are children of the given logical node + * + * This function cannot be mapped to any ACSI service. It is a convenience function for generic clients that + * wants to show a list of all available children of the MMS named variable representing the logical node. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param logicalNodeReference string that represents the LN reference + * + * \return the list of all MMS named variables as C strings in a LinkedList type + * + */ +LinkedList /**/ +IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, + const char* logicalNodeReference); + +/** + * \brief returns the directory of the given logical node (LN) containing elements of the specified ACSI class + * + * Implementation of the GetLogicalNodeDirectory ACSI service. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param logicalNodeReference string that represents the LN reference + * \param acsiClass specifies the ACSI class + * + * \return list of all logical node elements of the specified ACSI class type as C strings in a LinkedList + * + */ +LinkedList /**/ +IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, + const char* logicalNodeReference, ACSIClass acsiClass); + +/** + * \brief returns the directory of the given data object (DO) + * + * Implementation of the GetDataDirectory ACSI service. This will return the list of + * all data attributes or sub data objects. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param dataReference string that represents the DO reference + * + * \return list of all data attributes or sub data objects as C strings in a LinkedList + * + */ +LinkedList /**/ +IedConnection_getDataDirectory(IedConnection self, IedClientError* error, const char* dataReference); + +/** + * \brief returns the directory of the given data object (DO) + * + * Implementation of the GetDataDirectory ACSI service. This will return the list of + * C strings with all data attributes or sub data objects as elements. The returned + * strings will contain the functional constraint appended in square brackets when appropriate. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param dataReference string that represents the DO reference + * + * \return list of all data attributes or sub data objects as C strings in a LinkedList + * + */ +LinkedList /**/ +IedConnection_getDataDirectoryFC(IedConnection self, IedClientError* error, const char* dataReference); + +/** + * \brief returns the directory of the given data object/data attribute with the given FC + * + * Implementation of the GetDataDirectory ACSI service. This will return the list of + * C strings with all data attributes or sub data objects as elements. The returned + * strings will contain the functional constraint appended in square brackets when appropriate. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param dataReference string that represents the DO reference + * \param fc the functional constraint + * + * \return list of all data attributes or sub data objects as C strings in a LinkedList + * + */ +LinkedList +IedConnection_getDataDirectoryByFC(IedConnection self, IedClientError* error, const char* dataReference, FunctionalConstraint fc); + +/** + * \brief return the MMS variable type specification of the data attribute referenced by dataAttributeReference and function constraint fc. + * + * This function can be used to get the MMS variable type specification for an IEC 61850 data attribute. It is an extension + * of the ACSI that may be required by generic client applications. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param dataAttributeReference string that represents the DA reference + * \param fc functional constraint of the DA + * + * \return MmsVariableSpecification of the data attribute. + * + */ +MmsVariableSpecification* +IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* dataAttributeReference, + FunctionalConstraint fc); + +/** @} */ + +/** + * @defgroup IEC61850_CLIENT_FILE_SERVICE File service related functions, data types, and definitions + * + * @{ + */ + +typedef struct sFileDirectoryEntry* FileDirectoryEntry; + +FileDirectoryEntry +FileDirectoryEntry_create(const char* fileName, uint32_t fileSize, uint64_t lastModified); + +void +FileDirectoryEntry_destroy(FileDirectoryEntry self); + +char* +FileDirectoryEntry_getFileName(FileDirectoryEntry self); + +uint32_t +FileDirectoryEntry_getFileSize(FileDirectoryEntry self); + +uint64_t +FileDirectoryEntry_getLastModified(FileDirectoryEntry self); + + +/** + * \brief returns the directory entries of the specified file directory. + * + * Requires the server to support file services. + * + * NOTE: the returned linked list has to be freed by the user. You can user the following statement + * to free the list of directory entries: + * + * LinkedList_destroyDeep(fileNames, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy); + * + * where fileNames is the return value of this function. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param directoryName the name of the directory or NULL to get the entries of the root directory + * + * \return the list of directory entries. The return type is a LinkedList with FileDirectoryEntry elements + */ +LinkedList /**/ +IedConnection_getFileDirectory(IedConnection self, IedClientError* error, const char* directoryName); + +/** + * \brief user provided handler to receive the data of the GetFile request + * + * This handler will be invoked whenever the clients receives a data block from + * the server. The API user has to copy the data to another location before returning. + * The other location could for example be a file in the clients file system. + * + * \param parameter user provided parameter + * \param buffer pointer to the buffer containing the received data + * \param bytesRead number of bytes available in the buffer + * + * \return true if the client implementation shall continue to download data false if the download + * should be stopped. E.g. if the file cannot be stored client side due to missing resources. + */ +typedef bool +(*IedClientGetFileHandler) (void* parameter, uint8_t* buffer, uint32_t bytesRead); + +/** + * \brief Implementation of the GetFile ACSI service + * + * Download a file from the server. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param fileName the name of the file to be read from the server + * + * \return number of bytes received + */ +uint32_t +IedConnection_getFile(IedConnection self, IedClientError* error, const char* fileName, IedClientGetFileHandler handler, + void* handlerParameter); + +/** + * \brief Implementation of the DeleteFile ACSI service + * + * Delete a file at the server. + * + * \param self the connection object + * \param error the error code if an error occurs + * \param fileName the name of the file to delete + */ +void +IedConnection_deleteFile(IedConnection self, IedClientError* error, const char* fileName); + + +/** @} */ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + + +#endif /* IEC61850_CLIENT_H_ */ diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h new file mode 100644 index 0000000..c3d3bc6 --- /dev/null +++ b/src/iec61850/inc/iec61850_common.h @@ -0,0 +1,396 @@ +/* + * iec61850_common.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef IEC61850_COMMON_H_ +#define IEC61850_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "libiec61850_common_api.h" + +/** + * @defgroup iec61850_common_api_group IEC 61850 API common parts + */ +/**@{*/ + +/** + * @defgroup TRIGGER_OPTIONS Trigger options (bit values combinable) + * + * @{ + */ + +/** Report will be triggerd when data changes */ +#define TRG_OPT_DATA_CHANGED 1 + +/** Report will be triggered when quality changes */ +#define TRG_OPT_QUALITY_CHANGED 2 + +/** Report will be triggered when data is updated */ +#define TRG_OPT_DATA_UPDATE 4 + +/** Report will be triggered periodically */ +#define TRG_OPT_INTEGRITY 8 + +/** Report will be triggered by GI (general interrogation) request */ +#define TRG_OPT_GI 16 +/** @} */ + +/** + * @defgroup REPORT_OPTIONS Report options (bit values combinable) + * + * @{ + */ + +/** Report contains sequence number */ +#define RPT_OPT_SEQ_NUM 1 + +/** Report contains a report timestamp */ +#define RPT_OPT_TIME_STAMP 2 + +/** Report contains reason for inclusion value for each included data set member */ +#define RPT_OPT_REASON_FOR_INCLUSION 4 + +/** Report contains data set object reference */ +#define RPT_OPT_DATA_SET 8 + +/** Report contains data reference for each included data set member */ +#define RPT_OPT_DATA_REFERENCE 16 + +/** Report contains buffer overflow flag */ +#define RPT_OPT_BUFFER_OVERFLOW 32 + +/** Report contains entry id */ +#define RPT_OPT_ENTRY_ID 64 + +/** Report contains configuration revision */ +#define RPT_OPT_CONF_REV 128 +/** @} */ + +/** + * @defgroup ORIGINATOR_CATEGORIES Originator categories (orCat) + * + * @{ + */ + +/** Not supported - should not be used */ +#define CONTROL_ORCAT_NOT_SUPPORTED 0 + +/** Control operation issued from an operator using a client located at bay level */ +#define CONTROL_ORCAT_BAY_CONTROL 1 + +/** Control operation issued from an operator using a client located at station level */ +#define CONTROL_ORCAT_STATION_CONTROL 2 + +/** Control operation from a remote operator outside the substation (for example network control center) */ +#define CONTROL_ORCAT_REMOTE_CONTROL 3 + +/** Control operation issued from an automatic function at bay level */ +#define CONTROL_ORCAT_AUTOMATIC_BAY 4 + +/** Control operation issued from an automatic function at station level */ +#define CONTROL_ORCAT_AUTOMATIC_STATION 5 + +/** Control operation issued from a automatic function outside of the substation */ +#define CONTROL_ORCAT_AUTOMATIC_REMOTE 6 + +/** Control operation issued from a maintenance/service tool */ +#define CONTROL_ORCAT_MAINTENANCE 7 + +/** Status change occurred without control action (for example external trip of a circuit breaker or failure inside the breaker) */ +#define CONTROL_ORCAT_PROCESS 8 + +/** @} */ + +/** + * @defgroup CONTROL_ADD_CAUSE Definition for addCause type - used in control models + * + * @{ + */ + +/** AddCause - additional cause information for control model errors */ +typedef enum { + ADD_CAUSE_UNKNOWN = 0, + ADD_CAUSE_NOT_SUPPORTED = 1, + ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2, + ADD_CAUSE_SELECT_FAILED = 3, + ADD_CAUSE_INVALID_POSITION = 4, + ADD_CAUSE_POSITION_REACHED = 5, + ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6, + ADD_CAUSE_STEP_LIMIT = 7, + ADD_CAUSE_BLOCKED_BY_MODE = 8, + ADD_CAUSE_BLOCKED_BY_PROCESS = 9, + ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10, + ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11, + ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12, + ADD_CAUSE_BLOCKED_BY_HEALTH = 13, + ADD_CAUSE_1_OF_N_CONTROL = 14, + ADD_CAUSE_ABORTION_BY_CANCEL = 15, + ADD_CAUSE_TIME_LIMIT_OVER = 16, + ADD_CAUSE_ABORTION_BY_TRIP = 17, + ADD_CAUSE_OBJECT_NOT_SELECTED = 18, + ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19, + ADD_CAUSE_NO_ACCESS_AUTHORITY = 20, + ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21, + ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22, + ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23, + ADD_CAUSE_ABORTION_BY_COMMAND = 24, + ADD_CAUSE_NONE = 25, + ADD_CAUSE_INCONSISTENT_PARAMETERS = 26, + ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27 +} ControlAddCause; + +/** @} */ + +/** + * @defgroup FUNCTIONAL_CONSTRAINTS Definitions and functions related to functional constraints (FCs) + * + * @{ + */ + +#if (CONFIG_PROVIDE_OLD_FC_DEFINES == 1) +#define ST IEC61850_FC_ST +#define MX IEC61850_FC_MX +#define SP IEC61850_FC_SP +#define SV IEC61850_FC_SV +#define CF IEC61850_FC_CF +#define DC IEC61850_FC_DC +#define SG IEC61850_FC_SG +#define SE IEC61850_FC_SE +#define SR IEC61850_FC_SR +#define OR IEC61850_FC_OR +#define BL IEC61850_FC_BL +#define EX IEC61850_FC_EX +#define CO IEC61850_FC_CO +#define ALL IEC61850_FC_ALL +#define NONE IEC61850_FC_NONE +#endif /* (CONFIG_PROVIDE_OLD_FC_DEFINES == 1) */ + + +/** FCs (Functional constraints) according to IEC 61850-7-2 */ +typedef enum eFunctionalConstraint { + /** Status information */ + IEC61850_FC_ST = 0, + /** Measurands - analog values */ + IEC61850_FC_MX = 1, + /** Setpoint */ + IEC61850_FC_SP = 2, + /** Substitution */ + IEC61850_FC_SV = 3, + /** Configuration */ + IEC61850_FC_CF = 4, + /** Description */ + IEC61850_FC_DC = 5, + /** Setting group */ + IEC61850_FC_SG = 6, + /** Setting group editable */ + IEC61850_FC_SE = 7, + /** Service response / Service tracking */ + IEC61850_FC_SR = 8, + /** Operate received */ + IEC61850_FC_OR = 9, + /** Blocking */ + IEC61850_FC_BL = 10, + /** Extended definition */ + IEC61850_FC_EX = 11, + /** Control */ + IEC61850_FC_CO = 12, + IEC61850_FC_ALL = 99, + IEC61850_FC_NONE = -1 +} FunctionalConstraint; + +/**extern "C" { + * \brief convert a function constraint to a static string + */ +char* +FunctionalConstraint_toString(FunctionalConstraint fc); + +/** + * \brief parse a string treated as a functional constraint representation + */ +FunctionalConstraint +FunctionalConstraint_fromString(const char* fcString); + +/** @} */ + +/** + * @defgroup QUALITY Definitions and functions related to data attribute quality + * + * @{ + */ + + +typedef uint16_t Quality; +typedef uint16_t Validity; + +#define QUALITY_VALIDITY_GOOD 0 +#define QUALITY_VALIDITY_INVALID 2 +#define QUALITY_VALIDITY_RESERVED 1 +#define QUALITY_VALIDITY_QUESTIONABLE 3 + +#define QUALITY_DETAIL_OVERFLOW 4 +#define QUALITY_DETAIL_OUT_OF_RANGE 8 +#define QUALITY_DETAIL_BAD_REFERENCE 16 +#define QUALITY_DETAIL_OSCILLATORY 32 +#define QUALITY_DETAIL_FAILURE 64 +#define QUALITY_DETAIL_OLD_DATA 128 +#define QUALITY_DETAIL_INCONSISTENT 256 +#define QUALITY_DETAIL_INACCURATE 512 + +#define QUALITY_SOURCE_SUBSTITUTED 1024 + +#define QUALITY_TEST 2048 + +#define QUALITY_OPERATOR_BLOCKED 4096 + +Validity +Quality_getValidity(Quality* self); + +void +Quality_setValidity(Quality* self, Validity validity); + +void +Quality_setFlag(Quality* self, int flag); + +void +Quality_unsetFlag(Quality* self, int flag); + +bool +Quality_isFlagSet(Quality* self, int flag); + +Quality +Quality_fromMmsValue(const MmsValue* mmsValue); + +/** @} */ + +/** + * @defgroup DBPOS Definitions and functions related to IEC 61850 Dbpos (a CODED ENUM) data type + * + * @{ + */ + +typedef enum { + DBPOS_INTERMEDIATE_STATE = 0, + DBPOS_OFF = 1, + DBPOS_ON = 2, + DBPOS_BAD_STATE = 3 +} Dbpos; + + +/** + * \brief convert MMS bit string to Dbpos enumeration type + * + * \param mmsValue the MmsValue instance representing the Dbpos value + * + * \return the corresponding Dbpos value + */ +Dbpos +Dbpos_fromMmsValue(const MmsValue* mmsValue); + +/** + * \brief conver Dbpos to MMS bit string + * + * \param mmsValue the MmsValue instance representing a Dbpos value or NULL to create a new MmsValue instance + * \param a Dbpos value + * + * \return the corresponding MmsValue instance + */ +MmsValue* +Dbpos_toMmsValue(MmsValue* mmsValue, Dbpos dbpos); + +/** @} */ + +/** + * @defgroup TIMESTAMP Definitions and functions related to IEC 61850 Timestamp (UTC Time) data type + * + * @{ + */ + +typedef union { + uint8_t val[8]; +} Timestamp; + +void +Timestamp_clearFlags(Timestamp* self); + +uint32_t +Timestamp_getTimeInSeconds(Timestamp* self); + +uint64_t +Timestamp_getTimeInMs(Timestamp* self); + +bool +Timestamp_isLeapSecondKnown(Timestamp* self); + +void +Timestamp_setLeapSecondKnown(Timestamp* self, bool value); + +bool +Timestamp_hasClockFailure(Timestamp* self); + +void +Timestamp_setClockFailure(Timestamp* self, bool value); + +bool +Timestamp_isClockNotSynchronized(Timestamp* self); + +void +Timestamp_setClockNotSynchronized(Timestamp* self, bool value); + +int +Timestamp_getSubsecondPrecision(Timestamp* self); + +/** + * \brief Set the subsecond precision value of the time stamp + * + * \param subsecondPrecision the number of significant bits of the fractionOfSecond part of the time stamp + */ +void +Timestamp_setSubsecondPrecision(Timestamp* self, int subsecondPrecision); + +void +Timestamp_setTimeInSeconds(Timestamp* self, uint32_t secondsSinceEpoch); + +void +Timestamp_setTimeInMilliseconds(Timestamp* self, uint64_t millisSinceEpoch); + +/** + * \brief Get the version of the library as string + * + * \return the version of the library (e.g. "0.8.3") + */ +char* +LibIEC61850_getVersionString(void); + + +/** @} */ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* IEC61850_COMMON_H_ */ diff --git a/src/iec61850/inc/iec61850_config_file_parser.h b/src/iec61850/inc/iec61850_config_file_parser.h new file mode 100644 index 0000000..e595b11 --- /dev/null +++ b/src/iec61850/inc/iec61850_config_file_parser.h @@ -0,0 +1,54 @@ +/* + * config_file_parser.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef CONFIG_FILE_PARSER_H_ +#define CONFIG_FILE_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hal_filesystem.h" + +/** \addtogroup server_api_group + * @{ + */ + +/** + * @defgroup CONFIG_FILE_PARSER Create data models by configuration files + * + * @{ + */ + +IedModel* +ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_FILE_PARSER_H_ */ diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h new file mode 100644 index 0000000..7772533 --- /dev/null +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -0,0 +1,268 @@ +/* + * dynamic_model.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef DYNAMIC_MODEL_H_ +#define DYNAMIC_MODEL_H_ + +#include "iec61850_model.h" +#include "iec61850_cdc.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \addtogroup server_api_group + * @{ + */ + +/** + * @defgroup DYNAMIC_MODEL General dynamic model creation functions + * + * @{ + */ + + +/** + * \brief create a new IedModel instance + * + * The IedModel object is the root node of an IEC 61850 service data model. + * + * \param name the name of the IedModel or NULL (optional - NOT YET USED) + * + * \return + */ +IedModel* +IedModel_create(const char* name/*, MemoryAllocator allocator*/); + +/** + * \brief Set the name of the IED (use only for dynamic model!) + * + * This will change the default name (usualy "TEMPLATE") to a user configured values. + * NOTE: This function has to be called before IedServer_create ! + * NOTE: For dynamic model (and configuration file date model) this function has to be + * used instead of IedModel_setIedName. + * + * \param model the IedModel instance + * \param the name of the configured IED + */ +void +IedModel_setIedNameForDynamicModel(IedModel* self, const char* name); + +/** + * \brief destroy a dynamically created data model + * + * This function will free all the memory allocated for the data model. + * + * NOTE: Do not use this function when using a static data model (static_model.c create by static model generator). + * + * \param model the model instance to destroy + */ +void +IedModel_destroy(IedModel* model); + +/** + * \brief Create a new logical device model and add it to the IED model + * + * \param name the name of the new logical device + * \param parent the parent IED model + * + * \return the newly created LogicalDevice instance + */ +LogicalDevice* +LogicalDevice_create(const char* name, IedModel* parent); + + +/** + * \brief Create a new logical mode and add it to a logical device + * + * \param name the name of the new logical node + * \param parent the parent logical device + * + * \return the newly created LogicalNode instance + */ +LogicalNode* +LogicalNode_create(const char* name, LogicalDevice* parent); + +/** + * \brief create a new data object and add it to a parent model node + * + * The parent model node has to be of type DataObject or LogicalNode. + * + * \param name the name of the data object (e.h. "Mod", "Health" ...) + * \param parent the parent model node + * \param arrayElements the number of array elements if the data object is an array or 0 + * + * \return the newly create DataObject instance + */ +DataObject* +DataObject_create(const char* name, ModelNode* parent, int arrayElements); + +/** + * \brief create a new data attribute and add it to a parent model node + * + * The parent model node has to be of type LogicalNode or DataObject + * + * \param name the name of the data attribute (e.g. "stVal") + * \param parent the parent model node + * \param type the type of the data attribute (CONSTRUCTED if the type contains sub data attributes) + * \param fc the functional constraint (FC) of the data attribte + * \param triggerOptions the trigger options (dupd, dchg, qchg) that cause an event notification + * \param arrayElements the number of array elements if the data attribute is an array or 0 + * \param sAddr an optional short address + * + * \return the newly create DataAttribute instance + */ +DataAttribute* +DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type, FunctionalConstraint fc, + uint8_t triggerOptions, int arrayElements, uint32_t sAddr); + +/** + * \brief create a new report control block (RCB) + * + * Create a new report control block (RCB) and add it to the given logical node (LN). + * + * \param name name of the RCB relative to the parent LN + * \param parent the parent LN. + * \param rptId of the report. If NULL the default report ID (object reference) is used. + * \param isBuffered true for a buffered RCB - false for unbuffered RCB + * \param dataSetName name (object reference) of the default data set or NULL if no data + * is set by default + * \param confRef the configuration revision + * \param trgOps the trigger options supported by this RCB (bit set) + * \param options the inclusion options. Specifies what elements are included in a report (bit set) + * \param bufTm the buffering time of the RCB in milliseconds (time between the first event and the preparation of the report). + * \param intgPd integrity period in milliseconds + * + * \return the new RCB instance. + */ +ReportControlBlock* +ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bool isBuffered, char* + dataSetName, uint32_t confRef, uint8_t trgOps, uint8_t options, uint32_t bufTm, uint32_t intgPd); + +/** + * \brief create a setting group control block (SGCB) + * + * Create a new setting group control block (SGCB) and add it to the given logical node (LN). + * + * \param parent the parent LN. + * \param the active setting group on server startup (1..N) + * \param the number of setting groups (N) + * + * \return the new SGCB instance + */ +SettingGroupControlBlock* +SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numOfSGs); + +/** + * \brief create a new GSE/GOOSE control block (GoCB) + * + * Create a new GOOSE control block (GoCB) and add it to the given logical node (LN) + * + * \param name name of the GoCB relative to the parent LN + * \param parent the parent LN + * \param appId the application ID of the GoCB + * \param dataSet the data set reference to be used by the GoCB + * \param confRef the configuration revision + * \param fixedOffs indicates if GOOSE publisher shall use fixed offsets (NOT YET SUPPORTED) + * \param minTime minimum GOOSE retransmission time (-1 if not specified - uses stack default then) + * \param maxTime GOOSE retransmission time in stable state (-1 if not specified - uses stack default then) + * + * \return the new GoCB instance + */ +GSEControlBlock* +GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char* dataSet, uint32_t confRef, + bool fixedOffs, int minTime, int maxTime); + +/** + * \brief create a PhyComAddress object and add it to a GoCB + * + * A PhyComAddress object contains all required addressing informations for a GOOSE publisher. + * + * \param parent the parent GSEControlBlock object + * \param vlanPriority the priority field of the VLAN tag + * \param vlanId the ID field of the VLAN tag + * \param appId the application identifier + * \param dstAddress the 6 byte multicast MAC address to specify the destination + * + * \return the new PhyComAddress object + */ +PhyComAddress* +PhyComAddress_create(GSEControlBlock* parent, uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[]); + +/** + * \brief create a new data set + * + * \param name the name of the data set + * \param parent the logical node that hosts the data set (typically a LLN0) + * + * \return the new data set instance + */ +DataSet* +DataSet_create(const char* name, LogicalNode* parent); + +/** + * \brief returns the number of elements (entries) of the data set + * + * \param self the instance of the data set + * + * \returns the number of data set elements + */ +int +DataSet_getSize(DataSet* self); + +DataSetEntry* +DataSet_getFirstEntry(DataSet* self); + +DataSetEntry* +DataSetEntry_getNext(DataSetEntry* self); + +/** + * \brief create a new data set entry (FCDA) + * + * Create a new FCDA reference and add it to the given data set as a new data set member. + * + * Note: Be aware that data set entries are not IEC 61850 object reference but MMS variable names + * that have to contain the LN name, the FC and subsequent path elements separated by "$" instead of ".". + * This is due to efficiency reasons to avoid the creation of additional strings. + * + * \param dataSet the data set to which the new entry will be added + * \param variable the name of the variable as MMS variable name including FC ("$" used as separator!) + * \param index the index if the FCDA is an array element, otherwise -1 + * \param component the name of the component of the variable if the FCDA is a sub element of an array + * element. If this is not the case then NULL should be given here. + * + * \return the new data set entry instance + */ +DataSetEntry* +DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const char* component); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* DYNAMIC_MODEL_H_ */ diff --git a/src/iec61850/inc/iec61850_model.h b/src/iec61850/inc/iec61850_model.h new file mode 100644 index 0000000..665a249 --- /dev/null +++ b/src/iec61850/inc/iec61850_model.h @@ -0,0 +1,444 @@ +/* + * model.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MODEL_H_ +#define MODEL_H_ + +#include "iec61850_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup server_api_group + * @{ + */ + +/** + * @defgroup DATA_MODEL General data model definitions, access and iteration functions + * + * @{ + */ + +/** + * \brief abstract base type for IEC 61850 data model nodes + */ +typedef struct sModelNode ModelNode; + +/** + * \brief IEC 61850 data model element of type data attribute + */ +typedef struct sDataAttribute DataAttribute; + +/** + * \brief IEC 61850 data model element of type data object + */ +typedef struct sDataObject DataObject; + +/** + * \brief IEC 61850 data model element of type logical node + */ +typedef struct sLogicalNode LogicalNode; + +/** + * \brief IEC 61850 data model element of type logical device + */ +typedef struct sLogicalDevice LogicalDevice; + +/** + * \brief Root node of the IEC 61850 data model. This is usually created by the model generator tool (genmodel.jar) + */ +typedef struct sIedModel IedModel; + +typedef struct sDataSet DataSet; +typedef struct sReportControlBlock ReportControlBlock; + +/** + * \brief IEC 61850 data model of setting group control block (SGCB) + */ +typedef struct sSettingGroupControlBlock SettingGroupControlBlock; + +typedef struct sGSEControlBlock GSEControlBlock; + + +typedef enum { + BOOLEAN = 0,/* int */ + INT8 = 1, /* int8_t */ + INT16 = 2, /* int16_t */ + INT32 = 3, /* int32_t */ + INT64 = 4, /* int64_t */ + INT128 = 5, /* no native mapping! */ + INT8U = 6, /* uint8_t */ + INT16U = 7, /* uint16_t */ + INT24U = 8, /* uint32_t */ + INT32U = 9, /* uint32_t */ + FLOAT32 = 10, /* float */ + FLOAT64 = 11, /* double */ + ENUMERATED = 12, + OCTET_STRING_64 = 13, + OCTET_STRING_6 = 14, + OCTET_STRING_8 = 15, + VISIBLE_STRING_32 = 16, + VISIBLE_STRING_64 = 17, + VISIBLE_STRING_65 = 18, + VISIBLE_STRING_129 = 19, + VISIBLE_STRING_255 = 20, + UNICODE_STRING_255 = 21, + TIMESTAMP = 22, + QUALITY = 23, + CHECK = 24, + CODEDENUM = 25, + GENERIC_BITSTRING = 26, + CONSTRUCTED = 27, + ENTRY_TIME = 28, + PHYCOMADDR = 29 +} DataAttributeType; + +typedef enum { + LogicalDeviceModelType, + LogicalNodeModelType, + DataObjectModelType, + DataAttributeModelType +} ModelNodeType; + +struct sIedModel { + char* name; + LogicalDevice* firstChild; + DataSet* dataSets; + ReportControlBlock* rcbs; + GSEControlBlock* gseCBs; + SettingGroupControlBlock* sgcbs; + void (*initializer) (void); +}; + +struct sLogicalDevice { + ModelNodeType modelType; + char* name; + ModelNode* parent; + ModelNode* sibling; + ModelNode* firstChild; +}; + +struct sModelNode { + ModelNodeType modelType; + char* name; + ModelNode* parent; + ModelNode* sibling; + ModelNode* firstChild; +}; + +struct sLogicalNode { + ModelNodeType modelType; + char* name; + ModelNode* parent; + ModelNode* sibling; + ModelNode* firstChild; +}; + +struct sDataObject { + ModelNodeType modelType; + char* name; + ModelNode* parent; + ModelNode* sibling; + ModelNode* firstChild; + + int elementCount; /* > 0 if this is an array */ +}; + +struct sDataAttribute { + ModelNodeType modelType; + char* name; + ModelNode* parent; + ModelNode* sibling; + ModelNode* firstChild; + + int elementCount; /* > 0 if this is an array */ + + FunctionalConstraint fc; + DataAttributeType type; + + uint8_t triggerOptions; /* TRG_OPT_DATA_CHANGED | TRG_OPT_QUALITY_CHANGED | TRG_OPT_DATA_UPDATE */ + + MmsValue* mmsValue; + + uint32_t sAddr; +}; + +typedef struct sDataSetEntry { + char* logicalDeviceName; + bool isLDNameDynamicallyAllocated; + char* variableName; + int index; + char* componentName; + MmsValue* value; + struct sDataSetEntry* sibling; +} DataSetEntry; + +struct sDataSet { + char* logicalDeviceName; + char* name; /* eg. MMXU1$dataset1 */ + int elementCount; + DataSetEntry* fcdas; + DataSet* sibling; +}; + +struct sReportControlBlock { + LogicalNode* parent; + char* name; + char* rptId; + bool buffered; + char* dataSetName; /* pre loaded with relative name in logical node */ + + uint32_t confRef; /* ConfRef - configuration revision */ + uint8_t trgOps; /* TrgOps - trigger conditions */ + uint8_t options; /* OptFlds */ + uint32_t bufferTime; /* BufTm - time to buffer events until a report is generated */ + uint32_t intPeriod; /* IntgPd - integrity period */ + + ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ +}; + +struct sSettingGroupControlBlock { + LogicalNode* parent; + + uint8_t actSG; /* value from SCL file */ + uint8_t numOfSGs; /* value from SCL file */ + + uint8_t editSG; /* 0 at power-up */ + bool cnfEdit; /* false at power-up */ + uint64_t timestamp; + uint16_t resvTms; + + SettingGroupControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ +}; + +typedef struct { + uint8_t vlanPriority; + uint16_t vlanId; + uint16_t appId; + uint8_t dstAddress[6]; +} PhyComAddress; + +struct sGSEControlBlock { + LogicalNode* parent; + char* name; + char* appId; + char* dataSetName; /* pre loaded with relative name in logical node */ + uint32_t confRef; /* ConfRef - configuration revision */ + bool fixedOffs; /* fixed offsets */ + PhyComAddress* address; /* GSE communication parameters */ + int minTime; /* optional minTime parameter --> -1 if not present */ + int maxTime; /* optional maxTime parameter --> -1 if not present */ + GSEControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ +}; + +/** + * \brief get the number of direct children of a model node + * + * \param self the model node instance + * + * \return the number of children of the model node + * ¸ + */ +int +ModelNode_getChildCount(ModelNode* self); + +/** + * \brief return a child model node + * + * \param self the model node instance + * \param name the name of the child model node + * + * \return the model node instance or NULL if model node does not exist. + */ +ModelNode* +ModelNode_getChild(ModelNode* self, const char* name); + +/** + * \brief return a child model node with a given functional constraint + * + * Sometimes the name is not enough to identify a model node. This is the case when + * editable setting groups are used. In this case the setting group members have two different + * model nodes associated that differ in their FC (SG and SE). + * + * \param self the model node instance + * \param name the name of the child model node + * \param fc the functional constraint of the model node + * + * \return the model node instance or NULL if model node does not exist. + */ +ModelNode* +ModelNode_getChildWithFc(ModelNode* self, const char* name, FunctionalConstraint fc); + +/** + * \brief Return the IEC 61850 object reference of a model node + * + * \param self the model node instance + * \param objectReference pointer to a buffer where to write the object reference string. If NULL + * is given the buffer is allocated by the function. + * + * \return the object reference string + */ +char* +ModelNode_getObjectReference(ModelNode* self, char* objectReference); + +/** + * \brief Set the name of the IED + * + * This will change the default name (usualy "TEMPLATE") to a user configured values. + * NOTE: This function has to be called before IedServer_create ! + * + * \param model the IedModel instance + * \param the name of the configured IED + */ +void +IedModel_setIedName(IedModel* self, const char* iedName); + +/** + * \brief Lookup a model node by its object reference + * + * This function uses the full logical device name as part of the object reference + * as it happens to appear on the wire. E.g. if IED name in SCL file would be "IED1" + * and the logical device "WD1" the resulting LD name would be "IED1WD". + * + * \param model the IedModel instance that holds the model node + * \param objectReference the IEC 61850 object reference + * + * \return the model node instance or NULL if model node does not exist. + */ +ModelNode* +IedModel_getModelNodeByObjectReference(IedModel* model, const char* objectReference); + +/** + * \brief Lookup a model node by its short (normalized) reference + * + * This version uses the object reference that does not contain the + * IED name as part of the logical device name. This function is useful for + * devices where the IED name can be configured. + * + * \param model the IedModel instance that holds the model node + * \param objectReference the IEC 61850 object reference + * + * \return the model node instance or NULL if model node does not exist. + */ +ModelNode* +IedModel_getModelNodeByShortObjectReference(IedModel* model, const char* objectReference); + +/** + * \brief Lookup a model node by its short address + * + * Short address is a 32 bit unsigned integer as specified in the "sAddr" attribute of + * the ICD file or in the configuration file. + * + * \param model the IedModel instance that holds the model node + * \param shortAddress + * + * \return the model node instance or NULL if model node does not exist. + */ +ModelNode* +IedModel_getModelNodeByShortAddress(IedModel* model, uint32_t shortAddress); + +/** + * \brief Lookup a logical node by name that is part of the given logical device + * + * \param device the logical device instance + * \param lnName the logical node name + * + * \return the logical device instance or NULL if it does not exist + */ +LogicalNode* +LogicalDevice_getLogicalNode(LogicalDevice* device, const char* lnName); + +/** + * \brief Get the setting group control block (SGCB) of the logical device + * + * \param device the logical device instance + * + * \return the SGCB instance or NULL if no SGCB is available + */ +SettingGroupControlBlock* +LogicalDevice_getSettingGroupControlBlock(LogicalDevice* device); + +/**@}*/ + +/**@}*/ + + +/** + * \brief unset all MmsValue references in the data model + * + * \param model the IedModel instance that holds the model node + */ +void +IedModel_setAttributeValuesToNull(IedModel* iedModel); + +LogicalDevice* +IedModel_getDevice(IedModel* model, const char* deviceName); + +/* + * \param dataSetReference MMS mapping object reference! e.g. ied1Inverter/LLN0$dataset1 + */ +DataSet* +IedModel_lookupDataSet(IedModel* model, const char* dataSetReference); + +int +IedModel_getLogicalDeviceCount(IedModel* iedModel); + +int +LogicalDevice_getLogicalNodeCount(LogicalDevice* logicalDevice); + +ModelNode* +LogicalDevice_getChildByMmsVariableName(LogicalDevice* logicalDevice, const char* mmsVariableName); + +bool +LogicalNode_hasFCData(LogicalNode* node, FunctionalConstraint fc); + +bool +LogicalNode_hasBufferedReports(LogicalNode* node); + +bool +LogicalNode_hasUnbufferedReports(LogicalNode* node); + +/** + * \brief get a data set instance + * + * \param self the logical node instance of the data set + * \param dataSetName the name of the data set + * + * \return the data set instance or NULL if the data set does not exist + */ +DataSet* +LogicalNode_getDataSet(LogicalNode* self, const char* dataSetName); + +bool +DataObject_hasFCData(DataObject* dataObject, FunctionalConstraint fc); + +DataAttribute* +IedModel_lookupDataAttributeByMmsValue(IedModel* model, MmsValue* value); + +#ifdef __cplusplus +} +#endif + + +#endif /* MODEL_H_ */ diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h new file mode 100644 index 0000000..1af1dba --- /dev/null +++ b/src/iec61850/inc/iec61850_server.h @@ -0,0 +1,1013 @@ +/* + * iec61850_server.h + * + * IEC 61850 server API for libiec61850. + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + * + */ + +#ifndef IED_SERVER_API_H_ +#define IED_SERVER_API_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup server_api_group IEC 61850 server API + * @{ + */ + +#include "mms_server.h" +#include "iec61850_dynamic_model.h" +#include "iec61850_model.h" +#include "hal_filesystem.h" +#include "iec61850_config_file_parser.h" + +/** + * An opaque handle for an IED server instance + */ +typedef struct sIedServer* IedServer; + +/** + * An opaque handle for a client connection + */ +typedef struct sClientConnection* ClientConnection; + +/** + * @defgroup IEC61850_SERVER_GENERAL General server setup and management functions + * + * @{ + */ + + +/** + * \brief Create a new IedServer instance + * + * \param iedModel reference to the IedModel data structure to be used as IEC 61850 model of the device + * + * \return the newly generated IedServer instance + */ +IedServer +IedServer_create(IedModel* iedModel); + +/** + * \brief Destroy an IedServer instance and release all resources (memory, TCP sockets) + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_destroy(IedServer self); + +/** + * \brief Start handling client connections + * + * \param self the instance of IedServer to operate on. + * \param tcpPort the TCP port the server is listening + */ +void +IedServer_start(IedServer self, int tcpPort); + +/** + * \brief Stop handling client connections + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_stop(IedServer self); + +/** + * \brief Start handling client connection for non-threaded mode + * + * This function will instruct the TCP(IP stack to listen for incoming connections. + * In order to accept new connection the function IedServer_processIncomingData has to + * be called periodically. + * + * \param self the instance of IedServer to operate on. + * \param tcpPort the TCP port the server is listening + */ +void +IedServer_startThreadless(IedServer self, int tcpPort); + +int +IedServer_waitReady(IedServer self, unsigned int timeoutMs); + +/** + * \brief handle incoming TCP data in non-threaded mode + * + * The function should be called periodically. If the function is called more often + * the response time for incoming messages will be faster. As an alternative the + * function may only be called if new TCP data is available. + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_processIncomingData(IedServer self); + +/** + * \brief perform periodic background tasks in non-threaded mode + * + * The function should be called periodically. If the function is called more often + * the more accurate are internal timeouts (e.g. for reports). + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_performPeriodicTasks(IedServer self); + +/** + * \brief Stop handling client connections for non-threaded mode + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_stopThreadless(IedServer self); + +/** + * \brief Return the data model of the server + * + * \param self the instance of IedServer to operate on. + * + * \return the IedModel* instance of the server + */ +IedModel* +IedServer_getDataModel(IedServer self); + +/** + * \brief Check if IedServer instance is listening for client connections + * + * \param self the instance of IedServer to operate on. + * + * \return true if IedServer instance is listening for client connections + */ +bool +IedServer_isRunning(IedServer self); + +/** + * \brief Get access to the underlying MmsServer instance. + * + * This function should be handled with care. Since direct interaction with the + * MmsServer can interfere with the IedServer. + * + * \param self the instance of IedServer to operate on. + * + * \return MmsServer instance that is used by the IedServer + */ +MmsServer +IedServer_getMmsServer(IedServer self); + +/** + * \brief get the IsoServer instance for this IedServer object + * + * \param self the instance of IedServer to operate on. + * + * \return the IsoServer instance of this IedServer object + */ +IsoServer +IedServer_getIsoServer(IedServer self); + +/** + * \brief Enable all GOOSE control blocks. + * + * This will set the GoEna attribute of all configured GOOSE control blocks + * to true. If this method is not called at the startup or reset of the server + * then configured GOOSE control blocks keep inactive until a MMS client enables + * them by writing to the GOOSE control block. + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_enableGoosePublishing(IedServer self); + +/** + * \brief Disable all GOOSE control blocks. + * + * This will set the GoEna attribute of all configured GOOSE control blocks + * to false. This will stop GOOSE transmission. + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_disableGoosePublishing(IedServer self); + +/** + * \brief Set the ethernet interface to be used by GOOSE publishing + * + * This function can be used to set the GOOSE interface ID. If not used or set to NULL the + * default interface ID from stack_config.h is used. Note the interface ID is operating system + * specific! + * + * \param self the instance of IedServer to operate on. + * \param interfaceId the ID of the ethernet interface to be used for GOOSE publishing + */ +void +IedServer_setGooseInterfaceId(IedServer self, const char* interfaceId); + +/**@}*/ + +/** + * @defgroup IEC61850_SERVER_CONNECTION_HANDLING Connection handling and client authentication + * + * @{ + */ + +/** + * \brief set the authenticator for this server + * + * This function sets a user specified authenticator that is used to identify and authenticate clients that + * wants to connect. The authenticator is called on each connection attempt. Depending on the return value + * of the authenticator the client connection is accepted or refused. If no authenticator is set all client + * connections are accepted. + * + * \param self the instance of IedServer to operate on. + * \param authenticator the user provided authenticator callback + * \param authenticatorParameter user provided paremeter that is passed to the authenticator + */ +void +IedServer_setAuthenticator(IedServer self, AcseAuthenticator authenticator, void* authenticatorParameter); + + + +/** + * \brief get the peer address of this connection as string + * + * Note: the returned string is only valid as long as the client connection exists. It is save to use + * the string inside of the connection indication callback function. + * + * \param self the ClientConnection instance + * \return peer address as C string. + */ +const char* +ClientConnection_getPeerAddress(ClientConnection self); + +/** + * \brief Get the security token associated with this connection + * + * The security token is an opaque handle that is associated with the connection. It is provided by the + * authenticator (if one is present). If no security token is used then this function returns NULL + * + * \param self the ClientConnection instance + * + * \return the security token or NULL + */ +void* +ClientConnection_getSecurityToken(ClientConnection self); + +/** + * \brief User provided callback function that is invoked whenever a new client connects or an existing connection is closed + * or detected as lost. + * + * \param self the instance of IedServer where the connection event occured. + * \param connection the new or closed client connect object + * \param connected true if a new connection is indicated, false if the connection has been closed or detected as lost. + * \param parameter a user provided parameter + */ +typedef void (*IedConnectionIndicationHandler) (IedServer self, ClientConnection connection, bool connected, void* parameter); + +/** + * \brief set a callback function that will be called on connection events (open or close). + * + * \param self the instance of IedServer to operate on. + * \param handler the user provided callback function + * \param parameter a user provided parameter that is passed to the callback function. + */ +void +IedServer_setConnectionIndicationHandler(IedServer self, IedConnectionIndicationHandler handler, void* parameter); + + +/**@}*/ + +/** + * @defgroup IEC61850_SERVER_DATA_MODEL_ACCESS Data model access and data update + * + * @{ + */ + + +/** + * \brief Lock the MMS server data model. + * + * Client requests will be postponed until the lock is removed. + * + * NOTE: This method should never be called inside of a library callback function. In the context of + * a library callback the data model is always already locked! Calling this function inside of a + * library callback may lead to a deadlock condition. + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_lockDataModel(IedServer self); + +/** + * \brief Unlock the MMS server data model and process pending client requests. + * + * NOTE: This method should never be called inside of a library callback function. In the context of + * a library callback the data model is always already locked! + * + * \param self the instance of IedServer to operate on. + */ +void +IedServer_unlockDataModel(IedServer self); + +/** + * \brief Get data attribute value + * + * Get the MmsValue object of an MMS Named Variable that is part of the device model. + * You should not manipulate the received object directly. Instead you should use + * the IedServer_updateValue method. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return MmsValue object of the MMS Named Variable or NULL if the value does not exist. + */ +MmsValue* +IedServer_getAttributeValue(IedServer self, DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of a boolean data attribute + * + * Get the value of a data attribute of type MMS_BOOLEAN. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return true or false + */ +bool +IedServer_getBooleanAttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of an integer data attribute + * + * Get the value of a data attribute of type MMS_INTEGER. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value as 32 bit integer + */ +int32_t +IedServer_getInt32AttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of an integer data attribute + * + * Get the value of a data attribute of type MMS_INTEGER. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value as 64 bit integer + */ +int64_t +IedServer_getInt64AttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of an unsigned integer data attribute + * + * Get the value of a data attribute of type MMS_UNSIGNED. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value as 32 bit unsigned integer + */ +uint32_t +IedServer_getUInt32AttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of a floating point data attribute + * + * Get the value of a data attribute of type MMS_FLOAT. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value as 32 bit float + */ +float +IedServer_getFloatAttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of a UTC time data attribute + * + * Get the value of a data attribute of type MMS_UTC_TIME. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value as 32 bit float + */ +uint64_t +IedServer_getUTCTimeAttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of a bit string data attribute as integer value + * + * Get the value of a data attribute of type MMS_BIT_STRING. If the data attribute + * is of a different type the returned value is undefined. + * NOTE: The returned integer is determined by calculating the according the follwing + * formula: bit0^0 + bit1^1 + ... + bitn^n + * It is not specified in the IEC 61850 specifications how a bit string can be interpreted + * as an integer. Therefore this function has to be used with care. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value a 32 bit integer. + */ +uint32_t +IedServer_getBitStringAttributeValue(IedServer self, const DataAttribute* dataAttribute); + +/** + * \brief Get data attribute value of a string type data attribute + * + * Get the value of a data attribute of type MMS_STRING or MMS_VISIBLE_STRING. If the data attribute + * is of a different type the returned value is undefined. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * + * \return the value as a C string (null terminated string) + */ +const char* +IedServer_getStringAttributeValue(IedServer self, const DataAttribute* dataAttribute); + + +/** + * \brief Get the MmsValue object related to a FunctionalConstrainedData object + * + * Get the MmsValue from the server cache that is associated with the Functional Constrained Data (FCD) + * object that is specified by the DataObject and the given Function Constraint (FC). + * Accessing the value will directly influence the values presented by the server. This kind of direct + * access will also bypass the report notification mechanism (i.e. changes will not cause a report!). + * Therefore this function should be used with care. It could be useful to access arrays of DataObjects. + * + * \param self the instance of IedServer to operate on. + * \param dataObject the data object to specify the FCD + * \param fc the FC to specify the FCD + * + * \return MmsValue object cached by the server. + */ +MmsValue* +IedServer_getFunctionalConstrainedData(IedServer self, DataObject* dataObject, FunctionalConstraint fc); + +/** + * \brief Update the MmsValue object of an IEC 61850 data attribute. + * + * The data attribute handle of type DataAttribute* are imported with static_model.h in the case when + * the static data model is used. + * You should use this function instead of directly operating on the MmsValue instance + * that is hold by the MMS server. Otherwise the IEC 61850 server is not aware of the + * changed value and will e.g. not generate a report. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value MmsValue object used to update the value cached by the server. + */ +void +IedServer_updateAttributeValue(IedServer self, DataAttribute* dataAttribute, MmsValue* value); + +/** + * \brief Update the value of an IEC 61850 float data attribute. + * + * Update the value of a float data attribute without handling with MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new float value of the data attribute. + */ +void +IedServer_updateFloatAttributeValue(IedServer self, DataAttribute* dataAttribute, float value); + +/** + * \brief Update the value of an IEC 61850 integer32 data attribute. + * + * Update the value of a integer data attribute without handling with MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new integer value of the data attribute. + */ +void +IedServer_updateInt32AttributeValue(IedServer self, DataAttribute* dataAttribute, int32_t value); + +/** + * \brief Update the value of an IEC 61850 integer64 data attribute (like BCR actVal) + * + * Update the value of a integer data attribute without handling with MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new 64 bit integer value of the data attribute. + */ +void +IedServer_updateInt64AttributeValue(IedServer self, DataAttribute* dataAttribute, int64_t value); + +/** + * \brief Update the value of an IEC 61850 unsigned integer data attribute. + * + * Update the value of a unsigned data attribute without handling with MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new unsigned integer value of the data attribute. + */ +void +IedServer_updateUnsignedAttributeValue(IedServer self, DataAttribute* dataAttribute, uint32_t value); + +/** + * \brief Update the value of an IEC 61850 bit string data attribute. + * + * Update the value of a bit string data attribute without handling with MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new bit string integer value of the data attribute. + */ +void +IedServer_updateBitStringAttributeValue(IedServer self, DataAttribute* dataAttribute, uint32_t value); + +/** + * \brief Update the value of an IEC 61850 boolean data attribute. + * + * Update the value of a boolean data attribute without handling with MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new boolean value of the data attribute. + */ +void +IedServer_updateBooleanAttributeValue(IedServer self, DataAttribute* dataAttribute, bool value); + +/** + * \brief Update the value of an IEC 61850 visible string data attribute. + * + * Update the value of a visible string data attribute without handling MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new visible string value of the data attribute. + */ +void +IedServer_updateVisibleStringAttributeValue(IedServer self, DataAttribute* dataAttribute, char *value); + +/** + * \brief Update the value of an IEC 61850 UTC time (timestamp) data attribute. + * + * Update the value of a UTC time data attribute without handling MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new UTC time value of the data attribute as a ms timestamp + */ +void +IedServer_updateUTCTimeAttributeValue(IedServer self, DataAttribute* dataAttribute, uint64_t value); + +/** + * \brief Update the value of an IEC 61850 UTC time (timestamp) data attribute. + * + * Update the value of a UTC time data attribute without handling MmsValue instances. + * + * This function will also check if a trigger condition is satisfied in the case when a report or GOOSE + * control block is enabled. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param value the new UTC time value of the data attribute as a Timestamp + */ +void +IedServer_updateTimestampAttributeValue(IedServer self, DataAttribute* dataAttribute, Timestamp* timestamp); + +/** + * \brief Update a quality ("q") IEC 61850 data attribute. + * + * This is a specialized function to handle Quality data attributes. It can be used instead of the more + * generic IedServer_updateAttributeValue function. + * + * This function will also check if the quality change (qchg) trigger condition is satisfied and inform a + * report control block accordingly. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute handle + * \param quality the new quality value + * + */ +void +IedServer_updateQuality(IedServer self, DataAttribute* dataAttribute, Quality quality); + +/**@}*/ + + +/** + * @defgroup IEC61850_SERVER_SETTING_GROUPS Server side setting group handling + * + * @{ + */ + +/** + * \brief Change active setting group + * + * Inform the IedServer that the active setting group has changed due to an internal event. + * Before calling this function the user should update the relevant data attributes with FC=SG! + * + * \param self the instance of IedServer to operate on. + * \param sgcb the handle of the setting group control block of the setting group + * \param newActiveSg the number of the new active setting group + */ +void +IedServer_changeActiveSettingGroup(IedServer self, SettingGroupControlBlock* sgcb, uint8_t newActiveSg); + +/** + * \brief Get the active setting group number + * + * \param self the instance of IedServer to operate on. + * \param sgcb the handle of the setting group control block of the setting group + * + * \return the number of the active setting group + */ +uint8_t +IedServer_getActiveSettingGroup(IedServer self, SettingGroupControlBlock* sgcb); + +/** + * \brief Callback handler that is invoked when the active setting group is about to be changed by an + * external client. + * + * This function is called BEFORE the active setting group is changed. The user can reject to change the + * active setting group by returning false. + * + * \param user provided parameter + * \param sgcb the setting group control block of the setting group that is about to be changed + * \param newActSg the new active setting group + * \param connection the client connection that requests the change + * + * \return true if the change is accepted, false otherwise. + * + */ +typedef bool (*ActiveSettingGroupChangedHandler) (void* parameter, SettingGroupControlBlock* sgcb, + uint8_t newActSg, ClientConnection connection); + +/** + * \brief Set the callback handler for the SetActSG event + * + * \param self the instance of IedServer to operate on. + * \param sgcb the handle of the setting group control block of the setting group. + * \param handler the user provided callback handler. + * \param parameter a user provided parameter that is passed to the control handler. + */ +void +IedServer_setActiveSettingGroupChangedHandler(IedServer self, SettingGroupControlBlock* sgcb, + ActiveSettingGroupChangedHandler handler, void* parameter); + +/** + * \brief Callback handler that is invoked when the edit setting group is about to be changed by an + * external client. + * + * In this function the user should update all SE data attributes + * associated with the given SettingGroupControlBlock. + * This function is called BEFORE the active setting group is changed. The user can reject to change the + * edit setting group by returning false. This can be used to implement RBAC. + * + * \param user provided parameter + * \param sgcb the setting group control block of the setting group that is about to be changed + * \param newEditSg the new edit setting group + * \param connection the client connection that requests the change + * + * \return true if the change is accepted, false otherwise. + * + */ +typedef bool (*EditSettingGroupChangedHandler) (void* parameter, SettingGroupControlBlock* sgcb, + uint8_t newEditSg, ClientConnection connection); + +/** + * \brief Set the callback handler for the SetEditSG event + * + * \param self the instance of IedServer to operate on. + * \param sgcb the handle of the setting group control block of the setting group. + * \param handler the user provided callback handler. + * \param parameter a user provided parameter that is passed to the control handler. + */ +void +IedServer_setEditSettingGroupChangedHandler(IedServer self, SettingGroupControlBlock* sgcb, + EditSettingGroupChangedHandler handler, void* parameter); + +/** + * \brief Callback handler that is invoked when the edit setting group has been confirmed by an + * external client. + * + * \param user provided parameter + * \param sgcb the setting group control block of the setting group that is about to be changed + * \param editSg the edit setting group that has been confirmed + * + */ +typedef void (*EditSettingGroupConfirmationHandler) (void* parameter, SettingGroupControlBlock* sgcb, + uint8_t editSg); + +/** + * \brief Set the callback handler for the COnfEditSG event + * + * \param self the instance of IedServer to operate on. + * \param sgcb the handle of the setting group control block of the setting group. + * \param handler the user provided callback handler. + * \param parameter a user provided parameter that is passed to the control handler. + */ +void +IedServer_setEditSettingGroupConfirmationHandler(IedServer self, SettingGroupControlBlock* sgcb, + EditSettingGroupConfirmationHandler handler, void* parameter); + +/**@}*/ + +/** + * @defgroup IEC61850_SERVER_CONTROL Server side control model handling + * + * @{ + */ + +/** + * \brief result code for ControlPerformCheckHandler + */ +typedef enum { + CONTROL_ACCEPTED = -1, /** check passed */ + CONTROL_HARDWARE_FAULT = 1, /** check failed due to hardware fault */ + CONTROL_TEMPORARILY_UNAVAILABLE = 2, /** control is already selected or operated */ + CONTROL_OBJECT_ACCESS_DENIED = 3, /** check failed due to access control reason - access denied for this client or state */ + CONTROL_OBJECT_UNDEFINED = 4 /** object not visible in this security context ??? */ +} CheckHandlerResult; + +/** + * \brief result codes for control handler (ControlWaitForExecutionHandler and ControlHandler) + */ +typedef enum { + CONTROL_RESULT_FAILED = 0, /** check or operation failed */ + CONTROL_RESULT_OK = 1, /** check or operation was successful */ + CONTROL_RESULT_WAITING = 2 /** check or operation is in progress */ +} ControlHandlerResult; + +/** + * \brief Control model callback to perform the static tests (optional). + * + * User provided callback function for the control model. It will be invoked after + * a control operation has been invoked by the client. This callback function is + * intended to perform the static tests. It should check if the interlock conditions + * are met if the interlockCheck parameter is true. + * + * \param parameter the parameter that was specified when setting the control handler + * \param ctlVal the control value of the control operation. + * \param test indicates if the operate request is a test operation + * \param interlockCheck the interlockCheck parameter provided by the client + * \param connection the connection object of the client connection that invoked the control operation + * + * \return CONTROL_ACCEPTED if the static tests had been successful, one of the error codes otherwise + */ +typedef CheckHandlerResult (*ControlPerformCheckHandler) (void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, + ClientConnection connection); + +/** + * \brief Control model callback to perform the dynamic tests (optional). + * + * User provided callback function for the control model. It will be invoked after + * a control operation has been invoked by the client. This callback function is + * intended to perform the dynamic tests. It should check if the synchronization conditions + * are met if the synchroCheck parameter is set to true. + * NOTE: Since version 0.7.9 this function is intended to return immediately. If the operation + * cannot be performed immediately the function SHOULD return CONTROL_RESULT_WAITING and the + * handler will be invoked again later. + * + * \param parameter the parameter that was specified when setting the control handler + * \param ctlVal the control value of the control operation. + * \param test indicates if the operate request is a test operation + * \param synchroCheck the synchroCheck parameter provided by the client + * + * \return CONTROL_RESULT_OK if the dynamic tests had been successful, CONTROL_RESULT_FAILED otherwise, + * CONTROL_RESULT_WAITING if the test is not yet finished + */ +typedef ControlHandlerResult (*ControlWaitForExecutionHandler) (void* parameter, MmsValue* ctlVal, bool test, bool synchroCheck); + +/** + * \brief Control model callback to actually perform the control operation. + * + * User provided callback function for the control model. It will be invoked when + * a control operation happens (Oper). Here the user should perform the control operation + * (e.g. by setting an digital output or switching a relay). + * NOTE: Since version 0.7.9 this function is intended to return immediately. If the operation + * cannot be performed immediately the function SHOULD return CONTROL_RESULT_WAITING and the + * handler will be invoked again later. + * + * \param parameter the parameter that was specified when setting the control handler + * \param ctlVal the control value of the control operation. + * \param test indicates if the operate request is a test operation + * + * \return CONTROL_RESULT_OK if the control action bas been successful, CONTROL_RESULT_FAILED otherwise, + * CONTROL_RESULT_WAITING if the test is not yet finished + */ +typedef ControlHandlerResult (*ControlHandler) (void* parameter, MmsValue* ctlVal, bool test); + +/** + * \brief Set control handler for controllable data object + * + * This functions sets a user provided control handler for a data object. The data object + * has to be an instance of a controllable CDC (Common Data Class) like e.g. SPC, DPC or APC. + * The control handler is a callback function that will be called by the IEC server when a + * client invokes a control operation on the data object. + * + * \param self the instance of IedServer to operate on. + * \param node the controllable data object handle + * \param handler a callback function of type ControlHandler + * \param parameter a user provided parameter that is passed to the control handler. + */ +void +IedServer_setControlHandler(IedServer self, DataObject* node, ControlHandler handler, void* parameter); + +/** + * \brief Set a handler for a controllable data object to perform operative tests + * + * This functions sets a user provided handler that should perform the operative tests for a control operation. + * Setting this handler is not required. If not set the server assumes that the checks will always be successful. + * The handler has to return true upon a successful test of false if the test fails. In the later case the control + * operation will be aborted. + * + * \param self the instance of IedServer to operate on. + * \param node the controllable data object handle + * \param handler a callback function of type ControlHandler + * \param parameter a user provided parameter that is passed to the control handler. + * + */ +void +IedServer_setPerformCheckHandler(IedServer self, DataObject* node, ControlPerformCheckHandler handler, void* parameter); + +/** + * \brief Set a handler for a controllable data object to perform dynamic tests + * + * This functions sets a user provided handler that should perform the dynamic tests for a control operation. + * Setting this handler is not required. If not set the server assumes that the checks will always be successful. + * The handler has to return true upon a successful test of false if the test fails. In the later case the control + * operation will be aborted. If this handler is set than the server will start a new thread before calling the + * handler. This thread will also be used to execute the ControlHandler. + * + * \param self the instance of IedServer to operate on. + * \param node the controllable data object handle + * \param handler a callback function of type ControlHandler + * \param parameter a user provided parameter that is passed to the control handler. + * + */ +void +IedServer_setWaitForExecutionHandler(IedServer self, DataObject* node, ControlWaitForExecutionHandler handler, void* parameter); + +/**@}*/ + +/** + * @defgroup IEC61850_SERVER_EXTERNAL_ACCESS Handle external access to data model and access control + * + * @{ + */ + +/** + * \brief callback handler to monitor client access to data attributes + * + * User provided callback function to observe (monitor) MMS client access to + * IEC 61850 data attributes. The application can install the same handler + * multiple times and distinguish data attributes by the dataAttribute parameter. + * + * \param the data attribute that has been written by an MMS client. + * \param connection the connection object of the client connection that invoked the write operation + */ +typedef void (*AttributeChangedHandler) (DataAttribute* dataAttribute, ClientConnection connection); + +/** + * \deprecated Please use IedServer_handleWriteAccess instead! + * \brief Install an observer for a data attribute. + * + * This instructs the server to monitor write attempts by MMS clients to specific + * data attributes. If a successful write attempt happens the server will call + * the provided callback function to inform the application. This can be used to + * monitor important configuration values. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute to monitor + * \param handler the callback function that is invoked if a client has written to + * the monitored data attribute. + */ +void +IedServer_observeDataAttribute(IedServer self, DataAttribute* dataAttribute, + AttributeChangedHandler handler); + +/*************************************************************************** + * Access control + **************************************************************************/ + +/** + * \brief callback handler to intercept/control client access to data attributes + * + * User provided callback function to intercept/control MMS client access to + * IEC 61850 data attributes. The application can install the same handler + * multiple times and distinguish data attributes by the dataAttribute parameter. + * This handler can be used to perform write access control do data attributes. + * One application can be to allow write access only from a specific client. Another + * application could be to check if the value is in the allowed range before the write + * is accepted. + * + * \param the data attribute that has been written by an MMS client. + * \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 parameter the user provided parameter + * + * \return true if access is accepted, false if access is denied. + */ +typedef MmsDataAccessError +(*WriteAccessHandler) (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter); + +/** + * \brief Install a WriteAccessHandler for a data attribute. + * + * This instructs the server to monitor write attempts by MMS clients to specific + * data attributes. If a client tries to write to the monitored data attribute the + * handler is invoked. The handler can decide if the write access will be allowed + * or denied. If a WriteAccessHandler is set for a specific data attribute - the + * default write access policy will not be performed for that data attribute. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute to monitor + * \param handler the callback function that is invoked if a client tries to write to + * the monitored data attribute. + * \param parameter a user provided parameter that is passed to the WriteAccessHandler when called. + */ +void +IedServer_handleWriteAccess(IedServer self, DataAttribute* dataAttribute, + WriteAccessHandler handler, void* parameter); + +typedef enum { + ACCESS_POLICY_ALLOW, + ACCESS_POLICY_DENY +} AccessPolicy; + +/** + * \brief Change the default write access policy for functional constraint data with a specific FC. + * + * \param self the instance of IedServer to operate on. + * \param fc the FC for which to change the default write access policy. + * \param policy the new policy to apply. + * + */ +void +IedServer_setWriteAccessPolicy(IedServer self, FunctionalConstraint fc, AccessPolicy policy); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* IED_SERVER_API_H_ */ diff --git a/src/iec61850/inc_private/control.h b/src/iec61850/inc_private/control.h new file mode 100644 index 0000000..cd127b0 --- /dev/null +++ b/src/iec61850/inc_private/control.h @@ -0,0 +1,103 @@ +/* + * control.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef CONTROL_H_ +#define CONTROL_H_ + +#include "iec61850_model.h" +#include "mms_server_connection.h" +#include "mms_device_model.h" +#include "iec61850_server.h" + +typedef struct sControlObject ControlObject; + +ControlObject* +ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* name); + +void +ControlObject_destroy(ControlObject* self); + +void +ControlObject_setOper(ControlObject* self, MmsValue* oper); + +void +ControlObject_setCancel(ControlObject* self, MmsValue* cancel); + +void +ControlObject_setSBO(ControlObject* self, MmsValue* sbo); + +void +ControlObject_setSBOw(ControlObject* self, MmsValue* sbow); + +void +ControlObject_setMmsValue(ControlObject* self, MmsValue* value); + +MmsValue* +ControlObject_getMmsValue(ControlObject* self); + +void +ControlObject_setTypeSpec(ControlObject* self, MmsVariableSpecification* typeSpec); + +MmsVariableSpecification* +ControlObject_getTypeSpec(ControlObject* self); + +MmsValue* +ControlObject_getOper(ControlObject* self); + +MmsValue* +ControlObject_getSBOw(ControlObject* self); + +MmsValue* +ControlObject_getSBO(ControlObject* self); + +MmsValue* +ControlObject_getCancel(ControlObject* self); + +void +ControlObject_setCtlVal(ControlObject* self, MmsValue* ctlVal); + +char* +ControlObject_getName(ControlObject* self); + +char* +ControlObject_getLNName(ControlObject* self); + +MmsDomain* +ControlObject_getDomain(ControlObject* self); + +bool +ControlObject_select(ControlObject* self, MmsServerConnection connection); + +bool +ControlObject_unselect(ControlObject* self, MmsServerConnection connection); + +void +ControlObject_installListener(ControlObject* self, ControlHandler listener, void* parameter); + +void +ControlObject_installCheckHandler(ControlObject* self, ControlPerformCheckHandler handler, void* parameter); + +void +ControlObject_installWaitForExecutionHandler(ControlObject* self, ControlWaitForExecutionHandler handler, void* parameter); + +#endif /* CONTROL_H_ */ diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h new file mode 100644 index 0000000..b2a7bb6 --- /dev/null +++ b/src/iec61850/inc_private/ied_connection_private.h @@ -0,0 +1,120 @@ +/* + * ied_connection_private.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef IED_CONNECTION_PRIVATE_H_ +#define IED_CONNECTION_PRIVATE_H_ + +#ifndef DEBUG_IED_CLIENT +#define DEBUG_IED_CLIENT 0 +#endif + +#include "hal_thread.h" + +struct sIedConnection +{ + MmsConnection connection; + IedConnectionState state; + LinkedList enabledReports; + LinkedList logicalDevices; + LinkedList clientControls; + LastApplError lastApplError; + + Semaphore stateMutex; + Semaphore reportHandlerMutex; + + IedConnectionClosedHandler connectionCloseHandler; + void* connectionClosedParameter; + uint32_t connectionTimeout; +}; + +struct sClientReportControlBlock { + char* objectReference; + bool isBuffered; + + MmsValue* rptId; + MmsValue* rptEna; + MmsValue* resv; + MmsValue* datSet; + MmsValue* confRev; + MmsValue* optFlds; + MmsValue* bufTm; + MmsValue* sqNum; + MmsValue* trgOps; + MmsValue* intgPd; + MmsValue* gi; + MmsValue* purgeBuf; + MmsValue* entryId; + MmsValue* timeOfEntry; + MmsValue* resvTms; + MmsValue* owner; +}; + +IedClientError +private_IedConnection_mapMmsErrorToIedError(MmsError mmsError); + +bool +private_IedConnection_doesControlObjectMatch(const char* objRef, const char* cntrlObj); + +void +private_IedConnection_addControlClient(IedConnection self, ControlObjectClient control); + +void +private_IedConnection_removeControlClient(IedConnection self, ControlObjectClient control); + +bool +private_ClientReportControlBlock_updateValues(ClientReportControlBlock self, MmsValue* values); + +void +private_IedConnection_handleReport(IedConnection self, MmsValue* value); + +IedClientError +iedConnection_mapMmsErrorToIedError(MmsError mmsError); + +IedClientError +iedConnection_mapDataAccessErrorToIedError(MmsDataAccessError mmsError); + +ClientReport +ClientReport_create(void); + +void +ClientReport_destroy(ClientReport self); + +void +private_ControlObjectClient_invokeCommandTerminationHandler(ControlObjectClient self); + +/* some declarations that are shared with server side ! */ + +char* +MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer); + +char* +MmsMapping_createMmsVariableNameFromObjectReference(const char* objectReference, FunctionalConstraint fc, char* buffer); + + +char* +MmsMapping_varAccessSpecToObjectReference(MmsVariableAccessSpecification* varAccessSpec); + +MmsVariableAccessSpecification* +MmsMapping_ObjectReferenceToVariableAccessSpec(char* objectReference); + +#endif /* IED_CONNECTION_PRIVATE_H_ */ diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h new file mode 100644 index 0000000..d2ae3ae --- /dev/null +++ b/src/iec61850/inc_private/ied_server_private.h @@ -0,0 +1,75 @@ +/* + * ied_server_private.h + * + * Library private function definitions for IedServer. + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + + +#ifndef IED_SERVER_PRIVATE_H_ +#define IED_SERVER_PRIVATE_H_ + +#define ALLOW_WRITE_ACCESS_DC 1 +#define ALLOW_WRITE_ACCESS_CF 2 +#define ALLOW_WRITE_ACCESS_SP 4 +#define ALLOW_WRITE_ACCESS_SV 8 +#define ALLOW_WRITE_ACCESS_SE 16 + +struct sIedServer +{ + IedModel* model; + MmsDevice* mmsDevice; + MmsServer mmsServer; + IsoServer isoServer; + MmsMapping* mmsMapping; + LinkedList clientConnections; + uint8_t writeAccessPolicies; +}; + + +ClientConnection +private_IedServer_getClientConnectionByHandle(IedServer self, void* serverConnectionHandle); + +ClientConnection +private_ClientConnection_create(void* serverConnectionHandle); + +void +private_ClientConnection_destroy(ClientConnection self); + +int +private_ClientConnection_getTasksCount(ClientConnection self); + +void +private_ClientConnection_increaseTasksCount(ClientConnection self); + +void +private_ClientConnection_decreaseTasksCount(ClientConnection self); + +void* +private_ClientConnection_getServerConnectionHandle(ClientConnection self); + +void +private_IedServer_addNewClientConnection(IedServer self, ClientConnection newClientConnection); + +void +private_IedServer_removeClientConnection(IedServer self, ClientConnection clientConnection); + +#endif /* IED_SERVER_PRIVATE_H_ */ diff --git a/src/iec61850/inc_private/mms_goose.h b/src/iec61850/inc_private/mms_goose.h new file mode 100644 index 0000000..76bd1a6 --- /dev/null +++ b/src/iec61850/inc_private/mms_goose.h @@ -0,0 +1,75 @@ +/* + * mms_goose.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_GOOSE_H_ +#define MMS_GOOSE_H_ + +typedef struct sMmsGooseControlBlock* MmsGooseControlBlock; + +MmsGooseControlBlock +MmsGooseControlBlock_create(void); + +void +MmsGooseControlBlock_destroy(MmsGooseControlBlock self); + +MmsDomain* +MmsGooseControlBlock_getDomain(MmsGooseControlBlock self); + +char* +MmsGooseControlBlock_getLogicalNodeName(MmsGooseControlBlock self); + +char* +MmsGooseControlBlock_getName(MmsGooseControlBlock self); + +MmsValue* +MmsGooseControlBlock_getGCBValue(MmsGooseControlBlock self, char* elementName); + +MmsValue* +MmsGooseControlBlock_getMmsValues(MmsGooseControlBlock self); + +MmsVariableSpecification* +MmsGooseControlBlock_getVariableSpecification(MmsGooseControlBlock self); + +DataSet* +MmsGooseControlBlock_getDataSet(MmsGooseControlBlock self); + +bool +MmsGooseControlBlock_isEnabled(MmsGooseControlBlock self); + +void +MmsGooseControlBlock_checkAndPublish(MmsGooseControlBlock self, uint64_t currentTime); + +void +MmsGooseControlBlock_observedObjectChanged(MmsGooseControlBlock self); + +void +MmsGooseControlBlock_enable(MmsGooseControlBlock self); + +void +MmsGooseControlBlock_disable(MmsGooseControlBlock self); + +MmsVariableSpecification* +GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode, int gseCount); + +#endif /* MMS_GOOSE_H_ */ diff --git a/src/iec61850/inc_private/mms_mapping.h b/src/iec61850/inc_private/mms_mapping.h new file mode 100644 index 0000000..b969b48 --- /dev/null +++ b/src/iec61850/inc_private/mms_mapping.h @@ -0,0 +1,154 @@ +/* + * mms_mapping.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_MAPPING_H_ +#define MMS_MAPPING_H_ + +#include "iec61850_model.h" +//#include "mms_server_connection.h" +#include "mms_device_model.h" +#include "control.h" + +typedef enum { + REPORT_CONTROL_NONE, + REPORT_CONTROL_VALUE_UPDATE, + REPORT_CONTROL_VALUE_CHANGED, + REPORT_CONTROL_QUALITY_CHANGED +} ReportInclusionFlag; + +typedef struct sMmsMapping MmsMapping; + +MmsMapping* +MmsMapping_create(IedModel* model); + +MmsDevice* +MmsMapping_getMmsDeviceModel(MmsMapping* mapping); + +void +MmsMapping_configureSettingGroups(MmsMapping* self); + +void +MmsMapping_checkForSettingGroupReservationTimeouts(MmsMapping* self, uint64_t currentTime); + +void +MmsMapping_setSgChangedHandler(MmsMapping* self, SettingGroupControlBlock* sgcb, + ActiveSettingGroupChangedHandler handler, void* parameter); + +void +MmsMapping_setEditSgChangedHandler(MmsMapping* self, SettingGroupControlBlock* sgcb, + EditSettingGroupChangedHandler handler, void* parameter); + +void +MmsMapping_setConfirmEditSgHandler(MmsMapping* self, SettingGroupControlBlock* sgcb, + EditSettingGroupConfirmationHandler handler, void* parameter); + +void +MmsMapping_changeActiveSettingGroup(MmsMapping* self, SettingGroupControlBlock* sgcb, uint8_t newActiveSg); + +void +MmsMapping_setMmsServer(MmsMapping* self, MmsServer server); + +void +MmsMapping_installHandlers(MmsMapping* self); + +void +MmsMapping_destroy(MmsMapping* mapping); + +void +MmsMapping_startEventWorkerThread(MmsMapping* self); + +void +MmsMapping_stopEventWorkerThread(MmsMapping* self); + +DataSet* +MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableList variableList); + +void +MmsMapping_triggerReportObservers(MmsMapping* self, MmsValue* value, ReportInclusionFlag flag); + +void +MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value); + +void +MmsMapping_enableGoosePublishing(MmsMapping* self); + +void +MmsMapping_disableGoosePublishing(MmsMapping* self); + +char* +MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer); + +void +MmsMapping_addControlObject(MmsMapping* self, ControlObject* controlObject); + +char* +MmsMapping_createMmsVariableNameFromObjectReference(const char* objectReference, FunctionalConstraint fc, char* buffer); + +void +MmsMapping_addObservedAttribute(MmsMapping* self, DataAttribute* dataAttribute, + AttributeChangedHandler handler); + +char* +MmsMapping_getNextNameElement(char* name); + +void /* Create PHYCOMADDR ACSI type instance */ +MmsMapping_createPhyComAddrStructure(MmsVariableSpecification* namedVariable); + +ControlObject* +MmsMapping_getControlObject(MmsMapping* self, MmsDomain* domain, char* lnName, char* coName); + +MmsNamedVariableList +MmsMapping_getDomainSpecificVariableList(MmsMapping* self, const char* variableListReference); + +DataSet* +MmsMapping_getDomainSpecificDataSet(MmsMapping* self, const char* dataSetName); + +void +MmsMapping_freeDynamicallyCreatedDataSet(DataSet* dataSet); + +MmsVariableAccessSpecification* +MmsMapping_ObjectReferenceToVariableAccessSpec(char* objectReference); + +char* +MmsMapping_varAccessSpecToObjectReference(MmsVariableAccessSpecification* varAccessSpec); + +void +MmsMapping_setIedServer(MmsMapping* self, IedServer iedServer); + +void +MmsMapping_setConnectionIndicationHandler(MmsMapping* self, IedConnectionIndicationHandler handler, void* parameter); + +void +MmsMapping_installWriteAccessHandler(MmsMapping* self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter); + +MmsDataAccessError +Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, + MmsValue* value, MmsServerConnection connection); + +ControlObject* +Control_lookupControlObject(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName); + +void +Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs); + +#endif /* MMS_MAPPING_H_ */ diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h new file mode 100644 index 0000000..a23fe8e --- /dev/null +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -0,0 +1,63 @@ +/* + * mms_mapping_internal.h + * + * Copyright 2013, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_MAPPING_INTERNAL_H_ +#define MMS_MAPPING_INTERNAL_H_ + +#include "stack_config.h" + +#include "hal_thread.h" +#include "linked_list.h" + +struct sMmsMapping { + IedModel* model; + MmsDevice* mmsDevice; + MmsServer mmsServer; + LinkedList reportControls; + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + LinkedList gseControls; + const char* gooseInterfaceId; +#endif + + LinkedList controlObjects; + LinkedList observedObjects; + LinkedList attributeAccessHandlers; + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + LinkedList settingGroups; +#endif + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + bool reportThreadRunning; + bool reportThreadFinished; + Thread reportWorkerThread; +#endif + + IedServer iedServer; + + IedConnectionIndicationHandler connectionIndicationHandler; + void* connectionIndicationHandlerParameter; +}; + +#endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h new file mode 100644 index 0000000..739bdf2 --- /dev/null +++ b/src/iec61850/inc_private/reporting.h @@ -0,0 +1,127 @@ +/* + * reporting.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef REPORTING_H_ +#define REPORTING_H_ + +typedef struct sReportBufferEntry ReportBufferEntry; + +struct sReportBufferEntry { + uint8_t entryId[8]; + uint8_t flags; /* bit 0 (1 = isIntegrityReport), bit 1 (1 = isGiReport) */ + uint64_t timeOfEntry; + int entryLength; + ReportBufferEntry* next; +}; + +typedef struct { + uint8_t* memoryBlock; + int memoryBlockSize; + int reportsCount; /* number of reports currently enqueued */ + ReportBufferEntry* oldestReport; + ReportBufferEntry* lastEnqueuedReport; + ReportBufferEntry* nextToTransmit; + bool isOverflow; /* true if overflow condition is active */ +} ReportBuffer; + +typedef struct { + char* name; + MmsDomain* domain; + + LogicalNode* parentLN; + + MmsValue* rcbValues; + MmsValue* inclusionField; + MmsValue* confRev; + DataSet* dataSet; + bool isDynamicDataSet; + bool enabled; + bool reserved; + bool buffered; /* true if report is a buffered report */ + + MmsValue** bufferedDataSetValues; /* used to buffer values during bufTm time */ + + MmsValue** valueReferences; /* array to store value references for fast access */ + + bool gi; + + uint16_t sqNum; + uint32_t intgPd; + uint32_t bufTm; + uint64_t nextIntgReportTime; + uint64_t reservationTimeout; + MmsServerConnection clientConnection; + + uint64_t lastEntryId; + + int triggerOps; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore createNotificationsMutex; /* { covered by mutex } */ +#endif + + ReportInclusionFlag* inclusionFlags; /* { covered by mutex } */ + bool triggered; /* { covered by mutex } */ + uint64_t reportTime; /* { covered by mutex } */ + + /* the following members are only required for buffered RCBs */ + bool isBuffering; /* true if buffered RCB is buffering (datSet is set to a valid value) */ + bool isResync; /* true if buffered RCB is in resync state */ + ReportBuffer* reportBuffer; + MmsValue* timeOfEntry; +} ReportControl; + +ReportControl* +ReportControl_create(bool buffered, LogicalNode* parentLN); + +void +ReportControl_destroy(ReportControl* self); + +void +ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, ReportInclusionFlag flag, MmsValue* value); + +MmsValue* +ReportControl_getRCBValue(ReportControl* rc, char* elementName); + +MmsVariableSpecification* +Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode, int reportsCount); + +MmsVariableSpecification* +Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode, int reportsCount); + +MmsDataAccessError +Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, + MmsServerConnection connection); + +void +Reporting_activateBufferedReports(MmsMapping* self); + +void +Reporting_processReportEvents(MmsMapping* self, uint64_t currentTimeInMs); + +void +Reporting_deactivateReportsForConnection(MmsMapping* self, MmsServerConnection connection); + +#endif /* REPORTING_H_ */ diff --git a/src/iec61850/server/impl/client_connection.c b/src/iec61850/server/impl/client_connection.c new file mode 100644 index 0000000..a492558 --- /dev/null +++ b/src/iec61850/server/impl/client_connection.c @@ -0,0 +1,138 @@ +/* + * client_connection.c + * + * Copyright 2013, 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "iso_server.h" +#include "mms_mapping.h" +#include "control.h" +#include "stack_config.h" +#include "hal_thread.h" + +#include "ied_server_private.h" + +#include "libiec61850_platform_includes.h" + +struct sClientConnection { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore tasksCountMutex; +#endif + + int tasksCount; + void* serverConnectionHandle; +}; + +ClientConnection +private_ClientConnection_create(void* serverConnectionHandle) +{ + ClientConnection self = (ClientConnection) GLOBAL_MALLOC(sizeof(struct sClientConnection)); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->tasksCountMutex = Semaphore_create(1); +#endif + + self->tasksCount = 0; + self->serverConnectionHandle = serverConnectionHandle; + + return self; +} + +void +private_ClientConnection_destroy(ClientConnection self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->tasksCountMutex); +#endif + + GLOBAL_FREEMEM(self); +} + +int +private_ClientConnection_getTasksCount(ClientConnection self) +{ + int tasksCount; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->tasksCountMutex); +#endif + + tasksCount = self->tasksCount; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->tasksCountMutex); +#endif + + return tasksCount; +} + +void +private_ClientConnection_increaseTasksCount(ClientConnection self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->tasksCountMutex); +#endif + + self->tasksCount++; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->tasksCountMutex); +#endif +} + +void +private_ClientConnection_decreaseTasksCount(ClientConnection self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->tasksCountMutex); +#endif + + self->tasksCount--; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->tasksCountMutex); +#endif +} + +void* +private_ClientConnection_getServerConnectionHandle(ClientConnection self) +{ + return self->serverConnectionHandle; +} + + +const char* +ClientConnection_getPeerAddress(ClientConnection self) +{ + MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle; + + return IsoConnection_getPeerAddress(MmsServerConnection_getIsoConnection(mmsConnection)); +} + + +void* +ClientConnection_getSecurityToken(ClientConnection self) +{ + MmsServerConnection mmsConnection = (MmsServerConnection) self->serverConnectionHandle; + + return IsoConnection_getSecurityToken(MmsServerConnection_getIsoConnection(mmsConnection)); +} diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c new file mode 100644 index 0000000..7652650 --- /dev/null +++ b/src/iec61850/server/impl/ied_server.c @@ -0,0 +1,1237 @@ +/* + * ied_server.c + * + * Copyright 2013, 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "mms_mapping.h" +#include "mms_mapping_internal.h" +#include "mms_value_internal.h" +#include "control.h" +#include "stack_config.h" +#include "ied_server_private.h" +#include "hal_thread.h" +#include "reporting.h" + +#include "libiec61850_platform_includes.h" + +#ifndef DEBUG_IED_SERVER +#define DEBUG_IED_SERVER 0 +#endif + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) +static bool +createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariableSpecification* typeSpec, char* namePrefix) +{ + MmsMapping* mapping = self->mmsMapping; + + bool success = false; + + if (typeSpec->type == MMS_STRUCTURE) { + int coCount = typeSpec->typeSpec.structure.elementCount; + int i; + for (i = 0; i < coCount; i++) { + + char objectName[65]; + objectName[0] = 0; + + if (namePrefix != NULL) { + strcat(objectName, namePrefix); + strcat(objectName, "$"); + } + + bool isControlObject = false; + bool hasCancel = false; + int cancelIndex = 0; + bool hasSBOw = false; + int sBOwIndex = 0; + int operIndex = 0; + + MmsVariableSpecification* coSpec = typeSpec->typeSpec.structure.elements[i]; + + if (coSpec->type == MMS_STRUCTURE) { + + int coElementCount = coSpec->typeSpec.structure.elementCount; + + int j; + for (j = 0; j < coElementCount; j++) { + MmsVariableSpecification* coElementSpec = coSpec->typeSpec.structure.elements[j]; + + if (strcmp(coElementSpec->name, "Oper") == 0) { + isControlObject = true; + operIndex = j; + } + else if (strcmp(coElementSpec->name, "Cancel") == 0) { + hasCancel = true; + cancelIndex = j; + } + else if (strcmp(coElementSpec->name, "SBOw") == 0) { + hasSBOw = true; + sBOwIndex = j; + } + else if (!(strcmp(coElementSpec->name, "SBO") == 0)) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: createControlObjects: Unknown element in CO: %s! --> seems not to be a control object\n", coElementSpec->name); + + break; + } + } + + if (isControlObject) { + + strcat(objectName, coSpec->name); + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: create control object LN:%s DO:%s\n", lnName, objectName); + + ControlObject* controlObject = ControlObject_create(self, domain, lnName, objectName); + + if (controlObject == NULL) + goto exit_function; + + MmsValue* structure = MmsValue_newDefaultValue(coSpec); + + if (structure == NULL) { + ControlObject_destroy(controlObject); + goto exit_function; + } + + ControlObject_setMmsValue(controlObject, structure); + + ControlObject_setTypeSpec(controlObject, coSpec); + + MmsValue* operVal = MmsValue_getElement(structure, operIndex); + ControlObject_setOper(controlObject, operVal); + + if (hasCancel) { + MmsValue* cancelVal = MmsValue_getElement(structure, cancelIndex); + ControlObject_setCancel(controlObject, cancelVal); + } + + if (hasSBOw) { + MmsValue* sbowVal = MmsValue_getElement(structure, sBOwIndex); + ControlObject_setSBOw(controlObject, sbowVal); + } + + MmsMapping_addControlObject(mapping, controlObject); + } + else { + strcat(objectName, coSpec->name); + + if (createControlObjects(self, domain, lnName, coSpec, objectName) == false) + goto exit_function; + } + } + } + } + + success = true; + +exit_function: + return success; +} +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + +static bool +createMmsServerCache(IedServer self) +{ + assert(self != NULL); + + bool success = false; + + int domain = 0; + + for (domain = 0; domain < self->mmsDevice->domainCount; domain++) { + + /* Install all top level MMS named variables (=Logical nodes) in the MMS server cache */ + MmsDomain* logicalDevice = self->mmsDevice->domains[domain]; + + int i; + + for (i = 0; i < logicalDevice->namedVariablesCount; i++) { + char* lnName = logicalDevice->namedVariables[i]->name; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Insert into cache %s - %s\n", logicalDevice->domainName, lnName); + + int fcCount = logicalDevice->namedVariables[i]->typeSpec.structure.elementCount; + int j; + + for (j = 0; j < fcCount; j++) { + MmsVariableSpecification* fcSpec = logicalDevice->namedVariables[i]->typeSpec.structure.elements[j]; + + char* fcName = fcSpec->name; + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + if (strcmp(fcName, "CO") == 0) { + createControlObjects(self, logicalDevice, lnName, fcSpec, NULL); + } + else +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + + if ((strcmp(fcName, "BR") != 0) && (strcmp(fcName, "RP") != 0) + && (strcmp(fcName, "GO") != 0)) + { + char* variableName = createString(3, lnName, "$", fcName); + + if (variableName == NULL) goto exit_function; + + MmsValue* defaultValue = MmsValue_newDefaultValue(fcSpec); + + if (defaultValue == NULL) { + GLOBAL_FREEMEM(variableName); + goto exit_function; + } + + if (DEBUG_IED_SERVER) + printf("ied_server.c: Insert into cache %s - %s\n", logicalDevice->domainName, variableName); + + MmsServer_insertIntoCache(self->mmsServer, logicalDevice, variableName, defaultValue); + + GLOBAL_FREEMEM(variableName); + } + } + } + } + + success = true; + +exit_function: + return success; +} + +static void +installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribute, + char* objectReference, int position) +{ + sprintf(objectReference + position, ".%s", dataAttribute->name); + + char mmsVariableName[65]; /* maximum size is 64 according to 61850-8-1 */ + + MmsValue* value = dataAttribute->mmsValue; + + MmsMapping_createMmsVariableNameFromObjectReference(objectReference, dataAttribute->fc, mmsVariableName); + + char domainName[65]; + + strncpy(domainName, self->model->name, 64); + + MmsMapping_getMmsDomainFromObjectReference(objectReference, domainName + strlen(domainName)); + + MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); + + if (domain == NULL) { + if (DEBUG_IED_SERVER) + printf("Error domain (%s) not found for %s!\n", domainName, objectReference); + return; + } + + MmsValue* cacheValue = MmsServer_getValueFromCache(self->mmsServer, domain, mmsVariableName); + + dataAttribute->mmsValue = cacheValue; + + if (value != NULL) { + + if (cacheValue != NULL) + MmsValue_update(cacheValue, value); + + #if (DEBUG_IED_SERVER == 1) + if (cacheValue == NULL) { + printf("IED_SERVER: exception: invalid initializer for %s\n", mmsVariableName); + exit(-1); + + //TODO else call exception handler + } + #endif + + MmsValue_delete(value); + } + + int childPosition = strlen(objectReference); + DataAttribute* subDataAttribute = (DataAttribute*) dataAttribute->firstChild; + + while (subDataAttribute != NULL) { + installDefaultValuesForDataAttribute(self, subDataAttribute, objectReference, childPosition); + + subDataAttribute = (DataAttribute*) subDataAttribute->sibling; + } +} + +static void +installDefaultValuesForDataObject(IedServer self, DataObject* dataObject, + char* objectReference, int position) +{ + if (dataObject->elementCount > 0) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: DataObject is an array. Skip installing default values in cache\n"); + + return; + } + + sprintf(objectReference + position, ".%s", dataObject->name); + + ModelNode* childNode = dataObject->firstChild; + + int childPosition = strlen(objectReference); + + while (childNode != NULL) { + if (childNode->modelType == DataObjectModelType) { + installDefaultValuesForDataObject(self, (DataObject*) childNode, objectReference, childPosition); + } + else if (childNode->modelType == DataAttributeModelType) { + installDefaultValuesForDataAttribute(self, (DataAttribute*) childNode, objectReference, childPosition); + } + + childNode = childNode->sibling; + } +} + +static void +installDefaultValuesInCache(IedServer self) +{ + IedModel* model = self->model; + + char objectReference[130]; + + LogicalDevice* logicalDevice = model->firstChild; + + while (logicalDevice != NULL) { + sprintf(objectReference, "%s", logicalDevice->name); + + LogicalNode* logicalNode = (LogicalNode*) logicalDevice->firstChild; + + char* nodeReference = objectReference + strlen(objectReference); + + while (logicalNode != NULL) { + sprintf(nodeReference, "/%s", logicalNode->name); + + DataObject* dataObject = (DataObject*) logicalNode->firstChild; + + int refPosition = strlen(objectReference); + + while (dataObject != NULL) { + installDefaultValuesForDataObject(self, dataObject, objectReference, refPosition); + + dataObject = (DataObject*) dataObject->sibling; + } + + logicalNode = (LogicalNode*) logicalNode->sibling; + } + + logicalDevice = (LogicalDevice*) logicalDevice->sibling; + } +} + +static void +updateDataSetsWithCachedValues(IedServer self) +{ + DataSet* dataSet = self->model->dataSets; + + int iedNameLength = strlen(self->model->name); + + if (iedNameLength <= 64) { + + while (dataSet != NULL) { + + DataSetEntry* dataSetEntry = dataSet->fcdas; + + while (dataSetEntry != NULL) { + + char domainName[65]; + + strncpy(domainName, self->model->name, 64); + strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedNameLength); + + MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); + + MmsValue* value = MmsServer_getValueFromCache(self->mmsServer, domain, dataSetEntry->variableName); + + if (value == NULL) { + if (DEBUG_IED_SERVER) { + printf("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; + + dataSetEntry = dataSetEntry->sibling; + } + + dataSet = dataSet->sibling; + } + } +} + +IedServer +IedServer_create(IedModel* iedModel) +{ + IedServer self = (IedServer) GLOBAL_CALLOC(1, sizeof(struct sIedServer)); + + self->model = iedModel; + + self->mmsMapping = MmsMapping_create(iedModel); + + self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping); + + self->isoServer = IsoServer_create(); + + self->mmsServer = MmsServer_create(self->isoServer, self->mmsDevice); + + MmsMapping_setMmsServer(self->mmsMapping, self->mmsServer); + + MmsMapping_installHandlers(self->mmsMapping); + + MmsMapping_setIedServer(self->mmsMapping, self); + + createMmsServerCache(self); + + iedModel->initializer(); + + installDefaultValuesInCache(self); /* This will also connect cached MmsValues to DataAttributes */ + + updateDataSetsWithCachedValues(self); + + self->clientConnections = LinkedList_create(); + + /* default write access policy allows access to SP, SE and SV FCDAs but denies access to DC and CF FCDAs */ + self->writeAccessPolicies = ALLOW_WRITE_ACCESS_SP | ALLOW_WRITE_ACCESS_SV | ALLOW_WRITE_ACCESS_SE; + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + Reporting_activateBufferedReports(self->mmsMapping); +#endif + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + MmsMapping_configureSettingGroups(self->mmsMapping); +#endif + + return self; +} + +void +IedServer_destroy(IedServer self) +{ + MmsServer_destroy(self->mmsServer); + IsoServer_destroy(self->isoServer); + MmsMapping_destroy(self->mmsMapping); + + LinkedList_destroyDeep(self->clientConnections, (LinkedListValueDeleteFunction) private_ClientConnection_destroy); + GLOBAL_FREEMEM(self); +} + +void +IedServer_setAuthenticator(IedServer self, AcseAuthenticator authenticator, void* authenticatorParameter) +{ + MmsServer_setClientAuthenticator(self->mmsServer, authenticator, authenticatorParameter); +} + +MmsServer +IedServer_getMmsServer(IedServer self) +{ + return self->mmsServer; +} + +IsoServer +IedServer_getIsoServer(IedServer self) +{ + return self->isoServer; +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +#if (CONFIG_MMS_SINGLE_THREADED == 1) +static void +singleThreadedServerThread(void* parameter) +{ + IedServer self = (IedServer) parameter; + + MmsMapping* mmsMapping = self->mmsMapping; + + bool running = true; + + mmsMapping->reportThreadFinished = false; + mmsMapping->reportThreadRunning = true; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: server thread started!\n"); + + while (running) { + + if (IedServer_waitReady(self, 25) > 0) { + MmsServer_handleIncomingMessages(self->mmsServer); + IedServer_performPeriodicTasks(self); + } + else { + IedServer_performPeriodicTasks(self); + } + + Thread_sleep(1); + + running = mmsMapping->reportThreadRunning; + } + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: server thread finished!\n"); + + mmsMapping->reportThreadFinished = true; +} +#endif /* (CONFIG_MMS_SINGLE_THREADED == 1) */ +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +IedServer_start(IedServer self, int tcpPort) +{ +#if (CONFIG_MMS_SINGLE_THREADED == 1) + MmsServer_startListeningThreadless(self->mmsServer, tcpPort); + + Thread serverThread = Thread_create((ThreadExecutionFunction) singleThreadedServerThread, (void*) self, true); + + Thread_start(serverThread); +#else + + MmsServer_startListening(self->mmsServer, tcpPort); + MmsMapping_startEventWorkerThread(self->mmsMapping); +#endif +} +#endif + +bool +IedServer_isRunning(IedServer self) +{ + if (IsoServer_getState(self->isoServer) == ISO_SVR_STATE_RUNNING) + return true; + else + return false; +} + +IedModel* +IedServer_getDataModel(IedServer self) +{ + return self->model; +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +IedServer_stop(IedServer self) +{ + MmsMapping_stopEventWorkerThread(self->mmsMapping); + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + MmsServer_stopListeningThreadless(self->mmsServer); +#else + MmsServer_stopListening(self->mmsServer); +#endif +} +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + + +void +IedServer_startThreadless(IedServer self, int tcpPort) +{ + MmsServer_startListeningThreadless(self->mmsServer, tcpPort); +} + +int +IedServer_waitReady(IedServer self, unsigned int timeoutMs) +{ + return MmsServer_waitReady(self->mmsServer, timeoutMs); +} + +void +IedServer_processIncomingData(IedServer self) +{ + MmsServer_handleIncomingMessages(self->mmsServer); +} + +void +IedServer_stopThreadless(IedServer self) +{ + MmsServer_stopListeningThreadless(self->mmsServer); +} + +void +IedServer_lockDataModel(IedServer self) +{ + MmsServer_lockModel(self->mmsServer); +} + +void +IedServer_unlockDataModel(IedServer self) +{ + MmsServer_unlockModel(self->mmsServer); +} + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) +static ControlObject* +lookupControlObject(IedServer self, DataObject* node) +{ + char objectReference[130]; + + ModelNode_getObjectReference((ModelNode*) node, objectReference); + + char* separator = strchr(objectReference, '/'); + + *separator = 0; + + MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, objectReference); + + char* lnName = separator + 1; + + separator = strchr(lnName, '.'); + + assert(separator != NULL); + + *separator = 0; + + char* objectName = separator + 1; + + StringUtils_replace(objectName, '.', '$'); + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: looking for control object: %s\n", objectName); + + ControlObject* controlObject = MmsMapping_getControlObject(self->mmsMapping, domain, + lnName, objectName); + + return controlObject; +} + +void +IedServer_setControlHandler( + IedServer self, + DataObject* node, + ControlHandler listener, + void* parameter) +{ + ControlObject* controlObject = lookupControlObject(self, node); + + if (controlObject != NULL) { + ControlObject_installListener(controlObject, listener, parameter); + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Installed control handler for %s!\n", node->name); + } + else + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Failed to install control handler!\n"); +} + +void +IedServer_setPerformCheckHandler(IedServer self, DataObject* node, ControlPerformCheckHandler handler, void* parameter) +{ + ControlObject* controlObject = lookupControlObject(self, node); + + if (controlObject != NULL) + ControlObject_installCheckHandler(controlObject, handler, parameter); +} + +void +IedServer_setWaitForExecutionHandler(IedServer self, DataObject* node, ControlWaitForExecutionHandler handler, + void* parameter) +{ + ControlObject* controlObject = lookupControlObject(self, node); + + if (controlObject != NULL) + ControlObject_installWaitForExecutionHandler(controlObject, handler, parameter); +} +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + +MmsValue* +IedServer_getAttributeValue(IedServer self, DataAttribute* dataAttribute) +{ + return dataAttribute->mmsValue; +} + +bool +IedServer_getBooleanAttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_BOOLEAN); + + return MmsValue_getBoolean(dataAttribute->mmsValue); +} + +int32_t +IedServer_getInt32AttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert((MmsValue_getType(dataAttribute->mmsValue) == MMS_INTEGER) || + (MmsValue_getType(dataAttribute->mmsValue) == MMS_UNSIGNED)); + + return MmsValue_toInt32(dataAttribute->mmsValue); +} + +int64_t +IedServer_getInt64AttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert((MmsValue_getType(dataAttribute->mmsValue) == MMS_INTEGER) || + (MmsValue_getType(dataAttribute->mmsValue) == MMS_UNSIGNED)); + + return MmsValue_toInt64(dataAttribute->mmsValue); +} + +uint32_t +IedServer_getUInt32AttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert((MmsValue_getType(dataAttribute->mmsValue) == MMS_INTEGER) || + (MmsValue_getType(dataAttribute->mmsValue) == MMS_UNSIGNED)); + + return MmsValue_toUint32(dataAttribute->mmsValue); +} + +float +IedServer_getFloatAttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_FLOAT); + + return MmsValue_toFloat(dataAttribute->mmsValue); +} + +uint64_t +IedServer_getUTCTimeAttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_UTC_TIME); + + return MmsValue_getUtcTimeInMs(dataAttribute->mmsValue); +} + +uint32_t +IedServer_getBitStringAttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_BIT_STRING); + assert(MmsValue_getBitStringSize(dataAttribute->mmsValue) < 33); + + return MmsValue_getBitStringAsInteger(dataAttribute->mmsValue); +} + +const char* +IedServer_getStringAttributeValue(IedServer self, const DataAttribute* dataAttribute) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(dataAttribute->mmsValue != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_VISIBLE_STRING); + + return MmsValue_toString(dataAttribute->mmsValue); +} + +static inline void +checkForUpdateTrigger(IedServer self, DataAttribute* dataAttribute) +{ +#if (CONFIG_IEC61850_REPORT_SERVICE== 1) + if (dataAttribute->triggerOptions & TRG_OPT_DATA_UPDATE) { + MmsMapping_triggerReportObservers(self->mmsMapping, dataAttribute->mmsValue, + REPORT_CONTROL_VALUE_UPDATE); + } +#endif +} + +static inline void +checkForChangedTriggers(IedServer self, DataAttribute* dataAttribute) +{ +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) || (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + if (dataAttribute->triggerOptions & TRG_OPT_DATA_CHANGED) { + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_triggerGooseObservers(self->mmsMapping, dataAttribute->mmsValue); +#endif + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + MmsMapping_triggerReportObservers(self->mmsMapping, dataAttribute->mmsValue, + REPORT_CONTROL_VALUE_CHANGED); +#endif + } + + else if (dataAttribute->triggerOptions & TRG_OPT_QUALITY_CHANGED) { + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_triggerGooseObservers(self->mmsMapping, dataAttribute->mmsValue); +#endif + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + MmsMapping_triggerReportObservers(self->mmsMapping, dataAttribute->mmsValue, + REPORT_CONTROL_QUALITY_CHANGED); +#endif + } +#endif /* (CONFIG_IEC61850_REPORT_SERVICE== 1) || (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + + +} + +void +IedServer_updateAttributeValue(IedServer self, DataAttribute* dataAttribute, MmsValue* value) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MmsValue_getType(value)); + + if (MmsValue_equals(dataAttribute->mmsValue, value)) + checkForUpdateTrigger(self, dataAttribute); + else { + MmsValue_update(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateFloatAttributeValue(IedServer self, DataAttribute* dataAttribute, float value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_FLOAT); + assert(dataAttribute != NULL); + assert(self != NULL); + + float currentValue = MmsValue_toFloat(dataAttribute->mmsValue); + + if (currentValue == value) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setFloat(dataAttribute->mmsValue, value); + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateInt32AttributeValue(IedServer self, DataAttribute* dataAttribute, int32_t value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_INTEGER); + assert(dataAttribute != NULL); + assert(self != NULL); + + int32_t currentValue = MmsValue_toInt32(dataAttribute->mmsValue); + + if (currentValue == value) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setInt32(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateInt64AttributeValue(IedServer self, DataAttribute* dataAttribute, int64_t value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_INTEGER); + assert(dataAttribute != NULL); + assert(self != NULL); + + int64_t currentValue = MmsValue_toInt64(dataAttribute->mmsValue); + + if (currentValue == value) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setInt64(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateUnsignedAttributeValue(IedServer self, DataAttribute* dataAttribute, uint32_t value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_UNSIGNED); + assert(dataAttribute != NULL); + assert(self != NULL); + + uint32_t currentValue = MmsValue_toUint32(dataAttribute->mmsValue); + + if (currentValue == value) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setUint32(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateBitStringAttributeValue(IedServer self, DataAttribute* dataAttribute, uint32_t value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_BIT_STRING); + assert(dataAttribute != NULL); + assert(self != NULL); + + uint32_t currentValue = MmsValue_getBitStringAsInteger(dataAttribute->mmsValue); + + if (currentValue == value) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setBitStringFromInteger(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateBooleanAttributeValue(IedServer self, DataAttribute* dataAttribute, bool value) +{ + assert(self != NULL); + assert(dataAttribute != NULL); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_BOOLEAN); + + bool currentValue = MmsValue_getBoolean(dataAttribute->mmsValue); + + if (currentValue == value) { + + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setBoolean(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateVisibleStringAttributeValue(IedServer self, DataAttribute* dataAttribute, char *value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_VISIBLE_STRING); + assert(dataAttribute != NULL); + assert(self != NULL); + + const char *currentValue = MmsValue_toString(dataAttribute->mmsValue); + + if (!strcmp(currentValue ,value)) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setVisibleString(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateUTCTimeAttributeValue(IedServer self, DataAttribute* dataAttribute, uint64_t value) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_UTC_TIME); + assert(dataAttribute != NULL); + assert(self != NULL); + + uint64_t currentValue = MmsValue_getUtcTimeInMs(dataAttribute->mmsValue); + + if (currentValue == value) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setUtcTimeMs(dataAttribute->mmsValue, value); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateTimestampAttributeValue(IedServer self, DataAttribute* dataAttribute, Timestamp* timestamp) +{ + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_UTC_TIME); + assert(dataAttribute != NULL); + assert(self != NULL); + + if (memcmp(dataAttribute->mmsValue->value.utcTime, timestamp->val, 8) == 0) { + checkForUpdateTrigger(self, dataAttribute); + } + else { + MmsValue_setUtcTimeByBuffer(dataAttribute->mmsValue, timestamp->val); + + checkForChangedTriggers(self, dataAttribute); + } +} + +void +IedServer_updateQuality(IedServer self, DataAttribute* dataAttribute, Quality quality) +{ + assert(strcmp(dataAttribute->name, "q") == 0); + assert(MmsValue_getType(dataAttribute->mmsValue) == MMS_BIT_STRING); + assert(MmsValue_getBitStringSize(dataAttribute->mmsValue) >= 12); + assert(MmsValue_getBitStringSize(dataAttribute->mmsValue) <= 15); + + uint32_t oldQuality = MmsValue_getBitStringAsInteger(dataAttribute->mmsValue); + + if (oldQuality != (uint32_t) quality) { + MmsValue_setBitStringFromInteger(dataAttribute->mmsValue, (uint32_t) quality); + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_triggerGooseObservers(self->mmsMapping, dataAttribute->mmsValue); +#endif + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + if (dataAttribute->triggerOptions & TRG_OPT_QUALITY_CHANGED) + MmsMapping_triggerReportObservers(self->mmsMapping, dataAttribute->mmsValue, + REPORT_CONTROL_QUALITY_CHANGED); +#endif + } + + +} + + +void +IedServer_enableGoosePublishing(IedServer self) +{ +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_enableGoosePublishing(self->mmsMapping); +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ +} + +void +IedServer_disableGoosePublishing(IedServer self) +{ +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_disableGoosePublishing(self->mmsMapping); +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ +} + +void +IedServer_observeDataAttribute(IedServer self, DataAttribute* dataAttribute, + AttributeChangedHandler handler) +{ + MmsMapping_addObservedAttribute(self->mmsMapping, dataAttribute, handler); +} + +void +IedServer_setWriteAccessPolicy(IedServer self, FunctionalConstraint fc, AccessPolicy policy) +{ + if (policy == ACCESS_POLICY_ALLOW) { + switch (fc) { + case IEC61850_FC_DC: + self->writeAccessPolicies |= ALLOW_WRITE_ACCESS_DC; + break; + case IEC61850_FC_CF: + self->writeAccessPolicies |= ALLOW_WRITE_ACCESS_CF; + break; + case IEC61850_FC_SP: + self->writeAccessPolicies |= ALLOW_WRITE_ACCESS_SP; + break; + case IEC61850_FC_SV: + self->writeAccessPolicies |= ALLOW_WRITE_ACCESS_SV; + break; + case IEC61850_FC_SE: + self->writeAccessPolicies |= ALLOW_WRITE_ACCESS_SE; + break; + default: /* ignore - request is invalid */ + break; + } + } + else { + switch (fc) { + case IEC61850_FC_DC: + self->writeAccessPolicies &= ~ALLOW_WRITE_ACCESS_DC; + break; + case IEC61850_FC_CF: + self->writeAccessPolicies &= ~ALLOW_WRITE_ACCESS_CF; + break; + case IEC61850_FC_SP: + self->writeAccessPolicies &= ~ALLOW_WRITE_ACCESS_SP; + break; + case IEC61850_FC_SV: + self->writeAccessPolicies &= ~ALLOW_WRITE_ACCESS_SV; + break; + case IEC61850_FC_SE: + self->writeAccessPolicies &= ALLOW_WRITE_ACCESS_SE; + break; + default: /* ignore - request is invalid */ + break; + } + } +} + +void +IedServer_handleWriteAccess(IedServer self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter) +{ + if (dataAttribute == NULL) + *((int*) NULL) = 1; + + MmsMapping_installWriteAccessHandler(self->mmsMapping, dataAttribute, handler, parameter); +} + +void +IedServer_setConnectionIndicationHandler(IedServer self, IedConnectionIndicationHandler handler, void* parameter) +{ + MmsMapping_setConnectionIndicationHandler(self->mmsMapping, handler, parameter); +} + +MmsValue* +IedServer_getFunctionalConstrainedData(IedServer self, DataObject* dataObject, FunctionalConstraint fc) +{ + char buffer[128]; /* buffer for variable name string */ + char* currentStart = buffer + 127; + currentStart[0] = 0; + MmsValue* value = NULL; + + int nameLen; + + while (dataObject->modelType == DataObjectModelType) { + nameLen = strlen(dataObject->name); + currentStart -= nameLen; + memcpy(currentStart, dataObject->name, nameLen); + currentStart--; + *currentStart = '$'; + + if (dataObject->parent->modelType == DataObjectModelType) + dataObject = (DataObject*) dataObject->parent; + else + break; + } + + char* fcString = FunctionalConstraint_toString(fc); + + currentStart--; + *currentStart = fcString[1]; + currentStart--; + *currentStart = fcString[0]; + currentStart--; + *currentStart = '$'; + + LogicalNode* ln = (LogicalNode*) dataObject->parent; + + nameLen = strlen(ln->name); + + currentStart -= nameLen; + memcpy(currentStart, ln->name, nameLen); + + LogicalDevice* ld = (LogicalDevice*) ln->parent; + + char domainName[65]; + + if ((strlen(self->model->name) + strlen(ld->name)) > 64) + goto exit_function; // TODO call exception handler! + + strncpy(domainName, self->model->name, 64); + strncat(domainName, ld->name, 64); + + MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); + + if (domain == NULL) + goto exit_function; // TODO call exception handler! + + value = MmsServer_getValueFromCache(self->mmsServer, domain, currentStart); + +exit_function: + return value; +} + +void +IedServer_changeActiveSettingGroup(IedServer self, SettingGroupControlBlock* sgcb, uint8_t newActiveSg) +{ +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + MmsMapping_changeActiveSettingGroup(self->mmsMapping, sgcb, newActiveSg); +#endif +} + +uint8_t +IedServer_getActiveSettingGroup(IedServer self, SettingGroupControlBlock* sgcb) +{ + return sgcb->actSG; +} + +void +IedServer_setActiveSettingGroupChangedHandler(IedServer self, SettingGroupControlBlock* sgcb, + ActiveSettingGroupChangedHandler handler, void* parameter) +{ +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + MmsMapping_setSgChangedHandler(self->mmsMapping, sgcb, handler, parameter); +#endif +} + +void +IedServer_setEditSettingGroupChangedHandler(IedServer self, SettingGroupControlBlock* sgcb, + EditSettingGroupChangedHandler handler, void* parameter) +{ +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + MmsMapping_setEditSgChangedHandler(self->mmsMapping, sgcb, handler, parameter); +#endif +} + +void +IedServer_setEditSettingGroupConfirmationHandler(IedServer self, SettingGroupControlBlock* sgcb, + EditSettingGroupConfirmationHandler handler, void* parameter) +{ +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + MmsMapping_setConfirmEditSgHandler(self->mmsMapping, sgcb, handler, parameter); +#endif +} + +ClientConnection +private_IedServer_getClientConnectionByHandle(IedServer self, void* serverConnectionHandle) +{ + LinkedList element = LinkedList_getNext(self->clientConnections); + ClientConnection matchingConnection = NULL; + + while (element != NULL) { + ClientConnection connection = (ClientConnection) element->data; + + if (private_ClientConnection_getServerConnectionHandle(connection) == serverConnectionHandle) { + matchingConnection = connection; + break; + } + + element = LinkedList_getNext(element); + } + + return matchingConnection; +} + +void +private_IedServer_addNewClientConnection(IedServer self, ClientConnection newClientConnection) +{ + LinkedList_add(self->clientConnections, (void*) newClientConnection); +} + +void +private_IedServer_removeClientConnection(IedServer self, ClientConnection clientConnection) +{ + LinkedList_remove(self->clientConnections, clientConnection); +} + + +void +IedServer_setGooseInterfaceId(IedServer self, const char* interfaceId) +{ +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + self->mmsMapping->gooseInterfaceId = interfaceId; +#endif +} diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c new file mode 100644 index 0000000..1e5a604 --- /dev/null +++ b/src/iec61850/server/mms_mapping/control.c @@ -0,0 +1,1591 @@ +/* + * control.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "control.h" +#include "mms_mapping.h" +#include "mms_mapping_internal.h" + +#include "mms_client_connection.h" + +#include "ied_server_private.h" + +#include "mms_value_internal.h" + +#include "libiec61850_platform_includes.h" + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + +#ifndef DEBUG_IED_SERVER +#define DEBUG_IED_SERVER 0 +#endif + +#define CONTROL_ERROR_NO_ERROR 0 +#define CONTROL_ERROR_UNKOWN 1 +#define CONTROL_ERROR_TIMEOUT_TEST 2 +#define CONTROL_ERROR_OPERATOR_TEST 3 + +#define STATE_UNSELECTED 0 +#define STATE_READY 1 +#define STATE_WAIT_FOR_ACTIVATION_TIME 2 +#define STATE_PERFORM_TEST 3 +#define STATE_WAIT_FOR_EXECUTION 4 +#define STATE_OPERATE 5 + +struct sControlObject +{ + MmsDomain* mmsDomain; + IedServer iedServer; + char* lnName; + char* name; + + int state; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore stateLock; +#endif + + MmsValue* mmsValue; + MmsVariableSpecification* typeSpec; + + MmsValue* oper; + MmsValue* sbo; + MmsValue* sbow; + MmsValue* cancel; + + MmsValue* ctlVal; + MmsValue* ctlNum; + MmsValue* origin; + MmsValue* timestamp; + + char* ctlObjectName; + + /* for LastAppIError */ + MmsValue* error; + MmsValue* addCause; + + bool selected; + uint64_t selectTime; + uint32_t selectTimeout; + MmsValue* sboClass; + MmsValue* sboTimeout; + + bool timeActivatedOperate; + uint64_t operateTime; + + bool operateOnce; + MmsServerConnection mmsConnection; + + MmsValue* emptyString; + + bool initialized; + uint32_t ctlModel; + + bool testMode; + bool interlockCheck; + bool synchroCheck; + + uint32_t operateInvokeId; + + ControlHandler operateHandler; + void* operateHandlerParameter; + + ControlPerformCheckHandler checkHandler; + void* checkHandlerParameter; + + ControlWaitForExecutionHandler waitForExecutionHandler; + void* waitForExecutionHandlerParameter; +}; + +void +ControlObject_sendLastApplError(ControlObject* self, MmsServerConnection connection, char* ctlVariable, int error, + ControlAddCause addCause, MmsValue* ctlNum, MmsValue* origin, bool handlerMode); + +void +ControlObject_sendCommandTerminationPositive(ControlObject* self); + +void +ControlObject_sendCommandTerminationNegative(ControlObject* self); + +MmsValue* +Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, + MmsServerConnection connection); + +static void +unselectObject(ControlObject* self); + +static void +setState(ControlObject* self, int newState) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->stateLock); +#endif + + self->state = newState; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->stateLock); +#endif +} + +static int +getState(ControlObject* self) +{ + int state; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->stateLock); +#endif + + state = self->state; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->stateLock); +#endif + + return state; +} + +static void +updateSboTimeoutValue(ControlObject* self) +{ + if (self->sboTimeout != NULL) { + uint32_t sboTimeoutVal = MmsValue_toInt32(self->sboTimeout); + + if (DEBUG_IED_SERVER) + printf("set timeout for %s to %u\n", self->ctlObjectName, sboTimeoutVal); + + self->selectTimeout = sboTimeoutVal; + } + else + self->selectTimeout = CONFIG_CONTROL_DEFAULT_SBO_TIMEOUT; +} + +static void +initialize(ControlObject* self) +{ + if (!(self->initialized)) { + + MmsServer mmsServer = IedServer_getMmsServer(self->iedServer); + + self->emptyString = MmsValue_newVisibleString(NULL); + + char* ctlModelName = createString(4, self->lnName, "$CF$", self->name, "$ctlModel"); + + if (DEBUG_IED_SERVER) + printf("initialize control for %s\n", ctlModelName); + + MmsValue* ctlModel = MmsServer_getValueFromCache(mmsServer, + self->mmsDomain, ctlModelName); + + if (ctlModel == NULL) { + if (DEBUG_IED_SERVER) + printf("No control model found for variable %s\n", ctlModelName); + } + + GLOBAL_FREEMEM(ctlModelName); + + char* sboClassName = createString(4, self->lnName, "$CF$", self->name, "$sboClass"); + + self->sboClass = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, sboClassName); + + GLOBAL_FREEMEM(sboClassName); + + self->ctlObjectName = (char*) GLOBAL_MALLOC(130); + + StringUtils_createStringInBuffer(self->ctlObjectName, 5, MmsDomain_getName(self->mmsDomain), "/", + self->lnName, "$CO$", self->name); + + self->error = MmsValue_newIntegerFromInt32(0); + self->addCause = MmsValue_newIntegerFromInt32(0); + + if (ctlModel != NULL) { + uint32_t ctlModelVal = MmsValue_toInt32(ctlModel); + + self->ctlModel = ctlModelVal; + + if (DEBUG_IED_SERVER) + printf(" ctlModel: %i\n", ctlModelVal); + + if ((ctlModelVal == 2) || (ctlModelVal == 4)) { /* SBO */ + char* sboTimeoutName = createString(4, self->lnName, "$CF$", self->name, "$sboTimeout"); + + char* controlObjectReference = createString(6, self->mmsDomain->domainName, "/", self->lnName, "$", + self->name, "$SBO"); + + self->sbo = MmsValue_newVisibleString(controlObjectReference); + + self->sboTimeout = MmsServer_getValueFromCache(mmsServer, + self->mmsDomain, sboTimeoutName); + + updateSboTimeoutValue(self); + + setState(self, STATE_UNSELECTED); + + if (DEBUG_IED_SERVER) + printf("timeout for %s is %i\n", sboTimeoutName, self->selectTimeout); + + GLOBAL_FREEMEM(controlObjectReference); + GLOBAL_FREEMEM(sboTimeoutName); + } + else { + self->sbo = MmsValue_newVisibleString(NULL); + + setState(self, STATE_READY); + } + } + + self->initialized = true; + } +} + +static bool +isSboClassOperateOnce(ControlObject* self) +{ + if (self->sboClass != NULL) { + if (MmsValue_toInt32(self->sboClass) == 1) + return false; + else + return true; + } + else + return true; /* default is operate-once ! */ +} + + + +static MmsValue* +getOperParameterOperTime(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + + if (MmsValue_getArraySize(operParameters) == 7) + return MmsValue_getElement(operParameters, 1); + } + + return NULL; +} + +static bool +initiateControlTask(ControlObject* self) +{ + ClientConnection iedClientConnection = + private_IedServer_getClientConnectionByHandle(self->iedServer, self->mmsConnection); + + if (iedClientConnection == NULL) + return false; + + private_ClientConnection_increaseTasksCount(iedClientConnection); + + return true; +} + +static void +exitControlTask(ControlObject* self) +{ + ClientConnection iedClientConnection = + private_IedServer_getClientConnectionByHandle(self->iedServer, self->mmsConnection); + + if (iedClientConnection == NULL) + return; + + /* synchronize with connection management */ + private_ClientConnection_decreaseTasksCount(iedClientConnection); +} + +static void +abortControlOperation(ControlObject* self) +{ + if ((self->ctlModel == 2) || (self->ctlModel == 4)) { + + if (isSboClassOperateOnce(self)) + unselectObject(self); + else + setState(self, STATE_READY); + } + else + setState(self, STATE_READY); + + exitControlTask(self); +} + +static ControlHandlerResult +operateControl(ControlObject* self, MmsValue* value, uint64_t currentTime, bool testCondition) +{ + self->selectTime = currentTime; + + if (self->operateHandler != NULL) + return self->operateHandler(self->operateHandlerParameter, value, testCondition); + + return CONTROL_RESULT_OK; +} + +static void +executeControlTask(ControlObject* self) +{ + int state; + +executeStateMachine: + + state = getState(self); + + switch (state) { + + case STATE_WAIT_FOR_ACTIVATION_TIME: + case STATE_WAIT_FOR_EXECUTION: + { + ControlHandlerResult dynamicCheckResult = CONTROL_RESULT_OK; + bool isTimeActivatedControl = false; + + if (state == STATE_WAIT_FOR_ACTIVATION_TIME) + isTimeActivatedControl = true; + + if (self->waitForExecutionHandler != NULL) { + dynamicCheckResult = self->waitForExecutionHandler(self->waitForExecutionHandlerParameter, self->ctlVal, + self->testMode, self->synchroCheck); + } + + if (dynamicCheckResult == CONTROL_RESULT_FAILED) { + if (isTimeActivatedControl) { + ControlObject_sendLastApplError(self, self->mmsConnection, "Oper", + CONTROL_ERROR_NO_ERROR, ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK, + self->ctlNum, self->origin, false); + } + else + MmsServerConnection_sendWriteResponse(self->mmsConnection, self->operateInvokeId, + DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED, true); + + abortControlOperation(self); + exitControlTask(self); + } + else if (dynamicCheckResult == CONTROL_RESULT_OK) { + if (isTimeActivatedControl) { + ControlObject_sendCommandTerminationPositive(self); + + MmsValue* operTm = getOperParameterOperTime(self->oper); + + MmsValue_setUtcTime(operTm, 0); + + } + else + MmsServerConnection_sendWriteResponse(self->mmsConnection, self->operateInvokeId, + DATA_ACCESS_ERROR_SUCCESS, true); + + setState(self, STATE_OPERATE); + + goto executeStateMachine; + } + } + break; + + case STATE_OPERATE: + { + uint64_t currentTime = Hal_getTimeInMs(); + + ControlHandlerResult result = operateControl(self, self->ctlVal, currentTime, self->testMode); + + if (result != CONTROL_RESULT_WAITING) { + + if (result == CONTROL_RESULT_OK) { + + if ((self->ctlModel == 4) || (self->ctlModel == 3)) { + ControlObject_sendCommandTerminationPositive(self); + } + } + else { + + if ((self->ctlModel == 4) || (self->ctlModel == 3)) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: operate failed!\n"); + + ControlObject_sendCommandTerminationNegative(self); + } + } + + abortControlOperation(self); + exitControlTask(self); + } + } + break; + + } +} + +ControlObject* +ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* name) +{ + ControlObject* self = (ControlObject*) GLOBAL_CALLOC(1, sizeof(ControlObject)); + + if (self == NULL) + goto exit_function; + + if (DEBUG_IED_SERVER) + printf("create control object for LD: %s, LN: %s, name: %s\n", domain->domainName, lnName, name); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->stateLock = Semaphore_create(1); + + if (self->stateLock == NULL) { + ControlObject_destroy(self); + self = NULL; + goto exit_function; + } +#endif + + self->name = copyString(name); + + if (self->name == NULL) { + ControlObject_destroy(self); + self = NULL; + goto exit_function; + } + + self->lnName = lnName; + self->mmsDomain = domain; + self->iedServer = iedServer; + +exit_function: + return self; +} + +void +ControlObject_destroy(ControlObject* self) +{ + if (self->mmsValue != NULL) + MmsValue_delete(self->mmsValue); + + if (self->sbo != NULL) + MmsValue_delete(self->sbo); + + if (self->emptyString != NULL) + MmsValue_delete(self->emptyString); + + if (self->ctlObjectName != NULL) + GLOBAL_FREEMEM(self->ctlObjectName); + + if (self->error != NULL) + MmsValue_delete(self->error); + + if (self->addCause != NULL) + MmsValue_delete(self->addCause); + + if (self->ctlVal != NULL) + MmsValue_delete(self->ctlVal); + + if (self->ctlNum != NULL) + MmsValue_delete(self->ctlNum); + + if (self->origin != NULL) + MmsValue_delete(self->origin); + + if (self->name != NULL) + GLOBAL_FREEMEM(self->name); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->stateLock != NULL) + Semaphore_destroy(self->stateLock); +#endif + + GLOBAL_FREEMEM(self); +} + +void +ControlObject_setOper(ControlObject* self, MmsValue* oper) +{ + self->oper = oper; +} + +void +ControlObject_setCancel(ControlObject* self, MmsValue* cancel) +{ + self->cancel = cancel; +} + +void +ControlObject_setSBOw(ControlObject* self, MmsValue* sbow) +{ + self->sbow = sbow; +} + +void +ControlObject_setSBO(ControlObject* self, MmsValue* sbo) +{ + self->sbo = sbo; +} + +void +ControlObject_setCtlVal(ControlObject* self, MmsValue* ctlVal) +{ + self->ctlVal = ctlVal; +} + +char* +ControlObject_getName(ControlObject* self) +{ + return self->name; +} + +char* +ControlObject_getLNName(ControlObject* self) +{ + return self->lnName; +} + +MmsDomain* +ControlObject_getDomain(ControlObject* self) +{ + return self->mmsDomain; +} + +MmsValue* +ControlObject_getOper(ControlObject* self) +{ + return self->oper; +} + +MmsValue* +ControlObject_getSBOw(ControlObject* self) +{ + return self->sbow; +} + +MmsValue* +ControlObject_getSBO(ControlObject* self) +{ + return self->sbo; +} + +MmsValue* +ControlObject_getCancel(ControlObject* self) +{ + return self->cancel; +} + +void +ControlObject_setMmsValue(ControlObject* self, MmsValue* value) +{ + self->mmsValue = value; +} + +void +ControlObject_setTypeSpec(ControlObject* self, MmsVariableSpecification* typeSpec) +{ + self->typeSpec = typeSpec; +} + +MmsVariableSpecification* +ControlObject_getTypeSpec(ControlObject* self) +{ + return self->typeSpec; +} + +MmsValue* +ControlObject_getMmsValue(ControlObject* self) +{ + return self->mmsValue; +} + +static void +selectObject(ControlObject* self, uint64_t selectTime, MmsServerConnection connection) +{ + if (DEBUG_IED_SERVER) + printf("IED_SERVER: control %s selected\n", self->ctlObjectName); + + updateSboTimeoutValue(self); + self->selected = true; + self->selectTime = selectTime; + self->mmsConnection = connection; + setState(self, STATE_READY); +} + +static void +unselectObject(ControlObject* self) +{ + setState(self, STATE_UNSELECTED); + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: control %s unselected\n", self->ctlObjectName); +} + +static void +checkSelectTimeout(ControlObject* self, uint64_t currentTime) +{ + if ((self->ctlModel == 2) || (self->ctlModel == 4)) { + + if (getState(self) == STATE_READY) { + if (self->selectTimeout > 0) { + if (currentTime > (self->selectTime + self->selectTimeout)) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: select-timeout (timeout-val = %i) for control %s\n", + self->selectTimeout, self->ctlObjectName); + + unselectObject(self); + } + } + } + } +} + +bool +ControlObject_unselect(ControlObject* self, MmsServerConnection connection) +{ + if (self->mmsConnection == connection) { + abortControlOperation(self); + return true; + } + else + return false; +} + +void +ControlObject_installListener(ControlObject* self, ControlHandler listener, void* parameter) +{ + self->operateHandler = listener; + self->operateHandlerParameter = parameter; +} + +void +ControlObject_installCheckHandler(ControlObject* self, ControlPerformCheckHandler handler, void* parameter) +{ + self->checkHandler = handler; + self->checkHandlerParameter = parameter; +} + +void +ControlObject_installWaitForExecutionHandler(ControlObject* self, ControlWaitForExecutionHandler handler, + void* parameter) +{ + self->waitForExecutionHandler = handler; + self->waitForExecutionHandlerParameter = parameter; +} + +void +Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) +{ + LinkedList element = LinkedList_getNext(self->controlObjects); + + while (element != NULL) { + ControlObject* controlObject = (ControlObject*) element->data; + + if (controlObject->state == STATE_WAIT_FOR_ACTIVATION_TIME) { + + if (controlObject->operateTime <= currentTimeInMs) { + + if (DEBUG_IED_SERVER) + printf("time activated operate: start operation\n"); + + controlObject->timeActivatedOperate = false; + + CheckHandlerResult checkResult = CONTROL_ACCEPTED; + + if (controlObject->checkHandler != NULL) { /* perform operative tests */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + controlObject->mmsConnection); + + checkResult = controlObject->checkHandler( + controlObject->checkHandlerParameter, controlObject->ctlVal, controlObject->testMode, + controlObject->interlockCheck, clientConnection); + } + + if (checkResult == CONTROL_ACCEPTED) { + executeControlTask(controlObject); + } + else { + ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper", + CONTROL_ERROR_NO_ERROR, ADD_CAUSE_BLOCKED_BY_INTERLOCKING, + controlObject->ctlNum, controlObject->origin, false); + + abortControlOperation(controlObject); + } + } + + } /* if (controlObject->state == STATE_WAIT_FOR_ACTICATION_TIME) */ + else if (!((controlObject->state == STATE_UNSELECTED) || (controlObject->state == STATE_READY))) { + executeControlTask(controlObject); + } + + element = LinkedList_getNext(element); + } +} + +ControlObject* +Control_lookupControlObject(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName) +{ + LinkedList element = LinkedList_getNext(self->controlObjects); + + while (element != NULL) { + ControlObject* controlObject = (ControlObject*) element->data; + + if (ControlObject_getDomain(controlObject) == domain) { + if (strcmp(ControlObject_getLNName(controlObject), lnName) == 0) { + if (strcmp(ControlObject_getName(controlObject), objectName) == 0) { + return controlObject; + } + } + } + + element = LinkedList_getNext(element); + } + + return NULL; +} + +static MmsValue* +getCtlVal(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getArraySize(operParameters) > 5) { + return MmsValue_getElement(operParameters, 0); + } + } + + return NULL; +} + +static MmsValue* +getOperParameterCtlNum(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getArraySize(operParameters) == 7) + return MmsValue_getElement(operParameters, 3); + else if (MmsValue_getArraySize(operParameters) == 6) + return MmsValue_getElement(operParameters, 2); + } + + return NULL; +} + +static MmsValue* +getCancelParameterCtlNum(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getArraySize(operParameters) == 6) + return MmsValue_getElement(operParameters, 3); + else if (MmsValue_getArraySize(operParameters) == 5) + return MmsValue_getElement(operParameters, 2); + } + + return NULL; +} + +static MmsValue* +getCancelParameterOrigin(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getArraySize(operParameters) == 6) + return MmsValue_getElement(operParameters, 2); + else if (MmsValue_getArraySize(operParameters) == 5) + return MmsValue_getElement(operParameters, 1); + } + + return NULL; +} + +static MmsValue* +getOperParameterTest(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { + if (MmsValue_getArraySize(operParameters) == 7) + return MmsValue_getElement(operParameters, 5); + else if (MmsValue_getArraySize(operParameters) == 6) + return MmsValue_getElement(operParameters, 4); + } + + return NULL; +} + +static MmsValue* +getOperParameterCheck(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { + if (MmsValue_getArraySize(operParameters) == 7) + return MmsValue_getElement(operParameters, 6); + else if (MmsValue_getArraySize(operParameters) == 6) + return MmsValue_getElement(operParameters, 5); + } + + return NULL; +} + +static MmsValue* +getOperParameterOrigin(MmsValue* operParameters) +{ + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { + if (MmsValue_getArraySize(operParameters) == 7) + return MmsValue_getElement(operParameters, 2); + else if (MmsValue_getArraySize(operParameters) == 6) + return MmsValue_getElement(operParameters, 1); + } + + return NULL; +} + +static MmsValue* +getOperParameterTime(MmsValue* operParameters) +{ + MmsValue* timeParameter = NULL; + + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { + if (MmsValue_getArraySize(operParameters) == 7) + timeParameter = MmsValue_getElement(operParameters, 4); + else if (MmsValue_getArraySize(operParameters) == 6) + timeParameter = MmsValue_getElement(operParameters, 3); + } + + if (timeParameter != NULL) + if ((MmsValue_getType(timeParameter) == MMS_UTC_TIME) || (MmsValue_getType(timeParameter) == MMS_BINARY_TIME)) + return timeParameter; + + return NULL; +} + +void +ControlObject_sendCommandTerminationPositive(ControlObject* self) +{ + char itemId[68]; /* 64 characters + space for FC + separator + string terminator */ + + StringUtils_createStringInBuffer(itemId, 4, self->lnName, "$CO$", self->name, "$Oper"); + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: send CommandTermination+: %s\n", itemId); + + char* domainId = MmsDomain_getName(self->mmsDomain); + + MmsVariableAccessSpecification varSpec; + + varSpec.itemId = itemId; + varSpec.domainId = domainId; + + LinkedList varSpecList = LinkedList_create(); + LinkedList values = LinkedList_create(); + + if ((varSpecList != NULL) && (values != NULL)) + { + LinkedList_add(varSpecList, &varSpec); + LinkedList_add(values, self->oper); + + MmsServerConnection_sendInformationReportListOfVariables(self->mmsConnection, varSpecList, values, false); + + LinkedList_destroyStatic(varSpecList); + LinkedList_destroyStatic(values); + } +} + +void +ControlObject_sendCommandTerminationNegative(ControlObject* self) +{ + /* create LastApplError */ + + MmsValue lastApplErrorMemory; + + MmsValue* lastApplError = &lastApplErrorMemory; + lastApplError->type = MMS_STRUCTURE; + lastApplError->value.structure.size = 5; + + MmsValue* componentContainer[5]; + + lastApplError->value.structure.components = componentContainer; + + char ctlObj[130]; + + StringUtils_createStringInBuffer(ctlObj, 2, self->ctlObjectName, "$Oper"); + + MmsValue ctlObjValueMemory; + + MmsValue* ctlObjValue = &ctlObjValueMemory; + ctlObjValue->type = MMS_VISIBLE_STRING; + ctlObjValue->value.visibleString.buf = ctlObj; + ctlObjValue->value.visibleString.size = sizeof(ctlObj); + + MmsValue_setElement(lastApplError, 0, ctlObjValue); + + MmsValue_setInt32(self->error, CONTROL_ERROR_UNKOWN); + MmsValue_setInt32(self->addCause, ADD_CAUSE_UNKNOWN); + + MmsValue_setElement(lastApplError, 1, self->error); + MmsValue_setElement(lastApplError, 2, self->origin); + MmsValue_setElement(lastApplError, 3, self->ctlNum); + MmsValue_setElement(lastApplError, 4, self->addCause); + + MmsVariableAccessSpecification lastApplErrorVarSpec; + + lastApplErrorVarSpec.itemId = "LastApplError"; + lastApplErrorVarSpec.domainId = NULL; + + /* create oper variable */ + + char itemId[130]; + + StringUtils_createStringInBuffer(itemId, 4, self->lnName, "$CO$", self->name, "$Oper"); + + char* domainId = MmsDomain_getName(self->mmsDomain); + + MmsVariableAccessSpecification operVarSpec; + + operVarSpec.itemId = itemId; + operVarSpec.domainId = domainId; + + + /* create response */ + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: send CommandTermination-: %s\n", itemId); + + LinkedList varSpecList = LinkedList_create(); + LinkedList values = LinkedList_create(); + + LinkedList_add(varSpecList, &lastApplErrorVarSpec); + LinkedList_add(varSpecList, &operVarSpec); + LinkedList_add(values, lastApplError); + LinkedList_add(values, self->oper); + + MmsServerConnection_sendInformationReportListOfVariables(self->mmsConnection, varSpecList, values, false); + + LinkedList_destroyStatic(varSpecList); + LinkedList_destroyStatic(values); +} /* ControlObject_sendCommandTerminationNegative() */ + + + +void +ControlObject_sendLastApplError(ControlObject* self, MmsServerConnection connection, char* ctlVariable, int error, + ControlAddCause addCause, MmsValue* ctlNum, MmsValue* origin, bool handlerMode) +{ + MmsValue lastApplErrorMemory; + + MmsValue* lastApplError = &lastApplErrorMemory; + lastApplError->type = MMS_STRUCTURE; + lastApplError->value.structure.size = 5; + + MmsValue* componentContainer[5]; + + lastApplError->value.structure.components =componentContainer; + + char ctlObj[130]; + + StringUtils_createStringInBuffer(ctlObj, 3, self->ctlObjectName, "$", ctlVariable); + + if (DEBUG_IED_SERVER) { + printf("IED_SERVER: sendLastApplError:\n"); + printf("IED_SERVER: control object: %s\n", ctlObj); + printf("IED_SERVER: ctlNum: %u\n", MmsValue_toUint32(ctlNum)); + } + + MmsValue ctlObjValueMemory; + + MmsValue* ctlObjValue = &ctlObjValueMemory; + ctlObjValue->type = MMS_VISIBLE_STRING; + ctlObjValue->value.visibleString.buf = ctlObj; + ctlObjValue->value.visibleString.size = sizeof(ctlObj); + + MmsValue_setElement(lastApplError, 0, ctlObjValue); + + MmsValue_setInt32(self->error, error); + MmsValue_setInt32(self->addCause, addCause); + + MmsValue_setElement(lastApplError, 1, self->error); + MmsValue_setElement(lastApplError, 2, origin); + MmsValue_setElement(lastApplError, 3, ctlNum); + MmsValue_setElement(lastApplError, 4, self->addCause); + + MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(connection, + "LastApplError", lastApplError, handlerMode); +} + +static void +updateControlParameters(ControlObject* controlObject, MmsValue* ctlVal, MmsValue* ctlNum, MmsValue* origin) +{ + if (controlObject->ctlVal != NULL) + MmsValue_delete(controlObject->ctlVal); + + if (controlObject->ctlNum != NULL) + MmsValue_delete(controlObject->ctlNum); + + if (controlObject->origin != NULL) + MmsValue_delete(controlObject->origin); + + controlObject->ctlVal = MmsValue_clone(ctlVal); + controlObject->ctlNum = MmsValue_clone(ctlNum); + controlObject->origin = MmsValue_clone(origin); +} + +static bool +doesElementEquals(char* element, char* name) +{ + int i = 0; + + while (name[i] != 0) { + if (element[i] == 0) + return false; + + if (element[i] != name[i]) + return false; + + i++; + } + + if ((element[i] != 0) && (element[i] != '$')) + return false; + + return true; +} + +MmsValue* +Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, + MmsServerConnection connection) +{ + MmsValue* value = NULL; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: readAccessControlObject: %s\n", variableIdOrig); + + char variableId[129]; + + strncpy(variableId, variableIdOrig, 128); + variableId[128] = 0; + + char* separator = strchr(variableId, '$'); + + if (separator == NULL) + return NULL; + + *separator = 0; + + char* lnName = variableId; + + if (lnName == NULL) + return NULL; + + char* objectName = MmsMapping_getNextNameElement(separator + 1); + + if (objectName == NULL) + return NULL; + + char* varName = MmsMapping_getNextNameElement(objectName); + + if (varName != NULL) { + + bool foundVar = false; + + char* nextVarName = varName; + + do { + if (doesElementEquals(varName, "Oper") || + doesElementEquals(varName, "SBO") || + doesElementEquals(varName, "SBOw") || + doesElementEquals(varName, "Cancel")) + { + *(varName - 1) = 0; + foundVar = true; + break; + } + + nextVarName = MmsMapping_getNextNameElement(varName); + + if (nextVarName != NULL) + varName = nextVarName; + + } while (nextVarName != NULL); + + if (foundVar == false) + varName = NULL; + } + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: read_access control object: objectName: (%s) varName: (%s)\n", objectName, varName); + + ControlObject* controlObject = Control_lookupControlObject(self, domain, lnName, objectName); + + if (controlObject != NULL) { + + initialize(controlObject); + + if (varName != NULL) { + if (strcmp(varName, "Oper") == 0) + value = ControlObject_getOper(controlObject); + else if (strcmp(varName, "SBOw") == 0) + value = ControlObject_getSBOw(controlObject); + else if (strcmp(varName, "SBO") == 0) { + if (controlObject->ctlModel == 2) { + + uint64_t currentTime = Hal_getTimeInMs(); + + value = controlObject->emptyString; + + checkSelectTimeout(controlObject, currentTime); + + if (getState(controlObject) == STATE_UNSELECTED) { + CheckHandlerResult checkResult = CONTROL_ACCEPTED; + + if (controlObject->checkHandler != NULL) { /* perform operative tests */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + checkResult = controlObject->checkHandler( + controlObject->checkHandlerParameter, NULL, false, false, + clientConnection); + } + + if (checkResult == CONTROL_ACCEPTED) { + selectObject(controlObject, currentTime, connection); + value = ControlObject_getSBO(controlObject); + } + } + + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: select not applicable for control model %i\n", controlObject->ctlModel); + + value = ControlObject_getSBO(controlObject); + } + } + + else if (strcmp(varName, "Cancel") == 0) + value = ControlObject_getCancel(controlObject); + else { + value = MmsValue_getSubElement(ControlObject_getMmsValue(controlObject), + ControlObject_getTypeSpec(controlObject), varName); + } + } + else + value = ControlObject_getMmsValue(controlObject); + } + + return value; +} + +//INFO: function can be removed if no certification is required +static bool +checkValidityOfOriginParameter(MmsValue* origin) +{ + if (MmsValue_getType(origin) != MMS_STRUCTURE) + return false; + + if (MmsValue_getArraySize(origin) != 2) + return false; + + MmsValue* orIdent = MmsValue_getElement(origin, 1); + + if (MmsValue_getType(orIdent) != MMS_OCTET_STRING) + return false; + + if (MmsValue_getOctetStringSize(orIdent) > 64) + return false; + + MmsValue* orCat = MmsValue_getElement(origin, 0); + + if (MmsValue_getType(orCat) != MMS_INTEGER) + return false; + + int orCatIntValue = MmsValue_toInt32(orCat); + + if ((orCatIntValue < 0) || (orCatIntValue > 8)) + return false; + + return true; +} + +static MmsDataAccessError +getDataAccessErrorFromCheckHandlerResult(CheckHandlerResult checkResult) +{ + MmsDataAccessError indication; + + if (checkResult == CONTROL_HARDWARE_FAULT) + indication = DATA_ACCESS_ERROR_HARDWARE_FAULT; + else + if (checkResult == CONTROL_TEMPORARILY_UNAVAILABLE) + indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + else + if (checkResult == CONTROL_OBJECT_UNDEFINED) + indication = DATA_ACCESS_ERROR_OBJECT_UNDEFINED; + else if (checkResult == CONTROL_OBJECT_ACCESS_DENIED) + indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + else + indication = DATA_ACCESS_ERROR_SUCCESS; + + return indication; +} + +MmsDataAccessError +Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, + MmsValue* value, MmsServerConnection connection) +{ + MmsDataAccessError indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: writeAccessControlObject: %s\n", variableIdOrig); + + char variableId[65]; + + strncpy(variableId, variableIdOrig, 64); + variableId[64] = 0; + + char* separator = strchr(variableId, '$'); + + if (separator == NULL) + goto free_and_return; + + *separator = 0; + + char* lnName = variableId; + + if (lnName == NULL) + goto free_and_return; + + char* objectName = MmsMapping_getNextNameElement(separator + 1); + + if (objectName == NULL) + goto free_and_return; + + char* varName = MmsMapping_getNextNameElement(objectName); + + if (varName != NULL) { + + bool foundVar = false; + + char* nextVarName = varName; + + do { + if (doesElementEquals(varName, "Oper") || + doesElementEquals(varName, "SBO") || + doesElementEquals(varName, "SBOw") || + doesElementEquals(varName, "Cancel")) + { + *(varName - 1) = 0; + foundVar = true; + break; + } + + nextVarName = MmsMapping_getNextNameElement(varName); + + if (nextVarName != NULL) + varName = nextVarName; + + } while (nextVarName != NULL); + + if (foundVar == false) + varName = NULL; + } + + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: write access control: objectName: (%s) varName: (%s)\n", objectName, varName); + + + if (varName == NULL) { + indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto free_and_return; + } + + ControlObject* controlObject = Control_lookupControlObject(self, domain, lnName, objectName); + + if (controlObject == NULL) { + indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto free_and_return; + } + + initialize(controlObject); + + if (strcmp(varName, "SBOw") == 0) { /* select with value */ + + if (controlObject->ctlModel == 4) { + + MmsValue* ctlVal = getCtlVal(value); + + if (ctlVal != NULL) { + + MmsValue* ctlNum = getOperParameterCtlNum(value); + MmsValue* origin = getOperParameterOrigin(value); + MmsValue* check = getOperParameterCheck(value); + MmsValue* test = getOperParameterTest(value); + + if (checkValidityOfOriginParameter(origin) == false) { + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto free_and_return; + } + + uint64_t currentTime = Hal_getTimeInMs(); + + checkSelectTimeout(controlObject, currentTime); + + int state = getState(controlObject); + + if (state != STATE_UNSELECTED) { + indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + + if (connection != controlObject->mmsConnection) + ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, + ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); + else + ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, + ADD_CAUSE_OBJECT_ALREADY_SELECTED, ctlNum, origin, true); + + if (DEBUG_IED_SERVER) + printf("SBOw: select failed!\n"); + } + else { + + CheckHandlerResult checkResult = CONTROL_ACCEPTED; + + bool interlockCheck = MmsValue_getBitStringBit(check, 1); + + bool testCondition = MmsValue_getBoolean(test); + + if (controlObject->checkHandler != NULL) { /* perform operative tests */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + checkResult = controlObject->checkHandler( + controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, + clientConnection); + } + + if (checkResult == CONTROL_ACCEPTED) { + selectObject(controlObject, currentTime, connection); + + updateControlParameters(controlObject, ctlVal, ctlNum, origin); + + indication = DATA_ACCESS_ERROR_SUCCESS; + + if (DEBUG_IED_SERVER) + printf("SBOw: selected successful\n"); + } + else { + indication = getDataAccessErrorFromCheckHandlerResult(checkResult); + + ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, + ADD_CAUSE_SELECT_FAILED, ctlNum, origin, true); + + if (DEBUG_IED_SERVER) + printf("SBOw: select rejected by application!\n"); + } + } + } + else { + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } + } + else { + indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto free_and_return; + } + } + else if (strcmp(varName, "Oper") == 0) { + MmsValue* ctlVal = getCtlVal(value); + MmsValue* test = getOperParameterTest(value); + MmsValue* ctlNum = getOperParameterCtlNum(value); + MmsValue* origin = getOperParameterOrigin(value); + MmsValue* check = getOperParameterCheck(value); + MmsValue* timeParameter = getOperParameterTime(value); + + if ((ctlVal == NULL) || (test == NULL) || (ctlNum == NULL) || (origin == NULL) || (check == NULL) + || (timeParameter == NULL)) { + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto free_and_return; + } + + if (checkValidityOfOriginParameter(origin) == false) { + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto free_and_return; + } + + uint64_t currentTime = Hal_getTimeInMs(); + + checkSelectTimeout(controlObject, currentTime); + + int state = getState(controlObject); + + if (state == STATE_WAIT_FOR_ACTIVATION_TIME) { + indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + + ControlObject_sendLastApplError(controlObject, connection, "Oper", + CONTROL_ERROR_NO_ERROR, ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION, + ctlNum, origin, true); + + goto free_and_return; + } + else if (state == STATE_READY) { + + bool interlockCheck = MmsValue_getBitStringBit(check, 1); + bool synchroCheck = MmsValue_getBitStringBit(check, 0); + + bool testCondition = MmsValue_getBoolean(test); + + controlObject->testMode = testCondition; + + if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { + if (controlObject->mmsConnection != connection) { + indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Oper - operate from wrong client connection!\n"); + goto free_and_return; + } + + if (controlObject->ctlModel == 4) { /* select-before-operate with enhanced security */ + if ((MmsValue_equals(ctlVal, controlObject->ctlVal) && + MmsValue_equals(origin, controlObject->origin) && + MmsValue_equals(ctlNum, controlObject->ctlNum)) == false) + { + + indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + ControlObject_sendLastApplError(controlObject, connection, "Oper", + CONTROL_ERROR_NO_ERROR, ADD_CAUSE_INCONSISTENT_PARAMETERS, + ctlNum, origin, true); + + goto free_and_return; + } + } + } + + updateControlParameters(controlObject, ctlVal, ctlNum, origin); + + MmsValue* operTm = getOperParameterOperTime(value); + + if (operTm != NULL) { + controlObject->operateTime = MmsValue_getUtcTimeInMs(operTm); + + if (controlObject->operateTime != 0) { + controlObject->timeActivatedOperate = true; + controlObject->synchroCheck = synchroCheck; + controlObject->interlockCheck = interlockCheck; + controlObject->mmsConnection = connection; + + initiateControlTask(controlObject); + + setState(controlObject, STATE_WAIT_FOR_ACTIVATION_TIME); + + if (DEBUG_IED_SERVER) + printf("Oper: activate time activated control\n"); + + indication = DATA_ACCESS_ERROR_SUCCESS; + } + } + + MmsValue_update(controlObject->oper, value); + + if (controlObject->timeActivatedOperate == false) { + + CheckHandlerResult checkResult = CONTROL_ACCEPTED; + + if (controlObject->checkHandler != NULL) { /* perform operative tests */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + checkResult = controlObject->checkHandler( + controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, + clientConnection); + } + + + if (checkResult == CONTROL_ACCEPTED) { + indication = DATA_ACCESS_ERROR_NO_RESPONSE; + + controlObject->mmsConnection = connection; + + controlObject->operateInvokeId = MmsServerConnection_getLastInvokeId(connection); + + setState(controlObject, STATE_WAIT_FOR_EXECUTION); + + initiateControlTask(controlObject); + +#if (CONFIG_MMS_THREADLESS_STACK == 1) + //TODO call this in single threaded version to increase response time!? + //executeControlTask(controlObject); +#endif + + } + else { + indication = getDataAccessErrorFromCheckHandlerResult(checkResult); + + abortControlOperation(controlObject); + } + } + + } + else if (state == STATE_UNSELECTED) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Oper failed - control not selected!\n"); + + indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + ControlObject_sendLastApplError(controlObject, connection, "Oper", + CONTROL_ERROR_NO_ERROR, ADD_CAUSE_OBJECT_NOT_SELECTED, + ctlNum, origin, true); + + goto free_and_return; + } + } + else if (strcmp(varName, "Cancel") == 0) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: control received cancel!\n"); + + int state = getState(controlObject); + + MmsValue* ctlNum = getCancelParameterCtlNum(value); + MmsValue* origin = getCancelParameterOrigin(value); + + if ((ctlNum == NULL) || (origin == NULL)) { + indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Invalid cancel message!\n"); + goto free_and_return; + } + + if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { + if (state != STATE_UNSELECTED) { + if (controlObject->mmsConnection == connection) { + indication = DATA_ACCESS_ERROR_SUCCESS; + unselectObject(controlObject); + goto free_and_return; + } + else { + indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + ControlObject_sendLastApplError(controlObject, connection, "Cancel", + CONTROL_ERROR_NO_ERROR, ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, + ctlNum, origin, true); + } + } + } + + if (controlObject->timeActivatedOperate) { + controlObject->timeActivatedOperate = false; + abortControlOperation(controlObject); + indication = DATA_ACCESS_ERROR_SUCCESS; + goto free_and_return; + } + } + +free_and_return: + + return indication; +} + +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + diff --git a/src/iec61850/server/mms_mapping/mms_goose.c b/src/iec61850/server/mms_mapping/mms_goose.c new file mode 100644 index 0000000..85428f3 --- /dev/null +++ b/src/iec61850/server/mms_mapping/mms_goose.c @@ -0,0 +1,591 @@ +/* + * mms_goose.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "stack_config.h" + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +#include "libiec61850_platform_includes.h" +#include "mms_mapping.h" +#include "linked_list.h" +#include "array_list.h" + +#include "hal_thread.h" + +#include "reporting.h" +#include "mms_mapping_internal.h" + +#include "mms_goose.h" +#include "goose_publisher.h" + +struct sMmsGooseControlBlock { + char* name; + bool goEna; + + char* dstAddress; + + MmsDomain* domain; + LogicalNode* logicalNode; + MmsVariableSpecification* mmsType; + MmsValue* mmsValue; + GoosePublisher publisher; + + DataSet* dataSet; + bool isDynamicDataSet; + + LinkedList dataSetValues; + uint64_t nextPublishTime; + int retransmissionsLeft; /* number of retransmissions left for the last event */ + + int minTime; + int maxTime; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore publisherMutex; +#endif + + MmsMapping* mmsMapping; + + char* goCBRef; + char* goId; + char* dataSetRef; +}; + +MmsGooseControlBlock +MmsGooseControlBlock_create() +{ + MmsGooseControlBlock self = (MmsGooseControlBlock) GLOBAL_CALLOC(1, sizeof(struct sMmsGooseControlBlock)); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->publisherMutex = Semaphore_create(1); +#endif + + return self; +} + +void +MmsGooseControlBlock_destroy(MmsGooseControlBlock self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->publisherMutex); +#endif + + if (self->publisher != NULL) + GoosePublisher_destroy(self->publisher); + + if (self->dataSetValues != NULL) + LinkedList_destroyStatic(self->dataSetValues); + + if (self->goCBRef != NULL) + GLOBAL_FREEMEM(self->goCBRef); + + if (self->goId != NULL) + GLOBAL_FREEMEM(self->goId); + + if (self->dataSetRef != NULL) + GLOBAL_FREEMEM(self->dataSetRef); + + if (self->dataSet != NULL) { + if (self->isDynamicDataSet) { + MmsMapping_freeDynamicallyCreatedDataSet(self->dataSet); + self->isDynamicDataSet = false; + self->dataSet = NULL; + } + } + + MmsValue_delete(self->mmsValue); + + GLOBAL_FREEMEM(self); +} + +MmsDomain* +MmsGooseControlBlock_getDomain(MmsGooseControlBlock self) +{ + return self->domain; +} + +DataSet* +MmsGooseControlBlock_getDataSet(MmsGooseControlBlock self) +{ + return self->dataSet; +} + +char* +MmsGooseControlBlock_getLogicalNodeName(MmsGooseControlBlock self) +{ + return self->logicalNode->name; +} + +char* +MmsGooseControlBlock_getName(MmsGooseControlBlock self) +{ + return self->name; +} + +MmsValue* +MmsGooseControlBlock_getMmsValues(MmsGooseControlBlock self) +{ + return self->mmsValue; +} + +MmsVariableSpecification* +MmsGooseControlBlock_getVariableSpecification(MmsGooseControlBlock self) +{ + return self->mmsType; +} + +bool +MmsGooseControlBlock_isEnabled(MmsGooseControlBlock self) +{ + return self->goEna; +} + +void +MmsGooseControlBlock_enable(MmsGooseControlBlock self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->publisherMutex); +#endif + + if (!MmsGooseControlBlock_isEnabled(self)) { + + if (self->dataSetRef != NULL) { + GLOBAL_FREEMEM(self->dataSetRef); + + if (self->dataSet != NULL) + if (self->isDynamicDataSet) { + MmsMapping_freeDynamicallyCreatedDataSet(self->dataSet); + self->isDynamicDataSet = false; + self->dataSet = NULL; + } + + if (self->dataSetValues != NULL) { + LinkedList_destroyStatic(self->dataSetValues); + self->dataSetValues = NULL; + } + } + + self->dataSet = NULL; + + const char* dataSetRef = MmsValue_toString(MmsValue_getElement(self->mmsValue, 2)); + + if (dataSetRef != NULL) { + + self->dataSetRef = copyString(dataSetRef); + + self->dataSet = IedModel_lookupDataSet(self->mmsMapping->model, self->dataSetRef); + + self->isDynamicDataSet = false; + + if (self->dataSet == NULL) { + self->dataSet = MmsMapping_getDomainSpecificDataSet(self->mmsMapping, self->dataSetRef); + + self->isDynamicDataSet = true; + } + + } + + if (self->dataSet != NULL) { + + MmsValue* goEna = MmsValue_getElement(self->mmsValue, 0); + + MmsValue_setBoolean(goEna, true); + + + MmsValue* dstAddress = MmsValue_getElement(self->mmsValue, 5); + + CommParameters commParameters; + commParameters.appId = MmsValue_toInt32(MmsValue_getElement(dstAddress, 3)); + commParameters.vlanId = MmsValue_toInt32(MmsValue_getElement(dstAddress, 2)); + commParameters.vlanPriority = MmsValue_toInt32(MmsValue_getElement(dstAddress, 1)); + + MmsValue* macAddress = MmsValue_getElement(dstAddress, 0); + + memcpy(commParameters.dstAddress, MmsValue_getOctetStringBuffer(macAddress), 6); + + self->publisher = GoosePublisher_create(&commParameters, self->mmsMapping->gooseInterfaceId); + + self->minTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 6)); + self->maxTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 7)); + + GoosePublisher_setTimeAllowedToLive(self->publisher, self->maxTime * 3); + + GoosePublisher_setDataSetRef(self->publisher, self->dataSetRef); + + GoosePublisher_setGoCbRef(self->publisher, self->goCBRef); + + uint32_t confRev = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 3)); + + GoosePublisher_setConfRev(self->publisher, confRev); + + bool needsCom = MmsValue_getBoolean(MmsValue_getElement(self->mmsValue, 4)); + + GoosePublisher_setNeedsCommission(self->publisher, needsCom); + + if (self->goId != NULL) + GoosePublisher_setGoID(self->publisher, self->goId); + + //prepare data set values + self->dataSetValues = LinkedList_create(); + + DataSetEntry* dataSetEntry = self->dataSet->fcdas; + + while (dataSetEntry != NULL) { + LinkedList_add(self->dataSetValues, dataSetEntry->value); + dataSetEntry = dataSetEntry->sibling; + } + + self->goEna = true; + } + + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->publisherMutex); +#endif +} + +void +MmsGooseControlBlock_disable(MmsGooseControlBlock self) +{ + if (MmsGooseControlBlock_isEnabled(self)) { + MmsValue* goEna = MmsValue_getElement(self->mmsValue, 0); + + MmsValue_setBoolean(goEna, false); + + self->goEna = false; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->publisherMutex); +#endif + + if (self->publisher != NULL) { + GoosePublisher_destroy(self->publisher); + self->publisher = NULL; + LinkedList_destroyStatic(self->dataSetValues); + self->dataSetValues = NULL; + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->publisherMutex); +#endif + } +} + + +void +MmsGooseControlBlock_checkAndPublish(MmsGooseControlBlock self, uint64_t currentTime) +{ + if (currentTime >= self->nextPublishTime) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->publisherMutex); +#endif + + GoosePublisher_publish(self->publisher, self->dataSetValues); + + if (self->retransmissionsLeft > 0) { + self->nextPublishTime = currentTime + CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL; + + + if (self->retransmissionsLeft > 1) + GoosePublisher_setTimeAllowedToLive(self->publisher, + CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL * 3); + else + GoosePublisher_setTimeAllowedToLive(self->publisher, + CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL * 3); + + self->retransmissionsLeft--; + } + else { + GoosePublisher_setTimeAllowedToLive(self->publisher, + CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL * 3); + + self->nextPublishTime = currentTime + + CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL; + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->publisherMutex); +#endif + } +} + +void +MmsGooseControlBlock_observedObjectChanged(MmsGooseControlBlock self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->publisherMutex); +#endif + + uint64_t currentTime = GoosePublisher_increaseStNum(self->publisher); + + self->retransmissionsLeft = CONFIG_GOOSE_EVENT_RETRANSMISSION_COUNT; + + if (self->retransmissionsLeft > 0) { + self->nextPublishTime = currentTime + + CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL; + + GoosePublisher_setTimeAllowedToLive(self->publisher, + CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL * 3); + } + else { + self->nextPublishTime = currentTime + + CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL; + + GoosePublisher_setTimeAllowedToLive(self->publisher, + CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL * 3); + } + + GoosePublisher_publish(self->publisher, self->dataSetValues); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->publisherMutex); +#endif +} + +static MmsVariableSpecification* +createMmsGooseControlBlock(char* gcbName) +{ + MmsVariableSpecification* gcb = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + gcb->name = copyString(gcbName); + gcb->type = MMS_STRUCTURE; + gcb->typeSpec.structure.elementCount = 9; + gcb->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(9, sizeof(MmsVariableSpecification*)); + + MmsVariableSpecification* namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("GoEna"); + namedVariable->type = MMS_BOOLEAN; + + gcb->typeSpec.structure.elements[0] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("GoID"); + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + + gcb->typeSpec.structure.elements[1] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("DatSet"); + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + + gcb->typeSpec.structure.elements[2] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("ConfRev"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + + gcb->typeSpec.structure.elements[3] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("NdsCom"); + namedVariable->type = MMS_BOOLEAN; + + gcb->typeSpec.structure.elements[4] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("DstAddress"); + MmsMapping_createPhyComAddrStructure(namedVariable); + + gcb->typeSpec.structure.elements[5] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("MinTime"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + + gcb->typeSpec.structure.elements[6] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("MaxTime"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + + gcb->typeSpec.structure.elements[7] = namedVariable; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("FixedOffs"); + namedVariable->type = MMS_BOOLEAN; + + gcb->typeSpec.structure.elements[8] = namedVariable; + + return gcb; +} + +static GSEControlBlock* +getGCBForLogicalNodeWithIndex(MmsMapping* self, LogicalNode* logicalNode, int index) +{ + int gseCount = 0; + + GSEControlBlock* gcb = self->model->gseCBs; + + /* Iterate list of GoCBs */ + while (gcb != NULL ) { + if (gcb->parent == logicalNode) { + if (gseCount == index) + return gcb; + + gseCount++; + } + + gcb = gcb->sibling; + } + + return NULL ; +} + +static char* +createDataSetReference(char* domainName, char* lnName, char* dataSetName) +{ + char* dataSetReference; + + dataSetReference = createString(5, domainName, "/", lnName, "$", dataSetName); + + return dataSetReference; +} + +MmsVariableSpecification* +GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode, int gseCount) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("GO"); + namedVariable->type = MMS_STRUCTURE; + + namedVariable->typeSpec.structure.elementCount = gseCount; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(gseCount, + sizeof(MmsVariableSpecification*)); + + int currentGCB = 0; + + while (currentGCB < gseCount) { + GSEControlBlock* gooseControlBlock = getGCBForLogicalNodeWithIndex( + self, logicalNode, currentGCB); + + MmsVariableSpecification* gseTypeSpec = createMmsGooseControlBlock(gooseControlBlock->name); + + MmsValue* gseValues = MmsValue_newStructure(gseTypeSpec); + + namedVariable->typeSpec.structure.elements[currentGCB] = gseTypeSpec; + + MmsGooseControlBlock mmsGCB = MmsGooseControlBlock_create(); + + + mmsGCB->goCBRef = createString(5, MmsDomain_getName(domain), "/", logicalNode->name, + "$GO$", gooseControlBlock->name); + + if (gooseControlBlock->appId != NULL) { + MmsValue* goID = MmsValue_getElement(gseValues, 1); + + MmsValue_setVisibleString(goID, gooseControlBlock->appId); + + mmsGCB->goId = copyString(gooseControlBlock->appId); + } + + if (gooseControlBlock->dataSetName != NULL) + mmsGCB->dataSetRef = createDataSetReference(MmsDomain_getName(domain), + logicalNode->name, gooseControlBlock->dataSetName); + else + mmsGCB->dataSetRef = NULL; + + MmsValue* dataSetRef = MmsValue_getElement(gseValues, 2); + + MmsValue_setVisibleString(dataSetRef, mmsGCB->dataSetRef); + + /* Set communication parameters */ + uint8_t priority = CONFIG_GOOSE_DEFAULT_PRIORITY; + uint8_t dstAddr[] = CONFIG_GOOSE_DEFAULT_DST_ADDRESS; + uint16_t vid = CONFIG_GOOSE_DEFAULT_VLAN_ID; + uint16_t appId = CONFIG_GOOSE_DEFAULT_APPID; + + if (gooseControlBlock->address != NULL) { + priority = gooseControlBlock->address->vlanPriority; + vid = gooseControlBlock->address->vlanId; + appId = gooseControlBlock->address->appId; + + int i; + for (i = 0; i < 6; i++) { + dstAddr[i] = gooseControlBlock->address->dstAddress[i]; + } + } + + MmsValue* dstAddress = MmsValue_getElement(gseValues, 5); + MmsValue* addr = MmsValue_getElement(dstAddress, 0); + MmsValue_setOctetString(addr, dstAddr, 6); + + MmsValue* prio = MmsValue_getElement(dstAddress, 1); + MmsValue_setUint8(prio, priority); + + MmsValue* vlanId = MmsValue_getElement(dstAddress, 2); + MmsValue_setUint16(vlanId, vid); + + MmsValue* appIdVal = MmsValue_getElement(dstAddress, 3); + MmsValue_setUint16(appIdVal, appId); + + MmsValue* confRef = MmsValue_getElement(gseValues, 3); + + MmsValue_setUint32(confRef, gooseControlBlock->confRef); + + mmsGCB->dataSet = NULL; + + mmsGCB->mmsValue = gseValues; + mmsGCB->mmsType = gseTypeSpec; + mmsGCB->name = gooseControlBlock->name; + + mmsGCB->domain = domain; + mmsGCB->logicalNode = logicalNode; + + if (gooseControlBlock->minTime == -1) + mmsGCB->minTime = CONFIG_GOOSE_EVENT_RETRANSMISSION_INTERVAL; + else + mmsGCB->minTime = gooseControlBlock->minTime; + + if (gooseControlBlock->maxTime == -1) + mmsGCB->maxTime = CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL; + else + mmsGCB->maxTime = gooseControlBlock->maxTime; + + MmsValue* minTime = MmsValue_getElement(gseValues, 6); + MmsValue_setUint32(minTime, mmsGCB->minTime); + + MmsValue* maxTime = MmsValue_getElement(gseValues, 7); + MmsValue_setUint32(maxTime, mmsGCB->maxTime); + + mmsGCB->mmsMapping = self; + + LinkedList_add(self->gseControls, mmsGCB); + + currentGCB++; + } + + return namedVariable; +} + +#endif + diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c new file mode 100644 index 0000000..b4e2246 --- /dev/null +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -0,0 +1,2994 @@ +/* + * mms_mapping.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_mapping.h" +#include "mms_mapping_internal.h" +#include "array_list.h" +#include "stack_config.h" + +#include "mms_goose.h" +#include "reporting.h" +#include "control.h" +#include "ied_server_private.h" + +#ifndef CONFIG_IEC61850_SG_RESVTMS +#define CONFIG_IEC61850_SG_RESVTMS 100 +#endif + +#ifndef DEBUG_IED_SERVER +#define DEBUG_IED_SERVER 0 +#endif + +typedef struct +{ + DataAttribute* attribute; + AttributeChangedHandler handler; +} AttributeObserver; + +typedef struct +{ + DataAttribute* attribute; + WriteAccessHandler handler; + void* parameter; +} AttributeAccessHandler; + + +typedef struct +{ + SettingGroupControlBlock* sgcb; + MmsValue* sgcbMmsValues; + MmsDomain* mmsDomain; + + ActiveSettingGroupChangedHandler actSgChangedHandler; + void* actSgChangedHandlerParameter; + + EditSettingGroupChangedHandler editSgChangedHandler; + void* editSgChangedHandlerParameter; + + EditSettingGroupConfirmationHandler editSgConfirmedHandler; + void* editSgConfirmedHandlerParameter; + + ClientConnection editingClient; + uint64_t reservationTimeout; +} SettingGroup; + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) +MmsValue* +Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, + MmsServerConnection connection); +#endif + +void /* Create PHYCOMADDR ACSI type instance */ +MmsMapping_createPhyComAddrStructure(MmsVariableSpecification* namedVariable) +{ + namedVariable->type = MMS_STRUCTURE; + namedVariable->typeSpec.structure.elementCount = 4; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(4, + sizeof(MmsVariableSpecification*)); + + MmsVariableSpecification* element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("Addr"); + element->type = MMS_OCTET_STRING; + element->typeSpec.octetString = 6; + namedVariable->typeSpec.structure.elements[0] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("PRIORITY"); + element->type = MMS_UNSIGNED; + element->typeSpec.unsignedInteger = 8; + namedVariable->typeSpec.structure.elements[1] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("VID"); + element->type = MMS_UNSIGNED; + element->typeSpec.unsignedInteger = 16; + namedVariable->typeSpec.structure.elements[2] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("APPID"); + element->type = MMS_UNSIGNED; + element->typeSpec.unsignedInteger = 16; + namedVariable->typeSpec.structure.elements[3] = element; +} + +static MmsVariableSpecification* +createNamedVariableFromDataAttribute(DataAttribute* attribute) +{ + MmsVariableSpecification* origNamedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + origNamedVariable->name = copyString(attribute->name); + + MmsVariableSpecification* namedVariable = origNamedVariable; + + if (attribute->elementCount > 0) { + namedVariable->type = MMS_ARRAY; + namedVariable->typeSpec.array.elementCount = attribute->elementCount; + namedVariable->typeSpec.array.elementTypeSpec = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable = namedVariable->typeSpec.array.elementTypeSpec; + } + + if (attribute->firstChild != NULL) { + namedVariable->type = MMS_STRUCTURE; + + int componentCount = ModelNode_getChildCount((ModelNode*) attribute); + + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(componentCount, + sizeof(MmsVariableSpecification*)); + + DataAttribute* subDataAttribute = (DataAttribute*) attribute->firstChild; + + int i = 0; + while (subDataAttribute != NULL) { + namedVariable->typeSpec.structure.elements[i] = + createNamedVariableFromDataAttribute(subDataAttribute); + + subDataAttribute = (DataAttribute*) subDataAttribute->sibling; + i++; + } + + namedVariable->typeSpec.structure.elementCount = i; + } + else { + switch (attribute->type) { + case BOOLEAN: + namedVariable->type = MMS_BOOLEAN; + break; + case INT8: + namedVariable->typeSpec.integer = 8; + namedVariable->type = MMS_INTEGER; + break; + case INT16: + namedVariable->typeSpec.integer = 16; + namedVariable->type = MMS_INTEGER; + break; + case INT32: + namedVariable->typeSpec.integer = 32; + namedVariable->type = MMS_INTEGER; + break; + case INT64: + namedVariable->typeSpec.integer = 64; + namedVariable->type = MMS_INTEGER; + break; + case INT128: + namedVariable->typeSpec.integer = 128; + namedVariable->type = MMS_INTEGER; + break; + case INT8U: + namedVariable->typeSpec.unsignedInteger = 8; + namedVariable->type = MMS_UNSIGNED; + break; + case INT16U: + namedVariable->typeSpec.unsignedInteger = 16; + namedVariable->type = MMS_UNSIGNED; + break; + case INT24U: + namedVariable->typeSpec.unsignedInteger = 24; + namedVariable->type = MMS_UNSIGNED; + break; + case INT32U: + namedVariable->typeSpec.unsignedInteger = 32; + namedVariable->type = MMS_UNSIGNED; + break; + case FLOAT32: + namedVariable->typeSpec.floatingpoint.formatWidth = 32; + namedVariable->typeSpec.floatingpoint.exponentWidth = 8; + namedVariable->type = MMS_FLOAT; + break; + case FLOAT64: + namedVariable->typeSpec.floatingpoint.formatWidth = 64; + namedVariable->typeSpec.floatingpoint.exponentWidth = 11; + namedVariable->type = MMS_FLOAT; + break; + case ENUMERATED: + namedVariable->typeSpec.integer = 8; /* 8 bit integer should be enough for all enumerations */ + namedVariable->type = MMS_INTEGER; + break; + case CHECK: + namedVariable->typeSpec.bitString = -2; + namedVariable->type = MMS_BIT_STRING; + break; + case CODEDENUM: + namedVariable->typeSpec.bitString = 2; + namedVariable->type = MMS_BIT_STRING; + break; + case OCTET_STRING_6: + namedVariable->typeSpec.octetString = -6; + namedVariable->type = MMS_OCTET_STRING; + break; + case OCTET_STRING_8: + namedVariable->typeSpec.octetString = 8; + namedVariable->type = MMS_OCTET_STRING; + break; + case OCTET_STRING_64: + namedVariable->typeSpec.octetString = -64; + namedVariable->type = MMS_OCTET_STRING; + break; + case VISIBLE_STRING_32: + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + break; + case VISIBLE_STRING_64: + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + break; + case VISIBLE_STRING_65: + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + break; + case VISIBLE_STRING_129: + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + break; + case VISIBLE_STRING_255: + namedVariable->typeSpec.visibleString = -255; + namedVariable->type = MMS_VISIBLE_STRING; + break; + case UNICODE_STRING_255: + namedVariable->typeSpec.mmsString = -255; + namedVariable->type = MMS_STRING; + break; + case GENERIC_BITSTRING: + namedVariable->type = MMS_BIT_STRING; + break; + case TIMESTAMP: + namedVariable->type = MMS_UTC_TIME; + break; + case QUALITY: + namedVariable->typeSpec.bitString = -13; // -13 = up to 13 bits + namedVariable->type = MMS_BIT_STRING; + break; + case ENTRY_TIME: + namedVariable->type = MMS_BINARY_TIME; + namedVariable->typeSpec.binaryTime = 6; + break; + case PHYCOMADDR: + MmsMapping_createPhyComAddrStructure(namedVariable); + break; + default: + if (DEBUG_IED_SERVER) + printf("MMS-MAPPING: type cannot be mapped %i\n", attribute->type); + break; + } + } + + return origNamedVariable; +} + +static int +countChildrenWithFc(DataObject* dataObject, FunctionalConstraint fc) +{ + int elementCount = 0; + + ModelNode* child = dataObject->firstChild; + + while (child != NULL) { + if (child->modelType == DataAttributeModelType) { + DataAttribute* dataAttribute = (DataAttribute*) child; + + if (dataAttribute->fc == fc) + elementCount++; + } + else if (child->modelType == DataObjectModelType) { + DataObject* subDataObject = (DataObject*) child; + + if (DataObject_hasFCData(subDataObject, fc)) + elementCount++; + } + + child = child->sibling; + } + + return elementCount; +} + +static MmsVariableSpecification* +createFCNamedVariableFromDataObject(DataObject* dataObject, + FunctionalConstraint fc) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + + MmsVariableSpecification* completeNamedVariable = namedVariable; + + namedVariable->name = copyString(dataObject->name); + + if (dataObject->elementCount > 0) { + namedVariable->type = MMS_ARRAY; + namedVariable->typeSpec.array.elementCount = dataObject->elementCount; + namedVariable->typeSpec.array.elementTypeSpec = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable = namedVariable->typeSpec.array.elementTypeSpec; + } + + namedVariable->type = MMS_STRUCTURE; + + int elementCount = countChildrenWithFc(dataObject, fc); + + /* Allocate memory for components */ + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(elementCount, + sizeof(MmsVariableSpecification*)); + + int i = 0; + ModelNode* component = dataObject->firstChild; + + while (component != NULL) { + if (component->modelType == DataAttributeModelType) { + DataAttribute* dataAttribute = (DataAttribute*) component; + + if (dataAttribute->fc == fc) { + namedVariable->typeSpec.structure.elements[i] = + createNamedVariableFromDataAttribute(dataAttribute); + i++; + } + } + else if (component->modelType == DataObjectModelType) { + DataObject* subDataObject = (DataObject*) component; + + if (DataObject_hasFCData(subDataObject, fc)) { + namedVariable->typeSpec.structure.elements[i] = + createFCNamedVariableFromDataObject(subDataObject, fc); + i++; + } + + } + + component = component->sibling; + } + + namedVariable->typeSpec.structure.elementCount = elementCount; + + return completeNamedVariable; +} + +static MmsVariableSpecification* +createFCNamedVariable(LogicalNode* logicalNode, FunctionalConstraint fc) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable->name = copyString(FunctionalConstraint_toString(fc)); + namedVariable->type = MMS_STRUCTURE; + + int dataObjectCount = 0; + + DataObject* dataObject = (DataObject*) logicalNode->firstChild; + + while (dataObject != NULL) { + if (DataObject_hasFCData(dataObject, fc)) + dataObjectCount++; + + dataObject = (DataObject*) dataObject->sibling; + } + + namedVariable->typeSpec.structure.elementCount = dataObjectCount; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(dataObjectCount, + sizeof(MmsVariableSpecification*)); + + dataObjectCount = 0; + + dataObject = (DataObject*) logicalNode->firstChild; + + while (dataObject != NULL) { + if (DataObject_hasFCData(dataObject, fc)) { + + namedVariable->typeSpec.structure.elements[dataObjectCount] = + createFCNamedVariableFromDataObject(dataObject, fc); + + dataObjectCount++; + } + + dataObject = (DataObject*) dataObject->sibling; + } + + return namedVariable; +} + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + +static MmsVariableSpecification* +createSGCB(void) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("SGCB"); + namedVariable->type = MMS_STRUCTURE; + + namedVariable->typeSpec.structure.elementCount = 6; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(6, + sizeof(MmsVariableSpecification*)); + + MmsVariableSpecification* element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("NumOfSG"); + element->type = MMS_UNSIGNED; + element->typeSpec.integer = 8; + namedVariable->typeSpec.structure.elements[0] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("ActSG"); + element->type = MMS_UNSIGNED; + element->typeSpec.integer = 8; + namedVariable->typeSpec.structure.elements[1] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("EditSG"); + element->type = MMS_UNSIGNED; + element->typeSpec.integer = 8; + namedVariable->typeSpec.structure.elements[2] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("CnfEdit"); + element->type = MMS_BOOLEAN; + namedVariable->typeSpec.structure.elements[3] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("LActTm"); + element->type = MMS_UTC_TIME; + namedVariable->typeSpec.structure.elements[4] = element; + + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = copyString("ResvTms"); + element->type = MMS_UNSIGNED; + element->typeSpec.integer = 16; + namedVariable->typeSpec.structure.elements[5] = element; + + return namedVariable; +} + + +static MmsVariableSpecification* +createFCNamedVariableSPWithSGCB(LogicalNode* logicalNode) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("SP"); + namedVariable->type = MMS_STRUCTURE; + + int dataObjectCount = 1; + + DataObject* dataObject = (DataObject*) logicalNode->firstChild; + + while (dataObject != NULL) { + if (DataObject_hasFCData(dataObject, IEC61850_FC_SP)) + dataObjectCount++; + + dataObject = (DataObject*) dataObject->sibling; + } + + namedVariable->typeSpec.structure.elementCount = dataObjectCount; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(dataObjectCount, + sizeof(MmsVariableSpecification*)); + + dataObjectCount = 1; + + namedVariable->typeSpec.structure.elements[0] = createSGCB(); + + dataObject = (DataObject*) logicalNode->firstChild; + + while (dataObject != NULL) { + if (DataObject_hasFCData(dataObject, IEC61850_FC_SP)) { + + namedVariable->typeSpec.structure.elements[dataObjectCount] = + createFCNamedVariableFromDataObject(dataObject, IEC61850_FC_SP); + + dataObjectCount++; + } + + dataObject = (DataObject*) dataObject->sibling; + } + + return namedVariable; +} + +static bool +isSettingGroupControlBlock(char* separator) +{ + if (strncmp(separator + 1, "SP$SGCB", 7) == 0) + return true; + + return false; +} + +static SettingGroup* +getSettingGroupByMmsDomain(MmsMapping* self, MmsDomain* domain) +{ + LinkedList settingGroupElement = LinkedList_getNext(self->settingGroups); + + while (settingGroupElement != NULL) { + SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement); + + if (settingGroup->mmsDomain == domain) + return settingGroup; + + settingGroupElement = LinkedList_getNext(settingGroupElement); + } + + return NULL; +} + +static SettingGroup* +getSettingGroupBySGCB(MmsMapping* self, SettingGroupControlBlock* sgcb) +{ + LinkedList settingGroupElement = LinkedList_getNext(self->settingGroups); + + while (settingGroupElement != NULL) { + SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement); + + if (settingGroup->sgcb == sgcb) + return settingGroup; + + settingGroupElement = LinkedList_getNext(settingGroupElement); + } + + return NULL; +} + +static void +unselectEditSettingGroup(SettingGroup* settingGroup) +{ + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Unselect setting group\n"); + + settingGroup->sgcb->editSG = 0; + settingGroup->editingClient = NULL; + MmsValue* editSg = MmsValue_getElement(settingGroup->sgcbMmsValues, 2); + MmsValue_setUint8(editSg, 0U); + MmsValue* resvTms = MmsValue_getElement(settingGroup->sgcbMmsValues, 5); + MmsValue_setUint16(resvTms, 0U); +} + +static void +unselectAllSettingGroups(MmsMapping* self, MmsServerConnection serverCon) +{ + LinkedList settingGroupElement = LinkedList_getNext(self->settingGroups); + + while (settingGroupElement != NULL) { + SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement); + + if (settingGroup->editingClient == (ClientConnection) serverCon) + unselectEditSettingGroup(settingGroup); + + settingGroupElement = LinkedList_getNext(settingGroupElement); + } +} + +void +MmsMapping_checkForSettingGroupReservationTimeouts(MmsMapping* self, uint64_t currentTime) +{ + LinkedList settingGroupElement = LinkedList_getNext(self->settingGroups); + + while (settingGroupElement != NULL) { + SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement); + + if (settingGroup->sgcb->editSG != 0) + if (currentTime >= settingGroup->reservationTimeout) + unselectEditSettingGroup(settingGroup); + + settingGroupElement = LinkedList_getNext(settingGroupElement); + } +} + +void +MmsMapping_configureSettingGroups(MmsMapping* self) +{ + + LinkedList settingGroupElement = LinkedList_getNext(self->settingGroups); + + while (settingGroupElement != NULL) { + SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement); + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Configure setting group\n"); + + MmsValue* values = + MmsServer_getValueFromCache(self->mmsServer, settingGroup->mmsDomain, "LLN0$SP$SGCB"); + + if (values != NULL) { + settingGroup->sgcb->resvTms = CONFIG_IEC61850_SG_RESVTMS; + + MmsValue* numOfSg = MmsValue_getElement(values, 0); + MmsValue* actSg = MmsValue_getElement(values, 1); + MmsValue* resvTms = MmsValue_getElement(values, 5); + + MmsValue_setUint8(numOfSg, settingGroup->sgcb->numOfSGs); + MmsValue_setUint8(actSg, settingGroup->sgcb->actSG); + MmsValue_setUint16(resvTms, 0U); + + settingGroup->sgcbMmsValues = values; + + break; + } + else if (DEBUG_IED_SERVER) + printf("IED_SERVER: Values for SGCB do not exist\n"); + + settingGroupElement = LinkedList_getNext(settingGroupElement); + } +} + +void +MmsMapping_setSgChangedHandler(MmsMapping* self, SettingGroupControlBlock* sgcb, + ActiveSettingGroupChangedHandler handler, void* parameter) +{ + SettingGroup* sg = getSettingGroupBySGCB(self, sgcb); + + if (sg != NULL) { + sg->actSgChangedHandler = handler; + sg->actSgChangedHandlerParameter = parameter; + } +} + +void +MmsMapping_setEditSgChangedHandler(MmsMapping* self, SettingGroupControlBlock* sgcb, + EditSettingGroupChangedHandler handler, void* parameter) +{ + SettingGroup* sg = getSettingGroupBySGCB(self, sgcb); + + if (sg != NULL) { + sg->editSgChangedHandler = handler; + sg->editSgChangedHandlerParameter = parameter; + } +} + +void +MmsMapping_setConfirmEditSgHandler(MmsMapping* self, SettingGroupControlBlock* sgcb, + EditSettingGroupConfirmationHandler handler, void* parameter) +{ + SettingGroup* sg = getSettingGroupBySGCB(self, sgcb); + + if (sg != NULL) { + sg->editSgConfirmedHandler = handler; + sg->editSgConfirmedHandlerParameter = parameter; + } +} + +void +MmsMapping_changeActiveSettingGroup(MmsMapping* self, SettingGroupControlBlock* sgcb, uint8_t newActiveSg) +{ + SettingGroup* sg = getSettingGroupBySGCB(self, sgcb); + + if (sg != NULL) { + if (newActiveSg > 0 && newActiveSg <= sgcb->numOfSGs) { + sgcb->actSG = newActiveSg; + + MmsValue* actSg = MmsValue_getElement(sg->sgcbMmsValues, 1); + MmsValue* lActTm = MmsValue_getElement(sg->sgcbMmsValues, 4); + + MmsValue_setUint8(actSg, sgcb->actSG); + MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs()); + } + } +} + +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + +static int +determineLogicalNodeComponentCount(LogicalNode* logicalNode) +{ + int componentCount = 0; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_ST)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_MX)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SP)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SV)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_CF)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_DC)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SG)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SE)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SR)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_OR)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_BL)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_EX)) + componentCount++; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_CO)) + componentCount++; + + return componentCount; +} + + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) +static int +countReportControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode, bool buffered) +{ + int rcbCount = 0; + + ReportControlBlock* rcb = self->model->rcbs; + + /* Iterate list of RCBs */ + while (rcb != NULL) { + if (rcb->parent == logicalNode) { + if (rcb->buffered == buffered) + rcbCount++; + } + + rcb = rcb->sibling; + } + + return rcbCount; +} +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +static int +countGSEControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode) +{ + int gseCount = 0; + + GSEControlBlock* gcb = self->model->gseCBs; + + while (gcb != NULL) { + if (gcb->parent == logicalNode) { + gseCount++; + } + + gcb = gcb->sibling; + } + + return gseCount; +} + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + +static SettingGroupControlBlock* +checkForSgcb(MmsMapping* self, LogicalNode* logicalNode) +{ + SettingGroupControlBlock* sgcb = self->model->sgcbs; + + while (sgcb != NULL) { + if (sgcb->parent == logicalNode) + return sgcb; + + sgcb = sgcb->sibling; + } + + return NULL; +} + +static MmsVariableSpecification* +createNamedVariableFromLogicalNode(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) + GLOBAL_MALLOC(sizeof(MmsVariableSpecification)); + + namedVariable->name = copyString(logicalNode->name); + + namedVariable->type = MMS_STRUCTURE; + + int componentCount = determineLogicalNodeComponentCount(logicalNode); + + + SettingGroupControlBlock* sgControlBlock = NULL; + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + + sgControlBlock = checkForSgcb(self, logicalNode); + + if (sgControlBlock != NULL) { + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SP) == false) + componentCount++; + + SettingGroup* settingGroup = (SettingGroup*) GLOBAL_CALLOC(1, sizeof(SettingGroup)); + + settingGroup->sgcb = sgControlBlock; + settingGroup->mmsDomain = domain; + + LinkedList_add(self->settingGroups, (void*) settingGroup); + } +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + if (DEBUG_IED_SERVER) + printf("LogicalNode %s has %i fc components\n", logicalNode->name, + componentCount); + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + int brcbCount = countReportControlBlocksForLogicalNode(self, logicalNode, + true); + + if (brcbCount > 0) { + if (DEBUG_IED_SERVER) + printf(" and %i buffered RCBs\n", brcbCount); + componentCount++; + } + + int urcbCount = countReportControlBlocksForLogicalNode(self, logicalNode, + false); + + if (urcbCount > 0) { + if (DEBUG_IED_SERVER) + printf(" and %i unbuffered RCBs\n", urcbCount); + componentCount++; + } +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + + int gseCount = countGSEControlBlocksForLogicalNode(self, logicalNode); + + if (gseCount > 0) { + if (DEBUG_IED_SERVER) + printf(" and %i GSE control blocks\n", gseCount); + componentCount++; + } + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(componentCount, + sizeof(MmsVariableSpecification*)); + + /* Create a named variable of type structure for each functional constrained */ + int currentComponent = 0; + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_MX)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_MX); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_ST)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_ST); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_CO)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_CO); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_CF)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_CF); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_DC)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_DC); + currentComponent++; + } + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + if (sgControlBlock != NULL) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariableSPWithSGCB(logicalNode); + currentComponent++; + } + else +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SP)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_SP); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SG)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_SG); + currentComponent++; + } + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + if (urcbCount > 0) { + namedVariable->typeSpec.structure.elements[currentComponent] = + Reporting_createMmsUnbufferedRCBs(self, domain, logicalNode, + urcbCount); + currentComponent++; + } +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + + /* TODO create LCBs here */ + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + if (brcbCount > 0) { + namedVariable->typeSpec.structure.elements[currentComponent] = + Reporting_createMmsBufferedRCBs(self, domain, logicalNode, + brcbCount); + currentComponent++; + } +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + if (gseCount > 0) { + namedVariable->typeSpec.structure.elements[currentComponent] = + GOOSE_createGOOSEControlBlocks(self, domain, logicalNode, gseCount); + + currentComponent++; + } +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + + + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SV)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_SV); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SE)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_SE); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_EX)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_EX); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_SR)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_SR); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_OR)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_OR); + currentComponent++; + } + + if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_BL)) { + namedVariable->typeSpec.structure.elements[currentComponent] = + createFCNamedVariable(logicalNode, IEC61850_FC_BL); + currentComponent++; + } + + namedVariable->typeSpec.structure.elementCount = currentComponent; + + return namedVariable; +} + +static MmsDomain* +createMmsDomainFromIedDevice(MmsMapping* self, LogicalDevice* logicalDevice) +{ + MmsDomain* domain = NULL; + char domainName[65]; + + int modelNameLength = strlen(self->model->name); + + if (modelNameLength > 64) + goto exit_function; + + strncpy(domainName, self->model->name, 64); + strncat(domainName, logicalDevice->name, 64 - modelNameLength); + + domain = MmsDomain_create(domainName); + + if (domain == NULL) + goto exit_function; + + int nodesCount = LogicalDevice_getLogicalNodeCount(logicalDevice); + + /* Logical nodes are first level named variables */ + domain->namedVariablesCount = nodesCount; + domain->namedVariables = (MmsVariableSpecification**) GLOBAL_MALLOC(nodesCount * sizeof(MmsVariableSpecification*)); + + LogicalNode* logicalNode = (LogicalNode*) logicalDevice->firstChild; + + int i = 0; + while (logicalNode != NULL) { + domain->namedVariables[i] = createNamedVariableFromLogicalNode(self, + domain, logicalNode); + + logicalNode = (LogicalNode*) logicalNode->sibling; + i++; + } + +exit_function: + return domain; +} + +static void +createMmsDataModel(MmsMapping* self, int iedDeviceCount, + MmsDevice* mmsDevice, IedModel* iedModel) +{ + mmsDevice->domains = (MmsDomain**) GLOBAL_MALLOC((iedDeviceCount) * sizeof(MmsDomain*)); + mmsDevice->domainCount = iedDeviceCount; + + LogicalDevice* logicalDevice = iedModel->firstChild; + + int i = 0; + while (logicalDevice != NULL) { + mmsDevice->domains[i] = createMmsDomainFromIedDevice(self, + logicalDevice); + i++; + logicalDevice = (LogicalDevice*) logicalDevice->sibling; + } +} + +static void +createDataSets(MmsDevice* mmsDevice, IedModel* iedModel) +{ + DataSet* dataset = iedModel->dataSets; + + char domainName[65]; + + int iedModelNameLength = strlen(iedModel->name); + + if (iedModelNameLength > 64) + goto exit_function; //TODO call exception handler! + + while (dataset != NULL) { + strncpy(domainName, iedModel->name, 64); + strncat(domainName, dataset->logicalDeviceName, 64 - iedModelNameLength); + + MmsDomain* dataSetDomain = MmsDevice_getDomain(mmsDevice, domainName); + + if (dataSetDomain == NULL) + goto exit_function; //TODO call exception handler! + + MmsNamedVariableList varList = MmsNamedVariableList_create(dataSetDomain, dataset->name, false); + + DataSetEntry* dataSetEntry = dataset->fcdas; + + while (dataSetEntry != NULL) { + + MmsAccessSpecifier accessSpecifier; + + strncpy(domainName, iedModel->name, 64); + strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedModelNameLength); + + accessSpecifier.domain = MmsDevice_getDomain(mmsDevice, domainName); + + accessSpecifier.variableName = dataSetEntry->variableName; + accessSpecifier.arrayIndex = dataSetEntry->index; + accessSpecifier.componentName = dataSetEntry->componentName; + + MmsNamedVariableListEntry variableListEntry = + MmsNamedVariableListEntry_create(accessSpecifier); + + MmsNamedVariableList_addVariable(varList, variableListEntry); + + dataSetEntry = dataSetEntry->sibling; + } + + MmsDomain_addNamedVariableList(dataSetDomain, varList); + + dataset = dataset->sibling; + } + +exit_function: + return; +} + +static MmsDevice* +createMmsModelFromIedModel(MmsMapping* self, IedModel* iedModel) +{ + MmsDevice* mmsDevice = NULL; + + if (iedModel->firstChild != NULL) { + + mmsDevice = MmsDevice_create(iedModel->name); + + int iedDeviceCount = IedModel_getLogicalDeviceCount(iedModel); + + createMmsDataModel(self, iedDeviceCount, mmsDevice, iedModel); + + createDataSets(mmsDevice, iedModel); + } + + return mmsDevice; +} + +MmsMapping* +MmsMapping_create(IedModel* model) +{ + MmsMapping* self = (MmsMapping*) GLOBAL_CALLOC(1, sizeof(struct sMmsMapping)); + + self->model = model; + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + self->reportControls = LinkedList_create(); +#endif + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + self->gseControls = LinkedList_create(); + self->gooseInterfaceId = NULL; +#endif + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + self->controlObjects = LinkedList_create(); +#endif + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + self->settingGroups = LinkedList_create(); +#endif + + self->observedObjects = LinkedList_create(); + + self->attributeAccessHandlers = LinkedList_create(); + + self->mmsDevice = createMmsModelFromIedModel(self, model); + + return self; +} + +void +MmsMapping_destroy(MmsMapping* self) +{ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->reportWorkerThread != NULL) { + self->reportThreadRunning = false; + Thread_destroy(self->reportWorkerThread); + } +#endif + + if (self->mmsDevice != NULL) + MmsDevice_destroy(self->mmsDevice); + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + LinkedList_destroyDeep(self->reportControls, (LinkedListValueDeleteFunction) ReportControl_destroy); +#endif + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + LinkedList_destroyDeep(self->gseControls, (LinkedListValueDeleteFunction) MmsGooseControlBlock_destroy); +#endif + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + LinkedList_destroyDeep(self->controlObjects, (LinkedListValueDeleteFunction) ControlObject_destroy); +#endif + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + LinkedList_destroy(self->settingGroups); +#endif + + LinkedList_destroy(self->observedObjects); + + LinkedList_destroy(self->attributeAccessHandlers); + + IedModel_setAttributeValuesToNull(self->model); + + GLOBAL_FREEMEM(self); +} + +MmsDevice* +MmsMapping_getMmsDeviceModel(MmsMapping* mapping) +{ + return mapping->mmsDevice; +} + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) +static bool +isReportControlBlock(char* separator) +{ + if (strncmp(separator + 1, "RP", 2) == 0) + return true; + + if (strncmp(separator + 1, "BR", 2) == 0) + return true; + + return false; +} +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + +static bool +isFunctionalConstraintCF(char* separator) +{ + if (strncmp(separator + 1, "CF", 2) == 0) + return true; + else + return false; +} + +static bool +isFunctionalConstraintDC(char* separator) +{ + if (strncmp(separator + 1, "DC", 2) == 0) + return true; + else + return false; +} + +static bool +isFunctionalConstraintSP(char* separator) +{ + if (strncmp(separator + 1, "SP", 2) == 0) + return true; + else + return false; +} + +static bool +isFunctionalConstraintSV(char* separator) +{ + if (strncmp(separator + 1, "SV", 2) == 0) + return true; + else + return false; +} + +static bool +isFunctionalConstraintSE(char* separator) +{ + if (strncmp(separator + 1, "SE", 2) == 0) + return true; + else + return false; +} + + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) +static bool +isControllable(char* separator) +{ + if (strncmp(separator + 1, "CO", 2) == 0) + return true; + else + return false; +} +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +static bool +isGooseControlBlock(char* separator) +{ + if (strncmp(separator + 1, "GO", 2) == 0) + return true; + else + return false; +} + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + +char* +MmsMapping_getNextNameElement(char* name) +{ + char* separator = strchr(name, '$'); + + if (separator == NULL) + return NULL; + + separator++; + + if (*separator == 0) + return NULL; + + return separator; +} + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +static MmsGooseControlBlock +lookupGCB(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName) +{ + LinkedList element = LinkedList_getNext(self->gseControls); + + while (element != NULL) { + MmsGooseControlBlock mmsGCB = (MmsGooseControlBlock) element->data; + + if (MmsGooseControlBlock_getDomain(mmsGCB) == domain) { + if (strcmp(MmsGooseControlBlock_getLogicalNodeName(mmsGCB), lnName) == 0) { + if (strcmp(MmsGooseControlBlock_getName(mmsGCB), objectName) == 0) { + return mmsGCB; + } + } + } + + element = LinkedList_getNext(element); + } + + return NULL; +} + +#ifndef CONFIG_GOOSE_GOID_WRITABLE +#define CONFIG_GOOSE_GOID_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_DATSET_WRITABLE +#define CONFIG_GOOSE_DATSET_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_CONFREV_WRITABLE +#define CONFIG_GOOSE_CONFREV_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_NDSCOM_WRITABLE +#define CONFIG_GOOSE_NDSCOM_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_DSTADDRESS_WRITABLE +#define CONFIG_GOOSE_DSTADDRESS_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_MINTIME_WRITABLE +#define CONFIG_GOOSE_MINTIME_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_MAXTIME_WRITABLE +#define CONFIG_GOOSE_MAXTIME_WRITABLE 0 +#endif + +#ifndef CONFIG_GOOSE_FIXEDOFFS_WRITABLE +#define CONFIG_GOOSE_FIXEDOFFS_WRITABLE 0 +#endif + +static MmsDataAccessError +writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, + MmsValue* value) +{ + char variableId[130]; + + strncpy(variableId, variableIdOrig, 129); + + char* separator = strchr(variableId, '$'); + + *separator = 0; + + char* lnName = variableId; + + if (lnName == NULL) + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + char* objectName = MmsMapping_getNextNameElement(separator + 1); + + if (objectName == NULL) + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + char* varName = MmsMapping_getNextNameElement(objectName); + + if (varName != NULL) + *(varName - 1) = 0; + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + MmsGooseControlBlock mmsGCB = lookupGCB(self, domain, lnName, objectName); + + if (mmsGCB == NULL) + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + if (strcmp(varName, "GoEna") == 0) { + if (MmsValue_getType(value) != MMS_BOOLEAN) + return DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + + if (MmsValue_getBoolean(value)) + MmsGooseControlBlock_enable(mmsGCB); + else + MmsGooseControlBlock_disable(mmsGCB); + + return DATA_ACCESS_ERROR_SUCCESS; + } + else { + if (MmsGooseControlBlock_isEnabled(mmsGCB)) + return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + else { + bool allowAccess = false; + +#if (CONFIG_GOOSE_GOID_WRITABLE == 1) + if (strcmp(varName, "GoID") == 0) { + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 1), value); + allowAccess = true; + } +#endif + +#if (CONFIG_GOOSE_DATSET_WRITABLE == 1) + if (strcmp(varName, "DatSet") == 0) { + // allow to set non-existing data set? + + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 2), value); + allowAccess = true; + } +#endif + +#if (CONFIG_GOOSE_CONFREV_WRITABLE == 1) + if (strcmp(varName, "ConfRev") == 0) { + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 3), value); + allowAccess = true; + } +#endif + +#if (CONFIG_GOOSE_NDSCOM_WRITABLE == 1) + if (strcmp(varName, "NdsCom") == 0) { + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 4), value); + allowAccess = true; + } +#endif + +#if (CONFIG_GOOSE_DSTADDRESS_WRITABLE == 1) + if (memcmp(varName, "DstAddress", 9) == 0) { + MmsValue* subValue = MmsValue_getSubElement(MmsGooseControlBlock_getMmsValues(mmsGCB), + MmsGooseControlBlock_getVariableSpecification(mmsGCB), varName); + + if (subValue == NULL) + return DATA_ACCESS_ERROR_INVALID_ADDRESS; + + if (MmsValue_update(subValue, value)) + return DATA_ACCESS_ERROR_SUCCESS; + else + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } +#endif + +#if (CONFIG_GOOSE_MINTIME_WRITABLE == 1) + if (strcmp(varName, "MinTime") == 0) { + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 6), value); + allowAccess = true; + } +#endif + +#if (CONFIG_GOOSE_MAXTIME_WRITABLE == 1) + if (strcmp(varName, "MaxTime") == 0) { + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 7), value); + allowAccess = true; + } +#endif + +#if (CONFIG_GOOSE_FIXEDOFFS_WRITABLE == 1) + if (strcmp(varName, "FixedOffs") == 0) { + MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 8), value); + allowAccess = true; + } +#endif + + if (allowAccess) + return DATA_ACCESS_ERROR_SUCCESS; + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + } + } +} + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + +static MmsValue* +checkIfValueBelongsToModelNode(DataAttribute* dataAttribute, MmsValue* value, MmsValue* newValue) +{ + if (dataAttribute->mmsValue == value) + return newValue; + + DataAttribute* child = (DataAttribute*) dataAttribute->firstChild; + + while (child != NULL) { + MmsValue* tmpValue = checkIfValueBelongsToModelNode(child, value, newValue); + + if (tmpValue != NULL) + return tmpValue; + else + child = (DataAttribute*) child->sibling; + } + + if (MmsValue_getType(value) == MMS_STRUCTURE) { + int elementCount = MmsValue_getArraySize(value); + + int i; + for (i = 0; i < elementCount; i++) { + MmsValue* childValue = MmsValue_getElement(value, i); + MmsValue* childNewValue = MmsValue_getElement(newValue, i); + + MmsValue* tmpValue = checkIfValueBelongsToModelNode(dataAttribute, childValue, childNewValue); + + if (tmpValue != NULL) + return tmpValue; + } + } + + return NULL; +} + +static FunctionalConstraint +getFunctionalConstraintForWritableNode(MmsMapping* self, char* separator) +{ + if (isFunctionalConstraintCF(separator)) + return IEC61850_FC_CF; + if (isFunctionalConstraintDC(separator)) + return IEC61850_FC_DC; + if (isFunctionalConstraintSP(separator)) + return IEC61850_FC_SP; + if (isFunctionalConstraintSV(separator)) + return IEC61850_FC_SV; + if (isFunctionalConstraintSE(separator)) + return IEC61850_FC_SE; + + return IEC61850_FC_NONE; +} + +static AccessPolicy +getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc) +{ + if (fc == IEC61850_FC_CF) { + if (self->iedServer->writeAccessPolicies & ALLOW_WRITE_ACCESS_CF) + return ACCESS_POLICY_ALLOW; + else + return ACCESS_POLICY_DENY; + } + + if (fc == IEC61850_FC_DC) { + if (self->iedServer->writeAccessPolicies & ALLOW_WRITE_ACCESS_DC) + return ACCESS_POLICY_ALLOW; + else + return ACCESS_POLICY_DENY; + } + + if (fc == IEC61850_FC_SP) { + if (self->iedServer->writeAccessPolicies & ALLOW_WRITE_ACCESS_SP) + return ACCESS_POLICY_ALLOW; + else + return ACCESS_POLICY_DENY; + } + + if (fc == IEC61850_FC_SV) { + if (self->iedServer->writeAccessPolicies & ALLOW_WRITE_ACCESS_SV) + return ACCESS_POLICY_ALLOW; + else + return ACCESS_POLICY_DENY; + } + + if (fc == IEC61850_FC_SE) { + if (self->iedServer->writeAccessPolicies & ALLOW_WRITE_ACCESS_SE) + return ACCESS_POLICY_ALLOW; + else + return ACCESS_POLICY_DENY; + } + + return ACCESS_POLICY_DENY; +} + +static MmsDataAccessError +mmsWriteHandler(void* parameter, MmsDomain* domain, + char* variableId, MmsValue* value, MmsServerConnection connection) +{ + MmsMapping* self = (MmsMapping*) parameter; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Write requested %s\n", variableId); + + /* Access control based on functional constraint */ + + char* separator = strchr(variableId, '$'); + + if (separator == NULL) + return DATA_ACCESS_ERROR_INVALID_ADDRESS; + + int lnNameLength = separator - variableId; + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + /* Controllable objects - CO */ + if (isControllable(separator)) { + return Control_writeAccessControlObject(self, domain, variableId, value, + connection); + } +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + /* Goose control block - GO */ + if (isGooseControlBlock(separator)) { + return writeAccessGooseControlBlock(self, domain, variableId, value); + } +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + /* Report control blocks - BR, RP */ + if (isReportControlBlock(separator)) { + + char* reportName = MmsMapping_getNextNameElement(separator + 1); + + if (reportName == NULL) + return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + + separator = strchr(reportName, '$'); + + int variableIdLen; + + if (separator != NULL) + variableIdLen = separator - variableId; + else + variableIdLen = strlen(variableId); + + LinkedList nextElement = self->reportControls; + + while ((nextElement = LinkedList_getNext(nextElement)) != NULL) { + ReportControl* rc = (ReportControl*) nextElement->data; + + if (rc->domain == domain) { + + int parentLNNameStrLen = strlen(rc->parentLN->name); + + if (parentLNNameStrLen != lnNameLength) + continue; + + if (memcmp(rc->parentLN->name, variableId, parentLNNameStrLen) != 0) + continue; + + int rcNameLen = strlen(rc->name); + + if (rcNameLen == variableIdLen) { + + if (strncmp(variableId, rc->name, variableIdLen) == 0) { + char* elementName = variableId + rcNameLen + 1; + + return Reporting_RCBWriteAccessHandler(self, rc, elementName, value, connection); + } + } + } + } + + return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + if (isSettingGroupControlBlock(separator)) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Access to SGCB\n"); + + char* nextSep = strchr(separator + 1, '$'); + + if (nextSep != NULL) { + nextSep = strchr(nextSep + 1, '$'); + + char* nameId = nextSep + 1; + + if (strcmp(nameId, "ActSG") == 0) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); + + if (sg != NULL) { + uint32_t val = MmsValue_toUint32(value); + + if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { + if (val != sg->sgcb->actSG) { + + if (sg->actSgChangedHandler != NULL) { + if (sg->actSgChangedHandler(sg->actSgChangedHandlerParameter, sg->sgcb, + (uint8_t) val, (ClientConnection) connection)) + { + sg->sgcb->actSG = val; + + MmsValue* actSg = MmsValue_getElement(sg->sgcbMmsValues, 1); + MmsValue* lActTm = MmsValue_getElement(sg->sgcbMmsValues, 4); + + MmsValue_setUint8(actSg, sg->sgcb->actSG); + MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs()); + } + + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + } + + return DATA_ACCESS_ERROR_SUCCESS; + } + else + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } + } + else if (strcmp(nameId, "EditSG") == 0) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); + + if (sg != NULL) { + uint32_t val = MmsValue_toUint32(value); + + if ((sg->editingClient != NULL) && ( sg->editingClient != (ClientConnection) connection)) + /* Edit SG was set by other client */ + return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + + if (val == 0) { + unselectEditSettingGroup(sg); + return DATA_ACCESS_ERROR_SUCCESS; + } + + if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { + + if (sg->editSgChangedHandler != NULL) { + + if (sg->editSgChangedHandler(sg->editSgChangedHandlerParameter, sg->sgcb, + (uint8_t) val, (ClientConnection) connection)) + { + sg->sgcb->editSG = val; + sg->editingClient = (ClientConnection) connection; + + sg->reservationTimeout = Hal_getTimeInMs() + (sg->sgcb->resvTms * 1000); + + MmsValue* editSg = MmsValue_getElement(sg->sgcbMmsValues, 2); + MmsValue* resvTms = MmsValue_getElement(sg->sgcbMmsValues, 5); + + MmsValue_setUint16(resvTms, sg->sgcb->resvTms); + MmsValue_setUint8(editSg, sg->sgcb->editSG); + + return DATA_ACCESS_ERROR_SUCCESS; + } + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + } + else + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + + } + } + else if (strcmp(nameId, "CnfEdit") == 0) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); + + if (sg != NULL) { + bool val = MmsValue_getBoolean(value); + + if (val == true) { + if (sg->sgcb->editSG != 0) { + if (sg->editingClient == (ClientConnection) connection) { + if (sg->editSgConfirmedHandler != NULL) { + sg->editSgConfirmedHandler(sg->editSgConfirmedHandlerParameter, sg->sgcb, + sg->sgcb->editSG); + + unselectEditSettingGroup(sg); + + return DATA_ACCESS_ERROR_SUCCESS; + } + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + else + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } + } + } + + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + FunctionalConstraint fc = getFunctionalConstraintForWritableNode(self, separator); + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + if (fc == IEC61850_FC_SE) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); + + if (sg->editingClient != (ClientConnection) connection) + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + /* writable data model elements - SP, SV, CF, DC */ + if (fc != IEC61850_FC_NONE) { + MmsValue* cachedValue; + + cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId); + + if (cachedValue != NULL) { + + if (!MmsValue_equalTypes(cachedValue, value)) + return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + + bool handlerFound = false; + + AccessPolicy nodeAccessPolicy = getAccessPolicyForFC(self, fc); + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: write to %s policy:%i\n", variableId, nodeAccessPolicy); + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + if (isFunctionalConstraintSE(separator)) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); + + if (sg != NULL) { + if (sg->sgcb->editSG == 0) + return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + } + else + return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } +#endif + + /* Call writer access handlers */ + LinkedList writeHandlerListElement = LinkedList_getNext(self->attributeAccessHandlers); + + while (writeHandlerListElement != NULL) { + AttributeAccessHandler* accessHandler = (AttributeAccessHandler*) writeHandlerListElement->data; + DataAttribute* dataAttribute = accessHandler->attribute; + + if (nodeAccessPolicy == ACCESS_POLICY_ALLOW) { + + MmsValue* matchingValue = checkIfValueBelongsToModelNode(dataAttribute, cachedValue, value); + + if (matchingValue != NULL) { + MmsDataAccessError handlerResult = + accessHandler->handler(dataAttribute, matchingValue, (ClientConnection) connection, + accessHandler->parameter); + + if (handlerResult == DATA_ACCESS_ERROR_SUCCESS) + handlerFound = true; + else + return handlerResult; + } + + } + else { /* if ACCESS_POLICY_DENY only allow direct access to handled data attribute */ + if (dataAttribute->mmsValue == cachedValue) { + MmsDataAccessError handlerResult = + accessHandler->handler(dataAttribute, value, (ClientConnection) connection, + accessHandler->parameter); + + if (handlerResult == DATA_ACCESS_ERROR_SUCCESS) { + handlerFound = true; + break; + } + else + return handlerResult; + } + + } + + writeHandlerListElement = LinkedList_getNext(writeHandlerListElement); + } + + /* DENY access if no handler is found and default policy is DENY */ + if (!handlerFound) { + + if (nodeAccessPolicy == ACCESS_POLICY_DENY) + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + } + + DataAttribute* da = IedModel_lookupDataAttributeByMmsValue(self->model, cachedValue); + + if (da != NULL) + IedServer_updateAttributeValue(self->iedServer, da, value); + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + /* Call observer callback */ + LinkedList observerListElement = LinkedList_getNext(self->observedObjects); + + while (observerListElement != NULL) { + AttributeObserver* observer = (AttributeObserver*) observerListElement->data; + DataAttribute* dataAttribute = observer->attribute; + + if (checkIfValueBelongsToModelNode(dataAttribute, cachedValue, value) != NULL) { + observer->handler(dataAttribute, (ClientConnection) connection); + break; /* only all one handler per data attribute */ + } + + observerListElement = LinkedList_getNext(observerListElement); + } + + return DATA_ACCESS_ERROR_SUCCESS; + } + else + return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } + + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; +} + +void +MmsMapping_addObservedAttribute(MmsMapping* self, DataAttribute* dataAttribute, + AttributeChangedHandler handler) +{ + AttributeObserver* observer = (AttributeObserver*) GLOBAL_MALLOC(sizeof(AttributeObserver)); + + observer->attribute = dataAttribute; + observer->handler = handler; + + LinkedList_add(self->observedObjects, observer); +} + +static AttributeAccessHandler* +getAccessHandlerForAttribute(MmsMapping* self, DataAttribute* dataAttribute) +{ + LinkedList element = LinkedList_getNext(self->attributeAccessHandlers); + + while (element != NULL) { + AttributeAccessHandler* accessHandler = (AttributeAccessHandler*) element->data; + + if (accessHandler->attribute == dataAttribute) + return accessHandler; + + element = LinkedList_getNext(element); + } + + return NULL; +} + +void +MmsMapping_installWriteAccessHandler(MmsMapping* self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter) +{ + AttributeAccessHandler* accessHandler = getAccessHandlerForAttribute(self, dataAttribute); + + if (accessHandler == NULL) { + accessHandler = (AttributeAccessHandler*) GLOBAL_MALLOC(sizeof(AttributeAccessHandler)); + + accessHandler->attribute = dataAttribute; + accessHandler->parameter = parameter; + LinkedList_add(self->attributeAccessHandlers, (void*) accessHandler); + } + + accessHandler->handler = handler; +} + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +static MmsValue* +readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) +{ + MmsValue* value = NULL; + + char variableId[130]; + + strncpy(variableId, variableIdOrig, 129); + + char* separator = strchr(variableId, '$'); + + *separator = 0; + + char* lnName = variableId; + + if (lnName == NULL) + return NULL; + + char* objectName = MmsMapping_getNextNameElement(separator + 1); + + if (objectName == NULL) + return NULL; + + char* varName = MmsMapping_getNextNameElement(objectName); + + if (varName != NULL) + *(varName - 1) = 0; + + MmsGooseControlBlock mmsGCB = lookupGCB(self, domain, lnName, objectName); + + if (mmsGCB != NULL) { + if (varName != NULL) { + value = MmsValue_getSubElement(MmsGooseControlBlock_getMmsValues(mmsGCB), + MmsGooseControlBlock_getVariableSpecification(mmsGCB), varName); + } + else { + value = MmsGooseControlBlock_getMmsValues(mmsGCB); + } + } + + return value; +} + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + +static MmsValue* +mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerConnection connection) +{ + MmsMapping* self = (MmsMapping*) parameter; + + MmsValue* retValue = NULL; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: mmsReadHandler: Requested %s\n", variableId); + + char* separator = strchr(variableId, '$'); + + if (separator == NULL) + goto exit_function; + + int lnNameLength = separator - variableId; + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + /* Controllable objects - CO */ + if (isControllable(separator)) { + retValue = Control_readAccessControlObject(self, domain, variableId, connection); + goto exit_function; + } +#endif + + /* GOOSE control blocks - GO */ +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + if (isGooseControlBlock(separator)) { + retValue = readAccessGooseControlBlock(self, domain, variableId); + goto exit_function; + } +#endif + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + /* Report control blocks - BR, RP */ + if (isReportControlBlock(separator)) { + + LinkedList reportControls = self->reportControls; + + LinkedList nextElement = reportControls; + + char* reportName = MmsMapping_getNextNameElement(separator + 1); + + if (reportName == NULL) { + retValue = NULL; + goto exit_function; + } + + separator = strchr(reportName, '$'); + + size_t variableIdLen; + + if (separator != NULL) + variableIdLen = separator - variableId; + else + variableIdLen = strlen(variableId); + + while ((nextElement = LinkedList_getNext(nextElement)) != NULL) { + ReportControl* rc = (ReportControl*) nextElement->data; + + if (rc->domain == domain) { + + int parentLNNameStrLen = strlen(rc->parentLN->name); + + if (parentLNNameStrLen != lnNameLength) + continue; + + if (memcmp(rc->parentLN->name, variableId, parentLNNameStrLen) != 0) + continue; + + if (strlen(rc->name) == variableIdLen) { + if (strncmp(variableId, rc->name, variableIdLen) == 0) { + + char* elementName = MmsMapping_getNextNameElement(reportName); + + MmsValue* value = NULL; + + if (elementName != NULL) + value = ReportControl_getRCBValue(rc, elementName); + else + value = rc->rcbValues; + + retValue = value; + + goto exit_function; + } + } + + } + + } + } +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + +exit_function: + return retValue; +} + +void +MmsMapping_setMmsServer(MmsMapping* self, MmsServer server) +{ + self->mmsServer = server; +} + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) +static void +unselectControlsForConnection(MmsMapping* self, MmsServerConnection connection) +{ + LinkedList controlObjectElement = LinkedList_getNext(self->controlObjects); + + while (controlObjectElement != NULL) { + ControlObject* controlObject = (ControlObject*) controlObjectElement->data; + + if (ControlObject_unselect(controlObject, connection)) + break; + + controlObjectElement = LinkedList_getNext(controlObjectElement); + } +} +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + +static void /* is called by MMS server layer */ +mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerEvent event) +{ + MmsMapping* self = (MmsMapping*) parameter; + + if (event == MMS_SERVER_CONNECTION_CLOSED) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + /* call user provided handler function */ + if (self->connectionIndicationHandler != NULL) + self->connectionIndicationHandler(self->iedServer, clientConnection, false, + self->connectionIndicationHandlerParameter); + + private_IedServer_removeClientConnection(self->iedServer, clientConnection); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + /* wait until control threads are finished */ + while (private_ClientConnection_getTasksCount(clientConnection) > 0) + Thread_sleep(10); +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + Reporting_deactivateReportsForConnection(self, connection); +#endif + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + unselectControlsForConnection(self, connection); +#endif + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + unselectAllSettingGroups(self, connection); +#endif + + private_ClientConnection_destroy(clientConnection); + } + else if (event == MMS_SERVER_NEW_CONNECTION) { + /* call user provided handler function */ + ClientConnection newClientConnection = private_ClientConnection_create(connection); + + private_IedServer_addNewClientConnection(self->iedServer, newClientConnection); + + /* call user provided handler function */ + if (self->connectionIndicationHandler != NULL) + self->connectionIndicationHandler(self->iedServer, newClientConnection, true, + self->connectionIndicationHandlerParameter); + } +} + +static MmsDataAccessError +mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsServerConnection connection) +{ + MmsMapping* self = (MmsMapping*) parameter; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: mmsReadAccessHandler: Requested %s\n", variableId); + + char* separator = strchr(variableId, '$'); + + if (separator == NULL) + return DATA_ACCESS_ERROR_SUCCESS; + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + + if (isFunctionalConstraintSE(separator)) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); + + if (sg != NULL) { + if (sg->sgcb->editSG == 0) + return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + } + else + return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } + +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + return DATA_ACCESS_ERROR_SUCCESS; +} + +static MmsError +variableListChangedHandler (void* parameter, bool create, MmsVariableListType listType, MmsDomain* domain, + char* listName, MmsServerConnection connection) +{ + MmsError allow = MMS_ERROR_NONE; + +#if (DEBUG_IED_SERVER == 1) + if (create) + printf("IED_SERVER: create data set "); + else + printf("IED_SERVER: delete data set "); + + switch (listType) { + case MMS_VMD_SPECIFIC: + printf("VMD "); + break; + case MMS_ASSOCIATION_SPECIFIC: + printf("association "); + break; + case MMS_DOMAIN_SPECIFIC: + printf("domain "); + break; + } + + printf("specific (name=%s)\n", listName); +#endif /* (DEBUG_IED_SERVER == 1) */ + + MmsMapping* self = (MmsMapping*) parameter; + + if (create) { + if (listType == MMS_DOMAIN_SPECIFIC) { + // check if LN exists - otherwise reject request (to fulfill test case sDsN1c) + + allow = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; + + IedModel* model = self->model; + + LogicalDevice* ld = IedModel_getDevice(model, domain->domainName); + + if (ld != NULL) { + + char lnName[129]; + + char* separator = strchr(listName, '$'); + + if (separator != NULL) { + int lnNameLen = separator - listName; + + memcpy(lnName, listName, lnNameLen); + lnName[lnNameLen] = 0; + + if (LogicalDevice_getLogicalNode(ld, lnName) != NULL) + allow = MMS_ERROR_NONE; + } + + } + + } + } + else { + /* Check if data set is referenced in a report */ + + LinkedList element = self->reportControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + ReportControl* rc = (ReportControl*) element->data; + + if (rc->isDynamicDataSet) { + if (rc->dataSet != NULL) { + + if (listType == MMS_DOMAIN_SPECIFIC) { + if (rc->dataSet->logicalDeviceName != NULL) { + if (strcmp(rc->dataSet->name, listName) == 0) { + if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain)) == 0) { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + break; + } + } + } + } + else if (listType == MMS_ASSOCIATION_SPECIFIC) { + if (rc->dataSet->logicalDeviceName == NULL) { + if (strcmp(rc->dataSet->name, listName) == 0) { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + break; + } + } + } + + } + } + } + } + + return allow; +} + +void +MmsMapping_installHandlers(MmsMapping* self) +{ + MmsServer_installReadHandler(self->mmsServer, mmsReadHandler, (void*) self); + MmsServer_installWriteHandler(self->mmsServer, mmsWriteHandler, (void*) self); + MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); + MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); + MmsServer_installVariableListChangedHandler(self->mmsServer, variableListChangedHandler, (void*) self); +} + +void +MmsMapping_setIedServer(MmsMapping* self, IedServer iedServer) +{ + self->iedServer = iedServer; +} + +void +MmsMapping_setConnectionIndicationHandler(MmsMapping* self, IedConnectionIndicationHandler handler, void* parameter) +{ + self->connectionIndicationHandler = handler; + self->connectionIndicationHandlerParameter = parameter; +} + +#if ((CONFIG_IEC61850_REPORT_SERVICE == 1) || (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)) + +static bool +isMemberValueRecursive(MmsValue* container, MmsValue* value) +{ + bool isMemberValue = false; + + if (container == value) + isMemberValue = true; + else { + if ((MmsValue_getType(container) == MMS_STRUCTURE) || + (MmsValue_getType(container) == MMS_ARRAY)) + { + + int compCount = MmsValue_getArraySize(container); + int i; + for (i = 0; i < compCount; i++) { + if (isMemberValueRecursive(MmsValue_getElement(container, i), value)) { + isMemberValue = true; + break; + } + } + } + } + + return isMemberValue; +} + +static bool +DataSet_isMemberValue(DataSet* dataSet, MmsValue* value, int* index) +{ + int i = 0; + + DataSetEntry* dataSetEntry = dataSet->fcdas; + + while (dataSetEntry != NULL) { + + MmsValue* dataSetValue = dataSetEntry->value; + + if (dataSetValue != NULL) { /* prevent invalid data set members */ + if (isMemberValueRecursive(dataSetValue, value)) { + if (index != NULL) + *index = i; + + return true; + } + } + + i++; + + dataSetEntry = dataSetEntry->sibling; + } + + return false; +} +#endif /* ((CONFIG_IEC61850_REPORT_SERVICE == 1) || (CONFIG_INCLUDE_GOOSE_SUPPORT)) */ + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) +void +MmsMapping_triggerReportObservers(MmsMapping* self, MmsValue* value, ReportInclusionFlag flag) +{ + LinkedList element = self->reportControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + ReportControl* rc = (ReportControl*) element->data; + + if (rc->enabled || (rc->buffered && rc->dataSet != NULL)) { + int index; + + switch (flag) { + case REPORT_CONTROL_VALUE_UPDATE: + if ((rc->triggerOps & TRG_OPT_DATA_UPDATE) == 0) + continue; + break; + case REPORT_CONTROL_VALUE_CHANGED: + if (((rc->triggerOps & TRG_OPT_DATA_CHANGED) == 0) && + ((rc->triggerOps & TRG_OPT_DATA_UPDATE) == 0)) + continue; + break; + case REPORT_CONTROL_QUALITY_CHANGED: + if ((rc->triggerOps & TRG_OPT_QUALITY_CHANGED) == 0) + continue; + break; + default: + continue; + } + + if (DataSet_isMemberValue(rc->dataSet, value, &index)) { + ReportControl_valueUpdated(rc, index, flag, value); + } + } + } +} + +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +void +MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value) +{ + LinkedList element = self->gseControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; + + if (MmsGooseControlBlock_isEnabled(gcb)) { + DataSet* dataSet = MmsGooseControlBlock_getDataSet(gcb); + + if (DataSet_isMemberValue(dataSet, value, NULL)) { + MmsGooseControlBlock_observedObjectChanged(gcb); + } + } + } +} + +void +MmsMapping_enableGoosePublishing(MmsMapping* self) +{ + + LinkedList element = self->gseControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; + + MmsGooseControlBlock_enable(gcb); + } + +} + +void +MmsMapping_disableGoosePublishing(MmsMapping* self) +{ + LinkedList element = self->gseControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; + + MmsGooseControlBlock_disable(gcb); + } +} + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) +void +MmsMapping_addControlObject(MmsMapping* self, ControlObject* controlObject) +{ + LinkedList_add(self->controlObjects, controlObject); +} + +ControlObject* +MmsMapping_getControlObject(MmsMapping* self, MmsDomain* domain, char* lnName, char* coName) +{ + return Control_lookupControlObject(self, domain, lnName, coName); +} +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ + + +char* +MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer) +{ + int objRefLength = strlen(objectReference); + char* domainName = NULL; + + /* check for object reference size limit VISIBLESTRING129 */ + if (objRefLength > 129) + goto exit_function; + + /* check if LD name is present */ + int i; + for (i = 0; i < objRefLength; i++) { + if (objectReference[i] == '/') { + break; + } + } + + /* check for LD name limit (=64 characters) */ + if (i > 64) + goto exit_function; + + if (i == objRefLength) + goto exit_function; + + if (buffer == NULL) + domainName = (char*) GLOBAL_MALLOC(i + 1); + else + domainName = buffer; + + int j; + for (j = 0; j < i; j++) { + domainName[j] = objectReference[j]; + } + + domainName[j] = 0; + +exit_function: + return domainName; +} + +char* +MmsMapping_createMmsVariableNameFromObjectReference(const char* objectReference, + FunctionalConstraint fc, char* buffer) +{ + int objRefLength = strlen(objectReference); + + /* check for object reference size limit VISIBLESTRING129 */ + if (objRefLength > 129) + return NULL; + + /* check if LD name is present */ + int i; + for (i = 0; i < objRefLength; i++) { + if (objectReference[i] == '/') { + break; + } + } + + /* check for LD name limit (= 64 characters) */ + if (i > 64) + return NULL; + + if (i == objRefLength) + i = 0; + else + i++; + + char* fcString = FunctionalConstraint_toString(fc); + + if (fcString == NULL) + return NULL; + + int namePartLength = objRefLength - i - 1; + + /* ensure that limit due to MMS name part length = 64 is not exceeded */ + if (namePartLength > 61) + return NULL; + + char* mmsVariableName; + + if (buffer == NULL) + mmsVariableName = (char*) GLOBAL_MALLOC(namePartLength + 5); + else + mmsVariableName = buffer; + + int sourceIndex = i; + int destIndex = 0; + + bool fcAdded = false; + + while (sourceIndex < objRefLength) { + + if (objectReference[sourceIndex] != '.') + mmsVariableName[destIndex++] = objectReference[sourceIndex++]; + else { + + if (!fcAdded) { + mmsVariableName[destIndex++] = '$'; + mmsVariableName[destIndex++] = fcString[0]; + mmsVariableName[destIndex++] = fcString[1]; + mmsVariableName[destIndex++] = '$'; + + fcAdded = true; + } + else + mmsVariableName[destIndex++] = '$'; + + sourceIndex++; + } + } + + mmsVariableName[destIndex] = 0; + + return mmsVariableName; +} + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + +static void +GOOSE_processGooseEvents(MmsMapping* self, uint64_t currentTimeInMs) +{ + LinkedList element = LinkedList_getNext(self->gseControls); + + while (element != NULL) { + MmsGooseControlBlock mmsGCB = (MmsGooseControlBlock) element->data; + + if (MmsGooseControlBlock_isEnabled(mmsGCB)) { + MmsGooseControlBlock_checkAndPublish(mmsGCB, currentTimeInMs); + } + + element = LinkedList_getNext(element); + } +} + +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + + + +static void +processPeriodicTasks(MmsMapping* self) +{ + uint64_t currentTimeInMs = Hal_getTimeInMs(); + +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + GOOSE_processGooseEvents(self, currentTimeInMs); +#endif + +#if (CONFIG_IEC61850_CONTROL_SERVICE == 1) + Control_processControlActions(self, currentTimeInMs); +#endif + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + Reporting_processReportEvents(self, currentTimeInMs); +#endif + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + MmsMapping_checkForSettingGroupReservationTimeouts(self, currentTimeInMs); +#endif +} + +void +IedServer_performPeriodicTasks(IedServer self) +{ + processPeriodicTasks(self->mmsMapping); +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +/* single worker thread for all enabled GOOSE and report control blocks */ +static void +eventWorkerThread(MmsMapping* self) +{ + bool running = true; + self->reportThreadFinished = false; + + while (running) { + processPeriodicTasks(self); + + Thread_sleep(1); /* hand-over control to other threads */ + + running = self->reportThreadRunning; + } + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: event worker thread finished!\n"); + + self->reportThreadFinished = true; +} + +void +MmsMapping_startEventWorkerThread(MmsMapping* self) +{ + self->reportThreadRunning = true; + + Thread thread = Thread_create((ThreadExecutionFunction) eventWorkerThread, self, false); + self->reportWorkerThread = thread; + Thread_start(thread); +} + +void +MmsMapping_stopEventWorkerThread(MmsMapping* self) +{ + if (self->reportThreadRunning) { + + self->reportThreadRunning = false; + + while (self->reportThreadFinished == false) + Thread_sleep(1); + } +} +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + +DataSet* +MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableList variableList) +{ + DataSet* dataSet = (DataSet*) GLOBAL_MALLOC(sizeof(DataSet)); + + if (variableList->domain != NULL) + dataSet->logicalDeviceName = MmsDomain_getName(variableList->domain); + else + dataSet->logicalDeviceName = NULL; /* name is not relevant for association specific data sets */ + + dataSet->name = variableList->name; + dataSet->elementCount = LinkedList_size(variableList->listOfVariables); + + LinkedList element = LinkedList_getNext(variableList->listOfVariables); + + DataSetEntry* lastDataSetEntry = NULL; + + while (element != NULL) { + MmsAccessSpecifier* listEntry = (MmsAccessSpecifier*) element->data; + + DataSetEntry* dataSetEntry = (DataSetEntry*) GLOBAL_MALLOC(sizeof(DataSetEntry)); + + /* 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; + dataSetEntry->sibling = NULL; + + if (lastDataSetEntry == NULL) + dataSet->fcdas =dataSetEntry; + else + lastDataSetEntry->sibling = dataSetEntry; + + dataSetEntry->value = + MmsServer_getValueFromCache(self->mmsServer, listEntry->domain, listEntry->variableName); + + lastDataSetEntry = dataSetEntry; + + element = LinkedList_getNext(element); + } + + return dataSet; +} + +MmsNamedVariableList +MmsMapping_getDomainSpecificVariableList(MmsMapping* self, const char* variableListReference) +{ + char variableListReferenceCopy[193]; + + strncpy(variableListReferenceCopy, variableListReference, 192); + variableListReferenceCopy[192] = 0; + + char* separator = strchr(variableListReferenceCopy, '/'); + + if (separator == NULL) + return NULL; + + char* domainName = variableListReferenceCopy; + + char* variableListName = separator + 1; + + *separator = 0; + + MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); + + if (domain == NULL) + return NULL; + + MmsNamedVariableList variableList = MmsDomain_getNamedVariableList(domain, variableListName); + + return variableList; +} + +DataSet* +MmsMapping_getDomainSpecificDataSet(MmsMapping* self, const char* dataSetName) +{ + MmsNamedVariableList variableList = MmsMapping_getDomainSpecificVariableList(self, dataSetName); + + if (variableList == NULL) + return NULL; + + return MmsMapping_createDataSetByNamedVariableList(self, variableList); +} + +void +MmsMapping_freeDynamicallyCreatedDataSet(DataSet* dataSet) +{ + DataSetEntry* dataSetEntry = dataSet->fcdas; + + while (dataSetEntry != NULL) { + DataSetEntry* nextEntry = dataSetEntry->sibling; + + GLOBAL_FREEMEM (dataSetEntry); + + dataSetEntry = nextEntry; + } + + GLOBAL_FREEMEM(dataSet); +} + +MmsVariableAccessSpecification* +MmsMapping_ObjectReferenceToVariableAccessSpec(char* objectReference) +{ + char* domainIdEnd = strchr(objectReference, '/'); + + if (domainIdEnd == NULL) /* no logical device name present */ + return NULL; + + int domainIdLen = domainIdEnd - objectReference; + + if (domainIdLen > 64) + return NULL; + + char* fcStart = strchr(objectReference, '['); + + if (fcStart == NULL) /* no FC present */ + return NULL; + + char* fcEnd = strchr(fcStart, ']'); + + if (fcEnd == NULL) /* syntax error in FC */ + return NULL; + + if ((fcEnd - fcStart) != 3) /* syntax error in FC */ + return NULL; + + FunctionalConstraint fc = FunctionalConstraint_fromString(fcStart + 1); + + MmsVariableAccessSpecification* accessSpec = + (MmsVariableAccessSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableAccessSpecification)); + + accessSpec->domainId = createStringFromBuffer((uint8_t*) objectReference, domainIdLen); + + char* indexBrace = strchr(domainIdEnd, '('); + + char* itemIdEnd = indexBrace; + + if (itemIdEnd == NULL) + itemIdEnd = strchr(domainIdEnd, '['); + + int objRefLen = strlen(objectReference); + + accessSpec->arrayIndex = -1; /* -1 --> not present */ + + if (itemIdEnd != NULL) { + int itemIdLen = itemIdEnd - domainIdEnd - 1; + + char itemIdStr[129]; + + memcpy(itemIdStr, (domainIdEnd + 1), itemIdLen); + itemIdStr[itemIdLen] = 0; + + accessSpec->itemId = MmsMapping_createMmsVariableNameFromObjectReference(itemIdStr, fc, NULL); + + if (indexBrace != NULL) { + + char* indexStart = itemIdEnd + 1; + + char* indexEnd = strchr(indexStart, ')'); + + int indexLen = indexEnd - indexStart; + + int index = StringUtils_digitsToInt(indexStart, indexLen); + + accessSpec->arrayIndex = (int32_t) index; + + int componentNameLen = objRefLen - ((indexEnd + 2) - objectReference) - 4; + + if (componentNameLen > 0) { + accessSpec->componentName = createStringFromBuffer((uint8_t*) (indexEnd + 2), componentNameLen); + StringUtils_replace(accessSpec->componentName, '.', '$'); + } + } + } + + return accessSpec; +} + +static int +getNumberOfDigits(int value) +{ + int numberOfDigits = 1; + + while (value > 9) { + numberOfDigits++; + value /= 10; + } + + return numberOfDigits; +} + +char* +MmsMapping_varAccessSpecToObjectReference(MmsVariableAccessSpecification* varAccessSpec) +{ + char* domainId = varAccessSpec->domainId; + + int domainIdLen = strlen(domainId); + + char* itemId = varAccessSpec->itemId; + + char* separator = strchr(itemId, '$'); + + int itemIdLen = strlen(itemId); + + int arrayIndexLen = 0; + + int componentPartLen = 0; + + if (varAccessSpec->componentName != NULL) + componentPartLen = strlen(varAccessSpec->componentName); + + if (varAccessSpec->arrayIndex > -1) + arrayIndexLen = 2 + getNumberOfDigits(varAccessSpec->arrayIndex); + + int newStringLen = (domainIdLen + 1) + (itemIdLen - 2) + arrayIndexLen + 4 /* for FC */+ componentPartLen + 1; + + char* newString = (char*) GLOBAL_MALLOC(newStringLen); + + char* targetPos = newString; + + /* Copy domain id part */ + char* currentPos = domainId; + + while (currentPos < (domainId + domainIdLen)) { + *targetPos = *currentPos; + targetPos++; + currentPos++; + } + + *targetPos = '/'; + targetPos++; + + /* Copy item id parts */ + currentPos = itemId; + + while (currentPos < separator) { + *targetPos = *currentPos; + targetPos++; + currentPos++; + } + + *targetPos = '.'; + targetPos++; + + currentPos = separator + 4; + + while (currentPos < (itemId + itemIdLen)) { + if (*currentPos == '$') + *targetPos = '.'; + else + *targetPos = *currentPos; + + targetPos++; + currentPos++; + } + + /* Add array index part */ + if (varAccessSpec->arrayIndex > -1) { + sprintf(targetPos, "(%i)", varAccessSpec->arrayIndex); + targetPos += arrayIndexLen; + } + + /* Add component part */ + if (varAccessSpec->componentName != NULL) { + *targetPos = '.'; + targetPos++; + + int i; + for (i = 0; i < componentPartLen; i++) { + if (varAccessSpec->componentName[i] == '$') + *targetPos = '.'; + else + *targetPos = varAccessSpec->componentName[i]; + + targetPos++; + } + } + + /* add FC part */ + *targetPos = '['; + targetPos++; + *targetPos = *(separator + 1); + targetPos++; + *targetPos = *(separator + 2); + targetPos++; + *targetPos = ']'; + targetPos++; + + *targetPos = 0; /* add terminator */ + + return newString; +} + diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c new file mode 100644 index 0000000..61ee939 --- /dev/null +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -0,0 +1,2339 @@ +/* + * reporting.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_mapping.h" +#include "linked_list.h" +#include "array_list.h" +#include "stack_config.h" +#include "hal_thread.h" + +#include "simple_allocator.h" +#include "mem_alloc_linked_list.h" + +#include "reporting.h" +#include "mms_mapping_internal.h" +#include "mms_value_internal.h" +#include "conversions.h" +#include + +#ifndef DEBUG_IED_SERVER +#define DEBUG_IED_SERVER 0 +#endif + +#if (CONFIG_IEC61850_REPORT_SERVICE == 1) + +static ReportBuffer* +ReportBuffer_create(void) +{ + ReportBuffer* self = (ReportBuffer*) GLOBAL_MALLOC(sizeof(ReportBuffer)); + self->lastEnqueuedReport = NULL; + self->oldestReport = NULL; + self->nextToTransmit = NULL; + self->memoryBlockSize = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; + self->memoryBlock = (uint8_t*) GLOBAL_MALLOC(self->memoryBlockSize); + self->reportsCount = 0; + self->isOverflow = false; + + return self; +} + +static void +ReportBuffer_destroy(ReportBuffer* self) +{ + GLOBAL_FREEMEM(self->memoryBlock); + GLOBAL_FREEMEM(self); +} + +ReportControl* +ReportControl_create(bool buffered, LogicalNode* parentLN) +{ + ReportControl* self = (ReportControl*) GLOBAL_MALLOC(sizeof(ReportControl)); + self->name = NULL; + self->domain = NULL; + self->parentLN = parentLN; + self->rcbValues = NULL; + self->confRev = NULL; + self->enabled = false; + self->reserved = false; + self->buffered = buffered; + self->isBuffering = false; + self->isResync = false; + self->gi = false; + self->inclusionField = NULL; + self->dataSet = NULL; + self->isDynamicDataSet = false; + self->clientConnection = NULL; + self->intgPd = 0; + self->sqNum = 0; + self->nextIntgReportTime = 0; + self->inclusionFlags = NULL; + self->triggered = false; + self->timeOfEntry = NULL; + self->reservationTimeout = 0; + self->triggerOps = 0; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->createNotificationsMutex = Semaphore_create(1); +#endif + + self->bufferedDataSetValues = NULL; + self->valueReferences = NULL; + self->lastEntryId = 0; + + if (buffered) { + self->reportBuffer = ReportBuffer_create(); + } + + return self; +} + +static void +ReportControl_lockNotify(ReportControl* self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->createNotificationsMutex); +#endif +} + +static void +ReportControl_unlockNotify(ReportControl* self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->createNotificationsMutex); +#endif +} + + +static void +deleteDataSetValuesShadowBuffer(ReportControl* self) +{ + if (self->bufferedDataSetValues != NULL) { + assert(self->dataSet != NULL); + + int dataSetSize = DataSet_getSize(self->dataSet); + + int i; + + for (i = 0; i < dataSetSize; i++) { + if (self->bufferedDataSetValues[i] != NULL) + MmsValue_delete(self->bufferedDataSetValues[i]); + } + + GLOBAL_FREEMEM(self->bufferedDataSetValues); + + if (self->valueReferences != NULL) + GLOBAL_FREEMEM(self->valueReferences); + + self->bufferedDataSetValues = NULL; + } +} + +void +ReportControl_destroy(ReportControl* self) +{ + if (self->rcbValues != NULL ) + MmsValue_delete(self->rcbValues); + + if (self->inclusionFlags != NULL) + GLOBAL_FREEMEM(self->inclusionFlags); + + if (self->inclusionField != NULL) + MmsValue_delete(self->inclusionField); + + if (self->buffered == false) + MmsValue_delete(self->timeOfEntry); + + deleteDataSetValuesShadowBuffer(self); + + if (self->isDynamicDataSet) { + if (self->dataSet != NULL) { + MmsMapping_freeDynamicallyCreatedDataSet(self->dataSet); + self->isDynamicDataSet = false; + self->dataSet = NULL; + } + } + + if (self->buffered) + ReportBuffer_destroy(self->reportBuffer); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->createNotificationsMutex); +#endif + + GLOBAL_FREEMEM(self->name); + + GLOBAL_FREEMEM(self); +} + +MmsValue* +ReportControl_getRCBValue(ReportControl* rc, char* elementName) +{ + if (rc->buffered) { + if (strcmp(elementName, "RptID") == 0) + return MmsValue_getElement(rc->rcbValues, 0); + else if (strcmp(elementName, "RptEna") == 0) + return MmsValue_getElement(rc->rcbValues, 1); + else if (strcmp(elementName, "DatSet") == 0) + return MmsValue_getElement(rc->rcbValues, 2); + else if (strcmp(elementName, "ConfRev") == 0) + return MmsValue_getElement(rc->rcbValues, 3); + else if (strcmp(elementName, "OptFlds") == 0) + return MmsValue_getElement(rc->rcbValues, 4); + else if (strcmp(elementName, "BufTm") == 0) + return MmsValue_getElement(rc->rcbValues, 5); + else if (strcmp(elementName, "SqNum") == 0) + return MmsValue_getElement(rc->rcbValues, 6); + else if (strcmp(elementName, "TrgOps") == 0) + return MmsValue_getElement(rc->rcbValues, 7); + else if (strcmp(elementName, "IntgPd") == 0) + return MmsValue_getElement(rc->rcbValues, 8); + else if (strcmp(elementName, "GI") == 0) + return MmsValue_getElement(rc->rcbValues, 9); + else if (strcmp(elementName, "PurgeBuf") == 0) + return MmsValue_getElement(rc->rcbValues, 10); + else if (strcmp(elementName, "EntryID") == 0) + return MmsValue_getElement(rc->rcbValues, 11); + else if (strcmp(elementName, "TimeofEntry") == 0) + return MmsValue_getElement(rc->rcbValues, 12); + else if (strcmp(elementName, "ResvTms") == 0) + return MmsValue_getElement(rc->rcbValues, 13); + else if (strcmp(elementName, "Owner") == 0) + return MmsValue_getElement(rc->rcbValues, 14); + } else { + if (strcmp(elementName, "RptID") == 0) + return MmsValue_getElement(rc->rcbValues, 0); + else if (strcmp(elementName, "RptEna") == 0) + return MmsValue_getElement(rc->rcbValues, 1); + else if (strcmp(elementName, "Resv") == 0) + return MmsValue_getElement(rc->rcbValues, 2); + else if (strcmp(elementName, "DatSet") == 0) + return MmsValue_getElement(rc->rcbValues, 3); + else if (strcmp(elementName, "ConfRev") == 0) + return MmsValue_getElement(rc->rcbValues, 4); + else if (strcmp(elementName, "OptFlds") == 0) + return MmsValue_getElement(rc->rcbValues, 5); + else if (strcmp(elementName, "BufTm") == 0) + return MmsValue_getElement(rc->rcbValues, 6); + else if (strcmp(elementName, "SqNum") == 0) + return MmsValue_getElement(rc->rcbValues, 7); + else if (strcmp(elementName, "TrgOps") == 0) + return MmsValue_getElement(rc->rcbValues, 8); + else if (strcmp(elementName, "IntgPd") == 0) + return MmsValue_getElement(rc->rcbValues, 9); + else if (strcmp(elementName, "GI") == 0) + return MmsValue_getElement(rc->rcbValues, 10); + else if (strcmp(elementName, "Owner") == 0) + return MmsValue_getElement(rc->rcbValues, 11); + } + + return NULL ; +} + +static void +updateTimeOfEntry(ReportControl* self, uint64_t currentTime) +{ + MmsValue* timeOfEntry = self->timeOfEntry; + MmsValue_setBinaryTime(timeOfEntry, currentTime); +} + +static void +sendReport(ReportControl* self, bool isIntegrity, bool isGI) +{ + LinkedList reportElements = LinkedList_create(); + + LinkedList deletableElements = LinkedList_create(); + + MmsValue* rptId = ReportControl_getRCBValue(self, "RptID"); + MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds"); + MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet"); + + LinkedList_add(reportElements, rptId); + LinkedList_add(reportElements, optFlds); + + /* delete option fields for unsupported options */ + MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */ + MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */ + + MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum"); + + if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */ + LinkedList_add(reportElements, sqNum); + + if (MmsValue_getBitStringBit(optFlds, 2)) /* report time stamp */ + LinkedList_add(reportElements, self->timeOfEntry); + + if (MmsValue_getBitStringBit(optFlds, 4)) /* data set reference */ + LinkedList_add(reportElements, datSet); + + if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */ + MmsValue* bufOvfl = MmsValue_newBoolean(false); + + LinkedList_add(reportElements, bufOvfl); + LinkedList_add(deletableElements, bufOvfl); + } + + if (MmsValue_getBitStringBit(optFlds, 8)) + LinkedList_add(reportElements, self->confRev); + + if (isGI || isIntegrity) + MmsValue_setAllBitStringBits(self->inclusionField); + else + MmsValue_deleteAllBitStringBits(self->inclusionField); + + LinkedList_add(reportElements, self->inclusionField); + + /* add data references if selected */ + if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */ + DataSetEntry* dataSetEntry = self->dataSet->fcdas; + + LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent; + + IedModel* iedModel = (IedModel*) ld->parent; + + char* iedName = iedModel->name; + + int iedNameLength = strlen(iedName); + + int i = 0; + + for (i = 0; i < self->dataSet->elementCount; i++) { + assert(dataSetEntry->value != NULL); + + bool addReferenceForEntry = false; + + if (isGI || isIntegrity) + addReferenceForEntry = true; + else + if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) + addReferenceForEntry = true; + + if (addReferenceForEntry) { + + char dataReference[130]; + int currentPos = 0; + + int j; + + for (j = 0; j < iedNameLength; j++) { + dataReference[currentPos++] = iedName[j]; + } + + int ldNameLength = strlen(dataSetEntry->logicalDeviceName); + for (j = 0; j < ldNameLength; j++) { + dataReference[currentPos] = dataSetEntry->logicalDeviceName[j]; + currentPos++; + } + + dataReference[currentPos++] = '/'; + + for (j = 0; j < (int) strlen(dataSetEntry->variableName); j++) { + dataReference[currentPos++] = dataSetEntry->variableName[j]; + } + + dataReference[currentPos] = 0; + + MmsValue* dataRef = MmsValue_newVisibleString(dataReference); + + LinkedList_add(reportElements, dataRef); + LinkedList_add(deletableElements, dataRef); + } + + dataSetEntry = dataSetEntry->sibling; + + } + } + + + /* add data set value elements */ + DataSetEntry* dataSetEntry = self->dataSet->fcdas; + + int i = 0; + for (i = 0; i < self->dataSet->elementCount; i++) { + assert(dataSetEntry->value != NULL); + + if (isGI || isIntegrity) { + LinkedList_add(reportElements, dataSetEntry->value); + } + else { + if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { + assert(self->bufferedDataSetValues[i] != NULL); + + LinkedList_add(reportElements, self->bufferedDataSetValues[i]); + MmsValue_setBitStringBit(self->inclusionField, i, true); + } + } + + dataSetEntry = dataSetEntry->sibling; + } + + /* add reason code to report if requested */ + if (MmsValue_getBitStringBit(optFlds, 3)) { + for (i = 0; i < self->dataSet->elementCount; i++) { + + if (isGI || isIntegrity) { + MmsValue* reason = MmsValue_newBitString(6); + + if (isGI) + MmsValue_setBitStringBit(reason, 5, true); + + if (isIntegrity) + MmsValue_setBitStringBit(reason, 4, true); + + LinkedList_add(reportElements, reason); + LinkedList_add(deletableElements, reason); + } + else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { + MmsValue* reason = MmsValue_newBitString(6); + + if (self->inclusionFlags[i] == REPORT_CONTROL_QUALITY_CHANGED) + MmsValue_setBitStringBit(reason, 2, true); + else if (self->inclusionFlags[i] == REPORT_CONTROL_VALUE_CHANGED) + MmsValue_setBitStringBit(reason, 1, true); + else if (self->inclusionFlags[i] == REPORT_CONTROL_VALUE_UPDATE) + MmsValue_setBitStringBit(reason, 3, true); + + LinkedList_add(reportElements, reason); + LinkedList_add(deletableElements, reason); + } + } + } + + /* clear inclusion flags */ + for (i = 0; i < self->dataSet->elementCount; i++) + self->inclusionFlags[i] = REPORT_CONTROL_NONE; + + MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", reportElements, false); + + /* Increase sequence number */ + self->sqNum++; + + /* Unbuffered reporting --> sqNum is 8 bit only!!! */ + if (self->sqNum == 256) + self->sqNum = 0; + + MmsValue_setUint16(sqNum, self->sqNum); + + LinkedList_destroyDeep(deletableElements, (LinkedListValueDeleteFunction) MmsValue_delete); + LinkedList_destroyStatic(reportElements); +} + +static void +createDataSetValuesShadowBuffer(ReportControl* rc) +{ + int dataSetSize = DataSet_getSize(rc->dataSet); + + MmsValue** dataSetValues = (MmsValue**) GLOBAL_CALLOC(dataSetSize, sizeof(MmsValue*)); + + rc->bufferedDataSetValues = dataSetValues; + + rc->valueReferences = (MmsValue**) GLOBAL_MALLOC(dataSetSize * sizeof(MmsValue*)); + + DataSetEntry* dataSetEntry = rc->dataSet->fcdas; + + int i; + for (i = 0; i < dataSetSize; i++) { + assert(dataSetEntry != NULL); + + rc->valueReferences[i] = dataSetEntry->value; + + dataSetEntry = dataSetEntry->sibling; + } +} + +static bool +updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, MmsServerConnection connection) +{ + bool success = false; + + MmsValue* dataSetValue; + + if (newDatSet != NULL) { + if (strcmp(MmsValue_toString(newDatSet), "") == 0) { + success = true; + dataSetValue = NULL; + } + else + dataSetValue = newDatSet; + } + else + dataSetValue = ReportControl_getRCBValue(rc, "DatSet"); + + if (rc->isDynamicDataSet) { + if (rc->dataSet != NULL) { + deleteDataSetValuesShadowBuffer(rc); + MmsMapping_freeDynamicallyCreatedDataSet(rc->dataSet); + rc->isDynamicDataSet = false; + rc->dataSet = NULL; + } + } + + if (dataSetValue != NULL) { + const char* dataSetName = MmsValue_toString(dataSetValue); + + DataSet* dataSet = IedModel_lookupDataSet(mapping->model, dataSetName); + +#if (MMS_DYNAMIC_DATA_SETS == 1) + if (dataSet == NULL) { + dataSet = MmsMapping_getDomainSpecificDataSet(mapping, dataSetName); + + if (dataSet == NULL) { + + /* check if association specific data set is requested */ + if (dataSetName[0] == '@') { + if (connection != NULL) { + MmsNamedVariableList mmsVariableList + = MmsServerConnection_getNamedVariableList(connection, dataSetName + 1); + + if (mmsVariableList != NULL) + dataSet = MmsMapping_createDataSetByNamedVariableList(mapping, mmsVariableList); + } + } + } + + if (dataSet == NULL) + goto exit_function; + + rc->isDynamicDataSet = true; + + } + else + rc->isDynamicDataSet = false; +#else + + if (dataSet == NULL) + goto exit_function; + +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + + deleteDataSetValuesShadowBuffer(rc); + + rc->dataSet = dataSet; + + createDataSetValuesShadowBuffer(rc); + + if (rc->inclusionField != NULL) + MmsValue_delete(rc->inclusionField); + + rc->inclusionField = MmsValue_newBitString(dataSet->elementCount); + + if (rc->inclusionFlags != NULL) + GLOBAL_FREEMEM(rc->inclusionFlags); + + rc->inclusionFlags = (ReportInclusionFlag*) GLOBAL_CALLOC(dataSet->elementCount, sizeof(ReportInclusionFlag)); + + success = true; + goto exit_function; + } + +exit_function: + return success; +} + +static char* +createDataSetReferenceForDefaultDataSet(ReportControlBlock* rcb, ReportControl* reportControl) +{ + char* dataSetReference; + + char* domainName = MmsDomain_getName(reportControl->domain); + char* lnName = rcb->parent->name; + + dataSetReference = createString(5, domainName, "/", lnName, "$", rcb->dataSetName); + + return dataSetReference; +} + + +static MmsValue* +createOptFlds(ReportControlBlock* reportControlBlock) +{ + MmsValue* optFlds = MmsValue_newBitString(-10); + uint8_t options = reportControlBlock->options; + + if (options & RPT_OPT_SEQ_NUM) + MmsValue_setBitStringBit(optFlds, 1, true); + if (options & RPT_OPT_TIME_STAMP) + MmsValue_setBitStringBit(optFlds, 2, true); + if (options & RPT_OPT_REASON_FOR_INCLUSION) + MmsValue_setBitStringBit(optFlds, 3, true); + if (options & RPT_OPT_DATA_SET) + MmsValue_setBitStringBit(optFlds, 4, true); + if (options & RPT_OPT_DATA_REFERENCE) + MmsValue_setBitStringBit(optFlds, 5, true); + if (options & RPT_OPT_BUFFER_OVERFLOW) + MmsValue_setBitStringBit(optFlds, 6, true); + if (options & RPT_OPT_ENTRY_ID) + MmsValue_setBitStringBit(optFlds, 7, true); + if (options & RPT_OPT_CONF_REV) + MmsValue_setBitStringBit(optFlds, 8, true); + + return optFlds; +} + +static MmsValue* +createTrgOps(ReportControlBlock* reportControlBlock) { + MmsValue* trgOps = MmsValue_newBitString(-6); + + uint8_t triggerOps = reportControlBlock->trgOps; + + if (triggerOps & TRG_OPT_DATA_CHANGED) + MmsValue_setBitStringBit(trgOps, 1, true); + if (triggerOps & TRG_OPT_QUALITY_CHANGED) + MmsValue_setBitStringBit(trgOps, 2, true); + if (triggerOps & TRG_OPT_DATA_UPDATE) + MmsValue_setBitStringBit(trgOps, 3, true); + if (triggerOps & TRG_OPT_INTEGRITY) + MmsValue_setBitStringBit(trgOps, 4, true); + if (triggerOps & TRG_OPT_GI) + MmsValue_setBitStringBit(trgOps, 5, true); + + return trgOps; +} + +static void +refreshTriggerOptions(ReportControl* rc) +{ + rc->triggerOps = 0; + MmsValue* trgOps = ReportControl_getRCBValue(rc, "TrgOps"); + if (MmsValue_getBitStringBit(trgOps, 1)) + rc->triggerOps += TRG_OPT_DATA_CHANGED; + + if (MmsValue_getBitStringBit(trgOps, 2)) + rc->triggerOps += TRG_OPT_QUALITY_CHANGED; + + if (MmsValue_getBitStringBit(trgOps, 3)) + rc->triggerOps += TRG_OPT_DATA_UPDATE; + + if (MmsValue_getBitStringBit(trgOps, 4)) + rc->triggerOps += TRG_OPT_INTEGRITY; + + if (MmsValue_getBitStringBit(trgOps, 5)) + rc->triggerOps += TRG_OPT_GI; +} + +static void +purgeBuf(ReportControl* rc) +{ + if (DEBUG_IED_SERVER) printf("reporting.c: run purgeBuf\n"); + + ReportBuffer* reportBuffer = rc->reportBuffer; + + reportBuffer->lastEnqueuedReport = NULL; + reportBuffer->oldestReport = NULL; + reportBuffer->nextToTransmit = NULL; + reportBuffer->reportsCount = 0; +} + +static void +refreshIntegrityPeriod(ReportControl* rc) +{ + MmsValue* intgPd = ReportControl_getRCBValue(rc, "IntgPd"); + rc->intgPd = MmsValue_toUint32(intgPd); + + if (rc->buffered == false) + rc->nextIntgReportTime = 0; +} + +static void +refreshBufferTime(ReportControl* rc) +{ + MmsValue* bufTm = ReportControl_getRCBValue(rc, "BufTm"); + rc->bufTm = MmsValue_toUint32(bufTm); +} + +static void +composeDefaultRptIdString(char* rptIdString, ReportControl* reportControl) +{ + int bufPos = 0; + while (reportControl->domain->domainName[bufPos] != 0) { + rptIdString[bufPos] = reportControl->domain->domainName[bufPos]; + bufPos++; + } + rptIdString[bufPos++] = '/'; + int i = 0; + while (reportControl->name[i] != 0) { + rptIdString[bufPos] = reportControl->name[i]; + bufPos++; + i++; + } + rptIdString[bufPos] = 0; +} + +static MmsValue* +createDefaultRptId(ReportControl* reportControl) +{ + char rptIdString[130]; /* maximum length 129 chars */ + + composeDefaultRptIdString(rptIdString, reportControl); + + return MmsValue_newVisibleString(rptIdString); +} + +static void +updateWithDefaultRptId(ReportControl* reportControl, MmsValue* rptId) +{ + char rptIdString[130]; /* maximum length 129 chars */ + + composeDefaultRptIdString(rptIdString, reportControl); + + MmsValue_setVisibleString(rptId, rptIdString); +} + +static MmsVariableSpecification* +createUnbufferedReportControlBlock(ReportControlBlock* reportControlBlock, + ReportControl* reportControl) +{ + MmsVariableSpecification* rcb = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + rcb->name = copyString(reportControlBlock->name); + rcb->type = MMS_STRUCTURE; + + MmsValue* mmsValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + mmsValue->deleteValue = false; + mmsValue->type = MMS_STRUCTURE; + mmsValue->value.structure.size = 12; + mmsValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(12, sizeof(MmsValue*)); + + rcb->typeSpec.structure.elementCount = 12; + + rcb->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(12, + sizeof(MmsVariableSpecification*)); + + MmsVariableSpecification* namedVariable = + (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("RptID"); + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + rcb->typeSpec.structure.elements[0] = namedVariable; + if ((reportControlBlock->rptId != NULL) && (strlen(reportControlBlock->rptId) > 0)) + mmsValue->value.structure.components[0] = MmsValue_newVisibleString( + reportControlBlock->rptId); + else + mmsValue->value.structure.components[0] = createDefaultRptId(reportControl); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("RptEna"); + namedVariable->type = MMS_BOOLEAN; + rcb->typeSpec.structure.elements[1] = namedVariable; + mmsValue->value.structure.components[1] = MmsValue_newBoolean(false); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("Resv"); + namedVariable->type = MMS_BOOLEAN; + rcb->typeSpec.structure.elements[2] = namedVariable; + mmsValue->value.structure.components[2] = MmsValue_newBoolean(false); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("DatSet"); + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + rcb->typeSpec.structure.elements[3] = namedVariable; + + if (reportControlBlock->dataSetName != NULL) { + char* dataSetReference = createDataSetReferenceForDefaultDataSet(reportControlBlock, + reportControl); + mmsValue->value.structure.components[3] = MmsValue_newVisibleString(dataSetReference); + GLOBAL_FREEMEM(dataSetReference); + } + else + mmsValue->value.structure.components[3] = MmsValue_newVisibleString(""); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("ConfRev"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[4] = namedVariable; + mmsValue->value.structure.components[4] = + MmsValue_newUnsignedFromUint32(reportControlBlock->confRef); + + reportControl->confRev = mmsValue->value.structure.components[4]; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("OptFlds"); + namedVariable->type = MMS_BIT_STRING; + namedVariable->typeSpec.bitString = -10; + rcb->typeSpec.structure.elements[5] = namedVariable; + mmsValue->value.structure.components[5] = createOptFlds(reportControlBlock); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("BufTm"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[6] = namedVariable; + mmsValue->value.structure.components[6] = + MmsValue_newUnsignedFromUint32(reportControlBlock->bufferTime); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("SqNum"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 8; + rcb->typeSpec.structure.elements[7] = namedVariable; + mmsValue->value.structure.components[7] = MmsValue_newUnsigned(8); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("TrgOps"); + namedVariable->type = MMS_BIT_STRING; + namedVariable->typeSpec.bitString = -6; + rcb->typeSpec.structure.elements[8] = namedVariable; + mmsValue->value.structure.components[8] = createTrgOps(reportControlBlock); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("IntgPd"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[9] = namedVariable; + mmsValue->value.structure.components[9] = + MmsValue_newUnsignedFromUint32(reportControlBlock->intPeriod); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("GI"); + namedVariable->type = MMS_BOOLEAN; + rcb->typeSpec.structure.elements[10] = namedVariable; + mmsValue->value.structure.components[10] = MmsValue_newBoolean(false); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = 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; + + reportControl->timeOfEntry = MmsValue_newBinaryTime(false); + + refreshBufferTime(reportControl); + refreshIntegrityPeriod(reportControl); + refreshTriggerOptions(reportControl); + + return rcb; +} + +static MmsVariableSpecification* +createBufferedReportControlBlock(ReportControlBlock* reportControlBlock, + ReportControl* reportControl, MmsMapping* mmsMapping) +{ + MmsVariableSpecification* rcb = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + rcb->name = copyString(reportControlBlock->name); + rcb->type = MMS_STRUCTURE; + + MmsValue* mmsValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + mmsValue->deleteValue = false; + mmsValue->type = MMS_STRUCTURE; + mmsValue->value.structure.size = 15; + mmsValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(15, sizeof(MmsValue*)); + + rcb->typeSpec.structure.elementCount = 15; + + rcb->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(15, + sizeof(MmsVariableSpecification*)); + + MmsVariableSpecification* namedVariable = + (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("RptID"); + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + rcb->typeSpec.structure.elements[0] = namedVariable; + + if ((reportControlBlock->rptId != NULL) && (strlen(reportControlBlock->rptId) > 0)) + mmsValue->value.structure.components[0] = MmsValue_newVisibleString( + reportControlBlock->rptId); + else + mmsValue->value.structure.components[0] = createDefaultRptId(reportControl); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("RptEna"); + namedVariable->type = MMS_BOOLEAN; + rcb->typeSpec.structure.elements[1] = namedVariable; + mmsValue->value.structure.components[1] = MmsValue_newBoolean(false); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("DatSet"); + namedVariable->typeSpec.visibleString = -129; + namedVariable->type = MMS_VISIBLE_STRING; + rcb->typeSpec.structure.elements[2] = namedVariable; + + if (reportControlBlock->dataSetName != NULL) { + char* dataSetReference = createDataSetReferenceForDefaultDataSet(reportControlBlock, + reportControl); + + mmsValue->value.structure.components[2] = MmsValue_newVisibleString(dataSetReference); + GLOBAL_FREEMEM(dataSetReference); + } + else + mmsValue->value.structure.components[2] = MmsValue_newVisibleString(""); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("ConfRev"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[3] = namedVariable; + mmsValue->value.structure.components[3] = + MmsValue_newUnsignedFromUint32(reportControlBlock->confRef); + + reportControl->confRev = mmsValue->value.structure.components[3]; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("OptFlds"); + namedVariable->type = MMS_BIT_STRING; + namedVariable->typeSpec.bitString = -10; + rcb->typeSpec.structure.elements[4] = namedVariable; + mmsValue->value.structure.components[4] = createOptFlds(reportControlBlock); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("BufTm"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[5] = namedVariable; + mmsValue->value.structure.components[5] = + MmsValue_newUnsignedFromUint32(reportControlBlock->bufferTime); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("SqNum"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 16; + rcb->typeSpec.structure.elements[6] = namedVariable; + mmsValue->value.structure.components[6] = MmsValue_newUnsigned(16); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("TrgOps"); + namedVariable->type = MMS_BIT_STRING; + namedVariable->typeSpec.bitString = -6; + rcb->typeSpec.structure.elements[7] = namedVariable; + mmsValue->value.structure.components[7] = createTrgOps(reportControlBlock); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("IntgPd"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[8] = namedVariable; + mmsValue->value.structure.components[8] = + MmsValue_newUnsignedFromUint32(reportControlBlock->intPeriod); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("GI"); + namedVariable->type = MMS_BOOLEAN; + rcb->typeSpec.structure.elements[9] = namedVariable; + mmsValue->value.structure.components[9] = MmsValue_newBoolean(false); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("PurgeBuf"); + namedVariable->type = MMS_BOOLEAN; + rcb->typeSpec.structure.elements[10] = namedVariable; + mmsValue->value.structure.components[10] = MmsValue_newBoolean(false); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("EntryID"); + namedVariable->type = MMS_OCTET_STRING; + namedVariable->typeSpec.octetString = 8; + rcb->typeSpec.structure.elements[11] = namedVariable; + mmsValue->value.structure.components[11] = MmsValue_newOctetString(8, 8); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("TimeofEntry"); + namedVariable->type = MMS_BINARY_TIME; + namedVariable->typeSpec.binaryTime = 6; + rcb->typeSpec.structure.elements[12] = namedVariable; + mmsValue->value.structure.components[12] = MmsValue_newBinaryTime(false); + + reportControl->timeOfEntry = mmsValue->value.structure.components[12]; + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("ResvTms"); + namedVariable->type = MMS_UNSIGNED; + namedVariable->typeSpec.unsignedInteger = 32; + rcb->typeSpec.structure.elements[13] = namedVariable; + mmsValue->value.structure.components[13] = MmsValue_newUnsigned(32); + + namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("Owner"); + namedVariable->type = MMS_OCTET_STRING; + namedVariable->typeSpec.octetString = -64; + rcb->typeSpec.structure.elements[14] = namedVariable; + mmsValue->value.structure.components[14] = MmsValue_newOctetString(0, 4); /* size 4 is enough to store client IPv4 address */ + + reportControl->rcbValues = mmsValue; + + /* get initial values from BRCB */ + refreshBufferTime(reportControl); + refreshIntegrityPeriod(reportControl); + refreshTriggerOptions(reportControl); + + return rcb; +} + +static ReportControlBlock* +getRCBForLogicalNodeWithIndex(MmsMapping* self, LogicalNode* logicalNode, + int index, bool buffered) +{ + int rcbCount = 0; + + ReportControlBlock* nextRcb = self->model->rcbs; + + while (nextRcb != NULL ) { + if (nextRcb->parent == logicalNode) { + + if (nextRcb->buffered == buffered) { + if (rcbCount == index) + return nextRcb; + + rcbCount++; + } + + } + + nextRcb = nextRcb->sibling; + } + + return NULL ; +} + +MmsVariableSpecification* +Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode, int reportsCount) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("BR"); + namedVariable->type = MMS_STRUCTURE; + + namedVariable->typeSpec.structure.elementCount = reportsCount; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(reportsCount, + sizeof(MmsVariableSpecification*)); + + int currentReport = 0; + + while (currentReport < reportsCount) { + ReportControl* rc = ReportControl_create(true, logicalNode); + + rc->domain = domain; + + ReportControlBlock* reportControlBlock = getRCBForLogicalNodeWithIndex( + self, logicalNode, currentReport, true); + + rc->name = createString(3, logicalNode->name, "$BR$", + reportControlBlock->name); + + namedVariable->typeSpec.structure.elements[currentReport] = + createBufferedReportControlBlock(reportControlBlock, rc, self); + + LinkedList_add(self->reportControls, rc); + + currentReport++; + } + + return namedVariable; +} + +MmsVariableSpecification* +Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain, + LogicalNode* logicalNode, int reportsCount) +{ + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, + sizeof(MmsVariableSpecification)); + namedVariable->name = copyString("RP"); + namedVariable->type = MMS_STRUCTURE; + + namedVariable->typeSpec.structure.elementCount = reportsCount; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(reportsCount, + sizeof(MmsVariableSpecification*)); + + int currentReport = 0; + + while (currentReport < reportsCount) { + ReportControl* rc = ReportControl_create(false, logicalNode); + + rc->domain = domain; + + ReportControlBlock* reportControlBlock = getRCBForLogicalNodeWithIndex( + self, logicalNode, currentReport, false); + + rc->name = createString(3, logicalNode->name, "$RP$", + reportControlBlock->name); + + namedVariable->typeSpec.structure.elements[currentReport] = + createUnbufferedReportControlBlock(reportControlBlock, rc); + + LinkedList_add(self->reportControls, rc); + + currentReport++; + } + + return namedVariable; +} + +#define CONFIG_REPORTING_SUPPORTS_OWNER 1 + +static void +updateOwner(ReportControl* rc, MmsServerConnection connection) +{ + rc->clientConnection = connection; + +#if (CONFIG_REPORTING_SUPPORTS_OWNER == 1) + + MmsValue* owner = ReportControl_getRCBValue(rc, "Owner"); + + if (owner != NULL) { + + if (connection != NULL) { + char* clientAddressString = MmsServerConnection_getClientAddress(connection); + + if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: set owner to %s\n", clientAddressString); + + if (strchr(clientAddressString, '.') != NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: reporting.c: client address is IPv4 address\n"); + + uint8_t ipV4Addr[4]; + + int addrElementCount = 0; + + char* separator = clientAddressString; + + while (separator != NULL && addrElementCount < 4) { + int intVal = atoi(separator); + + ipV4Addr[addrElementCount] = intVal; + + separator = strchr(separator, '.'); + + if (separator != NULL) + separator++; // skip '.' character + + 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 emptyAddr[1]; + MmsValue_setOctetString(owner, emptyAddr, 0); + } + } + +#endif /* CONFIG_REPORTING_SUPPORTS_OWNER == 1*/ +} + +static bool +checkReportBufferForEntryID(ReportControl* rc, MmsValue* value) +{ + bool retVal = false; + + ReportBufferEntry* entry = rc->reportBuffer->oldestReport; + + while (entry != NULL) { + if (memcmp(entry->entryId, value->value.octetString.buf, 8) == 0) { + ReportBufferEntry* nextEntryForResync = entry->next; + + if (nextEntryForResync != NULL) { + rc->reportBuffer->nextToTransmit = nextEntryForResync; + rc->isResync = true; + } + else { + rc->isResync = false; + rc->reportBuffer->nextToTransmit = NULL; + } + + retVal = true; + break; + } + } + + return retVal; +} + +static void +increaseConfRev(ReportControl* self) +{ + uint32_t confRev = MmsValue_toUint32(self->confRev); + + confRev++; + + if (confRev == 0) + confRev = 1; + + MmsValue_setUint32(self->confRev, confRev); +} + +MmsDataAccessError +Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, + MmsServerConnection connection) +{ + MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; + + ReportControl_lockNotify(rc); + + if (strcmp(elementName, "RptEna") == 0) { + + if (value->value.boolean == true) { + + if (rc->enabled == true) { + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; + } + + if (DEBUG_IED_SERVER) + printf("Activate report for client %s\n", + MmsServerConnection_getClientAddress(connection)); + + if (updateReportDataset(self, rc, NULL, connection)) { + + updateOwner(rc, connection); + + MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); + + MmsValue_update(rptEna, value); + + rc->enabled = true; + rc->isResync = false; + rc->gi = false; + + refreshBufferTime(rc); + refreshTriggerOptions(rc); + refreshIntegrityPeriod(rc); + + rc->sqNum = 0; + + MmsValue* sqNum = ReportControl_getRCBValue(rc, "SqNum"); + + MmsValue_setUint32(sqNum, 0U); + + retVal = DATA_ACCESS_ERROR_SUCCESS; + goto exit_function; + } + else { + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; + } + } + else { + if (rc->enabled == false) + goto exit_function; + + if (((rc->enabled) || (rc->reserved)) && (rc->clientConnection != connection)) { + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; + } + + if (DEBUG_IED_SERVER) + printf("Deactivate report for client %s\n", + MmsServerConnection_getClientAddress(connection)); + + if (rc->buffered == false) { + GLOBAL_FREEMEM(rc->inclusionFlags); + rc->inclusionFlags = NULL; + + MmsValue* resv = ReportControl_getRCBValue(rc, "Resv"); + MmsValue_setBoolean(resv, false); + + rc->triggered = false; + + rc->reserved = false; + } + + updateOwner(rc, NULL); + + rc->enabled = false; + } + + } + + if (strcmp(elementName, "GI") == 0) { + if ((rc->enabled) && (rc->clientConnection == connection)) { + + if (MmsValue_getBoolean(value)) + rc->gi = true; + + retVal = DATA_ACCESS_ERROR_SUCCESS; + goto exit_function; + } + else { + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; + } + } + + if (rc->enabled == false) { + + if ((rc->reserved) && (rc->clientConnection != connection)) { + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; + } + + if (strcmp(elementName, "Resv") == 0) { + rc->reserved = value->value.boolean; + + if (rc->reserved == true) + rc->clientConnection = connection; + } + else if (strcmp(elementName, "PurgeBuf") == 0) { + if (MmsValue_getType(value) == MMS_BOOLEAN) { + + if (MmsValue_getBoolean(value) == true) { + purgeBuf(rc); + retVal = DATA_ACCESS_ERROR_SUCCESS; + goto exit_function; + } + } + + } + else if (strcmp(elementName, "DatSet") == 0) { + MmsValue* datSet = ReportControl_getRCBValue(rc, "DatSet"); + + if (!MmsValue_equals(datSet, value)) { + + if (updateReportDataset(self, rc, value, connection)) { + + if (rc->buffered) + purgeBuf(rc); + + MmsValue_update(datSet, value); + + increaseConfRev(rc); + } + else { + printf("BBBBBB\n"); + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; + } + } + + retVal = DATA_ACCESS_ERROR_SUCCESS; + goto exit_function; + } + else if (strcmp(elementName, "IntgPd") == 0) { + MmsValue* intgPd = ReportControl_getRCBValue(rc, elementName); + + if (!MmsValue_equals(intgPd, value)) { + MmsValue_update(intgPd, value); + + refreshIntegrityPeriod(rc); + + if (rc->buffered) { + rc->nextIntgReportTime = 0; + purgeBuf(rc); + } + } + + goto exit_function; + } + else if (strcmp(elementName, "TrgOps") == 0) { + MmsValue* trgOps = ReportControl_getRCBValue(rc, elementName); + + if (!MmsValue_equals(trgOps, value)) { + MmsValue_update(trgOps, value); + + if (rc->buffered) + purgeBuf(rc); + + refreshTriggerOptions(rc); + } + + goto exit_function; + } + else if (strcmp(elementName, "EntryId") == 0) { + if (MmsValue_getOctetStringSize(value) != 8) { + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; + } + + if (!checkReportBufferForEntryID(rc, value)) { + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; + } + + MmsValue* entryID = ReportControl_getRCBValue(rc, elementName); + + MmsValue_update(entryID, value); + + goto exit_function; + } + + else if (strcmp(elementName, "BufTm") == 0) { + MmsValue* bufTm = ReportControl_getRCBValue(rc, elementName); + + if (!MmsValue_equals(bufTm, value)) { + MmsValue_update(bufTm, value); + + if (rc->buffered) + purgeBuf(rc); + + refreshBufferTime(rc); + } + + goto exit_function; + } + else if ((strcmp(elementName, "ConfRev") == 0) || (strcmp(elementName, "SqNum") == 0)) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; + } + else if (strcmp(elementName, "RptID") == 0) { + MmsValue* rptId = ReportControl_getRCBValue(rc, elementName); + + if (strlen(MmsValue_toString(value)) == 0) + updateWithDefaultRptId(rc, rptId); + else + MmsValue_update(rptId, value); + + goto exit_function; + } + else if (strcmp(elementName, "SqNum") == 0) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; + } + else if (strcmp(elementName, "Owner") == 0) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; + } + + MmsValue* rcbValue = ReportControl_getRCBValue(rc, elementName); + + if (rcbValue != NULL) + MmsValue_update(rcbValue, value); + else { + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; + } + + } + else + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + +exit_function: + ReportControl_unlockNotify(rc); + + return retVal; +} + +void +Reporting_deactivateReportsForConnection(MmsMapping* self, MmsServerConnection connection) +{ + LinkedList reportControl = self->reportControls; + + while ((reportControl = LinkedList_getNext(reportControl)) != NULL) { + ReportControl* rc = (ReportControl*) reportControl->data; + + if (rc->clientConnection == connection) { + + rc->enabled = false; + rc->clientConnection = NULL; + + MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); + MmsValue_setBoolean(rptEna, false); + + if (rc->buffered == false) { + + if (rc->inclusionField != NULL) { + MmsValue_delete(rc->inclusionField); + rc->inclusionField = NULL; + } + + MmsValue* resv = ReportControl_getRCBValue(rc, "Resv"); + MmsValue_setBoolean(resv, false); + + rc->reserved = false; + } + + updateOwner(rc, NULL); + } + } +} + +#if (DEBUG_IED_SERVER == 1) +static void +printEnqueuedReports(ReportControl* reportControl) +{ + ReportBuffer* rb = reportControl->reportBuffer; + + printf("IED_SERVER: --- Enqueued reports ---\n"); + + if (rb->oldestReport == NULL) { + printf("IED_SERVER: -- no reports --\n"); + } + else { + ReportBufferEntry* entry = rb->oldestReport; + + while (entry != NULL) { + printf("IED_SERVER: "); + + int i = 0; + printf(" "); + for (i = 0; i < 8; i++) { + printf("%02x ", entry->entryId[i]); + } + printf(" at [%p] next [%p] (len=%i pos=%i)", entry, entry->next, + entry->entryLength, (int) ((uint8_t*) entry - rb->memoryBlock)); + + if (entry == rb->lastEnqueuedReport) + printf(" <-- lastEnqueued"); + + if (entry == rb->nextToTransmit) + printf(" <-- nexttoTransmit"); + + printf("\n"); + + entry = entry->next; + } + } + printf("IED_SERVER: reports: %i\n", rb->reportsCount); + printf("IED_SERVER: -------------------------\n"); +} + +static void +printReportId(ReportBufferEntry* report) +{ + int i = 0; + for (i = 0; i < 8; i++) { + printf("%02x ", report->entryId[i]); + } +} +#endif + +static void +enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_t timeOfEntry) +{ + if (DEBUG_IED_SERVER) printf("IED_SERVER: enqueueReport: RCB name: %s (SQN:%u) enabled:%i buffered:%i buffering:%i intg:%i GI:%i\n", + reportControl->name, (unsigned) reportControl->sqNum, reportControl->enabled, + reportControl->isBuffering, reportControl->buffered, isIntegrity, isGI); + + ReportBuffer* buffer = reportControl->reportBuffer; + + /* calculate size of complete buffer entry */ + int bufferEntrySize = sizeof(ReportBufferEntry); + + int inclusionFieldSize = MmsValue_getBitStringByteSize(reportControl->inclusionField); + + MmsValue inclusionFieldStatic; + + inclusionFieldStatic.type = MMS_BIT_STRING; + inclusionFieldStatic.value.bitString.size = MmsValue_getBitStringSize(reportControl->inclusionField); + + MmsValue* inclusionField = &inclusionFieldStatic; + + if (isIntegrity || isGI) { + + DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas; + + int i; + + for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) { + assert(dataSetEntry != NULL); + + bufferEntrySize += 1; /* reason-for-inclusion */ + + bufferEntrySize += MmsValue_getSizeInMemory(dataSetEntry->value); + + dataSetEntry = dataSetEntry->sibling; + } + } + else { /* other trigger reason */ + bufferEntrySize += inclusionFieldSize; + + int i; + + for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) { + + if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) { + bufferEntrySize += 1; /* reason-for-inclusion */ + + assert(reportControl->bufferedDataSetValues[i] != NULL); + + bufferEntrySize += MmsValue_getSizeInMemory(reportControl->bufferedDataSetValues[i]); + } + } + } + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: enqueueReport: bufferEntrySize: %i\n", bufferEntrySize); + + if (bufferEntrySize > buffer->memoryBlockSize) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: enqueueReport: report buffer too small for report entry! Skip event!\n"); + + return; + } + + uint8_t* entryBufPos = NULL; + uint8_t* entryStartPos; + + if (DEBUG_IED_SERVER) printf("IED_SERVER: number of buffered reports:%i\n", buffer->reportsCount); + + if (buffer->lastEnqueuedReport == NULL) { /* buffer is empty - we start at the beginning of the memory block */ + entryBufPos = buffer->memoryBlock; + buffer->oldestReport = (ReportBufferEntry*) entryBufPos; + buffer->nextToTransmit = (ReportBufferEntry*) entryBufPos; + } + else { + + assert(buffer->lastEnqueuedReport != NULL); + assert(buffer->oldestReport != NULL); + + if (DEBUG_IED_SERVER) { + printf("IED_SERVER: buffer->lastEnqueuedReport: %p\n", buffer->lastEnqueuedReport); + printf("IED_SERVER: buffer->oldestReport: %p\n", buffer->oldestReport); + printf("IED_SERVER: buffer->nextToTransmit: %p\n", buffer->nextToTransmit); + } + + if (DEBUG_IED_SERVER) printf ("IED_SERVER: Last buffer offset: %i\n", (int) ((uint8_t*) buffer->lastEnqueuedReport - buffer->memoryBlock)); + + if (buffer->lastEnqueuedReport == buffer->oldestReport) { // --> buffer->reportsCount = 1? + assert(buffer->reportsCount == 1); + + entryBufPos = (uint8_t*) ((uint8_t*) buffer->lastEnqueuedReport + buffer->lastEnqueuedReport->entryLength); + + if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) { /* buffer overflow */ + entryBufPos = buffer->memoryBlock; + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: REMOVE report with ID "); + printReportId(buffer->oldestReport); + printf("\n"); +#endif + + buffer->reportsCount = 0; + buffer->oldestReport = (ReportBufferEntry*) entryBufPos; + buffer->oldestReport->next = NULL; + buffer->nextToTransmit = NULL; + } + else { + if (buffer->nextToTransmit == buffer->oldestReport) + buffer->nextToTransmit = buffer->lastEnqueuedReport; + + buffer->oldestReport = buffer->lastEnqueuedReport; + buffer->oldestReport->next = (ReportBufferEntry*) entryBufPos; + } + + } + else if (buffer->lastEnqueuedReport > buffer->oldestReport) { + entryBufPos = (uint8_t*) ((uint8_t*) buffer->lastEnqueuedReport + buffer->lastEnqueuedReport->entryLength); + + if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) { /* buffer overflow */ + entryBufPos = buffer->memoryBlock; + + while ((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) { + assert(buffer->oldestReport != NULL); + + if (buffer->nextToTransmit == buffer->oldestReport) + buffer->nextToTransmit = buffer->oldestReport->next; + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: REMOVE report with ID "); + printReportId(buffer->oldestReport); + printf("\n"); +#endif + + buffer->isOverflow = true; + + buffer->oldestReport = buffer->oldestReport->next; + + buffer->reportsCount--; + + if (buffer->oldestReport == NULL) { + buffer->oldestReport = (ReportBufferEntry*) entryBufPos; + buffer->oldestReport->next = NULL; + break; + } + } + } + + buffer->lastEnqueuedReport->next = (ReportBufferEntry*) entryBufPos; + } + else if (buffer->lastEnqueuedReport < buffer->oldestReport) { + entryBufPos = (uint8_t*) ((uint8_t*) buffer->lastEnqueuedReport + buffer->lastEnqueuedReport->entryLength); + + if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) { /* buffer overflow */ + entryBufPos = buffer->memoryBlock; + + /* remove older reports in upper buffer part */ + while ((uint8_t*) buffer->oldestReport > buffer->memoryBlock) { + assert(buffer->oldestReport != NULL); + + if (buffer->nextToTransmit == buffer->oldestReport) + buffer->nextToTransmit = buffer->oldestReport->next; + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: REMOVE report with ID "); + printReportId(buffer->oldestReport); + printf("\n"); +#endif + + buffer->oldestReport = buffer->oldestReport->next; + buffer->reportsCount--; + } + + /* remove older reports in lower buffer part that will be overwritten by new report */ + while ((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) { + if (buffer->oldestReport == NULL) + break; + + assert(buffer->oldestReport != NULL); + + if (buffer->nextToTransmit == buffer->oldestReport) + buffer->nextToTransmit = buffer->oldestReport->next; + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: REMOVE report with ID "); + printReportId(buffer->oldestReport); + printf("\n"); +#endif + + buffer->oldestReport = buffer->oldestReport->next; + buffer->reportsCount--; + } + } + else { + while (((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) && ((uint8_t*) buffer->oldestReport != buffer->memoryBlock)) { + + if (buffer->oldestReport == NULL) + break; + + assert(buffer->oldestReport != NULL); + + if (buffer->nextToTransmit == buffer->oldestReport) + buffer->nextToTransmit = buffer->oldestReport->next; + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: REMOVE report with ID "); + printReportId(buffer->oldestReport); + printf("\n"); +#endif + + buffer->oldestReport = buffer->oldestReport->next; + buffer->reportsCount--; + } + } + + buffer->lastEnqueuedReport->next = (ReportBufferEntry*) entryBufPos; + } + + } + + entryStartPos = entryBufPos; + buffer->lastEnqueuedReport = (ReportBufferEntry*) entryBufPos; + buffer->lastEnqueuedReport->next = NULL; + buffer->reportsCount++; + + ReportBufferEntry* entry = (ReportBufferEntry*) entryBufPos; + + /* ENTRY_ID is set to system time in ms! */ + uint64_t entryId = timeOfEntry; + + if (entryId <= reportControl->lastEntryId) + entryId = reportControl->lastEntryId + 1; + + entry->timeOfEntry = entryId; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(entry->entryId, (uint8_t*) &entryId, 8); +#else + memcpy (entry->entryId, (uint8_t*) &entryId, 8); +#endif + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: ENCODE REPORT WITH ID: "); + printReportId(entry); + printf(" at pos %p\n", entryStartPos); +#endif + + if (reportControl->enabled == false) { + MmsValue* entryIdValue = MmsValue_getElement(reportControl->rcbValues, 11); + MmsValue_setOctetString(entryIdValue, (uint8_t*) entry->entryId, 8); + } + + if (isIntegrity) + entry->flags = 1; + else if (isGI) + entry->flags = 2; + else + entry->flags = 0; + + if ((bufferEntrySize % sizeof(void*)) > 0) + bufferEntrySize = sizeof(void*) * ((bufferEntrySize + sizeof(void*) - 1) / sizeof(void*)); + + entry->entryLength = bufferEntrySize; + + entryBufPos += sizeof(ReportBufferEntry); + + if (isIntegrity || isGI) { + DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas; + + int i; + + for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) { + + assert(dataSetEntry != NULL); + + *entryBufPos = (uint8_t) reportControl->inclusionFlags[i]; + entryBufPos++; + + entryBufPos = MmsValue_cloneToBuffer(dataSetEntry->value, entryBufPos); + + dataSetEntry = dataSetEntry->sibling; + } + + } + else { + inclusionFieldStatic.value.bitString.buf = entryBufPos; + memset(entryBufPos, 0, inclusionFieldSize); + entryBufPos += inclusionFieldSize; + + int i; + + for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) { + + if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) { + + assert(reportControl->bufferedDataSetValues[i] != NULL); + + *entryBufPos = (uint8_t) reportControl->inclusionFlags[i]; + entryBufPos++; + + entryBufPos = MmsValue_cloneToBuffer(reportControl->bufferedDataSetValues[i], entryBufPos); + + MmsValue_setBitStringBit(inclusionField, i, true); + } + + } + } + + /* clear inclusion flags */ + int i; + + for (i = 0; i < reportControl->dataSet->elementCount; i++) + reportControl->inclusionFlags[i] = REPORT_CONTROL_NONE; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: enqueueReport: encoded %i bytes for report (estimated %i) at buffer offset %i\n", + (int) (entryBufPos - entryStartPos), bufferEntrySize, (int) (entryStartPos - buffer->memoryBlock)); + +#if (DEBUG_IED_SERVER == 1) + printEnqueuedReports(reportControl); +#endif + + if (buffer->nextToTransmit == NULL) + buffer->nextToTransmit = buffer->lastEnqueuedReport; + + if (buffer->oldestReport == NULL) + buffer->oldestReport = buffer->lastEnqueuedReport; + + reportControl->lastEntryId = entryId; +} + +static void +sendNextReportEntry(ReportControl* self) +{ +#define LOCAL_STORAGE_MEMORY_SIZE 65536 + + if (self->reportBuffer->nextToTransmit == NULL) + return; + + char* localStorage = (char*) GLOBAL_MALLOC(LOCAL_STORAGE_MEMORY_SIZE); /* reserve 64k for dynamic memory allocation - + this can be optimized - maybe there is a good guess for the + required memory size */ + + if (localStorage == NULL) /* out-of-memory */ + goto return_out_of_memory; + + MemoryAllocator ma; + MemoryAllocator_init(&ma, localStorage, LOCAL_STORAGE_MEMORY_SIZE); + + ReportBufferEntry* report = self->reportBuffer->nextToTransmit; + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: SEND NEXT REPORT: "); + printReportId(report); + printf(" size: %i\n", report->entryLength); +#endif + + MmsValue* entryIdValue = MmsValue_getElement(self->rcbValues, 11); + MmsValue_setOctetString(entryIdValue, (uint8_t*) report->entryId, 8); + + MemAllocLinkedList reportElements = MemAllocLinkedList_create(&ma); + + assert(reportElements != NULL); + + if (reportElements == NULL) + goto return_out_of_memory; + + MmsValue* rptId = ReportControl_getRCBValue(self, "RptID"); + MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds"); + + if (MemAllocLinkedList_add(reportElements, rptId) == NULL) + goto return_out_of_memory; + + if (MemAllocLinkedList_add(reportElements, optFlds) == NULL) + goto return_out_of_memory; + + MmsValue inclusionFieldStack; + + inclusionFieldStack.type = MMS_BIT_STRING; + inclusionFieldStack.value.bitString.size = MmsValue_getBitStringSize(self->inclusionField); + + uint8_t* currentReportBufferPos = (uint8_t*) report + sizeof(ReportBufferEntry); + + inclusionFieldStack.value.bitString.buf = currentReportBufferPos; + + MmsValue* inclusionField = &inclusionFieldStack; + + if (report->flags == 0) + currentReportBufferPos += MmsValue_getBitStringByteSize(inclusionField); + else { + inclusionFieldStack.value.bitString.buf = + (uint8_t*) MemoryAllocator_allocate(&ma, MmsValue_getBitStringByteSize(inclusionField)); + + if (inclusionFieldStack.value.bitString.buf == NULL) + goto return_out_of_memory; + } + + uint8_t* valuesInReportBuffer = currentReportBufferPos; + + MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */ + + MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum"); + + if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */ + if (MemAllocLinkedList_add(reportElements, sqNum) == NULL) + goto return_out_of_memory; + + if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */ + MmsValue* timeOfEntry = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue)); + + if (timeOfEntry == NULL) goto return_out_of_memory; + + timeOfEntry->deleteValue = 0; + timeOfEntry->type = MMS_UTC_TIME; + MmsValue_setUtcTimeMs(timeOfEntry, report->timeOfEntry); + + if (MemAllocLinkedList_add(reportElements, timeOfEntry) == NULL) + goto return_out_of_memory; + } + + if (MmsValue_getBitStringBit(optFlds, 4)) {/* data set reference */ + MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet"); + if (MemAllocLinkedList_add(reportElements, datSet) == NULL) + goto return_out_of_memory; + } + + if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */ + + MmsValue* bufOvfl = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue)); + + if (bufOvfl == NULL) goto return_out_of_memory; + + bufOvfl->deleteValue = 0; + bufOvfl->type = MMS_BOOLEAN; + bufOvfl->value.boolean = self->reportBuffer->isOverflow; + + if (self->reportBuffer->isOverflow) + self->reportBuffer->isOverflow = false; + + if (MemAllocLinkedList_add(reportElements, bufOvfl) == NULL) + goto return_out_of_memory; + } + + if (MmsValue_getBitStringBit(optFlds, 7)) { /* entryID */ + MmsValue* entryId = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue)); + + if (entryId == NULL) goto return_out_of_memory; + + entryId->deleteValue = 0; + entryId->type = MMS_OCTET_STRING; + entryId->value.octetString.buf = report->entryId; + entryId->value.octetString.size = 8; + entryId->value.octetString.maxSize = 8; + + if (MemAllocLinkedList_add(reportElements, entryId) == NULL) + goto return_out_of_memory; + } + + if (MmsValue_getBitStringBit(optFlds, 8)) + if (MemAllocLinkedList_add(reportElements, self->confRev) == NULL) + goto return_out_of_memory; + + if (report->flags > 0) + MmsValue_setAllBitStringBits(inclusionField); + + if (MemAllocLinkedList_add(reportElements, inclusionField) == NULL) + goto return_out_of_memory; + + /* add data references if selected */ + if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */ + DataSetEntry* dataSetEntry = self->dataSet->fcdas; + + LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent; + + IedModel* iedModel = (IedModel*) ld->parent; + + char* iedName = iedModel->name; + + int iedNameLength = strlen(iedName); + + int i = 0; + + for (i = 0; i < self->dataSet->elementCount; i++) { + assert(dataSetEntry->value != NULL); + + bool addReferenceForEntry = false; + + if (report->flags > 0) + addReferenceForEntry = true; + else + if (MmsValue_getBitStringBit(inclusionField, i)) + addReferenceForEntry = true; + + if (addReferenceForEntry) { + + int ldNameLength = strlen(dataSetEntry->logicalDeviceName); + int variableNameLength = strlen(dataSetEntry->variableName); + + int refLen = iedNameLength + + ldNameLength + + variableNameLength + 1; + + char* dataReference = (char*) MemoryAllocator_allocate(&ma, refLen + 1); + + if (dataReference == NULL) goto return_out_of_memory; + + int currentPos = 0; + + int j; + + for (j = 0; j < iedNameLength; j++) { + dataReference[currentPos++] = iedName[j]; + } + + for (j = 0; j < ldNameLength; j++) { + dataReference[currentPos] = dataSetEntry->logicalDeviceName[j]; + currentPos++; + } + + dataReference[currentPos++] = '/'; + + for (j = 0; j < variableNameLength; j++) { + dataReference[currentPos++] = dataSetEntry->variableName[j]; + } + + dataReference[currentPos] = 0; + + MmsValue* dataRef = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue)); + + if (dataRef == NULL) goto return_out_of_memory; + + dataRef->deleteValue = 0; + dataRef->type = MMS_VISIBLE_STRING; + dataRef->value.visibleString.buf = dataReference; + dataRef->value.visibleString.size = refLen; + + + if (MemAllocLinkedList_add(reportElements, dataRef) == NULL) + goto return_out_of_memory; + + } + + dataSetEntry = dataSetEntry->sibling; + + } + } + + /* add data set value elements */ + int i = 0; + for (i = 0; i < self->dataSet->elementCount; i++) { + + if (report->flags > 0) { + currentReportBufferPos++; + if (MemAllocLinkedList_add(reportElements, currentReportBufferPos) == NULL) + goto return_out_of_memory; + + currentReportBufferPos += MmsValue_getSizeInMemory((MmsValue*) currentReportBufferPos); + } + else { + if (MmsValue_getBitStringBit(inclusionField, i)) { + currentReportBufferPos++; + if (MemAllocLinkedList_add(reportElements, currentReportBufferPos) == NULL) + goto return_out_of_memory; + currentReportBufferPos += MmsValue_getSizeInMemory((MmsValue*) currentReportBufferPos); + } + } + } + + /* add reason code to report if requested */ + if (MmsValue_getBitStringBit(optFlds, 3)) { + currentReportBufferPos = valuesInReportBuffer; + + for (i = 0; i < self->dataSet->elementCount; i++) { + + if (report->flags > 0) { + MmsValue* reason = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue)); + + if (reason == NULL) goto return_out_of_memory; + + reason->deleteValue = 0; + reason->type = MMS_BIT_STRING; + reason->value.bitString.size = 6; + reason->value.bitString.buf = (uint8_t*) MemoryAllocator_allocate(&ma, 1); + + if (reason->value.bitString.buf == NULL) goto return_out_of_memory; + + MmsValue_deleteAllBitStringBits(reason); + + if (report->flags & 0x02) /* GI */ + MmsValue_setBitStringBit(reason, 5, true); + + if (report->flags & 0x01) /* Integrity */ + MmsValue_setBitStringBit(reason, 4, true); + + if (MemAllocLinkedList_add(reportElements, reason) == NULL) + goto return_out_of_memory; + + currentReportBufferPos++; + + MmsValue* dataSetElement = (MmsValue*) currentReportBufferPos; + + currentReportBufferPos += MmsValue_getSizeInMemory(dataSetElement); + } + else if (MmsValue_getBitStringBit(inclusionField, i)) { + MmsValue* reason = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue)); + + if (reason == NULL) goto return_out_of_memory; + + reason->deleteValue = 0; + reason->type = MMS_BIT_STRING; + reason->value.bitString.size = 6; + reason->value.bitString.buf = (uint8_t*) MemoryAllocator_allocate(&ma, 1); + + if (reason->value.bitString.buf == NULL) + goto return_out_of_memory; + + MmsValue_deleteAllBitStringBits(reason); + + switch((ReportInclusionFlag) *currentReportBufferPos) { + case REPORT_CONTROL_QUALITY_CHANGED: + MmsValue_setBitStringBit(reason, 2, true); + break; + case REPORT_CONTROL_VALUE_CHANGED: + MmsValue_setBitStringBit(reason, 1, true); + break; + case REPORT_CONTROL_VALUE_UPDATE: + MmsValue_setBitStringBit(reason, 3, true); + break; + default: + break; + } + + currentReportBufferPos++; + + MmsValue* dataSetElement = (MmsValue*) currentReportBufferPos; + + currentReportBufferPos += MmsValue_getSizeInMemory(dataSetElement); + + if (MemAllocLinkedList_add(reportElements, reason) == NULL) + goto return_out_of_memory; + } + } + } + + MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", (LinkedList) reportElements, false); + + /* Increase sequence number */ + self->sqNum++; + MmsValue_setUint32(sqNum, self->sqNum); + + assert(self->reportBuffer->nextToTransmit != self->reportBuffer->nextToTransmit->next); + + self->reportBuffer->nextToTransmit = self->reportBuffer->nextToTransmit->next; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: sendNextReportEntry: memory(used/size): %i/%i\n", + (int) (ma.currentPtr - ma.memoryBlock), ma.size); + +#if (DEBUG_IED_SERVER == 1) + printf("IED_SERVER: reporting.c nextToTransmit: %p\n", self->reportBuffer->nextToTransmit); + printEnqueuedReports(self); +#endif + + goto cleanup_and_return; + +return_out_of_memory: + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: sendNextReportEntry failed - memory allocation problem!\n"); + + //TODO set some flag to notify application here + +cleanup_and_return: + + if (localStorage != NULL) + GLOBAL_FREEMEM(localStorage); +} + +void +Reporting_activateBufferedReports(MmsMapping* self) +{ + LinkedList element = self->reportControls; + + while ((element = LinkedList_getNext(element)) != NULL ) { + ReportControl* rc = (ReportControl*) element->data; + + if (rc->buffered) { + if (updateReportDataset(self, rc, NULL, NULL)) + rc->isBuffering = true; + else + rc->isBuffering = false; + } + } +} + +static void +processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) +{ + if ((rc->enabled) || (rc->isBuffering)) { + + if (rc->triggerOps & TRG_OPT_GI) { + if (rc->gi) { + + /* send current events in event buffer before GI report */ + if (rc->triggered) { + if (rc->buffered) + enqueueReport(rc, false, false, currentTimeInMs); + else + sendReport(rc, false, false); + + rc->triggered = false; + } + + updateTimeOfEntry(rc, currentTimeInMs); + + if (rc->buffered) + enqueueReport(rc, false, true, currentTimeInMs); + else + sendReport(rc, false, true); + + rc->gi = false; + + rc->triggered = false; + } + } + + if (rc->triggerOps & TRG_OPT_INTEGRITY) { + + if (rc->intgPd > 0) { + if (currentTimeInMs >= rc->nextIntgReportTime) { + + /* send current events in event buffer before integrity report */ + if (rc->triggered) { + if (rc->buffered) + enqueueReport(rc, false, false, currentTimeInMs); + else + sendReport(rc, false, false); + + rc->triggered = false; + } + + rc->nextIntgReportTime = currentTimeInMs + rc->intgPd; + updateTimeOfEntry(rc, currentTimeInMs); + + if (rc->buffered) + enqueueReport(rc, true, false, currentTimeInMs); + else + sendReport(rc, true, false); + + rc->triggered = false; + } + } + } + + if (rc->triggered) { + if (currentTimeInMs >= rc->reportTime) { + + if (rc->buffered) + enqueueReport(rc, false, false, currentTimeInMs); + else + sendReport(rc, false, false); + + rc->triggered = false; + } + } + + if (rc->buffered && rc->enabled) + sendNextReportEntry(rc); + + } +} + +void +Reporting_processReportEvents(MmsMapping* self, uint64_t currentTimeInMs) +{ + LinkedList element = self->reportControls; + + while ((element = LinkedList_getNext(element)) != NULL ) { + ReportControl* rc = (ReportControl*) element->data; + + ReportControl_lockNotify(rc); + + processEventsForReport(rc, currentTimeInMs); + + ReportControl_unlockNotify(rc); + } +} + +void +ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, ReportInclusionFlag flag, MmsValue* value) +{ + ReportControl_lockNotify(self); + + if (self->inclusionFlags[dataSetEntryIndex] != 0) { /* report for this data set entry is already pending (bypass BufTm) */ + self->reportTime = Hal_getTimeInMs(); + processEventsForReport(self, self->reportTime); + } + + self->inclusionFlags[dataSetEntryIndex] = flag; + + /* buffer value for report */ + if (self->bufferedDataSetValues[dataSetEntryIndex] == NULL) + self->bufferedDataSetValues[dataSetEntryIndex] = MmsValue_clone(self->valueReferences[dataSetEntryIndex]); + else + MmsValue_update(self->bufferedDataSetValues[dataSetEntryIndex], self->valueReferences[dataSetEntryIndex]); + + if (self->triggered == false) { + uint64_t currentTime = Hal_getTimeInMs(); + + MmsValue_setBinaryTime(self->timeOfEntry, currentTime); + + self->reportTime = currentTime + self->bufTm; + } + + self->triggered = true; + + ReportControl_unlockNotify(self); +} + +#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ diff --git a/src/iec61850/server/model/cdc.c b/src/iec61850/server/model/cdc.c new file mode 100644 index 0000000..9391b99 --- /dev/null +++ b/src/iec61850/server/model/cdc.c @@ -0,0 +1,1155 @@ +/* + * cdc.c + * + * Helper functions for the dynamic creation of Common Data Classes (CDCs) + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_dynamic_model.h" +#include "iec61850_cdc.h" +#include "libiec61850_platform_includes.h" + +/************************************************ + * Constructed Attribute Classes + ***********************************************/ + +DataAttribute* +CAC_AnalogueValue_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, + bool isIntegerNotFloat) +{ + DataAttribute* analogeValue = DataAttribute_create(name, parent, CONSTRUCTED, fc, triggerOptions, 0, 0); + + if (isIntegerNotFloat) + DataAttribute_create("i", (ModelNode*) analogeValue, INT32, fc, triggerOptions, 0, 0); + else + DataAttribute_create("f", (ModelNode*) analogeValue, FLOAT32, fc, triggerOptions, 0, 0); + + return analogeValue; +} + +DataAttribute* +CAC_ValWithTrans_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasTransientIndicator) +{ + DataAttribute* valWithTrans = DataAttribute_create(name, parent, CONSTRUCTED, fc, triggerOptions, 0, 0); + + DataAttribute_create("posVal", (ModelNode*) valWithTrans, INT8, fc, triggerOptions, 0, 0); + + if (hasTransientIndicator) + DataAttribute_create("transInd", (ModelNode*) valWithTrans, BOOLEAN, fc, triggerOptions, 0, 0); + + return valWithTrans; +} + +/** + * CDC_OPTION_AC_CLC_O + */ +DataAttribute* +CAC_Vector_create(const char* name, ModelNode* parent, uint32_t options, FunctionalConstraint fc, uint8_t triggerOptions) +{ + DataAttribute* vector = DataAttribute_create(name, parent, CONSTRUCTED, fc, triggerOptions, 0, 0); + + CAC_AnalogueValue_create("mag", (ModelNode*) vector, fc, triggerOptions, false); + + if (options & CDC_OPTION_AC_CLC_O) + CAC_AnalogueValue_create("ang", (ModelNode*) vector, fc, triggerOptions, false); + + return vector; +} + +DataAttribute* +CAC_Point_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasZVal) +{ + DataAttribute* point = DataAttribute_create(name, parent, CONSTRUCTED, fc, triggerOptions, 0, 0); + + DataAttribute_create("xVal", (ModelNode*) point, FLOAT32, fc, triggerOptions, 0, 0); + DataAttribute_create("yVal", (ModelNode*) point, FLOAT32, fc, triggerOptions, 0, 0); + + if (hasZVal) + DataAttribute_create("zVal", (ModelNode*) point, FLOAT32, fc, triggerOptions, 0, 0); + + return point; +} + +DataAttribute* +CAC_ScaledValueConfig_create(const char* name, ModelNode* parent) +{ + DataAttribute* scaling = DataAttribute_create(name, parent, CONSTRUCTED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + DataAttribute_create("scaleFactor", (ModelNode*) scaling, FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("offset", (ModelNode*) scaling, FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + return scaling; +} + +DataAttribute* +CAC_Unit_create(const char* name, ModelNode* parent, bool hasMagnitude) +{ + DataAttribute* unit = DataAttribute_create(name, parent, CONSTRUCTED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + DataAttribute_create("SIUnit", (ModelNode*) unit, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + if (hasMagnitude) + DataAttribute_create("multiplier", (ModelNode*) unit, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + return unit; +} + +/************************************************ + * Control parameters + ************************************************/ + +static void +addOriginator(char* name, ModelNode* parent, FunctionalConstraint fc) +{ + DataAttribute* origin = DataAttribute_create(name, parent, CONSTRUCTED, fc, 0 ,0 ,0); + + DataAttribute_create("orCat", (ModelNode*) origin, ENUMERATED, fc, 0, 0, 0); + DataAttribute_create("orIdent", (ModelNode*) origin, OCTET_STRING_64, fc, 0, 0, 0); + +} + +static void +addGenericOperateElements(DataAttribute* oper, DataAttributeType type, bool isTimeActivated, bool hasCheck) +{ + DataAttribute_create("ctlVal", (ModelNode*) oper, type, IEC61850_FC_CO, 0, 0, 0); + + if (isTimeActivated) + DataAttribute_create("operTm", (ModelNode*) oper, TIMESTAMP, IEC61850_FC_CO, 0, 0, 0); + + addOriginator("origin", (ModelNode*) oper, IEC61850_FC_CO); + + DataAttribute_create("ctlNum", (ModelNode*) oper, INT8U, IEC61850_FC_CO, 0, 0, 0); + DataAttribute_create("T", (ModelNode*) oper, TIMESTAMP, IEC61850_FC_CO, 0, 0, 0); + DataAttribute_create("Test", (ModelNode*) oper, BOOLEAN, IEC61850_FC_CO, 0, 0, 0); + + if (hasCheck) + DataAttribute_create("Check", (ModelNode*) oper, CHECK, IEC61850_FC_CO, 0, 0, 0); +} + +static void +addCommonOperateElements(DataAttribute* oper, bool isTimeActivated, bool hasCheck) +{ + if (isTimeActivated) + DataAttribute_create("operTm", (ModelNode*) oper, TIMESTAMP, IEC61850_FC_CO, 0, 0, 0); + + addOriginator("origin", (ModelNode*) oper, IEC61850_FC_CO); + + DataAttribute_create("ctlNum", (ModelNode*) oper, INT8U, IEC61850_FC_CO, 0, 0, 0); + DataAttribute_create("T", (ModelNode*) oper, TIMESTAMP, IEC61850_FC_CO, 0, 0, 0); + DataAttribute_create("Test", (ModelNode*) oper, BOOLEAN, IEC61850_FC_CO, 0, 0, 0); + + if (hasCheck) + DataAttribute_create("Check", (ModelNode*) oper, CHECK, IEC61850_FC_CO, 0, 0, 0); +} + +static DataAttribute* +CDA_Oper(ModelNode* parent, DataAttributeType type, bool isTImeActivated) +{ + DataAttribute* oper = DataAttribute_create("Oper", parent, CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0); + + addGenericOperateElements(oper, type, isTImeActivated, true); + + return oper; +} + +static DataAttribute* +CDA_SBOw(ModelNode* parent, DataAttributeType type, bool isTImeActivated) +{ + DataAttribute* oper = DataAttribute_create("SBOw", parent, CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0); + + addGenericOperateElements(oper, type, isTImeActivated, true); + + return oper; +} + +static DataAttribute* +CDA_Cancel(ModelNode* parent, DataAttributeType type, bool isTImeActivated) +{ + DataAttribute* oper = DataAttribute_create("Cancel", parent, CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0); + + addGenericOperateElements(oper, type, isTImeActivated, false); + + return oper; +} + + + +/************************************************ + * Common Data Classes - helper functions + ***********************************************/ + +static void +CDC_addTimeQuality(DataObject* dataObject, FunctionalConstraint fc) +{ + DataAttribute_create("q", (ModelNode*) dataObject, QUALITY, fc, TRG_OPT_QUALITY_CHANGED, 0, 0); + DataAttribute_create("t", (ModelNode*) dataObject, TIMESTAMP, fc, 0, 0, 0); +} + +static void +CDC_addStatusToDataObject(DataObject* dataObject, DataAttributeType statusType) +{ + DataAttribute_create("stVal", (ModelNode*) dataObject, statusType, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED | TRG_OPT_DATA_UPDATE, 0, 0); + CDC_addTimeQuality(dataObject, IEC61850_FC_ST); +} + +static void +CDC_addOptionPicsSubst(DataObject* dataObject, DataAttributeType type) +{ + DataAttribute_create("subEna", (ModelNode*) dataObject, BOOLEAN, IEC61850_FC_SV, 0, 0, 0); + DataAttribute_create("subVal", (ModelNode*) dataObject, type, IEC61850_FC_SV, 0, 0, 0); + DataAttribute_create("subQ", (ModelNode*) dataObject, QUALITY, IEC61850_FC_SV, 0, 0, 0); + DataAttribute_create("subID", (ModelNode*) dataObject, VISIBLE_STRING_64, IEC61850_FC_SV, 0, 0, 0); +} + +static void +CDC_addOptionPicsSubstValWithTrans(DataObject* dataObject, bool hasTransientIndicator) +{ + DataAttribute_create("subEna", (ModelNode*) dataObject, BOOLEAN, IEC61850_FC_SV, 0, 0, 0); + + CAC_ValWithTrans_create("subVal", (ModelNode*) dataObject, IEC61850_FC_SV, 0, hasTransientIndicator); + + DataAttribute_create("subQ", (ModelNode*) dataObject, QUALITY, IEC61850_FC_SV, 0, 0, 0); + DataAttribute_create("subID", (ModelNode*) dataObject, VISIBLE_STRING_64, IEC61850_FC_SV, 0, 0, 0); +} + +/* Add optional attributes for extension (name spaces) and textual descriptions */ +static void +CDC_addStandardOptions(DataObject* dataObject, uint32_t options) +{ + /* Standard options ? */ + if (options & CDC_OPTION_DESC) + DataAttribute_create("d",(ModelNode*) dataObject, VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_DESC_UNICODE) + DataAttribute_create("dU", (ModelNode*) dataObject, UNICODE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_AC_DLNDA) { + DataAttribute_create("cdcNs", (ModelNode*) dataObject, VISIBLE_STRING_255, IEC61850_FC_EX, 0, 0, 0); + DataAttribute_create("cdcName", (ModelNode*) dataObject, VISIBLE_STRING_255, IEC61850_FC_EX, 0, 0, 0); + } + + if (options & CDC_OPTION_AC_DLN) + DataAttribute_create("dataNs", (ModelNode*) dataObject, VISIBLE_STRING_255, IEC61850_FC_EX, 0, 0, 0); +} + +/************************************************ + * Common Data Classes - constructors + ***********************************************/ + +DataObject* +CDC_SPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newSPS = DataObject_create(dataObjectName, parent, 0); + + CDC_addStatusToDataObject(newSPS, BOOLEAN); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newSPS, BOOLEAN); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newSPS, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newSPS, options); + + return newSPS; +} + +DataObject* +CDC_DPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newDPS = DataObject_create(dataObjectName, parent, 0); + + CDC_addStatusToDataObject(newDPS, CODEDENUM); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newDPS, CODEDENUM); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newDPS, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newDPS, options); + + return newDPS; +} + +DataObject* +CDC_INS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newINS = DataObject_create(dataObjectName, parent, 0); + + CDC_addStatusToDataObject(newINS, INT32); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newINS, INT32); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newINS, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newINS, options); + + return newINS; +} + + +DataObject* +CDC_ENS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newENS = DataObject_create(dataObjectName, parent, 0); + + CDC_addStatusToDataObject(newENS, ENUMERATED); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newENS, ENUMERATED); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newENS, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newENS, options); + + return newENS; +} + +DataObject* +CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newBCR = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("actVal", (ModelNode*) newBCR, INT64, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_FROZEN_VALUE) { + DataAttribute_create("frVal", (ModelNode*) newBCR, INT64, IEC61850_FC_ST, TRG_OPT_DATA_UPDATE, 0, 0); + DataAttribute_create("frTm", (ModelNode*) newBCR, TIMESTAMP, IEC61850_FC_ST, 0, 0, 0); + } + + CDC_addTimeQuality(newBCR, IEC61850_FC_ST); + + if (options & CDC_OPTION_UNIT) + DataAttribute_create("units", (ModelNode*) newBCR, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + DataAttribute_create("pulsQty", (ModelNode*) newBCR, FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_FROZEN_VALUE) { + DataAttribute_create("frEna", (ModelNode*) newBCR, BOOLEAN, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("strTm", (ModelNode*) newBCR, TIMESTAMP, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("frPd", (ModelNode*) newBCR, INT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("frRs", (ModelNode*) newBCR, BOOLEAN, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + } + + CDC_addStandardOptions(newBCR, options); + + return newBCR; +} + +DataObject* +CDC_SEC_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newSEC = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("cnt", (ModelNode*) newSEC, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("sev", (ModelNode*) newSEC, ENUMERATED, IEC61850_FC_ST, 0, 0, 0); + DataAttribute_create("t", (ModelNode*) newSEC, TIMESTAMP, IEC61850_FC_ST, 0, 0, 0); + + if (options & CDC_OPTION_ADDR) + DataAttribute_create("addr", (ModelNode*) newSEC, OCTET_STRING_64, IEC61850_FC_ST, 0, 0, 0); + + if (options & CDC_OPTION_ADDINFO) + DataAttribute_create("addInfo", (ModelNode*) newSEC, VISIBLE_STRING_64, IEC61850_FC_ST, 0, 0, 0); + + CDC_addStandardOptions(newSEC, options); + + return newSEC; +} + + + + +/** + * CDC_OPTION_INST_MAG + * CDC_OPTION_RANGE + * CDC_OPTION_PICS_SUBST + */ +DataObject* +CDC_MV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat) +{ + DataObject* newMV = DataObject_create(dataObjectName, parent, 0); + + if (options & CDC_OPTION_INST_MAG) + CAC_AnalogueValue_create("instMag", (ModelNode*) newMV, IEC61850_FC_MX, 0, isIntegerNotFloat); + + CAC_AnalogueValue_create("mag", (ModelNode*) newMV, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED | TRG_OPT_DATA_UPDATE, isIntegerNotFloat); + + if (options & CDC_OPTION_RANGE) + DataAttribute_create("range", (ModelNode*) newMV, ENUMERATED, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addTimeQuality(newMV, IEC61850_FC_MX); + +// if (options & CDC_OPTION_PICS_SUBST) +// CDC_addOptionPicsSubst(newMV, ) + + CDC_addStandardOptions(newMV, options); + + return newMV; +} + +/** + * CDC_OPTION_INST_MAG + * CDC_OPTION_RANGE + */ +DataObject* +CDC_CMV_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newMV = DataObject_create(dataObjectName, parent, 0); + + if (options & CDC_OPTION_INST_MAG) + CAC_Vector_create("instCVal", (ModelNode*) newMV, options, IEC61850_FC_MX, 0); + + CAC_Vector_create("cVal", (ModelNode*) newMV, options, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED | TRG_OPT_DATA_UPDATE); + + if (options & CDC_OPTION_RANGE) + DataAttribute_create("range", (ModelNode*) newMV, ENUMERATED, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_RANGE_ANG) + DataAttribute_create("rangeAng", (ModelNode*) newMV, ENUMERATED, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addTimeQuality(newMV, IEC61850_FC_MX); + +// if (options & CDC_OPTION_PICS_SUBST) +// CDC_addOptionPicsSubst(newMV, ) + + CDC_addStandardOptions(newMV, options); + + return newMV; +} + + +/** + * CDC_OPTION_UNIT + * CDC_OPTION_AC_SCAV + * CDC_OPTION_MIN + * CDC_OPTION_MAX + */ +DataObject* +CDC_SAV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat) +{ + DataObject* newSAV = DataObject_create(dataObjectName, parent, 0); + + CAC_AnalogueValue_create("instMag", (ModelNode*) newSAV, IEC61850_FC_MX, 0, isIntegerNotFloat); + + CDC_addTimeQuality(newSAV, IEC61850_FC_MX); + + if (options & CDC_OPTION_UNIT) + CAC_Unit_create("units", (ModelNode*) newSAV, options & CDC_OPTION_UNIT_MULTIPLIER); + + if (options & CDC_OPTION_AC_SCAV) + CAC_ScaledValueConfig_create("sVC", (ModelNode*) newSAV); + + if (options & CDC_OPTION_MIN) + CAC_AnalogueValue_create("min", (ModelNode*) newSAV, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + if (options & CDC_OPTION_MAX) + CAC_AnalogueValue_create("max", (ModelNode*) newSAV, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + CDC_addStandardOptions(newSAV, options); + + return newSAV; +} + +DataObject* +CDC_HST_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint16_t maxPts) +{ + DataObject* newHST = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("hstVal", (ModelNode*) newHST, INT32, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED | TRG_OPT_DATA_UPDATE, maxPts, 0); + + CDC_addTimeQuality(newHST, IEC61850_FC_ST); + + DataAttribute_create("numPts", (ModelNode*) newHST, INT16U, IEC61850_FC_CF, 0, 0, 0); + + //TODO add mandatory attribute "hstRangeC" + + CAC_Unit_create("units", (ModelNode*) newHST, options & CDC_OPTION_UNIT_MULTIPLIER); + + DataAttribute_create("maxPts", (ModelNode*) newHST, INT16U, IEC61850_FC_CF, 0, 0, 0); + + CDC_addStandardOptions(newHST, options); + + return newHST; +} + + +static void +addControls(DataObject* parent, DataAttributeType type, uint32_t controlOptions) +{ + DataAttribute* ctlModel = + DataAttribute_create("ctlModel", (ModelNode*) parent, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + int controlModel = controlOptions & 0x07; + + ctlModel->mmsValue = MmsValue_newIntegerFromInt16(controlModel); + + if (controlModel > 0) { + + if (controlModel == CDC_CTL_MODEL_SBO_NORMAL) + DataAttribute_create("SBO", (ModelNode*) parent, VISIBLE_STRING_129, IEC61850_FC_CO, 0, 0, 0); + + bool isTimeActivated = false; + + if (controlOptions & CDC_CTL_MODEL_IS_TIME_ACTIVATED) + isTimeActivated = true; + + if (controlModel == CDC_CTL_MODEL_SBO_ENHANCED) + CDA_SBOw((ModelNode*) parent, type, isTimeActivated); + + CDA_Oper((ModelNode*) parent, type, isTimeActivated); + + if (controlOptions & CDC_CTL_MODEL_HAS_CANCEL) + CDA_Cancel((ModelNode*) parent, type, isTimeActivated); + + } +} + +static void +addOriginatorAndCtlNumOptions(ModelNode* parent, uint32_t controlOptions) +{ + if (controlOptions & CDC_CTL_OPTION_ORIGIN) + addOriginator("origin", parent, IEC61850_FC_ST); + + if (controlOptions & CDC_CTL_OPTION_CTL_NUM) + DataAttribute_create("ctlNum", parent, INT8U, IEC61850_FC_ST, 0, 0, 0); +} + +/** + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + */ +DataObject* +CDC_SPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) +{ + DataObject* newSPC = DataObject_create(dataObjectName, parent, 0); + + addOriginatorAndCtlNumOptions((ModelNode*) newSPC, controlOptions); + + CDC_addStatusToDataObject(newSPC, BOOLEAN); + + addControls(newSPC, BOOLEAN, controlOptions); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newSPC, BOOLEAN); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newSPC, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newSPC, options); + + return newSPC; +} + +/** + * + * CDC_OPTION_IS_TIME_ACTICATED + * + * substitution options + * CDC_OPTION_BLK_ENA + * standard description and namespace options + * + */ +DataObject* +CDC_DPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) +{ + DataObject* newDPC = DataObject_create(dataObjectName, parent, 0); + + addOriginatorAndCtlNumOptions((ModelNode*) newDPC, controlOptions); + + CDC_addStatusToDataObject(newDPC, CODEDENUM); + + addControls(newDPC, BOOLEAN, controlOptions); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newDPC, CODEDENUM); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newDPC, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newDPC, options); + + return newDPC; +} + +static void +addAnalogControls(DataObject* parent, uint32_t controlOptions, bool isIntegerNotFloat) +{ + DataAttribute* ctlModel = + DataAttribute_create("ctlModel", (ModelNode*) parent, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + int controlModel = controlOptions & 0x07; + + ctlModel->mmsValue = MmsValue_newIntegerFromInt16(controlModel); + + if (controlModel != CDC_CTL_MODEL_NONE) { + + if (controlModel == CDC_CTL_MODEL_SBO_NORMAL) + DataAttribute_create("SBO", (ModelNode*) parent, VISIBLE_STRING_129, IEC61850_FC_CO, 0, 0, 0); + + bool isTimeActivated = false; + + if (controlOptions & CDC_CTL_MODEL_IS_TIME_ACTIVATED) + isTimeActivated = true; + + if (controlModel == CDC_CTL_MODEL_SBO_ENHANCED) { + DataAttribute* sBOw = DataAttribute_create("SBOw", (ModelNode*) parent, CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0); + + CAC_AnalogueValue_create("ctlVal", (ModelNode*) sBOw, IEC61850_FC_CO, 0, isIntegerNotFloat); + + addCommonOperateElements(sBOw, isTimeActivated, true); + } + + DataAttribute* oper = DataAttribute_create("Oper", (ModelNode*) parent, CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0); + + CAC_AnalogueValue_create("ctlVal", (ModelNode*) oper, IEC61850_FC_CO, 0, isIntegerNotFloat); + + addCommonOperateElements(oper, isTimeActivated, true); + + if (controlOptions & CDC_CTL_MODEL_HAS_CANCEL) { + DataAttribute* cancel = DataAttribute_create("SBOw", (ModelNode*) parent, CONSTRUCTED, IEC61850_FC_CO, 0, 0, 0); + + CAC_AnalogueValue_create("ctlVal", (ModelNode*) cancel, IEC61850_FC_CO, 0, isIntegerNotFloat); + + addCommonOperateElements(cancel, isTimeActivated, true); + } + + } +} + +DataObject* +CDC_APC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool isIntegerNotFloat) +{ + DataObject* newAPC = DataObject_create(dataObjectName, parent, 0); + + if (controlOptions & CDC_CTL_OPTION_ORIGIN) + addOriginator("origin", (ModelNode*) newAPC, IEC61850_FC_MX); + + if (controlOptions & CDC_CTL_OPTION_CTL_NUM) + DataAttribute_create("ctlNum", (ModelNode*) newAPC, INT8U, IEC61850_FC_MX, 0, 0, 0); + + CAC_AnalogueValue_create("mxVal", (ModelNode*) newAPC, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + CDC_addTimeQuality(newAPC, IEC61850_FC_MX); + + if (controlOptions & CDC_CTL_OPTION_ST_SELD) + DataAttribute_create("stSeld", (ModelNode*) newAPC, BOOLEAN, IEC61850_FC_MX, TRG_OPT_DATA_CHANGED, 0, 0); + + if (controlOptions & CDC_CTL_OPTION_OP_RCVD) + DataAttribute_create("opRcvd", (ModelNode*) newAPC, BOOLEAN, IEC61850_FC_OR, TRG_OPT_DATA_CHANGED, 0, 0); + + if (controlOptions & CDC_CTL_OPTION_OP_OK) + DataAttribute_create("opOk", (ModelNode*) newAPC, BOOLEAN, IEC61850_FC_OR, TRG_OPT_DATA_CHANGED, 0, 0); + + if (controlOptions & CDC_CTL_OPTION_T_OP_OK) + DataAttribute_create("tOpOk", (ModelNode*) newAPC, BOOLEAN, IEC61850_FC_OR, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_PICS_SUBST) { + DataAttribute_create("subEna", (ModelNode*) newAPC, BOOLEAN, IEC61850_FC_SV, 0, 0, 0); + CAC_AnalogueValue_create("subVal", (ModelNode*) newAPC, IEC61850_FC_SV, 0, isIntegerNotFloat); + DataAttribute_create("subQ", (ModelNode*) newAPC, QUALITY, IEC61850_FC_SV, 0, 0, 0); + DataAttribute_create("subID", (ModelNode*) newAPC, VISIBLE_STRING_64, IEC61850_FC_SV, 0, 0, 0); + } + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newAPC, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + addAnalogControls(newAPC, controlOptions, isIntegerNotFloat); + + CDC_addStandardOptions(newAPC, options); + + return newAPC; +} + + +DataObject* +CDC_INC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) +{ + DataObject* newINC = DataObject_create(dataObjectName, parent, 0); + + addOriginatorAndCtlNumOptions((ModelNode*) newINC, controlOptions); + + CDC_addStatusToDataObject(newINC, INT32); + + addControls(newINC, INT32, controlOptions); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newINC, INT32); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newINC, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + if (options & CDC_OPTION_MIN) + DataAttribute_create("minVal", (ModelNode*) newINC, INT32, IEC61850_FC_CF, 0, 0, 0); + + if (options & CDC_OPTION_MAX) + DataAttribute_create("maxVal", (ModelNode*) newINC, INT32, IEC61850_FC_CF, 0, 0, 0); + + if (options & CDC_OPTION_STEP_SIZE) + DataAttribute_create("stepSize", (ModelNode*) newINC, INT32U, IEC61850_FC_CF, 0, 0, 0); + + CDC_addStandardOptions(newINC, options); + + return newINC; +} + +DataObject* +CDC_ENC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) +{ + DataObject* newENC = DataObject_create(dataObjectName, parent, 0); + + addOriginatorAndCtlNumOptions((ModelNode*) newENC, controlOptions); + + CDC_addStatusToDataObject(newENC, ENUMERATED); + + addControls(newENC, ENUMERATED, controlOptions); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubst(newENC, ENUMERATED); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newENC, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newENC, options); + + return newENC; +} + +DataObject* +CDC_BSC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool hasTransientIndicator) +{ + DataObject* newBSC = DataObject_create(dataObjectName, parent, 0); + + addOriginatorAndCtlNumOptions((ModelNode*) newBSC, controlOptions); + + CAC_ValWithTrans_create("valWTr", (ModelNode*) newBSC, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, hasTransientIndicator); + CDC_addTimeQuality(newBSC, IEC61850_FC_ST); + + DataAttribute_create("persistent", (ModelNode*) newBSC, BOOLEAN, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + addControls(newBSC, CODEDENUM, controlOptions); + + if (options & CDC_OPTION_PICS_SUBST) + CDC_addOptionPicsSubstValWithTrans(newBSC, hasTransientIndicator); + + if (options & CDC_OPTION_BLK_ENA) + DataAttribute_create("blkEna", (ModelNode*) newBSC, BOOLEAN, IEC61850_FC_BL, 0, 0, 0); + + CDC_addStandardOptions(newBSC, options); + + return newBSC; +} + +DataObject* +CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newLPL = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("vendor", (ModelNode*) newLPL, VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + DataAttribute_create("swRev", (ModelNode*) newLPL, VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + CDC_addStandardOptions(newLPL, options); + + return newLPL; +} + +/* Directional protection activation information (ACD) */ +DataObject* +CDC_ACD_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newACD = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("general", (ModelNode*) newACD, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("dirGeneral", (ModelNode*) newACD, ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_PHASE_A) { + DataAttribute_create("phsA", (ModelNode*) newACD, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("dirPhsA", (ModelNode*) newACD, ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + } + + if (options & CDC_OPTION_PHASE_B) { + DataAttribute_create("phsB", (ModelNode*) newACD, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("dirPhsB", (ModelNode*) newACD, ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + } + + if (options & CDC_OPTION_PHASE_C) { + DataAttribute_create("phsC", (ModelNode*) newACD, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("dirPhsC", (ModelNode*) newACD, ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + } + + if (options & CDC_OPTION_PHASE_NEUT) { + DataAttribute_create("neut", (ModelNode*) newACD, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + DataAttribute_create("dirNeut", (ModelNode*) newACD, ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + } + + CDC_addTimeQuality(newACD, IEC61850_FC_ST); + + CDC_addStandardOptions(newACD, options); + + return newACD; +} + +DataObject* +CDC_ACT_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newACT = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("general", (ModelNode*) newACT, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_PHASE_A) + DataAttribute_create("phsA", (ModelNode*) newACT, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_PHASE_B) + DataAttribute_create("phsB", (ModelNode*) newACT, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_PHASE_C) + DataAttribute_create("phsC", (ModelNode*) newACT, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_PHASE_NEUT) + DataAttribute_create("neut", (ModelNode*) newACT, BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addTimeQuality(newACT, IEC61850_FC_ST); + + CDC_addStandardOptions(newACT, options); + + return newACT; +} + +DataObject* +CDC_WYE_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newWYE = DataObject_create(dataObjectName, parent, 0); + + //TODO check if some options should be masked + //TODO take care for GC_1 + CDC_CMV_create("phsA", (ModelNode*) newWYE, options); + CDC_CMV_create("phsB", (ModelNode*) newWYE, options); + CDC_CMV_create("phsC", (ModelNode*) newWYE, options); + CDC_CMV_create("neut", (ModelNode*) newWYE, options); + CDC_CMV_create("net", (ModelNode*) newWYE, options); + CDC_CMV_create("res", (ModelNode*) newWYE, options); + + if (options & CDC_OPTION_ANGLE_REF) + DataAttribute_create("angRef", (ModelNode*) newWYE, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addStandardOptions(newWYE, options); + + return newWYE; +} + + +DataObject* +CDC_DEL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newDEL = DataObject_create(dataObjectName, parent, 0); + + //TODO check if some options should be masked + CDC_CMV_create("phsAB", (ModelNode*) newDEL, options); + CDC_CMV_create("phsBC", (ModelNode*) newDEL, options); + CDC_CMV_create("phsCA", (ModelNode*) newDEL, options); + + if (options & CDC_OPTION_ANGLE_REF) + DataAttribute_create("angRef", (ModelNode*) newDEL, ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addStandardOptions(newDEL, options); + + return newDEL; +} + + +DataObject* +CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newSPG = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("setVal", (ModelNode*) newSPG, BOOLEAN, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addStandardOptions(newSPG, options); + + return newSPG; +} + +DataObject* +CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newENG = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("setVal", (ModelNode*) newENG, ENUMERATED, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addStandardOptions(newENG, options); + + return newENG; +} + +DataObject* +CDC_ING_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newING = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("setVal", (ModelNode*) newING, INT32, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_UNIT) + CAC_Unit_create("units", (ModelNode*) newING, options & CDC_OPTION_UNIT_MULTIPLIER); + + if (options & CDC_OPTION_MIN) + DataAttribute_create("minVal", (ModelNode*) newING, INT32, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_MAX) + DataAttribute_create("maxVal", (ModelNode*) newING, INT32, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); + + if (options & CDC_OPTION_STEP_SIZE) + DataAttribute_create("stepSize", (ModelNode*) newING, INT32U, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addStandardOptions(newING, options); + + + return newING; +} + +DataObject* +CDC_ASG_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat) +{ + DataObject* newASG = DataObject_create(dataObjectName, parent, 0); + + CAC_AnalogueValue_create("setMag", (ModelNode*) newASG, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + if (options & CDC_OPTION_UNIT) + CAC_Unit_create("units", (ModelNode*) newASG, options & CDC_OPTION_UNIT_MULTIPLIER); + + if (options & CDC_OPTION_AC_SCAV) + CAC_ScaledValueConfig_create("sVC", (ModelNode*) newASG); + + if (options & CDC_OPTION_MIN) + CAC_AnalogueValue_create("minVal", (ModelNode*) newASG, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + if (options & CDC_OPTION_MAX) + CAC_AnalogueValue_create("maxVal", (ModelNode*) newASG, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + if (options & CDC_OPTION_STEP_SIZE) + CAC_AnalogueValue_create("stepSize", (ModelNode*) newASG, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); + + CDC_addStandardOptions(newASG, options); + + return newASG; +} + +/********************************************************************************** + * Wind power specific CDCs - according to 61400-25-2:2006 + *********************************************************************************/ + +DataObject* +CDC_SPV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, uint32_t wpOptions, bool hasChaManRs) +{ + DataObject* newSPV = DataObject_create(dataObjectName, parent, 0); + + if (hasChaManRs) + CDC_SPC_create("chaManRs", (ModelNode*) newSPV, 0, CDC_CTL_MODEL_DIRECT_NORMAL); + + CDC_APC_create("actVal", (ModelNode*) newSPV, 0, controlOptions, false); + + //TOOO add optional "oldVal" APC + + if (wpOptions & CDC_OPTION_61400_MIN_MX_VAL) + CAC_AnalogueValue_create("minMxVal", (ModelNode*) newSPV, IEC61850_FC_MX, 0, false); + + if (wpOptions & CDC_OPTION_61400_MAX_MX_VAL) + CAC_AnalogueValue_create("maxMxVal", (ModelNode*) newSPV, IEC61850_FC_MX, 0, false); + + if (wpOptions & CDC_OPTION_61400_TOT_AV_VAL) + CAC_AnalogueValue_create("totAvVal", (ModelNode*) newSPV, IEC61850_FC_MX, 0, false); + + if (wpOptions & CDC_OPTION_61400_SDV_VAL) + CAC_AnalogueValue_create("sdvVal", (ModelNode*) newSPV, IEC61850_FC_MX, 0, false); + + if (options & CDC_OPTION_UNIT) + CAC_Unit_create("units", (ModelNode*) newSPV, options & CDC_OPTION_UNIT_MULTIPLIER); + + if (options & CDC_OPTION_MIN) + CAC_AnalogueValue_create("minVal", (ModelNode*) newSPV, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, false); + + if (options & CDC_OPTION_MAX) + CAC_AnalogueValue_create("maxVal", (ModelNode*) newSPV, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, false); + + if (wpOptions & CDC_OPTION_61400_SP_ACS) + DataAttribute_create("spAcs", (ModelNode*) newSPV, CODEDENUM, IEC61850_FC_CF, 0, 0, 0); + + if (wpOptions & CDC_OPTION_61400_CHA_PER_RS) + DataAttribute_create("chaPerRs", (ModelNode*) newSPV, CODEDENUM, IEC61850_FC_CF, 0, 0, 0); + + CDC_addStandardOptions(newSPV, options); + + return newSPV; +} + +DataObject* +CDC_STV_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasOldStatus) +{ + DataObject* newSTV = DataObject_create(dataObjectName, parent, 0); + + CDC_INS_create("actSt", (ModelNode*) newSTV, 0); + + if (hasOldStatus) + CDC_INS_create("oldSt", (ModelNode*) newSTV, 0); + + CDC_addStandardOptions(newSTV, options); + + return newSTV; +} + +DataObject* +CDC_ALM_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasOldStatus) +{ + DataObject* newALM = DataObject_create(dataObjectName, parent, 0); + + CDC_SPC_create("almAck", (ModelNode*) newALM, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); + + CDC_INS_create("actSt", (ModelNode*) newALM, 0); + + if (hasOldStatus) + CDC_INS_create("oldSt", (ModelNode*) newALM, 0); + + CDC_addStandardOptions(newALM, options); + + return newALM; +} + +DataObject* +CDC_CMD_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasOldStatus, + bool hasCmTm, + bool hasCmCt) +{ + DataObject* newCMD = DataObject_create(dataObjectName, parent, 0); + + CDC_INC_create("actSt", (ModelNode*) newCMD, 0, controlOptions); + + if (hasOldStatus) + CDC_INS_create("oldSt", (ModelNode*) newCMD, 0); + + if (wpOptions & CDC_OPTION_61400_CM_ACS) + DataAttribute_create("cmAcs", (ModelNode*) newCMD, INT8U, IEC61850_FC_CF, 0, 0, 0); + + CDC_addStandardOptions(newCMD, options); + + return newCMD; +} + + +/** + * \brief create a new CDC instance of type CTE (Event counting) + */ +DataObject* +CDC_CTE_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasHisRs) +{ + DataObject* newCTE = DataObject_create(dataObjectName, parent, 0); + + CDC_SPC_create("manRs", (ModelNode*) newCTE, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); + + if (hasHisRs) + CDC_INC_create("hisRs", (ModelNode*) newCTE, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); + + CDC_INS_create("actCtVal", (ModelNode*) newCTE, 0); + + CDC_INS_create("oldCtVal", (ModelNode*) newCTE, 0); + + if (wpOptions & CDC_OPTION_61400_TM_TOT) + DataAttribute_create("ctTot", (ModelNode*) newCTE, INT32U, IEC61850_FC_ST, 0, 0, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_DAILY) + DataAttribute_create("dly", (ModelNode*) newCTE, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 32, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_MONTHLY) + DataAttribute_create("mly", (ModelNode*) newCTE, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 13, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_YEARLY) + DataAttribute_create("mly", (ModelNode*) newCTE, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 21, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_TOTAL) + DataAttribute_create("tot", (ModelNode*) newCTE, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + CDC_addStandardOptions(newCTE, options); + + return newCTE; +} + + +DataObject* +CDC_TMS_create(const char* dataObjectName, ModelNode* parent, + uint32_t options, + uint32_t controlOptions, + uint32_t wpOptions, + bool hasHisRs) +{ + DataObject* newTMS = DataObject_create(dataObjectName, parent, 0); + + CDC_SPC_create("manRs", (ModelNode*) newTMS, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); + + if (hasHisRs) + CDC_INC_create("hisRs", (ModelNode*) newTMS, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); + + CDC_INS_create("actTmVal", (ModelNode*) newTMS, 0); + + CDC_INS_create("oldTmVal", (ModelNode*) newTMS, 0); + + if (wpOptions & CDC_OPTION_61400_TM_TOT) + DataAttribute_create("tmTot", (ModelNode*) newTMS, INT32U, IEC61850_FC_ST, 0, 0, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_DAILY) + DataAttribute_create("dly", (ModelNode*) newTMS, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 32, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_MONTHLY) + DataAttribute_create("mly", (ModelNode*) newTMS, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 13, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_YEARLY) + DataAttribute_create("mly", (ModelNode*) newTMS, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 21, 0); + + if (wpOptions & CDC_OPTION_61400_COUNTING_TOTAL) + DataAttribute_create("tot", (ModelNode*) newTMS, INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); + + + CDC_addStandardOptions(newTMS, options); + + return newTMS; +} + diff --git a/src/iec61850/server/model/config_file_parser.c b/src/iec61850/server/model/config_file_parser.c new file mode 100644 index 0000000..fef92d3 --- /dev/null +++ b/src/iec61850/server/model/config_file_parser.c @@ -0,0 +1,437 @@ +/* + * config_file_parser.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "iec61850_dynamic_model.h" +#include "iec61850_config_file_parser.h" + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" + +#define READ_BUFFER_MAX_SIZE 1024 + +static uint8_t lineBuffer[READ_BUFFER_MAX_SIZE]; + + +static int +readLine(FileHandle fileHandle, uint8_t* buffer, int maxSize) +{ + int bytesRead = 0; + int bufPos = 0; + + int fileReadResult = 1; + + /* eat up leading cr or lf */ + while (fileReadResult > 0) { + fileReadResult = FileSystem_readFile(fileHandle, buffer + bufPos, 1); + + if (fileReadResult == 1) { + + if (!((buffer[bufPos] == '\n') || (buffer[bufPos] == '\r'))) { + bufPos++; + bytesRead++; + break; + } + } + } + + if (fileReadResult > 0) { + while (fileReadResult > 0) { + fileReadResult = FileSystem_readFile(fileHandle, buffer + bufPos, 1); + + if (fileReadResult == 1) { + + if ((buffer[bufPos] == '\n') || (buffer[bufPos] == '\r')) + break; + else { + bufPos++; + bytesRead++; + } + } + } + } + + + return bytesRead; +} + +static void +terminateString(char* string, char ch) +{ + int index = 0; + + while (string[index] != 0) { + if (string[index] == ch) { + string[index] = 0; + break; + } + + index++; + } +} + +IedModel* +ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) +{ + int bytesRead = 1; + + bool stateInModel = false; + int indendation = 0; + + IedModel* model = NULL; + LogicalDevice* currentLD = NULL; + LogicalNode* currentLN = NULL; + ModelNode* currentModelNode = NULL; + DataSet* currentDataSet = NULL; + GSEControlBlock* currentGoCB = NULL; + + char nameString[130]; + char nameString2[130]; + char nameString3[130]; + + int currentLine = 0; + + while (bytesRead > 0) { + bytesRead = readLine(fileHandle, lineBuffer, READ_BUFFER_MAX_SIZE); + + currentLine++; + + if (bytesRead > 0) { + lineBuffer[bytesRead] = 0; + + if (stateInModel) { + + if (StringUtils_startsWith((char*) lineBuffer, "}")) { + if (indendation == 1) { + stateInModel = false; + indendation = 0; + } + else if (indendation == 2) { + indendation = 1; + } + else if (indendation == 3) { + indendation = 2; + } + else if (indendation == 4) { + indendation = 3; + } + else if (indendation > 4) { + currentModelNode = currentModelNode->parent; + indendation--; + } + } + + else if (indendation == 1) { + if (StringUtils_startsWith((char*) lineBuffer, "LD")) { + indendation = 2; + + if (sscanf((char*) lineBuffer, "LD(%s)", nameString) < 1) + goto exit_error; + + terminateString(nameString, ')'); + + currentLD = LogicalDevice_create(nameString, model); + } + else + goto exit_error; + } + else if (indendation == 2) { + if (StringUtils_startsWith((char*) lineBuffer, "LN")) { + indendation = 3; + + if (sscanf((char*) lineBuffer, "LN(%s)", nameString) < 1) + goto exit_error; + + terminateString(nameString, ')'); + + currentLN = LogicalNode_create(nameString, currentLD); + } + else + goto exit_error; + } + else if (indendation == 3) { + if (StringUtils_startsWith((char*) lineBuffer, "DO")) { + indendation = 4; + + int arrayElements = 0; + + sscanf((char*) lineBuffer, "DO(%s %i)", nameString, &arrayElements); + + currentModelNode = (ModelNode*) + DataObject_create(nameString, (ModelNode*) currentLN, arrayElements); + } + else if (StringUtils_startsWith((char*) lineBuffer, "DS")) { + indendation = 4; + + sscanf((char*) lineBuffer, "DS(%s)", nameString); + terminateString(nameString, ')'); + + currentDataSet = DataSet_create(nameString, currentLN); + } + else if (StringUtils_startsWith((char*) lineBuffer, "RC")) { + int isBuffered; + uint32_t confRef; + int trgOps; + int options; + uint32_t bufTm; + uint32_t intgPd; + + int matchedItems = sscanf((char*) lineBuffer, "RC(%s %s %i %s %u %i %i %u %u)", + nameString, nameString2, &isBuffered, nameString3, &confRef, + &trgOps, &options, &bufTm, &intgPd); + + if (matchedItems < 9) goto exit_error; + + char* rptId = NULL; + + if (strcmp(nameString2, "-") != 0) + rptId = nameString2; + + char* dataSetName = NULL; + + if (strcmp(nameString3, "-") != 0) + dataSetName = nameString3; + + ReportControlBlock_create(nameString, currentLN, rptId, + (bool) isBuffered, dataSetName, confRef, trgOps, options, bufTm, intgPd); + } + else if (StringUtils_startsWith((char*) lineBuffer, "GC")) { + uint32_t confRef; + int fixedOffs; + int minTime = -1; + int maxTime = -1; + + int matchedItems = sscanf((char*) lineBuffer, "GC(%s %s %s %u %i %i %i)", + nameString, nameString2, nameString3, &confRef, &fixedOffs, &minTime, &maxTime); + + if (matchedItems < 5) goto exit_error; + + currentGoCB = GSEControlBlock_create(nameString, currentLN, nameString2, + nameString3, confRef, fixedOffs, minTime, maxTime); + + indendation = 4; + + } +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + else if (StringUtils_startsWith((char*) lineBuffer, "SG")) { + + if (strcmp(currentLN->name, "LLN0") != 0) { + if (DEBUG_IED_SERVER) + printf("Setting group control is not defined in LLN0\n"); + + goto exit_error; + } + + int actSG; + int numOfSGs; + + int matchedItems = sscanf((char*) lineBuffer, "SG(%i %i)", &actSG, &numOfSGs); + + if (matchedItems < 2) + goto exit_error; + + SettingGroupControlBlock_create(currentLN, actSG, numOfSGs); + } +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Unknown identifier (%s)\n", lineBuffer); + + goto exit_error; + } + + } + else if (indendation > 3) { + if (StringUtils_startsWith((char*) lineBuffer, "DO")) { + indendation++; + + int arrayElements = 0; + + int matchedItems = sscanf((char*) lineBuffer, "DO(%s %i)", nameString, &arrayElements); + + if (matchedItems != 2) goto exit_error; + + currentModelNode = (ModelNode*) DataObject_create(nameString, currentModelNode, arrayElements); + } + else if (StringUtils_startsWith((char*) lineBuffer, "DA")) { + + int arrayElements = 0; + + int attributeType = 0; + int functionalConstraint = 0; + int triggerOptions = 0; + uint32_t sAddr = 0; + + sscanf((char*) lineBuffer, "DA(%s %i %i %i %i %u)", nameString, &arrayElements, &attributeType, &functionalConstraint, &triggerOptions, &sAddr); + + DataAttribute* dataAttribute = DataAttribute_create(nameString, currentModelNode, + (DataAttributeType) attributeType, (FunctionalConstraint) functionalConstraint, triggerOptions, arrayElements, sAddr); + + char* valueIndicator = strchr((char*) lineBuffer, '='); + + if (valueIndicator != NULL) { + switch (dataAttribute->type) { + case UNICODE_STRING_255: + { + char* stringStart = valueIndicator + 2; + terminateString(stringStart, '"'); + dataAttribute->mmsValue = MmsValue_newMmsString(stringStart); + } + break; + + case VISIBLE_STRING_255: + case VISIBLE_STRING_129: + case VISIBLE_STRING_65: + case VISIBLE_STRING_64: + case VISIBLE_STRING_32: + { + char* stringStart = valueIndicator + 2; + terminateString(stringStart, '"'); + dataAttribute->mmsValue = MmsValue_newVisibleString(stringStart); + } + break; + + case INT8: + case INT16: + case INT32: + case INT64: + case INT128: + case ENUMERATED: + { + int32_t intValue; + if (sscanf(valueIndicator + 1, "%i", &intValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newIntegerFromInt32(intValue); + } + break; + + case INT8U: + case INT16U: + case INT24U: + case INT32U: + { + uint32_t uintValue; + if (sscanf(valueIndicator + 1, "%u", &uintValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newUnsignedFromUint32(uintValue); + } + break; + + case FLOAT32: + { + float floatValue; + if (sscanf(valueIndicator + 1, "%f", &floatValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newFloat(floatValue); + } + break; + + case FLOAT64: + { + double doubleValue; + if (sscanf(valueIndicator + 1, "%lf", &doubleValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newDouble(doubleValue); + } + break; + + case BOOLEAN: + { + int boolean; + if (sscanf(valueIndicator + 1, "%i", &boolean) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newBoolean((bool) boolean); + } + break; + + default: + break; + + } + } + + int lineLength = strlen((char*) lineBuffer); + + if (lineBuffer[lineLength - 1] == '{') { + indendation++; + currentModelNode = (ModelNode*) dataAttribute; + } + } + else if (StringUtils_startsWith((char*) lineBuffer, "DE")) { + sscanf((char*) lineBuffer, "DE(%s)", nameString); + terminateString(nameString, ')'); + + DataSetEntry_create(currentDataSet, nameString, -1, NULL); + } + else if (StringUtils_startsWith((char*) lineBuffer, "PA")) { + uint32_t vlanPrio; + uint32_t vlanId; + uint32_t appId; + + int matchedItems = sscanf((char*) lineBuffer, "PA(%u %u %u %s)", &vlanPrio, &vlanId, &appId, nameString); + + if ((matchedItems != 4) || (currentGoCB == NULL)) goto exit_error; + + terminateString(nameString, ')'); + + if (strlen(nameString) != 12) goto exit_error; + + if (StringUtils_createBufferFromHexString(nameString, (uint8_t*) nameString2) != 6) + goto exit_error; + + PhyComAddress_create(currentGoCB, (uint8_t) vlanPrio, (uint16_t) vlanId, (uint16_t) appId, + (uint8_t*) nameString2); + + } + else + goto exit_error; + } + + + } + else { + if (StringUtils_startsWith((char*) lineBuffer, "MODEL{")) { + + model = IedModel_create(""); + stateInModel = true; + indendation = 1; + } + else if (StringUtils_startsWith((char*) lineBuffer, "MODEL(")) { + sscanf((char*) lineBuffer, "MODEL(%s)", nameString); + terminateString(nameString, ')'); + model = IedModel_create(nameString); + stateInModel = true; + indendation = 1; + } + else + goto exit_error; + } + } + } + + return model; + +exit_error: + if (DEBUG_IED_SERVER) + printf("IED_SERVER: error parsing line %i (indendation level = %i)\n", currentLine, indendation); + IedModel_destroy(model); + return NULL; +} + + diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c new file mode 100644 index 0000000..09a719e --- /dev/null +++ b/src/iec61850/server/model/dynamic_model.c @@ -0,0 +1,725 @@ +/* + * dynamic_model.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_server.h" +#include "libiec61850_platform_includes.h" +#include "stack_config.h" + +static void +iedModel_emptyVariableInitializer(void) +{ + return; +} + +void +IedModel_setIedNameForDynamicModel(IedModel* self, const char* name) +{ + if (self->name != NULL) + GLOBAL_FREEMEM(self->name); + + self->name = copyString(name); +} + +IedModel* +IedModel_create(const char* name/*, MemoryAllocator allocator*/) +{ + IedModel* self = (IedModel*) GLOBAL_CALLOC(1, sizeof(IedModel)); + + if (name) + self->name = copyString(name); + else + self->name = NULL; + + self->rcbs = NULL; + + self->dataSets = NULL; + + self->gseCBs = NULL; + + self->sgcbs = NULL; + + self->initializer = iedModel_emptyVariableInitializer; + + return self; +} + +static void +IedModel_addDataSet(IedModel* self, DataSet* dataSet) +{ + if (self->dataSets == NULL) + self->dataSets = dataSet; + else { + DataSet* lastDataSet = self->dataSets; + + while (lastDataSet != NULL) { + if (lastDataSet->sibling == NULL) { + lastDataSet->sibling = dataSet; + break; + } + + lastDataSet = lastDataSet->sibling; + } + } +} + +static void +IedModel_addLogicalDevice(IedModel* self, LogicalDevice* lDevice) +{ + if (self->firstChild == NULL) + self->firstChild = lDevice; + else { + LogicalDevice* sibling = self->firstChild; + + while (sibling->sibling != NULL) + sibling = (LogicalDevice*) sibling->sibling; + + sibling->sibling = (ModelNode*) lDevice; + } +} + +static void +IedModel_addReportControlBlock(IedModel* self, ReportControlBlock* rcb) +{ + if (self->rcbs == NULL) + self->rcbs = rcb; + else { + ReportControlBlock* lastRcb = self->rcbs; + + while (lastRcb->sibling != NULL) + lastRcb = lastRcb->sibling; + + lastRcb->sibling = rcb; + } +} + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) +static void +IedModel_addSettingGroupControlBlock(IedModel* self, SettingGroupControlBlock* sgcb) +{ + if (self->sgcbs == NULL) + self->sgcbs = sgcb; + else { + SettingGroupControlBlock* lastSgcb = self->sgcbs; + + while (lastSgcb->sibling != NULL) + lastSgcb = lastSgcb->sibling; + + lastSgcb->sibling = sgcb; + } +} +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + +static void +IedModel_addGSEControlBlock(IedModel* self, GSEControlBlock* gcb) +{ + if (self->gseCBs == NULL) + self->gseCBs = gcb; + else { + GSEControlBlock* lastGcb = self->gseCBs; + + while (lastGcb->sibling != NULL) + lastGcb = lastGcb->sibling; + + lastGcb->sibling = gcb; + } +} + +LogicalDevice* +LogicalDevice_create(const char* name, IedModel* parent) +{ + LogicalDevice* self = (LogicalDevice*) GLOBAL_CALLOC(1, sizeof(LogicalDevice)); + + self->name = copyString(name); + self->modelType = LogicalDeviceModelType; + self->parent = (ModelNode*) parent; + self->sibling = NULL; + + IedModel_addLogicalDevice(parent, self); + + return self; +} + +static LogicalNode* +LogicalDevice_getLastLogicalNode(LogicalDevice* self) +{ + LogicalNode* lastNode = (LogicalNode*) self->firstChild; + + LogicalNode* nextNode = lastNode; + + while (nextNode != NULL) { + lastNode = nextNode; + nextNode = (LogicalNode*) nextNode->sibling; + } + + return lastNode; +} + +static void +LogicalDevice_addLogicalNode(LogicalDevice* self, LogicalNode* lNode) +{ + if (self->firstChild == NULL) + self->firstChild = (ModelNode*) lNode; + else { + LogicalNode* lastNode = LogicalDevice_getLastLogicalNode(self); + + lastNode->sibling = (ModelNode*) lNode; + } +} + +LogicalNode* +LogicalNode_create(const char* name, LogicalDevice* parent) +{ + LogicalNode* self = (LogicalNode*) GLOBAL_MALLOC(sizeof(LogicalNode)); + + self->name = copyString(name); + self->parent = (ModelNode*) parent; + self->modelType = LogicalNodeModelType; + self->firstChild = NULL; + self->sibling = NULL; + + LogicalDevice_addLogicalNode(parent, self); + + return self; +} + +static DataObject* +LogicalNode_getLastDataObject(LogicalNode* self) +{ + DataObject* lastNode = (DataObject*) self->firstChild; + + DataObject* nextNode = lastNode; + + while (nextNode != NULL) { + lastNode = nextNode; + nextNode = (DataObject*) nextNode->sibling; + } + + return lastNode; + +} + +static void +LogicalNode_addDataObject(LogicalNode* self, DataObject* dataObject) +{ + if (self->firstChild == NULL) + self->firstChild = (ModelNode*) dataObject; + else { + DataObject* lastDataObject = LogicalNode_getLastDataObject(self); + + lastDataObject->sibling = (ModelNode*) dataObject; + } +} + +static void +LogicalNode_addReportControlBlock(LogicalNode* self, ReportControlBlock* rcb) +{ + IedModel* model = (IedModel*) self->parent->parent; + + IedModel_addReportControlBlock(model, rcb); +} + +ReportControlBlock* +ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bool isBuffered, char* + dataSetName, uint32_t confRef, uint8_t trgOps, uint8_t options, uint32_t bufTm, uint32_t intgPd) +{ + ReportControlBlock* self = (ReportControlBlock*) GLOBAL_MALLOC(sizeof(ReportControlBlock)); + + self->name = copyString(name); + self->parent = parent; + + if (rptId) + self->rptId = copyString(rptId); + else + self->rptId = NULL; + + self->buffered = isBuffered; + + if (dataSetName) + self->dataSetName = copyString(dataSetName); + else + self->dataSetName = NULL; + + self->confRef = confRef; + self->trgOps = trgOps; + self->options = options; + self->bufferTime = bufTm; + self->intPeriod = intgPd; + self->sibling = NULL; + + LogicalNode_addReportControlBlock(parent, self); + + return self; +} + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) +static void +LogicalNode_addSettingGroupControlBlock(LogicalNode* self, SettingGroupControlBlock* sgcb) +{ + IedModel* model = (IedModel*) self->parent->parent; + + IedModel_addSettingGroupControlBlock(model, sgcb); +} + +SettingGroupControlBlock* +SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numOfSGs) +{ + assert(actSG <= numOfSGs); /* actSG starting with 1 */ + assert(strcmp(parent->name, "LLN0") == 0); + + SettingGroupControlBlock* self = (SettingGroupControlBlock*) GLOBAL_MALLOC(sizeof(SettingGroupControlBlock)); + + self->parent = parent; + self->actSG = actSG; + self->numOfSGs = numOfSGs; + self->sibling = NULL; + + LogicalNode_addSettingGroupControlBlock(parent, self); + + return self; +} +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + +static void +LogicalNode_addGSEControlBlock(LogicalNode* self, GSEControlBlock* gcb) +{ + IedModel* model = (IedModel*) self->parent->parent; + + IedModel_addGSEControlBlock(model, gcb); +} + +GSEControlBlock* +GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char* dataSet, uint32_t confRef, bool fixedOffs, + int minTime, int maxTime) +{ + GSEControlBlock* self = (GSEControlBlock*) GLOBAL_MALLOC(sizeof(GSEControlBlock)); + + self->name = copyString(name); + self->parent = parent; + + if (appId) + self->appId = copyString(appId); + else + self->appId = NULL; + + if (dataSet) + self->dataSetName = copyString(dataSet); + else + self->dataSetName = NULL; + + self->confRef = confRef; + self->fixedOffs = fixedOffs; + self->minTime = minTime; + self->maxTime = maxTime; + + self->address = NULL; + + self->sibling = NULL; + + if (parent != NULL) + LogicalNode_addGSEControlBlock(parent, self); + + return self; +} + +static void +GSEControlBlock_addPhyComAddress(GSEControlBlock* self, PhyComAddress* phyComAddress) +{ + self->address = phyComAddress; +} + +PhyComAddress* +PhyComAddress_create(GSEControlBlock* parent, uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[]) +{ + PhyComAddress* self = (PhyComAddress*) GLOBAL_MALLOC(sizeof(PhyComAddress)); + + self->vlanPriority = vlanPriority; + self->vlanId = vlanId; + self->appId = appId; + + memcpy(self->dstAddress, dstAddress, 6); + + if (parent != NULL) + GSEControlBlock_addPhyComAddress(parent, self); + + return self; +} + +static ModelNode* +DataObject_getLastChild(DataObject* self) +{ + ModelNode* lastNode = self->firstChild; + + ModelNode* nextNode = lastNode; + + while (nextNode != NULL) { + lastNode = nextNode; + nextNode = (ModelNode*) nextNode->sibling; + } + + return lastNode; +} + +static void +DataObject_addChild(DataObject* self, ModelNode* child) +{ + if (self->firstChild == NULL) + self->firstChild = child; + else { + ModelNode* lastChild = DataObject_getLastChild(self); + + lastChild->sibling = child; + } +} + +DataObject* +DataObject_create(const char* name, ModelNode* parent, int arrayElements) +{ + DataObject* self = (DataObject*) GLOBAL_MALLOC(sizeof(DataObject)); + + self->name = copyString(name); + self->modelType = DataObjectModelType; + self->elementCount = arrayElements; + self->firstChild = NULL; + self->parent = parent; + self->sibling = NULL; + + if (parent->modelType == LogicalNodeModelType) + LogicalNode_addDataObject((LogicalNode*) parent, self); + else if (parent->modelType == DataObjectModelType) + DataObject_addChild((DataObject*) parent, (ModelNode*) self); + + return self; +} + +static ModelNode* +DataAttribute_getLastChild(DataAttribute* self) +{ + ModelNode* lastNode = self->firstChild; + + ModelNode* nextNode = lastNode; + + while (nextNode != NULL) { + lastNode = nextNode; + nextNode = (ModelNode*) nextNode->sibling; + } + + return lastNode; +} + +static void +DataAttribute_addChild(DataAttribute* self, ModelNode* child) +{ + if (self->firstChild == NULL) + self->firstChild = child; + else { + ModelNode* lastChild = DataAttribute_getLastChild(self); + + lastChild->sibling = child; + } +} + +DataAttribute* +DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type, FunctionalConstraint fc, + uint8_t triggerOptions, int arrayElements, uint32_t sAddr) +{ + DataAttribute* self = (DataAttribute*) GLOBAL_MALLOC(sizeof(DataAttribute)); + + self->name = copyString(name); + self->elementCount = arrayElements; + self->modelType = DataAttributeModelType; + self->type = type; + self->fc = fc; + self->firstChild = NULL; + self->mmsValue = NULL; + self->parent = parent; + self->sibling = NULL; + self->triggerOptions = triggerOptions; + self->sAddr = sAddr; + + if (parent->modelType == DataObjectModelType) + DataObject_addChild((DataObject*) parent, (ModelNode*) self); + else if (parent->modelType == DataAttributeModelType) + DataAttribute_addChild((DataAttribute*) parent, (ModelNode*) self); + + return self; +} + +DataSet* +DataSet_create(const char* name, LogicalNode* parent) +{ + DataSet* self = (DataSet*) GLOBAL_MALLOC(sizeof(DataSet)); + + LogicalDevice* ld = (LogicalDevice*) parent->parent; + + self->name = createString(3, parent->name, "$", name); + self->elementCount = 0; + self->sibling = NULL; + self->logicalDeviceName = ld->name; + self->fcdas = NULL; + + IedModel_addDataSet((IedModel*) ld->parent, self); + + return self; +} + +int +DataSet_getSize(DataSet* self) +{ + return self->elementCount; +} + +DataSetEntry* +DataSet_getFirstEntry(DataSet* self) +{ + return self->fcdas; +} + +DataSetEntry* +DataSetEntry_getNext(DataSetEntry* self) +{ + return self->sibling; +} + +static void +DataSet_addEntry(DataSet* self, DataSetEntry* newEntry) +{ + self->elementCount++; + + if (self->fcdas == NULL) + self->fcdas = newEntry; + else { + DataSetEntry* lastEntry = self->fcdas; + + while (lastEntry != NULL) { + + if (lastEntry->sibling == NULL) { + lastEntry->sibling = newEntry; + break; + } + + lastEntry = lastEntry->sibling; + } + } +} + +DataSetEntry* +DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const char* component) +{ + DataSetEntry* self = (DataSetEntry*) GLOBAL_MALLOC(sizeof(DataSetEntry)); + + char variableName[130]; + + strncpy(variableName, variable, 129); + + char* separator = strchr(variableName, '/'); + + if (separator != NULL) { + *separator = 0; + + self->variableName = copyString(separator + 1); + self->logicalDeviceName = copyString(variableName); + self->isLDNameDynamicallyAllocated = true; + } + else { + self->variableName = copyString(variable); + self->logicalDeviceName = dataSet->logicalDeviceName; + self->isLDNameDynamicallyAllocated = false; + } + + if (component != NULL) + self->componentName = copyString(component); + else + self->componentName = NULL; + + self->index = index; + + self->sibling = NULL; + + DataSet_addEntry(dataSet, self); + + return self; +} + +static void +ModelNode_destroy(ModelNode* modelNode) +{ + GLOBAL_FREEMEM(modelNode->name); + + ModelNode* currentChild = modelNode->firstChild; + + while (currentChild != NULL) { + ModelNode* nextChild = currentChild->sibling; + + ModelNode_destroy(currentChild); + + currentChild = nextChild; + } + + if (modelNode->modelType == DataAttributeModelType) { + DataAttribute* dataAttribute = (DataAttribute*) modelNode; + + if (dataAttribute->mmsValue != NULL) { + MmsValue_delete(dataAttribute->mmsValue); + dataAttribute->mmsValue = NULL; + } + } + + GLOBAL_FREEMEM(modelNode); +} + +void +IedModel_destroy(IedModel* model) +{ + // delete all model nodes and dynamically created strings + + /* delete all logical devices */ + + LogicalDevice* ld = model->firstChild; + + while (ld != NULL) { + GLOBAL_FREEMEM (ld->name); + + LogicalNode* ln = (LogicalNode*) ld->firstChild; + + while (ln != NULL) { + GLOBAL_FREEMEM(ln->name); + + /* delete all data objects */ + + DataObject* currentDataObject = (DataObject*) ln->firstChild; + + while (currentDataObject != NULL) { + DataObject* nextDataObject = (DataObject*) currentDataObject->sibling; + + ModelNode_destroy((ModelNode*) currentDataObject); + + currentDataObject = nextDataObject; + } + + LogicalNode* currentLn = ln; + ln = (LogicalNode*) ln->sibling; + + GLOBAL_FREEMEM(currentLn); + } + + + LogicalDevice* currentLd = ld; + ld = (LogicalDevice*) ld->sibling; + + GLOBAL_FREEMEM(currentLd); + } + + /* delete all data sets */ + + DataSet* dataSet = model->dataSets; + + while (dataSet != NULL) { + DataSet* nextDataSet = dataSet->sibling; + + GLOBAL_FREEMEM(dataSet->name); + + DataSetEntry* dse = dataSet->fcdas; + + while (dse != NULL) { + DataSetEntry* nextDse = dse->sibling; + + if (dse->componentName != NULL) + GLOBAL_FREEMEM(dse->componentName); + + GLOBAL_FREEMEM(dse->variableName); + + if (dse->isLDNameDynamicallyAllocated) + GLOBAL_FREEMEM(dse->logicalDeviceName); + + GLOBAL_FREEMEM(dse); + + dse = nextDse; + } + + GLOBAL_FREEMEM(dataSet); + + dataSet = nextDataSet; + } + + /* delete all RCBs */ + + ReportControlBlock* rcb = model->rcbs; + + while (rcb != NULL) { + ReportControlBlock* nextRcb = rcb->sibling; + + GLOBAL_FREEMEM(rcb->name); + + if (rcb->rptId) + GLOBAL_FREEMEM(rcb->rptId); + + if (rcb->dataSetName) + GLOBAL_FREEMEM(rcb->dataSetName); + + GLOBAL_FREEMEM(rcb); + + rcb = nextRcb; + } + + /* delete all GoCBs */ + + GSEControlBlock* gcb = model->gseCBs; + + while (gcb != NULL) { + GSEControlBlock* nextGcb = gcb->sibling; + + GLOBAL_FREEMEM(gcb->name); + GLOBAL_FREEMEM(gcb->appId); + GLOBAL_FREEMEM(gcb->dataSetName); + + if (gcb->address) + GLOBAL_FREEMEM(gcb->address); + + GLOBAL_FREEMEM(gcb); + + gcb = nextGcb; + } + + /* delete setting controls */ + + SettingGroupControlBlock* sgcb = model->sgcbs; + + while (sgcb != NULL) { + SettingGroupControlBlock* nextSgcb = sgcb->sibling; + + GLOBAL_FREEMEM(sgcb); + + sgcb = nextSgcb; + } + + + /* delete generic model parts */ + + if (model->name) + GLOBAL_FREEMEM(model->name); + + GLOBAL_FREEMEM(model); + +} + diff --git a/src/iec61850/server/model/model.c b/src/iec61850/server/model/model.c new file mode 100644 index 0000000..3a5a858 --- /dev/null +++ b/src/iec61850/server/model/model.c @@ -0,0 +1,651 @@ +/* + * model.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "iec61850_model.h" + +#include "libiec61850_platform_includes.h" + +static void +setAttributeValuesToNull(ModelNode* node) +{ + if (node->modelType == DataAttributeModelType) { + DataAttribute* da = (DataAttribute*) node; + + da->mmsValue = NULL; + } + + ModelNode* child = node->firstChild; + + while (child != NULL) { + setAttributeValuesToNull(child); + child = child->sibling; + } +} + +void +IedModel_setIedName(IedModel* self, const char* name) +{ + self->name = (char*) name; +} + +void +IedModel_setAttributeValuesToNull(IedModel* iedModel) +{ + LogicalDevice* ld = iedModel->firstChild; + + while (ld != NULL) { + + LogicalNode* ln = (LogicalNode*) ld->firstChild; + + while (ln != NULL) { + ModelNode* node = ln->firstChild; + + while (node != NULL) { + setAttributeValuesToNull(node); + node = node->sibling; + } + + ln = (LogicalNode*) ln->sibling; + } + + ld = (LogicalDevice*) ld->sibling; + } +} + + + +int +IedModel_getLogicalDeviceCount(IedModel* iedModel) +{ + if (iedModel->firstChild == NULL) + return 0; + + LogicalDevice* logicalDevice = iedModel->firstChild; + + int ldCount = 1; + + while (logicalDevice->sibling != NULL) { + logicalDevice = (LogicalDevice*) logicalDevice->sibling; + ldCount++; + } + + return ldCount; +} + +DataSet* +IedModel_lookupDataSet(IedModel* model, const char* dataSetReference /* e.g. ied1Inverter/LLN0$dataset1 */) +{ + DataSet* dataSet = model->dataSets; + + const char* separator = strchr(dataSetReference, '/'); + + if (separator == NULL) + return NULL; + + int ldNameLen = separator - dataSetReference; + + char domainName[65]; + + int modelNameLen = strlen(model->name); + + memcpy(domainName, model->name, modelNameLen); + + while (dataSet != NULL) { + + domainName[modelNameLen] = 0; + + strncat(domainName, dataSet->logicalDeviceName, 64); + + if (strncmp(domainName, dataSetReference, ldNameLen) == 0) { + if (strcmp(dataSet->name, separator + 1) == 0) { + return dataSet; + } + } + + dataSet = dataSet->sibling; + } + + return NULL; +} + +LogicalDevice* +IedModel_getDevice(IedModel* model, const char* deviceName) +{ + LogicalDevice* device = model->firstChild; + + while (device != NULL) { + + char domainName[65]; + + strncpy(domainName, model->name, 64); + strncat(domainName, device->name, 64); + + if (strcmp(domainName, deviceName) == 0) + return device; + + device = (LogicalDevice*) device->sibling; + } + + return NULL; +} + +static DataAttribute* +ModelNode_getDataAttributeByMmsValue(ModelNode* self, MmsValue* value) +{ + ModelNode* node = self->firstChild; + + while (node != NULL) { + if (node->modelType == DataAttributeModelType) { + DataAttribute* da = (DataAttribute*) node; + + if (da->mmsValue == value) + return da; + } + + DataAttribute* da = ModelNode_getDataAttributeByMmsValue(node, value); + + if (da != NULL) + return da; + + node = node->sibling; + } + + return NULL; +} + +DataAttribute* +IedModel_lookupDataAttributeByMmsValue(IedModel* model, MmsValue* value) +{ + LogicalDevice* ld = model->firstChild; + + while (ld != NULL) { + + DataAttribute* da = + ModelNode_getDataAttributeByMmsValue((ModelNode*) ld, value); + + if (da != NULL) + return da; + + + ld = (LogicalDevice*) ld->sibling; + } + + return NULL; +} + +static ModelNode* +getChildWithShortAddress(ModelNode* node, uint32_t sAddr) +{ + ModelNode* child; + + child = node->firstChild; + + while (child != NULL) { + if (child->modelType == DataAttributeModelType) { + DataAttribute* da = (DataAttribute*) child; + + if (da->sAddr == sAddr) + return child; + } + + ModelNode* childChild = getChildWithShortAddress(child, sAddr); + + if (childChild != NULL) + return childChild; + + child = child->sibling; + } + + return NULL; +} + +ModelNode* +IedModel_getModelNodeByShortAddress(IedModel* model, uint32_t sAddr) +{ + ModelNode* node = NULL; + + LogicalDevice* ld = (LogicalDevice*) model->firstChild; + + while (ld != NULL) { + + LogicalNode* ln = (LogicalNode*) ld->firstChild; + + while (ln != NULL) { + + ModelNode* doNode = ln->firstChild; + + while (doNode != NULL) { + ModelNode* matchingNode = getChildWithShortAddress(doNode, sAddr); + + if (matchingNode != NULL) + return matchingNode; + + doNode = doNode->sibling; + } + + ln = (LogicalNode*) ln->sibling; + } + + ld = (LogicalDevice*) ld->sibling; + } + + return node; +} + +ModelNode* +IedModel_getModelNodeByObjectReference(IedModel* model, const char* objectReference) +{ + assert(strlen(objectReference) < 129); + + char objRef[130]; + + strncpy(objRef, objectReference, 129); + objRef[129] = 0; + + char* separator = strchr(objRef, '/'); + + if (separator == NULL) + return NULL; + + *separator = 0; + + LogicalDevice* ld = IedModel_getDevice(model, objRef); + + if (ld == NULL) return NULL; + + return ModelNode_getChild((ModelNode*) ld, separator + 1); +} + +ModelNode* +IedModel_getModelNodeByShortObjectReference(IedModel* model, const char* objectReference) +{ + assert((strlen(model->name) + strlen(objectReference)) < 130); + + char objRef[130]; + + strncpy(objRef, objectReference, 129); + objRef[129] = 0; + + char* separator = strchr(objRef, '/'); + + if (separator == NULL) + return NULL; + + *separator = 0; + + char ldName[65]; + strcpy(ldName, model->name); + strcat(ldName, objRef); + + LogicalDevice* ld = IedModel_getDevice(model, ldName); + + if (ld == NULL) return NULL; + + return ModelNode_getChild((ModelNode*) ld, separator + 1); +} + + +bool +DataObject_hasFCData(DataObject* dataObject, FunctionalConstraint fc) +{ + ModelNode* modelNode = dataObject->firstChild; + + while (modelNode != NULL) { + + if (modelNode->modelType == DataAttributeModelType) { + DataAttribute* dataAttribute = (DataAttribute*) modelNode; + + if (dataAttribute->fc == fc) + return true; + } + else if (modelNode->modelType == DataObjectModelType) { + + if (DataObject_hasFCData((DataObject*) modelNode, fc)) + return true; + } + + modelNode = modelNode->sibling; + } + + return false; +} + +bool +LogicalNode_hasFCData(LogicalNode* node, FunctionalConstraint fc) +{ + DataObject* dataObject = (DataObject*) node->firstChild; + + while (dataObject != NULL) { + if (DataObject_hasFCData(dataObject, fc)) + return true; + + dataObject = (DataObject*) dataObject->sibling; + } + + return false; +} + +DataSet* +LogicalNode_getDataSet(LogicalNode* self, const char* dataSetName) +{ + assert(self->modelType == LogicalNodeModelType); + assert(dataSetName != NULL); + + char dsName[66]; + + LogicalDevice* ld = (LogicalDevice*) self->parent; + + if (strlen(dataSetName) > 32) { + + if (DEBUG_IED_SERVER) { + printf("IED_SERVER: LogicalNode_getDataSet - data set name %s too long!\n", dataSetName); + } + + goto exit_error; + } + + StringUtils_createStringInBuffer(dsName, 3, self->name, "$", dataSetName); + + IedModel* iedModel = (IedModel*) ld->parent; + + DataSet* ds = iedModel->dataSets; + + while (ds != NULL) { + if (strcmp(ds->logicalDeviceName, ld->name) == 0) { + if (strcmp(ds->name, dsName) == 0) { + return ds; + } + } + + ds = ds->sibling; + } + + +exit_error: + return NULL; +} + +int +LogicalDevice_getLogicalNodeCount(LogicalDevice* logicalDevice) +{ + int lnCount = 0; + + LogicalNode* logicalNode = (LogicalNode*) logicalDevice->firstChild; + + while (logicalNode != NULL) { + logicalNode = (LogicalNode*) logicalNode->sibling; + lnCount++; + } + + return lnCount; +} + +ModelNode* +LogicalDevice_getChildByMmsVariableName(LogicalDevice* logicalDevice, const char* mmsVariableName) +{ + + + char fcString[3]; + char nameRef[65]; + + const char* separator = strchr(mmsVariableName,'$'); + + if (separator == NULL) + return NULL; + + if (strlen(separator) > 4) { + fcString[0] = separator[1]; + fcString[1] = separator[2]; + fcString[2] = 0; + + const char* strpos = mmsVariableName; + + int targetPos = 0; + + while (strpos < separator) { + nameRef[targetPos++] = strpos[0]; + strpos++; + } + + nameRef[targetPos++] = '.'; + + strpos = separator + 4; + + while (strpos[0] != 0) { + nameRef[targetPos++] = strpos[0]; + strpos++; + } + + nameRef[targetPos++] = 0; + + StringUtils_replace(nameRef, '$', '.'); + + FunctionalConstraint fc = FunctionalConstraint_fromString(fcString); + + return ModelNode_getChildWithFc((ModelNode*) logicalDevice, nameRef, fc); + } + + return NULL; +} + +static int +createObjectReference(ModelNode* node, char* objectReference) +{ + int bufPos; + + if (node->modelType != LogicalNodeModelType) { + bufPos = createObjectReference(node->parent, objectReference); + + objectReference[bufPos++] = '.'; + } + else { + LogicalNode* lNode = (LogicalNode*) node; + + LogicalDevice* lDevice = (LogicalDevice*) lNode->parent; + + IedModel* iedModel = (IedModel*) lDevice->parent; + + bufPos = 0; + + int nameLength = strlen (iedModel->name) + strlen(lDevice->name); + + strncpy(objectReference, iedModel->name, 64); + strncat(objectReference, lDevice->name, 64); + + bufPos += nameLength; + + objectReference[bufPos++] = '/'; + } + + /* append own name */ + int nameLength = strlen(node->name); + + int i; + for (i = 0; i < nameLength; i++) { + objectReference[bufPos++] = node->name[i]; + } + + return bufPos; +} + +char* +ModelNode_getObjectReference(ModelNode* node, char* objectReference) +{ + if (objectReference == NULL) + objectReference = (char*) GLOBAL_MALLOC(130); + + int bufPos = createObjectReference(node, objectReference); + + objectReference[bufPos] = 0; + + return objectReference; +} + +int +ModelNode_getChildCount(ModelNode* modelNode) { + int childCount = 0; + + ModelNode* child = modelNode->firstChild; + + while (child != NULL) { + childCount++; + child = child->sibling; + } + + return childCount; +} + + +ModelNode* +ModelNode_getChild(ModelNode* self, const char* name) +{ + // check for separator + const char* separator = strchr(name, '.'); + + int nameElementLength = 0; + + if (separator != NULL) + nameElementLength = (separator - name); + else + nameElementLength = strlen(name); + + ModelNode* nextNode = self->firstChild; + + ModelNode* matchingNode = NULL; + + while (nextNode != NULL) { + int nodeNameLen = strlen(nextNode->name); + + if (nodeNameLen == nameElementLength) { + if (memcmp(nextNode->name, name, nodeNameLen) == 0) { + matchingNode = nextNode; + break; + } + } + + nextNode = nextNode->sibling; + } + + if ((separator != NULL) && (matchingNode != NULL)) { + return ModelNode_getChild(matchingNode, separator + 1); + } + else + return matchingNode; +} + +ModelNode* +ModelNode_getChildWithFc(ModelNode* self, const char* name, FunctionalConstraint fc) +{ + // check for separator + const char* separator = strchr(name, '.'); + + int nameElementLength = 0; + + if (separator != NULL) + nameElementLength = (separator - name); + else + nameElementLength = strlen(name); + + ModelNode* nextNode = self->firstChild; + + ModelNode* matchingNode = NULL; + + while (nextNode != NULL) { + int nodeNameLen = strlen(nextNode->name); + + if (nodeNameLen == nameElementLength) { + if (memcmp(nextNode->name, name, nodeNameLen) == 0) { + + if (separator == NULL) { + if (nextNode->modelType == DataAttributeModelType) { + DataAttribute* da = (DataAttribute*) nextNode; + + if (da->fc == fc) { + matchingNode = nextNode; + break; + } + } + } + else { + + if (nextNode->modelType == DataAttributeModelType) { + DataAttribute* da = (DataAttribute*) nextNode; + + if (da->fc == fc) { + matchingNode = nextNode; + break; + } + } + else { + matchingNode = nextNode; + break; + } + + } + } + } + + nextNode = nextNode->sibling; + } + + if ((separator != NULL) && (matchingNode != NULL)) { + return ModelNode_getChildWithFc(matchingNode, separator + 1, fc); + } + else + return matchingNode; +} + +LogicalNode* +LogicalDevice_getLogicalNode(LogicalDevice* self, const char* nodeName) +{ + return (LogicalNode*) ModelNode_getChild((ModelNode*) self, nodeName); +} + +SettingGroupControlBlock* +LogicalDevice_getSettingGroupControlBlock(LogicalDevice* self) +{ + IedModel* model = (IedModel*) self->parent; + + if (model == NULL) + return NULL; + + LogicalNode* ln = LogicalDevice_getLogicalNode(self, "LLN0"); + + if (ln == NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: logical node LLN0 not found!\n"); + + return NULL; + } + + SettingGroupControlBlock* sgcb = model->sgcbs; + + while (sgcb != NULL) { + if (sgcb->parent == ln) + return sgcb; + + sgcb = sgcb->sibling; + } + + return NULL; +} diff --git a/src/mms/asn1/asn1_ber_primitive_value.c b/src/mms/asn1/asn1_ber_primitive_value.c new file mode 100644 index 0000000..d08e885 --- /dev/null +++ b/src/mms/asn1/asn1_ber_primitive_value.c @@ -0,0 +1,95 @@ +/* + * asn1_ber_primitive_value.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "asn1_ber_primitive_value.h" + +Asn1PrimitiveValue* +Asn1PrimitiveValue_create(int size) +{ + Asn1PrimitiveValue* self = (Asn1PrimitiveValue*) GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue)); + + self->size = size; + self->maxSize = size; + self->octets = (uint8_t*) GLOBAL_CALLOC(1, size); + + return self; +} + +//Asn1PrimitiveValue* +//Asn1PrimitiveValue_createFromBuffer(uint8_t buffer, int bufferSize) +//{ +// Asn1PrimitiveValue* self = GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue)); +// self->size = bufferSize; +// self->maxSize = bufferSize; +// self->octets = GLOBAL_MALLOC(1, bufferSize); +// +//} + +Asn1PrimitiveValue* +Asn1PrimitiveValue_clone(Asn1PrimitiveValue* self) +{ + Asn1PrimitiveValue* clone = (Asn1PrimitiveValue*) GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue)); + + clone->size = self->size; + clone->maxSize = self->maxSize; + + clone->octets = (uint8_t*) GLOBAL_MALLOC(self->maxSize); + + memcpy(clone->octets, self->octets, clone->maxSize); + + return clone; +} + +bool +Asn1PrimitivaValue_compare(Asn1PrimitiveValue* self, Asn1PrimitiveValue* otherValue) +{ + if (self->size == otherValue->size) { + if (memcmp(self->octets, otherValue->octets, self->size) == 0) + return true; + else + return false; + } + else + return false; +} + +int +Asn1PrimitiveValue_getSize(Asn1PrimitiveValue* self) +{ + return self->size; +} + +int +Asn1PrimitiveValue_getMaxSize(Asn1PrimitiveValue* self) +{ + return self->maxSize; +} + +void +Asn1PrimitiveValue_destroy(Asn1PrimitiveValue* self) +{ + GLOBAL_FREEMEM(self->octets); + GLOBAL_FREEMEM(self); +} diff --git a/src/mms/asn1/ber_decode.c b/src/mms/asn1/ber_decode.c new file mode 100644 index 0000000..7eca930 --- /dev/null +++ b/src/mms/asn1/ber_decode.c @@ -0,0 +1,137 @@ +/* + * ber_decoder.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "ber_decode.h" + +int +BerDecoder_decodeLength(uint8_t* buffer, int* length, int bufPos, int maxBufPos) +{ + if (bufPos >= maxBufPos) + return -1; + + uint8_t len1 = buffer[bufPos++]; + + if (len1 & 0x80) { + int lenLength = len1 & 0x7f; + + if (lenLength == 0) { /* indefinite length form */ + *length = -1; + } + else { + *length = 0; + + int i; + for (i = 0; i < lenLength; i++) { + if (bufPos >= maxBufPos) + return -1; + + *length <<= 8; + *length += buffer[bufPos++]; + } + } + + } + else { + *length = len1; + } + + return bufPos; +} + +char* +BerDecoder_decodeString(uint8_t* buffer, int strlen, int bufPos, int maxBufPos) +{ + char* string = (char*) GLOBAL_MALLOC(strlen + 1); + memcpy(string, buffer + bufPos, strlen); + string[strlen] = 0; + + return string; +} + +uint32_t +BerDecoder_decodeUint32(uint8_t* buffer, int intlen, int bufPos) { + uint32_t value = 0; + + int i; + for (i = 0; i < intlen; i++) { + value <<= 8; + value += buffer[bufPos + i]; + } + + return value; +} + +float +BerDecoder_decodeFloat(uint8_t* buffer, int bufPos) +{ + float value; + uint8_t* valueBuf = (uint8_t*) &value; + + int i; + + bufPos += 1; /* skip exponentWidth field */ + +#if (ORDER_LITTLE_ENDIAN == 1) + for (i = 3; i >= 0; i--) { + valueBuf[i] = buffer[bufPos++]; + } +#else + for (i = 0; i < 4; i++) { + valueBuf[i] = buffer[bufPos++]; + } +#endif + + return value; +} + +double +BerDecoder_decodeDouble(uint8_t* buffer, int bufPos) +{ + double value; + uint8_t* valueBuf = (uint8_t*) &value; + + int i; + + bufPos += 1; /* skip exponentWidth field */ + +#if (ORDER_LITTLE_ENDIAN == 1) + for (i = 7; i >= 0; i--) { + valueBuf[i] = buffer[bufPos++]; + } +#else + for (i = 0; i < 8; i++) { + valueBuf[i] = buffer[bufPos++]; + } +#endif + + return value; +} + +bool +BerDecoder_decodeBoolean(uint8_t* buffer, int bufPos) { + if (buffer[bufPos] != 0) + return true; + else + return false; +} diff --git a/src/mms/asn1/ber_encoder.c b/src/mms/asn1/ber_encoder.c new file mode 100644 index 0000000..35953c6 --- /dev/null +++ b/src/mms/asn1/ber_encoder.c @@ -0,0 +1,416 @@ +/* + * ber_encoder.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "ber_encoder.h" + +int +BerEncoder_encodeLength(uint32_t length, uint8_t* buffer, int bufPos) +{ + if (length < 128) { + buffer[bufPos++] = (uint8_t) length; + } + else if (length < 256) { + buffer[bufPos++] = 0x81; + buffer[bufPos++] = (uint8_t) length; + } + else { + buffer[bufPos++] = 0x82; + + buffer[bufPos++] = length / 256; + buffer[bufPos++] = length % 256; + } + + return bufPos; +} + +int +BerEncoder_encodeTL(uint8_t tag, uint32_t length, uint8_t* buffer, int bufPos) +{ + buffer[bufPos++] = tag; + bufPos = BerEncoder_encodeLength(length, buffer, bufPos); + + return bufPos; +} + +int +BerEncoder_encodeBoolean(uint8_t tag, bool value, uint8_t* buffer, int bufPos) +{ + buffer[bufPos++] = tag; + buffer[bufPos++] = 1; + + if (value) + buffer[bufPos++] = 0xff; + else + buffer[bufPos++] = 0x00; + + return bufPos; +} + +int +BerEncoder_encodeStringWithTag(uint8_t tag, const char* string, uint8_t* buffer, int bufPos) +{ + buffer[bufPos++] = tag; + + if (string != NULL) { + int length = strlen(string); + + bufPos = BerEncoder_encodeLength(length, buffer, bufPos); + + int i; + for (i = 0; i < length; i++) { + buffer[bufPos++] = string[i]; + } + } + else + buffer[bufPos++] = 0; + + return bufPos; +} + +int +BerEncoder_encodeAsn1PrimitiveValue(uint8_t tag, Asn1PrimitiveValue* value, uint8_t* buffer, int bufPos) +{ + buffer[bufPos++] = tag; + + bufPos = BerEncoder_encodeLength(value->size, buffer, bufPos); + + int i; + for (i = 0; i < value->size; i++) { + buffer[bufPos++] = value->octets[i]; + } + + return bufPos; +} + +int +BerEncoder_encodeOctetString(uint8_t tag, uint8_t* octetString, uint32_t octetStringSize, uint8_t* buffer, int bufPos) +{ + buffer[bufPos++] = tag; + + bufPos = BerEncoder_encodeLength(octetStringSize, buffer, bufPos); + + uint32_t i; + for (i = 0; i < octetStringSize; i++) { + buffer[bufPos++] = octetString[i]; + } + + return bufPos; +} + +int +BerEncoder_encodeBitString(uint8_t tag, int bitStringSize, uint8_t* bitString, uint8_t* buffer, int bufPos) +{ + buffer[bufPos++] = tag; + + int byteSize = bitStringSize / 8; + + if (bitStringSize % 8) + byteSize++; + + int padding = (byteSize * 8) - bitStringSize; + + bufPos = BerEncoder_encodeLength(byteSize + 1, buffer, bufPos); + + buffer[bufPos++] = padding; + + int i; + + for (i = 0; i < byteSize; i++) { + buffer[bufPos++] = bitString[i]; + } + + uint8_t paddingMask = 0; + + for (i = 0; i < padding; i++) { + paddingMask += (1 << i); + } + + paddingMask = ~paddingMask; + + buffer[bufPos -1] = buffer[bufPos -1] & paddingMask; + + return bufPos; +} + +int +BerEncoder_determineEncodedBitStringSize(int bitStringSize) +{ + int size = 2; /* for tag and padding */ + + int byteSize = bitStringSize / 8; + + if (bitStringSize % 8) + byteSize++; + + size += BerEncoder_determineLengthSize(byteSize); + + size += byteSize; + + return size; +} + +void +BerEncoder_revertByteOrder(uint8_t* octets, const int size) +{ + int i; + uint8_t temp; + + for (i = 0; i < size / 2; i++) { + temp = octets[i]; + octets[i] = octets[(size - 1) - i]; + octets[(size - 1) - i] = temp; + } +} + + +int +BerEncoder_compressInteger(uint8_t* integer, int originalSize) +{ + + uint8_t* integerEnd = integer + originalSize - 1; + uint8_t* bytePosition; + + for (bytePosition = integer; bytePosition < integerEnd; bytePosition++) { + + if (bytePosition[0] == 0x00) { + if ((bytePosition[1] & 0x80) == 0) + continue; + } + else if (bytePosition[0] == 0xff) { + if (bytePosition[1] & 0x80) + continue; + } + + break; + } + + int bytesToDelete = bytePosition - integer; + int newSize = originalSize; + + if (bytesToDelete) { + newSize -= bytesToDelete; + uint8_t* newEnd = integer + newSize; + + uint8_t *newBytePosition; + + for(newBytePosition = integer; newBytePosition < newEnd; newBytePosition++) { + *newBytePosition = *bytePosition; + bytePosition++; + } + + } + + return newSize; +} + +int +BerEncoder_encodeUInt32(uint32_t value, uint8_t* buffer, int bufPos) +{ + uint8_t* valueArray = (uint8_t*) &value; + uint8_t valueBuffer[5]; + + valueBuffer[0] = 0; + + int i; + for (i = 0; i < 4; i++) { + valueBuffer[i + 1] = valueArray[i]; + } + +#if (ORDER_LITTLE_ENDIAN == 1) + BerEncoder_revertByteOrder(valueBuffer + 1, 4); +#endif + + int size = BerEncoder_compressInteger(valueBuffer, 5); + + for (i = 0; i < size; i++) { + buffer[bufPos++] = valueBuffer[i]; + } + + return bufPos; +} + +int +BerEncoder_encodeUInt32WithTL(uint8_t tag, uint32_t value, uint8_t* buffer, int bufPos) +{ + uint8_t* valueArray = (uint8_t*) &value; + uint8_t valueBuffer[5]; + + valueBuffer[0] = 0; + + int i; + for (i = 0; i < 4; i++) { + valueBuffer[i + 1] = valueArray[i]; + } + +#if (ORDER_LITTLE_ENDIAN == 1) + BerEncoder_revertByteOrder(valueBuffer + 1, 4); +#endif + + int size = BerEncoder_compressInteger(valueBuffer, 5); + + buffer[bufPos++] = tag; + buffer[bufPos++] = (uint8_t) size; + + for (i = 0; i < size; i++) { + buffer[bufPos++] = valueBuffer[i]; + } + + return bufPos; +} + +int +BerEncoder_encodeFloat(uint8_t* floatValue, uint8_t formatWidth, uint8_t exponentWidth, + uint8_t* buffer, int bufPos) +{ + //TODO operate on encoding buffer directly + uint8_t valueBuffer[9]; + + int byteSize = formatWidth / 8; + + valueBuffer[0] = exponentWidth; + + int i; + for (i = 0; i < byteSize; i++) { + valueBuffer[i + 1] = floatValue[i]; + } + +#if (ORDER_LITTLE_ENDIAN == 1) + BerEncoder_revertByteOrder(valueBuffer + 1, byteSize); +#endif + + for (i = 0; i < byteSize + 1; i++) { + buffer[bufPos++] = valueBuffer[i]; + } + + return bufPos; +} + +int +BerEncoder_UInt32determineEncodedSize(uint32_t value) +{ + uint8_t* valueArray = (uint8_t*) &value; + uint8_t valueBuffer[5]; + + valueBuffer[0] = 0; + + int i; + for (i = 0; i < 4; i++) { + valueBuffer[i + 1] = valueArray[i]; + } + +#if (ORDER_LITTLE_ENDIAN == 1) + BerEncoder_revertByteOrder(valueBuffer + 1, 4); +#endif + + int size = BerEncoder_compressInteger(valueBuffer, 5); + + return size; +} + +int +BerEncoder_determineLengthSize(uint32_t length) +{ + if (length < 128) + return 1; + if (length < 256) + return 2; + else + return 3; +} + +int +BerEncoder_determineEncodedStringSize(const char* string) +{ + if (string != NULL) { + int size = 1; + + int length = strlen(string); + + size += BerEncoder_determineLengthSize(length); + + size += length; + + return size; + } + else + return 2; +} + +int +BerEncoder_encodeOIDToBuffer(const char* oidString, uint8_t* buffer, int maxBufLen) +{ + int encodedBytes = 0; + + int x = atoi(oidString); + + const char* separator = strchr(oidString, '.'); + + if (separator == NULL) return 0; + + int y = atoi(separator + 1); + + int val = x * 40 + y; + + if (encodedBytes < maxBufLen) + buffer[encodedBytes] = (uint8_t) val; + else + return 0; + + encodedBytes++; + + while (1) { + separator = strchr(separator + 1, '.'); + + if (separator == NULL) + break; + + val = atoi(separator + 1); + + int requiredBytes = 0; + + int val2 = val; + while (val2 > 0) { + requiredBytes++; + val2 = val2 >> 7; + } + + while (requiredBytes > 0) { + val2 = val >> (7 * (requiredBytes - 1)); + + val2 = val2 & 0x7f; + + if (requiredBytes > 1) + val2 += 128; + + if (encodedBytes == maxBufLen) + return 0; + + buffer[encodedBytes++] = (uint8_t) val2; + + requiredBytes--; + } + } + + return encodedBytes; +} diff --git a/src/mms/asn1/ber_integer.c b/src/mms/asn1/ber_integer.c new file mode 100644 index 0000000..0c3042e --- /dev/null +++ b/src/mms/asn1/ber_integer.c @@ -0,0 +1,238 @@ +/* + * ber_integer.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "ber_integer.h" +#include "ber_encoder.h" + +static int +setIntegerValue(Asn1PrimitiveValue* self, uint8_t* valueBuffer, int bufferSize) +{ +#if (ORDER_LITTLE_ENDIAN == 1) + BerEncoder_revertByteOrder(valueBuffer, bufferSize); +#endif + + int size = BerEncoder_compressInteger(valueBuffer, bufferSize); + + if (size <= self->maxSize) { + self->size = size; + memcpy(self->octets, valueBuffer, size); + return 1; + } + else + return 0; +} + +Asn1PrimitiveValue* +BerInteger_createInt32() +{ + return Asn1PrimitiveValue_create(5); +} + +Asn1PrimitiveValue* +BerInteger_createFromBuffer(uint8_t* buf, int size) +{ + int maxSize; + + if (size > 8) + maxSize = size; + else + maxSize = 8; + + Asn1PrimitiveValue* self = Asn1PrimitiveValue_create(maxSize); + + memcpy(self->octets, buf, size); + + self->size = size; + + return self; +} + +int +BerInteger_setFromBerInteger(Asn1PrimitiveValue* self, Asn1PrimitiveValue* value) +{ + if (self->maxSize >= value->size) { + self->size = value->size; + + memcpy(self->octets, value->octets, value->size); + + return 1; + } + else + return 0; +} + +int +BerInteger_setInt32(Asn1PrimitiveValue* self, int32_t value) +{ + int32_t valueCopy = value; + uint8_t* valueBuffer = (uint8_t*) &valueCopy; + + return setIntegerValue(self, valueBuffer, sizeof(value)); +} + +Asn1PrimitiveValue* +BerInteger_createFromInt32(int32_t value) +{ + Asn1PrimitiveValue* asn1Value = BerInteger_createInt32(); + BerInteger_setInt32(asn1Value, value); + + return asn1Value; +} + +int +BerInteger_setUint16(Asn1PrimitiveValue* self, uint16_t value) +{ + uint16_t valueCopy = value; + uint8_t* valueBuffer = (uint8_t*) &valueCopy; + + return setIntegerValue(self, valueBuffer, sizeof(value)); +} + +int +BerInteger_setUint8(Asn1PrimitiveValue* self, uint8_t value) +{ + uint8_t valueCopy = value; + uint8_t* valueBuffer = (uint8_t*) &valueCopy; + + return setIntegerValue(self, valueBuffer, sizeof(value)); +} + +int +BerInteger_setUint32(Asn1PrimitiveValue* self, uint32_t value) +{ + uint32_t valueCopy = value; + uint8_t* valueBuffer = (uint8_t*) &valueCopy; + + uint8_t byteBuffer[5]; + + int i; + +#if (ORDER_LITTLE_ENDIAN == 1) + byteBuffer[4] = 0; + + for (i = 0; i < 4; i++) + byteBuffer[i] = valueBuffer[i]; +#else + byteBuffer[0] = 0; + + for (i = 0; i < 4; i++) + byteBuffer[i + 1] = valueBuffer[i]; +#endif /* (ORDER_LITTLE_ENDIAN == 1) */ + + return setIntegerValue(self, byteBuffer, 5); +} + +Asn1PrimitiveValue* +BerInteger_createFromUint32(uint32_t value) +{ + Asn1PrimitiveValue* asn1Value = BerInteger_createInt32(); + BerInteger_setUint32(asn1Value, value); + + return asn1Value; +} + +Asn1PrimitiveValue* +BerInteger_createInt64() +{ + return Asn1PrimitiveValue_create(9); +} + +int +BerInteger_setInt64(Asn1PrimitiveValue* self, int64_t value) +{ + int64_t valueCopy = value; + uint8_t* valueBuffer = (uint8_t*) &valueCopy; + + return setIntegerValue(self, valueBuffer, sizeof(value)); +} + +Asn1PrimitiveValue* +BerInteger_createFromInt64(int64_t value) +{ + Asn1PrimitiveValue* asn1Value = BerInteger_createInt64(); + BerInteger_setInt64(asn1Value, value); + + return asn1Value; +} + +int /* 1 - if conversion is possible, 0 - out of range */ +BerInteger_toInt32(Asn1PrimitiveValue* self, int32_t* nativeValue) +{ + if (self->size < 5) { + uint8_t* buf = self->octets; + int i; + + if (buf[0] & 0x80) /* sign extension */ + *nativeValue = 0xffffffff; + else + *nativeValue = 0; + + for (i = 0; i < self->size; i++) + *nativeValue = (*nativeValue << 8) | buf[i]; + + return 1; + } + else + return 0; +} + +int /* 1 - if conversion is possible, 0 - out of range */ +BerInteger_toUint32(Asn1PrimitiveValue* self, uint32_t* nativeValue) +{ + if (self->size < 6) { + uint8_t* buf = self->octets; + int i; + + *nativeValue = 0; + + for (i = 0; i < self->size; i++) + *nativeValue = (*nativeValue << 8) | buf[i]; + + return 1; + } + else + return 0; +} + +int /* 1 - if conversion is possible, 0 - out of range */ +BerInteger_toInt64(Asn1PrimitiveValue* self, int64_t* nativeValue) +{ + if (self->size < 9) { + uint8_t* buf = self->octets; + int i; + + if (buf[0] & 0x80) /* sign extension */ + *nativeValue = 0xffffffffffffffff; + else + *nativeValue = 0; + + for (i = 0; i < self->size; i++) + *nativeValue = (*nativeValue << 8) | buf[i]; + + return 1; + } + else + return 0; +} + diff --git a/src/mms/inc/asn1_ber_primitive_value.h b/src/mms/inc/asn1_ber_primitive_value.h new file mode 100644 index 0000000..5821b60 --- /dev/null +++ b/src/mms/inc/asn1_ber_primitive_value.h @@ -0,0 +1,62 @@ +/* + * asn1_ber_primitive_value.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ASN1_BER_PRIMITIVE_VALUE_H_ +#define ASN1_BER_PRIMITIVE_VALUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "libiec61850_common_api.h" + +typedef struct ATTRIBUTE_PACKED { + uint8_t size; + uint8_t maxSize; + uint8_t* octets; +} Asn1PrimitiveValue; + +Asn1PrimitiveValue* +Asn1PrimitiveValue_create(int size); + +int +Asn1PrimitiveValue_getSize(Asn1PrimitiveValue* self); + +int +Asn1PrimitiveValue_getMaxSize(Asn1PrimitiveValue* self); + +Asn1PrimitiveValue* +Asn1PrimitiveValue_clone(Asn1PrimitiveValue* self); + +bool +Asn1PrimitivaValue_compare(Asn1PrimitiveValue* self, Asn1PrimitiveValue* otherValue); + +void +Asn1PrimitiveValue_destroy(Asn1PrimitiveValue* self); + +#ifdef __cplusplus +} +#endif + +#endif /* ASN1_BER_PRIMITIVE_VALUE_H_ */ diff --git a/src/mms/inc/ber_integer.h b/src/mms/inc/ber_integer.h new file mode 100644 index 0000000..32e32ca --- /dev/null +++ b/src/mms/inc/ber_integer.h @@ -0,0 +1,82 @@ +/* + * ber_integer.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef BER_INTEGER_H_ +#define BER_INTEGER_H_ + +#include "asn1_ber_primitive_value.h" + +#ifdef __cplusplus +extern "C" { +#endif + +Asn1PrimitiveValue* +BerInteger_createFromBuffer(uint8_t* buf, int size); + +Asn1PrimitiveValue* +BerInteger_createInt32(void); + +int +BerInteger_setFromBerInteger(Asn1PrimitiveValue* self, Asn1PrimitiveValue* value); + +int +BerInteger_setInt32(Asn1PrimitiveValue* self, int32_t value); + +Asn1PrimitiveValue* +BerInteger_createFromInt32(int32_t value); + +int +BerInteger_setUint8(Asn1PrimitiveValue* self, uint8_t value); + +int +BerInteger_setUint16(Asn1PrimitiveValue* self, uint16_t value); + +int +BerInteger_setUint32(Asn1PrimitiveValue* self, uint32_t value); + +Asn1PrimitiveValue* +BerInteger_createFromUint32(uint32_t value); + +Asn1PrimitiveValue* +BerInteger_createFromInt64(int64_t value); + +Asn1PrimitiveValue* +BerInteger_createInt64(void); + +int +BerInteger_setInt64(Asn1PrimitiveValue* self, int64_t value); + +int /* 1 - if conversion is possible, 0 - out of range */ +BerInteger_toInt32(Asn1PrimitiveValue* self, int32_t* nativeValue); + +int /* 1 - if conversion is possible, 0 - out of range */ +BerInteger_toUint32(Asn1PrimitiveValue* self, uint32_t* nativeValue); + +int /* 1 - if conversion is possible, 0 - out of range */ +BerInteger_toInt64(Asn1PrimitiveValue* self, int64_t* nativeValue); + +#ifdef __cplusplus +} +#endif + +#endif /* BER_INTEGER_H_ */ diff --git a/src/mms/inc/iso_connection_parameters.h b/src/mms/inc/iso_connection_parameters.h new file mode 100644 index 0000000..27fbb82 --- /dev/null +++ b/src/mms/inc/iso_connection_parameters.h @@ -0,0 +1,242 @@ +/* + * iso_connection_parameters.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ISO_CONNECTION_PARAMETERS_H_ +#define ISO_CONNECTION_PARAMETERS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup mms_client_api_group + */ +/**@{*/ + + +typedef enum +{ + ACSE_AUTH_NONE = 0, + ACSE_AUTH_PASSWORD = 1 +} AcseAuthenticationMechanism; + + +/* --> for compatibility with older versions (libiec61850 < 0.7.7) */ +#ifndef AUTH_NONE +#define AUTH_NONE ACSE_AUTH_NONE +#endif + +#ifndef AUTH_PASSWORD +#define AUTH_PASSWORD ACSE_AUTH_PASSWORD +#endif +/* <-- for compatibility with older versions (libiec61850 < 0.7.7) */ + +typedef struct sAcseAuthenticationParameter* AcseAuthenticationParameter; + +struct sAcseAuthenticationParameter +{ + AcseAuthenticationMechanism mechanism; + union + { + struct + { + uint8_t* octetString; + int passwordLength; + } password; + } value; +}; + +AcseAuthenticationParameter +AcseAuthenticationParameter_create(void); + +void +AcseAuthenticationParameter_destroy(AcseAuthenticationParameter self); + +void +AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, AcseAuthenticationMechanism mechanism); + +void +AcseAuthenticationParameter_setPassword(AcseAuthenticationParameter self, char* password); + + +/** + * \brief Callback function to authenticate a client + * + * \param parameter user provided parameter - set when user registers the authenticator + * \param authParameter the authentication parameters provided by the client + * \param securityToken pointer where to store an application specific security token - can be ignored if not used. + * + * \return true if client connection is accepted, false otherwise + */ +typedef bool +(*AcseAuthenticator)(void* parameter, AcseAuthenticationParameter authParameter, void** securityToken); + +/** + * \brief COTP T selector + * + * To not use T SEL set size to 0. + */ +typedef struct { + uint8_t size; /** 0 .. 4 - 0 means T-selector is not present */ + uint8_t value[4]; /** T-selector value - value[0] */ +} TSelector; + +struct sIsoConnectionParameters +{ + AcseAuthenticationParameter acseAuthParameter; + + const char* hostname; + int tcpPort; + + uint8_t remoteApTitle[10]; + int remoteApTitleLen; + int remoteAEQualifier; + uint32_t remotePSelector; + uint16_t remoteSSelector; + TSelector remoteTSelector; + + uint8_t localApTitle[10]; + int localApTitleLen; + int localAEQualifier; + uint32_t localPSelector; + uint16_t localSSelector; + TSelector localTSelector; + +}; + +typedef struct sIsoConnectionParameters* IsoConnectionParameters; + +/** + * \brief create a new IsoConnectionParameters instance (FOR LIBRARY INTERNAL USE) + * + * NOTE: This function used internally by the MMS client library. When using the MMS or IEC 61850 API + * there should be no reason for the user to call this function. + * + * \return new IsoConnectionParameters instanceextern "C" { + */ +IsoConnectionParameters +IsoConnectionParameters_create(void); + +/** + * \brief Destroy an IsoConnectionParameters instance (FOR LIBRARY INTERNAL USE) + * + * NOTE: This function used internally by the MMS client library. When using the MMS or IEC 61850 API + * there should be no reason for the user to call this function. + * + * \param self the IsoConnectionParameters instance + */ +void +IsoConnectionParameters_destroy(IsoConnectionParameters self); + +/** + * \brief set the authentication parameter + * + * This will set the authentication parameter and activates authentication. + * + * \param self the IsoConnectionParameters instance + * \param acseAuthParameter + */ +void +IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters self, + AcseAuthenticationParameter acseAuthParameter); + +/** + * \brief Set TCP parameters (FOR LIBRARY INTERNAL USE) + * + * NOTE: This function used internally by the MMS client library. When using the MMS or IEC 61850 API + * there should be no reason for the user to call this function + * + * \param self the IsoConnectionParameters instance + * \param hostname the hostname of IP address if the server + * \param tcpPort the TCP port number of the server + */ +void +IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const char* hostname, int tcpPort); + +/** + * \brief set the remote AP-Title and AE-Qualifier + * + * Calling this function is optional and not recommended. If not called the default + * parameters are used. + * If apTitle is NULL the parameter the AP-Title and AE-Qualifier will not be transmitted. + * This seems to be required by some server devices. + * + * \param self the IsoConnectionParameters instance + * \param apTitle the AP-Title OID as string. + * \param aeQualifier the AP-qualifier + */ +void +IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier); + +/** + * \brief set remote addresses for the lower layers + * + * This function can be used to set the addresses for the lower layer protocols (presentation, session, and transport + * layer). Calling this function is optional and not recommended. If not called the default + * parameters are used. + * + * \param self the IsoConnectionParameters instance + * \param pSelector the P-Selector (presentation layer address) + * \param sSelector the S-Selector (session layer address) + * \param tSelector the T-Selector (ISO transport layer address) + */ +void +IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector); + +/** + * \brief set the local AP-Title and AE-Qualifier + * + * Calling this function is optional and not recommended. If not called the default + * parameters are used. + * If apTitle is NULL the parameter the AP-Title and AE-Qualifier will not be transmitted. + * This seems to be required by some server devices. + * + * \param self the IsoConnectionParameters instance + * \param apTitle the AP-Title OID as string. + * \param aeQualifier the AP-qualifier + */ +void +IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, char* apTitle, int aeQualifier); + +/** + * \brief set local addresses for the lower layers + * + * This function can be used to set the addresses for the lower layer protocols (presentation, session, and transport + * layer). Calling this function is optional and not recommended. If not called the default + * parameters are used. + * + * \param self the IsoConnectionParameters instance + * \param pSelector the P-Selector (presentation layer address) + * \param sSelector the S-Selector (session layer address) + * \param tSelector the T-Selector (ISO transport layer address) + */ +void +IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* ISO_CONNECTION_PARAMETERS_H_ */ diff --git a/src/mms/inc/iso_server.h b/src/mms/inc/iso_server.h new file mode 100644 index 0000000..8c1615f --- /dev/null +++ b/src/mms/inc/iso_server.h @@ -0,0 +1,150 @@ +/* + * iso_server.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ISO_SERVER_H_ +#define ISO_SERVER_H_ + +#include "byte_buffer.h" +#include "iso_connection_parameters.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup mms_server_api_group + * @{ + */ + +typedef enum +{ + ISO_SVR_STATE_IDLE, + ISO_SVR_STATE_RUNNING, + ISO_SVR_STATE_STOPPED, + ISO_SVR_STATE_ERROR +} IsoServerState; + +typedef struct sIsoServer* IsoServer; + +typedef enum +{ + ISO_CONNECTION_OPENED, + ISO_CONNECTION_CLOSED +} IsoConnectionIndication; + +typedef struct sIsoConnection* IsoConnection; + +typedef struct sIsoServerCallbacks +{ + void + (*clientConnected)(IsoConnection connection); +} IsoServerCallbacks; + +typedef void +(*ConnectionIndicationHandler)(IsoConnectionIndication indication, + void* parameter, IsoConnection connection); + +typedef void +(*MessageReceivedHandler)(void* parameter, ByteBuffer* message, ByteBuffer* response); + +char* +IsoConnection_getPeerAddress(IsoConnection self); + +void +IsoConnection_close(IsoConnection self); + +void +IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler, + void* parameter); + +void* +IsoConnection_getSecurityToken(IsoConnection self); + +/** + * \brief send a message over an ISO connection + * + * \param handlerMode specifies if this function is used in the context of the connection handling thread + * (handlerMode) + */ +void +IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerMode); + +IsoServer +IsoServer_create(void); + +void +IsoServer_setTcpPort(IsoServer self, int port); + +void +IsoServer_setLocalIpAddress(IsoServer self, char* ipAddress); + +IsoServerState +IsoServer_getState(IsoServer self); + +void +IsoServer_setConnectionHandler(IsoServer self, ConnectionIndicationHandler handler, + void* parameter); + +void +IsoServer_setAuthenticator(IsoServer self, AcseAuthenticator authenticator, void* authenticatorParameter); + +AcseAuthenticator +IsoServer_getAuthenticator(IsoServer self); + +void* +IsoServer_getAuthenticatorParameter(IsoServer self); + +void +IsoServer_startListening(IsoServer self); + +void +IsoServer_stopListening(IsoServer self); + + +void +IsoServer_startListeningThreadless(IsoServer self); + +/** + * for non-threaded operation + */ +void +IsoServer_processIncomingMessages(IsoServer self); + +int +IsoServer_waitReady(IsoServer self, unsigned int timeoutMs); + +void +IsoServer_stopListeningThreadless(IsoServer self); + +void +IsoServer_closeConnection(IsoServer self, IsoConnection isoConnection); + +void +IsoServer_destroy(IsoServer self); + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* ISO_SERVER_H_ */ diff --git a/src/mms/inc/mms_client_connection.h b/src/mms/inc/mms_client_connection.h new file mode 100644 index 0000000..d87667e --- /dev/null +++ b/src/mms/inc/mms_client_connection.h @@ -0,0 +1,685 @@ +/* + * mms_client_connection.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_CLIENT_CONNECTION_H_ +#define MMS_CLIENT_CONNECTION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup mms_client_api_group MMS client API (for IEC 61850 use IEC 61850 client API instead!) + */ +/**@{*/ + +#include "libiec61850_common_api.h" + +#include "mms_common.h" +#include "mms_type_spec.h" +#include "mms_value.h" +#include "iso_connection_parameters.h" +#include "linked_list.h" + +/** + * Contains MMS layer specific parameters + */ +typedef struct sMmsConnectionParameters { + int maxServOutstandingCalling; + int maxServOutstandingCalled; + int dataStructureNestingLevel; + int maxPduSize; /* local detail */ +} MmsConnectionParameters; + +typedef struct { + char* vendorName; + char* modelName; + char* revision; +} MmsServerIdentity; + +typedef void (*MmsInformationReportHandler) (void* parameter, char* domainName, + char* variableListName, MmsValue* value, bool isVariableListName); + +/** + * Opaque handle for MMS client connection instance. + */ +typedef struct sMmsConnection* MmsConnection; + + +/******************************************************************************* + * Connection management functions + *******************************************************************************/ + +/** + * \brief Create a new MmsConnection instance + * + * \return the newly created instance. + */ +MmsConnection +MmsConnection_create(void); + +/** + * \brief Set the request timeout in ms for this connection + * + * \param self MmsConnection instance to operate on + * \param timeoutInMs request timeout in milliseconds + */ +void +MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs); + +/** + * \brief Set the connect timeout in ms for this connection instance + * + * \param self MmsConnection instance to operate on + * \param timeoutInMs connect timeout in milliseconds + */ +void +MmsConnection_setConnectTimeout(MmsConnection self, uint32_t timeoutInMs); + +/** + * \brief Install a handler function for MMS information reports (unsolicited messages from the server). + * + * The handler function will be called whenever the client receives an MMS information report message. + * Note that the API user is responsible to properly free the passed MmsValue object. + * + * \param self MmsConnection instance to operate on + * \param handler the handler function to install for this client connection + * \param parameter a user specified parameter that will be passed to the handler function on each + * invocation. + */ +void +MmsConnection_setInformationReportHandler(MmsConnection self, MmsInformationReportHandler handler, + void* parameter); + +/** + * \brief Get the connection parameters for an MmsConnection instance + * + * \param self MmsConnection instance to operate on + * \return params the to be used by this connection + */ +IsoConnectionParameters +MmsConnection_getIsoConnectionParameters(MmsConnection self); + +/** + * \brief User provided handler function that will be called if the connection to the server is lost + * + * \param connection MmsConnection object of the lost connection + * \param parameter user provided parameter. + */ +typedef void (*MmsConnectionLostHandler) (MmsConnection connection, void* parameter); + +/** + * \brief Install a callback function that will be called by the client stack if the MMS connection to the server is lost + * + * \param handler the user provided callback function + * \param handlerParameter a parameter that will be passed to the callback function. Can be set to NULL if not required. + */ +void +MmsConnection_setConnectionLostHandler(MmsConnection self, MmsConnectionLostHandler handler, void* handlerParameter); + +/** + * \brief Set the ISO connection parameters for a MmsConnection instance + * + * \param self MmsConnection instance to operate on + * \param params the ISO client parameters to use + */ +void +MmsConnection_setIsoConnectionParameters(MmsConnection self, IsoConnectionParameters* params); + +/** + * \brief Destroy an MmsConnection instance and release all resources + * + * \param self MmsConnection instance to operate on + */ +void +MmsConnection_destroy(MmsConnection self); + +/******************************************************************************* + * Blocking functions for connection establishment and data access + *******************************************************************************/ + + +/** + * \brief Connect to an MMS server. + * + * This will open a new TCP connection and send a MMS initiate request. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param serverName hostname or IP address of the server to connect + * \param serverPort TCP port number of the server to connect (usually 102) + * + * \return true on success. false if the connection attempt failed. + */ +bool +MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort); + +/** + * \brief Close the connection - not recommended + * + * This service simply closes the TCP socket without any hand-shaking with the server. + * This behavior is not specified. Use with care! + * + * \param self MmsConnection instance to operate on + */ +void +MmsConnection_close(MmsConnection self); + +/** + * \brief Uses the MMS/ACSE abort service to close the connection to the server + * + * This service should be used to abruptly interrupt the connection to the server. It is not quite clear what the + * benefit of this service is (simply closing the TCP connection should do the same). Though it is required by + * conformance tests. In case the server doesn't close the connection after the internal timeout interval the + * client will close the TCP connection and set mmsError to MMS_ERROR_SERVICE_TIMEOUT. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + */ +void +MmsConnection_abort(MmsConnection self, MmsError* mmsError); + +/** + * \brief Uses the MMS conclude service to close the connection to the server + * + * This should be used to orderly release the connection to the server. If the server denies the conclude + * request (by sending a concludeError PDU) this service fails with an error (mmsError set accordingly) and + * the connection remains open. In this case the close or abort methods have to be used to close the connection. + * It is not quite clear if this service is really useful but it is required by conformance tests. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + */ +void +MmsConnection_conclude(MmsConnection self, MmsError* mmsError); + + +/** + * \brief Get the names of all VMD scope variables of the server. + * + * This will result in a VMD specific GetNameList request. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * + * \return the of VMD specific variable names or NULL if the request failed. + */ +LinkedList /* */ +MmsConnection_getVMDVariableNames(MmsConnection self, MmsError* mmsError); + +/** + * \brief Get the domains names for all domains of the server. + * + * This will result in a VMD specific GetNameList request. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variaextern "C" {ble to store error code + * + * \return the list of domain names or NULL if the request failed. + * + */ +LinkedList /* */ +MmsConnection_getDomainNames(MmsConnection self, MmsError* mmsError); + +/** + * \brief Get the names of all variables present in a MMS domain of the server. + * + * This will result in a domain specific GetNameList request. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name for the domain specific request + * + * \return the of domain specific variable names or NULL if the request failed. + */ +LinkedList /* */ +MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, const char* domainId); + +/** + * \brief Get the names of all named variable lists present in a MMS domain of the server. + * + * This will result in a domain specific GetNameList request. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name for the domain specific request + * + * \return the domain specific named variable list names or NULL if the request failed. + */ +LinkedList /* */ +MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, const char* domainId); + +/** + * \brief Get the names of all named variable lists associated with this client connection. + * + * This will result in an association specific GetNameList request. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * + * \return the association specific named variable list names or NULL if the request failed. + */ +LinkedList /* */ +MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsError* mmsError); + + +/** + * \brief Read a single variable from the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the variable to be read or NULL to read a VMD specific named variable + * \param itemId name of the variable to be read + * + * \return Returns a MmsValue object or NULL if the request failed. The MmsValue object can + * either be a simple value or a complex value or array. + */ +MmsValue* +MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId); + +/** + * \brief Read an element of a single array variable from the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the variable to be read + * \param itemId name of the variable to be read + * \param startIndex index of element to read or start index if a element range is to be read + * \param numberOfElements Number of elements to read or 0 if a single element is to be read + * + * \return Returns a MmsValue object or NULL if the request failed. The MmsValue object is either + * a simple or complex type if numberOfElements is 0, or an array containing the selected + * array elements of numberOfElements > 0. + */ +MmsValue* +MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId, + uint32_t startIndex, uint32_t numberOfElements); + +/** + * \brief Read multiple variables of a domain from the server with one request message. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the requested variables. + * \param items: LinkedList is the list of item IDs of the requested variables. + * + * \return Returns a MmsValue object or NULL if the request failed. The MmsValue object is + * is of type MMS_ARRAY and contains the variable values of simple or complex type + * in the order as they appeared in the item ID list. + */ +MmsValue* +MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId, + LinkedList /**/ items); + +/** + * \brief Write a single variable to the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the variable to be written + * \param itemId name of the variable to be written + * \param value value of the variable to be written + */ +void +MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, MmsValue* value); + +/** + * \brief Write multiple variables to the server. + * + * This function will write multiple variables at the server. + * + * The parameter accessResults is a pointer to a LinkedList reference. The methods will create a new LinkedList + * object that contains the AccessResults of the single variable write attempts. It is up to the user to free this + * objects properly (e.g. with LinkedList_destroyDeep(accessResults, MmsValue_delete)). + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the common domain name of all variables to be written + * \param items a linked list containing the names of the variables to be written. The names are C strings. + * \param values values of the variables to be written + * \param (OUTPUT) the MmsValue objects of type MMS_DATA_ACCESS_ERROR representing the write success of a single variable + * write. + */ +void +MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId, + LinkedList /**/ items, LinkedList /* */ values, + LinkedList* /* */ accessResults); + +/** + * \brief Get the variable access attributes of a MMS named variable of the server + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the variable + * \param itemId name of the variable + * + * \return Returns a MmsTypeSpecification object or NULL if the request failed. + */ +MmsVariableSpecification* +MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId); + +/** + * \brief Read the values of a domain specific named variable list + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the requested variables. + * \param listName the name of the named variable list + * \param specWithResult if specWithResult is set to true, a IEC 61850 compliant request will be sent. + * + * \return Returns a MmsValue object or NULL if the request failed. The MmsValue object is + * is of type MMS_ARRAY and contains the variable values of simple or complex type + * in the order as they appeared in named variable list definition. + */ +MmsValue* +MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError, const char* domainId, + const char* listName, bool specWithResult); + + +/** + * \brief Read the values of a association specific named variable list + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param listName the name of the named variable list + * \param specWithResult if specWithResult is set to true, a IEC 61850 compliant request will be sent. + * + * \return Returns a MmsValue object or NULL if the request failed. The MmsValue object is + * is of type MMS_ARRAY and contains the variable values of simple or complex type + * in the order as they appeared in named variable list definition. + */ +MmsValue* +MmsConnection_readNamedVariableListValuesAssociationSpecific(MmsConnection self, MmsError* mmsError, + const char* listName, bool specWithResult); + +/** + * \brief Define a new named variable list at the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the domain for the new variable list + * \param listName the name of the named variable list + * \param variableSpecs a list of variable specifications for the new variable list. The list + * elements have to be of type MmsVariableAccessSpecification*. + */ +void +MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError, const char* domainId, + const char* listName, LinkedList variableSpecs); + + +/** + * \brief Define a new association specific named variable list at the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param listName the name of the named variable list + * \param variableSpecs list of variable specifications for the new variable list.The list + * elements have to be of type MmsVariableAccessSpecification*. + */ +void +MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self, MmsError* mmsError, + const char* listName, LinkedList variableSpecs); + +/** + * \brief Read the entry list of a named variable list at the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the domain of the variable list + * \param listName the name of the named variable list + * \param deletable THIS IS A OUTPUT PARAMETER - indicates if the variable list is deletable by the + * client. The user may provide a NULL pointer if the value doesn't matter. + * + * \return List of names of the variable list entries or NULL if the request failed + */ +LinkedList /* */ +MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* listName, bool* deletable); + + + +/** + * \brief Read the entry list of an association specific named variable list at the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param listName the name of the named variable list + * + * \return List of names of the variable list entries or NULL if the request failed + */ +LinkedList /* */ +MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection self, MmsError* mmsError, + const char* listName, bool* deletable); + +/** + * \brief Delete a named variable list at the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the domain of the variable list + * \param listName the name of the named variable list + */ +void +MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError, const char* domainId, const char* listName); + +/** + * \brief Delete an association specific named variable list at the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param listName the name of the named variable list + */ +void +MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self, MmsError* mmsError, + const char* listName); + +/** + * \brief Create a new MmsVariableSpecification that can be used to define named variable lists. + * + * The created object can be deleted with free(). If the parameter strings were dynamically + * allocated the deallocation is in the responsibility of the user. + * + * \param domainId the MMS domain name of the variable + * \param itemId the name for the MMS variable + * + * \return reference to the new MmsVariableSpecfication object + */ +MmsVariableAccessSpecification* +MmsVariableAccessSpecification_create(char* domainId, char* itemId); + +/** + * \brief Create a new MmsVariableSpecification that can be used to define named variable lists. + * + * The created object can be deleted with free(). If the parameter strings were dynamically + * allocated the deallocation is in the responsibility of the user. This function should be + * used for named variable list entries that are array elements or components of array elements + * in the case when the array element is of complex (structured) type. + * + * \param domainId the MMS domain name of the variable + * \param itemId the name for the MMS variable + * \param index the array index to describe an array element + * \param componentName the name of the component of the array element. Should be set to NULL + * if the array element is of simple type or the whole array element is required. + * + * \return reference to the new MmsVariableSpecfication object + */ +MmsVariableAccessSpecification* +MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemId, int32_t index, + char* componentName); + +/** + * \brief Delete the MmsVariableAccessSpecification data structure + * + * \param self the instance to delete + */ +void +MmsVariableAccessSpecification_destroy(MmsVariableAccessSpecification* self); + +/** + * \brief Get the MMS local detail parameter (local detail means maximum MMS PDU size). + * + * This defaults to 65000 (or the value specified in the stack_config.h file. + * This function should not be called after a successful connection attempt. + * + * \param self MmsConnection instance to operate on + * \param localDetail the maximum size of the MMS PDU that will be accepted. + */ +void +MmsConnection_setLocalDetail(MmsConnection self, int32_t localDetail); + +int32_t +MmsConnection_getLocalDetail(MmsConnection self); + +/** + * \brief get the identity of the connected server + * + * This function will return the identity of the server if the server supports the MMS identify service. + * The server identity consists of a vendor name, model name, and a revision. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + */ +MmsServerIdentity* +MmsConnection_identify(MmsConnection self, MmsError* mmsError); + +void +MmsServerIdentity_destroy(MmsServerIdentity* self); + +/** + * \brief get the VMD status of the connected server (is MMS status service) + * + * This function will return the status of the connected server by invoking the MMS status service. + * The services returns the logical and physical states of the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param vmdLogicalStatus user provided variable to store the logical state of the VMD + * \param vmdPhysicalStatus user provided variable to store the physical state of the VMD + * \param extendedDerivation instructs the server to invoke self-diagnosis routines to determine server status + */ +void +MmsConnection_getServerStatus(MmsConnection self, MmsError* mmsError, int* vmdLogicalStatus, int* vmdPhysicalStatus, + bool extendedDerivation); + +/******************************************************************************* + * functions for MMS file services + *******************************************************************************/ + +typedef void +(*MmsFileDirectoryHandler) (void* parameter, char* filename, uint32_t size, uint64_t lastModified); + +typedef void +(*MmsFileReadHandler) (void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t bytesReceived); + +/** + * \brief open a file for read + * + * \return the FRSM ID (file read state machine) handle of the opened file + */ +int32_t +MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filename, uint32_t initialPosition, + uint32_t* fileSize, uint64_t* lastModified); + +/** + * \brief read the next data block from the file + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param frsmId the FRSM ID (file read state machine) handle of the file + * \param handler callback that is invoked to deliver the received data + * \param handlerParameter user provided paramter that is passed to the callback function + * + * \return true if more data follows, false if last data has been received. + */ +bool +MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, MmsFileReadHandler handler, void* handlerParameter); + +/** + * \brief close the file with the specified frsmID + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param frsmId id of the file to close + */ +void +MmsConnection_fileClose(MmsConnection self, MmsError* mmsError, int32_t frsmId); + +/** + * \brief delete the file with the specified name + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param fileName name of the file to delete + */ +void +MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, const char* fileName); + +/** + * \brief rename the file with the specified name + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param currentFileName name of the file to rename + * \param newFileName new name of the file + */ +void +MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, const char* currentFileName, const char* newFileName); + +/** + * \brief get the file directory of the server. + * + * This function will return the directory entries of the given server directory. For each directory entry + * the provided callback handler is called. If the + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param fileSpecification the file specification of the directory to browse or NULL to browse the root directory + * \param continueAfter continuation point or NULL for the first request. The continuation point is the first entry + * after the provided continuation file name. + * \param handler user provided callback handler + * \param handlerParameter user provided parameter that is passed to the handler + * + * \return (more follows) true if more data is available + */ +bool +MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, const char* fileSpecification, const char* continueAfter, + MmsFileDirectoryHandler handler, void* handlerParameter); + + +/** + * \brief Destroy (free) an MmsServerIdentity object + * + * \param self the object to destroy + */ +void +MmsServerIdentity_destroy(MmsServerIdentity* self); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_CLIENT_CONNECTION_H_ */ diff --git a/src/mms/inc/mms_common.h b/src/mms/inc/mms_common.h new file mode 100644 index 0000000..50d6b12 --- /dev/null +++ b/src/mms/inc/mms_common.h @@ -0,0 +1,161 @@ +/* + * mms_common.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_common_api.h" + +#ifndef MMS_COMMON_H_ +#define MMS_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup common_api_group + */ +/**@{*/ + +typedef enum +{ + /* generic error codes */ + MMS_ERROR_NONE = 0, + MMS_ERROR_CONNECTION_REJECTED = 1, + MMS_ERROR_CONNECTION_LOST = 2, + MMS_ERROR_SERVICE_TIMEOUT = 3, + MMS_ERROR_PARSING_RESPONSE = 4, + MMS_ERROR_HARDWARE_FAULT = 5, + MMS_ERROR_CONCLUDE_REJECTED = 6, + MMS_ERROR_OTHER = 9, + + /* confirmed error PDU codes */ + MMS_ERROR_VMDSTATE_OTHER = 10, + + MMS_ERROR_APPLICATION_REFERENCE_OTHER = 20, + + MMS_ERROR_DEFINITION_OTHER = 30, + MMS_ERROR_DEFINITION_INVALID_ADDRESS = 31, + MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED = 32, + MMS_ERROR_DEFINITION_TYPE_INCONSISTENT = 33, + MMS_ERROR_DEFINITION_OBJECT_UNDEFINED = 34, + MMS_ERROR_DEFINITION_OBJECT_EXISTS = 35, + MMS_ERROR_DEFINITION_OBJECT_ATTRIBUTE_INCONSISTENT = 36, + + MMS_ERROR_RESOURCE_OTHER = 40, + MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE = 41, + + MMS_ERROR_SERVICE_OTHER = 50, + + MMS_ERROR_SERVICE_PREEMPT_OTHER = 60, + + MMS_ERROR_TIME_RESOLUTION_OTHER = 70, + + MMS_ERROR_ACCESS_OTHER = 80, + MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT = 81, + MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED = 82, + MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED = 83, + MMS_ERROR_ACCESS_OBJECT_INVALIDATED = 84, + MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID = 85, /* for DataAccessError 11 */ + MMS_ERROR_ACCESS_TEMPORARILY_UNAVAILABLE = 86, /* for DataAccessError 2 */ + + MMS_ERROR_FILE_OTHER = 90, + MMS_ERROR_FILE_FILENAME_AMBIGUOUS = 91, + MMS_ERROR_FILE_FILE_BUSY = 92, + MMS_ERROR_FILE_FILENAME_SYNTAX_ERROR = 93, + MMS_ERROR_FILE_CONTENT_TYPE_INVALID = 94, + MMS_ERROR_FILE_POSITION_INVALID = 95, + MMS_ERROR_FILE_FILE_ACCESS_DENIED = 96, + MMS_ERROR_FILE_FILE_NON_EXISTENT = 97, + MMS_ERROR_FILE_DUPLICATE_FILENAME = 98, + MMS_ERROR_FILE_INSUFFICIENT_SPACE_IN_FILESTORE = 99, + + /* reject codes */ + MMS_ERROR_REJECT_OTHER = 100, + MMS_ERROR_REJECT_UNKNOWN_PDU_TYPE = 101, + MMS_ERROR_REJECT_INVALID_PDU = 102, + MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE = 103, + MMS_ERROR_REJECT_UNRECOGNIZED_MODIFIER = 104, + MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT = 105 + +} MmsError; + +typedef enum ATTRIBUTE_PACKED +{ + /*! this represents all MMS array types (arrays contain uniform elements) */ + MMS_ARRAY = 0, + /*! this represents all complex MMS types (structures) */ + MMS_STRUCTURE = 1, + /*! boolean value */ + MMS_BOOLEAN = 2, + /*! bit string */ + MMS_BIT_STRING = 3, + /*! represents all signed integer types */ + MMS_INTEGER = 4, + /*! represents all unsigned integer types */ + MMS_UNSIGNED = 5, + /*! represents all float type (32 and 64 bit) */ + MMS_FLOAT = 6, + /*! octet string (unstructured bytes) */ + MMS_OCTET_STRING = 7, + /*! MMS visible string */ + MMS_VISIBLE_STRING = 8, + MMS_GENERALIZED_TIME = 9, + MMS_BINARY_TIME = 10, + MMS_BCD = 11, + MMS_OBJ_ID = 12, + /*! MMS unicode string */ + MMS_STRING = 13, + /*! MMS UTC time type */ + MMS_UTC_TIME = 14, + /*! This represents an error code as returned by MMS read services */ + MMS_DATA_ACCESS_ERROR = 15 +} MmsType; + +typedef struct sMmsDomain MmsDomain; + +typedef struct sMmsAccessSpecifier +{ + MmsDomain* domain; + char* variableName; + int arrayIndex; /* -1 --> no index present / ignore index */ + char* componentName; +} MmsAccessSpecifier; + +typedef struct +{ + char* domainId; + char* itemId; + int32_t arrayIndex; /* -1 --> no index present / ignore index */ + char* componentName; +} MmsVariableAccessSpecification; + +typedef struct sMmsNamedVariableList* MmsNamedVariableList; +typedef struct sMmsAccessSpecifier* MmsNamedVariableListEntry; + +/**@}*/ + + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_COMMON_H_ */ diff --git a/src/mms/inc/mms_device_model.h b/src/mms/inc/mms_device_model.h new file mode 100644 index 0000000..0787fa4 --- /dev/null +++ b/src/mms/inc/mms_device_model.h @@ -0,0 +1,191 @@ +/* + * mms_model.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_DEVICE_MODEL_H_ +#define MMS_DEVICE_MODEL_H_ + +#include "libiec61850_common_api.h" + +#include "mms_type_spec.h" +#include "mms_common.h" +#include "mms_named_variable_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char* deviceName; + + /* MMS VMD scope variables support */ + int namedVariablesCount; + MmsVariableSpecification** namedVariables; + + /* MMS VMD scope named variables list support */ + LinkedList /**/ namedVariableLists; + + /* MMS domain support */ + int domainCount; + MmsDomain** domains; +} MmsDevice; + +/* + * Server side data structure to hold informations for a MMS domain (Logical Device) + */ +struct sMmsDomain { + char* domainName; + int namedVariablesCount; + MmsVariableSpecification** namedVariables; + LinkedList /**/ namedVariableLists; +}; + +/** + * @defgroup mms_server_api_group MMS server API (for IEC 61850 use IEC 61850 server API instead!) + * + * @{ + */ + +/** + * \brief Create a new MmsDomain instance + * + * This method should not be invoked by client code! + * + * \param domainName the name of the MMS domain + * + * \return the new MmsDomain instance + */ +MmsDomain* +MmsDomain_create(char* domainName); + +char* +MmsDomain_getName(MmsDomain* self); + +/** + * Delete a MmsDomain instance + * + * This method should not be invoked by client code! + */ +void +MmsDomain_destroy(MmsDomain* self); + +/** + * \brief Add a new MMS Named Variable List (Data set) to a MmsDomain instance + * + * The passed MmsNamedVariableList instance will be handled by the MmsDomain instance + * and will be destroyed if the MmsDomain_destroy function on this MmsDomain instance + * is called. + * + * \param self instance of MmsDomain to operate on + * \param variableList new named variable list that will be added to this MmsDomain + * + * \return true if operation was successful. + */ +bool +MmsDomain_addNamedVariableList(MmsDomain* self, MmsNamedVariableList variableList); + +/** + * \brief Delete a MMS Named Variable List from this MmsDomain instance + * + * A call to this function will also destroy the MmsNamedVariableList instance. + * + * \param self instance of MmsDomain to operate on + * \param variableListName the name of the variable list to delete. + * + */ +void +MmsDomain_deleteNamedVariableList(MmsDomain* self, char* variableListName); + +MmsNamedVariableList +MmsDomain_getNamedVariableList(MmsDomain* self, char* variableListName); + +LinkedList +MmsDomain_getNamedVariableLists(MmsDomain* self); + +LinkedList +MmsDomain_getNamedVariableListValues(MmsDomain* self, char* variableListName); + +LinkedList +MmsDomain_createNamedVariableListValues(MmsDomain* self, char* variableListName); + +/** + * \brief Get the MmsTypeSpecification instance of a MMS named variable + * + * \param self instance of MmsDomain to operate on + * \param nameId name of the named variable + * + * \return MmsTypeSpecification instance of the named variable + */ +MmsVariableSpecification* +MmsDomain_getNamedVariable(MmsDomain* self, char* nameId); + +/** + * \brief Create a new MmsDevice instance. + * + * MmsDevice objects are the root objects of the address space of an MMS server. + * + * An MmsDevice object can contain one or more MmsDomain instances. + * + * \param deviceName the name of the MMS device or NULL if the device has no name. + * + * \return the new MmsDevice instance + */ +MmsDevice* +MmsDevice_create(char* deviceName); + +/** + * \brief Delete the MmsDevice instance + */ +void +MmsDevice_destroy(MmsDevice* self); + +/** + * \brief Get the MmsDomain object with the specified MMS domain name. + * + * \param deviceName the name of the MMS device or NULL if the device has no name. + * + * \return the new MmsDevice instance + */ +MmsDomain* +MmsDevice_getDomain(MmsDevice* self, char* domainId); + +/** + * \brief Get the MmsTypeSpecification instance of a MMS named variable of VMD scope + * + * \param self instance of MmsDevice to operate on + * \param variableName name of the named variable + * + * \return MmsTypeSpecification instance of the named variable + */ +MmsVariableSpecification* +MmsDevice_getNamedVariable(MmsDevice* self, char* variableName); + +LinkedList +MmsDevice_getNamedVariableLists(MmsDevice* self); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_DEVICE_MODEL_H_ */ diff --git a/src/mms/inc/mms_named_variable_list.h b/src/mms/inc/mms_named_variable_list.h new file mode 100644 index 0000000..15e7d16 --- /dev/null +++ b/src/mms/inc/mms_named_variable_list.h @@ -0,0 +1,85 @@ +/* + * mms_named_variable_list.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_NAMED_VARIABLE_LIST_H_ +#define MMS_NAMED_VARIABLE_LIST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup mms_server_api_group + * @{ + */ + +#include "libiec61850_common_api.h" +#include "linked_list.h" +#include "mms_common.h" + +struct sMmsNamedVariableList { + bool deletable; + MmsDomain* domain; + char* name; + LinkedList listOfVariables; +}; + +MmsNamedVariableListEntry +MmsNamedVariableListEntry_create(MmsAccessSpecifier accessSpecifier); + +void +MmsNamedVariableListEntry_destroy(MmsNamedVariableListEntry self); + +MmsDomain* +MmsNamedVariableListEntry_getDomain(MmsNamedVariableListEntry self); + +char* +MmsNamedVariableListEntry_getVariableName(MmsNamedVariableListEntry self); + +MmsNamedVariableList +MmsNamedVariableList_create(MmsDomain* domain, char* name, bool deletable); + +char* +MmsNamedVariableList_getName(MmsNamedVariableList self); + +MmsDomain* +MmsNamedVariableList_getDomain(MmsNamedVariableList self); + +bool +MmsNamedVariableList_isDeletable(MmsNamedVariableList self); + +void +MmsNamedVariableList_addVariable(MmsNamedVariableList self, MmsNamedVariableListEntry variable); + +LinkedList +MmsNamedVariableList_getVariableList(MmsNamedVariableList self); + +void +MmsNamedVariableList_destroy(MmsNamedVariableList self); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_NAMED_VARIABLE_LIST_H_ */ diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h new file mode 100644 index 0000000..da2035b --- /dev/null +++ b/src/mms/inc/mms_server.h @@ -0,0 +1,345 @@ +/* + * mms_server.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_SERVER_H_ +#define MMS_SERVER_H_ + +/** \addtogroup mms_server_api_group + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mms_device_model.h" +#include "mms_value.h" +#include "iso_server.h" + +typedef enum { + MMS_SERVER_NEW_CONNECTION, MMS_SERVER_CONNECTION_CLOSED +} MmsServerEvent; + +typedef struct sMmsServer* MmsServer; + +typedef struct sMmsServerConnection* MmsServerConnection; + +typedef enum { + MMS_DOMAIN_SPECIFIC, + MMS_ASSOCIATION_SPECIFIC, + MMS_VMD_SPECIFIC +} MmsVariableListType; + +typedef MmsValue* (*MmsReadVariableHandler)(void* parameter, MmsDomain* domain, + char* variableId, MmsServerConnection connection); + +typedef MmsDataAccessError (*MmsReadAccessHandler) (void* parameter, MmsDomain* domain, + char* variableId, MmsServerConnection connection); + +typedef MmsDataAccessError (*MmsWriteVariableHandler)(void* parameter, + MmsDomain* domain, char* variableId, MmsValue* value, + MmsServerConnection connection); + +typedef void (*MmsConnectionHandler)(void* parameter, + MmsServerConnection connection, MmsServerEvent event); + +MmsServer +MmsServer_create(IsoServer isoServer, MmsDevice* device); + +void +MmsServer_destroy(MmsServer self); + +void +MmsServer_installReadHandler(MmsServer self, MmsReadVariableHandler, + void* parameter); + +void +MmsServer_installReadAccessHandler(MmsServer self, MmsReadAccessHandler, void* parameter); + +void +MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler, + void* parameter); + +/** + * A connection handler will be invoked whenever a new client connection is opened or closed + */ +void +MmsServer_installConnectionHandler(MmsServer self, MmsConnectionHandler, + void* parameter); + +void +MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter); + +MmsDevice* +MmsServer_getDevice(MmsServer self); + +MmsValue* +MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, char* itemId); + +bool +MmsServer_isLocked(MmsServer self); + +/** + * \brief callback handler that is called whenever a named variable list changes + * + * \param parameter a user provided parameter + * \param create if true the the request if a request to create a new variable list, false is a delete request + * \param listType the type (scope) of the named variable list (either domain, association or VMD specific) + * \param domain the MMS domain the list is belonging to (is NULL for association or VMD specific lists!) + * \param listName the name + * \param connection client connection that requests the creation of deletion of the variable list + * + * \return MMS_ERROR_NONE if the request is accepted, otherwise the MmsError value that has to be sent back to the client + */ +typedef MmsError (*MmsNamedVariableListChangedHandler)(void* parameter, bool create, MmsVariableListType listType, MmsDomain* domain, + char* listName, MmsServerConnection connection); + +/** + * \brief Install callback handler that is called when a named variable list changes (is created or deleted) + * + * \param self the MmsServer instance to operate on + * \param handler the callback handler function + * \param parameter user provided parameter that is passed to the callback handler + */ +void +MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableListChangedHandler handler, void* parameter); + +/** + * \brief lock the cached server data model + * + * NOTE: This method should never be called inside of a library callback function. In the context of + * a library callback the data model is always already locked! Calling this function inside of a + * library callback may lead to a deadlock condition. + * + * \param self the MmsServer instance to operate on + */ +void +MmsServer_lockModel(MmsServer self); + +/** + * \brief unlock the cached server data model + * + * NOTE: This method should never be called inside of a library callback function. In the context of + * a library callback the data model is always already locked! + * + * \param self the MmsServer instance to operate on + */ +void +MmsServer_unlockModel(MmsServer self); + +void +MmsServer_insertIntoCache(MmsServer self, MmsDomain* domain, char* itemId, + MmsValue* value); + +void +MmsServer_setDevice(MmsServer self, MmsDevice* device); + +/*************************************************** + * Functions for multi-threaded operation mode + ***************************************************/ + +/** + * \brief Start a new server thread and listen for incoming connections + * + * \param self the MmsServer instance to operate on + * \param tcpPort the TCP port the server is listening on. + */ +void +MmsServer_startListening(MmsServer self, int tcpPort); + +/** + * \brief Stop server thread an all open connection threads + * + * \param self the MmsServer instance to operate on + */ +void +MmsServer_stopListening(MmsServer self); + +/*************************************************** + * Functions for threadless operation mode + ***************************************************/ + +/** + * \brief Start a new server in non-threaded operation mode + * + * \param self the MmsServer instance to operate on + * \param tcpPort the TCP port the server is listening on. + */ +void +MmsServer_startListeningThreadless(MmsServer self, int tcpPort); + +/** + * \brief Wait for the server to come ready in non-threaded operation mode + * + * \param self the MmsServer instance to operate on + * \param timeoutMs maximum number of milliseconds to wait + * \return 1 if the server is ready, 0 if not or -1 on error + */ +int +MmsServer_waitReady(MmsServer self, unsigned int timeoutMs); + +/** + * \brief Handle client connections (for non-threaded operation mode) + * + * This function is listening for new client connections and handles incoming + * requests for existing client connections. + * + * \param self the MmsServer instance to operate on + */ +void +MmsServer_handleIncomingMessages(MmsServer self); + +/** + * \brief Stop the server (for non-threaded operation mode) + * + * \param self the MmsServer instance to operate on + */ +void +MmsServer_stopListeningThreadless(MmsServer self); + + +/*************************************************** + * Functions for MMS identify service + ***************************************************/ + +/** + * \brief set the values that the server will give as response for an MMS identify request + * + * With this function the VMD identity attributes can be set programmatically. If not set by this + * function the default values form stack_config.h are used. + * + * \param self the MmsServer instance to operate on + * \param vendorName the vendor name attribute of the VMD + * \param modelName the model name attribute of the VMD + * \param revision the revision attribute of the VMD + */ +void +MmsServer_setServerIdentity(MmsServer self, char* vendorName, char* modelName, char* revision); + +/** + * \brief get the vendor name attribute of the VMD identity + * + * \param self the MmsServer instance to operate on + * \return the vendor name attribute of the VMD as C string + */ +char* +MmsServer_getVendorName(MmsServer self); + +/** + * \brief get the model name attribute of the VMD identity + * + * \param self the MmsServer instance to operate on + * \return the model name attribute of the VMD as C string + */ +char* +MmsServer_getModelName(MmsServer self); + +/** + * \brief get the revision attribute of the VMD identity + * + * \param self the MmsServer instance to operate on + * \return the revision attribute of the VMD as C string + */ +char* +MmsServer_getRevision(MmsServer self); + +/*************************************************** + * Functions for MMS status service + ***************************************************/ + +#define MMS_LOGICAL_STATE_STATE_CHANGES_ALLOWED 0 +#define MMS_LOGICAL_STATE_NO_STATE_CHANGES_ALLOWED 1 +#define MMS_LOGICAL_STATE_LIMITED_SERVICES_PERMITTED 2 +#define MMS_LOGICAL_STATE_SUPPORT_SERVICES_ALLOWED 3 + +#define MMS_PHYSICAL_STATE_OPERATIONAL 0 +#define MMS_PHYSICAL_STATE_PARTIALLY_OPERATIONAL 1 +#define MMS_PHYSICAL_STATE_INOPERATIONAL 2 +#define MMS_PHYSICAL_STATE_NEEDS_COMMISSIONING 3 + +/** + * \brief User provided handler that is invoked on a MMS status request + * + * The extendedDerivation parameter indicates that the client requests the server to perform + * self diagnosis tests before answering the request. + * + * \param parameter is a user provided parameter + * \param mmsServer is the MmsServer instance + * \param connection is the MmsServerConnection instance that received the MMS status request + * \param extendedDerivation indicates if the request contains the extendedDerivation parameter + */ +typedef void (*MmsStatusRequestListener)(void* parameter, MmsServer mmsServer, MmsServerConnection connection, bool extendedDerivation); + +/** + * \brief set the VMD state values for the VMD status service + * + * \param self the MmsServer instance to operate on + * \param vmdLogicalStatus the logical status attribute of the VMD + * \param vmdPhysicalStatus the physical status attribute of the VMD + */ +void +MmsServer_setVMDStatus(MmsServer self, int vmdLogicalStatus, int vmdPhysicalStatus); + +/** + * \brief get the logical status attribute of the VMD + * + * \param self the MmsServer instance to operate on + */ +int +MmsServer_getVMDLogicalStatus(MmsServer self); + +/** + * \brief get the physical status attribute of the VMD + * + * \param self the MmsServer instance to operate on + */ +int +MmsServer_getVMDPhysicalStatus(MmsServer self); + +/** + * \brief set the MmsStatusRequestListener for this MmsServer + * + * With this function the API user can register a listener that is invoked whenever a + * MMS status request is received from a client. Inside of the handler the user can + * provide new status values with the MmsServer_setVMDStatus function. + * + * \param self the MmsServer instance to operate on + * \param listener the listener that is called when a MMS status request is received + * \param parameter a user provided parameter that is handed over to the listener + */ +void +MmsServer_setStatusRequestListener(MmsServer self, MmsStatusRequestListener listener, void* parameter); + +char* +MmsServerConnection_getClientAddress(MmsServerConnection self); + +IsoConnection +MmsServerConnection_getIsoConnection(MmsServerConnection self); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_SERVER_H_ */ diff --git a/src/mms/inc/mms_type_spec.h b/src/mms/inc/mms_type_spec.h new file mode 100644 index 0000000..d9db23f --- /dev/null +++ b/src/mms/inc/mms_type_spec.h @@ -0,0 +1,137 @@ +/* + * mms_type_spec.h + * + * MmsTypeSpecfication objects are used to describe simple and complex MMS types. + * Complex types are arrays or structures of simple and complex types. + * They also represent MMS NamedVariables. + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_TYPE_SPEC_H_ +#define MMS_TYPE_SPEC_H_ + +#include "mms_common.h" +#include "mms_types.h" +#include "linked_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup common_api_group + */ +/**@{*/ + +/** + * \defgroup MMS_VAR_SPEC MmsVariableSpecification data type specifications + */ +/**@{*/ + +/** + * \brief Delete MmsTypeSpecification object (recursive). + * + * \param self the MmsVariableSpecification instance + */ +void +MmsVariableSpecification_destroy(MmsVariableSpecification* self); + +/** + * \brief Get the corresponding child of value according to childId. + * + * This function assumes that value is the corresponding value of the MMS variable self. + * Given the relative name of a child of self this function returns the corresponding child + * of the value object. Note: the child name has to be provided in MMS mapping syntax (with + * "$" sign as separator between path name elements! + * + * \param self the MmsVariableSpecification instance + * \param value the MmsValue instance + * \param childId the relative MMS name to the child MMS variable (with "$" separators!) + * + */ +MmsValue* +MmsVariableSpecification_getChildValue(MmsVariableSpecification* self, MmsValue* value, const char* childId); + +/** + * \brief Get the child of self specified by its relative name + * + * \param self the MmsVariableSpecification instance + * \param nameId the relative MMS name to the child MMS variable (with "$" separators!) + * + * \return the variable specification of the child or NULL if not existing. + */ +MmsVariableSpecification* +MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* self, const char* nameId); + +/** + * \brief get the MMS type of the variable + * + * \param self the MmsVariableSpecification instance + * + * \return the MMS type of the variable + */ +MmsType +MmsVariableSpecification_getType(MmsVariableSpecification* self); + +/** + * \brief get the name of the variable + * + * Note: the return string is only valid as long as the MmsVariableSpecification + * instance exists! + * + * \param self the MmsVariableSpecification instance + * + * \return the name of the variable + */ +const char* +MmsVariableSpecification_getName(MmsVariableSpecification* self); + +LinkedList /* */ +MmsVariableSpecification_getStructureElements(MmsVariableSpecification* self); + +/** + * \brief returns the number of elements if the type is a complex type (structure, array) or the + * bit size of integers, unsigned integers, floats, bit strings, visible and MMS strings and octet strings. + * + * \param self the MmsVariableSpecification object + * \return the number of elements or -1 if not applicable + */ +int +MmsVariableSpecification_getSize(MmsVariableSpecification* self); + +MmsVariableSpecification* +MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification* self, int index); + +MmsVariableSpecification* +MmsVariableSpecification_getArrayElementSpecification(MmsVariableSpecification* self); + +int +MmsVariableSpecification_getExponentWidth(MmsVariableSpecification* self); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_TYPE_SPEC_H_ */ diff --git a/src/mms/inc/mms_types.h b/src/mms/inc/mms_types.h new file mode 100644 index 0000000..61fdab4 --- /dev/null +++ b/src/mms/inc/mms_types.h @@ -0,0 +1,81 @@ +/* + * mms_types.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_TYPES_H_ +#define MMS_TYPES_H_ + +#include "libiec61850_common_api.h" + +typedef enum ATTRIBUTE_PACKED { + MMS_VALUE_NO_RESPONSE, + MMS_VALUE_OK, + MMS_VALUE_ACCESS_DENIED, + MMS_VALUE_VALUE_INVALID, + MMS_VALUE_TEMPORARILY_UNAVAILABLE, + MMS_VALUE_OBJECT_ACCESS_UNSUPPORTED +} MmsValueIndication; + +/** + * \addtogroup MMS_VAR_SPEC + */ +/**@{*/ + +/** + * Type definition for MMS Named Variables + */ +typedef struct sMmsVariableSpecification MmsVariableSpecification; + +/**@}*/ + +struct ATTRIBUTE_PACKED sMmsVariableSpecification { + MmsType type; + char* name; + union uMmsTypeSpecification + { + struct sMmsArray { + int elementCount; /* number of array elements */ + MmsVariableSpecification* elementTypeSpec; + } array; + struct sMmsStructure { + int elementCount; + MmsVariableSpecification** elements; + } structure; + int boolean; /* dummy - not required */ + int integer; /* size of integer in bits */ + int unsignedInteger; /* size of integer in bits */ + struct sMmsFloat + { + uint8_t exponentWidth; + uint8_t formatWidth; + } floatingpoint; + int bitString; /* Number of bits in bitstring */ + int octetString; /* Number of octets in octet string */ + int visibleString; /* Maximum size of string */ + int mmsString; + int utctime; /* dummy - not required */ + int binaryTime; /* size: either 4 or 6 */ + } typeSpec; +}; + + +#endif /* MMS_TYPES_H_ */ diff --git a/src/mms/inc/mms_value.h b/src/mms/inc/mms_value.h new file mode 100644 index 0000000..0a8aeb8 --- /dev/null +++ b/src/mms/inc/mms_value.h @@ -0,0 +1,949 @@ +/* + * mms_value.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_VALUE_H_ +#define MMS_VALUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libiec61850_common_api.h" +#include "mms_common.h" +#include "mms_types.h" +#include "ber_integer.h" + +/** + * \defgroup common_api_group libIEC61850 API common parts + */ +/**@{*/ + +/** + * \defgroup MMS_VALUE MmsValue data type definition and handling functions + */ +/**@{*/ + + +typedef enum { + DATA_ACCESS_ERROR_NO_RESPONSE = -2, /* for server internal purposes only! */ + DATA_ACCESS_ERROR_SUCCESS = -1, + DATA_ACCESS_ERROR_OBJECT_INVALIDATED = 0, + DATA_ACCESS_ERROR_HARDWARE_FAULT = 1, + DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE = 2, + DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED = 3, + DATA_ACCESS_ERROR_OBJECT_UNDEFINED = 4, + DATA_ACCESS_ERROR_INVALID_ADDRESS = 5, + DATA_ACCESS_ERROR_TYPE_UNSUPPORTED = 6, + DATA_ACCESS_ERROR_TYPE_INCONSISTENT = 7, + DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT = 8, + DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED = 9, + DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT = 10, + DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID = 11, + DATA_ACCESS_ERROR_UNKNOWN = 12 +} MmsDataAccessError; + +/** + * MmsValue - complex value type for MMS Client API + */ +typedef struct sMmsValue MmsValue; + +/************************************************************************************* + * Array functions + *************************************************************************************/ + +/** + * \brief Create an Array and initialize elements with default values. + * + * \param elementType type description for the elements the new array + * \param size the size of the new array + * + * \return a newly created array instance + */ +MmsValue* +MmsValue_createArray(MmsVariableSpecification* elementType, int size); + +/** + * \brief Get the size of an array. + * + * \param self MmsValue instance to operate on. Has to be of type MMS_ARRAY. + * + * \return the size of the array + */ +uint32_t +MmsValue_getArraySize(const MmsValue* self); + +/** + * \brief Get an element of an array or structure. + * + * \param self MmsValue instance to operate on. Has to be of type MMS_ARRAY or MMS_STRUCTURE. + * \param index ndex of the requested array or structure element + * + * \return the element object + */ +MmsValue* +MmsValue_getElement(MmsValue* array, int index); + +/** + * \brief Create an emtpy array. + * + * \param size the size of the new array + * + * \return a newly created empty array instance + */ +MmsValue* +MmsValue_createEmptyArray(int size); + +/** + * \brief Set an element of a complex type + * + * NOTE: If the element already exists it will simply be replaced by the provided new value. + * The caller is responsible to free the replaced value. + * + * \param complexValue MmsValue instance to operate on. Has to be of a type MMS_STRUCTURE or MMS_ARRAY + * \param the index of the element to set/replace + * \param elementValue the (new) value of the element + */ +void +MmsValue_setElement(MmsValue* complexValue, int index, MmsValue* elementValue); + + +/************************************************************************************* + * Basic type functions + *************************************************************************************/ + +MmsDataAccessError +MmsValue_getDataAccessError(const MmsValue* self); + +/** + * \brief Get the int64_t value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER or MMS_UNSIGNED + * + * \return signed 64 bit integer + */ +int64_t +MmsValue_toInt64(const MmsValue* self); + +/** + * \brief Get the int32_t value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER or MMS_UNSIGNED + * + * \return signed 32 bit integer + */ +int32_t +MmsValue_toInt32(const MmsValue* value); + +/** + * \brief Get the uint32_t value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER or MMS_UNSIGNED + * + * \return unsigned 32 bit integer + */ +uint32_t +MmsValue_toUint32(const MmsValue* value); + +/** + * \brief Get the double value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of type MMS_FLOAT. + * + * \return 64 bit floating point value + */ +double +MmsValue_toDouble(const MmsValue* self); + +/** + * \brief Get the float value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of type MMS_FLOAT. + * + * \return 32 bit floating point value + */ +float +MmsValue_toFloat(const MmsValue* self); + +/** + * \brief Get the unix timestamp of a MmsValue object of type MMS_UTCTIME. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTC_TIME. + * + * \return unix timestamp of the MMS_UTCTIME variable. + */ +uint32_t +MmsValue_toUnixTimestamp(const MmsValue* self); + +/** + * \brief Set the float value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_FLOAT. + */ +void +MmsValue_setFloat(MmsValue* self, float newFloatValue); + +/** + * \brief Set the double value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_FLOAT. + */ +void +MmsValue_setDouble(MmsValue* self, double newFloatValue); + +/** + * \brief Set the Int8 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER. + * \param integer the new value to set + */ +void +MmsValue_setInt8(MmsValue* value, int8_t integer); + +/** + * \brief Set the Int16 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER. + * \param integer the new value to set + */ +void +MmsValue_setInt16(MmsValue* value, int16_t integer); + +/** + * \brief Set the Int32 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER. + * \param integer the new value to set + */ +void +MmsValue_setInt32(MmsValue* self, int32_t integer); + +/** + * \brief Set the Int64 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_INTEGER. + * \param integer the new value to set + */ +void +MmsValue_setInt64(MmsValue* value, int64_t integer); + +/** + * \brief Set the UInt8 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UNSIGNED. + * \param integer the new value to set + */ +void +MmsValue_setUint8(MmsValue* value, uint8_t integer); + +/** + * \brief Set the UInt16 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UNSIGNED. + * \param integer the new value to set + */ +void +MmsValue_setUint16(MmsValue* value, uint16_t integer); + +/** + * \brief Set the UInt32 value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UNSIGNED. + * \param integer the new value to set + */ +void +MmsValue_setUint32(MmsValue* value, uint32_t integer); + + +/** + * \brief Set the bool value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BOOLEAN. + * \param boolValue a bool value + */ +void +MmsValue_setBoolean(MmsValue* value, bool boolValue); + +/** + * \brief Get the bool value of a MmsValue object. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BOOLEAN. + * \return the MmsValue value as bool value + */ +bool +MmsValue_getBoolean(const MmsValue* value); + +/** + * \brief Returns the value of an MMS_VISIBLE_STRING object as C string + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_VISIBLE_STRING or MMS_STRING. + * + * \returns the string value as 0 terminated C string + */ +const char* +MmsValue_toString(MmsValue* self); + +/** + * \brief Returns the (maximum) length of the string + * + * NOTE: this function return the amount of memory allocated for the string buffer - 1. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_VISIBLE_STRING or MMS_STRING. + */ +int +MmsValue_getStringSize(MmsValue* self); + +void +MmsValue_setVisibleString(MmsValue* self, const char* string); + + +/** + * \brief Set a single bit (set to one) of an MmsType object of type MMS_BITSTRING + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + * \param bitPos the position of the bit in the bit string. Starting with 0. The bit + * with position 0 is the first bit if the MmsValue instance is serialized. + * \param value the new value of the bit (true = 1 / false = 0) + */ +void +MmsValue_setBitStringBit(MmsValue* self, int bitPos, bool value); + +/** + * \brief Get the value of a single bit (set to one) of an MmsType object of type MMS_BITSTRING + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + * \param bitPos the position of the bit in the bit string. Starting with 0. The bit + * with position 0 is the first bit if the MmsValue instance is serialized. + * \return the value of the bit (true = 1 / false = 0) + */ +bool +MmsValue_getBitStringBit(const MmsValue* self, int bitPos); + +/** + * \brief Delete all bits (set to zero) of an MmsType object of type MMS_BITSTRING + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +void +MmsValue_deleteAllBitStringBits(MmsValue* self); + + +/** + * \brief Get the size of a bit string in bits. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +int +MmsValue_getBitStringSize(const MmsValue* self); + +/** + * \brief Get the number of bytes required by this bitString + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +int +MmsValue_getBitStringByteSize(const MmsValue* self); + +/** + * \brief Count the number of set bits in a bit string. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +int +MmsValue_getNumberOfSetBits(const MmsValue* self); + +/** + * Set all bits (set to one) of an MmsType object of type MMS_BITSTRING + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +void +MmsValue_setAllBitStringBits(MmsValue* self); + +/** + * \brief Convert a bit string to an unsigned integer + * + * This function assumes that the first bit in the bit string is the + * least significant bit (little endian bit order). + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +uint32_t +MmsValue_getBitStringAsInteger(const MmsValue* self); + +/** + * \brief Convert an unsigned integer to a bit string + * + * The integer representation in the bit string assumes the first bit is the + * least significant bit (little endian bit order). + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + * \param intValue the integer value that is used to set the bit string + */ +void +MmsValue_setBitStringFromInteger(MmsValue* self, uint32_t intValue); + +/** + * \brief Convert a bit string to an unsigned integer (big endian bit order) + * + * This function assumes that the first bit in the bit string is the + * most significant bit (big endian bit order). + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + */ +uint32_t +MmsValue_getBitStringAsIntegerBigEndian(const MmsValue* self); + +/** + * \brief Convert an unsigned integer to a bit string (big endian bit order) + * + * The integer representation in the bit string assumes the first bit is the + * most significant bit (big endian bit order). + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BITSTRING. + * \param intValue the integer value that is used to set the bit string + */ +void +MmsValue_setBitStringFromIntegerBigEndian(MmsValue* self, uint32_t intValue); + +/** + * \brief Update an MmsValue object of UtcTime type with a timestamp in s + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BOOLEAN. + * \param timeval the new value in seconds since epoch (1970/01/01 00:00 UTC) + */ +MmsValue* +MmsValue_setUtcTime(MmsValue* self, uint32_t timeval); + +/** + * \brief Update an MmsValue object of type MMS_UTCTIME with a millisecond time. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * \param timeval the new value in milliseconds since epoch (1970/01/01 00:00 UTC) + */ +MmsValue* +MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval); + +/** + * \brief Update an MmsValue object of type MMS_UTCTIME with a buffer containing a BER encoded UTCTime. + * + * The buffer must have a size of 8 bytes! + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * \param buffer buffer containing the encoded UTCTime. + */ +void +MmsValue_setUtcTimeByBuffer(MmsValue* self, const uint8_t* buffer); + +/** + * \brief return the raw buffer containing the UTC time data + * + * Note: This will return the address of the raw byte buffer. The array length is 8 byte. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * + * \return the buffer containing the raw data + */ +uint8_t* +MmsValue_getUtcTimeBuffer(MmsValue* self); + +/** + * \brief Get a millisecond time value from an MmsValue object of MMS_UTCTIME type. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * + * \return the value in milliseconds since epoch (1970/01/01 00:00 UTC) + */ +uint64_t +MmsValue_getUtcTimeInMs(const MmsValue* value); + +/** + * \brief Get a millisecond time value and optional us part from an MmsValue object of MMS_UTCTIME type. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * \param usec a pointer to store the us (microsecond) value. + * + * \return the value in milliseconds since epoch (1970/01/01 00:00 UTC) + */ +uint64_t +MmsValue_getUtcTimeInMsWithUs(const MmsValue* self, uint32_t* usec); + +/** + * \brief set the TimeQuality byte of the UtcTime + * + * Meaning of the bits in the timeQuality byte: + * + * bit 7 = leapSecondsKnown + * bit 6 = clockFailure + * bit 5 = clockNotSynchronized + * bit 0-4 = subsecond time accuracy (number of significant bits of subsecond time) + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * + * \param timeQuality the byte representing the time quality + */ +void +MmsValue_setUtcTimeQuality(MmsValue* self, uint8_t timeQuality); + +/** + * \brief get the TimeQuality byte of the UtcTime + * + * Meaning of the bits in the timeQuality byte: + * + * bit 7 = leapSecondsKnown + * bit 6 = clockFailure + * bit 5 = clockNotSynchronized + * bit 0-4 = subsecond time accuracy (number of significant bits of subsecond time) + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * + * \return the byte representing the time quality + */ +uint8_t +MmsValue_getUtcTimeQuality(const MmsValue* self); + +/** + * \brief Update an MmsValue object of type MMS_BINARYTIME with a millisecond time. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME. + * \param timeval the new value in milliseconds since epoch (1970/01/01 00:00 UTC) + */ +void +MmsValue_setBinaryTime(MmsValue* self, uint64_t timestamp); + +/** + * \brief Get a millisecond time value from an MmsValue object of type MMS_BINARYTIME. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_BINARYTIME. + * + * \return the value in milliseconds since epoch (1970/01/01 00:00 UTC) + */ +uint64_t +MmsValue_getBinaryTimeAsUtcMs(const MmsValue* self); + +/** + * \brief Set the value of an MmsValue object of type MMS_OCTET_STRING. + * + * This method will copy the provided buffer to the internal buffer of the + * MmsValue instance. This will only happen if the internal buffer size is large + * enough for the new value. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_OCTET_STRING. + * \param buf the buffer that contains the new value + * \param size the size of the buffer that contains the new value + */ +void +MmsValue_setOctetString(MmsValue* self, uint8_t* buf, int size); + +/** + * \brief Returns the size in bytes of an MmsValue object of type MMS_OCTET_STRING. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_OCTET_STRING. + * + * \return size in bytes + */ +uint16_t +MmsValue_getOctetStringSize(const MmsValue* self); + +/** + * \brief Returns the maximum size in bytes of an MmsValue object of type MMS_OCTET_STRING. + * + * Returns the maximum size if bytes of the MmsValue object of type MMS_OCTET_STRING. This + * is the size of the internally allocated buffer to hold the octet string data. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_OCTET_STRING. + * + * \return maximum size in bytes + */ +uint16_t +MmsValue_getOctetStringMaxSize(MmsValue* self); + +/** + * \brief Returns the reference to the internally hold buffer of an MmsValue object of type MMS_OCTET_STRING. + * + * \param self MmsValue instance to operate on. Has to be of a type MMS_OCTET_STRING. + * + * \return reference to the buffer + */ +uint8_t* +MmsValue_getOctetStringBuffer(MmsValue* self); + +/** + * \brief Update the value of an MmsValue instance by the value of another MmsValue instance. + * + * Both instances should be of same time. E.g. is self is of type MMS_INTEGER then + * source has also to be of type MMS_INTEGER. Otherwise the call will have no effect. + * + * \param self MmsValue instance to operate on. + * \param source MmsValue used as source for the update. Has to be of same type as self + * + * \return indicates if the update has been successful (false if not) + */ +bool +MmsValue_update(MmsValue* self, const MmsValue* source); + +/** + * \brief Check if two instances of MmsValue have the same value. + * + * Both instances should be of same type. E.g. is self is of type MMS_INTEGER then + * source has also to be of type MMS_INTEGER. Otherwise the call will return false. + * + * \param self MmsValue instance to operate on. + * \param otherValue MmsValue that is used to test + * + * \return true if both instances are of the same type and have the same value + */ +bool +MmsValue_equals(const MmsValue* self, const MmsValue* otherValue); + +/** + * \brief Check if two (complex) instances of MmsValue have the same type. + * + * This function will test if the two values are of the same type. The function + * will return true only if all child instances in the MmsValue instance tree are + * also of equal type. + * + * \param self MmsValue instance to operate on. + * \param otherValue MmsValue that is used to test + * + * \return true if both instances and all their children are of the same type. + */ +bool +MmsValue_equalTypes(const MmsValue* self, const MmsValue* otherValue); + +/************************************************************************************* + * Constructors and destructors + *************************************************************************************/ + + +MmsValue* +MmsValue_newDataAccessError(MmsDataAccessError accessError); + +MmsValue* +MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger); + +MmsValue* +MmsValue_newUnsignedFromBerInteger(Asn1PrimitiveValue* berInteger); + +MmsValue* +MmsValue_newInteger(int size); + +MmsValue* +MmsValue_newUnsigned(int size); + +MmsValue* +MmsValue_newBoolean(bool boolean); + +/** + * \brief Create a new MmsValue instance of type MMS_BITSTRING. + * + * \param bitSize the size of the bit string in bit + * + * \return new MmsValue instance of type MMS_BITSTRING + */ +MmsValue* +MmsValue_newBitString(int bitSize); + +MmsValue* +MmsValue_newOctetString(int size, int maxSize); + +MmsValue* +MmsValue_newStructure(const MmsVariableSpecification* typeSpec); + +MmsValue* +MmsValue_createEmptyStructure(int size); + +MmsValue* +MmsValue_newDefaultValue(const MmsVariableSpecification* typeSpec); + +MmsValue* +MmsValue_newIntegerFromInt8(int8_t integer); + +MmsValue* +MmsValue_newIntegerFromInt16(int16_t integer); + +MmsValue* +MmsValue_newIntegerFromInt32(int32_t integer); + +MmsValue* +MmsValue_newIntegerFromInt64(int64_t integer); + +MmsValue* +MmsValue_newUnsignedFromUint32(uint32_t integer); + +MmsValue* +MmsValue_newFloat(float variable); + +MmsValue* +MmsValue_newDouble(double variable); + +/** + * \brief Create a (deep) copy of an MmsValue instance + * + * This operation will allocate dynamic memory. It is up to the caller to + * free this memory by calling MmsValue_delete() later. + * + * \param self the MmsValue instance that will be cloned + * + * \return an MmsValue instance that is an exact copy of the given instance. + */ +MmsValue* +MmsValue_clone(const MmsValue* self); + +/** + * \brief Create a (deep) copy of an MmsValue instance in a user provided buffer + * + * This operation copies the give MmsValue instance to a user provided buffer. + * + * \param self the MmsValue instance that will be cloned + * \param destinationAddress the start address of the user provided buffer + * + * \return a pointer to the position in the buffer just after the last byte written. + */ +uint8_t* +MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress); + +/** + * \brief Determine the required amount of bytes by a clone. + * + * This function is intended to be used to determine the buffer size of a clone operation + * (MmsValue_cloneToBuffer) in advance. + * + * \param self the MmsValue instance + * + * \return the number of bytes required by a clone + */ +int +MmsValue_getSizeInMemory(const MmsValue* self); + +/** + * \brief Delete an MmsValue instance. + * + * This operation frees all dynamically allocated memory of the MmsValue instance. + * If the instance is of type MMS_STRUCTURE or MMS_ARRAY all child elements will + * be deleted too. + * + * \param self the MmsValue instance to be deleted. + */ +void +MmsValue_delete(MmsValue* self); + +/** + * \brief Delete an MmsValue instance. + * + * This operation frees all dynamically allocated memory of the MmsValue instance. + * If the instance is of type MMS_STRUCTURE or MMS_ARRAY all child elements will + * be deleted too. + * + * NOTE: this functions only frees the instance if deleteValue field = 0! + * + * + * \param self the MmsValue instance to be deleted. + */ +void +MmsValue_deleteConditional(MmsValue* value); + +/** + * \brief Delete an MmsValue instance if the provided pointer is not NULL + * + * This operation frees all dynamically allocated memory of the MmsValue instance. + * If the instance is of type MMS_STRUCTURE or MMS_ARRAY all child elements will + * be deleted too. + * + * \param self the MmsValue instance to be deleted. + */ +void +MmsValue_deleteIfNotNull(MmsValue* value); + +/** + * \brief Create a new MmsValue instance of type MMS_VISIBLE_STRING. + * + * This function will allocate as much memory as required to hold the string and sets the maximum size of + * the string to this size. + * + * \param string a text string that should be the value of the new instance of NULL for an empty string. + * + * \return new MmsValue instance of type MMS_VISIBLE_STRING + */ +MmsValue* +MmsValue_newVisibleString(const char* string); + +/** + * \brief Create a new MmsValue instance of type MMS_VISIBLE_STRING. + * + * This function will create a new empty MmsValue string object. The maximum size of the string is set + * according to the size parameter. The function allocates as much memory as is required to hold a string + * of the maximum size. + * + * \param size the new maximum size of the string. + * + * \return new MmsValue instance of type MMS_VISIBLE_STRING + */ +MmsValue* +MmsValue_newVisibleStringWithSize(int size); + +/** + * \brief Create a new MmsValue instance of type MMS_STRING. + * + * This function will create a new empty MmsValue string object. The maximum size of the string is set + * according to the size parameter. The function allocates as much memory as is required to hold a string + * of the maximum size. + * + * \param size the new maximum size of the string. + * + * \return new MmsValue instance of type MMS_STRING + */ +MmsValue* +MmsValue_newMmsStringWithSize(int size); + +/** + * \brief Create a new MmsValue instance of type MMS_BINARYTIME. + * + * If the timeOfDay parameter is set to true then the resulting + * MMS_BINARYTIME object is only 4 octets long and includes only + * the seconds since midnight. Otherwise the MMS_BINARYTIME + * + * \param timeOfDay if true only the TimeOfDay value is included. + * + * \return new MmsValue instance of type MMS_BINARYTIME + */ +MmsValue* +MmsValue_newBinaryTime(bool timeOfDay); + +/** + * \brief Create a new MmsValue instance of type MMS_VISIBLE_STRING from the specified byte array + * + * \param byteArray the byte array containing the string data + * \param size the size of the byte array + * + * \return new MmsValue instance of type MMS_VISIBLE_STRING + */ +MmsValue* +MmsValue_newVisibleStringFromByteArray(uint8_t* byteArray, int size); + +/** + * \brief Create a new MmsValue instance of type MMS_STRING from the specified byte array + * + * \param byteArray the byte array containing the string data + * \param size the size of the byte array + * + * \return new MmsValue instance of type MMS_STRING + */ +MmsValue* +MmsValue_newMmsStringFromByteArray(uint8_t* byteArray, int size); + +/** + * \brief Create a new MmsValue instance of type MMS_STRING. + * + * \param string a text string that should be the value of the new instance of NULL for an empty string. + * + * \return new MmsValue instance of type MMS_STRING + */ +MmsValue* +MmsValue_newMmsString(char* string); + +void +MmsValue_setMmsString(MmsValue* value, const char* string); + +/** + * \brief Create a new MmsValue instance of type MMS_UTCTIME. + * + * \param timeval time value as UNIX timestamp (seconds since epoch) + * + * \return new MmsValue instance of type MMS_UTCTIME + */ +MmsValue* +MmsValue_newUtcTime(uint32_t timeval); + +/** + * \brief Create a new MmsValue instance of type MMS_UTCTIME. + * + * \param timeval time value as millisecond timestamp (milliseconds since epoch) + * + * \return new MmsValue instance of type MMS_UTCTIME + */ +MmsValue* +MmsValue_newUtcTimeByMsTime(uint64_t timeval); + + +void +MmsValue_setDeletable(MmsValue* self); + +void +MmsValue_setDeletableRecursive(MmsValue* value); + +/** + * \brief Check if the MmsValue instance has the deletable flag set. + * + * The deletable flag indicates if an libiec61850 API client should call the + * MmsValue_delete() method or not if the MmsValue instance was passed to the + * client by an API call or callback method. + * + * \param self the MmsValue instance + * + * \return 1 if deletable flag is set, otherwise 0 + */ +int +MmsValue_isDeletable(MmsValue* self); + +/** + * \brief Get the MmsType of an MmsValue instance + * + * \param self the MmsValue instance + */ +MmsType +MmsValue_getType(MmsValue* self); + +/** + * \brief Get a sub-element of a MMS_STRUCTURE value specified by a path name. + * + * \param self the MmsValue instance + * \param varSpec - type specification if the MMS_STRUCTURE value + * \param mmsPath - path (in MMS variable name syntax) to specify the sub element. + * + * \return the sub elements MmsValue instance or NULL if the element does not exist + */ +MmsValue* +MmsValue_getSubElement(MmsValue* self, MmsVariableSpecification* varSpec, char* mmsPath); + +/** + * \brief return the value type as a human readable string + * + * \param self the MmsValue instance + * + * \return the value type as a human readable string + */ +char* +MmsValue_getTypeString(MmsValue* self); + +char* +MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MMS_VALUE_H_ */ diff --git a/src/mms/inc_private/acse.h b/src/mms/inc_private/acse.h new file mode 100644 index 0000000..4282508 --- /dev/null +++ b/src/mms/inc_private/acse.h @@ -0,0 +1,101 @@ +/* + * acse.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "byte_buffer.h" +#include "buffer_chain.h" +#include "iso_connection_parameters.h" + +#ifndef ACSE_H_ +#define ACSE_H_ + +typedef enum +{ + idle, requestIndicated, connected +} AcseConnectionState; + +typedef enum +{ + ACSE_ERROR, + ACSE_ASSOCIATE, + ACSE_ASSOCIATE_FAILED, + ACSE_OK, + ACSE_ABORT, + ACSE_RELEASE_REQUEST, + ACSE_RELEASE_RESPONSE +} AcseIndication; + +typedef struct sAcseConnection +{ + AcseConnectionState state; + long nextReference; + uint8_t* userDataBuffer; + int userDataBufferSize; + AcseAuthenticationParameter authentication; + AcseAuthenticator authenticator; + void* authenticatorParameter; + void* securityToken; +} AcseConnection; + +#define ACSE_RESULT_ACCEPT 0 +#define ACSE_RESULT_REJECT_PERMANENT 1 +#define ACSE_RESULT_REJECT_TRANSIENT 2 + +void +AcseConnection_init(AcseConnection* self, AcseAuthenticator authenticator, void* parameter); + +void +AcseConnection_destroy(AcseConnection* self); + +AcseIndication +AcseConnection_parseMessage(AcseConnection* self, ByteBuffer* message); + +void +AcseConnection_createAssociateFailedMessage(AcseConnection* connection, BufferChain writeBuffer); + +void +AcseConnection_createAssociateResponseMessage( + AcseConnection* self, + uint8_t resultCode, + BufferChain acseWriteBuffer, + BufferChain payloadBuffer + ); + +void +AcseConnection_createAssociateRequestMessage(AcseConnection* self, + IsoConnectionParameters isoParameters, + BufferChain writeBuffer, + BufferChain payload, + AcseAuthenticationParameter authParameter); + +void +AcseConnection_createAbortMessage(AcseConnection* self, BufferChain writeBuffer, bool isProvider); + +void +AcseConnection_createReleaseRequestMessage(AcseConnection* self, BufferChain writeBuffer); + +void +AcseConnection_createReleaseResponseMessage(AcseConnection* self, BufferChain writeBuffer); + +#endif /* ACSE_H_ */ diff --git a/src/mms/inc_private/ber_decode.h b/src/mms/inc_private/ber_decode.h new file mode 100644 index 0000000..258f6a2 --- /dev/null +++ b/src/mms/inc_private/ber_decode.h @@ -0,0 +1,46 @@ +/* + * ber_decode.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef BER_DECODER_H_ +#define BER_DECODER_H_ + +#include "libiec61850_platform_includes.h" + +int +BerDecoder_decodeLength(uint8_t* buffer, int* length, int bufPos, int maxBufPos); +char* +BerDecoder_decodeString(uint8_t* buffer, int strlen, int bufPos, int maxBufPos); + +uint32_t +BerDecoder_decodeUint32(uint8_t* buffer, int intlen, int bufPos); + +float +BerDecoder_decodeFloat(uint8_t* buffer, int bufPos); + +double +BerDecoder_decodeDouble(uint8_t* buffer, int bufPos); + +bool +BerDecoder_decodeBoolean(uint8_t* buffer, int bufPos); + +#endif /* BER_DECODER_H_ */ diff --git a/src/mms/inc_private/ber_encoder.h b/src/mms/inc_private/ber_encoder.h new file mode 100644 index 0000000..343f54f --- /dev/null +++ b/src/mms/inc_private/ber_encoder.h @@ -0,0 +1,100 @@ +/* + * ber_encoder.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef BER_ENCODER_H_ +#define BER_ENCODER_H_ + +#include "libiec61850_platform_includes.h" +#include "asn1_ber_primitive_value.h" + +/* + * encoding functions + * + * Encoding to buffer starts at bufPos. The return value is the position in the buffer + * of the next entity to encode. + */ + +int +BerEncoder_encodeLength(uint32_t length, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeTL(uint8_t tag, uint32_t length, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeBoolean(uint8_t tag, bool value, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeStringWithTag(uint8_t tag, const char* string, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeOctetString(uint8_t tag, uint8_t* octetString, uint32_t octetStringSize, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeAsn1PrimitiveValue(uint8_t tag, Asn1PrimitiveValue* value, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeUInt32(uint32_t value, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeUInt32WithTL(uint8_t tag, uint32_t value, uint8_t* buffer, int bufPos); + +int +BerEncoder_encodeBitString(uint8_t tag, int bitStringSize, uint8_t* bitString, uint8_t* buffer, int bufPos); + +int +BerEncoder_determineEncodedBitStringSize(int bitStringSize); + +int +BerEncoder_encodeFloat(uint8_t* floatValue, uint8_t formatWidth, uint8_t exponentWidth, + uint8_t* buffer, int bufPos); + +/* + * functions to determine size of encoded entities. + */ + +int +BerEncoder_UInt32determineEncodedSize(uint32_t value); + +int +BerEncoder_determineLengthSize(uint32_t length); + +int +BerEncoder_determineEncodedStringSize(const char* string); + +int +BerEncoder_determineEncodedBitStringSize(int bitStringSize); + +/* + * helper functions + */ + +int +BerEncoder_encodeOIDToBuffer(const char* oidString, uint8_t* buffer, int maxBufLen); + +void +BerEncoder_revertByteOrder(uint8_t* octets, const int size); + +int +BerEncoder_compressInteger(uint8_t* integer, int originalSize); + +#endif /* BER_ENCODER_H_ */ diff --git a/src/mms/inc_private/cotp.h b/src/mms/inc_private/cotp.h new file mode 100644 index 0000000..273ef65 --- /dev/null +++ b/src/mms/inc_private/cotp.h @@ -0,0 +1,105 @@ +/* + * cotp.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef COTP_H_ +#define COTP_H_ + +#include "libiec61850_platform_includes.h" +#include "byte_buffer.h" +#include "buffer_chain.h" +#include "hal_socket.h" +#include "iso_connection_parameters.h" + +typedef struct { + TSelector tSelSrc; + TSelector tSelDst; + uint8_t tpduSize; +} CotpOptions; + +typedef struct { + int state; + int srcRef; + int dstRef; + int protocolClass; + Socket socket; + CotpOptions options; + bool isLastDataUnit; + ByteBuffer* payload; + ByteBuffer* writeBuffer; /* buffer to store TPKT packet to send */ + ByteBuffer* readBuffer; /* buffer to store received TPKT packet */ + uint16_t packetSize; /* size of the packet currently received */ +} CotpConnection; + +typedef enum { + COTP_OK, + COTP_ERROR, + COTP_CONNECT_INDICATION, + COTP_DATA_INDICATION, + COTP_DISCONNECT_INDICATION, + COTP_MORE_FRAGMENTS_FOLLOW +} CotpIndication; + +typedef enum { + TPKT_PACKET_COMPLETE = 0, + TPKT_WAITING = 1, + TPKT_ERROR = 2 +} TpktState; + +int /* in byte */ +CotpConnection_getTpduSize(CotpConnection* self); + +void +CotpConnection_setTpduSize(CotpConnection* self, int tpduSize /* in byte */); + +void +CotpConnection_init(CotpConnection* self, Socket socket, + ByteBuffer* payloadBuffer, ByteBuffer* readBuffer, ByteBuffer* writeBuffer); + +CotpIndication +CotpConnection_parseIncomingMessage(CotpConnection* self); + +void +CotpConnection_resetPayload(CotpConnection* self); + +TpktState +CotpConnection_readToTpktBuffer(CotpConnection* self); + +CotpIndication +CotpConnection_sendConnectionRequestMessage(CotpConnection* self, IsoConnectionParameters isoParameters); + +CotpIndication +CotpConnection_sendConnectionResponseMessage(CotpConnection* self); + +CotpIndication +CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload); + +ByteBuffer* +CotpConnection_getPayload(CotpConnection* self); + +int +CotpConnection_getSrcRef(CotpConnection* self); + +int +CotpConnection_getDstRef(CotpConnection* self); + +#endif /* COTP_H_ */ diff --git a/src/mms/inc_private/iso_client_connection.h b/src/mms/inc_private/iso_client_connection.h new file mode 100644 index 0000000..2c6fae3 --- /dev/null +++ b/src/mms/inc_private/iso_client_connection.h @@ -0,0 +1,103 @@ +/* + * iso_client_connection.h + * + * This is an internal interface of MMSClientConnection that connects MMS to the ISO client + * protocol stack. It is used as an abstraction layer to isolate the MMS code from the lower + * protocol layers. + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ISO_CLIENT_CONNECTION_H_ +#define ISO_CLIENT_CONNECTION_H_ + +#include "byte_buffer.h" +#include "iso_connection_parameters.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + ISO_IND_ASSOCIATION_SUCCESS, + ISO_IND_ASSOCIATION_FAILED, + ISO_IND_CLOSED, + ISO_IND_DATA +} IsoIndication; + +typedef void* +(*IsoIndicationCallback)(IsoIndication indication, void* param, ByteBuffer* payload); + +/** + * opaque data structure to represent an ISO client connection. + */ +typedef struct sIsoClientConnection* IsoClientConnection; + +IsoClientConnection +IsoClientConnection_create(IsoIndicationCallback callback, void* callbackParameter); + +void +IsoClientConnection_destroy(IsoClientConnection self); + +void +IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters params, + ByteBuffer* payload, uint32_t connectTimeoutInMs); + +void +IsoClientConnection_sendMessage(IsoClientConnection self, ByteBuffer* payload); + +void +IsoClientConnection_release(IsoClientConnection self); + +/** + * \brief Send ACSE abort message and wait until connection is closed by server or timeout occured + * + * \return true if abort has been successful, false indicates a timeout + */ +bool +IsoClientConnection_abort(IsoClientConnection self); + +void +IsoClientConnection_close(IsoClientConnection self); + +/** + * This function should be called by the API client (usually the MmsConnection) to reserve(allocate) + * the payload buffer. This is used to prevent concurrent access to the send buffer of the IsoClientConnection + */ +ByteBuffer* +IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self); + +/* + * The client should release the receive buffer in order for the IsoClientConnection to + * reuse the buffer! If this function is not called then the reception of messages is + * blocked! + */ +void +IsoClientConnection_releaseReceiveBuffer(IsoClientConnection self); + +void* +IsoClientConnection_getSecurityToken(IsoClientConnection self); + +#ifdef __cplusplus +} +#endif + +#endif /* ISO_CLIENT_CONNECTION_H_ */ diff --git a/src/mms/inc_private/iso_presentation.h b/src/mms/inc_private/iso_presentation.h new file mode 100644 index 0000000..ea3d153 --- /dev/null +++ b/src/mms/inc_private/iso_presentation.h @@ -0,0 +1,68 @@ +/* + * iso_presentation.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ISO_PRESENTATION_H_ +#define ISO_PRESENTATION_H_ + +#include "byte_buffer.h" +#include "buffer_chain.h" +#include "iso_connection_parameters.h" + +typedef struct { + uint32_t callingPresentationSelector; + uint32_t calledPresentationSelector; + uint8_t nextContextId; + uint8_t acseContextId; + uint8_t mmsContextId; + ByteBuffer nextPayload; +} IsoPresentation; + +void +IsoPresentation_init(IsoPresentation* session); + +int +IsoPresentation_parseUserData(IsoPresentation* session, ByteBuffer* message); + +int +IsoPresentation_parseConnect(IsoPresentation* session, ByteBuffer* message); + +void +IsoPresentation_createConnectPdu(IsoPresentation* self, IsoConnectionParameters parameters, + BufferChain buffer, BufferChain payload); + +void +IsoPresentation_createCpaMessage(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload); + +void +IsoPresentation_createUserData(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload); + +void +IsoPresentation_createUserDataACSE(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload); + +int +IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer); + +void +IsoPresentation_createAbortUserMessage(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload); + +#endif /* ISO_PRESENTATION_H_ */ diff --git a/src/mms/inc_private/iso_server_private.h b/src/mms/inc_private/iso_server_private.h new file mode 100644 index 0000000..f5c3669 --- /dev/null +++ b/src/mms/inc_private/iso_server_private.h @@ -0,0 +1,65 @@ +/* + * iso_server_private.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ISO_SERVER_PRIVATE_H_ +#define ISO_SERVER_PRIVATE_H_ + +#include "hal_socket.h" + +IsoConnection +IsoConnection_create(Socket socket, IsoServer isoServer); + +void +IsoConnection_destroy(IsoConnection self); + +void +IsoConnection_handleTcpConnection(IsoConnection self); + +void +IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles); + +void +private_IsoServer_increaseConnectionCounter(IsoServer self); + +void +private_IsoServer_decreaseConnectionCounter(IsoServer self); + +int +private_IsoServer_getConnectionCounter(IsoServer self); + +/** + * \brief User provided lock that will be called when higher layer (MMS) is called + */ +void +IsoServer_setUserLock(IsoServer self, Semaphore userLock); + +void +IsoServer_userLock(IsoServer self); + +void +IsoServer_userUnlock(IsoServer self); + +bool +IsoConnection_isRunning(IsoConnection self); + +#endif /* ISO_SERVER_PRIVATE_H_ */ diff --git a/src/mms/inc_private/iso_session.h b/src/mms/inc_private/iso_session.h new file mode 100644 index 0000000..2e53a54 --- /dev/null +++ b/src/mms/inc_private/iso_session.h @@ -0,0 +1,78 @@ +/* + * ise_session.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef ISE_SESSION_H_ +#define ISE_SESSION_H_ + +#include "byte_buffer.h" +#include "buffer_chain.h" +#include "iso_connection_parameters.h" + +typedef struct { + uint16_t callingSessionSelector; + uint16_t calledSessionSelector; + uint16_t sessionRequirement; + uint8_t protocolOptions; + ByteBuffer userData; +} IsoSession; + +typedef enum { + SESSION_OK, + SESSION_ERROR, + SESSION_CONNECT, + SESSION_GIVE_TOKEN, + SESSION_DATA, + SESSION_ABORT, + SESSION_FINISH, + SESSION_DISCONNECT, + SESSION_NOT_FINISHED +} IsoSessionIndication; + +void +IsoSession_init(IsoSession* session); + +ByteBuffer* +IsoSession_getUserData(IsoSession* session); + +void +IsoSession_createConnectSpdu(IsoSession* self, IsoConnectionParameters isoParameters, BufferChain buffer, BufferChain payload); + +IsoSessionIndication +IsoSession_parseMessage(IsoSession* session, ByteBuffer* message); + +void +IsoSession_createDataSpdu(IsoSession* session, BufferChain buffer, BufferChain payload); + +void +IsoSession_createAcceptSpdu(IsoSession* self, BufferChain buffer, BufferChain payload); + +void +IsoSession_createAbortSpdu(IsoSession* self, BufferChain buffer, BufferChain payload); + +void +IsoSession_createFinishSpdu(IsoSession* self, BufferChain buffer, BufferChain payload); + +void +IsoSession_createDisconnectSpdu(IsoSession* self, BufferChain buffer, BufferChain payload); + +#endif /* ISE_SESSION_H_ */ diff --git a/src/mms/inc_private/mms_access_result.h b/src/mms/inc_private/mms_access_result.h new file mode 100644 index 0000000..51df0f5 --- /dev/null +++ b/src/mms/inc_private/mms_access_result.h @@ -0,0 +1,32 @@ +/* + * mms_access_result.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_ACCESS_RESULT_H_ +#define MMS_ACCESS_RESULT_H_ + +#include "mms_value.h" + +int +mmsServer_encodeAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode); + +#endif /* MMS_ACCESS_RESULT_H_ */ diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h new file mode 100644 index 0000000..fc1ec8b --- /dev/null +++ b/src/mms/inc_private/mms_client_internal.h @@ -0,0 +1,259 @@ +/* + * mms_msg_internal.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_MSG_INTERNAL_H_ +#define MMS_MSG_INTERNAL_H_ + +#include "MmsPdu.h" +#include "linked_list.h" +#include "mms_client_connection.h" +#include "iso_client_connection.h" +#include "ber_decode.h" + +#include "hal_thread.h" + +#ifndef DEBUG_MMS_CLIENT +#define DEBUG_MMS_CLIENT 0 +#endif + +typedef enum { + MMS_STATE_CLOSED, + MMS_STATE_CONNECTING, + MMS_STATE_CONNECTED +} AssociationState; + +typedef enum { + MMS_CON_IDLE, + MMS_CON_WAITING, + MMS_CON_ASSOCIATION_FAILED, + MMS_CON_ASSOCIATED, + MMS_CON_RESPONSE_PENDING +} ConnectionState; + +#define CONCLUDE_STATE_CONNECTION_ACTIVE 0 +#define CONCLUDE_STATE_REQUESTED 1 +#define CONCLUDE_STATE_REJECTED 2 +#define CONCLUDE_STATE_ACCEPTED 3 + +/* private instance variables */ +struct sMmsConnection { + Semaphore lastInvokeIdLock; + uint32_t lastInvokeId; + + Semaphore lastResponseLock; + volatile uint32_t responseInvokeId; + ByteBuffer* lastResponse; + volatile uint32_t lastResponseBufPos; + volatile MmsError lastResponseError; + + Semaphore outstandingCallsLock; + uint32_t* outstandingCalls; + + uint32_t requestTimeout; + uint32_t connectTimeout; + + IsoClientConnection isoClient; + AssociationState associationState; + ConnectionState connectionState; + + MmsConnectionParameters parameters; + IsoConnectionParameters isoParameters; + + MmsInformationReportHandler reportHandler; + void* reportHandlerParameter; + + MmsConnectionLostHandler connectionLostHandler; + void* connectionLostHandlerParameter; + + /* state of an active connection conclude/release process */ + int concludeState; +}; + + +/** + * MMS Object class enumeration type + */ +typedef enum { + MMS_NAMED_VARIABLE, + MMS_NAMED_VARIABLE_LIST, + MMS_DOMAIN_NAMES +} MmsObjectClass; + +MmsValue* +mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSize, bool createArray); + +uint32_t +mmsClient_getInvokeId(ConfirmedResponsePdu_t* confirmedResponse); + +int +mmsClient_write_out(void *buffer, size_t size, void *app_key); + +int +mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* writeBuffer); + +MmsPdu_t* +mmsClient_createConfirmedRequestPdu(uint32_t invokeId); + +int +mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writeBuffer, const char* continueAfter); + +bool +mmsClient_parseGetNameListResponse(LinkedList* nameList, ByteBuffer* message, uint32_t* invokeId); + +int +mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, const char* domainName, + ByteBuffer* writeBuffer, MmsObjectClass objectClass, const char* continueAfter); + +MmsValue* +mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool createArray); + +int +mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* itemId, ByteBuffer* writeBuffer); + +int +mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* domainId, const char* itemId, + uint32_t index, uint32_t elementCount, ByteBuffer* writeBuffer); + +int +mmsClient_createReadRequestMultipleValues(uint32_t invokeId, const char* domainId, LinkedList /**/ items, + ByteBuffer* writeBuffer); + +int +mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, const char* domainId, const char* itemId, + ByteBuffer* writeBuffer, bool specWithResult); + +int +mmsClient_createReadAssociationSpecificNamedVariableListRequest( + uint32_t invokeId, + const char* itemId, + ByteBuffer* writeBuffer, + bool specWithResult); + +void +mmsClient_createGetNamedVariableListAttributesRequest(uint32_t invokeId, ByteBuffer* writeBuffer, + const char* domainId, const char* listNameId); + +void +mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(uint32_t invokeId, + ByteBuffer* writeBuffer, const char* listNameId); + +LinkedList +mmsClient_parseGetNamedVariableListAttributesResponse(ByteBuffer* message, uint32_t* invokeId, + bool* /*OUT*/ deletable); + +int +mmsClient_createGetVariableAccessAttributesRequest( + uint32_t invokeId, + const char* domainId, const char* itemId, + ByteBuffer* writeBuffer); + +MmsVariableSpecification* +mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t* invokeId); + +void +mmsClient_parseWriteResponse(ByteBuffer* message, int32_t bufPos, MmsError* mmsError); + +void +mmsClient_parseWriteMultipleItemsResponse(ByteBuffer* message, int32_t bufPos, MmsError* mmsError, + int itemCount, LinkedList* accessResults); + +int +mmsClient_createWriteRequest(uint32_t invokeId, const char* domainId, const char* itemId, MmsValue* value, + ByteBuffer* writeBuffer); + +int +mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, const char* domainId, LinkedList itemIds, LinkedList values, + ByteBuffer* writeBuffer); + +void +mmsClient_createDefineNamedVariableListRequest(uint32_t invokeId, ByteBuffer* writeBuffer, + const char* domainId, const char* listNameId, LinkedList /**/ listOfVariables, + bool associationSpecific); + +bool +mmsClient_parseDefineNamedVariableResponse(ByteBuffer* message, uint32_t* invokeId); + +void +mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeBuffer, + const char* domainId, const char* listNameId); + +bool +mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* invokeId); + +void +mmsClient_createDeleteAssociationSpecificNamedVariableListRequest( + long invokeId, + ByteBuffer* writeBuffer, + const char* listNameId); + +void +mmsClient_createIdentifyRequest(uint32_t invokeId, ByteBuffer* request); + +MmsServerIdentity* +mmsClient_parseIdentifyResponse(MmsConnection self); + +void +mmsClient_createStatusRequest(uint32_t invokeId, ByteBuffer* request, bool extendedDerivation); + +bool +mmsClient_parseStatusResponse(MmsConnection self, int* vmdLogicalStatus, int* vmdPhysicalStatus); + +void +mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName, uint32_t initialPosition); + +bool +mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified); + +void +mmsClient_createFileReadRequest(uint32_t invokeId, ByteBuffer* request, int32_t frsmId); + +bool +mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreFollows, MmsFileReadHandler handler, void* handlerParameter); + +void +mmsClient_createFileCloseRequest(uint32_t invokeId, ByteBuffer* request, int32_t frsmId); + +void +mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, const char* currentFileName, const char* newFileName); + +void +mmsClient_createFileDeleteRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName); + +void +mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, const char* fileSpecification, const char* continueAfter); + +bool +mmsClient_parseFileDirectoryResponse(MmsConnection self, MmsFileDirectoryHandler handler, void* handlerParameter, + bool* moreFollows); + +bool +mmsClient_parseInitiateResponse(MmsConnection self); + +int +mmsClient_createConcludeRequest(MmsConnection self, ByteBuffer* message); + +int +mmsClient_createMmsGetNameListRequestAssociationSpecific(long invokeId, ByteBuffer* writeBuffer, + const char* continueAfter); + +#endif /* MMS_MSG_INTERNAL_H_ */ diff --git a/src/mms/inc_private/mms_common_internal.h b/src/mms/inc_private/mms_common_internal.h new file mode 100644 index 0000000..3d49387 --- /dev/null +++ b/src/mms/inc_private/mms_common_internal.h @@ -0,0 +1,54 @@ +/* + * mms_common_internal.h + * + * Copyright 2013, 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_COMMON_INTERNAL_H_ +#define MMS_COMMON_INTERNAL_H_ + +#include "mms_value.h" +#include "MmsPdu.h" +#include "mms_access_result.h" +#include "conversions.h" + + + + +MmsValue* +mmsMsg_parseDataElement(Data_t* dataElement); + +Data_t* +mmsMsg_createBasicDataElement(MmsValue* value); + +AccessResult_t** +mmsMsg_createAccessResultsList(MmsPdu_t* mmsPdu, int resultsCount); + +char* +mmsMsg_createStringFromAsnIdentifier(Identifier_t identifier); + +void +mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, int bufSize); + +void +mmsMsg_deleteAccessResultList(AccessResult_t** accessResult, int variableCount); + +#endif /* MMS_COMMON_INTERNAL */ + diff --git a/src/mms/inc_private/mms_indication.h b/src/mms/inc_private/mms_indication.h new file mode 100644 index 0000000..b1a6724 --- /dev/null +++ b/src/mms/inc_private/mms_indication.h @@ -0,0 +1,41 @@ +/* + * mms_indication.h + * + * Copyright 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + * + * + * MMS client connection handling code for libiec61850. + * + * Handles a MMS client connection. + */ + +#ifndef MMS_INDICATION_H_ +#define MMS_INDICATION_H_ + +#define DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5 +#define DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5 +#define DEFAULT_DATA_STRUCTURE_NESTING_LEVEL 10 + +typedef enum +{ + MMS_ERROR, MMS_INITIATE, MMS_CONFIRMED_REQUEST, MMS_OK, MMS_CONCLUDE +} MmsIndication; + +#endif /* MMS_INDICATION_H_ */ diff --git a/src/mms/inc_private/mms_server_connection.h b/src/mms/inc_private/mms_server_connection.h new file mode 100644 index 0000000..8102bed --- /dev/null +++ b/src/mms/inc_private/mms_server_connection.h @@ -0,0 +1,103 @@ +/* + * mms_connection.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +/** + * A MmsServerConnection object is responsible for handling a client connection. + */ + +#ifndef MMS_SERVER_CONNECTION_H_ +#define MMS_SERVER_CONNECTION_H_ + +#include "libiec61850_platform_includes.h" + +#include "mms_common.h" +#include "mms_indication.h" +#include "mms_device_model.h" +#include "mms_value.h" +#include "mms_server.h" +#include "iso_server.h" +#include "linked_list.h" +#include "byte_buffer.h" + +MmsServerConnection +MmsServerConnection_init(MmsServerConnection connection, MmsServer server, IsoConnection isoCon); + +void +MmsServerConnection_destroy(MmsServerConnection connection); + +bool +MmsServerConnection_addNamedVariableList(MmsServerConnection self, MmsNamedVariableList variableList); + +MmsNamedVariableList +MmsServerConnection_getNamedVariableList(MmsServerConnection self, const char* variableListName); + +LinkedList +MmsServerConnection_getNamedVariableLists(MmsServerConnection self); + +void +MmsServerConnection_deleteNamedVariableList(MmsServerConnection self, char* listName); + +MmsIndication +MmsServerConnection_parseMessage(MmsServerConnection connection, ByteBuffer* message, ByteBuffer* response); + + +/** \brief send information report for a single VMD specific variable + * + * \param handlerMode send this message in the context of a stack callback handler + */ +void +MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConnection self, + char* itemId, MmsValue* value, bool handlerMode); + + +/** \brief send information report for a VMD specific named variable list + * + * \param handlerMode send this message in the context of a stack callback handler + */ +void /* send information report for a VMD specific named variable list */ +MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, char* itemId, LinkedList values + , bool handlerMode); + +/** \brief send information report for list of variables + * + * \param handlerMode send this message in the context of a stack callback handler + */ +void +MmsServerConnection_sendInformationReportListOfVariables( + MmsServerConnection self, + LinkedList /* MmsVariableAccessSpecification */ variableAccessDeclarations, + LinkedList /* MmsValue */ values, + bool handlerMode + ); + +void +MmsServerConnection_sendWriteResponse(MmsServerConnection self, uint32_t invokeId, MmsDataAccessError indication, + bool handlerMode); + + +uint32_t +MmsServerConnection_getLastInvokeId(MmsServerConnection self); + +#endif /* MMS_SERVER_CONNECTION_H_ */ + + diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h new file mode 100644 index 0000000..2e7f571 --- /dev/null +++ b/src/mms/inc_private/mms_server_internal.h @@ -0,0 +1,296 @@ +/* + * mms_server_internal.h + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_SERVER_INTERNAL_H_ +#define MMS_SERVER_INTERNAL_H_ + +#include "libiec61850_platform_includes.h" + +#include +#include "mms_common.h" +#include "mms_indication.h" +#include "mms_server_connection.h" +#include "mms_device_model.h" +#include "mms_common_internal.h" +#include "stack_config.h" +#include "mms_server.h" + + +#include "byte_buffer.h" +#include "string_utilities.h" +#include "map.h" +#include "hal_thread.h" + +#include "ber_encoder.h" +#include "ber_decode.h" + +#ifndef DEBUG_MMS_SERVER +#define DEBUG_MMS_SERVER 0 +#endif + +#ifndef MMS_STATUS_SERVICE +#define MMS_STATUS_SERVICE 1 +#endif + +#ifndef MMS_IDENTIFY_SERVICE +#define MMS_IDENTIFY_SERVICE 1 +#endif + +#ifndef MMS_FILE_SERVICE +#define MMS_FILE_SERVICE 1 +#endif + +struct sMmsServer { + IsoServer isoServer; + MmsDevice* device; + + MmsReadVariableHandler readHandler; + void* readHandlerParameter; + + MmsReadAccessHandler readAccessHandler; + void* readAccessHandlerParameter; + + MmsWriteVariableHandler writeHandler; + void* writeHandlerParameter; + + MmsConnectionHandler connectionHandler; + void* connectionHandlerParameter; + + MmsNamedVariableListChangedHandler variableListChangedHandler; //TODO this is only required if dynamic data sets are supported! + void* variableListChangedHandlerParameter; + + Map openConnections; + Map valueCaches; + bool isLocked; + + ByteBuffer* reportBuffer; /* global buffer for encoding reports */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore modelMutex; +#endif + +#if (MMS_STATUS_SERVICE == 1) + int vmdLogicalStatus; + int vmdPhysicalStatus; + MmsStatusRequestListener statusRequestListener; + void* statusRequestListenerParameter; +#endif /* MMS_STATUS_SERVICE == 1 */ + +#if (MMS_IDENTIFY_SERVICE == 1) + char* vendorName; + char* modelName; + char* revision; +#endif /* MMS_IDENTIFY_SERVICE == 1 */ +}; + +#if (MMS_FILE_SERVICE == 1) + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION +#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5 +#endif + +#include "hal_filesystem.h" + +typedef struct { + int32_t frsmId; + uint32_t readPosition; + uint32_t fileSize; + FileHandle fileHandle; +} MmsFileReadStateMachine; + +#endif /* (MMS_FILE_SERVICE == 1) */ + +struct sMmsServerConnection { + int maxServOutstandingCalling; + int maxServOutstandingCalled; + int dataStructureNestingLevel; + uint32_t maxPduSize; /* local detail */ + IsoConnection isoConnection; + MmsServer server; + uint32_t lastInvokeId; + +#if (MMS_DYNAMIC_DATA_SETS == 1) + LinkedList /**/namedVariableLists; /* aa-specific named variable lists */ +#endif + +#if (MMS_FILE_SERVICE == 1) + int32_t nextFrsmId; + MmsFileReadStateMachine frsms[CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION]; +#endif + +}; + +/* write_out function required for ASN.1 encoding */ +int +mmsServer_write_out(const void *buffer, size_t size, void *app_key); + +void +mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleGetNamedVariableListAttributesRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleReadRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +MmsPdu_t* +mmsServer_createConfirmedResponse(uint32_t invokeId); + +void +mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsError errorType); + +void +mmsServer_writeConcludeResponsePdu(ByteBuffer* response); + +void +mmsServer_handleInitiateRequest ( + MmsServerConnection self, + uint8_t* buffer, int bufPos, int maxBufPos, + ByteBuffer* response); + +int +mmsServer_handleGetVariableAccessAttributesRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleDefineNamedVariableListRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleGetNameListRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleWriteRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleIdentifyRequest( + MmsServerConnection connection, + int invokeId, + ByteBuffer* response); + +void +mmsServer_handleStatusRequest( + MmsServerConnection connection, + uint8_t* requestBuffer, + int bufPos, + int invokeId, + ByteBuffer* response); + +void +mmsServer_handleFileDirectoryRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleFileOpenRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleFileDeleteRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleFileRenameRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleFileReadRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +void +mmsServer_handleFileCloseRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + +int +mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess); + +int +mmsServer_getLowIndex(AlternateAccess_t* alternateAccess); + +int +mmsServer_getNumberOfElements(AlternateAccess_t* alternateAccess); + +void +mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListName); + +MmsDataAccessError +mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, + MmsServerConnection connection); + +MmsValue* +mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection); + +int +mmsServer_createMmsWriteResponse(MmsServerConnection connection, + int invokeId, ByteBuffer* response, int numberOfItems, MmsDataAccessError* accessResults); + +void +mmsServer_writeMmsRejectPdu(uint32_t* invokeId, int reason, ByteBuffer* response); + +MmsError +mmsServer_callVariableListChangedHandler(bool create, MmsVariableListType listType, MmsDomain* domain, + char* listName, MmsServerConnection connection); + +#endif /* MMS_SERVER_INTERNAL_H_ */ diff --git a/src/mms/inc_private/mms_value_cache.h b/src/mms/inc_private/mms_value_cache.h new file mode 100644 index 0000000..c7b9a7c --- /dev/null +++ b/src/mms/inc_private/mms_value_cache.h @@ -0,0 +1,44 @@ +/* + * mms_value_cache.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_VARIABLE_CACHE_H_ +#define MMS_VARIABLE_CACHE_H_ + +#include "mms_device_model.h" +#include "mms_value.h" + +typedef struct sMmsValueCache* MmsValueCache; + +MmsValueCache +MmsValueCache_create(MmsDomain* domain); + +void +MmsValueCache_insertValue(MmsValueCache self, char* itemId, MmsValue* value); + +MmsValue* +MmsValueCache_lookupValue(MmsValueCache self, char* itemId); + +void +MmsValueCache_destroy(MmsValueCache self); + +#endif /* MMS_VARIABLE_CACHE_H_ */ diff --git a/src/mms/inc_private/mms_value_internal.h b/src/mms/inc_private/mms_value_internal.h new file mode 100644 index 0000000..ef789a5 --- /dev/null +++ b/src/mms/inc_private/mms_value_internal.h @@ -0,0 +1,67 @@ +/* + * mms_value_internal.h + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef MMS_VALUE_INTERNAL_H_ +#define MMS_VALUE_INTERNAL_H_ + +#include "mms_value.h" + +struct ATTRIBUTE_PACKED sMmsValue { + MmsType type; + uint8_t deleteValue; + union uMmsValue { + MmsDataAccessError dataAccessError; + struct { + int size; + MmsValue** components; + } structure; + bool boolean; + Asn1PrimitiveValue* integer; + struct { + uint8_t exponentWidth; + uint8_t formatWidth; /* number of bits - either 32 or 64) */ + uint8_t* buf; + } floatingPoint; + struct { + uint16_t size; + uint16_t maxSize; + uint8_t* buf; + } octetString; + struct { + int size; /* Number of bits */ + uint8_t* buf; + } bitString; + struct { + char* buf; + int16_t size; /* size of the string, equals the amount of allocated memory - 1 */ + } visibleString; + uint8_t utcTime[8]; + struct { + uint8_t size; + uint8_t buf[6]; + } binaryTime; + } value; +}; + + +#endif /* MMS_VALUE_INTERNAL_H_ */ diff --git a/src/mms/iso_acse/acse.c b/src/mms/iso_acse/acse.c new file mode 100644 index 0000000..67f0ad1 --- /dev/null +++ b/src/mms/iso_acse/acse.c @@ -0,0 +1,701 @@ +/* + * acse.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "acse.h" +#include "ber_encoder.h" +#include "ber_decode.h" + +#if ((DEBUG_ISO_CLIENT == 1) || (DEBUG_ISO_SERVER == 1)) +#define DEBUG_ACSE 1 +#else +#define DEBUG_ACSE 0 +#endif + +static uint8_t appContextNameMms[] = { 0x28, 0xca, 0x22, 0x02, 0x03 }; + +static uint8_t auth_mech_password_oid[] = { 0x52, 0x03, 0x01 }; + +static uint8_t requirements_authentication[] = { 0x80 }; + +static AcseAuthenticationMechanism +checkAuthMechanismName(uint8_t* authMechanism, int authMechLen) +{ + AcseAuthenticationMechanism authenticationMechanism = ACSE_AUTH_NONE; + + if (authMechanism != NULL ) { + + if (authMechLen == 3) { + if (memcmp(auth_mech_password_oid, authMechanism, 3) == 0) { + authenticationMechanism = ACSE_AUTH_PASSWORD; + } + } + } + + return authenticationMechanism; +} + +static bool +authenticateClient(AcseConnection* self, AcseAuthenticationMechanism mechanism, uint8_t* authValue, int authValueLen) +{ + struct sAcseAuthenticationParameter authParamStruct; + + AcseAuthenticationParameter authParameter = &authParamStruct; + + authParameter->mechanism = mechanism; + + if (mechanism == ACSE_AUTH_PASSWORD) { + authParameter->value.password.octetString = authValue; + authParameter->value.password.passwordLength = authValueLen; + } + + return self->authenticator(self->authenticatorParameter, authParameter, &(self->securityToken)); +} + +static bool +checkAuthentication(AcseConnection* self, uint8_t* authMechanism, int authMechLen, uint8_t* authValue, int authValueLen) +{ + self->securityToken = NULL; + + if (self->authenticator != NULL ) { + + AcseAuthenticationMechanism mechanism = checkAuthMechanismName(authMechanism, authMechLen); + + return authenticateClient(self, mechanism, authValue, authValueLen); + } + else + return true; +} + + + +static int +parseUserInformation(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos, bool* userInfoValid) +{ + if (DEBUG_ACSE) printf("ACSE: parseUserInformation %i %i\n", bufPos, maxBufPos); + + bool hasindirectReference = false; + bool isDataValid = false; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + switch (tag) { + + case 0x02: /* indirect-reference */ + self->nextReference = BerDecoder_decodeUint32(buffer, len, bufPos); + bufPos += len; + hasindirectReference = true; + break; + + case 0xa0: /* encoding */ + isDataValid = true; + + self->userDataBufferSize = len; + self->userDataBuffer = buffer + bufPos; + + bufPos += len; + + break; + + default: /* ignore unknown tag */ + bufPos += len; + } + } + + + if (DEBUG_ACSE) { + if (!hasindirectReference) printf("ACSE: User data has no indirect reference!\n"); + + if (!isDataValid) printf("ACSE: No valid user data\n"); + } + + if (hasindirectReference && isDataValid) + *userInfoValid = true; + else + *userInfoValid = false; + + return bufPos; +} + +static AcseIndication +parseAarePdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) +{ + if (DEBUG_ACSE) printf("ACSE: parse AARE PDU\n"); + + bool userInfoValid = false; + + uint32_t result = 99; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + switch (tag) { + case 0xa1: /* application context name */ + bufPos += len; + break; + + case 0xa2: /* result */ + bufPos++; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + result = BerDecoder_decodeUint32(buffer, len, bufPos); + + bufPos += len; + break; + + case 0xa3: /* result source diagnostic */ + bufPos += len; + break; + + case 0xbe: /* user information */ + if (buffer[bufPos] != 0x28) { + if (DEBUG_ACSE) printf("ACSE: invalid user info\n"); + bufPos += len; + } + else { + bufPos++; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + bufPos = parseUserInformation(self, buffer, bufPos, bufPos + len, &userInfoValid); + } + break; + + default: /* ignore unknown tag */ + if (DEBUG_ACSE) + printf("ACSE: parseAarePdu: unknown tag %02x\n", tag); + + bufPos += len; + break; + } + } + + if (!userInfoValid) + return ACSE_ERROR; + + if (result != 0) + return ACSE_ASSOCIATE_FAILED; + + return ACSE_ASSOCIATE; +} + +static AcseIndication +parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) +{ + if (DEBUG_ACSE) printf("ACSE: parse AARQ PDU\n"); + + uint8_t* authValue = NULL; + int authValueLen = 0; + uint8_t* authMechanism = NULL; + int authMechLen = 0; + bool userInfoValid = false; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + if (bufPos < 0) { + if (DEBUG_ACSE) + printf("ACSE: parseAarqPdu: user info invalid!\n"); + return ACSE_ASSOCIATE_FAILED; + } + + switch (tag) { + case 0xa1: /* application context name */ + bufPos += len; + break; + + case 0xa2: /* called AP title */ + bufPos += len; + break; + case 0xa3: /* called AE qualifier */ + bufPos += len; + break; + + case 0xa6: /* calling AP title */ + bufPos += len; + break; + + case 0xa7: /* calling AE qualifier */ + bufPos += len; + break; + + case 0x8a: /* sender ACSE requirements */ + bufPos += len; + break; + + case 0x8b: /* (authentication) mechanism name */ + authMechLen = len; + authMechanism = buffer + bufPos; + bufPos += len; + break; + + case 0xac: /* authentication value */ + bufPos++; + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + authValueLen = len; + authValue = buffer + bufPos; + bufPos += len; + break; + + case 0xbe: /* user information */ + if (buffer[bufPos] != 0x28) { + if (DEBUG_ACSE) printf("ACSE: invalid user info\n"); + bufPos += len; + } + else { + bufPos++; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + bufPos = parseUserInformation(self, buffer, bufPos, bufPos + len, &userInfoValid); + } + break; + + default: /* ignore unknown tag */ + if (DEBUG_ACSE) + printf("ACSE: parseAarqPdu: unknown tag %02x\n", tag); + + bufPos += len; + break; + } + } + + if (checkAuthentication(self, authMechanism, authMechLen, authValue, authValueLen) == false) { + if (DEBUG_ACSE) + printf("ACSE: parseAarqPdu: check authentication failed!\n"); + + return ACSE_ASSOCIATE_FAILED; + } + + if (userInfoValid == false) { + if (DEBUG_ACSE) + printf("ACSE: parseAarqPdu: user info invalid!\n"); + + return ACSE_ASSOCIATE_FAILED; + } + + return ACSE_ASSOCIATE; +} + +void +AcseConnection_init(AcseConnection* self, AcseAuthenticator authenticator, void* parameter) +{ + self->state = idle; + self->nextReference = 0; + self->userDataBuffer = NULL; + self->userDataBufferSize = 0; + self->authenticator= authenticator; + self->authenticatorParameter = parameter; +} + +void +AcseConnection_destroy(AcseConnection* connection) +{ +} + +AcseIndication +AcseConnection_parseMessage(AcseConnection* self, ByteBuffer* message) +{ + AcseIndication indication; + + uint8_t* buffer = message->buffer; + + int messageSize = message->size; + + int bufPos = 0; + + uint8_t messageType = buffer[bufPos++]; + + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, messageSize); + + if (bufPos < 0) { + if (DEBUG_ACSE) + printf("ACSE: AcseConnection_parseMessage: invalid ACSE message!\n"); + + return ACSE_ERROR; + } + + switch (messageType) { + case 0x60: + indication = parseAarqPdu(self, buffer, bufPos, messageSize); + break; + case 0x61: + indication = parseAarePdu(self, buffer, bufPos, messageSize); + break; + case 0x62: /* A_RELEASE.request RLRQ-apdu */ + indication = ACSE_RELEASE_REQUEST; + break; + case 0x63: /* A_RELEASE.response RLRE-apdu */ + indication = ACSE_RELEASE_RESPONSE; + break; + case 0x64: /* A_ABORT */ + indication = ACSE_ABORT; + break; + default: + if (DEBUG_ACSE) printf("ACSE: Unknown ACSE message\n"); + indication = ACSE_ERROR; + break; + } + + return indication; +} + +void +AcseConnection_createAssociateFailedMessage(AcseConnection* self, BufferChain writeBuffer) +{ + AcseConnection_createAssociateResponseMessage(self, ACSE_RESULT_REJECT_PERMANENT, writeBuffer, NULL); +} + +void +AcseConnection_createAssociateResponseMessage(AcseConnection* self, + uint8_t acseResult, + BufferChain writeBuffer, + BufferChain payload + ) +{ + assert(self != NULL); + assert(writeBuffer != NULL); + assert(payload != NULL); + + int appContextLength = 9; + int resultLength = 5; + int resultDiagnosticLength = 5; + + int fixedContentLength = appContextLength + resultLength + resultDiagnosticLength; + + int variableContentLength = 0; + + int assocDataLength; + int userInfoLength; + int nextRefLength; + + int payloadLength = payload->length; + + /* single ASN1 type tag */ + variableContentLength += payloadLength; + variableContentLength += 1; + variableContentLength += BerEncoder_determineLengthSize(payloadLength); + + /* indirect reference */ + nextRefLength = BerEncoder_UInt32determineEncodedSize(self->nextReference); + variableContentLength += nextRefLength; + variableContentLength += 2; + + /* association data */ + assocDataLength = variableContentLength; + variableContentLength += BerEncoder_determineLengthSize(assocDataLength); + variableContentLength += 1; + + /* user information */ + userInfoLength = variableContentLength; + variableContentLength += BerEncoder_determineLengthSize(userInfoLength); + variableContentLength += 1; + + variableContentLength += 2; + + int contentLength = fixedContentLength + variableContentLength; + + uint8_t* buffer = writeBuffer->buffer; + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0x61, contentLength, buffer, bufPos); + + /* application context name */ + bufPos = BerEncoder_encodeTL(0xa1, 7, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x06, 5, buffer, bufPos); + memcpy(buffer + bufPos, appContextNameMms, 5); + bufPos += 5; + + /* result */ + bufPos = BerEncoder_encodeTL(0xa2, 3, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos); + buffer[bufPos++] = acseResult; + + /* result source diagnostics */ + bufPos = BerEncoder_encodeTL(0xa3, 5, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa1, 3, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos); + buffer[bufPos++] = 0; + + /* user information */ + bufPos = BerEncoder_encodeTL(0xbe, userInfoLength, buffer, bufPos); + + /* association data */ + bufPos = BerEncoder_encodeTL(0x28, assocDataLength, buffer, bufPos); + + /* indirect-reference */ + bufPos = BerEncoder_encodeTL(0x02, nextRefLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(self->nextReference, buffer, bufPos); + + /* single ASN1 type */ + bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payloadLength; + writeBuffer->nextPart = payload; +} + +void +AcseConnection_createAssociateRequestMessage(AcseConnection* self, + IsoConnectionParameters isoParameters, + BufferChain writeBuffer, + BufferChain payload, + AcseAuthenticationParameter authParameter) +{ + assert(self != NULL); + assert(writeBuffer != NULL); + assert(payload != NULL); + + int payloadLength = payload->length; + int authValueLength; + int authValueStringLength = 0; + + int passwordLength = 0; + + int contentLength = 0; + + /* application context name */ + contentLength += 9; + + int calledAEQualifierLength = 0; + + if (isoParameters->remoteApTitleLen > 0) { + + /* called AP title */ + contentLength += (4 + isoParameters->remoteApTitleLen); + + calledAEQualifierLength = BerEncoder_UInt32determineEncodedSize(isoParameters->remoteAEQualifier); + + /* called AP qualifier */ + contentLength += (4 + calledAEQualifierLength); + } + + int callingAEQualifierLength = 0; + + if (isoParameters->localApTitleLen > 0) { + /* calling AP title */ + contentLength += (4 + isoParameters->localApTitleLen); + + callingAEQualifierLength = BerEncoder_UInt32determineEncodedSize(isoParameters->localAEQualifier); + + /* calling AP qualifier */ + contentLength += (4 + callingAEQualifierLength); + } + + if (authParameter != NULL) { + + /* sender ACSE requirements */ + contentLength += 4; + + /* mechanism name */ + contentLength += 5; + + /* authentication value */ + if (authParameter->mechanism == ACSE_AUTH_PASSWORD) { + contentLength += 2; + + //if (authParameter->value.password.passwordLength == 0) + + passwordLength = authParameter->value.password.passwordLength; + + authValueStringLength = BerEncoder_determineLengthSize(passwordLength); + + contentLength += passwordLength + authValueStringLength; + + authValueLength = BerEncoder_determineLengthSize(passwordLength + authValueStringLength + 1); + + contentLength += authValueLength; + } + else { + contentLength += 2; + } + } + + /* user information */ + int userInfoLength = 0; + + /* single ASN1 type tag */ + userInfoLength += payloadLength; + userInfoLength += 1; + userInfoLength += BerEncoder_determineLengthSize(payloadLength); + + /* indirect reference */ + userInfoLength += 1; + userInfoLength += 2; + + /* association data */ + int assocDataLength = userInfoLength; + userInfoLength += BerEncoder_determineLengthSize(assocDataLength); + userInfoLength += 1; + + /* user information */ + int userInfoLen = userInfoLength; + userInfoLength += BerEncoder_determineLengthSize(userInfoLength); + userInfoLength += 1; + + contentLength += userInfoLength; + + uint8_t* buffer = writeBuffer->buffer; + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0x60, contentLength, buffer, bufPos); + + /* application context name */ + bufPos = BerEncoder_encodeTL(0xa1, 7, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x06, 5, buffer, bufPos); + memcpy(buffer + bufPos, appContextNameMms, 5); + bufPos += 5; + + if (isoParameters->remoteApTitleLen > 0) { + + /* called AP title */ + bufPos = BerEncoder_encodeTL(0xa2, isoParameters->remoteApTitleLen + 2, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x06, isoParameters->remoteApTitleLen, buffer, bufPos); + + memcpy(buffer + bufPos, isoParameters->remoteApTitle, isoParameters->remoteApTitleLen); + bufPos += isoParameters->remoteApTitleLen; + + /* called AE qualifier */ + bufPos = BerEncoder_encodeTL(0xa3, calledAEQualifierLength + 2, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, calledAEQualifierLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(isoParameters->remoteAEQualifier, buffer, bufPos); + } + + if (isoParameters->localApTitleLen > 0) { + /* calling AP title */ + bufPos = BerEncoder_encodeTL(0xa6, isoParameters->localApTitleLen + 2, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x06, isoParameters->localApTitleLen, buffer, bufPos); + memcpy(buffer + bufPos, isoParameters->localApTitle, isoParameters->localApTitleLen); + bufPos += isoParameters->localApTitleLen; + + /* calling AE qualifier */ + bufPos = BerEncoder_encodeTL(0xa7, callingAEQualifierLength + 2, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, callingAEQualifierLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(isoParameters->localAEQualifier, buffer, bufPos); + } + + if (authParameter != NULL) { + /* sender requirements */ + bufPos = BerEncoder_encodeTL(0x8a, 2, buffer, bufPos); + buffer[bufPos++] = 0x04; + + if (authParameter->mechanism == ACSE_AUTH_PASSWORD) { + buffer[bufPos++] = requirements_authentication[0]; + + bufPos = BerEncoder_encodeTL(0x8b, 3, buffer, bufPos); + memcpy(buffer + bufPos, auth_mech_password_oid, 3); + bufPos += 3; + + /* authentication value */ + bufPos = BerEncoder_encodeTL(0xac, authValueStringLength + passwordLength + 1, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, passwordLength, buffer, bufPos); + memcpy(buffer + bufPos, authParameter->value.password.octetString, passwordLength); + bufPos += passwordLength; + } + else { /* AUTH_NONE */ + buffer[bufPos++] = 0; + } + } + + /* user information */ + bufPos = BerEncoder_encodeTL(0xbe, userInfoLen, buffer, bufPos); + + /* association data */ + bufPos = BerEncoder_encodeTL(0x28, assocDataLength, buffer, bufPos); + + /* indirect-reference */ + bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos); + buffer[bufPos++] = 3; + + /* single ASN1 type */ + bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payload->length; + writeBuffer->nextPart = payload; +} + +/** + * \param isProvider specifies abort source (false = user/client; true = provider/server) + */ +void +AcseConnection_createAbortMessage(AcseConnection* self, BufferChain writeBuffer, bool isProvider) +{ + uint8_t* buffer = writeBuffer->buffer; + + buffer[0] = 0x64; /* [APPLICATION 4] */ + buffer[1] = 3; + buffer[2] = 0x80; + buffer[3] = 1; + + if (isProvider) + buffer[4] = 1; + else + buffer[4] = 0; + + writeBuffer->partLength = 5; + writeBuffer->length = 5; + writeBuffer->nextPart = NULL; +} + +void +AcseConnection_createReleaseRequestMessage(AcseConnection* self, BufferChain writeBuffer) +{ + uint8_t* buffer = writeBuffer->buffer; + + buffer[0] = 0x62; + buffer[1] = 3; + buffer[2] = 0x80; + buffer[3] = 1; + buffer[4] = 0; + + writeBuffer->partLength = 5; + writeBuffer->length = 5; + writeBuffer->nextPart = NULL; +} + +void +AcseConnection_createReleaseResponseMessage(AcseConnection* self, BufferChain writeBuffer) +{ + uint8_t* buffer = writeBuffer->buffer; + + buffer[0] = 0x63; + buffer[1] = 0; + + writeBuffer->partLength = 2; + writeBuffer->length = 2; + writeBuffer->nextPart = NULL; +} + diff --git a/src/mms/iso_client/iso_client_connection.c b/src/mms/iso_client/iso_client_connection.c new file mode 100644 index 0000000..b68631b --- /dev/null +++ b/src/mms/iso_client/iso_client_connection.c @@ -0,0 +1,591 @@ +/* + * iso_client_connection.c + * + * Client side representation of the ISO stack (COTP, session, presentation, ACSE) + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#include "hal_socket.h" +#include "hal_thread.h" +#include "cotp.h" +#include "iso_session.h" +#include "iso_presentation.h" +#include "iso_client_connection.h" +#include "acse.h" + +#ifndef DEBUG_ISO_CLIENT +#ifdef DEBUG +#define DEBUG_ISO_CLIENT 1 +#else +#define DEBUG_ISO_CLIENT 0 +#endif /*DEBUG */ +#endif /* DEBUG_ISO_SERVER */ + +#define STATE_IDLE 0 +#define STATE_ASSOCIATED 1 +#define STATE_ERROR 2 + +#define TPKT_RFC1006_HEADER_SIZE 4 + +#define ISO_CLIENT_BUFFER_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100 + +struct sIsoClientConnection +{ + IsoIndicationCallback callback; + void* callbackParameter; + volatile int state; + Socket socket; + CotpConnection* cotpConnection; + IsoPresentation* presentation; + IsoSession* session; + AcseConnection acseConnection; + + uint8_t* sendBuffer; /* ISO/MMS send buffer */ + uint8_t* receiveBuf; /* ISO/MMS receive buffer */ + ByteBuffer* receiveBuffer; + + ByteBuffer* transmitPayloadBuffer; + Semaphore transmitBufferMutex; + + ByteBuffer* receivePayloadBuffer; + Semaphore receiveBufferMutex; + + uint8_t* cotpReadBuf; + uint8_t* cotpWriteBuf; + + ByteBuffer* cotpReadBuffer; + ByteBuffer* cotpWriteBuffer; + + volatile bool handlingThreadRunning; + volatile bool stopHandlingThread; + volatile bool destroyHandlingThread; + volatile bool startHandlingThread; + + Thread thread; +}; + +static void +connectionHandlingThread(IsoClientConnection self) +{ + IsoSessionIndication sessionIndication; + + self->handlingThreadRunning = true; + self->stopHandlingThread = false; + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: new connection %p\n", self); + + /* Wait until lower layer association is finished */ + Semaphore_wait(self->receiveBufferMutex); + + CotpConnection_resetPayload(self->cotpConnection); + + while (true) { + + TpktState packetState; + + while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING) + { + Thread_sleep(1); + + if (self->stopHandlingThread) { + packetState = TPKT_ERROR; + break; + } + } + + if (packetState == TPKT_ERROR) + break; + + CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + if (cotpIndication == COTP_MORE_FRAGMENTS_FOLLOW) + continue; + + if (cotpIndication != COTP_DATA_INDICATION) + break; + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: parse message\n"); + + sessionIndication = + IsoSession_parseMessage(self->session, + CotpConnection_getPayload(self->cotpConnection)); + + if (sessionIndication != SESSION_DATA) { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: Invalid session message\n"); + break; + } + + if (!IsoPresentation_parseUserData(self->presentation, IsoSession_getUserData(self->session))) { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: Invalid presentation message\n"); + break; + } + + self->callback(ISO_IND_DATA, self->callbackParameter, + &(self->presentation->nextPayload)); + + /* wait for user to release the buffer */ + Semaphore_wait(self->receiveBufferMutex); + + CotpConnection_resetPayload(self->cotpConnection); + } + + self->callback(ISO_IND_CLOSED, self->callbackParameter, NULL);; + + self->state = STATE_IDLE; + + Socket_destroy(self->socket); + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: exit connection %p\n", self); + + /* release buffer to enable reuse of client connection */ + Semaphore_post(self->receiveBufferMutex); + + self->handlingThreadRunning = false; +} + + +static void* +connectionThreadFunction(void* parameter) +{ + IsoClientConnection self = (IsoClientConnection) parameter; + + while (self->destroyHandlingThread == false) { + + if (self->startHandlingThread) { + self->startHandlingThread = false; + connectionHandlingThread(self); + } + + Thread_sleep(1); + } + + self->destroyHandlingThread = false; + + return NULL; +} + + +IsoClientConnection +IsoClientConnection_create(IsoIndicationCallback callback, void* callbackParameter) +{ + IsoClientConnection self = (IsoClientConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoClientConnection)); + + if (self == NULL) + return NULL; + + self->callback = callback; + self->callbackParameter = callbackParameter; + self->state = STATE_IDLE; + + self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE); + + self->transmitPayloadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + self->transmitPayloadBuffer->buffer = self->sendBuffer; + self->transmitPayloadBuffer->maxSize = ISO_CLIENT_BUFFER_SIZE; + + self->receivePayloadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + + self->transmitBufferMutex = Semaphore_create(1); + + self->receiveBufferMutex = Semaphore_create(1); + + self->receiveBuf = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE); + self->receiveBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + ByteBuffer_wrap(self->receiveBuffer, self->receiveBuf, 0, ISO_CLIENT_BUFFER_SIZE); + + self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation)); + + self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession)); + + self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpReadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + ByteBuffer_wrap(self->cotpReadBuffer, self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpWriteBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + ByteBuffer_wrap(self->cotpWriteBuffer, self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection)); + + return self; +} + +void +IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters params, + ByteBuffer* payload, uint32_t connectTimeoutInMs) +{ + self->socket = TcpSocket_create(); + + Socket_setConnectTimeout(self->socket, connectTimeoutInMs); + + if (!Socket_connect(self->socket, params->hostname, params->tcpPort)) + goto returnError; + + /* COTP (ISO transport) handshake */ + CotpConnection_init(self->cotpConnection, self->socket, self->receiveBuffer, self->cotpReadBuffer, self->cotpWriteBuffer); + CotpIndication cotpIndication = + CotpConnection_sendConnectionRequestMessage(self->cotpConnection, params); + + TpktState packetState; + + uint64_t timeout = Hal_getTimeInMs() + CONFIG_TCP_READ_TIMEOUT_MS; + + while (((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING) + && (Hal_getTimeInMs() < timeout)) + { + Thread_sleep(1); + } + + if (packetState != TPKT_PACKET_COMPLETE) + goto returnError; + + cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + if (cotpIndication != COTP_CONNECT_INDICATION) + goto returnError; + + /* Upper layers handshake */ + struct sBufferChain sAcsePayload; + BufferChain acsePayload = &sAcsePayload; + acsePayload->buffer = payload->buffer; + acsePayload->partLength = payload->size; + acsePayload->length = payload->size; + acsePayload->nextPart = NULL; + + AcseConnection_init(&(self->acseConnection), NULL, NULL); + + AcseAuthenticationParameter authParameter = params->acseAuthParameter; + + struct sBufferChain sAcseBuffer; + BufferChain acseBuffer = &sAcseBuffer; + + acseBuffer->buffer = self->sendBuffer + payload->size; + acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acsePayload->length; + + AcseConnection_createAssociateRequestMessage(&(self->acseConnection), params, acseBuffer, acsePayload, + authParameter); + + struct sBufferChain sPresentationBuffer; + BufferChain presentationBuffer = &sPresentationBuffer; + + presentationBuffer->buffer = self->sendBuffer + acseBuffer->length; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length; + + IsoPresentation_init(self->presentation); + IsoPresentation_createConnectPdu(self->presentation, params, presentationBuffer, acseBuffer); + + struct sBufferChain sSessionBuffer; + BufferChain sessionBuffer = &sSessionBuffer; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length; + + IsoSession_init(self->session); + IsoSession_createConnectSpdu(self->session, params, sessionBuffer, + presentationBuffer); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + Semaphore_post(self->transmitBufferMutex); + + while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING) + { + Thread_sleep(1); + } + + cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + if (cotpIndication != COTP_DATA_INDICATION) + goto returnError; + + IsoSessionIndication sessionIndication; + + sessionIndication = + IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection)); + + if (sessionIndication != SESSION_CONNECT) { + if (DEBUG_ISO_CLIENT) + printf("IsoClientConnection_associate: no session connect indication\n"); + goto returnError; + } + + if (!IsoPresentation_parseAcceptMessage(self->presentation, IsoSession_getUserData(self->session))) { + if (DEBUG_ISO_CLIENT) + printf("IsoClientConnection_associate: no presentation ok indication\n"); + goto returnError; + } + + AcseIndication acseIndication; + + acseIndication = AcseConnection_parseMessage(&(self->acseConnection), &self->presentation->nextPayload); + + if (acseIndication != ACSE_ASSOCIATE) { + if (DEBUG_ISO_CLIENT) + printf("IsoClientConnection_associate: no ACSE_ASSOCIATE indication\n"); + goto returnError; + } + + + ByteBuffer_wrap(self->receivePayloadBuffer, self->acseConnection.userDataBuffer, + self->acseConnection.userDataBufferSize, self->acseConnection.userDataBufferSize); + + Semaphore_wait(self->receiveBufferMutex); + + self->callback(ISO_IND_ASSOCIATION_SUCCESS, self->callbackParameter, self->receivePayloadBuffer); + + /* wait for upper layer to release buffer */ + Semaphore_wait(self->receiveBufferMutex); + + self->state = STATE_ASSOCIATED; + + if (self->thread == NULL) { + self->thread = Thread_create(connectionThreadFunction, self, false); + Thread_start(self->thread); + } + + self->startHandlingThread = true; + + while (self->handlingThreadRunning == false) + Thread_sleep(1); + + return; + +returnError: + self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); + + self->state = STATE_ERROR; + + Socket_destroy(self->socket); + self->socket = NULL; + + Semaphore_post(self->transmitBufferMutex); //TODO check + + return; +} + +void +IsoClientConnection_sendMessage(IsoClientConnection self, ByteBuffer* payloadBuffer) +{ + + struct sBufferChain payloadBCMemory; + BufferChain payload = &payloadBCMemory; + + BufferChain_init(payload, payloadBuffer->size, payloadBuffer->size, NULL, payloadBuffer->buffer); + + struct sBufferChain presentationBCMemory; + BufferChain presentationBuffer = &presentationBCMemory; + + presentationBuffer->buffer = self->sendBuffer + payload->length; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE; + + IsoPresentation_createUserData(self->presentation, presentationBuffer, payload); + + struct sBufferChain sessionBufferBCMemory; + BufferChain sessionBuffer = &sessionBufferBCMemory; + + IsoSession_createDataSpdu(self->session, sessionBuffer, presentationBuffer); + + CotpIndication indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + /* release transmit buffer for use by API client */ + Semaphore_post(self->transmitBufferMutex); + + if (indication != COTP_OK) + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_sendMessage: send message failed!\n"); +} + +void +IsoClientConnection_close(IsoClientConnection self) +{ + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_close\n"); + + if (self->handlingThreadRunning) { + self->stopHandlingThread = true; + while (self->handlingThreadRunning) + Thread_sleep(1); + } + + self->state = STATE_IDLE; +} + + +void +IsoClientConnection_destroy(IsoClientConnection self) +{ + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_destroy\n"); + + if (self->state == STATE_ASSOCIATED) { + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: call IsoClientConnection_close\n"); + + IsoClientConnection_close(self); + } + + /* stop handling thread */ + self->destroyHandlingThread = true; + + if (self->thread != NULL) { + while (self->destroyHandlingThread) + Thread_sleep(1); + + Thread_destroy(self->thread); + } + + if (self->receiveBuf != NULL) + GLOBAL_FREEMEM(self->receiveBuf); + if (self->receiveBuffer != NULL) + GLOBAL_FREEMEM(self->receiveBuffer); + if (self->cotpConnection != NULL) + GLOBAL_FREEMEM(self->cotpConnection); + + if (self->cotpReadBuffer != NULL) + GLOBAL_FREEMEM(self->cotpReadBuffer); + + if (self->cotpReadBuf != NULL) + GLOBAL_FREEMEM(self->cotpReadBuf); + + if (self->cotpWriteBuffer != NULL) + GLOBAL_FREEMEM(self->cotpWriteBuffer); + + if (self->cotpWriteBuf != NULL) + GLOBAL_FREEMEM(self->cotpWriteBuf); + + if (self->session != NULL) + GLOBAL_FREEMEM(self->session); + if (self->presentation != NULL) + GLOBAL_FREEMEM(self->presentation); + + GLOBAL_FREEMEM(self->transmitPayloadBuffer); + GLOBAL_FREEMEM(self->receivePayloadBuffer); + + Semaphore_destroy(self->receiveBufferMutex); + Semaphore_destroy(self->transmitBufferMutex); + + GLOBAL_FREEMEM(self->sendBuffer); + GLOBAL_FREEMEM(self); +} + +bool +IsoClientConnection_abort(IsoClientConnection self) +{ + //TODO block other messages from being sent + IsoClientConnection_allocateTransmitBuffer(self); + + struct sBufferChain sAcseBuffer; + BufferChain acseBuffer = &sAcseBuffer; + acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE; + acseBuffer->buffer = self->sendBuffer; + acseBuffer->nextPart = NULL; + + AcseConnection_createAbortMessage(NULL, acseBuffer, false); + + struct sBufferChain sPresentationBuffer; + BufferChain presentationBuffer = &sPresentationBuffer; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length; + presentationBuffer->buffer = self->sendBuffer + acseBuffer->length; + presentationBuffer->nextPart = acseBuffer; + + IsoPresentation_createAbortUserMessage(self->presentation, presentationBuffer, acseBuffer); + + struct sBufferChain sSessionBuffer; + BufferChain sessionBuffer = &sSessionBuffer; + sessionBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - presentationBuffer->length; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length; + sessionBuffer->nextPart = presentationBuffer; + + IsoSession_createAbortSpdu(self->session, sessionBuffer, presentationBuffer); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + Semaphore_post(self->transmitBufferMutex); + + uint64_t timeout = Hal_getTimeInMs() + CONFIG_TCP_READ_TIMEOUT_MS; + + while ((self->handlingThreadRunning == true) && (Hal_getTimeInMs() < timeout)); + + if (self->handlingThreadRunning) + return false; + else + return true; +} + +void +IsoClientConnection_release(IsoClientConnection self) +{ + //TODO block other messages from being sent + IsoClientConnection_allocateTransmitBuffer(self); + + struct sBufferChain sAcseBuffer; + BufferChain acseBuffer = &sAcseBuffer; + acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE; + acseBuffer->buffer = self->sendBuffer; + acseBuffer->nextPart = NULL; + + AcseConnection_createReleaseRequestMessage(NULL, acseBuffer); + + struct sBufferChain sPresentationBuffer; + BufferChain presentationBuffer = &sPresentationBuffer; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length; + presentationBuffer->buffer = self->sendBuffer + acseBuffer->length; + presentationBuffer->nextPart = acseBuffer; + + IsoPresentation_createUserDataACSE(self->presentation, presentationBuffer, acseBuffer); + + struct sBufferChain sSessionBuffer; + BufferChain sessionBuffer = &sSessionBuffer; + sessionBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - presentationBuffer->length; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length; + sessionBuffer->nextPart = presentationBuffer; + + IsoSession_createFinishSpdu(NULL, sessionBuffer, presentationBuffer); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + Semaphore_post(self->transmitBufferMutex); +} + + +ByteBuffer* +IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self) +{ + Semaphore_wait(self->transmitBufferMutex); + self->transmitPayloadBuffer->size = 0; + self->transmitPayloadBuffer->maxSize = ISO_CLIENT_BUFFER_SIZE; + return self->transmitPayloadBuffer; +} + +void +IsoClientConnection_releaseReceiveBuffer(IsoClientConnection self) +{ + Semaphore_post(self->receiveBufferMutex); +} diff --git a/src/mms/iso_common/iso_connection_parameters.c b/src/mms/iso_common/iso_connection_parameters.c new file mode 100644 index 0000000..8f4b2d2 --- /dev/null +++ b/src/mms/iso_common/iso_connection_parameters.c @@ -0,0 +1,132 @@ +/* + * iso_connection_parameters.c + * + * IsoConnectionParameters abstract data type to represent the configurable parameters of the ISO protocol stack. + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#include "iso_connection_parameters.h" + +#include "ber_encoder.h" + +AcseAuthenticationParameter +AcseAuthenticationParameter_create() +{ + AcseAuthenticationParameter self = (AcseAuthenticationParameter) + GLOBAL_CALLOC(1, sizeof(struct sAcseAuthenticationParameter)); + + return self; +} + +void +AcseAuthenticationParameter_destroy(AcseAuthenticationParameter self) +{ + if (self->mechanism == ACSE_AUTH_PASSWORD) + if (self->value.password.octetString != NULL) + GLOBAL_FREEMEM(self->value.password.octetString); + + GLOBAL_FREEMEM(self); +} + +void +AcseAuthenticationParameter_setPassword(AcseAuthenticationParameter self, char* password) +{ + self->value.password.octetString = (uint8_t*) copyString(password); + self->value.password.passwordLength = strlen(password); +} + +void +AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, AcseAuthenticationMechanism mechanism) +{ + self->mechanism = mechanism; +} + + +IsoConnectionParameters +IsoConnectionParameters_create() +{ + IsoConnectionParameters self = (IsoConnectionParameters) GLOBAL_CALLOC(1, sizeof(struct sIsoConnectionParameters)); + + return self; +} + +void +IsoConnectionParameters_destroy(IsoConnectionParameters self) +{ + GLOBAL_FREEMEM(self); +} + +void +IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters self, + AcseAuthenticationParameter acseAuthParameter) +{ + self->acseAuthParameter = acseAuthParameter; +} + +void +IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const char* hostname, int tcpPort) +{ + self->hostname = hostname; + self->tcpPort = tcpPort; +} + +void +IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier) +{ + if (apTitle == NULL) + self->remoteApTitleLen = 0; + else { + self->remoteApTitleLen = BerEncoder_encodeOIDToBuffer(apTitle, self->remoteApTitle, 10); + self->remoteAEQualifier = aeQualifier; + } +} + +void +IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector) +{ + self->remotePSelector = pSelector; + self->remoteSSelector = sSelector; + self->remoteTSelector = tSelector; +} + + +void +IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, char* apTitle, int aeQualifier) +{ + if (apTitle == NULL) + self->localApTitleLen = 0; + else { + self->localApTitleLen = BerEncoder_encodeOIDToBuffer(apTitle, self->localApTitle, 10); + self->localAEQualifier = aeQualifier; + } +} + +void +IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector) +{ + self->localPSelector = pSelector; + self->localSSelector = sSelector; + self->localTSelector = tSelector; +} diff --git a/src/mms/iso_cotp/cotp.c b/src/mms/iso_cotp/cotp.c new file mode 100644 index 0000000..4d53f77 --- /dev/null +++ b/src/mms/iso_cotp/cotp.c @@ -0,0 +1,715 @@ +/* + * cotp.c + * + * ISO 8073 Connection Oriented Transport Protocol over TCP (RFC1006) + * + * Partial implementation of the ISO 8073 COTP (ISO TP0) protocol for MMS. + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "cotp.h" +#include "byte_buffer.h" +#include "buffer_chain.h" + +#define TPKT_RFC1006_HEADER_SIZE 4 + +#define COTP_DATA_HEADER_SIZE 3 + +#ifdef CONFIG_COTP_MAX_TPDU_SIZE +#define COTP_MAX_TPDU_SIZE CONFIG_COTP_MAX_TPDU_SIZE +#else +#define COTP_MAX_TPDU_SIZE 8192 +#endif + +#ifndef DEBUG_COTP +#define DEBUG_COTP 0 +#endif + +static bool +addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength); + +static inline uint16_t +getUint16(uint8_t* buffer) +{ + return (buffer[0] * 0x100) + buffer[1]; +} + +static inline uint8_t +getUint8(uint8_t* buffer) +{ + return buffer[0]; +} + +static void +writeOptions(CotpConnection* self) +{ + // max size = 11 byte + uint8_t* buffer = self->writeBuffer->buffer; + int bufPos = self->writeBuffer->size; + + if (self->options.tpduSize != 0) { + + if (DEBUG_COTP) + printf("COTP: send TPDU size: %i\n", CotpConnection_getTpduSize(self)); + + buffer[bufPos++] = 0xc0; + buffer[bufPos++] = 0x01; + buffer[bufPos++] = self->options.tpduSize; + } + + if (self->options.tSelDst.size != 0) { + buffer[bufPos++] = 0xc2; + buffer[bufPos++] = (uint8_t) self->options.tSelDst.size; + + int i; + for (i = 0; i < self->options.tSelDst.size; i++) + buffer[bufPos++] = (uint8_t) self->options.tSelDst.value[i]; + } + + if (self->options.tSelSrc.size != 0) { + buffer[bufPos++] = 0xc1; + buffer[bufPos++] = (uint8_t) self->options.tSelSrc.size; + + int i; + for (i = 0; i < self->options.tSelSrc.size; i++) + buffer[bufPos++] = (uint8_t) self->options.tSelSrc.value[i]; + } + + self->writeBuffer->size = bufPos; +} + +static int +getOptionsLength(CotpConnection* self) +{ + int optionsLength = 0; + + if (self->options.tpduSize != 0) + optionsLength += 3; + + if (self->options.tSelDst.size != 0) + optionsLength += (2 + self->options.tSelDst.size); + + if (self->options.tSelSrc.size != 0) + optionsLength += (2 + self->options.tSelSrc.size); + + return optionsLength; +} + +static inline void +writeStaticConnectResponseHeader(CotpConnection* self, int optionsLength) +{ + /* always same size (7) and same position in buffer */ + uint8_t* buffer = self->writeBuffer->buffer; + + buffer[4] = 6 + optionsLength; + buffer[5] = 0xd0; + buffer[6] = (uint8_t) (self->srcRef / 0x100); + buffer[7] = (uint8_t) (self->srcRef & 0xff); + buffer[8] = (uint8_t) (self->dstRef / 0x100); + buffer[9] = (uint8_t) (self->dstRef & 0xff); + buffer[10] = (uint8_t) (self->protocolClass); + + self->writeBuffer->size = 11; +} + +static void +writeRfc1006Header(CotpConnection* self, int len) +{ + uint8_t* buffer = self->writeBuffer->buffer; + + buffer[0] = 0x03; + buffer[1] = 0x00; + buffer[2] = (uint8_t) (len / 0x100); + buffer[3] = (uint8_t) (len & 0xff); + + self->writeBuffer->size = 4; +} + +static void +writeDataTpduHeader(CotpConnection* self, int isLastUnit) +{ + /* always 3 byte starting from byte 5 in buffer */ + uint8_t* buffer = self->writeBuffer->buffer; + + buffer[4] = 0x02; + buffer[5] = 0xf0; + if (isLastUnit) + buffer[6] = 0x80; + else + buffer[6] = 0x00; + + self->writeBuffer->size = 7; +} + +static bool +sendBuffer(CotpConnection* self) +{ + int writeBufferPosition = ByteBuffer_getSize(self->writeBuffer); + + bool retVal = false; + + int sentBytes; + + do { + sentBytes = Socket_write(self->socket, ByteBuffer_getBuffer(self->writeBuffer), writeBufferPosition); + + if (sentBytes == -1) + goto exit_function; + + } while (sentBytes == 0); + + retVal = true; + + ByteBuffer_setSize(self->writeBuffer, 0); + +exit_function: + return retVal; +} + +CotpIndication +CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) +{ + CotpIndication retValue = COTP_OK; + + int fragments = 1; + + int fragmentPayloadSize = CotpConnection_getTpduSize(self) - COTP_DATA_HEADER_SIZE; + + if (payload->length > fragmentPayloadSize) { /* Check if segmentation is required? */ + fragments = payload->length / fragmentPayloadSize; + + if ((payload->length % fragmentPayloadSize) != 0) + fragments += 1; + } + + int currentBufPos = 0; + int currentLimit; + int lastUnit; + + BufferChain currentChain = payload; + int currentChainIndex = 0; + + if (DEBUG_COTP) + printf("\nCOTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength); + + uint8_t* buffer = self->writeBuffer->buffer; + + while (fragments > 0) { + if (fragments > 1) { + currentLimit = currentBufPos + fragmentPayloadSize; + lastUnit = 0; + } + else { + currentLimit = payload->length; + lastUnit = 1; + } + + writeRfc1006Header(self, 7 + (currentLimit - currentBufPos)); + + writeDataTpduHeader(self, lastUnit); + + int bufPos = 7; + + int i; + for (i = currentBufPos; i < currentLimit; i++) { + + if (currentChainIndex >= currentChain->partLength) { + currentChain = currentChain->nextPart; + if (DEBUG_COTP) + printf("\nCOTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength); + currentChainIndex = 0; + } + + buffer[bufPos++] = currentChain->buffer[currentChainIndex]; + + currentChainIndex++; + + currentBufPos++; + } + + self->writeBuffer->size = bufPos; + + if (DEBUG_COTP) + printf("COTP: Send COTP fragment %i bufpos: %i\n", fragments, currentBufPos); + + if (!sendBuffer(self)) { + retValue = COTP_ERROR; + + if (DEBUG_COTP) + printf("COTP: sending message failed!\n"); + + goto exit_function; + } + + + fragments--; + } + +exit_function: + + if (DEBUG_COTP) + printf("COTP: message transmission finished (fragments=%i, return=%i)\n", fragments, retValue); + + return retValue; +} + +static void +allocateWriteBuffer(CotpConnection* self) +{ + if (self->writeBuffer == NULL ) + self->writeBuffer = ByteBuffer_create(NULL, + CotpConnection_getTpduSize(self) + TPKT_RFC1006_HEADER_SIZE); +} + +/* client side */ +CotpIndication +CotpConnection_sendConnectionRequestMessage(CotpConnection* self, IsoConnectionParameters isoParameters) +{ + allocateWriteBuffer(self); + + self->options.tSelDst = isoParameters->remoteTSelector; + self->options.tSelSrc = isoParameters->localTSelector; + + int cotpRequestSize = getOptionsLength(self) + 6; + + int conRequestSize = cotpRequestSize + 5; + + if(self->writeBuffer->maxSize < conRequestSize) + return COTP_ERROR; + + uint8_t* buffer = self->writeBuffer->buffer; + + writeRfc1006Header(self, conRequestSize); + + /* LI */ + buffer[4] = (uint8_t) cotpRequestSize; + + /* TPDU CODE */ + buffer[5] = 0xe0; + + /* DST REF */ + buffer[6] = 0x00; + buffer[7] = 0x00; + + /* SRC REF */ + buffer[8] = 0x00; + buffer[9] = 0x02; /* or 0x01 ? */ + + /* Class */ + buffer[10] = 0x00; + + self->writeBuffer->size = 11; + + writeOptions(self); + + if (sendBuffer(self)) + return COTP_OK; + else + return COTP_ERROR; +} + +CotpIndication +CotpConnection_sendConnectionResponseMessage(CotpConnection* self) +{ + allocateWriteBuffer(self); + + int optionsLength = getOptionsLength(self); + int messageLength = 11 + optionsLength; + + writeRfc1006Header(self, messageLength); + + writeStaticConnectResponseHeader(self, optionsLength); + + writeOptions(self); + + if (sendBuffer(self)) + return COTP_OK; + else + return COTP_ERROR; +} + +static bool +parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen) +{ + int bufPos = 0; + + while (bufPos < bufLen) { + uint8_t optionType = buffer[bufPos++]; + uint8_t optionLen = buffer[bufPos++]; + + if (optionLen > (bufLen - bufPos)) { + if (DEBUG_COTP) + printf("COTP: option to long optionLen:%i bufPos:%i bufLen:%i\n", optionLen, bufPos, bufLen); + goto cpo_error; + } + + if (DEBUG_COTP) + printf("COTP: option: %02x len: %02x\n", optionType, optionLen); + + switch (optionType) { + case 0xc0: + if (optionLen == 1) { + int requestedTpduSize = (1 << buffer[bufPos++]); + + CotpConnection_setTpduSize(self, requestedTpduSize); + + if (DEBUG_COTP) + printf("COTP: requested TPDU size: %i\n", requestedTpduSize); + } + else + goto cpo_error; + break; + + case 0xc1: /* remote T-selector */ + if (optionLen < 5) { + self->options.tSelSrc.size = optionLen; + + int i; + for (i = 0; i < optionLen; i++) + self->options.tSelSrc.value[i] = buffer[bufPos++]; + } + else + goto cpo_error; + break; + + case 0xc2: /* local T-selector */ + if (optionLen < 5) { + self->options.tSelDst.size = optionLen; + + int i; + for (i = 0; i < optionLen; i++) + self->options.tSelDst.value[i] = buffer[bufPos++]; + } + else + goto cpo_error; + break; + + case 0xc6: /* additional option selection */ + if (optionLen == 1) + bufPos++; /* ignore value */ + else + goto cpo_error; + break; + + default: + if (DEBUG_COTP) + printf("COTP: Unknown option %02x\n", optionType); + + bufPos += optionLen; /* ignore value */ + + break; + } + } + + return true; + +cpo_error: + if (DEBUG_COTP) + printf("COTP: cotp_parse_options: error parsing options!\n"); + return false; +} + +void +CotpConnection_init(CotpConnection* self, Socket socket, + ByteBuffer* payloadBuffer, ByteBuffer* readBuffer, ByteBuffer* writeBuffer) +{ + self->state = 0; + self->socket = socket; + self->srcRef = -1; + self->dstRef = -1; + self->protocolClass = -1; + self->options.tpduSize = 0; + + TSelector tsel; + tsel.size = 2; + tsel.value[0] = 0; + tsel.value[1] = 1; + + self->options.tSelSrc = tsel; + self->options.tSelDst = tsel; + self->payload = payloadBuffer; + + /* default TPDU size is maximum size */ + CotpConnection_setTpduSize(self, COTP_MAX_TPDU_SIZE); + + self->writeBuffer = writeBuffer; + self->readBuffer = readBuffer; + self->packetSize = 0; +} + +int /* in byte */ +CotpConnection_getTpduSize(CotpConnection* self) +{ + return (1 << self->options.tpduSize); +} + +void +CotpConnection_setTpduSize(CotpConnection* self, int tpduSize /* in byte */) +{ + int newTpduSize = 1; + + if (tpduSize > COTP_MAX_TPDU_SIZE) + tpduSize = COTP_MAX_TPDU_SIZE; + + while ((1 << newTpduSize) < tpduSize) + newTpduSize++; + + if ((1 << newTpduSize) > tpduSize) + newTpduSize--; + + self->options.tpduSize = newTpduSize; +} + +ByteBuffer* +CotpConnection_getPayload(CotpConnection* self) +{ + return self->payload; +} + +int +CotpConnection_getSrcRef(CotpConnection* self) +{ + return self->srcRef; +} + +int +CotpConnection_getDstRef(CotpConnection* self) +{ + return self->dstRef; +} + +/* + CR TPDU (from RFC 0905): + + 1 2 3 4 5 6 7 8 p p+1...end + +--+------+---------+---------+---+---+------+-------+---------+ + |LI|CR CDT| DST - REF |SRC-REF|CLASS |VARIAB.|USER | + | |1110 |0000 0000|0000 0000| | |OPTION|PART |DATA | + +--+------+---------+---------+---+---+------+-------+---------+ + */ + + +static bool +parseConnectRequestTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) +{ + if (len < 6) + return false; + + self->dstRef = getUint16(buffer); + self->srcRef = getUint16(buffer + 2); + self->protocolClass = getUint8(buffer + 4); + + return parseOptions(self, buffer + 5, len - 6); +} + +static bool +parseConnectConfirmTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) +{ + if (len < 6) + return false; + + self->srcRef = getUint16(buffer); + self->dstRef = getUint16(buffer + 2); + self->protocolClass = getUint8(buffer + 4); + + return parseOptions(self, buffer + 5, len - 6); +} + +static bool +parseDataTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) +{ + if (len != 2) + return false; + + uint8_t flowControl = getUint8(buffer); + + if (flowControl & 0x80) + self->isLastDataUnit = true; + else + self->isLastDataUnit = false; + + return true; +} + +static bool +addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength) +{ + if (DEBUG_COTP) + printf("COTP: add to payload buffer (cur size: %i, len: %i)\n", self->payload->size, payloadLength); + + if ((self->payload->size + payloadLength) > self->payload->maxSize) + return false; + + memcpy(self->payload->buffer + self->payload->size, buffer, payloadLength); + + self->payload->size += payloadLength; + + return true; +} + +static CotpIndication +parseCotpMessage(CotpConnection* self) +{ + uint8_t* buffer = self->readBuffer->buffer + 4; + int tpduLength = self->readBuffer->size - 4; + + uint8_t len; + uint8_t tpduType; + + len = buffer[0]; + + if (len > tpduLength) { + if (DEBUG_COTP) + printf("COTP: parseCotpMessage: len=%d tpduLength=%d\n", len, tpduLength); + + return COTP_ERROR; + } + + tpduType = buffer[1]; + + switch (tpduType) { + case 0xe0: + if (parseConnectRequestTpdu(self, buffer + 2, len)) + return COTP_CONNECT_INDICATION; + else + return COTP_ERROR; + case 0xd0: + if (parseConnectConfirmTpdu(self, buffer + 2, len)) + return COTP_CONNECT_INDICATION; + else + return COTP_ERROR; + case 0xf0: + if (parseDataTpdu(self, buffer + 2, len)) { + + if (addPayloadToBuffer(self, buffer + 3, tpduLength - 3) != 1) + return COTP_ERROR; + + if (self->isLastDataUnit) + return COTP_DATA_INDICATION; + else + return COTP_MORE_FRAGMENTS_FOLLOW; + } + else + return COTP_ERROR; + default: + return COTP_ERROR; + } + +} + +CotpIndication +CotpConnection_parseIncomingMessage(CotpConnection* self) +{ + CotpIndication indication = parseCotpMessage(self); + + self->readBuffer->size = 0; + self->packetSize = 0; + + return indication; +} + +void +CotpConnection_resetPayload(CotpConnection* self) +{ + self->payload->size = 0; +} + +TpktState +CotpConnection_readToTpktBuffer(CotpConnection* self) +{ + uint8_t* buffer = self->readBuffer->buffer; + int bufferSize = self->readBuffer->maxSize; + int bufPos = self->readBuffer->size; + + assert (bufferSize > 4); + + int readBytes; + + if (bufPos < 4) { + + readBytes = Socket_read(self->socket, buffer + bufPos, 4 - bufPos); + + if (readBytes < 0) + goto exit_closed; + + if (DEBUG_COTP) { + if (readBytes > 0) + printf("TPKT: read %i bytes from socket\n", readBytes); + } + + bufPos += readBytes; + + if (bufPos == 4) { + if ((buffer[0] == 3) && (buffer[1] == 0)) { + self->packetSize = (buffer[2] * 0x100) + buffer[3]; + + if (DEBUG_COTP) + printf("TPKT: header complete (msg size = %i)\n", self->packetSize); + + if (self->packetSize > bufferSize) { + if (DEBUG_COTP) printf("TPKT: packet too large\n"); + goto exit_error; + } + } + else { + if (DEBUG_COTP) printf("TPKT: failed to decode TPKT header.\n"); + goto exit_error; + } + } + else + goto exit_waiting; + } + + readBytes = Socket_read(self->socket, buffer + bufPos, self->packetSize - bufPos); + + if (readBytes < 0) + goto exit_closed; + + bufPos += readBytes; + + if (bufPos < self->packetSize) + goto exit_waiting; + + if (DEBUG_COTP) printf("TPKT: message complete (size = %i)\n", self->packetSize); + + self->readBuffer->size = bufPos; + return TPKT_PACKET_COMPLETE; + +exit_closed: + if (DEBUG_COTP) printf("TPKT: socket closed or socket error\n"); + return TPKT_ERROR; + +exit_error: + if (DEBUG_COTP) printf("TPKT: Error parsing message\n"); + return TPKT_ERROR; + +exit_waiting: + + if (DEBUG_COTP) + if (bufPos != 0) + printf("TPKT: waiting (read %i of %i)\n", bufPos, self->packetSize); + + self->readBuffer->size = bufPos; + return TPKT_WAITING; +} + diff --git a/src/mms/iso_mms/asn1c/AccessResult.c b/src/mms/iso_mms/asn1c/AccessResult.c new file mode 100644 index 0000000..897f844 --- /dev/null +++ b/src/mms/iso_mms/asn1c/AccessResult.c @@ -0,0 +1,207 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "AccessResult.h" + +static asn_TYPE_member_t asn_MBR_AccessResult_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.failure), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DataAccessError, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "failure" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.array), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DataSequence, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "array" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.structure), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DataSequence, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "structure" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.boolean), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "boolean" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.bitstring), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "bitstring" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.integer), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "integer" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.Unsigned), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unsigned" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.floatingpoint), + (ASN_TAG_CLASS_CONTEXT | (7 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_FloatingPoint, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "floatingpoint" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.octetstring), + (ASN_TAG_CLASS_CONTEXT | (9 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "octetstring" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.visiblestring), + (ASN_TAG_CLASS_CONTEXT | (10 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_VisibleString, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "visiblestring" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.generalizedtime), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_GeneralizedTime, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "generalizedtime" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.binarytime), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_TimeOfDay, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "binarytime" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.bcd), + (ASN_TAG_CLASS_CONTEXT | (13 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "bcd" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.booleanArray), + (ASN_TAG_CLASS_CONTEXT | (14 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "booleanArray" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.mMSString), + (ASN_TAG_CLASS_CONTEXT | (16 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_MMSString, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mMSString" + }, + { ATF_NOFLAGS, 0, offsetof(struct AccessResult, choice.utctime), + (ASN_TAG_CLASS_CONTEXT | (17 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_UtcTime, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "utctime" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_AccessResult_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* failure at 687 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* array at 689 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* structure at 690 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* boolean at 691 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* bitstring at 692 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* integer at 693 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 6, 0, 0 }, /* unsigned at 694 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 7, 0, 0 }, /* floatingpoint at 695 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 8, 0, 0 }, /* octetstring at 697 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 9, 0, 0 }, /* visiblestring at 698 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 10, 0, 0 }, /* generalizedtime at 699 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 11, 0, 0 }, /* binarytime at 700 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 12, 0, 0 }, /* bcd at 701 */ + { (ASN_TAG_CLASS_CONTEXT | (14 << 2)), 13, 0, 0 }, /* booleanArray at 702 */ + { (ASN_TAG_CLASS_CONTEXT | (16 << 2)), 14, 0, 0 }, /* mMSString at 705 */ + { (ASN_TAG_CLASS_CONTEXT | (17 << 2)), 15, 0, 0 } /* utctime at 709 */ +}; +static asn_CHOICE_specifics_t asn_SPC_AccessResult_specs_1 = { + sizeof(struct AccessResult), + offsetof(struct AccessResult, _asn_ctx), + offsetof(struct AccessResult, present), + sizeof(((struct AccessResult *)0)->present), + asn_MAP_AccessResult_tag2el_1, + 16, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_AccessResult = { + "AccessResult", + "AccessResult", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_AccessResult_1, + 16, /* Elements count */ + &asn_SPC_AccessResult_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/AccessResult.h b/src/mms/iso_mms/asn1c/AccessResult.h new file mode 100644 index 0000000..edaac44 --- /dev/null +++ b/src/mms/iso_mms/asn1c/AccessResult.h @@ -0,0 +1,87 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _AccessResult_H_ +#define _AccessResult_H_ + + +#include + +/* Including external dependencies */ +#include "DataAccessError.h" +#include "DataSequence.h" +#include +#include +#include +#include "FloatingPoint.h" +#include +#include +#include +#include "TimeOfDay.h" +#include "MMSString.h" +#include "UtcTime.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum AccessResult_PR { + AccessResult_PR_NOTHING, /* No components present */ + AccessResult_PR_failure, + AccessResult_PR_array, + AccessResult_PR_structure, + AccessResult_PR_boolean, + AccessResult_PR_bitstring, + AccessResult_PR_integer, + AccessResult_PR_unsigned, + AccessResult_PR_floatingpoint, + AccessResult_PR_octetstring, + AccessResult_PR_visiblestring, + AccessResult_PR_generalizedtime, + AccessResult_PR_binarytime, + AccessResult_PR_bcd, + AccessResult_PR_booleanArray, + AccessResult_PR_mMSString, + AccessResult_PR_utctime +} AccessResult_PR; + +/* AccessResult */ +typedef struct AccessResult { + AccessResult_PR present; + union AccessResult_u { + DataAccessError_t failure; + DataSequence_t array; + DataSequence_t structure; + BOOLEAN_t boolean; + BIT_STRING_t bitstring; + INTEGER_t integer; + INTEGER_t Unsigned; + FloatingPoint_t floatingpoint; + OCTET_STRING_t octetstring; + VisibleString_t visiblestring; + GeneralizedTime_t generalizedtime; + TimeOfDay_t binarytime; + INTEGER_t bcd; + BIT_STRING_t booleanArray; + MMSString_t mMSString; + UtcTime_t utctime; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} AccessResult_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_AccessResult; + +#ifdef __cplusplus +} +#endif + +#endif /* _AccessResult_H_ */ diff --git a/src/mms/iso_mms/asn1c/Address.c b/src/mms/iso_mms/asn1c/Address.c new file mode 100644 index 0000000..5b28a51 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Address.c @@ -0,0 +1,77 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Address.h" + +static asn_TYPE_member_t asn_MBR_Address_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Address, choice.numericAddress), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numericAddress" + }, + { ATF_NOFLAGS, 0, offsetof(struct Address, choice.symbolicAddress), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_VisibleString, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "symbolicAddress" + }, + { ATF_NOFLAGS, 0, offsetof(struct Address, choice.unconstrainedAddress), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unconstrainedAddress" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_Address_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* numericAddress at 792 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* symbolicAddress at 793 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* unconstrainedAddress at 794 */ +}; +static asn_CHOICE_specifics_t asn_SPC_Address_specs_1 = { + sizeof(struct Address), + offsetof(struct Address, _asn_ctx), + offsetof(struct Address, present), + sizeof(((struct Address *)0)->present), + asn_MAP_Address_tag2el_1, + 3, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_Address = { + "Address", + "Address", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_Address_1, + 3, /* Elements count */ + &asn_SPC_Address_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/Address.h b/src/mms/iso_mms/asn1c/Address.h new file mode 100644 index 0000000..4cd51d3 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Address.h @@ -0,0 +1,52 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Address_H_ +#define _Address_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum Address_PR { + Address_PR_NOTHING, /* No components present */ + Address_PR_numericAddress, + Address_PR_symbolicAddress, + Address_PR_unconstrainedAddress +} Address_PR; + +/* Address */ +typedef struct Address { + Address_PR present; + union Address_u { + Unsigned32_t numericAddress; + VisibleString_t symbolicAddress; + OCTET_STRING_t unconstrainedAddress; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Address_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Address; + +#ifdef __cplusplus +} +#endif + +#endif /* _Address_H_ */ diff --git a/src/mms/iso_mms/asn1c/AlternateAccess.c b/src/mms/iso_mms/asn1c/AlternateAccess.c new file mode 100644 index 0000000..1b5e01d --- /dev/null +++ b/src/mms/iso_mms/asn1c/AlternateAccess.c @@ -0,0 +1,181 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "AlternateAccess.h" + +static asn_TYPE_member_t asn_MBR_named_4[] = { + { ATF_NOFLAGS, 0, offsetof(struct named, componentName), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "componentName" + }, + { ATF_POINTER, 0, offsetof(struct named, access), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_AlternateAccessSelection, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "access" + }, +}; +static ber_tlv_tag_t asn_DEF_named_tags_4[] = { + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_named_tag2el_4[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 1 }, /* componentName at 540 */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 1, -1, 0 }, /* selectAlternateAccess at 555 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* component at 561 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* index at 562 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 1, 0, 0 }, /* indexRange at 564 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 } /* allElements at 567 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_named_specs_4 = { + sizeof(struct named), + offsetof(struct named, _asn_ctx), + asn_MAP_named_tag2el_4, + 6, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_named_4 = { + "named", + "named", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_named_tags_4, + sizeof(asn_DEF_named_tags_4) + /sizeof(asn_DEF_named_tags_4[0]) - 1, /* 1 */ + asn_DEF_named_tags_4, /* Same as above */ + sizeof(asn_DEF_named_tags_4) + /sizeof(asn_DEF_named_tags_4[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_named_4, + 2, /* Elements count */ + &asn_SPC_named_specs_4 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_Member_2[] = { + { ATF_POINTER, 0, offsetof(struct AlternateAccess__Member, choice.unnamed), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_AlternateAccessSelection, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unnamed" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccess__Member, choice.named), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_named_4, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "named" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_Member_tag2el_2[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* selectAlternateAccess at 555 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* component at 561 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 }, /* index at 562 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 0, 0, 0 }, /* indexRange at 564 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 0, 0, 0 }, /* allElements at 567 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 } /* named at 540 */ +}; +static asn_CHOICE_specifics_t asn_SPC_Member_specs_2 = { + sizeof(struct AlternateAccess__Member), + offsetof(struct AlternateAccess__Member, _asn_ctx), + offsetof(struct AlternateAccess__Member, present), + sizeof(((struct AlternateAccess__Member *)0)->present), + asn_MAP_Member_tag2el_2, + 6, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_Member_2 = { + "CHOICE", + "CHOICE", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_Member_2, + 2, /* Elements count */ + &asn_SPC_Member_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_AlternateAccess_1[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Member_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_AlternateAccess_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_AlternateAccess_specs_1 = { + sizeof(struct AlternateAccess), + offsetof(struct AlternateAccess, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +asn_TYPE_descriptor_t asn_DEF_AlternateAccess = { + "AlternateAccess", + "AlternateAccess", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_AlternateAccess_tags_1, + sizeof(asn_DEF_AlternateAccess_tags_1) + /sizeof(asn_DEF_AlternateAccess_tags_1[0]), /* 1 */ + asn_DEF_AlternateAccess_tags_1, /* Same as above */ + sizeof(asn_DEF_AlternateAccess_tags_1) + /sizeof(asn_DEF_AlternateAccess_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_AlternateAccess_1, + 1, /* Single element */ + &asn_SPC_AlternateAccess_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/AlternateAccess.h b/src/mms/iso_mms/asn1c/AlternateAccess.h new file mode 100644 index 0000000..4ac9d09 --- /dev/null +++ b/src/mms/iso_mms/asn1c/AlternateAccess.h @@ -0,0 +1,70 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _AlternateAccess_H_ +#define _AlternateAccess_H_ + + +#include + +/* Including external dependencies */ +#include +#include "Identifier.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum AlternateAccess__Member_PR { + AlternateAccess__Member_PR_NOTHING, /* No components present */ + AlternateAccess__Member_PR_unnamed, + AlternateAccess__Member_PR_named +} AlternateAccess__Member_PR; + +/* Forward declarations */ +struct AlternateAccessSelection; + +struct AlternateAccess__Member { + AlternateAccess__Member_PR present; + union AlternateAccess__Member_u { + struct AlternateAccessSelection *unnamed; + struct named { + Identifier_t componentName; + struct AlternateAccessSelection *access; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } named; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* AlternateAccess */ +typedef struct AlternateAccess { + A_SEQUENCE_OF(struct AlternateAccess__Member) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} AlternateAccess_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_AlternateAccess; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "AlternateAccessSelection.h" + +#endif /* _AlternateAccess_H_ */ diff --git a/src/mms/iso_mms/asn1c/AlternateAccessSelection.c b/src/mms/iso_mms/asn1c/AlternateAccessSelection.c new file mode 100644 index 0000000..89cea84 --- /dev/null +++ b/src/mms/iso_mms/asn1c/AlternateAccessSelection.c @@ -0,0 +1,413 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "AlternateAccessSelection.h" + +static asn_TYPE_member_t asn_MBR_indexRange_6[] = { + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection__indexRange, lowIndex), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "lowIndex" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection__indexRange, numberOfElements), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numberOfElements" + }, +}; +static ber_tlv_tag_t asn_DEF_indexRange_tags_6[] = { + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_indexRange_tag2el_6[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* lowIndex at 551 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* numberOfElements at 553 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_indexRange_specs_6 = { + sizeof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection__indexRange), + offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection__indexRange, _asn_ctx), + asn_MAP_indexRange_tag2el_6, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_indexRange_6 = { + "indexRange", + "indexRange", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_indexRange_tags_6, + sizeof(asn_DEF_indexRange_tags_6) + /sizeof(asn_DEF_indexRange_tags_6[0]) - 1, /* 1 */ + asn_DEF_indexRange_tags_6, /* Same as above */ + sizeof(asn_DEF_indexRange_tags_6) + /sizeof(asn_DEF_indexRange_tags_6[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_indexRange_6, + 2, /* Elements count */ + &asn_SPC_indexRange_specs_6 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_accessSelection_3[] = { + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection, choice.component), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "component" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection, choice.index), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "index" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection, choice.indexRange), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_indexRange_6, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "indexRange" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection, choice.allElements), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "allElements" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_accessSelection_tag2el_3[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* component at 548 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* index at 549 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* indexRange at 551 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 } /* allElements at 554 */ +}; +static asn_CHOICE_specifics_t asn_SPC_accessSelection_specs_3 = { + sizeof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection), + offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection, _asn_ctx), + offsetof(struct AlternateAccessSelection__selectAlternateAccess__accessSelection, present), + sizeof(((struct AlternateAccessSelection__selectAlternateAccess__accessSelection *)0)->present), + asn_MAP_accessSelection_tag2el_3, + 4, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_accessSelection_3 = { + "accessSelection", + "accessSelection", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_accessSelection_3, + 4, /* Elements count */ + &asn_SPC_accessSelection_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_selectAlternateAccess_2[] = { + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess, accessSelection), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_accessSelection_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "accessSelection" + }, + { ATF_POINTER, 0, offsetof(struct AlternateAccessSelection__selectAlternateAccess, alternateAccess), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_AlternateAccess, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "alternateAccess" + }, +}; +static ber_tlv_tag_t asn_DEF_selectAlternateAccess_tags_2[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_selectAlternateAccess_tag2el_2[] = { + { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 1, 0, 0 }, /* alternateAccess at 558 */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* component at 548 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* index at 549 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 }, /* indexRange at 551 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 0, 0, 0 } /* allElements at 554 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_selectAlternateAccess_specs_2 = { + sizeof(struct AlternateAccessSelection__selectAlternateAccess), + offsetof(struct AlternateAccessSelection__selectAlternateAccess, _asn_ctx), + asn_MAP_selectAlternateAccess_tag2el_2, + 5, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_selectAlternateAccess_2 = { + "selectAlternateAccess", + "selectAlternateAccess", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_selectAlternateAccess_tags_2, + sizeof(asn_DEF_selectAlternateAccess_tags_2) + /sizeof(asn_DEF_selectAlternateAccess_tags_2[0]) - 1, /* 1 */ + asn_DEF_selectAlternateAccess_tags_2, /* Same as above */ + sizeof(asn_DEF_selectAlternateAccess_tags_2) + /sizeof(asn_DEF_selectAlternateAccess_tags_2[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_selectAlternateAccess_2, + 2, /* Elements count */ + &asn_SPC_selectAlternateAccess_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_indexRange_14[] = { + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAccess__indexRange, lowIndex), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "lowIndex" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAccess__indexRange, numberOfElements), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numberOfElements" + }, +}; +static ber_tlv_tag_t asn_DEF_indexRange_tags_14[] = { + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_indexRange_tag2el_14[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* lowIndex at 564 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* numberOfElements at 566 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_indexRange_specs_14 = { + sizeof(struct AlternateAccessSelection__selectAccess__indexRange), + offsetof(struct AlternateAccessSelection__selectAccess__indexRange, _asn_ctx), + asn_MAP_indexRange_tag2el_14, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_indexRange_14 = { + "indexRange", + "indexRange", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_indexRange_tags_14, + sizeof(asn_DEF_indexRange_tags_14) + /sizeof(asn_DEF_indexRange_tags_14[0]) - 1, /* 1 */ + asn_DEF_indexRange_tags_14, /* Same as above */ + sizeof(asn_DEF_indexRange_tags_14) + /sizeof(asn_DEF_indexRange_tags_14[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_indexRange_14, + 2, /* Elements count */ + &asn_SPC_indexRange_specs_14 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_selectAccess_11[] = { + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAccess, choice.component), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "component" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAccess, choice.index), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "index" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAccess, choice.indexRange), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_indexRange_14, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "indexRange" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection__selectAccess, choice.allElements), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "allElements" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_selectAccess_tag2el_11[] = { + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* component at 561 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* index at 562 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 2, 0, 0 }, /* indexRange at 564 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 3, 0, 0 } /* allElements at 567 */ +}; +static asn_CHOICE_specifics_t asn_SPC_selectAccess_specs_11 = { + sizeof(struct AlternateAccessSelection__selectAccess), + offsetof(struct AlternateAccessSelection__selectAccess, _asn_ctx), + offsetof(struct AlternateAccessSelection__selectAccess, present), + sizeof(((struct AlternateAccessSelection__selectAccess *)0)->present), + asn_MAP_selectAccess_tag2el_11, + 4, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_selectAccess_11 = { + "selectAccess", + "selectAccess", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_selectAccess_11, + 4, /* Elements count */ + &asn_SPC_selectAccess_specs_11 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_AlternateAccessSelection_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection, choice.selectAlternateAccess), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_selectAlternateAccess_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "selectAlternateAccess" + }, + { ATF_NOFLAGS, 0, offsetof(struct AlternateAccessSelection, choice.selectAccess), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_selectAccess_11, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "selectAccess" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_AlternateAccessSelection_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* selectAlternateAccess at 555 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* component at 561 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* index at 562 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 1, 0, 0 }, /* indexRange at 564 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 } /* allElements at 567 */ +}; +static asn_CHOICE_specifics_t asn_SPC_AlternateAccessSelection_specs_1 = { + sizeof(struct AlternateAccessSelection), + offsetof(struct AlternateAccessSelection, _asn_ctx), + offsetof(struct AlternateAccessSelection, present), + sizeof(((struct AlternateAccessSelection *)0)->present), + asn_MAP_AlternateAccessSelection_tag2el_1, + 5, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_AlternateAccessSelection = { + "AlternateAccessSelection", + "AlternateAccessSelection", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_AlternateAccessSelection_1, + 2, /* Elements count */ + &asn_SPC_AlternateAccessSelection_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/AlternateAccessSelection.h b/src/mms/iso_mms/asn1c/AlternateAccessSelection.h new file mode 100644 index 0000000..a2bca8c --- /dev/null +++ b/src/mms/iso_mms/asn1c/AlternateAccessSelection.h @@ -0,0 +1,111 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _AlternateAccessSelection_H_ +#define _AlternateAccessSelection_H_ + + +#include + +/* Including external dependencies */ +#include "Identifier.h" +#include "Unsigned32.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum AlternateAccessSelection_PR { + AlternateAccessSelection_PR_NOTHING, /* No components present */ + AlternateAccessSelection_PR_selectAlternateAccess, + AlternateAccessSelection_PR_selectAccess +} AlternateAccessSelection_PR; +typedef enum AlternateAccessSelection__selectAlternateAccess__accessSelection_PR { + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_NOTHING, /* No components present */ + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component, + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index, + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_indexRange, + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_allElements +} AlternateAccessSelection__selectAlternateAccess__accessSelection_PR; +typedef enum AlternateAccessSelection__selectAccess_PR { + AlternateAccessSelection__selectAccess_PR_NOTHING, /* No components present */ + AlternateAccessSelection__selectAccess_PR_component, + AlternateAccessSelection__selectAccess_PR_index, + AlternateAccessSelection__selectAccess_PR_indexRange, + AlternateAccessSelection__selectAccess_PR_allElements +} AlternateAccessSelection__selectAccess_PR; + +/* Forward declarations */ +struct AlternateAccess; + +/* AlternateAccessSelection */ +typedef struct AlternateAccessSelection { + AlternateAccessSelection_PR present; + union AlternateAccessSelection_u { + struct AlternateAccessSelection__selectAlternateAccess { + struct AlternateAccessSelection__selectAlternateAccess__accessSelection { + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR present; + union AlternateAccessSelection__selectAlternateAccess__accessSelection_u { + Identifier_t component; + Unsigned32_t index; + struct AlternateAccessSelection__selectAlternateAccess__accessSelection__indexRange { + Unsigned32_t lowIndex; + Unsigned32_t numberOfElements; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } indexRange; + NULL_t allElements; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } accessSelection; + struct AlternateAccess *alternateAccess; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } selectAlternateAccess; + struct AlternateAccessSelection__selectAccess { + AlternateAccessSelection__selectAccess_PR present; + union AlternateAccessSelection__selectAccess_u { + Identifier_t component; + Unsigned32_t index; + struct AlternateAccessSelection__selectAccess__indexRange { + Unsigned32_t lowIndex; + Unsigned32_t numberOfElements; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } indexRange; + NULL_t allElements; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } selectAccess; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} AlternateAccessSelection_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_AlternateAccessSelection; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "AlternateAccess.h" + +#endif /* _AlternateAccessSelection_H_ */ diff --git a/src/mms/iso_mms/asn1c/BIT_STRING.c b/src/mms/iso_mms/asn1c/BIT_STRING.c new file mode 100644 index 0000000..6469d4f --- /dev/null +++ b/src/mms/iso_mms/asn1c/BIT_STRING.c @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * BIT STRING basic type description. + */ +static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) +}; +static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { + sizeof(BIT_STRING_t), + offsetof(BIT_STRING_t, _asn_ctx), + 1, /* Special indicator that this is a BIT STRING type */ +}; +asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { + "BIT STRING", + "BIT_STRING", + OCTET_STRING_free, /* Implemented in terms of OCTET STRING */ + BIT_STRING_print, + BIT_STRING_constraint, + OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_decode_xer_binary, + BIT_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BIT_STRING_tags, + sizeof(asn_DEF_BIT_STRING_tags) + / sizeof(asn_DEF_BIT_STRING_tags[0]), + asn_DEF_BIT_STRING_tags, /* Same as above */ + sizeof(asn_DEF_BIT_STRING_tags) + / sizeof(asn_DEF_BIT_STRING_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_DEF_BIT_STRING_specs +}; + +/* + * BIT STRING generic constraint. + */ +int +BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + + if(st && st->buf) { + if(st->size == 1 && st->bits_unused) { + _ASN_CTFAIL(app_key, td, + "%s: invalid padding byte (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + } else { + _ASN_CTFAIL(app_key, td, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + return 0; +} + +static char *_bit_pattern[16] = { + "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", + "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" +}; + +asn_enc_rval_t +BIT_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + char scratch[128]; + char *p = scratch; + char *scend = scratch + (sizeof(scratch) - 10); + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + int xcan = (flags & XER_F_CANONICAL); + uint8_t *buf; + uint8_t *end; + + if(!st || !st->buf) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + buf = st->buf; + end = buf + st->size - 1; /* Last byte is special */ + + /* + * Binary dump + */ + for(; buf < end; buf++) { + int v = *buf; + int nline = xcan?0:(((buf - st->buf) % 8) == 0); + if(p >= scend || nline) { + er.encoded += p - scratch; + _ASN_CALLBACK(scratch, p - scratch); + p = scratch; + if(nline) _i_ASN_TEXT_INDENT(1, ilevel); + } + memcpy(p + 0, _bit_pattern[v >> 4], 4); + memcpy(p + 4, _bit_pattern[v & 0x0f], 4); + p += 8; + } + + if(!xcan && ((buf - st->buf) % 8) == 0) + _i_ASN_TEXT_INDENT(1, ilevel); + er.encoded += p - scratch; + _ASN_CALLBACK(scratch, p - scratch); + p = scratch; + + if(buf == end) { + int v = *buf; + int ubits = st->bits_unused; + int i; + for(i = 7; i >= ubits; i--) + *p++ = (v & (1 << i)) ? 0x31 : 0x30; + er.encoded += p - scratch; + _ASN_CALLBACK(scratch, p - scratch); + } + + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + + +/* + * BIT STRING specific contents printer. + */ +int +BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + static const char *h2c = "0123456789ABCDEF"; + char scratch[64]; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + uint8_t *buf; + uint8_t *end; + char *p = scratch; + + (void)td; /* Unused argument */ + + if(!st || !st->buf) + return (cb("", 8, app_key) < 0) ? -1 : 0; + + ilevel++; + buf = st->buf; + end = buf + st->size; + + /* + * Hexadecimal dump. + */ + for(; buf < end; buf++) { + if((buf - st->buf) % 16 == 0 && (st->size > 16) + && buf != st->buf) { + _i_INDENT(1); + /* Dump the string */ + if(cb(scratch, p - scratch, app_key) < 0) return -1; + p = scratch; + } + *p++ = h2c[*buf >> 4]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + + if(p > scratch) { + p--; /* Eat the tailing space */ + + if((st->size > 16)) { + _i_INDENT(1); + } + + /* Dump the incomplete 16-bytes row */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + } + + return 0; +} + diff --git a/src/mms/iso_mms/asn1c/BIT_STRING.h b/src/mms/iso_mms/asn1c/BIT_STRING.h new file mode 100644 index 0000000..732e878 --- /dev/null +++ b/src/mms/iso_mms/asn1c/BIT_STRING.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BIT_STRING_H_ +#define _BIT_STRING_H_ + +#include /* Some help from OCTET STRING */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BIT_STRING_s { + uint8_t *buf; /* BIT STRING body */ + int size; /* Size of the above buffer */ + + int bits_unused;/* Unused trailing bits in the last octet (0..7) */ + + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ +} BIT_STRING_t; + +extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; + +asn_struct_print_f BIT_STRING_print; /* Human-readable output */ +asn_constr_check_f BIT_STRING_constraint; +xer_type_encoder_f BIT_STRING_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _BIT_STRING_H_ */ diff --git a/src/mms/iso_mms/asn1c/BOOLEAN.c b/src/mms/iso_mms/asn1c/BOOLEAN.c new file mode 100644 index 0000000..2472a78 --- /dev/null +++ b/src/mms/iso_mms/asn1c/BOOLEAN.c @@ -0,0 +1,284 @@ +/*- + * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * BOOLEAN basic type description. + */ +static ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (1 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_BOOLEAN = { + "BOOLEAN", + "BOOLEAN", + BOOLEAN_free, + BOOLEAN_print, + asn_generic_no_constraint, + BOOLEAN_decode_ber, + BOOLEAN_encode_der, + BOOLEAN_decode_xer, + BOOLEAN_encode_xer, + BOOLEAN_decode_uper, /* Unaligned PER decoder */ + BOOLEAN_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BOOLEAN_tags, + sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), + asn_DEF_BOOLEAN_tags, /* Same as above */ + sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Decode BOOLEAN type. + */ +asn_dec_rval_t +BOOLEAN_decode_ber(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **bool_value, const void *buf_ptr, size_t size, + int tag_mode) { + BOOLEAN_t *st = (BOOLEAN_t *)*bool_value; + asn_dec_rval_t rval; + ber_tlv_len_t length; + ber_tlv_len_t lidx; + + if(st == NULL) { + st = (BOOLEAN_t *)(*bool_value = CALLOC(1, sizeof(*st))); + if(st == NULL) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } + + ASN_DEBUG("Decoding %s as BOOLEAN (tm=%d)", + td->name, tag_mode); + + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("Boolean length is %d bytes", (int)length); + + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + /* + * Compute boolean value. + */ + for(*st = 0, lidx = 0; + (lidx < length) && *st == 0; lidx++) { + /* + * Very simple approach: read bytes until the end or + * value is already TRUE. + * BOOLEAN is not supposed to contain meaningful data anyway. + */ + *st |= ((const uint8_t *)buf_ptr)[lidx]; + } + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s, value=%d", + (long)rval.consumed, (long)length, + td->name, *st); + + return rval; +} + +asn_enc_rval_t +BOOLEAN_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t erval; + BOOLEAN_t *st = (BOOLEAN_t *)sptr; + + erval.encoded = der_write_tags(td, 1, tag_mode, 0, tag, cb, app_key); + if(erval.encoded == -1) { + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + + if(cb) { + uint8_t bool_value; + + bool_value = *st ? 0x01 : 0; /* 0xff mandated by DER - 0x01 required by some IEDs */ + + if(cb(&bool_value, 1, app_key) < 0) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + } + + erval.encoded += 1; + + _ASN_ENCODED_OK(erval); +} + + +/* + * Decode the chunk of XML text encoding INTEGER. + */ +static enum xer_pbd_rval +BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { + BOOLEAN_t *st = (BOOLEAN_t *)sptr; + const char *p = (const char *)chunk_buf; + + (void)td; + + if(chunk_size && p[0] == 0x3c /* '<' */) { + switch(xer_check_tag(chunk_buf, chunk_size, "false")) { + case XCT_BOTH: + /* "" */ + *st = 0; + break; + case XCT_UNKNOWN_BO: + if(xer_check_tag(chunk_buf, chunk_size, "true") + != XCT_BOTH) + return XPBD_BROKEN_ENCODING; + /* "" */ + *st = 1; /* Or 0xff as in DER?.. */ + break; + default: + return XPBD_BROKEN_ENCODING; + } + return XPBD_BODY_CONSUMED; + } else { + if(xer_is_whitespace(chunk_buf, chunk_size)) + return XPBD_NOT_BODY_IGNORE; + else + return XPBD_BROKEN_ENCODING; + } +} + + +asn_dec_rval_t +BOOLEAN_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(BOOLEAN_t), opt_mname, buf_ptr, size, + BOOLEAN__xer_body_decode); +} + +asn_enc_rval_t +BOOLEAN_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + asn_enc_rval_t er; + + (void)ilevel; + (void)flags; + + if(!st) _ASN_ENCODE_FAILED; + + if(*st) { + _ASN_CALLBACK("", 7); + er.encoded = 7; + } else { + _ASN_CALLBACK("", 8); + er.encoded = 8; + } + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +int +BOOLEAN_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + const char *buf; + size_t buflen; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st) { + if(*st) { + buf = "TRUE"; + buflen = 4; + } else { + buf = "FALSE"; + buflen = 5; + } + } else { + buf = ""; + buflen = 8; + } + + return (cb(buf, buflen, app_key) < 0) ? -1 : 0; +} + +void +BOOLEAN_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + if(td && ptr && !contents_only) { + FREEMEM(ptr); + } +} + +asn_dec_rval_t +BOOLEAN_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + BOOLEAN_t *st = (BOOLEAN_t *)*sptr; + + (void)opt_codec_ctx; + (void)constraints; + + if(!st) { + st = (BOOLEAN_t *)(*sptr = MALLOC(sizeof(*st))); + if(!st) _ASN_DECODE_FAILED; + } + + /* + * Extract a single bit + */ + switch(per_get_few_bits(pd, 1)) { + case 1: *st = 1; break; + case 0: *st = 0; break; + case -1: default: _ASN_DECODE_FAILED; + } + + ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE"); + + rv.code = RC_OK; + rv.consumed = 1; + return rv; +} + + +asn_enc_rval_t +BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + asn_enc_rval_t er; + + (void)constraints; + + if(!st) _ASN_ENCODE_FAILED; + + per_put_few_bits(po, *st ? 1 : 0, 1); + + _ASN_ENCODED_OK(er); +} diff --git a/src/mms/iso_mms/asn1c/BOOLEAN.h b/src/mms/iso_mms/asn1c/BOOLEAN.h new file mode 100644 index 0000000..217d0f1 --- /dev/null +++ b/src/mms/iso_mms/asn1c/BOOLEAN.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BOOLEAN_H_ +#define _BOOLEAN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The underlying integer may contain various values, but everything + * non-zero is capped to 0xff by the DER encoder. The BER decoder may + * yield non-zero values different from 1, beware. + */ +typedef int BOOLEAN_t; + +extern asn_TYPE_descriptor_t asn_DEF_BOOLEAN; + +asn_struct_free_f BOOLEAN_free; +asn_struct_print_f BOOLEAN_print; +ber_type_decoder_f BOOLEAN_decode_ber; +der_type_encoder_f BOOLEAN_encode_der; +xer_type_decoder_f BOOLEAN_decode_xer; +xer_type_encoder_f BOOLEAN_encode_xer; +per_type_decoder_f BOOLEAN_decode_uper; +per_type_encoder_f BOOLEAN_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _BOOLEAN_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConcludeRequestPDU.c b/src/mms/iso_mms/asn1c/ConcludeRequestPDU.c new file mode 100644 index 0000000..edba970 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConcludeRequestPDU.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConcludeRequestPDU.h" + +int +ConcludeRequestPDU_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_NULL.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using NULL, + * so here we adjust the DEF accordingly. + */ +static void +ConcludeRequestPDU_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NULL.free_struct; + td->print_struct = asn_DEF_NULL.print_struct; + td->ber_decoder = asn_DEF_NULL.ber_decoder; + td->der_encoder = asn_DEF_NULL.der_encoder; + td->xer_decoder = asn_DEF_NULL.xer_decoder; + td->xer_encoder = asn_DEF_NULL.xer_encoder; + td->uper_decoder = asn_DEF_NULL.uper_decoder; + td->uper_encoder = asn_DEF_NULL.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NULL.per_constraints; + td->elements = asn_DEF_NULL.elements; + td->elements_count = asn_DEF_NULL.elements_count; + td->specifics = asn_DEF_NULL.specifics; +} + +void +ConcludeRequestPDU_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + ConcludeRequestPDU_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +ConcludeRequestPDU_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + ConcludeRequestPDU_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +ConcludeRequestPDU_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + ConcludeRequestPDU_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +ConcludeRequestPDU_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + ConcludeRequestPDU_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +ConcludeRequestPDU_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + ConcludeRequestPDU_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +ConcludeRequestPDU_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + ConcludeRequestPDU_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_ConcludeRequestPDU_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (5 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_ConcludeRequestPDU = { + "ConcludeRequestPDU", + "ConcludeRequestPDU", + ConcludeRequestPDU_free, + ConcludeRequestPDU_print, + ConcludeRequestPDU_constraint, + ConcludeRequestPDU_decode_ber, + ConcludeRequestPDU_encode_der, + ConcludeRequestPDU_decode_xer, + ConcludeRequestPDU_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ConcludeRequestPDU_tags_1, + sizeof(asn_DEF_ConcludeRequestPDU_tags_1) + /sizeof(asn_DEF_ConcludeRequestPDU_tags_1[0]), /* 1 */ + asn_DEF_ConcludeRequestPDU_tags_1, /* Same as above */ + sizeof(asn_DEF_ConcludeRequestPDU_tags_1) + /sizeof(asn_DEF_ConcludeRequestPDU_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConcludeRequestPDU.h b/src/mms/iso_mms/asn1c/ConcludeRequestPDU.h new file mode 100644 index 0000000..719c5be --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConcludeRequestPDU.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConcludeRequestPDU_H_ +#define _ConcludeRequestPDU_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConcludeRequestPDU */ +typedef NULL_t ConcludeRequestPDU_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConcludeRequestPDU; +asn_struct_free_f ConcludeRequestPDU_free; +asn_struct_print_f ConcludeRequestPDU_print; +asn_constr_check_f ConcludeRequestPDU_constraint; +ber_type_decoder_f ConcludeRequestPDU_decode_ber; +der_type_encoder_f ConcludeRequestPDU_encode_der; +xer_type_decoder_f ConcludeRequestPDU_decode_xer; +xer_type_encoder_f ConcludeRequestPDU_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConcludeRequestPDU_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConcludeResponsePDU.c b/src/mms/iso_mms/asn1c/ConcludeResponsePDU.c new file mode 100644 index 0000000..525650d --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConcludeResponsePDU.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConcludeResponsePDU.h" + +int +ConcludeResponsePDU_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_NULL.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using NULL, + * so here we adjust the DEF accordingly. + */ +static void +ConcludeResponsePDU_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NULL.free_struct; + td->print_struct = asn_DEF_NULL.print_struct; + td->ber_decoder = asn_DEF_NULL.ber_decoder; + td->der_encoder = asn_DEF_NULL.der_encoder; + td->xer_decoder = asn_DEF_NULL.xer_decoder; + td->xer_encoder = asn_DEF_NULL.xer_encoder; + td->uper_decoder = asn_DEF_NULL.uper_decoder; + td->uper_encoder = asn_DEF_NULL.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NULL.per_constraints; + td->elements = asn_DEF_NULL.elements; + td->elements_count = asn_DEF_NULL.elements_count; + td->specifics = asn_DEF_NULL.specifics; +} + +void +ConcludeResponsePDU_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + ConcludeResponsePDU_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +ConcludeResponsePDU_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + ConcludeResponsePDU_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +ConcludeResponsePDU_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + ConcludeResponsePDU_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +ConcludeResponsePDU_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + ConcludeResponsePDU_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +ConcludeResponsePDU_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + ConcludeResponsePDU_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +ConcludeResponsePDU_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + ConcludeResponsePDU_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_ConcludeResponsePDU_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (5 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_ConcludeResponsePDU = { + "ConcludeResponsePDU", + "ConcludeResponsePDU", + ConcludeResponsePDU_free, + ConcludeResponsePDU_print, + ConcludeResponsePDU_constraint, + ConcludeResponsePDU_decode_ber, + ConcludeResponsePDU_encode_der, + ConcludeResponsePDU_decode_xer, + ConcludeResponsePDU_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ConcludeResponsePDU_tags_1, + sizeof(asn_DEF_ConcludeResponsePDU_tags_1) + /sizeof(asn_DEF_ConcludeResponsePDU_tags_1[0]), /* 1 */ + asn_DEF_ConcludeResponsePDU_tags_1, /* Same as above */ + sizeof(asn_DEF_ConcludeResponsePDU_tags_1) + /sizeof(asn_DEF_ConcludeResponsePDU_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConcludeResponsePDU.h b/src/mms/iso_mms/asn1c/ConcludeResponsePDU.h new file mode 100644 index 0000000..b33f27a --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConcludeResponsePDU.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConcludeResponsePDU_H_ +#define _ConcludeResponsePDU_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConcludeResponsePDU */ +typedef NULL_t ConcludeResponsePDU_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConcludeResponsePDU; +asn_struct_free_f ConcludeResponsePDU_free; +asn_struct_print_f ConcludeResponsePDU_print; +asn_constr_check_f ConcludeResponsePDU_constraint; +ber_type_decoder_f ConcludeResponsePDU_decode_ber; +der_type_encoder_f ConcludeResponsePDU_encode_der; +xer_type_decoder_f ConcludeResponsePDU_decode_xer; +xer_type_encoder_f ConcludeResponsePDU_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConcludeResponsePDU_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConfirmedErrorPDU.c b/src/mms/iso_mms/asn1c/ConfirmedErrorPDU.c new file mode 100644 index 0000000..2f81272 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedErrorPDU.c @@ -0,0 +1,71 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConfirmedErrorPDU.h" + +static asn_TYPE_member_t asn_MBR_ConfirmedErrorPDU_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedErrorPDU, invokeID), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "invokeID" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedErrorPDU, serviceError), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ServiceError, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "serviceError" + }, +}; +static ber_tlv_tag_t asn_DEF_ConfirmedErrorPDU_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ConfirmedErrorPDU_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* invokeID at 95 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 } /* serviceError at 98 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ConfirmedErrorPDU_specs_1 = { + sizeof(struct ConfirmedErrorPDU), + offsetof(struct ConfirmedErrorPDU, _asn_ctx), + asn_MAP_ConfirmedErrorPDU_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ConfirmedErrorPDU = { + "ConfirmedErrorPDU", + "ConfirmedErrorPDU", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ConfirmedErrorPDU_tags_1, + sizeof(asn_DEF_ConfirmedErrorPDU_tags_1) + /sizeof(asn_DEF_ConfirmedErrorPDU_tags_1[0]), /* 1 */ + asn_DEF_ConfirmedErrorPDU_tags_1, /* Same as above */ + sizeof(asn_DEF_ConfirmedErrorPDU_tags_1) + /sizeof(asn_DEF_ConfirmedErrorPDU_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ConfirmedErrorPDU_1, + 2, /* Elements count */ + &asn_SPC_ConfirmedErrorPDU_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConfirmedErrorPDU.h b/src/mms/iso_mms/asn1c/ConfirmedErrorPDU.h new file mode 100644 index 0000000..914f503 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedErrorPDU.h @@ -0,0 +1,39 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConfirmedErrorPDU_H_ +#define _ConfirmedErrorPDU_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include "ServiceError.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConfirmedErrorPDU */ +typedef struct ConfirmedErrorPDU { + Unsigned32_t invokeID; + ServiceError_t serviceError; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ConfirmedErrorPDU_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConfirmedErrorPDU; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConfirmedErrorPDU_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConfirmedRequestPdu.c b/src/mms/iso_mms/asn1c/ConfirmedRequestPdu.c new file mode 100644 index 0000000..7b2d708 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedRequestPdu.c @@ -0,0 +1,77 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConfirmedRequestPdu.h" + +static asn_TYPE_member_t asn_MBR_ConfirmedRequestPdu_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedRequestPdu, invokeID), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), + 0, + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "invokeID" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedRequestPdu, confirmedServiceRequest), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_ConfirmedServiceRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedServiceRequest" + }, +}; +static ber_tlv_tag_t asn_DEF_ConfirmedRequestPdu_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ConfirmedRequestPdu_tag2el_1[] = { + { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 0 }, /* invokeID at 114 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* getNameList at 127 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 }, /* read at 128 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 }, /* write at 129 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 1, 0, 0 }, /* getVariableAccessAttributes at 130 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 1, 0, 0 }, /* defineNamedVariableList at 131 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 1, 0, 0 }, /* getNamedVariableListAttributes at 132 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 1, 0, 0 } /* deleteNamedVariableList at 136 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ConfirmedRequestPdu_specs_1 = { + sizeof(struct ConfirmedRequestPdu), + offsetof(struct ConfirmedRequestPdu, _asn_ctx), + asn_MAP_ConfirmedRequestPdu_tag2el_1, + 8, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ConfirmedRequestPdu = { + "ConfirmedRequestPdu", + "ConfirmedRequestPdu", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ConfirmedRequestPdu_tags_1, + sizeof(asn_DEF_ConfirmedRequestPdu_tags_1) + /sizeof(asn_DEF_ConfirmedRequestPdu_tags_1[0]), /* 1 */ + asn_DEF_ConfirmedRequestPdu_tags_1, /* Same as above */ + sizeof(asn_DEF_ConfirmedRequestPdu_tags_1) + /sizeof(asn_DEF_ConfirmedRequestPdu_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ConfirmedRequestPdu_1, + 2, /* Elements count */ + &asn_SPC_ConfirmedRequestPdu_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConfirmedRequestPdu.h b/src/mms/iso_mms/asn1c/ConfirmedRequestPdu.h new file mode 100644 index 0000000..b37b981 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedRequestPdu.h @@ -0,0 +1,39 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConfirmedRequestPdu_H_ +#define _ConfirmedRequestPdu_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include "ConfirmedServiceRequest.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConfirmedRequestPdu */ +typedef struct ConfirmedRequestPdu { + Unsigned32_t invokeID; + ConfirmedServiceRequest_t confirmedServiceRequest; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ConfirmedRequestPdu_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConfirmedRequestPdu; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConfirmedRequestPdu_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConfirmedResponsePdu.c b/src/mms/iso_mms/asn1c/ConfirmedResponsePdu.c new file mode 100644 index 0000000..7338201 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedResponsePdu.c @@ -0,0 +1,77 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConfirmedResponsePdu.h" + +static asn_TYPE_member_t asn_MBR_ConfirmedResponsePdu_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedResponsePdu, invokeID), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), + 0, + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "invokeID" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedResponsePdu, confirmedServiceResponse), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_ConfirmedServiceResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedServiceResponse" + }, +}; +static ber_tlv_tag_t asn_DEF_ConfirmedResponsePdu_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ConfirmedResponsePdu_tag2el_1[] = { + { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 0 }, /* invokeID at 121 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* getNameList at 140 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 }, /* read at 141 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 }, /* write at 142 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 1, 0, 0 }, /* getVariableAccessAttributes at 143 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 1, 0, 0 }, /* defineNamedVariableList at 144 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 1, 0, 0 }, /* getNamedVariableListAttributes at 145 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 1, 0, 0 } /* deleteNamedVariableList at 147 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ConfirmedResponsePdu_specs_1 = { + sizeof(struct ConfirmedResponsePdu), + offsetof(struct ConfirmedResponsePdu, _asn_ctx), + asn_MAP_ConfirmedResponsePdu_tag2el_1, + 8, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ConfirmedResponsePdu = { + "ConfirmedResponsePdu", + "ConfirmedResponsePdu", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ConfirmedResponsePdu_tags_1, + sizeof(asn_DEF_ConfirmedResponsePdu_tags_1) + /sizeof(asn_DEF_ConfirmedResponsePdu_tags_1[0]), /* 1 */ + asn_DEF_ConfirmedResponsePdu_tags_1, /* Same as above */ + sizeof(asn_DEF_ConfirmedResponsePdu_tags_1) + /sizeof(asn_DEF_ConfirmedResponsePdu_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ConfirmedResponsePdu_1, + 2, /* Elements count */ + &asn_SPC_ConfirmedResponsePdu_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConfirmedResponsePdu.h b/src/mms/iso_mms/asn1c/ConfirmedResponsePdu.h new file mode 100644 index 0000000..9b62d00 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedResponsePdu.h @@ -0,0 +1,39 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConfirmedResponsePdu_H_ +#define _ConfirmedResponsePdu_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include "ConfirmedServiceResponse.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConfirmedResponsePdu */ +typedef struct ConfirmedResponsePdu { + Unsigned32_t invokeID; + ConfirmedServiceResponse_t confirmedServiceResponse; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ConfirmedResponsePdu_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConfirmedResponsePdu; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConfirmedResponsePdu_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConfirmedServiceRequest.c b/src/mms/iso_mms/asn1c/ConfirmedServiceRequest.c new file mode 100644 index 0000000..610903a --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedServiceRequest.c @@ -0,0 +1,117 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConfirmedServiceRequest.h" + +static asn_TYPE_member_t asn_MBR_ConfirmedServiceRequest_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.getNameList), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_GetNameListRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "getNameList" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.read), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ReadRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "read" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.write), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_WriteRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "write" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.getVariableAccessAttributes), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_GetVariableAccessAttributesRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "getVariableAccessAttributes" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.defineNamedVariableList), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DefineNamedVariableListRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "defineNamedVariableList" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.getNamedVariableListAttributes), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_GetNamedVariableListAttributesRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "getNamedVariableListAttributes" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceRequest, choice.deleteNamedVariableList), + (ASN_TAG_CLASS_CONTEXT | (13 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DeleteNamedVariableListRequest, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "deleteNamedVariableList" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_ConfirmedServiceRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* getNameList at 127 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 }, /* read at 128 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 2, 0, 0 }, /* write at 129 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 3, 0, 0 }, /* getVariableAccessAttributes at 130 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 4, 0, 0 }, /* defineNamedVariableList at 131 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 5, 0, 0 }, /* getNamedVariableListAttributes at 132 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 6, 0, 0 } /* deleteNamedVariableList at 136 */ +}; +static asn_CHOICE_specifics_t asn_SPC_ConfirmedServiceRequest_specs_1 = { + sizeof(struct ConfirmedServiceRequest), + offsetof(struct ConfirmedServiceRequest, _asn_ctx), + offsetof(struct ConfirmedServiceRequest, present), + sizeof(((struct ConfirmedServiceRequest *)0)->present), + asn_MAP_ConfirmedServiceRequest_tag2el_1, + 7, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_ConfirmedServiceRequest = { + "ConfirmedServiceRequest", + "ConfirmedServiceRequest", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_ConfirmedServiceRequest_1, + 7, /* Elements count */ + &asn_SPC_ConfirmedServiceRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConfirmedServiceRequest.h b/src/mms/iso_mms/asn1c/ConfirmedServiceRequest.h new file mode 100644 index 0000000..9efee04 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedServiceRequest.h @@ -0,0 +1,64 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConfirmedServiceRequest_H_ +#define _ConfirmedServiceRequest_H_ + + +#include + +/* Including external dependencies */ +#include "GetNameListRequest.h" +#include "ReadRequest.h" +#include "WriteRequest.h" +#include "GetVariableAccessAttributesRequest.h" +#include "DefineNamedVariableListRequest.h" +#include "GetNamedVariableListAttributesRequest.h" +#include "DeleteNamedVariableListRequest.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ConfirmedServiceRequest_PR { + ConfirmedServiceRequest_PR_NOTHING, /* No components present */ + ConfirmedServiceRequest_PR_getNameList, + ConfirmedServiceRequest_PR_read, + ConfirmedServiceRequest_PR_write, + ConfirmedServiceRequest_PR_getVariableAccessAttributes, + ConfirmedServiceRequest_PR_defineNamedVariableList, + ConfirmedServiceRequest_PR_getNamedVariableListAttributes, + ConfirmedServiceRequest_PR_deleteNamedVariableList +} ConfirmedServiceRequest_PR; + +/* ConfirmedServiceRequest */ +typedef struct ConfirmedServiceRequest { + ConfirmedServiceRequest_PR present; + union ConfirmedServiceRequest_u { + GetNameListRequest_t getNameList; + ReadRequest_t read; + WriteRequest_t write; + GetVariableAccessAttributesRequest_t getVariableAccessAttributes; + DefineNamedVariableListRequest_t defineNamedVariableList; + GetNamedVariableListAttributesRequest_t getNamedVariableListAttributes; + DeleteNamedVariableListRequest_t deleteNamedVariableList; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ConfirmedServiceRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConfirmedServiceRequest; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConfirmedServiceRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/ConfirmedServiceResponse.c b/src/mms/iso_mms/asn1c/ConfirmedServiceResponse.c new file mode 100644 index 0000000..1c92d34 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedServiceResponse.c @@ -0,0 +1,117 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ConfirmedServiceResponse.h" + +static asn_TYPE_member_t asn_MBR_ConfirmedServiceResponse_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.getNameList), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_GetNameListResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "getNameList" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.read), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ReadResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "read" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.write), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_WriteResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "write" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.getVariableAccessAttributes), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_GetVariableAccessAttributesResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "getVariableAccessAttributes" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.defineNamedVariableList), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DefineNamedVariableListResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "defineNamedVariableList" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.getNamedVariableListAttributes), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_GetNamedVariableListAttributesResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "getNamedVariableListAttributes" + }, + { ATF_NOFLAGS, 0, offsetof(struct ConfirmedServiceResponse, choice.deleteNamedVariableList), + (ASN_TAG_CLASS_CONTEXT | (13 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DeleteNamedVariableListResponse, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "deleteNamedVariableList" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_ConfirmedServiceResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* getNameList at 140 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 }, /* read at 141 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 2, 0, 0 }, /* write at 142 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 3, 0, 0 }, /* getVariableAccessAttributes at 143 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 4, 0, 0 }, /* defineNamedVariableList at 144 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 5, 0, 0 }, /* getNamedVariableListAttributes at 145 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 6, 0, 0 } /* deleteNamedVariableList at 147 */ +}; +static asn_CHOICE_specifics_t asn_SPC_ConfirmedServiceResponse_specs_1 = { + sizeof(struct ConfirmedServiceResponse), + offsetof(struct ConfirmedServiceResponse, _asn_ctx), + offsetof(struct ConfirmedServiceResponse, present), + sizeof(((struct ConfirmedServiceResponse *)0)->present), + asn_MAP_ConfirmedServiceResponse_tag2el_1, + 7, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_ConfirmedServiceResponse = { + "ConfirmedServiceResponse", + "ConfirmedServiceResponse", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_ConfirmedServiceResponse_1, + 7, /* Elements count */ + &asn_SPC_ConfirmedServiceResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ConfirmedServiceResponse.h b/src/mms/iso_mms/asn1c/ConfirmedServiceResponse.h new file mode 100644 index 0000000..e4458e0 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ConfirmedServiceResponse.h @@ -0,0 +1,64 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ConfirmedServiceResponse_H_ +#define _ConfirmedServiceResponse_H_ + + +#include + +/* Including external dependencies */ +#include "GetNameListResponse.h" +#include "ReadResponse.h" +#include "WriteResponse.h" +#include "GetVariableAccessAttributesResponse.h" +#include "DefineNamedVariableListResponse.h" +#include "GetNamedVariableListAttributesResponse.h" +#include "DeleteNamedVariableListResponse.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ConfirmedServiceResponse_PR { + ConfirmedServiceResponse_PR_NOTHING, /* No components present */ + ConfirmedServiceResponse_PR_getNameList, + ConfirmedServiceResponse_PR_read, + ConfirmedServiceResponse_PR_write, + ConfirmedServiceResponse_PR_getVariableAccessAttributes, + ConfirmedServiceResponse_PR_defineNamedVariableList, + ConfirmedServiceResponse_PR_getNamedVariableListAttributes, + ConfirmedServiceResponse_PR_deleteNamedVariableList +} ConfirmedServiceResponse_PR; + +/* ConfirmedServiceResponse */ +typedef struct ConfirmedServiceResponse { + ConfirmedServiceResponse_PR present; + union ConfirmedServiceResponse_u { + GetNameListResponse_t getNameList; + ReadResponse_t read; + WriteResponse_t write; + GetVariableAccessAttributesResponse_t getVariableAccessAttributes; + DefineNamedVariableListResponse_t defineNamedVariableList; + GetNamedVariableListAttributesResponse_t getNamedVariableListAttributes; + DeleteNamedVariableListResponse_t deleteNamedVariableList; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ConfirmedServiceResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConfirmedServiceResponse; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConfirmedServiceResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/Data.c b/src/mms/iso_mms/asn1c/Data.c new file mode 100644 index 0000000..0409584 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Data.c @@ -0,0 +1,197 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Data.h" + +static asn_TYPE_member_t asn_MBR_Data_1[] = { + { ATF_POINTER, 0, offsetof(struct Data, choice.array), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DataSequence, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "array" + }, + { ATF_POINTER, 0, offsetof(struct Data, choice.structure), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DataSequence, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "structure" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.boolean), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "boolean" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.bitstring), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "bitstring" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.integer), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "integer" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.Unsigned), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unsigned" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.floatingpoint), + (ASN_TAG_CLASS_CONTEXT | (7 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_FloatingPoint, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "floatingpoint" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.octetstring), + (ASN_TAG_CLASS_CONTEXT | (9 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "octetstring" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.visiblestring), + (ASN_TAG_CLASS_CONTEXT | (10 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_VisibleString, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "visiblestring" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.generalizedtime), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_GeneralizedTime, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "generalizedtime" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.binarytime), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_TimeOfDay, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "binarytime" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.bcd), + (ASN_TAG_CLASS_CONTEXT | (13 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "bcd" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.booleanArray), + (ASN_TAG_CLASS_CONTEXT | (14 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BIT_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "booleanArray" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.mMSString), + (ASN_TAG_CLASS_CONTEXT | (16 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_MMSString, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mMSString" + }, + { ATF_NOFLAGS, 0, offsetof(struct Data, choice.utctime), + (ASN_TAG_CLASS_CONTEXT | (17 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_UtcTime, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "utctime" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_Data_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* array at 733 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* structure at 734 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 2, 0, 0 }, /* boolean at 735 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 3, 0, 0 }, /* bitstring at 736 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 4, 0, 0 }, /* integer at 737 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 5, 0, 0 }, /* unsigned at 738 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 6, 0, 0 }, /* floatingpoint at 739 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 7, 0, 0 }, /* octetstring at 741 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 8, 0, 0 }, /* visiblestring at 742 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 9, 0, 0 }, /* generalizedtime at 743 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 10, 0, 0 }, /* binarytime at 744 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 11, 0, 0 }, /* bcd at 745 */ + { (ASN_TAG_CLASS_CONTEXT | (14 << 2)), 12, 0, 0 }, /* booleanArray at 746 */ + { (ASN_TAG_CLASS_CONTEXT | (16 << 2)), 13, 0, 0 }, /* mMSString at 749 */ + { (ASN_TAG_CLASS_CONTEXT | (17 << 2)), 14, 0, 0 } /* utctime at 751 */ +}; +static asn_CHOICE_specifics_t asn_SPC_Data_specs_1 = { + sizeof(struct Data), + offsetof(struct Data, _asn_ctx), + offsetof(struct Data, present), + sizeof(((struct Data *)0)->present), + asn_MAP_Data_tag2el_1, + 15, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_Data = { + "Data", + "Data", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_Data_1, + 15, /* Elements count */ + &asn_SPC_Data_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/Data.h b/src/mms/iso_mms/asn1c/Data.h new file mode 100644 index 0000000..e8d039c --- /dev/null +++ b/src/mms/iso_mms/asn1c/Data.h @@ -0,0 +1,89 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Data_H_ +#define _Data_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include +#include "FloatingPoint.h" +#include +#include +#include +#include "TimeOfDay.h" +#include "MMSString.h" +#include "UtcTime.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum Data_PR { + Data_PR_NOTHING, /* No components present */ + Data_PR_array, + Data_PR_structure, + Data_PR_boolean, + Data_PR_bitstring, + Data_PR_integer, + Data_PR_unsigned, + Data_PR_floatingpoint, + Data_PR_octetstring, + Data_PR_visiblestring, + Data_PR_generalizedtime, + Data_PR_binarytime, + Data_PR_bcd, + Data_PR_booleanArray, + Data_PR_mMSString, + Data_PR_utctime +} Data_PR; + +/* Forward declarations */ +struct DataSequence; + +/* Data */ +typedef struct Data { + Data_PR present; + union Data_u { + struct DataSequence *array; + struct DataSequence *structure; + BOOLEAN_t boolean; + BIT_STRING_t bitstring; + INTEGER_t integer; + INTEGER_t Unsigned; + FloatingPoint_t floatingpoint; + OCTET_STRING_t octetstring; + VisibleString_t visiblestring; + GeneralizedTime_t generalizedtime; + TimeOfDay_t binarytime; + INTEGER_t bcd; + BIT_STRING_t booleanArray; + MMSString_t mMSString; + UtcTime_t utctime; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Data_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Data; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "DataSequence.h" + +#endif /* _Data_H_ */ diff --git a/src/mms/iso_mms/asn1c/DataAccessError.c b/src/mms/iso_mms/asn1c/DataAccessError.c new file mode 100644 index 0000000..cadc30a --- /dev/null +++ b/src/mms/iso_mms/asn1c/DataAccessError.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "DataAccessError.h" + +int +DataAccessError_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_INTEGER.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using INTEGER, + * so here we adjust the DEF accordingly. + */ +static void +DataAccessError_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_INTEGER.free_struct; + td->print_struct = asn_DEF_INTEGER.print_struct; + td->ber_decoder = asn_DEF_INTEGER.ber_decoder; + td->der_encoder = asn_DEF_INTEGER.der_encoder; + td->xer_decoder = asn_DEF_INTEGER.xer_decoder; + td->xer_encoder = asn_DEF_INTEGER.xer_encoder; + td->uper_decoder = asn_DEF_INTEGER.uper_decoder; + td->uper_encoder = asn_DEF_INTEGER.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_INTEGER.per_constraints; + td->elements = asn_DEF_INTEGER.elements; + td->elements_count = asn_DEF_INTEGER.elements_count; + td->specifics = asn_DEF_INTEGER.specifics; +} + +void +DataAccessError_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + DataAccessError_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +DataAccessError_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + DataAccessError_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +DataAccessError_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + DataAccessError_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +DataAccessError_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + DataAccessError_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +DataAccessError_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + DataAccessError_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +DataAccessError_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + DataAccessError_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_DataAccessError_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_DataAccessError = { + "DataAccessError", + "DataAccessError", + DataAccessError_free, + DataAccessError_print, + DataAccessError_constraint, + DataAccessError_decode_ber, + DataAccessError_encode_der, + DataAccessError_decode_xer, + DataAccessError_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_DataAccessError_tags_1, + sizeof(asn_DEF_DataAccessError_tags_1) + /sizeof(asn_DEF_DataAccessError_tags_1[0]), /* 1 */ + asn_DEF_DataAccessError_tags_1, /* Same as above */ + sizeof(asn_DEF_DataAccessError_tags_1) + /sizeof(asn_DEF_DataAccessError_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* Defined elsewhere */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/DataAccessError.h b/src/mms/iso_mms/asn1c/DataAccessError.h new file mode 100644 index 0000000..7bb2a0a --- /dev/null +++ b/src/mms/iso_mms/asn1c/DataAccessError.h @@ -0,0 +1,54 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _DataAccessError_H_ +#define _DataAccessError_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum DataAccessError { + DataAccessError_objectinvalidated = 0, + DataAccessError_hardwarefault = 1, + DataAccessError_temporarilyunavailable = 2, + DataAccessError_objectaccessdenied = 3, + DataAccessError_objectundefined = 4, + DataAccessError_invalidaddress = 5, + DataAccessError_typeunsupported = 6, + DataAccessError_typeinconsistent = 7, + DataAccessError_objectattributeinconsistent = 8, + DataAccessError_objectaccessunsupported = 9, + DataAccessError_objectnonexistent = 10, + DataAccessError_objectvalueinvalid = 11 +} e_DataAccessError; + +/* DataAccessError */ +typedef INTEGER_t DataAccessError_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_DataAccessError; +asn_struct_free_f DataAccessError_free; +asn_struct_print_f DataAccessError_print; +asn_constr_check_f DataAccessError_constraint; +ber_type_decoder_f DataAccessError_decode_ber; +der_type_encoder_f DataAccessError_encode_der; +xer_type_decoder_f DataAccessError_decode_xer; +xer_type_encoder_f DataAccessError_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _DataAccessError_H_ */ diff --git a/src/mms/iso_mms/asn1c/DataSequence.c b/src/mms/iso_mms/asn1c/DataSequence.c new file mode 100644 index 0000000..66d94f1 --- /dev/null +++ b/src/mms/iso_mms/asn1c/DataSequence.c @@ -0,0 +1,54 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "DataSequence.h" + +static asn_TYPE_member_t asn_MBR_DataSequence_1[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Data, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_DataSequence_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_DataSequence_specs_1 = { + sizeof(struct DataSequence), + offsetof(struct DataSequence, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +asn_TYPE_descriptor_t asn_DEF_DataSequence = { + "DataSequence", + "DataSequence", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_DataSequence_tags_1, + sizeof(asn_DEF_DataSequence_tags_1) + /sizeof(asn_DEF_DataSequence_tags_1[0]), /* 1 */ + asn_DEF_DataSequence_tags_1, /* Same as above */ + sizeof(asn_DEF_DataSequence_tags_1) + /sizeof(asn_DEF_DataSequence_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_DataSequence_1, + 1, /* Single element */ + &asn_SPC_DataSequence_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/DataSequence.h b/src/mms/iso_mms/asn1c/DataSequence.h new file mode 100644 index 0000000..a7a58fa --- /dev/null +++ b/src/mms/iso_mms/asn1c/DataSequence.h @@ -0,0 +1,43 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _DataSequence_H_ +#define _DataSequence_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct Data; + +/* DataSequence */ +typedef struct DataSequence { + A_SEQUENCE_OF(struct Data) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} DataSequence_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_DataSequence; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "Data.h" + +#endif /* _DataSequence_H_ */ diff --git a/src/mms/iso_mms/asn1c/DefineNamedVariableListRequest.c b/src/mms/iso_mms/asn1c/DefineNamedVariableListRequest.c new file mode 100644 index 0000000..1a53ffb --- /dev/null +++ b/src/mms/iso_mms/asn1c/DefineNamedVariableListRequest.c @@ -0,0 +1,183 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "DefineNamedVariableListRequest.h" + +static asn_TYPE_member_t asn_MBR_Member_4[] = { + { ATF_NOFLAGS, 0, offsetof(struct DefineNamedVariableListRequest__listOfVariable__Member, variableSpecification), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_VariableSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableSpecification" + }, + { ATF_POINTER, 1, offsetof(struct DefineNamedVariableListRequest__listOfVariable__Member, alternateAccess), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_AlternateAccess, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "alternateAccess" + }, +}; +static ber_tlv_tag_t asn_DEF_Member_tags_4[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_Member_tag2el_4[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* name at 772 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* address at 773 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 }, /* variableDescription at 776 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 0, 0, 0 }, /* scatteredAccessDescription at 779 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 0, 0, 0 }, /* invalidated at 780 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 } /* alternateAccess at 635 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Member_specs_4 = { + sizeof(struct DefineNamedVariableListRequest__listOfVariable__Member), + offsetof(struct DefineNamedVariableListRequest__listOfVariable__Member, _asn_ctx), + asn_MAP_Member_tag2el_4, + 6, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_Member_4 = { + "SEQUENCE", + "SEQUENCE", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Member_tags_4, + sizeof(asn_DEF_Member_tags_4) + /sizeof(asn_DEF_Member_tags_4[0]), /* 1 */ + asn_DEF_Member_tags_4, /* Same as above */ + sizeof(asn_DEF_Member_tags_4) + /sizeof(asn_DEF_Member_tags_4[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Member_4, + 2, /* Elements count */ + &asn_SPC_Member_specs_4 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_listOfVariable_3[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_Member_4, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfVariable_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfVariable_specs_3 = { + sizeof(struct DefineNamedVariableListRequest__listOfVariable), + offsetof(struct DefineNamedVariableListRequest__listOfVariable, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfVariable_3 = { + "listOfVariable", + "listOfVariable", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfVariable_tags_3, + sizeof(asn_DEF_listOfVariable_tags_3) + /sizeof(asn_DEF_listOfVariable_tags_3[0]) - 1, /* 1 */ + asn_DEF_listOfVariable_tags_3, /* Same as above */ + sizeof(asn_DEF_listOfVariable_tags_3) + /sizeof(asn_DEF_listOfVariable_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfVariable_3, + 1, /* Single element */ + &asn_SPC_listOfVariable_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_DefineNamedVariableListRequest_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct DefineNamedVariableListRequest, variableListName), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_ObjectName, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableListName" + }, + { ATF_NOFLAGS, 0, offsetof(struct DefineNamedVariableListRequest, listOfVariable), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfVariable_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfVariable" + }, +}; +static ber_tlv_tag_t asn_DEF_DefineNamedVariableListRequest_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_DefineNamedVariableListRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 1 }, /* vmdspecific at 169 */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 1, -1, 0 }, /* listOfVariable at 636 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* domainspecific at 172 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 } /* aaspecific at 176 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_DefineNamedVariableListRequest_specs_1 = { + sizeof(struct DefineNamedVariableListRequest), + offsetof(struct DefineNamedVariableListRequest, _asn_ctx), + asn_MAP_DefineNamedVariableListRequest_tag2el_1, + 4, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_DefineNamedVariableListRequest = { + "DefineNamedVariableListRequest", + "DefineNamedVariableListRequest", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_DefineNamedVariableListRequest_tags_1, + sizeof(asn_DEF_DefineNamedVariableListRequest_tags_1) + /sizeof(asn_DEF_DefineNamedVariableListRequest_tags_1[0]), /* 1 */ + asn_DEF_DefineNamedVariableListRequest_tags_1, /* Same as above */ + sizeof(asn_DEF_DefineNamedVariableListRequest_tags_1) + /sizeof(asn_DEF_DefineNamedVariableListRequest_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_DefineNamedVariableListRequest_1, + 2, /* Elements count */ + &asn_SPC_DefineNamedVariableListRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/DefineNamedVariableListRequest.h b/src/mms/iso_mms/asn1c/DefineNamedVariableListRequest.h new file mode 100644 index 0000000..93c4076 --- /dev/null +++ b/src/mms/iso_mms/asn1c/DefineNamedVariableListRequest.h @@ -0,0 +1,60 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _DefineNamedVariableListRequest_H_ +#define _DefineNamedVariableListRequest_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectName.h" +#include +#include "VariableSpecification.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct AlternateAccess; + +struct DefineNamedVariableListRequest__listOfVariable__Member { + VariableSpecification_t variableSpecification; + struct AlternateAccess *alternateAccess /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ; + +/* DefineNamedVariableListRequest */ +typedef struct DefineNamedVariableListRequest { + ObjectName_t variableListName; + struct DefineNamedVariableListRequest__listOfVariable { + A_SEQUENCE_OF(struct DefineNamedVariableListRequest__listOfVariable__Member) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } listOfVariable; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} DefineNamedVariableListRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_DefineNamedVariableListRequest; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "AlternateAccess.h" + +#endif /* _DefineNamedVariableListRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/DefineNamedVariableListResponse.c b/src/mms/iso_mms/asn1c/DefineNamedVariableListResponse.c new file mode 100644 index 0000000..87a8a59 --- /dev/null +++ b/src/mms/iso_mms/asn1c/DefineNamedVariableListResponse.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "DefineNamedVariableListResponse.h" + +int +DefineNamedVariableListResponse_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_NULL.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using NULL, + * so here we adjust the DEF accordingly. + */ +static void +DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NULL.free_struct; + td->print_struct = asn_DEF_NULL.print_struct; + td->ber_decoder = asn_DEF_NULL.ber_decoder; + td->der_encoder = asn_DEF_NULL.der_encoder; + td->xer_decoder = asn_DEF_NULL.xer_decoder; + td->xer_encoder = asn_DEF_NULL.xer_encoder; + td->uper_decoder = asn_DEF_NULL.uper_decoder; + td->uper_encoder = asn_DEF_NULL.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NULL.per_constraints; + td->elements = asn_DEF_NULL.elements; + td->elements_count = asn_DEF_NULL.elements_count; + td->specifics = asn_DEF_NULL.specifics; +} + +void +DefineNamedVariableListResponse_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +DefineNamedVariableListResponse_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +DefineNamedVariableListResponse_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +DefineNamedVariableListResponse_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +DefineNamedVariableListResponse_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +DefineNamedVariableListResponse_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + DefineNamedVariableListResponse_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_DefineNamedVariableListResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (5 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_DefineNamedVariableListResponse = { + "DefineNamedVariableListResponse", + "DefineNamedVariableListResponse", + DefineNamedVariableListResponse_free, + DefineNamedVariableListResponse_print, + DefineNamedVariableListResponse_constraint, + DefineNamedVariableListResponse_decode_ber, + DefineNamedVariableListResponse_encode_der, + DefineNamedVariableListResponse_decode_xer, + DefineNamedVariableListResponse_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_DefineNamedVariableListResponse_tags_1, + sizeof(asn_DEF_DefineNamedVariableListResponse_tags_1) + /sizeof(asn_DEF_DefineNamedVariableListResponse_tags_1[0]), /* 1 */ + asn_DEF_DefineNamedVariableListResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_DefineNamedVariableListResponse_tags_1) + /sizeof(asn_DEF_DefineNamedVariableListResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/DefineNamedVariableListResponse.h b/src/mms/iso_mms/asn1c/DefineNamedVariableListResponse.h new file mode 100644 index 0000000..201655e --- /dev/null +++ b/src/mms/iso_mms/asn1c/DefineNamedVariableListResponse.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _DefineNamedVariableListResponse_H_ +#define _DefineNamedVariableListResponse_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* DefineNamedVariableListResponse */ +typedef NULL_t DefineNamedVariableListResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_DefineNamedVariableListResponse; +asn_struct_free_f DefineNamedVariableListResponse_free; +asn_struct_print_f DefineNamedVariableListResponse_print; +asn_constr_check_f DefineNamedVariableListResponse_constraint; +ber_type_decoder_f DefineNamedVariableListResponse_decode_ber; +der_type_encoder_f DefineNamedVariableListResponse_encode_der; +xer_type_decoder_f DefineNamedVariableListResponse_decode_xer; +xer_type_encoder_f DefineNamedVariableListResponse_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _DefineNamedVariableListResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/DeleteNamedVariableListRequest.c b/src/mms/iso_mms/asn1c/DeleteNamedVariableListRequest.c new file mode 100644 index 0000000..f3a06a0 --- /dev/null +++ b/src/mms/iso_mms/asn1c/DeleteNamedVariableListRequest.c @@ -0,0 +1,146 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "DeleteNamedVariableListRequest.h" + +static int asn_DFL_2_set_0(int set_value, void **sptr) { + INTEGER_t *st = *sptr; + + if(!st) { + if(!set_value) return -1; /* Not a default value */ + st = (*sptr = CALLOC(1, sizeof(*st))); + if(!st) return -1; + } + + if(set_value) { + /* Install default value 0 */ + return asn_long2INTEGER(st, 0); + } else { + /* Test default value 0 */ + long value; + if(asn_INTEGER2long(st, &value)) + return -1; + return (value == 0); + } +} +static asn_TYPE_member_t asn_MBR_listOfVariableListName_7[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_ObjectName, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfVariableListName_tags_7[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfVariableListName_specs_7 = { + sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName), + offsetof(struct DeleteNamedVariableListRequest__listOfVariableListName, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfVariableListName_7 = { + "listOfVariableListName", + "listOfVariableListName", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfVariableListName_tags_7, + sizeof(asn_DEF_listOfVariableListName_tags_7) + /sizeof(asn_DEF_listOfVariableListName_tags_7[0]) - 1, /* 1 */ + asn_DEF_listOfVariableListName_tags_7, /* Same as above */ + sizeof(asn_DEF_listOfVariableListName_tags_7) + /sizeof(asn_DEF_listOfVariableListName_tags_7[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfVariableListName_7, + 1, /* Single element */ + &asn_SPC_listOfVariableListName_specs_7 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_DeleteNamedVariableListRequest_1[] = { + { ATF_POINTER, 3, offsetof(struct DeleteNamedVariableListRequest, scopeOfDelete), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + asn_DFL_2_set_0, /* DEFAULT 0 */ + "scopeOfDelete" + }, + { ATF_POINTER, 2, offsetof(struct DeleteNamedVariableListRequest, listOfVariableListName), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfVariableListName_7, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfVariableListName" + }, + { ATF_POINTER, 1, offsetof(struct DeleteNamedVariableListRequest, domainName), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "domainName" + }, +}; +static ber_tlv_tag_t asn_DEF_DeleteNamedVariableListRequest_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_DeleteNamedVariableListRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* scopeOfDelete at 663 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* listOfVariableListName at 668 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* domainName at 669 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_DeleteNamedVariableListRequest_specs_1 = { + sizeof(struct DeleteNamedVariableListRequest), + offsetof(struct DeleteNamedVariableListRequest, _asn_ctx), + asn_MAP_DeleteNamedVariableListRequest_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_DeleteNamedVariableListRequest = { + "DeleteNamedVariableListRequest", + "DeleteNamedVariableListRequest", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_DeleteNamedVariableListRequest_tags_1, + sizeof(asn_DEF_DeleteNamedVariableListRequest_tags_1) + /sizeof(asn_DEF_DeleteNamedVariableListRequest_tags_1[0]), /* 1 */ + asn_DEF_DeleteNamedVariableListRequest_tags_1, /* Same as above */ + sizeof(asn_DEF_DeleteNamedVariableListRequest_tags_1) + /sizeof(asn_DEF_DeleteNamedVariableListRequest_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_DeleteNamedVariableListRequest_1, + 3, /* Elements count */ + &asn_SPC_DeleteNamedVariableListRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/DeleteNamedVariableListRequest.h b/src/mms/iso_mms/asn1c/DeleteNamedVariableListRequest.h new file mode 100644 index 0000000..ac81dd8 --- /dev/null +++ b/src/mms/iso_mms/asn1c/DeleteNamedVariableListRequest.h @@ -0,0 +1,63 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _DeleteNamedVariableListRequest_H_ +#define _DeleteNamedVariableListRequest_H_ + + +#include + +/* Including external dependencies */ +#include +#include "Identifier.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum DeleteNamedVariableListRequest__scopeOfDelete { + DeleteNamedVariableListRequest__scopeOfDelete_specific = 0, + DeleteNamedVariableListRequest__scopeOfDelete_aaspecific = 1, + DeleteNamedVariableListRequest__scopeOfDelete_domain = 2, + DeleteNamedVariableListRequest__scopeOfDelete_vmd = 3 +} e_DeleteNamedVariableListRequest__scopeOfDelete; + +/* Forward declarations */ +struct ObjectName; + +struct DeleteNamedVariableListRequest__listOfVariableListName { + A_SEQUENCE_OF(struct ObjectName) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +}; + +/* DeleteNamedVariableListRequest */ +typedef struct DeleteNamedVariableListRequest { + INTEGER_t *scopeOfDelete /* DEFAULT 0 */; + struct DeleteNamedVariableListRequest__listOfVariableListName *listOfVariableListName; + Identifier_t *domainName /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} DeleteNamedVariableListRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_DeleteNamedVariableListRequest; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "ObjectName.h" + +#endif /* _DeleteNamedVariableListRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/DeleteNamedVariableListResponse.c b/src/mms/iso_mms/asn1c/DeleteNamedVariableListResponse.c new file mode 100644 index 0000000..adb5a58 --- /dev/null +++ b/src/mms/iso_mms/asn1c/DeleteNamedVariableListResponse.c @@ -0,0 +1,71 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "DeleteNamedVariableListResponse.h" + +static asn_TYPE_member_t asn_MBR_DeleteNamedVariableListResponse_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct DeleteNamedVariableListResponse, numberMatched), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numberMatched" + }, + { ATF_NOFLAGS, 0, offsetof(struct DeleteNamedVariableListResponse, numberDeleted), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numberDeleted" + }, +}; +static ber_tlv_tag_t asn_DEF_DeleteNamedVariableListResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_DeleteNamedVariableListResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* numberMatched at 675 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* numberDeleted at 677 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_DeleteNamedVariableListResponse_specs_1 = { + sizeof(struct DeleteNamedVariableListResponse), + offsetof(struct DeleteNamedVariableListResponse, _asn_ctx), + asn_MAP_DeleteNamedVariableListResponse_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_DeleteNamedVariableListResponse = { + "DeleteNamedVariableListResponse", + "DeleteNamedVariableListResponse", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_DeleteNamedVariableListResponse_tags_1, + sizeof(asn_DEF_DeleteNamedVariableListResponse_tags_1) + /sizeof(asn_DEF_DeleteNamedVariableListResponse_tags_1[0]), /* 1 */ + asn_DEF_DeleteNamedVariableListResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_DeleteNamedVariableListResponse_tags_1) + /sizeof(asn_DEF_DeleteNamedVariableListResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_DeleteNamedVariableListResponse_1, + 2, /* Elements count */ + &asn_SPC_DeleteNamedVariableListResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/DeleteNamedVariableListResponse.h b/src/mms/iso_mms/asn1c/DeleteNamedVariableListResponse.h new file mode 100644 index 0000000..3e117ff --- /dev/null +++ b/src/mms/iso_mms/asn1c/DeleteNamedVariableListResponse.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _DeleteNamedVariableListResponse_H_ +#define _DeleteNamedVariableListResponse_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* DeleteNamedVariableListResponse */ +typedef struct DeleteNamedVariableListResponse { + Unsigned32_t numberMatched; + Unsigned32_t numberDeleted; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} DeleteNamedVariableListResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_DeleteNamedVariableListResponse; + +#ifdef __cplusplus +} +#endif + +#endif /* _DeleteNamedVariableListResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/FloatingPoint.c b/src/mms/iso_mms/asn1c/FloatingPoint.c new file mode 100644 index 0000000..e323da3 --- /dev/null +++ b/src/mms/iso_mms/asn1c/FloatingPoint.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "FloatingPoint.h" + +int +FloatingPoint_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_OCTET_STRING.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using OCTET_STRING, + * so here we adjust the DEF accordingly. + */ +static void +FloatingPoint_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_OCTET_STRING.free_struct; + td->print_struct = asn_DEF_OCTET_STRING.print_struct; + td->ber_decoder = asn_DEF_OCTET_STRING.ber_decoder; + td->der_encoder = asn_DEF_OCTET_STRING.der_encoder; + td->xer_decoder = asn_DEF_OCTET_STRING.xer_decoder; + td->xer_encoder = asn_DEF_OCTET_STRING.xer_encoder; + td->uper_decoder = asn_DEF_OCTET_STRING.uper_decoder; + td->uper_encoder = asn_DEF_OCTET_STRING.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_OCTET_STRING.per_constraints; + td->elements = asn_DEF_OCTET_STRING.elements; + td->elements_count = asn_DEF_OCTET_STRING.elements_count; + td->specifics = asn_DEF_OCTET_STRING.specifics; +} + +void +FloatingPoint_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + FloatingPoint_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +FloatingPoint_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + FloatingPoint_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +FloatingPoint_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + FloatingPoint_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +FloatingPoint_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + FloatingPoint_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +FloatingPoint_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + FloatingPoint_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +FloatingPoint_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + FloatingPoint_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_FloatingPoint_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_FloatingPoint = { + "FloatingPoint", + "FloatingPoint", + FloatingPoint_free, + FloatingPoint_print, + FloatingPoint_constraint, + FloatingPoint_decode_ber, + FloatingPoint_encode_der, + FloatingPoint_decode_xer, + FloatingPoint_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_FloatingPoint_tags_1, + sizeof(asn_DEF_FloatingPoint_tags_1) + /sizeof(asn_DEF_FloatingPoint_tags_1[0]), /* 1 */ + asn_DEF_FloatingPoint_tags_1, /* Same as above */ + sizeof(asn_DEF_FloatingPoint_tags_1) + /sizeof(asn_DEF_FloatingPoint_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/FloatingPoint.h b/src/mms/iso_mms/asn1c/FloatingPoint.h new file mode 100644 index 0000000..36d070d --- /dev/null +++ b/src/mms/iso_mms/asn1c/FloatingPoint.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _FloatingPoint_H_ +#define _FloatingPoint_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* FloatingPoint */ +typedef OCTET_STRING_t FloatingPoint_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_FloatingPoint; +asn_struct_free_f FloatingPoint_free; +asn_struct_print_f FloatingPoint_print; +asn_constr_check_f FloatingPoint_constraint; +ber_type_decoder_f FloatingPoint_decode_ber; +der_type_encoder_f FloatingPoint_encode_der; +xer_type_decoder_f FloatingPoint_decode_xer; +xer_type_encoder_f FloatingPoint_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _FloatingPoint_H_ */ diff --git a/src/mms/iso_mms/asn1c/GeneralizedTime.c b/src/mms/iso_mms/asn1c/GeneralizedTime.c new file mode 100644 index 0000000..e04df24 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GeneralizedTime.c @@ -0,0 +1,718 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#define _POSIX_PTHREAD_SEMANTICS /* for Sun */ +#define _REENTRANT /* for Sun */ +#include +#include +#include + +#ifdef __CYGWIN__ +#include "/usr/include/time.h" +#else +#include +#endif /* __CYGWIN__ */ + +#ifdef __IAR_SYSTEMS_ICC__ + +static struct tm *localtime_r(const time_t *tloc, struct tm *result) { + struct tm *tm; + if((tm = localtime(tloc))) + return memcpy(result, tm, sizeof(struct tm)); + return 0; +} + +static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { + struct tm *tm; + if((tm = gmtime(tloc))) + return memcpy(result, tm, sizeof(struct tm)); + return 0; +} +#endif /* __IAR_SYSTEMS_ICC__ */ + +#if defined(WIN32) + +#ifdef __GNUC__ + +static struct tm *localtime_r(const time_t *tloc, struct tm *result) { + struct tm *tm; + if((tm = localtime(tloc))) + return memcpy(result, tm, sizeof(struct tm)); + return 0; +} + +static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { + struct tm *tm; + if((tm = gmtime(tloc))) + return memcpy(result, tm, sizeof(struct tm)); + return 0; +} + +#else + +int +localtime_s(struct tm* _tm, const time_t *time); + +int +gmtime_s(struct tm* _tm, const time_t* time); + + + +static struct tm* +localtime_r(const time_t *tloc, struct tm *result) +{ + + if(localtime_s(result, tloc) == 0) + return result; + else + return 0; +} + +static struct tm* +gmtime_r(const time_t *tloc, struct tm *result) +{ + if(gmtime_s(result, tloc) == 0) + return result; + else + return 0; +} +#endif /* __GNUC__ */ + +#define tzset() _tzset() +#define putenv(c) _putenv(c) +#define _EMULATE_TIMEGM + +#endif /* WIN32 */ + +#if defined(sun) || defined(_sun_) || defined(__solaris__) +#define _EMULATE_TIMEGM +#endif + +/* + * Where to look for offset from GMT, Phase I. + * Several platforms are known. + */ +#if defined(__FreeBSD__) \ + || (defined(__GNUC__) && defined(__APPLE_CC__)) \ + || (defined __GLIBC__ && __GLIBC__ >= 2) +#undef HAVE_TM_GMTOFF +#define HAVE_TM_GMTOFF +#endif /* BSDs and newer glibc */ + +/* + * Where to look for offset from GMT, Phase II. + */ +#ifdef HAVE_TM_GMTOFF +#define GMTOFF(tm) ((tm).tm_gmtoff) +#else /* HAVE_TM_GMTOFF */ +#define GMTOFF(tm) (-timezone) +#endif /* HAVE_TM_GMTOFF */ + +/* + * Override our GMTOFF decision for other known platforms. + */ +#ifdef __CYGWIN__ +#undef GMTOFF +static long GMTOFF(struct tm a){ + struct tm *lt; + time_t local_time, gmt_time; + long zone; + + tzset(); + gmt_time = time (NULL); + + lt = gmtime(&gmt_time); + + local_time = mktime(lt); + return (gmt_time - local_time); +} +#define _EMULATE_TIMEGM + +#endif /* __CYGWIN__ */ + +#define ATZVARS do { \ + char tzoldbuf[64]; \ + char *tzold +#define ATZSAVETZ do { \ + tzold = getenv("TZ"); \ + if(tzold) { \ + size_t tzlen = strlen(tzold); \ + if(tzlen < sizeof(tzoldbuf)) \ + tzold = memcpy(tzoldbuf, tzold, tzlen + 1); \ + else \ + tzold = strdup(tzold); /* Ignore error */ \ + setenv("TZ", "UTC", 1); \ + } \ + tzset(); \ +} while(0) +#define ATZOLDTZ do { \ + if (tzold) { \ + setenv("TZ", tzold, 1); \ + *tzoldbuf = 0; \ + if(tzold != tzoldbuf) \ + FREEMEM(tzold); \ + } else { \ + unsetenv("TZ"); \ + } \ + tzset(); \ +} while(0); } while(0); + +#ifdef _EMULATE_TIMEGM +static time_t timegm(struct tm *tm) { + time_t tloc; + //ATZVARS; + //ATZSAVETZ; + tloc = mktime(tm); +// ATZOLDTZ; + return tloc; +} +#endif /* _EMULATE_TIMEGM */ + + +#ifndef __ASN_INTERNAL_TEST_MODE__ + +/* + * GeneralizedTime basic type description. + */ +static ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (24 << 2)), /* [UNIVERSAL 24] IMPLICIT ...*/ + (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ +}; +asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { + "GeneralizedTime", + "GeneralizedTime", + OCTET_STRING_free, + GeneralizedTime_print, + GeneralizedTime_constraint, /* Check validity of time */ + OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ + GeneralizedTime_encode_der, + OCTET_STRING_decode_xer_utf8, + GeneralizedTime_encode_xer, + 0, 0, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GeneralizedTime_tags, + sizeof(asn_DEF_GeneralizedTime_tags) + / sizeof(asn_DEF_GeneralizedTime_tags[0]) - 2, + asn_DEF_GeneralizedTime_tags, + sizeof(asn_DEF_GeneralizedTime_tags) + / sizeof(asn_DEF_GeneralizedTime_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +#endif /* __ASN_INTERNAL_TEST_MODE__ */ + +/* + * Check that the time looks like the time. + */ +int +GeneralizedTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; + time_t tloc; + + errno = EPERM; /* Just an unlikely error code */ + tloc = asn_GT2time(st, 0, 0); + if(tloc == -1 && errno != EPERM) { + _ASN_CTFAIL(app_key, td, + "%s: Invalid time format: %s (%s:%d)", + td->name, strerror(errno), __FILE__, __LINE__); + return -1; + } + + return 0; +} + +asn_enc_rval_t +GeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + GeneralizedTime_t *st = (GeneralizedTime_t *)sptr; + asn_enc_rval_t erval; + int fv, fd; /* seconds fraction value and number of digits */ + struct tm tm; + time_t tloc; + + /* + * Encode as a canonical DER. + */ + errno = EPERM; + tloc = asn_GT2time_frac(st, &fv, &fd, &tm, 1); /* Recognize time */ + if(tloc == -1 && errno != EPERM) + /* Failed to recognize time. Fail completely. */ + _ASN_ENCODE_FAILED; + + //st = asn_time2GT_frac(0, &tm, fv, fd, 1); /* Save time canonically */ + if(!st) _ASN_ENCODE_FAILED; /* Memory allocation failure. */ + + erval = OCTET_STRING_encode_der(td, st, tag_mode, tag, cb, app_key); + + FREEMEM(st->buf); + FREEMEM(st); + + return erval; +} + +#ifndef __ASN_INTERNAL_TEST_MODE__ + +asn_enc_rval_t +GeneralizedTime_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + + if(flags & XER_F_CANONICAL) { + GeneralizedTime_t *gt = NULL; // modified MZ + asn_enc_rval_t rv; + int fv, fd; /* fractional parts */ + struct tm tm; + + errno = EPERM; + if(asn_GT2time_frac((GeneralizedTime_t *)sptr, + &fv, &fd, &tm, 1) == -1 + && errno != EPERM) + _ASN_ENCODE_FAILED; + + //gt = asn_time2GT_frac(0, &tm, fv, fd, 1); + if(!gt) _ASN_ENCODE_FAILED; + + rv = OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, + cb, app_key); + ASN_STRUCT_FREE(asn_DEF_GeneralizedTime, gt); + return rv; + } else { + return OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, + cb, app_key); + } +} + +#endif /* __ASN_INTERNAL_TEST_MODE__ */ + +int +GeneralizedTime_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st && st->buf) { + char buf[32]; + struct tm tm; + int ret; + + errno = EPERM; + if(asn_GT2time(st, &tm, 1) == -1 && errno != EPERM) + return (cb("", 11, app_key) < 0) ? -1 : 0; + + ret = snprintf(buf, sizeof(buf), + "%04d-%02d-%02d %02d:%02d:%02d (GMT)", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + assert(ret > 0 && ret < (int)sizeof(buf)); + return (cb(buf, ret, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +time_t +asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { + return asn_GT2time_frac(st, 0, 0, ret_tm, as_gmt); +} + +time_t +asn_GT2time_prec(const GeneralizedTime_t *st, int *frac_value, int frac_digits, struct tm *ret_tm, int as_gmt) { + time_t tloc; + int fv, fd = 0; + + if(frac_value) + tloc = asn_GT2time_frac(st, &fv, &fd, ret_tm, as_gmt); + else + return asn_GT2time_frac(st, 0, 0, ret_tm, as_gmt); + if(fd == 0 || frac_digits <= 0) { + *frac_value = 0; + } else { + while(fd > frac_digits) + fv /= 10, fd--; + while(fd < frac_digits) { + int new_fv = fv * 10; + if(new_fv / 10 != fv) { + /* Too long precision request */ + fv = 0; + break; + } + fv = new_fv, fd++; + } + + *frac_value = fv; + } + + return tloc; +} + +time_t +asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, struct tm *ret_tm, int as_gmt) { + struct tm tm_s; + uint8_t *buf; + uint8_t *end; + int gmtoff_h = 0; + int gmtoff_m = 0; + int gmtoff = 0; /* h + m */ + int offset_specified = 0; + int fvalue = 0; + int fdigits = 0; + time_t tloc = 0; + + if(!st || !st->buf) { + errno = EINVAL; + return -1; + } else { + buf = st->buf; + end = buf + st->size; + } + + if(st->size < 10) { + errno = EINVAL; + return -1; + } + + /* + * Decode first 10 bytes: "AAAAMMJJhh" + */ + memset(&tm_s, 0, sizeof(tm_s)); +#undef B2F +#undef B2T +#define B2F(var) do { \ + unsigned ch = *buf; \ + if(ch < 0x30 || ch > 0x39) { \ + errno = EINVAL; \ + return -1; \ + } else { \ + var = var * 10 + (ch - 0x30); \ + buf++; \ + } \ + } while(0) +#define B2T(var) B2F(tm_s.var) + + B2T(tm_year); /* 1: A */ + B2T(tm_year); /* 2: A */ + B2T(tm_year); /* 3: A */ + B2T(tm_year); /* 4: A */ + B2T(tm_mon); /* 5: M */ + B2T(tm_mon); /* 6: M */ + B2T(tm_mday); /* 7: J */ + B2T(tm_mday); /* 8: J */ + B2T(tm_hour); /* 9: h */ + B2T(tm_hour); /* 0: h */ + + if(buf == end) goto local_finish; + + /* + * Parse [mm[ss[(.|,)ffff]]] + * ^^ + */ + switch(*buf) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + tm_s.tm_min = (*buf++) - 0x30; + if(buf == end) { errno = EINVAL; return -1; } + B2T(tm_min); + break; + case 0x2B: case 0x2D: /* +, - */ + goto offset; + case 0x5A: /* Z */ + goto utc_finish; + default: + errno = EINVAL; + return -1; + } + + if(buf == end) goto local_finish; + + /* + * Parse [mm[ss[(.|,)ffff]]] + * ^^ + */ + switch(*buf) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + tm_s.tm_sec = (*buf++) - 0x30; + if(buf == end) { errno = EINVAL; return -1; } + B2T(tm_sec); + break; + case 0x2B: case 0x2D: /* +, - */ + goto offset; + case 0x5A: /* Z */ + goto utc_finish; + default: + errno = EINVAL; + return -1; + } + + if(buf == end) goto local_finish; + + /* + * Parse [mm[ss[(.|,)ffff]]] + * ^ ^ + */ + switch(*buf) { + case 0x2C: case 0x2E: /* (.|,) */ + /* + * Process fractions of seconds. + */ + for(buf++; buf < end; buf++) { + int v = *buf; + int new_fvalue; + switch(v) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + new_fvalue = fvalue * 10 + (v - 0x30); + if(new_fvalue / 10 != fvalue) { + /* Not enough precision, ignore */ + } else { + fvalue = new_fvalue; + fdigits++; + } + continue; + default: + break; + } + break; + } + } + + if(buf == end) goto local_finish; + + switch(*buf) { + case 0x2B: case 0x2D: /* +, - */ + goto offset; + case 0x5A: /* Z */ + goto utc_finish; + default: + errno = EINVAL; + return -1; + } + + +offset: + + if(end - buf < 3) { + errno = EINVAL; + return -1; + } + buf++; + B2F(gmtoff_h); + B2F(gmtoff_h); + if(buf[-3] == 0x2D) /* Negative */ + gmtoff = -1; + else + gmtoff = 1; + + if((end - buf) == 2) { + B2F(gmtoff_m); + B2F(gmtoff_m); + } else if(end != buf) { + errno = EINVAL; + return -1; + } + + gmtoff = gmtoff * (3600 * gmtoff_h + 60 * gmtoff_m); + + /* Fall through */ +utc_finish: + + offset_specified = 1; + + /* Fall through */ +local_finish: + + /* + * Validation. + */ + if((tm_s.tm_mon > 12 || tm_s.tm_mon < 1) + || (tm_s.tm_mday > 31 || tm_s.tm_mday < 1) + || (tm_s.tm_hour > 23) + || (tm_s.tm_sec > 60) + ) { + errno = EINVAL; + return -1; + } + + /* Canonicalize */ + tm_s.tm_mon -= 1; /* 0 - 11 */ + tm_s.tm_year -= 1900; + tm_s.tm_isdst = -1; + + tm_s.tm_sec -= gmtoff; + + /*** AT THIS POINT tm_s is either GMT or local (unknown) ****/ + + if(offset_specified) { + //tloc = timegm(&tm_s); + } else { + /* + * Without an offset (or "Z"), + * we can only guess that it is a local zone. + * Interpret it in this fashion. + */ + tloc = mktime(&tm_s); + } + if(tloc == -1) { + errno = EINVAL; + return -1; + } + + if(ret_tm) { + if(as_gmt) { + if(offset_specified) { + *ret_tm = tm_s; + } else { + if(gmtime_r(&tloc, ret_tm) == 0) { + errno = EINVAL; + return -1; + } + } + } else { + if(localtime_r(&tloc, ret_tm) == 0) { + errno = EINVAL; + return -1; + } + } + } + + /* Fractions of seconds */ + if(frac_value) *frac_value = fvalue; + if(frac_digits) *frac_digits = fdigits; + + return tloc; +} + +#if 0 + +GeneralizedTime_t * +asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) { + return asn_time2GT_frac(opt_gt, tm, 0, 0, force_gmt); +} + +GeneralizedTime_t * +asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, int frac_digits, int force_gmt) { + struct tm tm_s; + long gmtoff; + const unsigned int buf_size = + 4 + 2 + 2 /* yyyymmdd */ + + 2 + 2 + 2 /* hhmmss */ + + 1 + 6 /* .ffffff */ + + 1 + 4 /* +hhmm */ + + 1 /* '\0' */ + ; + char *buf; + char *p; + int size; + + /* Check arguments */ + if(!tm) { + errno = EINVAL; + return 0; + } + + /* Pre-allocate a buffer of sufficient yet small length */ + buf = (char *)MALLOC(buf_size); + if(!buf) return 0; + + gmtoff = GMTOFF(*tm); + + if(force_gmt && gmtoff) { + tm_s = *tm; + tm_s.tm_sec -= gmtoff; + timegm(&tm_s); /* Fix the time */ + tm = &tm_s; +#ifdef HAVE_TM_GMTOFF + assert(!GMTOFF(tm_s)); /* Will fix itself */ +#else /* !HAVE_TM_GMTOFF */ + gmtoff = 0; +#endif + } + + size = snprintf(buf, buf_size, "%04d%02d%02d%02d%02d%02d", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + if(size != 14) { + /* Could be assert(size == 14); */ + FREEMEM(buf); + errno = EINVAL; + return 0; + } + + p = buf + size; + + /* + * Deal with fractions. + */ + if(frac_value > 0 && frac_digits > 0) { + char *end = p + 1 + 6; /* '.' + maximum 6 digits */ + char *z = p; + long fbase; + *z++ = '.'; + + /* Place bounds on precision */ + while(frac_digits-- > 6) + frac_value /= 10; + + /* emulate fbase = pow(10, frac_digits) */ + for(fbase = 1; frac_digits--;) + fbase *= 10; + + do { + int digit = frac_value / fbase; + if(digit > 9) { z = 0; break; } + *z++ = digit + 0x30; + frac_value %= fbase; + fbase /= 10; + } while(fbase > 0 && frac_value > 0 && z < end); + if(z) { + for(--z; *z == 0x30; --z); /* Strip zeroes */ + p = z + (*z != '.'); + size = p - buf; + } + } + + if(force_gmt) { + *p++ = 0x5a; /* "Z" */ + *p++ = 0; + size++; + } else { + int ret; + gmtoff %= 86400; + ret = snprintf(p, buf_size - size, "%+03ld%02ld", + gmtoff / 3600, labs(gmtoff % 3600)); + if(ret != 5) { + FREEMEM(buf); + errno = EINVAL; + return 0; + } + size += ret; + } + + if(opt_gt) { + if(opt_gt->buf) + FREEMEM(opt_gt->buf); + } else { + opt_gt = (GeneralizedTime_t *)CALLOC(1, sizeof *opt_gt); + if(!opt_gt) { FREEMEM(buf); return 0; } + } + + opt_gt->buf = (unsigned char *)buf; + opt_gt->size = size; + + return opt_gt; +} + +#endif diff --git a/src/mms/iso_mms/asn1c/GeneralizedTime.h b/src/mms/iso_mms/asn1c/GeneralizedTime.h new file mode 100644 index 0000000..1ea06b0 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GeneralizedTime.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _GeneralizedTime_H_ +#define _GeneralizedTime_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef OCTET_STRING_t GeneralizedTime_t; /* Implemented via OCTET STRING */ + +extern asn_TYPE_descriptor_t asn_DEF_GeneralizedTime; + +asn_struct_print_f GeneralizedTime_print; +asn_constr_check_f GeneralizedTime_constraint; +der_type_encoder_f GeneralizedTime_encode_der; +xer_type_encoder_f GeneralizedTime_encode_xer; + +/*********************** + * Some handy helpers. * + ***********************/ + +struct tm; /* */ + +/* + * Convert a GeneralizedTime structure into time_t + * and optionally into struct tm. + * If as_gmt is given, the resulting _optional_tm4fill will have a GMT zone, + * instead of default local one. + * On error returns -1 and errno set to EINVAL + */ +time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill, + int as_gmt); + +/* A version of the above function also returning the fractions of seconds */ +time_t asn_GT2time_frac(const GeneralizedTime_t *, + int *frac_value, int *frac_digits, /* (value / (10 ^ digits)) */ + struct tm *_optional_tm4fill, int as_gmt); + +/* + * Another version returning fractions with defined precision + * For example, parsing of the time ending with ".1" seconds + * with frac_digits=3 (msec) would yield frac_value = 100. + */ +time_t asn_GT2time_prec(const GeneralizedTime_t *, + int *frac_value, int frac_digits, + struct tm *_optional_tm4fill, int as_gmt); + +/* + * Convert a struct tm into GeneralizedTime. + * If _optional_gt is not given, this function will try to allocate one. + * If force_gmt is given, the resulting GeneralizedTime will be forced + * into a GMT time zone (encoding ends with a "Z"). + * On error, this function returns 0 and sets errno. + */ +GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *_optional_gt, + const struct tm *, int force_gmt); +GeneralizedTime_t *asn_time2GT_frac(GeneralizedTime_t *_optional_gt, + const struct tm *, int frac_value, int frac_digits, int force_gmt); + +#ifdef __cplusplus +} +#endif + +#endif /* _GeneralizedTime_H_ */ diff --git a/src/mms/iso_mms/asn1c/GetNameListRequest.c b/src/mms/iso_mms/asn1c/GetNameListRequest.c new file mode 100644 index 0000000..d787794 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNameListRequest.c @@ -0,0 +1,148 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "GetNameListRequest.h" + +static asn_TYPE_member_t asn_MBR_objectScope_3[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetNameListRequest__objectScope, choice.vmdSpecific), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "vmdSpecific" + }, + { ATF_NOFLAGS, 0, offsetof(struct GetNameListRequest__objectScope, choice.domainSpecific), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "domainSpecific" + }, + { ATF_NOFLAGS, 0, offsetof(struct GetNameListRequest__objectScope, choice.aaSpecific), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "aaSpecific" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_objectScope_tag2el_3[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* vmdSpecific at 454 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* domainSpecific at 455 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* aaSpecific at 456 */ +}; +static asn_CHOICE_specifics_t asn_SPC_objectScope_specs_3 = { + sizeof(struct GetNameListRequest__objectScope), + offsetof(struct GetNameListRequest__objectScope, _asn_ctx), + offsetof(struct GetNameListRequest__objectScope, present), + sizeof(((struct GetNameListRequest__objectScope *)0)->present), + asn_MAP_objectScope_tag2el_3, + 3, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_objectScope_3 = { + "objectScope", + "objectScope", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_objectScope_3, + 3, /* Elements count */ + &asn_SPC_objectScope_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_GetNameListRequest_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetNameListRequest, objectClass), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_ObjectClass, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "objectClass" + }, + { ATF_NOFLAGS, 0, offsetof(struct GetNameListRequest, objectScope), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_objectScope_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "objectScope" + }, + { ATF_POINTER, 1, offsetof(struct GetNameListRequest, continueAfter), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "continueAfter" + }, +}; +static ber_tlv_tag_t asn_DEF_GetNameListRequest_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_GetNameListRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* objectClass at 451 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* objectScope at 454 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* continueAfter at 458 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_GetNameListRequest_specs_1 = { + sizeof(struct GetNameListRequest), + offsetof(struct GetNameListRequest, _asn_ctx), + asn_MAP_GetNameListRequest_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_GetNameListRequest = { + "GetNameListRequest", + "GetNameListRequest", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GetNameListRequest_tags_1, + sizeof(asn_DEF_GetNameListRequest_tags_1) + /sizeof(asn_DEF_GetNameListRequest_tags_1[0]), /* 1 */ + asn_DEF_GetNameListRequest_tags_1, /* Same as above */ + sizeof(asn_DEF_GetNameListRequest_tags_1) + /sizeof(asn_DEF_GetNameListRequest_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_GetNameListRequest_1, + 3, /* Elements count */ + &asn_SPC_GetNameListRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/GetNameListRequest.h b/src/mms/iso_mms/asn1c/GetNameListRequest.h new file mode 100644 index 0000000..01d0415 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNameListRequest.h @@ -0,0 +1,60 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _GetNameListRequest_H_ +#define _GetNameListRequest_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectClass.h" +#include "Identifier.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum GetNameListRequest__objectScope_PR { + GetNameListRequest__objectScope_PR_NOTHING, /* No components present */ + GetNameListRequest__objectScope_PR_vmdSpecific, + GetNameListRequest__objectScope_PR_domainSpecific, + GetNameListRequest__objectScope_PR_aaSpecific +} GetNameListRequest__objectScope_PR; + +/* GetNameListRequest */ +typedef struct GetNameListRequest { + ObjectClass_t objectClass; + struct GetNameListRequest__objectScope { + GetNameListRequest__objectScope_PR present; + union GetNameListRequest__objectScope_u { + NULL_t vmdSpecific; + Identifier_t domainSpecific; + NULL_t aaSpecific; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } objectScope; + Identifier_t *continueAfter /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} GetNameListRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_GetNameListRequest; + +#ifdef __cplusplus +} +#endif + +#endif /* _GetNameListRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/GetNameListResponse.c b/src/mms/iso_mms/asn1c/GetNameListResponse.c new file mode 100644 index 0000000..b45d100 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNameListResponse.c @@ -0,0 +1,116 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "GetNameListResponse.h" + +static asn_TYPE_member_t asn_MBR_listOfIdentifier_2[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), + 0, + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfIdentifier_tags_2[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfIdentifier_specs_2 = { + sizeof(struct GetNameListResponse__listOfIdentifier), + offsetof(struct GetNameListResponse__listOfIdentifier, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfIdentifier_2 = { + "listOfIdentifier", + "listOfIdentifier", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfIdentifier_tags_2, + sizeof(asn_DEF_listOfIdentifier_tags_2) + /sizeof(asn_DEF_listOfIdentifier_tags_2[0]) - 1, /* 1 */ + asn_DEF_listOfIdentifier_tags_2, /* Same as above */ + sizeof(asn_DEF_listOfIdentifier_tags_2) + /sizeof(asn_DEF_listOfIdentifier_tags_2[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfIdentifier_2, + 1, /* Single element */ + &asn_SPC_listOfIdentifier_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_GetNameListResponse_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetNameListResponse, listOfIdentifier), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfIdentifier_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfIdentifier" + }, + { ATF_POINTER, 1, offsetof(struct GetNameListResponse, moreFollows), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "moreFollows" + }, +}; +static ber_tlv_tag_t asn_DEF_GetNameListResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_GetNameListResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* listOfIdentifier at 483 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* moreFollows at 484 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_GetNameListResponse_specs_1 = { + sizeof(struct GetNameListResponse), + offsetof(struct GetNameListResponse, _asn_ctx), + asn_MAP_GetNameListResponse_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_GetNameListResponse = { + "GetNameListResponse", + "GetNameListResponse", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GetNameListResponse_tags_1, + sizeof(asn_DEF_GetNameListResponse_tags_1) + /sizeof(asn_DEF_GetNameListResponse_tags_1[0]), /* 1 */ + asn_DEF_GetNameListResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_GetNameListResponse_tags_1) + /sizeof(asn_DEF_GetNameListResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_GetNameListResponse_1, + 2, /* Elements count */ + &asn_SPC_GetNameListResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/GetNameListResponse.h b/src/mms/iso_mms/asn1c/GetNameListResponse.h new file mode 100644 index 0000000..777013b --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNameListResponse.h @@ -0,0 +1,46 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _GetNameListResponse_H_ +#define _GetNameListResponse_H_ + + +#include + +/* Including external dependencies */ +#include +#include "Identifier.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* GetNameListResponse */ +typedef struct GetNameListResponse { + struct GetNameListResponse__listOfIdentifier { + A_SEQUENCE_OF(Identifier_t) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } listOfIdentifier; + BOOLEAN_t *moreFollows /* DEFAULT TRUE */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} GetNameListResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_GetNameListResponse; + +#ifdef __cplusplus +} +#endif + +#endif /* _GetNameListResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.c b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.c new file mode 100644 index 0000000..c725227 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.c @@ -0,0 +1,105 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "GetNamedVariableListAttributesRequest.h" + +int +GetNamedVariableListAttributesRequest_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_ObjectName.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using ObjectName, + * so here we adjust the DEF accordingly. + */ +static void +GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_ObjectName.free_struct; + td->print_struct = asn_DEF_ObjectName.print_struct; + td->ber_decoder = asn_DEF_ObjectName.ber_decoder; + td->der_encoder = asn_DEF_ObjectName.der_encoder; + td->xer_decoder = asn_DEF_ObjectName.xer_decoder; + td->xer_encoder = asn_DEF_ObjectName.xer_encoder; + td->uper_decoder = asn_DEF_ObjectName.uper_decoder; + td->uper_encoder = asn_DEF_ObjectName.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_ObjectName.per_constraints; + td->elements = asn_DEF_ObjectName.elements; + td->elements_count = asn_DEF_ObjectName.elements_count; + td->specifics = asn_DEF_ObjectName.specifics; +} + +void +GetNamedVariableListAttributesRequest_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +GetNamedVariableListAttributesRequest_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +GetNamedVariableListAttributesRequest_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +GetNamedVariableListAttributesRequest_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +GetNamedVariableListAttributesRequest_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +GetNamedVariableListAttributesRequest_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + GetNamedVariableListAttributesRequest_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +asn_TYPE_descriptor_t asn_DEF_GetNamedVariableListAttributesRequest = { + "GetNamedVariableListAttributesRequest", + "GetNamedVariableListAttributesRequest", + GetNamedVariableListAttributesRequest_free, + GetNamedVariableListAttributesRequest_print, + GetNamedVariableListAttributesRequest_constraint, + GetNamedVariableListAttributesRequest_decode_ber, + GetNamedVariableListAttributesRequest_encode_der, + GetNamedVariableListAttributesRequest_decode_xer, + GetNamedVariableListAttributesRequest_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + 0, 0, /* Defined elsewhere */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.h b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.h new file mode 100644 index 0000000..43e2423 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesRequest.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _GetNamedVariableListAttributesRequest_H_ +#define _GetNamedVariableListAttributesRequest_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectName.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* GetNamedVariableListAttributesRequest */ +typedef ObjectName_t GetNamedVariableListAttributesRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_GetNamedVariableListAttributesRequest; +asn_struct_free_f GetNamedVariableListAttributesRequest_free; +asn_struct_print_f GetNamedVariableListAttributesRequest_print; +asn_constr_check_f GetNamedVariableListAttributesRequest_constraint; +ber_type_decoder_f GetNamedVariableListAttributesRequest_decode_ber; +der_type_encoder_f GetNamedVariableListAttributesRequest_encode_der; +xer_type_decoder_f GetNamedVariableListAttributesRequest_decode_xer; +xer_type_encoder_f GetNamedVariableListAttributesRequest_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _GetNamedVariableListAttributesRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.c b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.c new file mode 100644 index 0000000..537e4ae --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.c @@ -0,0 +1,181 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "GetNamedVariableListAttributesResponse.h" + +static asn_TYPE_member_t asn_MBR_Member_4[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member, variableSpecification), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_VariableSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableSpecification" + }, + { ATF_POINTER, 1, offsetof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member, alternateAccess), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_AlternateAccess, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "alternateAccess" + }, +}; +static ber_tlv_tag_t asn_DEF_Member_tags_4[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_Member_tag2el_4[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* name at 772 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* address at 773 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 }, /* variableDescription at 776 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 0, 0, 0 }, /* scatteredAccessDescription at 779 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 0, 0, 0 }, /* invalidated at 780 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 } /* alternateAccess at 653 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Member_specs_4 = { + sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member), + offsetof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member, _asn_ctx), + asn_MAP_Member_tag2el_4, + 6, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_Member_4 = { + "SEQUENCE", + "SEQUENCE", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Member_tags_4, + sizeof(asn_DEF_Member_tags_4) + /sizeof(asn_DEF_Member_tags_4[0]), /* 1 */ + asn_DEF_Member_tags_4, /* Same as above */ + sizeof(asn_DEF_Member_tags_4) + /sizeof(asn_DEF_Member_tags_4[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Member_4, + 2, /* Elements count */ + &asn_SPC_Member_specs_4 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_listOfVariable_3[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_Member_4, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfVariable_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfVariable_specs_3 = { + sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable), + offsetof(struct GetNamedVariableListAttributesResponse__listOfVariable, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfVariable_3 = { + "listOfVariable", + "listOfVariable", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfVariable_tags_3, + sizeof(asn_DEF_listOfVariable_tags_3) + /sizeof(asn_DEF_listOfVariable_tags_3[0]) - 1, /* 1 */ + asn_DEF_listOfVariable_tags_3, /* Same as above */ + sizeof(asn_DEF_listOfVariable_tags_3) + /sizeof(asn_DEF_listOfVariable_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfVariable_3, + 1, /* Single element */ + &asn_SPC_listOfVariable_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_GetNamedVariableListAttributesResponse_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetNamedVariableListAttributesResponse, mmsDeletable), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mmsDeletable" + }, + { ATF_NOFLAGS, 0, offsetof(struct GetNamedVariableListAttributesResponse, listOfVariable), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfVariable_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfVariable" + }, +}; +static ber_tlv_tag_t asn_DEF_GetNamedVariableListAttributesResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_GetNamedVariableListAttributesResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* mmsDeletable at 649 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* listOfVariable at 654 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_GetNamedVariableListAttributesResponse_specs_1 = { + sizeof(struct GetNamedVariableListAttributesResponse), + offsetof(struct GetNamedVariableListAttributesResponse, _asn_ctx), + asn_MAP_GetNamedVariableListAttributesResponse_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_GetNamedVariableListAttributesResponse = { + "GetNamedVariableListAttributesResponse", + "GetNamedVariableListAttributesResponse", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GetNamedVariableListAttributesResponse_tags_1, + sizeof(asn_DEF_GetNamedVariableListAttributesResponse_tags_1) + /sizeof(asn_DEF_GetNamedVariableListAttributesResponse_tags_1[0]), /* 1 */ + asn_DEF_GetNamedVariableListAttributesResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_GetNamedVariableListAttributesResponse_tags_1) + /sizeof(asn_DEF_GetNamedVariableListAttributesResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_GetNamedVariableListAttributesResponse_1, + 2, /* Elements count */ + &asn_SPC_GetNamedVariableListAttributesResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.h b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.h new file mode 100644 index 0000000..64ea208 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetNamedVariableListAttributesResponse.h @@ -0,0 +1,62 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _GetNamedVariableListAttributesResponse_H_ +#define _GetNamedVariableListAttributesResponse_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include "VariableSpecification.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct AlternateAccess; + +struct GetNamedVariableListAttributesResponse__listOfVariable__Member { + VariableSpecification_t variableSpecification; + struct AlternateAccess *alternateAccess /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } ; + +struct GetNamedVariableListAttributesResponse__listOfVariable { + A_SEQUENCE_OF(struct GetNamedVariableListAttributesResponse__listOfVariable__Member) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* GetNamedVariableListAttributesResponse */ +typedef struct GetNamedVariableListAttributesResponse { + BOOLEAN_t mmsDeletable; + struct GetNamedVariableListAttributesResponse__listOfVariable listOfVariable; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} GetNamedVariableListAttributesResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_GetNamedVariableListAttributesResponse; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "AlternateAccess.h" + +#endif /* _GetNamedVariableListAttributesResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.c b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.c new file mode 100644 index 0000000..744fcc3 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.c @@ -0,0 +1,67 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "GetVariableAccessAttributesRequest.h" + +static asn_TYPE_member_t asn_MBR_GetVariableAccessAttributesRequest_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetVariableAccessAttributesRequest, choice.name), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_ObjectName, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "name" + }, + { ATF_NOFLAGS, 0, offsetof(struct GetVariableAccessAttributesRequest, choice.address), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_Address, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "address" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_GetVariableAccessAttributesRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* name at 607 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* address at 609 */ +}; +static asn_CHOICE_specifics_t asn_SPC_GetVariableAccessAttributesRequest_specs_1 = { + sizeof(struct GetVariableAccessAttributesRequest), + offsetof(struct GetVariableAccessAttributesRequest, _asn_ctx), + offsetof(struct GetVariableAccessAttributesRequest, present), + sizeof(((struct GetVariableAccessAttributesRequest *)0)->present), + asn_MAP_GetVariableAccessAttributesRequest_tag2el_1, + 2, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_GetVariableAccessAttributesRequest = { + "GetVariableAccessAttributesRequest", + "GetVariableAccessAttributesRequest", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_GetVariableAccessAttributesRequest_1, + 2, /* Elements count */ + &asn_SPC_GetVariableAccessAttributesRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.h b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.h new file mode 100644 index 0000000..6fe24c3 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesRequest.h @@ -0,0 +1,49 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _GetVariableAccessAttributesRequest_H_ +#define _GetVariableAccessAttributesRequest_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectName.h" +#include "Address.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum GetVariableAccessAttributesRequest_PR { + GetVariableAccessAttributesRequest_PR_NOTHING, /* No components present */ + GetVariableAccessAttributesRequest_PR_name, + GetVariableAccessAttributesRequest_PR_address +} GetVariableAccessAttributesRequest_PR; + +/* GetVariableAccessAttributesRequest */ +typedef struct GetVariableAccessAttributesRequest { + GetVariableAccessAttributesRequest_PR present; + union GetVariableAccessAttributesRequest_u { + ObjectName_t name; + Address_t address; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} GetVariableAccessAttributesRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_GetVariableAccessAttributesRequest; + +#ifdef __cplusplus +} +#endif + +#endif /* _GetVariableAccessAttributesRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.c b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.c new file mode 100644 index 0000000..0f66232 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.c @@ -0,0 +1,81 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "GetVariableAccessAttributesResponse.h" + +static asn_TYPE_member_t asn_MBR_GetVariableAccessAttributesResponse_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct GetVariableAccessAttributesResponse, mmsDeletable), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mmsDeletable" + }, + { ATF_POINTER, 1, offsetof(struct GetVariableAccessAttributesResponse, address), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_Address, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "address" + }, + { ATF_NOFLAGS, 0, offsetof(struct GetVariableAccessAttributesResponse, typeSpecification), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_TypeSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "typeSpecification" + }, +}; +static ber_tlv_tag_t asn_DEF_GetVariableAccessAttributesResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_GetVariableAccessAttributesResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* mmsDeletable at 614 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* address at 615 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* typeSpecification at 617 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_GetVariableAccessAttributesResponse_specs_1 = { + sizeof(struct GetVariableAccessAttributesResponse), + offsetof(struct GetVariableAccessAttributesResponse, _asn_ctx), + asn_MAP_GetVariableAccessAttributesResponse_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_GetVariableAccessAttributesResponse = { + "GetVariableAccessAttributesResponse", + "GetVariableAccessAttributesResponse", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GetVariableAccessAttributesResponse_tags_1, + sizeof(asn_DEF_GetVariableAccessAttributesResponse_tags_1) + /sizeof(asn_DEF_GetVariableAccessAttributesResponse_tags_1[0]), /* 1 */ + asn_DEF_GetVariableAccessAttributesResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_GetVariableAccessAttributesResponse_tags_1) + /sizeof(asn_DEF_GetVariableAccessAttributesResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_GetVariableAccessAttributesResponse_1, + 3, /* Elements count */ + &asn_SPC_GetVariableAccessAttributesResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.h b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.h new file mode 100644 index 0000000..9a5ffd4 --- /dev/null +++ b/src/mms/iso_mms/asn1c/GetVariableAccessAttributesResponse.h @@ -0,0 +1,46 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _GetVariableAccessAttributesResponse_H_ +#define _GetVariableAccessAttributesResponse_H_ + + +#include + +/* Including external dependencies */ +#include +#include "TypeSpecification.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct Address; + +/* GetVariableAccessAttributesResponse */ +typedef struct GetVariableAccessAttributesResponse { + BOOLEAN_t mmsDeletable; + struct Address *address /* OPTIONAL */; + TypeSpecification_t typeSpecification; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} GetVariableAccessAttributesResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_GetVariableAccessAttributesResponse; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "Address.h" + +#endif /* _GetVariableAccessAttributesResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/INTEGER.c b/src/mms/iso_mms/asn1c/INTEGER.c new file mode 100644 index 0000000..c1d074f --- /dev/null +++ b/src/mms/iso_mms/asn1c/INTEGER.c @@ -0,0 +1,850 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* Encoder and decoder of a primitive type */ +//#include + +/* + * INTEGER basic type description. + */ +static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_INTEGER = { + "INTEGER", + "INTEGER", + ASN__PRIMITIVE_TYPE_free, + NULL, + asn_generic_no_constraint, + ber_decode_primitive, + INTEGER_encode_der, + NULL, + NULL, + INTEGER_decode_uper, /* Unaligned PER decoder */ + INTEGER_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_INTEGER_tags, + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), + asn_DEF_INTEGER_tags, /* Same as above */ + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Encode INTEGER type using DER. + */ +asn_enc_rval_t +INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + INTEGER_t *st = (INTEGER_t *)sptr; + + ASN_DEBUG("%s %s as INTEGER (tm=%d)", + cb?"Encoding":"Estimating", td->name, tag_mode); + + /* + * Canonicalize integer in the buffer. + * (Remove too long sign extension, remove some first 0x00 bytes) + */ + if(st->buf) { + uint8_t *buf = st->buf; + uint8_t *end1 = buf + st->size - 1; + int shift; + + /* Compute the number of superfluous leading bytes */ + for(; buf < end1; buf++) { + /* + * If the contents octets of an integer value encoding + * consist of more than one octet, then the bits of the + * first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + switch(*buf) { + case 0x00: if((buf[1] & 0x80) == 0) + continue; + break; + case 0xff: if((buf[1] & 0x80)) + continue; + break; + } + break; + } + + /* Remove leading superfluous bytes from the integer */ + shift = buf - st->buf; + if(shift) { + uint8_t *nb = st->buf; + uint8_t *end; + + st->size -= shift; /* New size, minus bad bytes */ + end = nb + st->size; + + for(; nb < end; nb++, buf++) + *nb = *buf; + } + + } /* if(1) */ + + return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key); +} + +#if 0 +/* + * INTEGER specific human-readable output. + */ +static ssize_t +INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + char scratch[32]; /* Enough for 64-bit integer */ + uint8_t *buf = st->buf; + uint8_t *buf_end = st->buf + st->size; + signed long accum; + ssize_t wrote = 0; + char *p; + int ret; + + /* + * Advance buf pointer until the start of the value's body. + * This will make us able to process large integers using simple case, + * when the actual value is small + * (0x0000000000abcdef would yield a fine 0x00abcdef) + */ + /* Skip the insignificant leading bytes */ + for(; buf < buf_end-1; buf++) { + switch(*buf) { + case 0x00: if((buf[1] & 0x80) == 0) continue; break; + case 0xff: if((buf[1] & 0x80) != 0) continue; break; + } + break; + } + + /* Simple case: the integer size is small */ + if((size_t)(buf_end - buf) <= sizeof(accum)) { + const asn_INTEGER_enum_map_t *el; + size_t scrsize; + char *scr; + + if(buf == buf_end) { + accum = 0; + } else { + accum = (*buf & 0x80) ? -1 : 0; + for(; buf < buf_end; buf++) + accum = (accum << 8) | *buf; + } + + el = INTEGER_map_value2enum(specs, accum); + if(el) { + scrsize = el->enum_len + 32; + scr = (char *)alloca(scrsize); + if(plainOrXER == 0) + ret = snprintf(scr, scrsize, + "%ld (%s)", accum, el->enum_name); + else + ret = snprintf(scr, scrsize, + "<%s/>", el->enum_name); + } else if(plainOrXER && specs && specs->strict_enumeration) { + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + errno = EPERM; + return -1; + } else { + scrsize = sizeof(scratch); + scr = scratch; + ret = snprintf(scr, scrsize, "%ld", accum); + } + assert(ret > 0 && (size_t)ret < scrsize); + return (cb(scr, ret, app_key) < 0) ? -1 : ret; + } else if(plainOrXER && specs && specs->strict_enumeration) { + /* + * Here and earlier, we cannot encode the ENUMERATED values + * if there is no corresponding identifier. + */ + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + errno = EPERM; + return -1; + } + + /* Output in the long xx:yy:zz... format */ + /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ + for(p = scratch; buf < buf_end; buf++) { + static const char *h2c = "0123456789ABCDEF"; + if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { + /* Flush buffer */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + wrote += p - scratch; + p = scratch; + } + *p++ = h2c[*buf >> 4]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x3a; /* ":" */ + } + if(p != scratch) + p--; /* Remove the last ":" */ + + wrote += p - scratch; + return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote; +} +#endif + + +#if 0 +/* + * INTEGER specific human-readable output. + */ +int +INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + ssize_t ret; + + (void)td; + (void)ilevel; + + if(!st || !st->buf) + ret = cb("", 8, app_key); + else + ret = INTEGER__dump(td, st, cb, app_key, 0); + + return (ret < 0) ? -1 : 0; +} +#endif + +#if 0 +struct e2v_key { + const char *start; + const char *stop; + asn_INTEGER_enum_map_t *vemap; + unsigned int *evmap; +}; +static int +INTEGER__compar_enum2value(const void *kp, const void *am) { + const struct e2v_key *key = (const struct e2v_key *)kp; + const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; + const char *ptr, *end, *name; + + /* Remap the element (sort by different criterion) */ + el = key->vemap + key->evmap[el - key->vemap]; + + /* Compare strings */ + for(ptr = key->start, end = key->stop, name = el->enum_name; + ptr < end; ptr++, name++) { + if(*ptr != *name) + return *(const unsigned char *)ptr + - *(const unsigned char *)name; + } + return name[0] ? -1 : 0; +} + + +static const asn_INTEGER_enum_map_t * +INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { + asn_INTEGER_enum_map_t *el_found; + int count = specs ? specs->map_count : 0; + struct e2v_key key; + const char *lp; + + if(!count) return NULL; + + /* Guaranteed: assert(lstart < lstop); */ + /* Figure out the tag name */ + for(lstart++, lp = lstart; lp < lstop; lp++) { + switch(*lp) { + case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */ + case 0x2f: /* '/' */ case 0x3e: /* '>' */ + break; + default: + continue; + } + break; + } + if(lp == lstop) return NULL; /* No tag found */ + lstop = lp; + + key.start = lstart; + key.stop = lstop; + key.vemap = specs->value2enum; + key.evmap = specs->enum2value; + el_found = (asn_INTEGER_enum_map_t *)bsearch(&key, + specs->value2enum, count, sizeof(specs->value2enum[0]), + INTEGER__compar_enum2value); + if(el_found) { + /* Remap enum2value into value2enum */ + el_found = key.vemap + key.evmap[el_found - key.vemap]; + } + return el_found; +} +#endif + +#if 0 +static int +INTEGER__compar_value2enum(const void *kp, const void *am) { + long a = *(const long *)kp; + const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; + long b = el->nat_value; + if(a < b) return -1; + else if(a == b) return 0; + else return 1; +} + +const asn_INTEGER_enum_map_t * +INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { + int count = specs ? specs->map_count : 0; + if(!count) return 0; + return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum, + count, sizeof(specs->value2enum[0]), + INTEGER__compar_value2enum); +} +#endif + +#if 0 +static int +INTEGER_st_prealloc(INTEGER_t *st, int min_size) { + void *p = MALLOC(min_size + 1); + if(p) { + void *b = st->buf; + st->size = 0; + st->buf = p; + FREEMEM(b); + return 0; + } else { + return -1; + } +} +#endif + +#if 0 +/* + * Decode the chunk of XML text encoding INTEGER. + */ +static enum xer_pbd_rval +INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { + INTEGER_t *st = (INTEGER_t *)sptr; + long sign = 1; + long value; + const char *lp; + const char *lstart = (const char *)chunk_buf; + const char *lstop = lstart + chunk_size; + enum { + ST_SKIPSPACE, + ST_SKIPSPHEX, + ST_WAITDIGITS, + ST_DIGITS, + ST_HEXDIGIT1, + ST_HEXDIGIT2, + ST_HEXCOLON, + ST_EXTRASTUFF + } state = ST_SKIPSPACE; + + if(chunk_size) + ASN_DEBUG("INTEGER body %d 0x%2x..0x%2x", + chunk_size, *lstart, lstop[-1]); + + /* + * We may have received a tag here. It will be processed inline. + * Use strtoul()-like code and serialize the result. + */ + for(value = 0, lp = lstart; lp < lstop; lp++) { + int lv = *lp; + switch(lv) { + case 0x09: case 0x0a: case 0x0d: case 0x20: + switch(state) { + case ST_SKIPSPACE: + case ST_SKIPSPHEX: + continue; + case ST_HEXCOLON: + if(xer_is_whitespace(lp, lstop - lp)) { + lp = lstop - 1; + continue; + } + break; + default: + break; + } + break; + case 0x2d: /* '-' */ + if(state == ST_SKIPSPACE) { + sign = -1; + state = ST_WAITDIGITS; + continue; + } + break; + case 0x2b: /* '+' */ + if(state == ST_SKIPSPACE) { + state = ST_WAITDIGITS; + continue; + } + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + switch(state) { + case ST_DIGITS: break; + case ST_SKIPSPHEX: /* Fall through */ + case ST_HEXDIGIT1: + value = (lv - 0x30) << 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + value += (lv - 0x30); + state = ST_HEXCOLON; + st->buf[st->size++] = value; + continue; + case ST_HEXCOLON: + return XPBD_BROKEN_ENCODING; + default: + state = ST_DIGITS; + break; + } + + { + long new_value = value * 10; + + if(new_value / 10 != value) + /* Overflow */ + return XPBD_DECODER_LIMIT; + + value = new_value + (lv - 0x30); + /* Check for two's complement overflow */ + if(value < 0) { + /* Check whether it is a LONG_MIN */ + if(sign == -1 + && (unsigned long)value + == ~((unsigned long)-1 >> 1)) { + sign = 1; + } else { + /* Overflow */ + return XPBD_DECODER_LIMIT; + } + } + } + continue; + case 0x3c: /* '<' */ + if(state == ST_SKIPSPACE) { + const asn_INTEGER_enum_map_t *el; + el = INTEGER_map_enum2value( + (asn_INTEGER_specifics_t *) + td->specifics, lstart, lstop); + if(el) { + ASN_DEBUG("Found \"%s\" => %ld", + el->enum_name, el->nat_value); + state = ST_DIGITS; + value = el->nat_value; + lp = lstop - 1; + continue; + } + ASN_DEBUG("Unknown identifier for INTEGER"); + } + return XPBD_BROKEN_ENCODING; + case 0x3a: /* ':' */ + if(state == ST_HEXCOLON) { + /* This colon is expected */ + state = ST_HEXDIGIT1; + continue; + } else if(state == ST_DIGITS) { + /* The colon here means that we have + * decoded the first two hexadecimal + * places as a decimal value. + * Switch decoding mode. */ + ASN_DEBUG("INTEGER re-evaluate as hex form"); + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + state = ST_SKIPSPHEX; + lp = lstart - 1; + continue; + } else { + ASN_DEBUG("state %d at %d", state, lp - lstart); + break; + } + /* [A-Fa-f] */ + case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: + case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: + switch(state) { + case ST_SKIPSPHEX: + case ST_SKIPSPACE: /* Fall through */ + case ST_HEXDIGIT1: + value = lv - ((lv < 0x61) ? 0x41 : 0x61); + value += 10; + value <<= 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + value += lv - ((lv < 0x61) ? 0x41 : 0x61); + value += 10; + st->buf[st->size++] = value; + state = ST_HEXCOLON; + continue; + case ST_DIGITS: + ASN_DEBUG("INTEGER re-evaluate as hex form"); + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + state = ST_SKIPSPHEX; + lp = lstart - 1; + continue; + default: + break; + } + break; + } + + /* Found extra non-numeric stuff */ + ASN_DEBUG("Found non-numeric 0x%2x at %d", + lv, lp - lstart); + state = ST_EXTRASTUFF; + break; + } + + switch(state) { + case ST_DIGITS: + /* Everything is cool */ + break; + case ST_HEXCOLON: + st->buf[st->size] = 0; /* Just in case termination */ + return XPBD_BODY_CONSUMED; + case ST_HEXDIGIT1: + case ST_HEXDIGIT2: + case ST_SKIPSPHEX: + return XPBD_BROKEN_ENCODING; + default: + if(xer_is_whitespace(lp, lstop - lp)) { + if(state != ST_EXTRASTUFF) + return XPBD_NOT_BODY_IGNORE; + break; + } else { + ASN_DEBUG("INTEGER: No useful digits (state %d)", + state); + return XPBD_BROKEN_ENCODING; /* No digits */ + } + break; + } + + value *= sign; /* Change sign, if needed */ + + if(asn_long2INTEGER(st, value)) + return XPBD_SYSTEM_FAILURE; + + return XPBD_BODY_CONSUMED; +} + +asn_dec_rval_t +INTEGER_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(INTEGER_t), opt_mname, + buf_ptr, size, INTEGER__xer_body_decode); +} +#endif + + +#if 0 +asn_enc_rval_t +INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + asn_enc_rval_t er; + + (void)ilevel; + (void)flags; + + if(!st || !st->buf) + _ASN_ENCODE_FAILED; + + er.encoded = INTEGER__dump(td, st, cb, app_key, 1); + if(er.encoded < 0) _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(er); +} +#endif + +asn_dec_rval_t +INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rval = { RC_OK, 0 }; + INTEGER_t *st = (INTEGER_t *)*sptr; + asn_per_constraint_t *ct; + int repeat; + + (void)opt_codec_ctx; + + if(!st) { + st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); + if(!st) _ASN_DECODE_FAILED; + } + + if(!constraints) constraints = td->per_constraints; + ct = constraints ? &constraints->value : 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) _ASN_DECODE_STARVED; + if(inext) ct = 0; + } + + FREEMEM(st->buf); + if(ct) { + if(ct->flags & APC_SEMI_CONSTRAINED) { + st->buf = (uint8_t *)CALLOC(1, 2); + if(!st->buf) _ASN_DECODE_FAILED; + st->size = 1; + } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { + size_t size = (ct->range_bits + 7) >> 3; + st->buf = (uint8_t *)MALLOC(1 + size + 1); + if(!st->buf) _ASN_DECODE_FAILED; + st->size = size; + } else { + st->size = 0; + } + } else { + st->size = 0; + } + + /* X.691, #12.2.2 */ + if(ct && ct->flags != APC_UNCONSTRAINED) { + /* #10.5.6 */ + ASN_DEBUG("Integer with range %d bits", ct->range_bits); + if(ct->range_bits >= 0) { + long value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + ASN_DEBUG("Got value %ld + low %ld", + value, ct->lower_bound); + value += ct->lower_bound; + if(asn_long2INTEGER(st, value)) + _ASN_DECODE_FAILED; + return rval; + } + } else { + ASN_DEBUG("Decoding unconstrained integer %s", td->name); + } + + /* X.691, #12.2.3, #12.2.4 */ + do { + ssize_t len; + void *p; + int ret; + + /* Get the PER length */ + len = uper_get_length(pd, -1, &repeat); + if(len < 0) _ASN_DECODE_STARVED; + + p = REALLOC(st->buf, st->size + len + 1); + if(!p) _ASN_DECODE_FAILED; + st->buf = (uint8_t *)p; + + ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); + if(ret < 0) _ASN_DECODE_STARVED; + st->size += len; + } while(repeat); + st->buf[st->size] = 0; /* JIC */ + + /* #12.2.3 */ + if(ct && ct->lower_bound) { + /* + * TODO: replace by in-place arithmetics. + */ + long value; + if(asn_INTEGER2long(st, &value)) + _ASN_DECODE_FAILED; + if(asn_long2INTEGER(st, value + ct->lower_bound)) + _ASN_DECODE_FAILED; + } + + return rval; +} + +asn_enc_rval_t +INTEGER_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_enc_rval_t er; + INTEGER_t *st = (INTEGER_t *)sptr; + const uint8_t *buf; + const uint8_t *end; + asn_per_constraint_t *ct; + long value = 0; + + if(!st || st->size == 0) _ASN_ENCODE_FAILED; + + if(!constraints) constraints = td->per_constraints; + ct = constraints ? &constraints->value : 0; + + er.encoded = 0; + + if(ct) { + int inext = 0; + if(asn_INTEGER2long(st, &value)) + _ASN_ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(value < ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(value < ct->lower_bound + || value > ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", + value, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 1)) + _ASN_ENCODE_FAILED; + if(inext) ct = 0; + } else if(inext) { + _ASN_ENCODE_FAILED; + } + } + + + /* X.691, #12.2.2 */ + if(ct && ct->range_bits >= 0) { + /* #10.5.6 */ + ASN_DEBUG("Encoding integer with range %d bits", + ct->range_bits); + if(per_put_few_bits(po, value - ct->lower_bound, + ct->range_bits)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + if(ct && ct->lower_bound) { + ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); + /* TODO: adjust lower bound */ + _ASN_ENCODE_FAILED; + } + + for(buf = st->buf, end = st->buf + st->size; buf < end;) { + ssize_t mayEncode = uper_put_length(po, end - buf); + if(mayEncode < 0) + _ASN_ENCODE_FAILED; + if(per_put_many_bits(po, buf, 8 * mayEncode)) + _ASN_ENCODE_FAILED; + buf += mayEncode; + } + + _ASN_ENCODED_OK(er); +} + +int +asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { + uint8_t *b, *end; + size_t size; + long l; + + /* Sanity checking */ + if(!iptr || !iptr->buf || !lptr) { + //errno = EINVAL; + return -1; + } + + /* Cache the begin/end of the buffer */ + b = iptr->buf; /* Start of the INTEGER buffer */ + size = iptr->size; + end = b + size; /* Where to stop */ + + if(size > sizeof(long)) { + uint8_t *end1 = end - 1; + /* + * Slightly more advanced processing, + * able to >sizeof(long) bytes, + * when the actual value is small + * (0x0000000000abcdef would yield a fine 0x00abcdef) + */ + /* Skip out the insignificant leading bytes */ + for(; b < end1; b++) { + switch(*b) { + case 0x00: if((b[1] & 0x80) == 0) continue; break; + case 0xff: if((b[1] & 0x80) != 0) continue; break; + } + break; + } + + size = end - b; + if(size > sizeof(long)) { + /* Still cannot fit the long */ + //errno = ERANGE; + return -1; + } + } + + /* Shortcut processing of a corner case */ + if(end == b) { + *lptr = 0; + return 0; + } + + /* Perform the sign initialization */ + /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ + if((*b >> 7)) l = -1; else l = 0; + + /* Conversion engine */ + for(; b < end; b++) + l = (l << 8) | *b; + + *lptr = l; + return 0; +} + +int +asn_long2INTEGER(INTEGER_t *st, long value) { + uint8_t *buf, *bp; + uint8_t *p; + uint8_t *pstart; + uint8_t *pend1; + int littleEndian = 1; /* Run-time detection */ + int add; + + if(!st) { + //errno = EINVAL; + return -1; + } + + buf = (uint8_t *)MALLOC(sizeof(value)); + if(!buf) return -1; + + if(*(char *)&littleEndian) { + pstart = (uint8_t *)&value + sizeof(value) - 1; + pend1 = (uint8_t *)&value; + add = -1; + } else { + pstart = (uint8_t *)&value; + pend1 = pstart + sizeof(value) - 1; + add = 1; + } + + /* + * If the contents octet consists of more than one octet, + * then bits of the first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + for(p = pstart; p != pend1; p += add) { + switch(*p) { + case 0x00: if((*(p+add) & 0x80) == 0) + continue; + break; + case 0xff: if((*(p+add) & 0x80)) + continue; + break; + } + break; + } + /* Copy the integer body */ + for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) + *bp++ = *p; + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = bp - buf; + + return 0; +} diff --git a/src/mms/iso_mms/asn1c/INTEGER.h b/src/mms/iso_mms/asn1c/INTEGER.h new file mode 100644 index 0000000..62832b1 --- /dev/null +++ b/src/mms/iso_mms/asn1c/INTEGER.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _INTEGER_H_ +#define _INTEGER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; + +extern asn_TYPE_descriptor_t asn_DEF_INTEGER; + +/* Map with to integer value association */ +typedef struct asn_INTEGER_enum_map_s { + long nat_value; /* associated native integer value */ + size_t enum_len; /* strlen("tag") */ + const char *enum_name; /* "tag" */ +} asn_INTEGER_enum_map_t; + +/* This type describes an enumeration for INTEGER and ENUMERATED types */ +typedef struct asn_INTEGER_specifics_s { + asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ + unsigned int *enum2value; /* "tag" => N; sorted by tag */ + int map_count; /* Elements in either map */ + int extension; /* This map is extensible */ + int strict_enumeration; /* Enumeration set is fixed */ +} asn_INTEGER_specifics_t; + +asn_struct_print_f INTEGER_print; +ber_type_decoder_f INTEGER_decode_ber; +der_type_encoder_f INTEGER_encode_der; +xer_type_decoder_f INTEGER_decode_xer; +xer_type_encoder_f INTEGER_encode_xer; +per_type_decoder_f INTEGER_decode_uper; +per_type_encoder_f INTEGER_encode_uper; + +/*********************************** + * Some handy conversion routines. * + ***********************************/ + +/* + * Returns 0 if it was possible to convert, -1 otherwise. + * -1/EINVAL: Mandatory argument missing + * -1/ERANGE: Value encoded is out of range for long representation + * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). + */ +int asn_INTEGER2long(const INTEGER_t *i, long *l); +int asn_long2INTEGER(INTEGER_t *i, long l); + +/* + * Convert the integer value into the corresponding enumeration map entry. + */ +const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); + +#ifdef __cplusplus +} +#endif + +#endif /* _INTEGER_H_ */ diff --git a/src/mms/iso_mms/asn1c/Identifier.c b/src/mms/iso_mms/asn1c/Identifier.c new file mode 100644 index 0000000..a64357a --- /dev/null +++ b/src/mms/iso_mms/asn1c/Identifier.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Identifier.h" + +int +Identifier_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_VisibleString.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using VisibleString, + * so here we adjust the DEF accordingly. + */ +static void +Identifier_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_VisibleString.free_struct; + td->print_struct = asn_DEF_VisibleString.print_struct; + td->ber_decoder = asn_DEF_VisibleString.ber_decoder; + td->der_encoder = asn_DEF_VisibleString.der_encoder; + td->xer_decoder = asn_DEF_VisibleString.xer_decoder; + td->xer_encoder = asn_DEF_VisibleString.xer_encoder; + td->uper_decoder = asn_DEF_VisibleString.uper_decoder; + td->uper_encoder = asn_DEF_VisibleString.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_VisibleString.per_constraints; + td->elements = asn_DEF_VisibleString.elements; + td->elements_count = asn_DEF_VisibleString.elements_count; + td->specifics = asn_DEF_VisibleString.specifics; +} + +void +Identifier_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Identifier_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Identifier_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Identifier_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Identifier_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Identifier_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Identifier_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Identifier_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Identifier_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Identifier_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Identifier_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Identifier_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Identifier_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Identifier = { + "Identifier", + "Identifier", + Identifier_free, + Identifier_print, + Identifier_constraint, + Identifier_decode_ber, + Identifier_encode_der, + Identifier_decode_xer, + Identifier_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Identifier_tags_1, + sizeof(asn_DEF_Identifier_tags_1) + /sizeof(asn_DEF_Identifier_tags_1[0]), /* 1 */ + asn_DEF_Identifier_tags_1, /* Same as above */ + sizeof(asn_DEF_Identifier_tags_1) + /sizeof(asn_DEF_Identifier_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Identifier.h b/src/mms/iso_mms/asn1c/Identifier.h new file mode 100644 index 0000000..6ca982a --- /dev/null +++ b/src/mms/iso_mms/asn1c/Identifier.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Identifier_H_ +#define _Identifier_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Identifier */ +typedef VisibleString_t Identifier_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Identifier; +asn_struct_free_f Identifier_free; +asn_struct_print_f Identifier_print; +asn_constr_check_f Identifier_constraint; +ber_type_decoder_f Identifier_decode_ber; +der_type_encoder_f Identifier_encode_der; +xer_type_decoder_f Identifier_decode_xer; +xer_type_encoder_f Identifier_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Identifier_H_ */ diff --git a/src/mms/iso_mms/asn1c/IndexRangeSeq.c b/src/mms/iso_mms/asn1c/IndexRangeSeq.c new file mode 100644 index 0000000..dc20c43 --- /dev/null +++ b/src/mms/iso_mms/asn1c/IndexRangeSeq.c @@ -0,0 +1,71 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "IndexRangeSeq.h" + +static asn_TYPE_member_t asn_MBR_IndexRangeSeq_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct IndexRangeSeq, lowIndex), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "lowIndex" + }, + { ATF_NOFLAGS, 0, offsetof(struct IndexRangeSeq, numberOfElements), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numberOfElements" + }, +}; +static ber_tlv_tag_t asn_DEF_IndexRangeSeq_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_IndexRangeSeq_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* lowIndex at 592 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* numberOfElements at 594 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_IndexRangeSeq_specs_1 = { + sizeof(struct IndexRangeSeq), + offsetof(struct IndexRangeSeq, _asn_ctx), + asn_MAP_IndexRangeSeq_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_IndexRangeSeq = { + "IndexRangeSeq", + "IndexRangeSeq", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_IndexRangeSeq_tags_1, + sizeof(asn_DEF_IndexRangeSeq_tags_1) + /sizeof(asn_DEF_IndexRangeSeq_tags_1[0]), /* 1 */ + asn_DEF_IndexRangeSeq_tags_1, /* Same as above */ + sizeof(asn_DEF_IndexRangeSeq_tags_1) + /sizeof(asn_DEF_IndexRangeSeq_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_IndexRangeSeq_1, + 2, /* Elements count */ + &asn_SPC_IndexRangeSeq_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/IndexRangeSeq.h b/src/mms/iso_mms/asn1c/IndexRangeSeq.h new file mode 100644 index 0000000..59e4a64 --- /dev/null +++ b/src/mms/iso_mms/asn1c/IndexRangeSeq.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _IndexRangeSeq_H_ +#define _IndexRangeSeq_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* IndexRangeSeq */ +typedef struct IndexRangeSeq { + Unsigned32_t lowIndex; + Unsigned32_t numberOfElements; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} IndexRangeSeq_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_IndexRangeSeq; + +#ifdef __cplusplus +} +#endif + +#endif /* _IndexRangeSeq_H_ */ diff --git a/src/mms/iso_mms/asn1c/InformationReport.c b/src/mms/iso_mms/asn1c/InformationReport.c new file mode 100644 index 0000000..04364f8 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InformationReport.c @@ -0,0 +1,117 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "InformationReport.h" + +static asn_TYPE_member_t asn_MBR_listOfAccessResult_3[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_AccessResult, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfAccessResult_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfAccessResult_specs_3 = { + sizeof(struct InformationReport__listOfAccessResult), + offsetof(struct InformationReport__listOfAccessResult, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfAccessResult_3 = { + "listOfAccessResult", + "listOfAccessResult", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfAccessResult_tags_3, + sizeof(asn_DEF_listOfAccessResult_tags_3) + /sizeof(asn_DEF_listOfAccessResult_tags_3[0]) - 1, /* 1 */ + asn_DEF_listOfAccessResult_tags_3, /* Same as above */ + sizeof(asn_DEF_listOfAccessResult_tags_3) + /sizeof(asn_DEF_listOfAccessResult_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfAccessResult_3, + 1, /* Single element */ + &asn_SPC_listOfAccessResult_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_InformationReport_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct InformationReport, variableAccessSpecification), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_VariableAccessSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableAccessSpecification" + }, + { ATF_NOFLAGS, 0, offsetof(struct InformationReport, listOfAccessResult), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfAccessResult_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfAccessResult" + }, +}; +static ber_tlv_tag_t asn_DEF_InformationReport_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_InformationReport_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 1 }, /* listOfVariable at 760 */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 1, -1, 0 }, /* listOfAccessResult at 625 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 } /* variableListName at 762 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_InformationReport_specs_1 = { + sizeof(struct InformationReport), + offsetof(struct InformationReport, _asn_ctx), + asn_MAP_InformationReport_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_InformationReport = { + "InformationReport", + "InformationReport", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_InformationReport_tags_1, + sizeof(asn_DEF_InformationReport_tags_1) + /sizeof(asn_DEF_InformationReport_tags_1[0]), /* 1 */ + asn_DEF_InformationReport_tags_1, /* Same as above */ + sizeof(asn_DEF_InformationReport_tags_1) + /sizeof(asn_DEF_InformationReport_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_InformationReport_1, + 2, /* Elements count */ + &asn_SPC_InformationReport_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/InformationReport.h b/src/mms/iso_mms/asn1c/InformationReport.h new file mode 100644 index 0000000..e2fb581 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InformationReport.h @@ -0,0 +1,51 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _InformationReport_H_ +#define _InformationReport_H_ + + +#include + +/* Including external dependencies */ +#include "VariableAccessSpecification.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct AccessResult; + +/* InformationReport */ +typedef struct InformationReport { + VariableAccessSpecification_t variableAccessSpecification; + struct InformationReport__listOfAccessResult { + A_SEQUENCE_OF(struct AccessResult) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } listOfAccessResult; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} InformationReport_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_InformationReport; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "AccessResult.h" + +#endif /* _InformationReport_H_ */ diff --git a/src/mms/iso_mms/asn1c/InitRequestDetail.c b/src/mms/iso_mms/asn1c/InitRequestDetail.c new file mode 100644 index 0000000..ec1ae21 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitRequestDetail.c @@ -0,0 +1,81 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "InitRequestDetail.h" + +static asn_TYPE_member_t asn_MBR_InitRequestDetail_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct InitRequestDetail, proposedVersionNumber), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer16, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "proposedVersionNumber" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitRequestDetail, proposedParameterCBB), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ParameterSupportOptions, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "proposedParameterCBB" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitRequestDetail, servicesSupportedCalling), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ServiceSupportOptions, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "servicesSupportedCalling" + }, +}; +static ber_tlv_tag_t asn_DEF_InitRequestDetail_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_InitRequestDetail_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* proposedVersionNumber at 194 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* proposedParameterCBB at 195 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* servicesSupportedCalling at 197 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_InitRequestDetail_specs_1 = { + sizeof(struct InitRequestDetail), + offsetof(struct InitRequestDetail, _asn_ctx), + asn_MAP_InitRequestDetail_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_InitRequestDetail = { + "InitRequestDetail", + "InitRequestDetail", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_InitRequestDetail_tags_1, + sizeof(asn_DEF_InitRequestDetail_tags_1) + /sizeof(asn_DEF_InitRequestDetail_tags_1[0]), /* 1 */ + asn_DEF_InitRequestDetail_tags_1, /* Same as above */ + sizeof(asn_DEF_InitRequestDetail_tags_1) + /sizeof(asn_DEF_InitRequestDetail_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_InitRequestDetail_1, + 3, /* Elements count */ + &asn_SPC_InitRequestDetail_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/InitRequestDetail.h b/src/mms/iso_mms/asn1c/InitRequestDetail.h new file mode 100644 index 0000000..9bb774b --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitRequestDetail.h @@ -0,0 +1,41 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _InitRequestDetail_H_ +#define _InitRequestDetail_H_ + + +#include + +/* Including external dependencies */ +#include "Integer16.h" +#include "ParameterSupportOptions.h" +#include "ServiceSupportOptions.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* InitRequestDetail */ +typedef struct InitRequestDetail { + Integer16_t proposedVersionNumber; + ParameterSupportOptions_t proposedParameterCBB; + ServiceSupportOptions_t servicesSupportedCalling; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} InitRequestDetail_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_InitRequestDetail; + +#ifdef __cplusplus +} +#endif + +#endif /* _InitRequestDetail_H_ */ diff --git a/src/mms/iso_mms/asn1c/InitResponseDetail.c b/src/mms/iso_mms/asn1c/InitResponseDetail.c new file mode 100644 index 0000000..64b567f --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitResponseDetail.c @@ -0,0 +1,81 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "InitResponseDetail.h" + +static asn_TYPE_member_t asn_MBR_InitResponseDetail_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct InitResponseDetail, negotiatedVersionNumber), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer16, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "negotiatedVersionNumber" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitResponseDetail, negotiatedParameterCBB), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ParameterSupportOptions, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "negotiatedParameterCBB" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitResponseDetail, servicesSupportedCalled), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ServiceSupportOptions, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "servicesSupportedCalled" + }, +}; +static ber_tlv_tag_t asn_DEF_InitResponseDetail_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_InitResponseDetail_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* negotiatedVersionNumber at 210 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* negotiatedParameterCBB at 211 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* servicesSupportedCalled at 213 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_InitResponseDetail_specs_1 = { + sizeof(struct InitResponseDetail), + offsetof(struct InitResponseDetail, _asn_ctx), + asn_MAP_InitResponseDetail_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_InitResponseDetail = { + "InitResponseDetail", + "InitResponseDetail", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_InitResponseDetail_tags_1, + sizeof(asn_DEF_InitResponseDetail_tags_1) + /sizeof(asn_DEF_InitResponseDetail_tags_1[0]), /* 1 */ + asn_DEF_InitResponseDetail_tags_1, /* Same as above */ + sizeof(asn_DEF_InitResponseDetail_tags_1) + /sizeof(asn_DEF_InitResponseDetail_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_InitResponseDetail_1, + 3, /* Elements count */ + &asn_SPC_InitResponseDetail_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/InitResponseDetail.h b/src/mms/iso_mms/asn1c/InitResponseDetail.h new file mode 100644 index 0000000..77e1433 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitResponseDetail.h @@ -0,0 +1,41 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _InitResponseDetail_H_ +#define _InitResponseDetail_H_ + + +#include + +/* Including external dependencies */ +#include "Integer16.h" +#include "ParameterSupportOptions.h" +#include "ServiceSupportOptions.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* InitResponseDetail */ +typedef struct InitResponseDetail { + Integer16_t negotiatedVersionNumber; + ParameterSupportOptions_t negotiatedParameterCBB; + ServiceSupportOptions_t servicesSupportedCalled; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} InitResponseDetail_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_InitResponseDetail; + +#ifdef __cplusplus +} +#endif + +#endif /* _InitResponseDetail_H_ */ diff --git a/src/mms/iso_mms/asn1c/InitiateErrorPdu.c b/src/mms/iso_mms/asn1c/InitiateErrorPdu.c new file mode 100644 index 0000000..e963402 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitiateErrorPdu.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "InitiateErrorPdu.h" + +int +InitiateErrorPdu_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_ServiceError.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using ServiceError, + * so here we adjust the DEF accordingly. + */ +static void +InitiateErrorPdu_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_ServiceError.free_struct; + td->print_struct = asn_DEF_ServiceError.print_struct; + td->ber_decoder = asn_DEF_ServiceError.ber_decoder; + td->der_encoder = asn_DEF_ServiceError.der_encoder; + td->xer_decoder = asn_DEF_ServiceError.xer_decoder; + td->xer_encoder = asn_DEF_ServiceError.xer_encoder; + td->uper_decoder = asn_DEF_ServiceError.uper_decoder; + td->uper_encoder = asn_DEF_ServiceError.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_ServiceError.per_constraints; + td->elements = asn_DEF_ServiceError.elements; + td->elements_count = asn_DEF_ServiceError.elements_count; + td->specifics = asn_DEF_ServiceError.specifics; +} + +void +InitiateErrorPdu_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + InitiateErrorPdu_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +InitiateErrorPdu_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + InitiateErrorPdu_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +InitiateErrorPdu_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + InitiateErrorPdu_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +InitiateErrorPdu_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + InitiateErrorPdu_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +InitiateErrorPdu_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + InitiateErrorPdu_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +InitiateErrorPdu_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + InitiateErrorPdu_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_InitiateErrorPdu_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_InitiateErrorPdu = { + "InitiateErrorPdu", + "InitiateErrorPdu", + InitiateErrorPdu_free, + InitiateErrorPdu_print, + InitiateErrorPdu_constraint, + InitiateErrorPdu_decode_ber, + InitiateErrorPdu_encode_der, + InitiateErrorPdu_decode_xer, + InitiateErrorPdu_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_InitiateErrorPdu_tags_1, + sizeof(asn_DEF_InitiateErrorPdu_tags_1) + /sizeof(asn_DEF_InitiateErrorPdu_tags_1[0]), /* 1 */ + asn_DEF_InitiateErrorPdu_tags_1, /* Same as above */ + sizeof(asn_DEF_InitiateErrorPdu_tags_1) + /sizeof(asn_DEF_InitiateErrorPdu_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* Defined elsewhere */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/InitiateErrorPdu.h b/src/mms/iso_mms/asn1c/InitiateErrorPdu.h new file mode 100644 index 0000000..b472c67 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitiateErrorPdu.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _InitiateErrorPdu_H_ +#define _InitiateErrorPdu_H_ + + +#include + +/* Including external dependencies */ +#include "ServiceError.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* InitiateErrorPdu */ +typedef ServiceError_t InitiateErrorPdu_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_InitiateErrorPdu; +asn_struct_free_f InitiateErrorPdu_free; +asn_struct_print_f InitiateErrorPdu_print; +asn_constr_check_f InitiateErrorPdu_constraint; +ber_type_decoder_f InitiateErrorPdu_decode_ber; +der_type_encoder_f InitiateErrorPdu_encode_der; +xer_type_decoder_f InitiateErrorPdu_decode_xer; +xer_type_encoder_f InitiateErrorPdu_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _InitiateErrorPdu_H_ */ diff --git a/src/mms/iso_mms/asn1c/InitiateRequestPdu.c b/src/mms/iso_mms/asn1c/InitiateRequestPdu.c new file mode 100644 index 0000000..9f00a7d --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitiateRequestPdu.c @@ -0,0 +1,101 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "InitiateRequestPdu.h" + +static asn_TYPE_member_t asn_MBR_InitiateRequestPdu_1[] = { + { ATF_POINTER, 1, offsetof(struct InitiateRequestPdu, localDetailCalling), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "localDetailCalling" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitiateRequestPdu, proposedMaxServOutstandingCalling), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer16, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "proposedMaxServOutstandingCalling" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitiateRequestPdu, proposedMaxServOutstandingCalled), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer16, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "proposedMaxServOutstandingCalled" + }, + { ATF_POINTER, 1, offsetof(struct InitiateRequestPdu, proposedDataStructureNestingLevel), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "proposedDataStructureNestingLevel" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitiateRequestPdu, mmsInitRequestDetail), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_InitRequestDetail, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mmsInitRequestDetail" + }, +}; +static ber_tlv_tag_t asn_DEF_InitiateRequestPdu_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_InitiateRequestPdu_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* localDetailCalling at 185 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* proposedMaxServOutstandingCalling at 186 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* proposedMaxServOutstandingCalled at 187 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* proposedDataStructureNestingLevel at 188 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 } /* mmsInitRequestDetail at 190 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_InitiateRequestPdu_specs_1 = { + sizeof(struct InitiateRequestPdu), + offsetof(struct InitiateRequestPdu, _asn_ctx), + asn_MAP_InitiateRequestPdu_tag2el_1, + 5, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_InitiateRequestPdu = { + "InitiateRequestPdu", + "InitiateRequestPdu", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_InitiateRequestPdu_tags_1, + sizeof(asn_DEF_InitiateRequestPdu_tags_1) + /sizeof(asn_DEF_InitiateRequestPdu_tags_1[0]), /* 1 */ + asn_DEF_InitiateRequestPdu_tags_1, /* Same as above */ + sizeof(asn_DEF_InitiateRequestPdu_tags_1) + /sizeof(asn_DEF_InitiateRequestPdu_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_InitiateRequestPdu_1, + 5, /* Elements count */ + &asn_SPC_InitiateRequestPdu_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/InitiateRequestPdu.h b/src/mms/iso_mms/asn1c/InitiateRequestPdu.h new file mode 100644 index 0000000..4739c73 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitiateRequestPdu.h @@ -0,0 +1,44 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _InitiateRequestPdu_H_ +#define _InitiateRequestPdu_H_ + + +#include + +/* Including external dependencies */ +#include "Integer32.h" +#include "Integer16.h" +#include "Integer8.h" +#include "InitRequestDetail.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* InitiateRequestPdu */ +typedef struct InitiateRequestPdu { + Integer32_t *localDetailCalling /* OPTIONAL */; + Integer16_t proposedMaxServOutstandingCalling; + Integer16_t proposedMaxServOutstandingCalled; + Integer8_t *proposedDataStructureNestingLevel /* OPTIONAL */; + InitRequestDetail_t mmsInitRequestDetail; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} InitiateRequestPdu_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_InitiateRequestPdu; + +#ifdef __cplusplus +} +#endif + +#endif /* _InitiateRequestPdu_H_ */ diff --git a/src/mms/iso_mms/asn1c/InitiateResponsePdu.c b/src/mms/iso_mms/asn1c/InitiateResponsePdu.c new file mode 100644 index 0000000..51658fb --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitiateResponsePdu.c @@ -0,0 +1,101 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "InitiateResponsePdu.h" + +static asn_TYPE_member_t asn_MBR_InitiateResponsePdu_1[] = { + { ATF_POINTER, 1, offsetof(struct InitiateResponsePdu, localDetailCalled), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "localDetailCalled" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitiateResponsePdu, negotiatedMaxServOutstandingCalling), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer16, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "negotiatedMaxServOutstandingCalling" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitiateResponsePdu, negotiatedMaxServOutstandingCalled), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer16, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "negotiatedMaxServOutstandingCalled" + }, + { ATF_POINTER, 1, offsetof(struct InitiateResponsePdu, negotiatedDataStructureNestingLevel), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "negotiatedDataStructureNestingLevel" + }, + { ATF_NOFLAGS, 0, offsetof(struct InitiateResponsePdu, mmsInitResponseDetail), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_InitResponseDetail, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mmsInitResponseDetail" + }, +}; +static ber_tlv_tag_t asn_DEF_InitiateResponsePdu_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_InitiateResponsePdu_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* localDetailCalled at 201 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* negotiatedMaxServOutstandingCalling at 202 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* negotiatedMaxServOutstandingCalled at 203 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* negotiatedDataStructureNestingLevel at 204 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 } /* mmsInitResponseDetail at 206 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_InitiateResponsePdu_specs_1 = { + sizeof(struct InitiateResponsePdu), + offsetof(struct InitiateResponsePdu, _asn_ctx), + asn_MAP_InitiateResponsePdu_tag2el_1, + 5, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_InitiateResponsePdu = { + "InitiateResponsePdu", + "InitiateResponsePdu", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_InitiateResponsePdu_tags_1, + sizeof(asn_DEF_InitiateResponsePdu_tags_1) + /sizeof(asn_DEF_InitiateResponsePdu_tags_1[0]), /* 1 */ + asn_DEF_InitiateResponsePdu_tags_1, /* Same as above */ + sizeof(asn_DEF_InitiateResponsePdu_tags_1) + /sizeof(asn_DEF_InitiateResponsePdu_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_InitiateResponsePdu_1, + 5, /* Elements count */ + &asn_SPC_InitiateResponsePdu_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/InitiateResponsePdu.h b/src/mms/iso_mms/asn1c/InitiateResponsePdu.h new file mode 100644 index 0000000..e0c31d4 --- /dev/null +++ b/src/mms/iso_mms/asn1c/InitiateResponsePdu.h @@ -0,0 +1,44 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _InitiateResponsePdu_H_ +#define _InitiateResponsePdu_H_ + + +#include + +/* Including external dependencies */ +#include "Integer32.h" +#include "Integer16.h" +#include "Integer8.h" +#include "InitResponseDetail.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* InitiateResponsePdu */ +typedef struct InitiateResponsePdu { + Integer32_t *localDetailCalled /* OPTIONAL */; + Integer16_t negotiatedMaxServOutstandingCalling; + Integer16_t negotiatedMaxServOutstandingCalled; + Integer8_t *negotiatedDataStructureNestingLevel /* OPTIONAL */; + InitResponseDetail_t mmsInitResponseDetail; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} InitiateResponsePdu_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_InitiateResponsePdu; + +#ifdef __cplusplus +} +#endif + +#endif /* _InitiateResponsePdu_H_ */ diff --git a/src/mms/iso_mms/asn1c/Integer16.c b/src/mms/iso_mms/asn1c/Integer16.c new file mode 100644 index 0000000..cee15bd --- /dev/null +++ b/src/mms/iso_mms/asn1c/Integer16.c @@ -0,0 +1,127 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Integer16.h" + +int +Integer16_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= -32768 && value <= 32767)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +Integer16_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + td->specifics = asn_DEF_NativeInteger.specifics; +} + +void +Integer16_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Integer16_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Integer16_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Integer16_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Integer16_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Integer16_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Integer16_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Integer16_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Integer16_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Integer16_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Integer16_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Integer16_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Integer16_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Integer16 = { + "Integer16", + "Integer16", + Integer16_free, + Integer16_print, + Integer16_constraint, + Integer16_decode_ber, + Integer16_encode_der, + Integer16_decode_xer, + Integer16_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Integer16_tags_1, + sizeof(asn_DEF_Integer16_tags_1) + /sizeof(asn_DEF_Integer16_tags_1[0]), /* 1 */ + asn_DEF_Integer16_tags_1, /* Same as above */ + sizeof(asn_DEF_Integer16_tags_1) + /sizeof(asn_DEF_Integer16_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Integer16.h b/src/mms/iso_mms/asn1c/Integer16.h new file mode 100644 index 0000000..1657f3c --- /dev/null +++ b/src/mms/iso_mms/asn1c/Integer16.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Integer16_H_ +#define _Integer16_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Integer16 */ +typedef long Integer16_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Integer16; +asn_struct_free_f Integer16_free; +asn_struct_print_f Integer16_print; +asn_constr_check_f Integer16_constraint; +ber_type_decoder_f Integer16_decode_ber; +der_type_encoder_f Integer16_encode_der; +xer_type_decoder_f Integer16_decode_xer; +xer_type_encoder_f Integer16_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Integer16_H_ */ diff --git a/src/mms/iso_mms/asn1c/Integer32.c b/src/mms/iso_mms/asn1c/Integer32.c new file mode 100644 index 0000000..dea4ffd --- /dev/null +++ b/src/mms/iso_mms/asn1c/Integer32.c @@ -0,0 +1,127 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Integer32.h" + +int +Integer32_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= -2147483648 && value <= 2147483647)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +Integer32_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + td->specifics = asn_DEF_NativeInteger.specifics; +} + +void +Integer32_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Integer32_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Integer32_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Integer32_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Integer32_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Integer32_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Integer32_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Integer32_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Integer32_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Integer32_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Integer32_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Integer32_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Integer32_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Integer32 = { + "Integer32", + "Integer32", + Integer32_free, + Integer32_print, + Integer32_constraint, + Integer32_decode_ber, + Integer32_encode_der, + Integer32_decode_xer, + Integer32_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Integer32_tags_1, + sizeof(asn_DEF_Integer32_tags_1) + /sizeof(asn_DEF_Integer32_tags_1[0]), /* 1 */ + asn_DEF_Integer32_tags_1, /* Same as above */ + sizeof(asn_DEF_Integer32_tags_1) + /sizeof(asn_DEF_Integer32_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Integer32.h b/src/mms/iso_mms/asn1c/Integer32.h new file mode 100644 index 0000000..ef33047 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Integer32.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Integer32_H_ +#define _Integer32_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Integer32 */ +typedef long Integer32_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Integer32; +asn_struct_free_f Integer32_free; +asn_struct_print_f Integer32_print; +asn_constr_check_f Integer32_constraint; +ber_type_decoder_f Integer32_decode_ber; +der_type_encoder_f Integer32_encode_der; +xer_type_decoder_f Integer32_decode_xer; +xer_type_encoder_f Integer32_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Integer32_H_ */ diff --git a/src/mms/iso_mms/asn1c/Integer8.c b/src/mms/iso_mms/asn1c/Integer8.c new file mode 100644 index 0000000..15962de --- /dev/null +++ b/src/mms/iso_mms/asn1c/Integer8.c @@ -0,0 +1,127 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Integer8.h" + +int +Integer8_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= -128 && value <= 127)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +Integer8_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + td->specifics = asn_DEF_NativeInteger.specifics; +} + +void +Integer8_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Integer8_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Integer8_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Integer8_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Integer8_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Integer8_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Integer8_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Integer8_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Integer8_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Integer8_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Integer8_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Integer8_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Integer8_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Integer8 = { + "Integer8", + "Integer8", + Integer8_free, + Integer8_print, + Integer8_constraint, + Integer8_decode_ber, + Integer8_encode_der, + Integer8_decode_xer, + Integer8_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Integer8_tags_1, + sizeof(asn_DEF_Integer8_tags_1) + /sizeof(asn_DEF_Integer8_tags_1[0]), /* 1 */ + asn_DEF_Integer8_tags_1, /* Same as above */ + sizeof(asn_DEF_Integer8_tags_1) + /sizeof(asn_DEF_Integer8_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Integer8.h b/src/mms/iso_mms/asn1c/Integer8.h new file mode 100644 index 0000000..4264509 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Integer8.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Integer8_H_ +#define _Integer8_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Integer8 */ +typedef long Integer8_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Integer8; +asn_struct_free_f Integer8_free; +asn_struct_print_f Integer8_print; +asn_constr_check_f Integer8_constraint; +ber_type_decoder_f Integer8_decode_ber; +der_type_encoder_f Integer8_encode_der; +xer_type_decoder_f Integer8_decode_xer; +xer_type_encoder_f Integer8_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Integer8_H_ */ diff --git a/src/mms/iso_mms/asn1c/ListOfVariableSeq.c b/src/mms/iso_mms/asn1c/ListOfVariableSeq.c new file mode 100644 index 0000000..d926d56 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ListOfVariableSeq.c @@ -0,0 +1,75 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ListOfVariableSeq.h" + +static asn_TYPE_member_t asn_MBR_ListOfVariableSeq_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ListOfVariableSeq, variableSpecification), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_VariableSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableSpecification" + }, + { ATF_POINTER, 1, offsetof(struct ListOfVariableSeq, alternateAccess), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_AlternateAccess, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "alternateAccess" + }, +}; +static ber_tlv_tag_t asn_DEF_ListOfVariableSeq_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ListOfVariableSeq_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* name at 772 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* address at 773 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 }, /* variableDescription at 776 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 0, 0, 0 }, /* scatteredAccessDescription at 779 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 0, 0, 0 }, /* invalidated at 780 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 } /* alternateAccess at 767 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ListOfVariableSeq_specs_1 = { + sizeof(struct ListOfVariableSeq), + offsetof(struct ListOfVariableSeq, _asn_ctx), + asn_MAP_ListOfVariableSeq_tag2el_1, + 6, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ListOfVariableSeq = { + "ListOfVariableSeq", + "ListOfVariableSeq", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ListOfVariableSeq_tags_1, + sizeof(asn_DEF_ListOfVariableSeq_tags_1) + /sizeof(asn_DEF_ListOfVariableSeq_tags_1[0]), /* 1 */ + asn_DEF_ListOfVariableSeq_tags_1, /* Same as above */ + sizeof(asn_DEF_ListOfVariableSeq_tags_1) + /sizeof(asn_DEF_ListOfVariableSeq_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ListOfVariableSeq_1, + 2, /* Elements count */ + &asn_SPC_ListOfVariableSeq_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ListOfVariableSeq.h b/src/mms/iso_mms/asn1c/ListOfVariableSeq.h new file mode 100644 index 0000000..07e2c4b --- /dev/null +++ b/src/mms/iso_mms/asn1c/ListOfVariableSeq.h @@ -0,0 +1,44 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ListOfVariableSeq_H_ +#define _ListOfVariableSeq_H_ + + +#include + +/* Including external dependencies */ +#include "VariableSpecification.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct AlternateAccess; + +/* ListOfVariableSeq */ +typedef struct ListOfVariableSeq { + VariableSpecification_t variableSpecification; + struct AlternateAccess *alternateAccess /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ListOfVariableSeq_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ListOfVariableSeq; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "AlternateAccess.h" + +#endif /* _ListOfVariableSeq_H_ */ diff --git a/src/mms/iso_mms/asn1c/MMSString.c b/src/mms/iso_mms/asn1c/MMSString.c new file mode 100644 index 0000000..dc60765 --- /dev/null +++ b/src/mms/iso_mms/asn1c/MMSString.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "MMSString.h" + +int +MMSString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_UTF8String.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using UTF8String, + * so here we adjust the DEF accordingly. + */ +static void +MMSString_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_UTF8String.free_struct; + td->print_struct = asn_DEF_UTF8String.print_struct; + td->ber_decoder = asn_DEF_UTF8String.ber_decoder; + td->der_encoder = asn_DEF_UTF8String.der_encoder; + td->xer_decoder = asn_DEF_UTF8String.xer_decoder; + td->xer_encoder = asn_DEF_UTF8String.xer_encoder; + td->uper_decoder = asn_DEF_UTF8String.uper_decoder; + td->uper_encoder = asn_DEF_UTF8String.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_UTF8String.per_constraints; + td->elements = asn_DEF_UTF8String.elements; + td->elements_count = asn_DEF_UTF8String.elements_count; + td->specifics = asn_DEF_UTF8String.specifics; +} + +void +MMSString_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + MMSString_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +MMSString_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + MMSString_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +MMSString_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + MMSString_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +MMSString_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + MMSString_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +MMSString_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + MMSString_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +MMSString_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + MMSString_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_MMSString_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (12 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_MMSString = { + "MMSString", + "MMSString", + MMSString_free, + MMSString_print, + MMSString_constraint, + MMSString_decode_ber, + MMSString_encode_der, + MMSString_decode_xer, + MMSString_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_MMSString_tags_1, + sizeof(asn_DEF_MMSString_tags_1) + /sizeof(asn_DEF_MMSString_tags_1[0]), /* 1 */ + asn_DEF_MMSString_tags_1, /* Same as above */ + sizeof(asn_DEF_MMSString_tags_1) + /sizeof(asn_DEF_MMSString_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/MMSString.h b/src/mms/iso_mms/asn1c/MMSString.h new file mode 100644 index 0000000..0c1e783 --- /dev/null +++ b/src/mms/iso_mms/asn1c/MMSString.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _MMSString_H_ +#define _MMSString_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* MMSString */ +typedef UTF8String_t MMSString_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_MMSString; +asn_struct_free_f MMSString_free; +asn_struct_print_f MMSString_print; +asn_constr_check_f MMSString_constraint; +ber_type_decoder_f MMSString_decode_ber; +der_type_encoder_f MMSString_encode_der; +xer_type_decoder_f MMSString_decode_xer; +xer_type_encoder_f MMSString_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _MMSString_H_ */ diff --git a/src/mms/iso_mms/asn1c/MmsPdu.c b/src/mms/iso_mms/asn1c/MmsPdu.c new file mode 100644 index 0000000..5ef43d9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/MmsPdu.c @@ -0,0 +1,147 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "MmsPdu.h" + +static asn_TYPE_member_t asn_MBR_MmsPdu_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.confirmedRequestPdu), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ConfirmedRequestPdu, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedRequestPdu" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.confirmedResponsePdu), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ConfirmedResponsePdu, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedResponsePdu" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.confirmedErrorPDU), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ConfirmedErrorPDU, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedErrorPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.unconfirmedPDU), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_UnconfirmedPDU, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unconfirmedPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.rejectPDU), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_RejectPDU, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "rejectPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.initiateRequestPdu), + (ASN_TAG_CLASS_CONTEXT | (8 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_InitiateRequestPdu, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "initiateRequestPdu" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.initiateResponsePdu), + (ASN_TAG_CLASS_CONTEXT | (9 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_InitiateResponsePdu, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "initiateResponsePdu" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.initiateErrorPdu), + (ASN_TAG_CLASS_CONTEXT | (10 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_InitiateErrorPdu, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "initiateErrorPdu" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.concludeRequestPDU), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ConcludeRequestPDU, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "concludeRequestPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct MmsPdu, choice.concludeResponsePDU), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ConcludeResponsePDU, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "concludeResponsePDU" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_MmsPdu_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* confirmedRequestPdu at 13 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* confirmedResponsePdu at 14 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* confirmedErrorPDU at 15 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* unconfirmedPDU at 16 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* rejectPDU at 17 */ + { (ASN_TAG_CLASS_CONTEXT | (8 << 2)), 5, 0, 0 }, /* initiateRequestPdu at 19 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 6, 0, 0 }, /* initiateResponsePdu at 20 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 7, 0, 0 }, /* initiateErrorPdu at 21 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 8, 0, 0 }, /* concludeRequestPDU at 22 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 9, 0, 0 } /* concludeResponsePDU at 24 */ +}; +static asn_CHOICE_specifics_t asn_SPC_MmsPdu_specs_1 = { + sizeof(struct MmsPdu), + offsetof(struct MmsPdu, _asn_ctx), + offsetof(struct MmsPdu, present), + sizeof(((struct MmsPdu *)0)->present), + asn_MAP_MmsPdu_tag2el_1, + 10, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_MmsPdu = { + "MmsPdu", + "MmsPdu", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_MmsPdu_1, + 10, /* Elements count */ + &asn_SPC_MmsPdu_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/MmsPdu.h b/src/mms/iso_mms/asn1c/MmsPdu.h new file mode 100644 index 0000000..2ef71ca --- /dev/null +++ b/src/mms/iso_mms/asn1c/MmsPdu.h @@ -0,0 +1,73 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _MmsPdu_H_ +#define _MmsPdu_H_ + + +#include + +/* Including external dependencies */ +#include "ConfirmedRequestPdu.h" +#include "ConfirmedResponsePdu.h" +#include "ConfirmedErrorPDU.h" +#include "UnconfirmedPDU.h" +#include "RejectPDU.h" +#include "InitiateRequestPdu.h" +#include "InitiateResponsePdu.h" +#include "InitiateErrorPdu.h" +#include "ConcludeRequestPDU.h" +#include "ConcludeResponsePDU.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum MmsPdu_PR { + MmsPdu_PR_NOTHING, /* No components present */ + MmsPdu_PR_confirmedRequestPdu, + MmsPdu_PR_confirmedResponsePdu, + MmsPdu_PR_confirmedErrorPDU, + MmsPdu_PR_unconfirmedPDU, + MmsPdu_PR_rejectPDU, + MmsPdu_PR_initiateRequestPdu, + MmsPdu_PR_initiateResponsePdu, + MmsPdu_PR_initiateErrorPdu, + MmsPdu_PR_concludeRequestPDU, + MmsPdu_PR_concludeResponsePDU +} MmsPdu_PR; + +/* MmsPdu */ +typedef struct MmsPdu { + MmsPdu_PR present; + union MmsPdu_u { + ConfirmedRequestPdu_t confirmedRequestPdu; + ConfirmedResponsePdu_t confirmedResponsePdu; + ConfirmedErrorPDU_t confirmedErrorPDU; + UnconfirmedPDU_t unconfirmedPDU; + RejectPDU_t rejectPDU; + InitiateRequestPdu_t initiateRequestPdu; + InitiateResponsePdu_t initiateResponsePdu; + InitiateErrorPdu_t initiateErrorPdu; + ConcludeRequestPDU_t concludeRequestPDU; + ConcludeResponsePDU_t concludeResponsePDU; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} MmsPdu_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_MmsPdu; + +#ifdef __cplusplus +} +#endif + +#endif /* _MmsPdu_H_ */ diff --git a/src/mms/iso_mms/asn1c/NULL.c b/src/mms/iso_mms/asn1c/NULL.c new file mode 100644 index 0000000..6d3316f --- /dev/null +++ b/src/mms/iso_mms/asn1c/NULL.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include /* Implemented in terms of BOOLEAN type */ + +/* + * NULL basic type description. + */ +static ber_tlv_tag_t asn_DEF_NULL_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (5 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_NULL = { + "NULL", + "NULL", + BOOLEAN_free, + NULL_print, + asn_generic_no_constraint, + BOOLEAN_decode_ber, /* Implemented in terms of BOOLEAN */ + NULL_encode_der, /* Special handling of DER encoding */ + NULL_decode_xer, + NULL_encode_xer, + NULL_decode_uper, /* Unaligned PER decoder */ + NULL_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NULL_tags, + sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]), + asn_DEF_NULL_tags, /* Same as above */ + sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +asn_enc_rval_t +NULL_encode_der(asn_TYPE_descriptor_t *td, void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t erval; + + erval.encoded = der_write_tags(td, 0, tag_mode, 0, tag, cb, app_key); + if(erval.encoded == -1) { + erval.failed_type = td; + erval.structure_ptr = ptr; + } + + _ASN_ENCODED_OK(erval); +} + +asn_enc_rval_t +NULL_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + + (void)td; + (void)sptr; + (void)ilevel; + (void)flags; + (void)cb; + (void)app_key; + + /* XMLNullValue is empty */ + er.encoded = 0; + _ASN_ENCODED_OK(er); +} + + +static enum xer_pbd_rval +NULL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { + (void)td; + (void)sptr; + + if(xer_is_whitespace(chunk_buf, chunk_size)) + return XPBD_BODY_CONSUMED; + else + return XPBD_BROKEN_ENCODING; +} + +asn_dec_rval_t +NULL_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(NULL_t), opt_mname, buf_ptr, size, + NULL__xer_body_decode); +} + +int +NULL_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(sptr) { + return (cb("", 9, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +asn_dec_rval_t +NULL_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + + (void)opt_codec_ctx; + (void)td; + (void)constraints; + (void)pd; + + if(!*sptr) { + *sptr = MALLOC(sizeof(NULL_t)); + if(*sptr) { + *(NULL_t *)*sptr = 0; + } else { + _ASN_DECODE_FAILED; + } + } + + /* + * NULL type does not have content octets. + */ + + rv.code = RC_OK; + rv.consumed = 0; + return rv; +} + +asn_enc_rval_t +NULL_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void *sptr, asn_per_outp_t *po) { + asn_enc_rval_t er; + + (void)td; + (void)constraints; + (void)sptr; + (void)po; + + er.encoded = 0; + _ASN_ENCODED_OK(er); +} diff --git a/src/mms/iso_mms/asn1c/NULL.h b/src/mms/iso_mms/asn1c/NULL.h new file mode 100644 index 0000000..131e775 --- /dev/null +++ b/src/mms/iso_mms/asn1c/NULL.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_TYPE_NULL_H +#define ASN_TYPE_NULL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The value of the NULL type is meaningless: see BOOLEAN if you want to + * carry true/false semantics. + */ +typedef int NULL_t; + +extern asn_TYPE_descriptor_t asn_DEF_NULL; + +asn_struct_print_f NULL_print; +der_type_encoder_f NULL_encode_der; +xer_type_decoder_f NULL_decode_xer; +xer_type_encoder_f NULL_encode_xer; +per_type_decoder_f NULL_decode_uper; +per_type_encoder_f NULL_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* NULL_H */ diff --git a/src/mms/iso_mms/asn1c/NativeEnumerated.c b/src/mms/iso_mms/asn1c/NativeEnumerated.c new file mode 100644 index 0000000..76aab81 --- /dev/null +++ b/src/mms/iso_mms/asn1c/NativeEnumerated.c @@ -0,0 +1,207 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Read the NativeInteger.h for the explanation wrt. differences between + * INTEGER and NativeInteger. + * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this + * implementation deals with the standard (machine-specific) representation + * of them instead of using the platform-independent buffer. + */ +#include +#include + +/* + * NativeEnumerated basic type description. + */ +static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { + "ENUMERATED", /* The ASN.1 type is still ENUMERATED */ + "ENUMERATED", + NativeInteger_free, + NULL, + asn_generic_no_constraint, + NativeInteger_decode_ber, + NativeInteger_encode_der, + NULL, + NULL, + //NativeEnumerated_encode_xer, + NativeEnumerated_decode_uper, + NativeEnumerated_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeEnumerated_tags, + sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), + asn_DEF_NativeEnumerated_tags, /* Same as above */ + sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +#if 0 +asn_enc_rval_t +NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + const long *native = (const long *)sptr; + const asn_INTEGER_enum_map_t *el; + + (void)ilevel; + (void)flags; + + if(!native) _ASN_ENCODE_FAILED; + + el = INTEGER_map_value2enum(specs, *native); + if(el) { + size_t srcsize = el->enum_len + 5; + char *src = (char *)alloca(srcsize); + + er.encoded = snprintf(src, srcsize, "<%s/>", el->enum_name); + assert(er.encoded > 0 && (size_t)er.encoded < srcsize); + if(cb(src, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } else { + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + _ASN_ENCODE_FAILED; + } +} +#endif + +asn_dec_rval_t +NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd) { + asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval = { RC_OK, 0 }; + long *native = (long *)*sptr; + asn_per_constraint_t *ct; + long value; + + (void)opt_codec_ctx; + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else _ASN_DECODE_FAILED; /* Mandatory! */ + if(!specs) _ASN_DECODE_FAILED; + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) _ASN_DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); + + if(ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) _ASN_DECODE_STARVED; + if(inext) ct = 0; + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + if(value >= (specs->extension + ? specs->extension - 1 : specs->map_count)) + _ASN_DECODE_FAILED; + } else { + if(!specs->extension) + _ASN_DECODE_FAILED; + /* + * X.691, #10.6: normally small non-negative whole number; + */ + value = uper_get_nsnnwn(pd); + if(value < 0) _ASN_DECODE_STARVED; + value += specs->extension - 1; + if(value >= specs->map_count) + _ASN_DECODE_FAILED; + } + + *native = specs->value2enum[value].nat_value; + ASN_DEBUG("Decoded %s = %ld", td->name, *native); + + return rval; +} + +static int +NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { + const asn_INTEGER_enum_map_t *a = ap; + const asn_INTEGER_enum_map_t *b = bp; + if(a->nat_value == b->nat_value) + return 0; + if(a->nat_value < b->nat_value) + return -1; + return 1; +} + +asn_enc_rval_t +NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + long native, value; + asn_per_constraint_t *ct; + int inext = 0; + asn_INTEGER_enum_map_t key; + asn_INTEGER_enum_map_t *kf; + + if(!sptr) _ASN_ENCODE_FAILED; + if(!specs) _ASN_ENCODE_FAILED; + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else _ASN_ENCODE_FAILED; /* Mandatory! */ + + ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); + + er.encoded = 0; + + native = *(long *)sptr; + if(native < 0) _ASN_ENCODE_FAILED; + + key.nat_value = native; + kf = bsearch(&key, specs->value2enum, specs->map_count, + sizeof(key), NativeEnumerated__compar_value2enum); + if(!kf) { + ASN_DEBUG("No element corresponds to %ld", native); + _ASN_ENCODE_FAILED; + } + value = kf - specs->value2enum; + + if(ct->range_bits >= 0) { + int cmpWith = specs->extension + ? specs->extension - 1 : specs->map_count; + if(value >= cmpWith) + inext = 1; + } + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 0)) + _ASN_ENCODE_FAILED; + ct = 0; + } else if(inext) { + _ASN_ENCODE_FAILED; + } + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, value, ct->range_bits)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + if(!specs->extension) + _ASN_ENCODE_FAILED; + + /* + * X.691, #10.6: normally small non-negative whole number; + */ + if(uper_put_nsnnwn(po, value - (specs->extension - 1))) + _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(er); +} + diff --git a/src/mms/iso_mms/asn1c/NativeEnumerated.h b/src/mms/iso_mms/asn1c/NativeEnumerated.h new file mode 100644 index 0000000..c59bb1b --- /dev/null +++ b/src/mms/iso_mms/asn1c/NativeEnumerated.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This type differs from the standard ENUMERATED in that it is modelled using + * the fixed machine type (long, int, short), so it can hold only values of + * limited length. There is no type (i.e., NativeEnumerated_t, any integer type + * will do). + * This type may be used when integer range is limited by subtype constraints. + */ +#ifndef _NativeEnumerated_H_ +#define _NativeEnumerated_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; + +xer_type_encoder_f NativeEnumerated_encode_xer; +per_type_decoder_f NativeEnumerated_decode_uper; +per_type_encoder_f NativeEnumerated_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _NativeEnumerated_H_ */ diff --git a/src/mms/iso_mms/asn1c/NativeInteger.c b/src/mms/iso_mms/asn1c/NativeInteger.c new file mode 100644 index 0000000..4a6f561 --- /dev/null +++ b/src/mms/iso_mms/asn1c/NativeInteger.c @@ -0,0 +1,233 @@ +/*- + * Copyright (c) 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Read the NativeInteger.h for the explanation wrt. differences between + * INTEGER and NativeInteger. + * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this + * implementation deals with the standard (machine-specific) representation + * of them instead of using the platform-independent buffer. + */ +#include +#include + +/* + * NativeInteger basic type description. + */ +static ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_NativeInteger = { + "INTEGER", /* The ASN.1 type is still INTEGER */ + "INTEGER", + NativeInteger_free, + NULL, + asn_generic_no_constraint, + NativeInteger_decode_ber, + NativeInteger_encode_der, + NULL, + NULL, + NativeInteger_decode_uper, /* Unaligned PER decoder */ + NativeInteger_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeInteger_tags, + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), + asn_DEF_NativeInteger_tags, /* Same as above */ + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Decode INTEGER type. + */ +asn_dec_rval_t +NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) { + long *native = (long *)*nint_ptr; + asn_dec_rval_t rval; + ber_tlv_len_t length; + + /* + * If the structure is not there, allocate it. + */ + if(native == NULL) { + native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); + if(native == NULL) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } + + ASN_DEBUG("Decoding %s as INTEGER (tm=%d)", + td->name, tag_mode); + + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("%s length is %d bytes", td->name, (int)length); + + /* + * Make sure we have this length. + */ + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + /* + * ASN.1 encoded INTEGER: buf_ptr, length + * Fill the native, at the same time checking for overflow. + * If overflow occured, return with RC_FAIL. + */ + { + INTEGER_t tmp; + union { + const void *constbuf; + void *nonconstbuf; + } unconst_buf; + long l; + + unconst_buf.constbuf = buf_ptr; + tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; + tmp.size = length; + + if(asn_INTEGER2long(&tmp, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + + *native = l; + } + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)", + (long)rval.consumed, (long)length, td->name, (long)*native); + + return rval; +} + +/* + * Encode the NativeInteger using the standard INTEGER type DER encoder. + */ +asn_enc_rval_t +NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + unsigned long native = *(unsigned long *)ptr; /* Disable sign ext. */ + asn_enc_rval_t erval; + INTEGER_t tmp; + +#ifdef WORDS_BIGENDIAN /* Opportunistic optimization */ + + tmp.buf = (uint8_t *)&native; + tmp.size = sizeof(native); + +#else /* Works even if WORDS_BIGENDIAN is not set where should've been */ + uint8_t buf[sizeof(native)]; + uint8_t *p; + + /* Prepare a fake INTEGER */ + for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) + *p = native; + + tmp.buf = buf; + tmp.size = sizeof(buf); +#endif /* WORDS_BIGENDIAN */ + + /* Encode fake INTEGER */ + erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key); + if(erval.encoded == -1) { + assert(erval.structure_ptr == &tmp); + erval.structure_ptr = ptr; + } + return erval; +} + + + +asn_dec_rval_t +NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + + asn_dec_rval_t rval; + long *native = (long *)*sptr; + INTEGER_t tmpint; + void *tmpintptr = &tmpint; + + (void)opt_codec_ctx; + ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name); + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) _ASN_DECODE_FAILED; + } + + memset(&tmpint, 0, sizeof tmpint); + rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, + &tmpintptr, pd); + if(rval.code == RC_OK) { + if(asn_INTEGER2long(&tmpint, native)) + rval.code = RC_FAIL; + else + ASN_DEBUG("NativeInteger %s got value %ld", + td->name, *native); + } + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + + return rval; +} + +asn_enc_rval_t +NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_enc_rval_t er; + long native; + INTEGER_t tmpint; + + if(!sptr) _ASN_ENCODE_FAILED; + + native = *(long *)sptr; + + ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); + + memset(&tmpint, 0, sizeof(tmpint)); + if(asn_long2INTEGER(&tmpint, native)) + _ASN_ENCODE_FAILED; + er = INTEGER_encode_uper(td, constraints, &tmpint, po); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + return er; +} + + +void +NativeInteger_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + + if(!td || !ptr) + return; + + ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)", + td->name, contents_only, ptr); + + if(!contents_only) { + FREEMEM(ptr); + } +} + diff --git a/src/mms/iso_mms/asn1c/NativeInteger.h b/src/mms/iso_mms/asn1c/NativeInteger.h new file mode 100644 index 0000000..4e63a83 --- /dev/null +++ b/src/mms/iso_mms/asn1c/NativeInteger.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This type differs from the standard INTEGER in that it is modelled using + * the fixed machine type (long, int, short), so it can hold only values of + * limited length. There is no type (i.e., NativeInteger_t, any integer type + * will do). + * This type may be used when integer range is limited by subtype constraints. + */ +#ifndef _NativeInteger_H_ +#define _NativeInteger_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; + +asn_struct_free_f NativeInteger_free; +asn_struct_print_f NativeInteger_print; +ber_type_decoder_f NativeInteger_decode_ber; +der_type_encoder_f NativeInteger_encode_der; +xer_type_decoder_f NativeInteger_decode_xer; +xer_type_encoder_f NativeInteger_encode_xer; +per_type_decoder_f NativeInteger_decode_uper; +per_type_encoder_f NativeInteger_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _NativeInteger_H_ */ diff --git a/src/mms/iso_mms/asn1c/OCTET_STRING.c b/src/mms/iso_mms/asn1c/OCTET_STRING.c new file mode 100644 index 0000000..0e2ae4f --- /dev/null +++ b/src/mms/iso_mms/asn1c/OCTET_STRING.c @@ -0,0 +1,1550 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* for .bits_unused member */ +#include + +/* + * OCTET STRING basic type description. + */ +static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) +}; +static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { + sizeof(OCTET_STRING_t), + offsetof(OCTET_STRING_t, _asn_ctx), + 0 +}; +static asn_per_constraint_t asn_DEF_OCTET_STRING_constraint = { + APC_SEMI_CONSTRAINED, -1, -1, 0, 0 +}; +asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { + "OCTET STRING", /* Canonical name */ + "OCTET_STRING", /* XML tag name */ + OCTET_STRING_free, + OCTET_STRING_print, /* non-ascii stuff, generally */ + asn_generic_no_constraint, + OCTET_STRING_decode_ber, + OCTET_STRING_encode_der, + OCTET_STRING_decode_xer_hex, + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_OCTET_STRING_tags, + sizeof(asn_DEF_OCTET_STRING_tags) + / sizeof(asn_DEF_OCTET_STRING_tags[0]), + asn_DEF_OCTET_STRING_tags, /* Same as above */ + sizeof(asn_DEF_OCTET_STRING_tags) + / sizeof(asn_DEF_OCTET_STRING_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_DEF_OCTET_STRING_specs +}; + +#undef _CH_PHASE +#undef NEXT_PHASE +#undef PREV_PHASE +#define _CH_PHASE(ctx, inc) do { \ + if(ctx->phase == 0) \ + ctx->context = 0; \ + ctx->phase += inc; \ + } while(0) +#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) +#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = (num_bytes); \ + buf_ptr = ((const char *)buf_ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +#undef RETURN +#define RETURN(_code) do { \ + asn_dec_rval_t tmprval; \ + tmprval.code = _code; \ + tmprval.consumed = consumed_myself; \ + return tmprval; \ + } while(0) + +#undef APPEND +#define APPEND(bufptr, bufsize) do { \ + size_t _bs = (bufsize); /* Append size */ \ + size_t _ns = ctx->context; /* Allocated now */ \ + size_t _es = st->size + _bs; /* Expected size */ \ + /* int is really a typeof(st->size): */ \ + if((int)_es < 0) RETURN(RC_FAIL); \ + if(_ns <= _es) { \ + void *ptr; \ + /* Be nice and round to the memory allocator */ \ + do { _ns = _ns ? _ns << 1 : 16; } \ + while(_ns <= _es); \ + /* int is really a typeof(st->size): */ \ + if((int)_ns < 0) RETURN(RC_FAIL); \ + ptr = REALLOC(st->buf, _ns); \ + if(ptr) { \ + st->buf = (uint8_t *)ptr; \ + ctx->context = _ns; \ + } else { \ + RETURN(RC_FAIL); \ + } \ + ASN_DEBUG("Reallocating into %ld", (long)_ns); \ + } \ + memcpy(st->buf + st->size, bufptr, _bs); \ + /* Convenient nul-termination */ \ + st->buf[_es] = '\0'; \ + st->size = _es; \ + } while(0) + +/* + * Internal variant of the OCTET STRING. + */ +typedef enum OS_type { + _TT_GENERIC = 0, /* Just a random OCTET STRING */ + _TT_BIT_STRING = 1, /* BIT STRING type, a special case */ + _TT_ANY = 2 /* ANY type, a special case too */ +} OS_type_e; + +/* + * The main reason why ASN.1 is still alive is that too much time and effort + * is necessary for learning it more or less adequately, thus creating a gut + * necessity to demonstrate that aquired skill everywhere afterwards. + * No, I am not going to explain what the following stuff is. + */ +struct _stack_el { + ber_tlv_len_t left; /* What's left to read (or -1) */ + ber_tlv_len_t got; /* What was actually processed */ + int cont_level; /* Depth of subcontainment */ + int want_nulls; /* Want null "end of content" octets? */ + int bits_chopped; /* Flag in BIT STRING mode */ + ber_tlv_tag_t tag; /* For debugging purposes */ + struct _stack_el *prev; + struct _stack_el *next; +}; +struct _stack { + struct _stack_el *tail; + struct _stack_el *cur_ptr; +}; + +static struct _stack_el * +OS__add_stack_el(struct _stack *st) { + struct _stack_el *nel; + + /* + * Reuse the old stack frame or allocate a new one. + */ + if(st->cur_ptr && st->cur_ptr->next) { + nel = st->cur_ptr->next; + nel->bits_chopped = 0; + nel->got = 0; + /* Retain the nel->cont_level, it's correct. */ + } else { + nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el)); + if(nel == NULL) + return NULL; + + if(st->tail) { + /* Increase a subcontainment depth */ + nel->cont_level = st->tail->cont_level + 1; + st->tail->next = nel; + } + nel->prev = st->tail; + st->tail = nel; + } + + st->cur_ptr = nel; + + return nel; +} + +static struct _stack * +_new_stack(void) { + return (struct _stack *)CALLOC(1, sizeof(struct _stack)); +} + +/* + * Decode OCTET STRING type. + */ +asn_dec_rval_t +OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **sptr, const void *buf_ptr, size_t size, int tag_mode) { + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + asn_dec_rval_t rval; + asn_struct_ctx_t *ctx; + ssize_t consumed_myself = 0; + struct _stack *stck; /* Expectations stack structure */ + struct _stack_el *sel = 0; /* Stack element */ + int tlv_constr; + OS_type_e type_variant = (OS_type_e)specs->subvariant; + + ASN_DEBUG("Decoding %s as %s (frame %ld)", + td->name, + (type_variant == _TT_GENERIC) ? + "OCTET STRING" : "OS-SpecialCase", + (long)size); + + /* + * Create the string if does not exist. + */ + if(st == NULL) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(st == NULL) RETURN(RC_FAIL); + } + + /* Restore parsing context */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + switch(ctx->phase) { + case 0: + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, ctx, + buf_ptr, size, tag_mode, -1, + &ctx->left, &tlv_constr); + if(rval.code != RC_OK) + return rval; + + if(tlv_constr) { + /* + * Complex operation, requires stack of expectations. + */ + ctx->ptr = _new_stack(); + if(ctx->ptr) { + stck = (struct _stack *)ctx->ptr; + } else { + RETURN(RC_FAIL); + } + } else { + /* + * Jump into stackless primitive decoding. + */ + _CH_PHASE(ctx, 3); + if(type_variant == _TT_ANY && tag_mode != 1) + APPEND(buf_ptr, rval.consumed); + ADVANCE(rval.consumed); + goto phase3; + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 1: + phase1: + /* + * Fill the stack with expectations. + */ + stck = (struct _stack *)ctx->ptr; + sel = stck->cur_ptr; + do { + ber_tlv_tag_t tlv_tag; + ber_tlv_len_t tlv_len; + ber_tlv_tag_t expected_tag; + ssize_t tl, ll, tlvl; + /* This one works even if (sel->left == -1) */ + ssize_t Left = ((!sel||(size_t)sel->left >= size) + ?(ssize_t)size:sel->left); + + + ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel, + (long)(sel?sel->left:0), + (long)(sel?sel->want_nulls:0), + (long)(sel?sel->got:0) + ); + if(sel && sel->left <= 0 && sel->want_nulls == 0) { + if(sel->prev) { + struct _stack_el *prev = sel->prev; + if(prev->left != -1) { + if(prev->left < sel->got) + RETURN(RC_FAIL); + prev->left -= sel->got; + } + prev->got += sel->got; + sel = stck->cur_ptr = prev; + if(!sel) break; + tlv_constr = 1; + continue; + } else { + sel = stck->cur_ptr = 0; + break; /* Nothing to wait */ + } + } + + tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); + ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld", + (long)size, (long)Left, sel?"":"!", + (long)(sel?sel->left:0), + (long)(sel?sel->want_nulls:0), + (long)tl); + switch(tl) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr); + + ll = ber_fetch_length(tlv_constr, + (const char *)buf_ptr + tl,Left - tl,&tlv_len); + ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld", + ber_tlv_tag_string(tlv_tag), tlv_constr, + (long)Left, (long)tl, (long)tlv_len, (long)ll); + switch(ll) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + if(sel && sel->want_nulls + && ((const uint8_t *)buf_ptr)[0] == 0 + && ((const uint8_t *)buf_ptr)[1] == 0) + { + + ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); + + if(type_variant == _TT_ANY + && (tag_mode != 1 || sel->cont_level)) + APPEND("\0\0", 2); + + ADVANCE(2); + sel->got += 2; + if(sel->left != -1) { + sel->left -= 2; /* assert(sel->left >= 2) */ + } + + sel->want_nulls--; + if(sel->want_nulls == 0) { + /* Move to the next expectation */ + sel->left = 0; + tlv_constr = 1; + } + + continue; + } + + /* + * Set up expected tags, + * depending on ASN.1 type being decoded. + */ + switch(type_variant) { + case _TT_BIT_STRING: + /* X.690: 8.6.4.1, NOTE 2 */ + /* Fall through */ + case _TT_GENERIC: + default: + if(sel) { + int level = sel->cont_level; + if(level < td->all_tags_count) { + expected_tag = td->all_tags[level]; + break; + } else if(td->all_tags_count) { + expected_tag = td->all_tags + [td->all_tags_count - 1]; + break; + } + /* else, Fall through */ + } + /* Fall through */ + case _TT_ANY: + expected_tag = tlv_tag; + break; + } + + + if(tlv_tag != expected_tag) { + char buf[2][32]; + ber_tlv_tag_snprint(tlv_tag, + buf[0], sizeof(buf[0])); + ber_tlv_tag_snprint(td->tags[td->tags_count-1], + buf[1], sizeof(buf[1])); + ASN_DEBUG("Tag does not match expectation: %s != %s", + buf[0], buf[1]); + RETURN(RC_FAIL); + } + + tlvl = tl + ll; /* Combined length of T and L encoding */ + if((tlv_len + tlvl) < 0) { + /* tlv_len value is too big */ + ASN_DEBUG("TLV encoding + length (%ld) is too big", + (long)tlv_len); + RETURN(RC_FAIL); + } + + /* + * Append a new expectation. + */ + sel = OS__add_stack_el(stck); + if(!sel) RETURN(RC_FAIL); + + sel->tag = tlv_tag; + + sel->want_nulls = (tlv_len==-1); + if(sel->prev && sel->prev->left != -1) { + /* Check that the parent frame is big enough */ + if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len)) + RETURN(RC_FAIL); + if(tlv_len == -1) + sel->left = sel->prev->left - tlvl; + else + sel->left = tlv_len; + } else { + sel->left = tlv_len; + } + if(type_variant == _TT_ANY + && (tag_mode != 1 || sel->cont_level)) + APPEND(buf_ptr, tlvl); + sel->got += tlvl; + ADVANCE(tlvl); + + ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d", + (long)sel->got, (long)sel->left, + sel->want_nulls, sel->cont_level); + + } while(tlv_constr); + if(sel == NULL) { + /* Finished operation, "phase out" */ + ASN_DEBUG("Phase out"); + _CH_PHASE(ctx, +3); + break; + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 2: + stck = (struct _stack *)ctx->ptr; + sel = stck->cur_ptr; + ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", + (long)sel->left, (long)size, (long)sel->got, + sel->want_nulls); + { + ber_tlv_len_t len; + + assert(sel->left >= 0); + + len = ((ber_tlv_len_t)size < sel->left) + ? (ber_tlv_len_t)size : sel->left; + if(len > 0) { + if(type_variant == _TT_BIT_STRING + && sel->bits_chopped == 0) { + /* Put the unused-bits-octet away */ + st->bits_unused = *(const uint8_t *)buf_ptr; + APPEND(((const char *)buf_ptr+1), (len - 1)); + sel->bits_chopped = 1; + } else { + APPEND(buf_ptr, len); + } + ADVANCE(len); + sel->left -= len; + sel->got += len; + } + + if(sel->left) { + ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n", + (long)sel->left, (long)size, sel->want_nulls); + RETURN(RC_WMORE); + } + + PREV_PHASE(ctx); + goto phase1; + } + break; + case 3: + phase3: + /* + * Primitive form, no stack required. + */ + assert(ctx->left >= 0); + + if(size < (size_t)ctx->left) { + if(!size) RETURN(RC_WMORE); + if(type_variant == _TT_BIT_STRING && !ctx->context) { + st->bits_unused = *(const uint8_t *)buf_ptr; + ctx->left--; + ADVANCE(1); + } + APPEND(buf_ptr, size); + assert(ctx->context > 0); + ctx->left -= size; + ADVANCE(size); + RETURN(RC_WMORE); + } else { + if(type_variant == _TT_BIT_STRING + && !ctx->context && ctx->left) { + st->bits_unused = *(const uint8_t *)buf_ptr; + ctx->left--; + ADVANCE(1); + } + APPEND(buf_ptr, ctx->left); + ADVANCE(ctx->left); + ctx->left = 0; + + NEXT_PHASE(ctx); + } + break; + } + + if(sel) { + ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", + sel->prev, sel->want_nulls, + (long)sel->left, (long)sel->got, (long)size); + if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { + RETURN(RC_WMORE); + } + } + + /* + * BIT STRING-specific processing. + */ + if(type_variant == _TT_BIT_STRING && st->size) { + /* Finalize BIT STRING: zero out unused bits. */ + st->buf[st->size-1] &= 0xff << st->bits_unused; + } + + ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", + (long)consumed_myself, td->name, + (type_variant == _TT_GENERIC) ? (char *)st->buf : "", + (long)st->size); + + + RETURN(RC_OK); +} + +/* + * Encode OCTET STRING type using DER. + */ +asn_enc_rval_t +OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + BIT_STRING_t *st = (BIT_STRING_t *)sptr; + OS_type_e type_variant = (OS_type_e)specs->subvariant; + int fix_last_byte = 0; + + ASN_DEBUG("%s %s as OCTET STRING", + cb?"Estimating":"Encoding", td->name); + + /* + * Write tags. + */ + if(type_variant != _TT_ANY || tag_mode == 1) { + er.encoded = der_write_tags(td, + (type_variant == _TT_BIT_STRING) + st->size, + tag_mode, type_variant == _TT_ANY, tag, cb, app_key); + if(er.encoded == -1) { + er.failed_type = td; + er.structure_ptr = sptr; + return er; + } + } else { + /* Disallow: [] IMPLICIT ANY */ + assert(type_variant != _TT_ANY || tag_mode != -1); + er.encoded = 0; + } + + if(!cb) { + er.encoded += (type_variant == _TT_BIT_STRING) + st->size; + _ASN_ENCODED_OK(er); + } + + /* + * Prepare to deal with the last octet of BIT STRING. + */ + if(type_variant == _TT_BIT_STRING) { + uint8_t b = st->bits_unused & 0x07; + if(b && st->size) fix_last_byte = 1; + _ASN_CALLBACK(&b, 1); + er.encoded++; + } + + /* Invoke callback for the main part of the buffer */ + _ASN_CALLBACK(st->buf, st->size - fix_last_byte); + + /* The last octet should be stripped off the unused bits */ + if(fix_last_byte) { + uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); + _ASN_CALLBACK(&b, 1); + } + + er.encoded += st->size; + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +asn_enc_rval_t +OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + static const char *h2c = "0123456789ABCDEF"; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er; + char scratch[16 * 3 + 4]; + char *p = scratch; + uint8_t *buf; + uint8_t *end; + size_t i; + + if(!st || !st->buf) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + /* + * Dump the contents of the buffer in hexadecimal. + */ + buf = st->buf; + end = buf + st->size; + if(flags & XER_F_CANONICAL) { + char *scend = scratch + (sizeof(scratch) - 2); + for(; buf < end; buf++) { + if(p >= scend) { + _ASN_CALLBACK(scratch, p - scratch); + er.encoded += p - scratch; + p = scratch; + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + } + + _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ + er.encoded += p - scratch; + } else { + for(i = 0; buf < end; buf++, i++) { + if(!(i % 16) && (i || st->size > 16)) { + _ASN_CALLBACK(scratch, p-scratch); + er.encoded += (p-scratch); + p = scratch; + _i_ASN_TEXT_INDENT(1, ilevel); + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + if(p - scratch) { + p--; /* Remove the tail space */ + _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ + er.encoded += p - scratch; + if(st->size > 16) + _i_ASN_TEXT_INDENT(1, ilevel-1); + } + } + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +static struct OCTET_STRING__xer_escape_table_s { + char *string; + int size; +} OCTET_STRING__xer_escape_table[] = { +#define OSXET(s) { s, sizeof(s) - 1 } + OSXET("\074\156\165\154\057\076"), /* */ + OSXET("\074\163\157\150\057\076"), /* */ + OSXET("\074\163\164\170\057\076"), /* */ + OSXET("\074\145\164\170\057\076"), /* */ + OSXET("\074\145\157\164\057\076"), /* */ + OSXET("\074\145\156\161\057\076"), /* */ + OSXET("\074\141\143\153\057\076"), /* */ + OSXET("\074\142\145\154\057\076"), /* */ + OSXET("\074\142\163\057\076"), /* */ + OSXET("\011"), /* \t */ + OSXET("\012"), /* \n */ + OSXET("\074\166\164\057\076"), /* */ + OSXET("\074\146\146\057\076"), /* */ + OSXET("\015"), /* \r */ + OSXET("\074\163\157\057\076"), /* */ + OSXET("\074\163\151\057\076"), /* */ + OSXET("\074\144\154\145\057\076"), /* */ + OSXET("\074\144\143\061\057\076"), /* */ + OSXET("\074\144\143\062\057\076"), /* */ + OSXET("\074\144\143\063\057\076"), /* */ + OSXET("\074\144\143\064\057\076"), /* */ + OSXET("\074\156\141\153\057\076"), /* */ + OSXET("\074\163\171\156\057\076"), /* */ + OSXET("\074\145\164\142\057\076"), /* */ + OSXET("\074\143\141\156\057\076"), /* */ + OSXET("\074\145\155\057\076"), /* */ + OSXET("\074\163\165\142\057\076"), /* */ + OSXET("\074\145\163\143\057\076"), /* */ + OSXET("\074\151\163\064\057\076"), /* */ + OSXET("\074\151\163\063\057\076"), /* */ + OSXET("\074\151\163\062\057\076"), /* */ + OSXET("\074\151\163\061\057\076"), /* */ + { 0, 0 }, /* " " */ + { 0, 0 }, /* ! */ + { 0, 0 }, /* \" */ + { 0, 0 }, /* # */ + { 0, 0 }, /* $ */ + { 0, 0 }, /* % */ + OSXET("\046\141\155\160\073"), /* & */ + { 0, 0 }, /* ' */ + {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */ + {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */ + {0,0},{0,0},{0,0},{0,0}, /* 89:; */ + OSXET("\046\154\164\073"), /* < */ + { 0, 0 }, /* = */ + OSXET("\046\147\164\073"), /* > */ +}; + +static int +OS__check_escaped_control_char(const void *buf, int size) { + size_t i; + /* + * Inefficient algorithm which translates the escape sequences + * defined above into characters. Returns -1 if not found. + * TODO: replace by a faster algorithm (bsearch(), hash or + * nested table lookups). + */ + for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { + struct OCTET_STRING__xer_escape_table_s *el; + el = &OCTET_STRING__xer_escape_table[i]; + if(el->size == size && memcmp(buf, el->string, size) == 0) + return i; + } + return -1; +} + +static int +OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) { + /* + * This might be one of the escape sequences + * for control characters. Check it out. + * #11.15.5 + */ + int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size); + if(control_char >= 0) { + OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr; + void *p = REALLOC(st->buf, st->size + 2); + if(p) { + st->buf = (uint8_t *)p; + st->buf[st->size++] = control_char; + st->buf[st->size] = '\0'; /* nul-termination */ + return 0; + } + } + + return -1; /* No, it's not */ +} + +asn_enc_rval_t +OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er; + uint8_t *buf, *end; + uint8_t *ss; /* Sequence start */ + ssize_t encoded_len = 0; + + (void)ilevel; /* Unused argument */ + (void)flags; /* Unused argument */ + + if(!st || !st->buf) + _ASN_ENCODE_FAILED; + + buf = st->buf; + end = buf + st->size; + for(ss = buf; buf < end; buf++) { + unsigned int ch = *buf; + int s_len; /* Special encoding sequence length */ + + /* + * Escape certain characters: X.680/11.15 + */ + if(ch < sizeof(OCTET_STRING__xer_escape_table) + /sizeof(OCTET_STRING__xer_escape_table[0]) + && (s_len = OCTET_STRING__xer_escape_table[ch].size)) { + if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) + || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, + app_key) < 0) + _ASN_ENCODE_FAILED; + encoded_len += (buf - ss) + s_len; + ss = buf + 1; + } + } + + encoded_len += (buf - ss); + if((buf - ss) && cb(ss, buf - ss, app_key) < 0) + _ASN_ENCODE_FAILED; + + er.encoded = encoded_len; + _ASN_ENCODED_OK(er); +} + +/* + * Convert from hexadecimal format (cstring): "AB CD EF" + */ +static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const char *chunk_stop = (const char *)chunk_buf; + const char *p = chunk_stop; + const char *pend = p + chunk_size; + unsigned int clv = 0; + int half = 0; /* Half bit */ + uint8_t *buf; + + /* Reallocate buffer according to high cap estimation */ + ssize_t _ns = st->size + (chunk_size + 1) / 2; + void *nptr = REALLOC(st->buf, _ns + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + /* + * If something like " a b c " appears here, the " a b":3 will be + * converted, and the rest skipped. That is, unless buf_size is greater + * than chunk_size, then it'll be equivalent to "ABC0". + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + switch(ch) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* Ignore whitespace */ + continue; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ + clv = (clv << 4) + (ch - 0x30); + break; + case 0x41: case 0x42: case 0x43: /* ABC */ + case 0x44: case 0x45: case 0x46: /* DEF */ + clv = (clv << 4) + (ch - 0x41 + 10); + break; + case 0x61: case 0x62: case 0x63: /* abc */ + case 0x64: case 0x65: case 0x66: /* def */ + clv = (clv << 4) + (ch - 0x61 + 10); + break; + default: + *buf = 0; /* JIC */ + return -1; + } + if(half++) { + half = 0; + *buf++ = clv; + chunk_stop = p + 1; + } + } + + /* + * Check partial decoding. + */ + if(half) { + if(have_more) { + /* + * Partial specification is fine, + * because no more more PXER_TEXT data is available. + */ + *buf++ = clv << 4; + chunk_stop = p; + } + } else { + chunk_stop = p; + } + + st->size = buf - st->buf; /* Adjust the buffer size */ + assert(st->size <= _ns); + st->buf[st->size] = 0; /* Courtesy termination */ + + return (chunk_stop - (const char *)chunk_buf); /* Converted size */ +} + +/* + * Convert from binary format: "00101011101" + */ +static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + BIT_STRING_t *st = (BIT_STRING_t *)sptr; + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + int bits_unused = st->bits_unused & 0x7; + uint8_t *buf; + + /* Reallocate buffer according to high cap estimation */ + ssize_t _ns = st->size + (chunk_size + 7) / 8; + void *nptr = REALLOC(st->buf, _ns + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + (void)have_more; + + if(bits_unused == 0) + bits_unused = 8; + else if(st->size) + buf--; + + /* + * Convert series of 0 and 1 into the octet string. + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + switch(ch) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* Ignore whitespace */ + break; + case 0x30: + case 0x31: + if(bits_unused-- <= 0) { + *++buf = 0; /* Clean the cell */ + bits_unused = 7; + } + *buf |= (ch&1) << bits_unused; + break; + default: + st->bits_unused = bits_unused; + return -1; + } + } + + if(bits_unused == 8) { + st->size = buf - st->buf; + st->bits_unused = 0; + } else { + st->size = buf - st->buf + 1; + st->bits_unused = bits_unused; + } + + assert(st->size <= _ns); + st->buf[st->size] = 0; /* Courtesy termination */ + + return chunk_size; /* Converted in full */ +} + +/* + * Something like strtod(), but with stricter rules. + */ +static int +OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { + int32_t val = 0; + const char *p; + + for(p = buf; p < end; p++) { + int ch = *p; + + /* Strange huge value */ + if((val * base + base) < 0) + return -1; + + switch(ch) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ + val = val * base + (ch - 0x30); + break; + case 0x41: case 0x42: case 0x43: /* ABC */ + case 0x44: case 0x45: case 0x46: /* DEF */ + val = val * base + (ch - 0x41 + 10); + break; + case 0x61: case 0x62: case 0x63: /* abc */ + case 0x64: case 0x65: case 0x66: /* def */ + val = val * base + (ch - 0x61 + 10); + break; + case 0x3b: /* ';' */ + *ret_value = val; + return (p - buf) + 1; + default: + return -1; /* Character set error */ + } + } + + *ret_value = -1; + return (p - buf); +} + +/* + * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" + */ +static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + uint8_t *buf; + + /* Reallocate buffer */ + ssize_t _ns = st->size + chunk_size; + void *nptr = REALLOC(st->buf, _ns + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + /* + * Convert series of 0 and 1 into the octet string. + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + int len; /* Length of the rest of the chunk */ + + if(ch != 0x26 /* '&' */) { + *buf++ = ch; + continue; /* That was easy... */ + } + + /* + * Process entity reference. + */ + len = chunk_size - (p - (const char *)chunk_buf); + if(len == 1 /* "&" */) goto want_more; + if(p[1] == 0x23 /* '#' */) { + const char *pval; /* Pointer to start of digits */ + int32_t val = 0; /* Entity reference value */ + int base; + + if(len == 2 /* "&#" */) goto want_more; + if(p[2] == 0x78 /* 'x' */) + pval = p + 3, base = 16; + else + pval = p + 2, base = 10; + len = OS__strtoent(base, pval, p + len, &val); + if(len == -1) { + /* Invalid charset. Just copy verbatim. */ + *buf++ = ch; + continue; + } + if(!len || pval[len-1] != 0x3b) goto want_more; + assert(val > 0); + p += (pval - p) + len - 1; /* Advance past entref */ + + if(val < 0x80) { + *buf++ = (char)val; + } else if(val < 0x800) { + *buf++ = 0xc0 | ((val >> 6)); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x10000) { + *buf++ = 0xe0 | ((val >> 12)); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x200000) { + *buf++ = 0xf0 | ((val >> 18)); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x4000000) { + *buf++ = 0xf8 | ((val >> 24)); + *buf++ = 0x80 | ((val >> 18) & 0x3f); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else { + *buf++ = 0xfc | ((val >> 30) & 0x1); + *buf++ = 0x80 | ((val >> 24) & 0x3f); + *buf++ = 0x80 | ((val >> 18) & 0x3f); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } + } else { + /* + * Ugly, limited parsing of & > < + */ + char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len); + if(!sc) goto want_more; + if((sc - p) == 4 + && p[1] == 0x61 /* 'a' */ + && p[2] == 0x6d /* 'm' */ + && p[3] == 0x70 /* 'p' */) { + *buf++ = 0x26; + p = sc; + continue; + } + if((sc - p) == 3) { + if(p[1] == 0x6c) { + *buf = 0x3c; /* '<' */ + } else if(p[1] == 0x67) { + *buf = 0x3e; /* '>' */ + } else { + /* Unsupported entity reference */ + *buf++ = ch; + continue; + } + if(p[2] != 0x74) { + /* Unsupported entity reference */ + *buf++ = ch; + continue; + } + buf++; + p = sc; + continue; + } + /* Unsupported entity reference */ + *buf++ = ch; + } + + continue; + want_more: + if(have_more) { + /* + * We know that no more data (of the same type) + * is coming. Copy the rest verbatim. + */ + *buf++ = ch; + continue; + } + chunk_size = (p - (const char *)chunk_buf); + /* Processing stalled: need more data */ + break; + } + + st->size = buf - st->buf; + assert(st->size <= _ns); + st->buf[st->size] = 0; /* Courtesy termination */ + + return chunk_size; /* Converted in full */ +} + +/* + * Decode OCTET STRING from the XML element's body. + */ +static asn_dec_rval_t +OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_ptr, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_ptr, const void *chunk_buf, size_t chunk_size, + int have_more) +) { + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + asn_struct_ctx_t *ctx; /* Per-structure parser context */ + asn_dec_rval_t rval; /* Return value from the decoder */ + int st_allocated; + + /* + * Create the string if does not exist. + */ + if(!st) { + st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); + *sptr = (void *)st; + if(!st) goto sta_failed; + st_allocated = 1; + } else { + st_allocated = 0; + } + if(!st->buf) { + /* This is separate from above section */ + st->buf = (uint8_t *)CALLOC(1, 1); + if(!st->buf) { + if(st_allocated) { + *sptr = 0; + goto stb_failed; + } else { + goto sta_failed; + } + } + } + + /* Restore parsing context */ + ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset); + + return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag, + buf_ptr, size, opt_unexpected_tag_decoder, body_receiver); + +stb_failed: + FREEMEM(st); +sta_failed: + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; +} + +/* + * Decode OCTET STRING from the hexadecimal data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); +} + +/* + * Decode OCTET STRING from the binary (0/1) data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, 0, OCTET_STRING__convert_binary); +} + +/* + * Decode OCTET STRING from the string (ASCII/UTF-8) data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, + OCTET_STRING__handle_control_chars, + OCTET_STRING__convert_entrefs); +} + +asn_dec_rval_t +OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd) { + + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_per_constraint_t *ct = constraints ? &constraints->size + : (td->per_constraints + ? &td->per_constraints->size + : &asn_DEF_OCTET_STRING_constraint); + asn_dec_rval_t rval = { RC_OK, 0 }; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + ssize_t consumed_myself = 0; + int repeat; + int unit_bits = (specs->subvariant != 1) * 7 + 1; + + (void)opt_codec_ctx; + + /* + * Allocate the string. + */ + if(!st) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) RETURN(RC_FAIL); + } + + ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d", + ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed", + ct->lower_bound, ct->upper_bound, ct->effective_bits); + + if(ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) RETURN(RC_WMORE); + if(inext) ct = &asn_DEF_OCTET_STRING_constraint; + consumed_myself = 0; + } + + if(ct->effective_bits >= 0 + && (!st->buf || st->size < ct->upper_bound)) { + FREEMEM(st->buf); + if(unit_bits == 1) { + st->size = (ct->upper_bound + 7) >> 3; + } else { + st->size = ct->upper_bound; + } + st->buf = (uint8_t *)MALLOC(st->size + 1); + if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(ct->effective_bits == 0) { + int ret = per_get_many_bits(pd, st->buf, 0, + unit_bits * ct->upper_bound); + if(ret < 0) RETURN(RC_WMORE); + consumed_myself += unit_bits * ct->upper_bound; + st->buf[st->size] = 0; + if(unit_bits == 1 && (ct->upper_bound & 0x7)) + st->bits_unused = 8 - (ct->upper_bound & 0x7); + RETURN(RC_OK); + } + + st->size = 0; + do { + ssize_t len_bytes; + ssize_t len_bits; + void *p; + int ret; + + /* Get the PER length */ + len_bits = uper_get_length(pd, ct->effective_bits, &repeat); + if(len_bits < 0) RETURN(RC_WMORE); + len_bits += ct->lower_bound; + + ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", + (long)ct->effective_bits, (long)len_bits, + repeat ? "repeat" : "once", td->name); + if(unit_bits == 1) { + len_bytes = (len_bits + 7) >> 3; + if(len_bits & 0x7) + st->bits_unused = 8 - (len_bits & 0x7); + /* len_bits be multiple of 16K if repeat is set */ + } else { + len_bytes = len_bits; + len_bits = len_bytes << 3; + } + p = REALLOC(st->buf, st->size + len_bytes + 1); + if(!p) RETURN(RC_FAIL); + st->buf = (uint8_t *)p; + + ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); + if(ret < 0) RETURN(RC_WMORE); + st->size += len_bytes; + } while(repeat); + st->buf[st->size] = 0; /* nul-terminate */ + + return rval; +} + +asn_enc_rval_t +OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_per_constraint_t *ct = constraints ? &constraints->size + : (td->per_constraints + ? &td->per_constraints->size + : &asn_DEF_OCTET_STRING_constraint); + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + int unit_bits = (specs->subvariant != 1) * 7 + 1; + asn_enc_rval_t er; + int ct_extensible = ct->flags & APC_EXTENSIBLE; + int inext = 0; /* Lies not within extension root */ + int sizeinunits = st->size; + const uint8_t *buf; + int ret; + + if(!st || !st->buf) + _ASN_ENCODE_FAILED; + + if(unit_bits == 1) { + ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", + sizeinunits, st->bits_unused); + sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07); + } + + ASN_DEBUG("Encoding %s into %d units of %d bits" + " (%d..%d, effective %d)%s", + td->name, sizeinunits, unit_bits, + ct->lower_bound, ct->upper_bound, + ct->effective_bits, ct_extensible ? " EXT" : ""); + + /* Figure out wheter size lies within PER visible consrtaint */ + + if(ct->effective_bits >= 0) { + if(sizeinunits < ct->lower_bound + || sizeinunits > ct->upper_bound) { + if(ct_extensible) { + ct = &asn_DEF_OCTET_STRING_constraint; + inext = 1; + } else + _ASN_ENCODE_FAILED; + } + } else { + inext = 0; + } + + if(ct_extensible) { + /* Declare whether length is [not] within extension root */ + if(per_put_few_bits(po, inext, 1)) + _ASN_ENCODE_FAILED; + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(ct->effective_bits >= 0) { + ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", + st->size, sizeinunits - ct->lower_bound, + ct->effective_bits); + ret = per_put_few_bits(po, sizeinunits - ct->lower_bound, + ct->effective_bits); + if(ret) _ASN_ENCODE_FAILED; + ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits); + if(ret) _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %d bytes", st->size); + + if(sizeinunits == 0) { + if(uper_put_length(po, 0)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + buf = st->buf; + while(sizeinunits) { + ssize_t maySave = uper_put_length(po, sizeinunits); + if(maySave < 0) _ASN_ENCODE_FAILED; + + ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits); + + ret = per_put_many_bits(po, buf, maySave * unit_bits); + if(ret) _ASN_ENCODE_FAILED; + + if(unit_bits == 1) + buf += maySave >> 3; + else + buf += maySave; + sizeinunits -= maySave; + assert(!(maySave & 0x07) || !sizeinunits); + } + + _ASN_ENCODED_OK(er); +} + +int +OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + static const char *h2c = "0123456789ABCDEF"; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + char scratch[16 * 3 + 4]; + char *p = scratch; + uint8_t *buf; + uint8_t *end; + size_t i; + + (void)td; /* Unused argument */ + + if(!st || !st->buf) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* + * Dump the contents of the buffer in hexadecimal. + */ + buf = st->buf; + end = buf + st->size; + for(i = 0; buf < end; buf++, i++) { + if(!(i % 16) && (i || st->size > 16)) { + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + _i_INDENT(1); + p = scratch; + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + + if(p > scratch) { + p--; /* Remove the tail space */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + } + + return 0; +} + +int +OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st && st->buf) { + return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_struct_ctx_t *ctx = (asn_struct_ctx_t *) + ((char *)st + specs->ctx_offset); + struct _stack *stck; + + if(!td || !st) + return; + + ASN_DEBUG("Freeing %s as OCTET STRING", td->name); + + if(st->buf) { + FREEMEM(st->buf); + } + + /* + * Remove decode-time stack. + */ + stck = (struct _stack *)ctx->ptr; + if(stck) { + while(stck->tail) { + struct _stack_el *sel = stck->tail; + stck->tail = sel->prev; + FREEMEM(sel); + } + FREEMEM(stck); + } + + if(!contents_only) { + FREEMEM(st); + } +} + +/* + * Conversion routines. + */ +int +OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { + void *buf; + + if(st == 0 || (str == 0 && len)) { + errno = EINVAL; + return -1; + } + + /* + * Clear the OCTET STRING. + */ + if(str == NULL) { + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + return 0; + } + + /* Determine the original string size, if not explicitly given */ + if(len < 0) + len = strlen(str); + + /* Allocate and fill the memory */ + buf = MALLOC(len + 1); + if(buf == NULL) + return -1; + + memcpy(buf, str, len); + ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ + FREEMEM(st->buf); + st->buf = (uint8_t *)buf; + st->size = len; + + return 0; +} + +OCTET_STRING_t * +OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + OCTET_STRING_t *st; + + st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); + if(st && str && OCTET_STRING_fromBuf(st, str, len)) { + FREEMEM(st); + st = NULL; + } + + return st; +} + diff --git a/src/mms/iso_mms/asn1c/OCTET_STRING.h b/src/mms/iso_mms/asn1c/OCTET_STRING.h new file mode 100644 index 0000000..5150161 --- /dev/null +++ b/src/mms/iso_mms/asn1c/OCTET_STRING.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _OCTET_STRING_H_ +#define _OCTET_STRING_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OCTET_STRING { + uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ + int size; /* Size of the buffer */ + + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ +} OCTET_STRING_t; + +extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; + +asn_struct_free_f OCTET_STRING_free; +asn_struct_print_f OCTET_STRING_print; +asn_struct_print_f OCTET_STRING_print_utf8; +ber_type_decoder_f OCTET_STRING_decode_ber; +der_type_encoder_f OCTET_STRING_encode_der; +xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ +xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ +xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ +xer_type_encoder_f OCTET_STRING_encode_xer; +xer_type_encoder_f OCTET_STRING_encode_xer_utf8; +per_type_decoder_f OCTET_STRING_decode_uper; +per_type_encoder_f OCTET_STRING_encode_uper; + +/****************************** + * Handy conversion routines. * + ******************************/ + +/* + * This function clears the previous value of the OCTET STRING (if any) + * and then allocates a new memory with the specified content (str/size). + * If size = -1, the size of the original string will be determined + * using strlen(str). + * If str equals to NULL, the function will silently clear the + * current contents of the OCTET STRING. + * Returns 0 if it was possible to perform operation, -1 otherwise. + */ +int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); + +/* Handy conversion from the C string into the OCTET STRING. */ +#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) + +/* + * Allocate and fill the new OCTET STRING and return a pointer to the newly + * allocated object. NULL is permitted in str: the function will just allocate + * empty OCTET STRING. + */ +OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, + const char *str, int size); + +/**************************** + * Internally useful stuff. * + ****************************/ + +typedef struct asn_OCTET_STRING_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the structure */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + int subvariant; /* {0,1,2} for O-S, BIT STRING or ANY */ +} asn_OCTET_STRING_specifics_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _OCTET_STRING_H_ */ diff --git a/src/mms/iso_mms/asn1c/ObjectClass.c b/src/mms/iso_mms/asn1c/ObjectClass.c new file mode 100644 index 0000000..884b1f1 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ObjectClass.c @@ -0,0 +1,57 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ObjectClass.h" + +static asn_TYPE_member_t asn_MBR_ObjectClass_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ObjectClass, choice.basicObjectClass), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "basicObjectClass" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_ObjectClass_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* basicObjectClass at 464 */ +}; +static asn_CHOICE_specifics_t asn_SPC_ObjectClass_specs_1 = { + sizeof(struct ObjectClass), + offsetof(struct ObjectClass, _asn_ctx), + offsetof(struct ObjectClass, present), + sizeof(((struct ObjectClass *)0)->present), + asn_MAP_ObjectClass_tag2el_1, + 1, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_ObjectClass = { + "ObjectClass", + "ObjectClass", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_ObjectClass_1, + 1, /* Elements count */ + &asn_SPC_ObjectClass_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ObjectClass.h b/src/mms/iso_mms/asn1c/ObjectClass.h new file mode 100644 index 0000000..3cd9bb9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ObjectClass.h @@ -0,0 +1,62 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ObjectClass_H_ +#define _ObjectClass_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ObjectClass_PR { + ObjectClass_PR_NOTHING, /* No components present */ + ObjectClass_PR_basicObjectClass +} ObjectClass_PR; +typedef enum ObjectClass__basicObjectClass { + ObjectClass__basicObjectClass_namedVariable = 0, + ObjectClass__basicObjectClass_scatteredAccess = 1, + ObjectClass__basicObjectClass_namedVariableList = 2, + ObjectClass__basicObjectClass_namedType = 3, + ObjectClass__basicObjectClass_semaphore = 4, + ObjectClass__basicObjectClass_eventCondition = 5, + ObjectClass__basicObjectClass_eventAction = 6, + ObjectClass__basicObjectClass_eventEnrollment = 7, + ObjectClass__basicObjectClass_journal = 8, + ObjectClass__basicObjectClass_domain = 9, + ObjectClass__basicObjectClass_programInvocation = 10, + ObjectClass__basicObjectClass_operatorStation = 11, + ObjectClass__basicObjectClass_dataExchange = 12, + ObjectClass__basicObjectClass_accessControlList = 13 +} e_ObjectClass__basicObjectClass; + +/* ObjectClass */ +typedef struct ObjectClass { + ObjectClass_PR present; + union ObjectClass_u { + INTEGER_t basicObjectClass; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ObjectClass_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ObjectClass; + +#ifdef __cplusplus +} +#endif + +#endif /* _ObjectClass_H_ */ diff --git a/src/mms/iso_mms/asn1c/ObjectName.c b/src/mms/iso_mms/asn1c/ObjectName.c new file mode 100644 index 0000000..9434d7b --- /dev/null +++ b/src/mms/iso_mms/asn1c/ObjectName.c @@ -0,0 +1,139 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ObjectName.h" + +static asn_TYPE_member_t asn_MBR_domainspecific_3[] = { + { ATF_NOFLAGS, 0, offsetof(struct ObjectName__domainspecific, domainId), + (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), + 0, + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "domainId" + }, + { ATF_NOFLAGS, 0, offsetof(struct ObjectName__domainspecific, itemId), + (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), + 0, + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "itemId" + }, +}; +static ber_tlv_tag_t asn_DEF_domainspecific_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_domainspecific_tag2el_3[] = { + { (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), 0, 0, 1 }, /* domainId at 172 */ + { (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), 1, -1, 0 } /* itemId at 174 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_domainspecific_specs_3 = { + sizeof(struct ObjectName__domainspecific), + offsetof(struct ObjectName__domainspecific, _asn_ctx), + asn_MAP_domainspecific_tag2el_3, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_domainspecific_3 = { + "domainspecific", + "domainspecific", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_domainspecific_tags_3, + sizeof(asn_DEF_domainspecific_tags_3) + /sizeof(asn_DEF_domainspecific_tags_3[0]) - 1, /* 1 */ + asn_DEF_domainspecific_tags_3, /* Same as above */ + sizeof(asn_DEF_domainspecific_tags_3) + /sizeof(asn_DEF_domainspecific_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_domainspecific_3, + 2, /* Elements count */ + &asn_SPC_domainspecific_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_ObjectName_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ObjectName, choice.vmdspecific), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "vmdspecific" + }, + { ATF_NOFLAGS, 0, offsetof(struct ObjectName, choice.domainspecific), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_domainspecific_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "domainspecific" + }, + { ATF_NOFLAGS, 0, offsetof(struct ObjectName, choice.aaspecific), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "aaspecific" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_ObjectName_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* vmdspecific at 169 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* domainspecific at 172 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* aaspecific at 176 */ +}; +static asn_CHOICE_specifics_t asn_SPC_ObjectName_specs_1 = { + sizeof(struct ObjectName), + offsetof(struct ObjectName, _asn_ctx), + offsetof(struct ObjectName, present), + sizeof(((struct ObjectName *)0)->present), + asn_MAP_ObjectName_tag2el_1, + 3, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_ObjectName = { + "ObjectName", + "ObjectName", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_ObjectName_1, + 3, /* Elements count */ + &asn_SPC_ObjectName_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ObjectName.h b/src/mms/iso_mms/asn1c/ObjectName.h new file mode 100644 index 0000000..002312c --- /dev/null +++ b/src/mms/iso_mms/asn1c/ObjectName.h @@ -0,0 +1,59 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ObjectName_H_ +#define _ObjectName_H_ + + +#include + +/* Including external dependencies */ +#include "Identifier.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ObjectName_PR { + ObjectName_PR_NOTHING, /* No components present */ + ObjectName_PR_vmdspecific, + ObjectName_PR_domainspecific, + ObjectName_PR_aaspecific +} ObjectName_PR; + +struct ObjectName__domainspecific { + Identifier_t domainId; + Identifier_t itemId; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* ObjectName */ +typedef struct ObjectName { + ObjectName_PR present; + union ObjectName_u { + Identifier_t vmdspecific; + struct ObjectName__domainspecific domainspecific; + Identifier_t aaspecific; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ObjectName_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ObjectName; + +#ifdef __cplusplus +} +#endif + +#endif /* _ObjectName_H_ */ diff --git a/src/mms/iso_mms/asn1c/ParameterSupportOptions.c b/src/mms/iso_mms/asn1c/ParameterSupportOptions.c new file mode 100644 index 0000000..d709421 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ParameterSupportOptions.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ParameterSupportOptions.h" + +int +ParameterSupportOptions_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_BIT_STRING.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using BIT_STRING, + * so here we adjust the DEF accordingly. + */ +static void +ParameterSupportOptions_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; +} + +void +ParameterSupportOptions_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + ParameterSupportOptions_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +ParameterSupportOptions_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + ParameterSupportOptions_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +ParameterSupportOptions_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + ParameterSupportOptions_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +ParameterSupportOptions_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + ParameterSupportOptions_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +ParameterSupportOptions_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + ParameterSupportOptions_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +ParameterSupportOptions_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + ParameterSupportOptions_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_ParameterSupportOptions_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_ParameterSupportOptions = { + "ParameterSupportOptions", + "ParameterSupportOptions", + ParameterSupportOptions_free, + ParameterSupportOptions_print, + ParameterSupportOptions_constraint, + ParameterSupportOptions_decode_ber, + ParameterSupportOptions_encode_der, + ParameterSupportOptions_decode_xer, + ParameterSupportOptions_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ParameterSupportOptions_tags_1, + sizeof(asn_DEF_ParameterSupportOptions_tags_1) + /sizeof(asn_DEF_ParameterSupportOptions_tags_1[0]), /* 1 */ + asn_DEF_ParameterSupportOptions_tags_1, /* Same as above */ + sizeof(asn_DEF_ParameterSupportOptions_tags_1) + /sizeof(asn_DEF_ParameterSupportOptions_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* Defined elsewhere */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/ParameterSupportOptions.h b/src/mms/iso_mms/asn1c/ParameterSupportOptions.h new file mode 100644 index 0000000..56b7f07 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ParameterSupportOptions.h @@ -0,0 +1,52 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ParameterSupportOptions_H_ +#define _ParameterSupportOptions_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ParameterSupportOptions { + ParameterSupportOptions_str1 = 0, + ParameterSupportOptions_str2 = 1, + ParameterSupportOptions_vnam = 2, + ParameterSupportOptions_valt = 3, + ParameterSupportOptions_vadr = 4, + ParameterSupportOptions_vsca = 5, + ParameterSupportOptions_tpy = 6, + ParameterSupportOptions_vlis = 7, + ParameterSupportOptions_real = 8, + ParameterSupportOptions_cei = 10 +} e_ParameterSupportOptions; + +/* ParameterSupportOptions */ +typedef BIT_STRING_t ParameterSupportOptions_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ParameterSupportOptions; +asn_struct_free_f ParameterSupportOptions_free; +asn_struct_print_f ParameterSupportOptions_print; +asn_constr_check_f ParameterSupportOptions_constraint; +ber_type_decoder_f ParameterSupportOptions_decode_ber; +der_type_encoder_f ParameterSupportOptions_encode_der; +xer_type_decoder_f ParameterSupportOptions_decode_xer; +xer_type_encoder_f ParameterSupportOptions_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _ParameterSupportOptions_H_ */ diff --git a/src/mms/iso_mms/asn1c/ReadRequest.c b/src/mms/iso_mms/asn1c/ReadRequest.c new file mode 100644 index 0000000..0a067ab --- /dev/null +++ b/src/mms/iso_mms/asn1c/ReadRequest.c @@ -0,0 +1,71 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ReadRequest.h" + +static asn_TYPE_member_t asn_MBR_ReadRequest_1[] = { + { ATF_POINTER, 1, offsetof(struct ReadRequest, specificationWithResult), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "specificationWithResult" + }, + { ATF_NOFLAGS, 0, offsetof(struct ReadRequest, variableAccessSpecification), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_VariableAccessSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableAccessSpecification" + }, +}; +static ber_tlv_tag_t asn_DEF_ReadRequest_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ReadRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* specificationWithResult at 575 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* variableAccessSpecification at 577 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ReadRequest_specs_1 = { + sizeof(struct ReadRequest), + offsetof(struct ReadRequest, _asn_ctx), + asn_MAP_ReadRequest_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ReadRequest = { + "ReadRequest", + "ReadRequest", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ReadRequest_tags_1, + sizeof(asn_DEF_ReadRequest_tags_1) + /sizeof(asn_DEF_ReadRequest_tags_1[0]), /* 1 */ + asn_DEF_ReadRequest_tags_1, /* Same as above */ + sizeof(asn_DEF_ReadRequest_tags_1) + /sizeof(asn_DEF_ReadRequest_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ReadRequest_1, + 2, /* Elements count */ + &asn_SPC_ReadRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ReadRequest.h b/src/mms/iso_mms/asn1c/ReadRequest.h new file mode 100644 index 0000000..683cd50 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ReadRequest.h @@ -0,0 +1,39 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ReadRequest_H_ +#define _ReadRequest_H_ + + +#include + +/* Including external dependencies */ +#include +#include "VariableAccessSpecification.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ReadRequest */ +typedef struct ReadRequest { + BOOLEAN_t *specificationWithResult /* DEFAULT FALSE */; + VariableAccessSpecification_t variableAccessSpecification; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ReadRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ReadRequest; + +#ifdef __cplusplus +} +#endif + +#endif /* _ReadRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/ReadResponse.c b/src/mms/iso_mms/asn1c/ReadResponse.c new file mode 100644 index 0000000..8d05b65 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ReadResponse.c @@ -0,0 +1,116 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ReadResponse.h" + +static asn_TYPE_member_t asn_MBR_listOfAccessResult_3[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_AccessResult, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfAccessResult_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfAccessResult_specs_3 = { + sizeof(struct ReadResponse__listOfAccessResult), + offsetof(struct ReadResponse__listOfAccessResult, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfAccessResult_3 = { + "listOfAccessResult", + "listOfAccessResult", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfAccessResult_tags_3, + sizeof(asn_DEF_listOfAccessResult_tags_3) + /sizeof(asn_DEF_listOfAccessResult_tags_3[0]) - 1, /* 1 */ + asn_DEF_listOfAccessResult_tags_3, /* Same as above */ + sizeof(asn_DEF_listOfAccessResult_tags_3) + /sizeof(asn_DEF_listOfAccessResult_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfAccessResult_3, + 1, /* Single element */ + &asn_SPC_listOfAccessResult_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_ReadResponse_1[] = { + { ATF_POINTER, 1, offsetof(struct ReadResponse, variableAccessSpecification), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_VariableAccessSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableAccessSpecification" + }, + { ATF_NOFLAGS, 0, offsetof(struct ReadResponse, listOfAccessResult), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfAccessResult_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfAccessResult" + }, +}; +static ber_tlv_tag_t asn_DEF_ReadResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ReadResponse_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* variableAccessSpecification at 582 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* listOfAccessResult at 584 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ReadResponse_specs_1 = { + sizeof(struct ReadResponse), + offsetof(struct ReadResponse, _asn_ctx), + asn_MAP_ReadResponse_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ReadResponse = { + "ReadResponse", + "ReadResponse", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ReadResponse_tags_1, + sizeof(asn_DEF_ReadResponse_tags_1) + /sizeof(asn_DEF_ReadResponse_tags_1[0]), /* 1 */ + asn_DEF_ReadResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_ReadResponse_tags_1) + /sizeof(asn_DEF_ReadResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ReadResponse_1, + 2, /* Elements count */ + &asn_SPC_ReadResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ReadResponse.h b/src/mms/iso_mms/asn1c/ReadResponse.h new file mode 100644 index 0000000..ed6d003 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ReadResponse.h @@ -0,0 +1,54 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ReadResponse_H_ +#define _ReadResponse_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct VariableAccessSpecification; +struct AccessResult; + +struct ReadResponse__listOfAccessResult { + A_SEQUENCE_OF(struct AccessResult) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* ReadResponse */ +typedef struct ReadResponse { + struct VariableAccessSpecification *variableAccessSpecification /* OPTIONAL */; + struct ReadResponse__listOfAccessResult listOfAccessResult; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ReadResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ReadResponse; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "VariableAccessSpecification.h" +#include "AccessResult.h" + +#endif /* _ReadResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/RejectPDU.c b/src/mms/iso_mms/asn1c/RejectPDU.c new file mode 100644 index 0000000..cec4bb9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/RejectPDU.c @@ -0,0 +1,403 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "RejectPDU.h" + +static int +memb_confirmedRequestPDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 9)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_confirmedResponsePDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 6)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_confirmedErrorPDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 4)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_unconfirmedPDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 4)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_concludeRequestPDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 1)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_concludeResponsePDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 1)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_concludeErrorPDU_constraint_3(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 2)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_rejectReason_3[] = { + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.confirmedRequestPDU), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_confirmedRequestPDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedRequestPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.confirmedResponsePDU), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_confirmedResponsePDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedResponsePDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.confirmedErrorPDU), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_confirmedErrorPDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "confirmedErrorPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.unconfirmedPDU), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_unconfirmedPDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unconfirmedPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.pduError), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "pduError" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.cancelRequestPDU), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "cancelRequestPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.cancelResponsePDU), + (ASN_TAG_CLASS_CONTEXT | (7 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "cancelResponsePDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.cancelErrorPDU), + (ASN_TAG_CLASS_CONTEXT | (8 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "cancelErrorPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.concludeRequestPDU), + (ASN_TAG_CLASS_CONTEXT | (9 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_concludeRequestPDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "concludeRequestPDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.concludeResponsePDU), + (ASN_TAG_CLASS_CONTEXT | (10 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_concludeResponsePDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "concludeResponsePDU" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU__rejectReason, choice.concludeErrorPDU), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_concludeErrorPDU_constraint_3, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "concludeErrorPDU" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_rejectReason_tag2el_3[] = { + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* confirmedRequestPDU at 35 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* confirmedResponsePDU at 47 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 2, 0, 0 }, /* confirmedErrorPDU at 56 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 3, 0, 0 }, /* unconfirmedPDU at 63 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 4, 0, 0 }, /* pduError at 70 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 5, 0, 0 }, /* cancelRequestPDU at 74 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 6, 0, 0 }, /* cancelResponsePDU at 75 */ + { (ASN_TAG_CLASS_CONTEXT | (8 << 2)), 7, 0, 0 }, /* cancelErrorPDU at 76 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 8, 0, 0 }, /* concludeRequestPDU at 78 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 9, 0, 0 }, /* concludeResponsePDU at 82 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 10, 0, 0 } /* concludeErrorPDU at 86 */ +}; +static asn_CHOICE_specifics_t asn_SPC_rejectReason_specs_3 = { + sizeof(struct RejectPDU__rejectReason), + offsetof(struct RejectPDU__rejectReason, _asn_ctx), + offsetof(struct RejectPDU__rejectReason, present), + sizeof(((struct RejectPDU__rejectReason *)0)->present), + asn_MAP_rejectReason_tag2el_3, + 11, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_rejectReason_3 = { + "rejectReason", + "rejectReason", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_rejectReason_3, + 11, /* Elements count */ + &asn_SPC_rejectReason_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_RejectPDU_1[] = { + { ATF_POINTER, 1, offsetof(struct RejectPDU, originalInvokeID), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "originalInvokeID" + }, + { ATF_NOFLAGS, 0, offsetof(struct RejectPDU, rejectReason), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_rejectReason_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "rejectReason" + }, +}; +static ber_tlv_tag_t asn_DEF_RejectPDU_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_RejectPDU_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* originalInvokeID at 32 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* confirmedRequestPDU at 35 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* confirmedResponsePDU at 47 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 1, 0, 0 }, /* confirmedErrorPDU at 56 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 }, /* unconfirmedPDU at 63 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 }, /* pduError at 70 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 1, 0, 0 }, /* cancelRequestPDU at 74 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 1, 0, 0 }, /* cancelResponsePDU at 75 */ + { (ASN_TAG_CLASS_CONTEXT | (8 << 2)), 1, 0, 0 }, /* cancelErrorPDU at 76 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 1, 0, 0 }, /* concludeRequestPDU at 78 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 1, 0, 0 }, /* concludeResponsePDU at 82 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 1, 0, 0 } /* concludeErrorPDU at 86 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_RejectPDU_specs_1 = { + sizeof(struct RejectPDU), + offsetof(struct RejectPDU, _asn_ctx), + asn_MAP_RejectPDU_tag2el_1, + 12, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_RejectPDU = { + "RejectPDU", + "RejectPDU", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_RejectPDU_tags_1, + sizeof(asn_DEF_RejectPDU_tags_1) + /sizeof(asn_DEF_RejectPDU_tags_1[0]), /* 1 */ + asn_DEF_RejectPDU_tags_1, /* Same as above */ + sizeof(asn_DEF_RejectPDU_tags_1) + /sizeof(asn_DEF_RejectPDU_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_RejectPDU_1, + 2, /* Elements count */ + &asn_SPC_RejectPDU_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/RejectPDU.h b/src/mms/iso_mms/asn1c/RejectPDU.h new file mode 100644 index 0000000..891c14d --- /dev/null +++ b/src/mms/iso_mms/asn1c/RejectPDU.h @@ -0,0 +1,129 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _RejectPDU_H_ +#define _RejectPDU_H_ + + +#include + +/* Including external dependencies */ +#include "Unsigned32.h" +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum RejectPDU__rejectReason_PR { + RejectPDU__rejectReason_PR_NOTHING, /* No components present */ + RejectPDU__rejectReason_PR_confirmedRequestPDU, + RejectPDU__rejectReason_PR_confirmedResponsePDU, + RejectPDU__rejectReason_PR_confirmedErrorPDU, + RejectPDU__rejectReason_PR_unconfirmedPDU, + RejectPDU__rejectReason_PR_pduError, + RejectPDU__rejectReason_PR_cancelRequestPDU, + RejectPDU__rejectReason_PR_cancelResponsePDU, + RejectPDU__rejectReason_PR_cancelErrorPDU, + RejectPDU__rejectReason_PR_concludeRequestPDU, + RejectPDU__rejectReason_PR_concludeResponsePDU, + RejectPDU__rejectReason_PR_concludeErrorPDU +} RejectPDU__rejectReason_PR; +typedef enum RejectPDU__rejectReason__confirmedRequestPDU { + RejectPDU__rejectReason__confirmedRequestPDU_other = 0, + RejectPDU__rejectReason__confirmedRequestPDU_unrecognizedService = 1, + RejectPDU__rejectReason__confirmedRequestPDU_unrecognizedModifier = 2, + RejectPDU__rejectReason__confirmedRequestPDU_invalidInvokeID = 3, + RejectPDU__rejectReason__confirmedRequestPDU_invalidArgument = 4, + RejectPDU__rejectReason__confirmedRequestPDU_invalidModifier = 5, + RejectPDU__rejectReason__confirmedRequestPDU_maxServOutstandingEexceeded = 6, + RejectPDU__rejectReason__confirmedRequestPDU_maxRecursionExceeded = 8, + RejectPDU__rejectReason__confirmedRequestPDU_valueOutOfRange = 9 +} e_RejectPDU__rejectReason__confirmedRequestPDU; +typedef enum RejectPDU__rejectReason__confirmedResponsePDU { + RejectPDU__rejectReason__confirmedResponsePDU_other = 0, + RejectPDU__rejectReason__confirmedResponsePDU_unrecognizedService = 1, + RejectPDU__rejectReason__confirmedResponsePDU_invalidInvokeID = 2, + RejectPDU__rejectReason__confirmedResponsePDU_invalidResult = 3, + RejectPDU__rejectReason__confirmedResponsePDU_maxRecursionExceeded = 5, + RejectPDU__rejectReason__confirmedResponsePDU_valueOutOfRange = 6 +} e_RejectPDU__rejectReason__confirmedResponsePDU; +typedef enum RejectPDU__rejectReason__confirmedErrorPDU { + RejectPDU__rejectReason__confirmedErrorPDU_other = 0, + RejectPDU__rejectReason__confirmedErrorPDU_unrecognizedService = 1, + RejectPDU__rejectReason__confirmedErrorPDU_invalidInvokeID = 2, + RejectPDU__rejectReason__confirmedErrorPDU_invalidServiceError = 3, + RejectPDU__rejectReason__confirmedErrorPDU_valueOutOfRange = 4 +} e_RejectPDU__rejectReason__confirmedErrorPDU; +typedef enum RejectPDU__rejectReason__unconfirmedPDU { + RejectPDU__rejectReason__unconfirmedPDU_other = 0, + RejectPDU__rejectReason__unconfirmedPDU_unrecognizedService = 1, + RejectPDU__rejectReason__unconfirmedPDU_invalidArgument = 2, + RejectPDU__rejectReason__unconfirmedPDU_maxRecursionExceeded = 3, + RejectPDU__rejectReason__unconfirmedPDU_valueOutOfRange = 4 +} e_RejectPDU__rejectReason__unconfirmedPDU; +typedef enum RejectPDU__rejectReason__pduError { + RejectPDU__rejectReason__pduError_unknownPduType = 0, + RejectPDU__rejectReason__pduError_invalidPdu = 1, + RejectPDU__rejectReason__pduError_illegalAcseMapping = 2 +} e_RejectPDU__rejectReason__pduError; +typedef enum RejectPDU__rejectReason__concludeRequestPDU { + RejectPDU__rejectReason__concludeRequestPDU_other = 0, + RejectPDU__rejectReason__concludeRequestPDU_invalidArgument = 1 +} e_RejectPDU__rejectReason__concludeRequestPDU; +typedef enum RejectPDU__rejectReason__concludeResponsePDU { + RejectPDU__rejectReason__concludeResponsePDU_other = 0, + RejectPDU__rejectReason__concludeResponsePDU_invalidResult = 1 +} e_RejectPDU__rejectReason__concludeResponsePDU; +typedef enum RejectPDU__rejectReason__concludeErrorPDU { + RejectPDU__rejectReason__concludeErrorPDU_other = 0, + RejectPDU__rejectReason__concludeErrorPDU_invalidServiceError = 1, + RejectPDU__rejectReason__concludeErrorPDU_valueOutOfRange = 2 +} e_RejectPDU__rejectReason__concludeErrorPDU; + +struct RejectPDU__rejectReason { + RejectPDU__rejectReason_PR present; + union RejectPDU__rejectReason_u { + long confirmedRequestPDU; + long confirmedResponsePDU; + long confirmedErrorPDU; + long unconfirmedPDU; + INTEGER_t pduError; + NULL_t cancelRequestPDU; + NULL_t cancelResponsePDU; + NULL_t cancelErrorPDU; + long concludeRequestPDU; + long concludeResponsePDU; + long concludeErrorPDU; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* RejectPDU */ +typedef struct RejectPDU { + Unsigned32_t *originalInvokeID /* OPTIONAL */; + struct RejectPDU__rejectReason rejectReason; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} RejectPDU_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_RejectPDU; + +#ifdef __cplusplus +} +#endif + +#endif /* _RejectPDU_H_ */ diff --git a/src/mms/iso_mms/asn1c/ScatteredAccessDescription.c b/src/mms/iso_mms/asn1c/ScatteredAccessDescription.c new file mode 100644 index 0000000..6ed893a --- /dev/null +++ b/src/mms/iso_mms/asn1c/ScatteredAccessDescription.c @@ -0,0 +1,125 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ScatteredAccessDescription.h" + +static asn_TYPE_member_t asn_MBR_Member_2[] = { + { ATF_POINTER, 1, offsetof(struct ScatteredAccessDescription__Member, componentName), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "componentName" + }, + { ATF_POINTER, 0, offsetof(struct ScatteredAccessDescription__Member, variableSpecification), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_VariableSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableSpecification" + }, + { ATF_POINTER, 1, offsetof(struct ScatteredAccessDescription__Member, alternateAccess), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_AlternateAccess, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "alternateAccess" + }, +}; +static ber_tlv_tag_t asn_DEF_Member_tags_2[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_Member_tag2el_2[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* componentName at 785 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* variableSpecification at 786 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* alternateAccess at 787 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Member_specs_2 = { + sizeof(struct ScatteredAccessDescription__Member), + offsetof(struct ScatteredAccessDescription__Member, _asn_ctx), + asn_MAP_Member_tag2el_2, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_Member_2 = { + "SEQUENCE", + "SEQUENCE", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Member_tags_2, + sizeof(asn_DEF_Member_tags_2) + /sizeof(asn_DEF_Member_tags_2[0]), /* 1 */ + asn_DEF_Member_tags_2, /* Same as above */ + sizeof(asn_DEF_Member_tags_2) + /sizeof(asn_DEF_Member_tags_2[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Member_2, + 3, /* Elements count */ + &asn_SPC_Member_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_ScatteredAccessDescription_1[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_Member_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_ScatteredAccessDescription_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_ScatteredAccessDescription_specs_1 = { + sizeof(struct ScatteredAccessDescription), + offsetof(struct ScatteredAccessDescription, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +asn_TYPE_descriptor_t asn_DEF_ScatteredAccessDescription = { + "ScatteredAccessDescription", + "ScatteredAccessDescription", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ScatteredAccessDescription_tags_1, + sizeof(asn_DEF_ScatteredAccessDescription_tags_1) + /sizeof(asn_DEF_ScatteredAccessDescription_tags_1[0]), /* 1 */ + asn_DEF_ScatteredAccessDescription_tags_1, /* Same as above */ + sizeof(asn_DEF_ScatteredAccessDescription_tags_1) + /sizeof(asn_DEF_ScatteredAccessDescription_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ScatteredAccessDescription_1, + 1, /* Single element */ + &asn_SPC_ScatteredAccessDescription_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ScatteredAccessDescription.h b/src/mms/iso_mms/asn1c/ScatteredAccessDescription.h new file mode 100644 index 0000000..8c8c134 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ScatteredAccessDescription.h @@ -0,0 +1,58 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ScatteredAccessDescription_H_ +#define _ScatteredAccessDescription_H_ + + +#include + +/* Including external dependencies */ +#include +#include "Identifier.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct VariableSpecification; +struct AlternateAccess; + +struct ScatteredAccessDescription__Member { + Identifier_t *componentName /* OPTIONAL */; + struct VariableSpecification *variableSpecification; + struct AlternateAccess *alternateAccess /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + + + +/* ScatteredAccessDescription */ +typedef struct ScatteredAccessDescription { + A_SEQUENCE_OF(struct ScatteredAccessDescription__Member) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ScatteredAccessDescription_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ScatteredAccessDescription; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "VariableSpecification.h" +#include "AlternateAccess.h" + +#endif /* _ScatteredAccessDescription_H_ */ diff --git a/src/mms/iso_mms/asn1c/ServiceError.c b/src/mms/iso_mms/asn1c/ServiceError.c new file mode 100644 index 0000000..034ad07 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ServiceError.c @@ -0,0 +1,248 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ServiceError.h" + +static asn_TYPE_member_t asn_MBR_errorClass_2[] = { + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.vmdstate), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "vmdstate" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.applicationreference), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "applicationreference" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.definition), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "definition" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.resource), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "resource" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.service), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "service" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.servicepreempt), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "servicepreempt" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.timeresolution), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "timeresolution" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.access), + (ASN_TAG_CLASS_CONTEXT | (7 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "access" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.initiate), + (ASN_TAG_CLASS_CONTEXT | (8 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "initiate" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.conclude), + (ASN_TAG_CLASS_CONTEXT | (9 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "conclude" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.cancel), + (ASN_TAG_CLASS_CONTEXT | (10 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "cancel" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.file), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "file" + }, + { ATF_NOFLAGS, 0, offsetof(struct ServiceError__errorClass, choice.others), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "others" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_errorClass_tag2el_2[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* vmdstate at 328 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* applicationreference at 336 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* definition at 344 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* resource at 354 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* service at 363 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* servicepreempt at 372 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 6, 0, 0 }, /* timeresolution at 379 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 7, 0, 0 }, /* access at 384 */ + { (ASN_TAG_CLASS_CONTEXT | (8 << 2)), 8, 0, 0 }, /* initiate at 392 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 9, 0, 0 }, /* conclude at 403 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 10, 0, 0 }, /* cancel at 408 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 11, 0, 0 }, /* file at 414 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 12, 0, 0 } /* others at 426 */ +}; +static asn_CHOICE_specifics_t asn_SPC_errorClass_specs_2 = { + sizeof(struct ServiceError__errorClass), + offsetof(struct ServiceError__errorClass, _asn_ctx), + offsetof(struct ServiceError__errorClass, present), + sizeof(((struct ServiceError__errorClass *)0)->present), + asn_MAP_errorClass_tag2el_2, + 13, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_errorClass_2 = { + "errorClass", + "errorClass", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_errorClass_2, + 13, /* Elements count */ + &asn_SPC_errorClass_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_ServiceError_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ServiceError, errorClass), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_errorClass_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "errorClass" + }, + { ATF_POINTER, 2, offsetof(struct ServiceError, additionalCode), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_INTEGER, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "additionalCode" + }, + { ATF_POINTER, 1, offsetof(struct ServiceError, additionalDescription), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_VisibleString, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "additionalDescription" + }, +}; +static ber_tlv_tag_t asn_DEF_ServiceError_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_ServiceError_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* errorClass at 333 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* additionalCode at 427 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* additionalDescription at 428 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ServiceError_specs_1 = { + sizeof(struct ServiceError), + offsetof(struct ServiceError, _asn_ctx), + asn_MAP_ServiceError_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ServiceError = { + "ServiceError", + "ServiceError", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ServiceError_tags_1, + sizeof(asn_DEF_ServiceError_tags_1) + /sizeof(asn_DEF_ServiceError_tags_1[0]), /* 1 */ + asn_DEF_ServiceError_tags_1, /* Same as above */ + sizeof(asn_DEF_ServiceError_tags_1) + /sizeof(asn_DEF_ServiceError_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ServiceError_1, + 3, /* Elements count */ + &asn_SPC_ServiceError_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/ServiceError.h b/src/mms/iso_mms/asn1c/ServiceError.h new file mode 100644 index 0000000..c87c0c9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ServiceError.h @@ -0,0 +1,168 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ServiceError_H_ +#define _ServiceError_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ServiceError__errorClass_PR { + ServiceError__errorClass_PR_NOTHING, /* No components present */ + ServiceError__errorClass_PR_vmdstate, + ServiceError__errorClass_PR_applicationreference, + ServiceError__errorClass_PR_definition, + ServiceError__errorClass_PR_resource, + ServiceError__errorClass_PR_service, + ServiceError__errorClass_PR_servicepreempt, + ServiceError__errorClass_PR_timeresolution, + ServiceError__errorClass_PR_access, + ServiceError__errorClass_PR_initiate, + ServiceError__errorClass_PR_conclude, + ServiceError__errorClass_PR_cancel, + ServiceError__errorClass_PR_file, + ServiceError__errorClass_PR_others +} ServiceError__errorClass_PR; +typedef enum ServiceError__errorClass__vmdstate { + ServiceError__errorClass__vmdstate_other = 0, + ServiceError__errorClass__vmdstate_vmdstateconflict = 1, + ServiceError__errorClass__vmdstate_vmdoperationalproblem = 2, + ServiceError__errorClass__vmdstate_domaintransferproblem = 3, + ServiceError__errorClass__vmdstate_statemachineidinvalid = 4 +} e_ServiceError__errorClass__vmdstate; +typedef enum ServiceError__errorClass__applicationreference { + ServiceError__errorClass__applicationreference_other = 0, + ServiceError__errorClass__applicationreference_aplicationunreachable = 1, + ServiceError__errorClass__applicationreference_connectionlost = 2, + ServiceError__errorClass__applicationreference_applicationreferenceinvalid = 3, + ServiceError__errorClass__applicationreference_contextunsupported = 4 +} e_ServiceError__errorClass__applicationreference; +typedef enum ServiceError__errorClass__definition { + ServiceError__errorClass__definition_other = 0, + ServiceError__errorClass__definition_objectundefined = 1, + ServiceError__errorClass__definition_invalidaddress = 2, + ServiceError__errorClass__definition_typeunsupported = 3, + ServiceError__errorClass__definition_typeinconsistent = 4, + ServiceError__errorClass__definition_objectexists = 5, + ServiceError__errorClass__definition_objectattributeinconsistent = 6 +} e_ServiceError__errorClass__definition; +typedef enum ServiceError__errorClass__resource { + ServiceError__errorClass__resource_other = 0, + ServiceError__errorClass__resource_memoryunavailable = 1, + ServiceError__errorClass__resource_processorresourceunavailable = 2, + ServiceError__errorClass__resource_massstorageunavailable = 3, + ServiceError__errorClass__resource_capabilityunavailable = 4, + ServiceError__errorClass__resource_capabilityunknown = 5 +} e_ServiceError__errorClass__resource; +typedef enum ServiceError__errorClass__service { + ServiceError__errorClass__service_other = 0, + ServiceError__errorClass__service_primitivesoutofsequence = 1, + ServiceError__errorClass__service_objectstateconflict = 2, + ServiceError__errorClass__service_pdusize = 3, + ServiceError__errorClass__service_continuationinvalid = 4, + ServiceError__errorClass__service_objectconstraintconflict = 5 +} e_ServiceError__errorClass__service; +typedef enum ServiceError__errorClass__servicepreempt { + ServiceError__errorClass__servicepreempt_other = 0, + ServiceError__errorClass__servicepreempt_timeout = 1, + ServiceError__errorClass__servicepreempt_deadlock = 2, + ServiceError__errorClass__servicepreempt_cancel = 3 +} e_ServiceError__errorClass__servicepreempt; +typedef enum ServiceError__errorClass__timeresolution { + ServiceError__errorClass__timeresolution_other = 0, + ServiceError__errorClass__timeresolution_unsupportabletimeresolution = 1 +} e_ServiceError__errorClass__timeresolution; +typedef enum ServiceError__errorClass__access { + ServiceError__errorClass__access_other = 0, + ServiceError__errorClass__access_objectaccessunsupported = 1, + ServiceError__errorClass__access_objectnonexistent = 2, + ServiceError__errorClass__access_objectaccessdenied = 3, + ServiceError__errorClass__access_objectinvalidated = 4 +} e_ServiceError__errorClass__access; +typedef enum ServiceError__errorClass__initiate { + ServiceError__errorClass__initiate_other = 0, + ServiceError__errorClass__initiate_versionincompatible = 1, + ServiceError__errorClass__initiate_maxsegmentinsufficient = 2, + ServiceError__errorClass__initiate_maxservicesoutstandingcallinginsufficient = 3, + ServiceError__errorClass__initiate_maxservicesoutstandingcalledinsufficient = 4, + ServiceError__errorClass__initiate_serviceCBBinsufficient = 5, + ServiceError__errorClass__initiate_parameterCBBinsufficient = 6, + ServiceError__errorClass__initiate_nestinglevelinsufficient = 7 +} e_ServiceError__errorClass__initiate; +typedef enum ServiceError__errorClass__conclude { + ServiceError__errorClass__conclude_other = 0, + ServiceError__errorClass__conclude_furthercommunicationrequired = 1 +} e_ServiceError__errorClass__conclude; +typedef enum ServiceError__errorClass__cancel { + ServiceError__errorClass__cancel_other = 0, + ServiceError__errorClass__cancel_invokeidunknown = 1, + ServiceError__errorClass__cancel_cancelnotpossible = 2 +} e_ServiceError__errorClass__cancel; +typedef enum ServiceError__errorClass__file { + ServiceError__errorClass__file_other = 0, + ServiceError__errorClass__file_filenameambiguous = 1, + ServiceError__errorClass__file_filebusy = 2, + ServiceError__errorClass__file_filenamesyntaxError = 3, + ServiceError__errorClass__file_contenttypeinvalid = 4, + ServiceError__errorClass__file_positioninvalid = 5, + ServiceError__errorClass__file_fileaccesdenied = 6, + ServiceError__errorClass__file_filenonexistent = 7, + ServiceError__errorClass__file_duplicatefilename = 8, + ServiceError__errorClass__file_insufficientspaceinfilestore = 9 +} e_ServiceError__errorClass__file; + +struct ServiceError__errorClass { + ServiceError__errorClass_PR present; + union ServiceError__errorClass_u { + INTEGER_t vmdstate; + INTEGER_t applicationreference; + INTEGER_t definition; + INTEGER_t resource; + INTEGER_t service; + INTEGER_t servicepreempt; + INTEGER_t timeresolution; + INTEGER_t access; + INTEGER_t initiate; + INTEGER_t conclude; + INTEGER_t cancel; + INTEGER_t file; + INTEGER_t others; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* ServiceError */ +typedef struct ServiceError { + struct ServiceError__errorClass errorClass; + INTEGER_t *additionalCode /* OPTIONAL */; + VisibleString_t *additionalDescription /* OPTIONAL */; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ServiceError_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ServiceError; + +#ifdef __cplusplus +} +#endif + +#endif /* _ServiceError_H_ */ diff --git a/src/mms/iso_mms/asn1c/ServiceSupportOptions.c b/src/mms/iso_mms/asn1c/ServiceSupportOptions.c new file mode 100644 index 0000000..bac4bed --- /dev/null +++ b/src/mms/iso_mms/asn1c/ServiceSupportOptions.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "ServiceSupportOptions.h" + +int +ServiceSupportOptions_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_BIT_STRING.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using BIT_STRING, + * so here we adjust the DEF accordingly. + */ +static void +ServiceSupportOptions_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; +} + +void +ServiceSupportOptions_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + ServiceSupportOptions_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +ServiceSupportOptions_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + ServiceSupportOptions_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +ServiceSupportOptions_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + ServiceSupportOptions_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +ServiceSupportOptions_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + ServiceSupportOptions_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +ServiceSupportOptions_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + ServiceSupportOptions_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +ServiceSupportOptions_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + ServiceSupportOptions_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_ServiceSupportOptions_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_ServiceSupportOptions = { + "ServiceSupportOptions", + "ServiceSupportOptions", + ServiceSupportOptions_free, + ServiceSupportOptions_print, + ServiceSupportOptions_constraint, + ServiceSupportOptions_decode_ber, + ServiceSupportOptions_encode_der, + ServiceSupportOptions_decode_xer, + ServiceSupportOptions_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ServiceSupportOptions_tags_1, + sizeof(asn_DEF_ServiceSupportOptions_tags_1) + /sizeof(asn_DEF_ServiceSupportOptions_tags_1[0]), /* 1 */ + asn_DEF_ServiceSupportOptions_tags_1, /* Same as above */ + sizeof(asn_DEF_ServiceSupportOptions_tags_1) + /sizeof(asn_DEF_ServiceSupportOptions_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* Defined elsewhere */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/ServiceSupportOptions.h b/src/mms/iso_mms/asn1c/ServiceSupportOptions.h new file mode 100644 index 0000000..fcffc23 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ServiceSupportOptions.h @@ -0,0 +1,127 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _ServiceSupportOptions_H_ +#define _ServiceSupportOptions_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ServiceSupportOptions { + ServiceSupportOptions_status = 0, + ServiceSupportOptions_getNameList = 1, + ServiceSupportOptions_identify = 2, + ServiceSupportOptions_rename = 3, + ServiceSupportOptions_read = 4, + ServiceSupportOptions_write = 5, + ServiceSupportOptions_getVariableAccessAttributes = 6, + ServiceSupportOptions_defineNamedVariable = 7, + ServiceSupportOptions_defineScatteredAccess = 8, + ServiceSupportOptions_getScatteredAccessAttributes = 9, + ServiceSupportOptions_deleteVariableAccess = 10, + ServiceSupportOptions_defineNamedVariableList = 11, + ServiceSupportOptions_getNamedVariableListAttributes = 12, + ServiceSupportOptions_deleteNamedVariableList = 13, + ServiceSupportOptions_defineNamedType = 14, + ServiceSupportOptions_getNamedTypeAttributes = 15, + ServiceSupportOptions_deleteNamedType = 16, + ServiceSupportOptions_input = 17, + ServiceSupportOptions_output = 18, + ServiceSupportOptions_takeControl = 19, + ServiceSupportOptions_relinquishControl = 20, + ServiceSupportOptions_defineSemaphore = 21, + ServiceSupportOptions_deleteSemaphore = 22, + ServiceSupportOptions_reportSemaphoreStatus = 23, + ServiceSupportOptions_reportPoolSemaphoreStatus = 24, + ServiceSupportOptions_reportSemaphoreEntryStatus = 25, + ServiceSupportOptions_initiateDownloadSequence = 26, + ServiceSupportOptions_downloadSegment = 27, + ServiceSupportOptions_terminateDownloadSequence = 28, + ServiceSupportOptions_initiateUploadSequence = 29, + ServiceSupportOptions_uploadSegment = 30, + ServiceSupportOptions_terminateUploadSequence = 31, + ServiceSupportOptions_requestDomainDownload = 32, + ServiceSupportOptions_requestDomainUpload = 33, + ServiceSupportOptions_loadDomainContent = 34, + ServiceSupportOptions_storeDomainContent = 35, + ServiceSupportOptions_deleteDomain = 36, + ServiceSupportOptions_getDomainAttributes = 37, + ServiceSupportOptions_createProgramInvocation = 38, + ServiceSupportOptions_deleteProgramInvocation = 39, + ServiceSupportOptions_start = 40, + ServiceSupportOptions_stop = 41, + ServiceSupportOptions_resume = 42, + ServiceSupportOptions_reset = 43, + ServiceSupportOptions_kill = 44, + ServiceSupportOptions_getProgramInvocationAttributes = 45, + ServiceSupportOptions_obtainFile = 46, + ServiceSupportOptions_defineEventCondition = 47, + ServiceSupportOptions_deleteEventCondition = 48, + ServiceSupportOptions_getEventConditionAttributes = 49, + ServiceSupportOptions_reportEventConditionStatus = 50, + ServiceSupportOptions_alterEventConditionMonitoring = 51, + ServiceSupportOptions_triggerEvent = 52, + ServiceSupportOptions_defineEventAction = 53, + ServiceSupportOptions_deleteEventAction = 54, + ServiceSupportOptions_getEventActionAttributes = 55, + ServiceSupportOptions_reportEventActionStatus = 56, + ServiceSupportOptions_defineEventEnrollment = 57, + ServiceSupportOptions_deleteEventEnrollment = 58, + ServiceSupportOptions_alterEventEnrollment = 59, + ServiceSupportOptions_reportEventEnrollmentStatus = 60, + ServiceSupportOptions_getEventEnrollmentAttributes = 61, + ServiceSupportOptions_acknowledgeEventNotification = 62, + ServiceSupportOptions_getAlarmSummary = 63, + ServiceSupportOptions_getAlarmEnrollmentSummary = 64, + ServiceSupportOptions_readJournal = 65, + ServiceSupportOptions_writeJournal = 66, + ServiceSupportOptions_initializeJournal = 67, + ServiceSupportOptions_reportJournalStatus = 68, + ServiceSupportOptions_createJournal = 69, + ServiceSupportOptions_deleteJournal = 70, + ServiceSupportOptions_getCapabilityList = 71, + ServiceSupportOptions_fileOpen = 72, + ServiceSupportOptions_fileRead = 73, + ServiceSupportOptions_fileClose = 74, + ServiceSupportOptions_fileRename = 75, + ServiceSupportOptions_fileDelete = 76, + ServiceSupportOptions_fileDirectory = 77, + ServiceSupportOptions_unsolicitedStatus = 78, + ServiceSupportOptions_informationReport = 79, + ServiceSupportOptions_eventNotification = 80, + ServiceSupportOptions_attachToEventCondition = 81, + ServiceSupportOptions_attachToSemaphore = 82, + ServiceSupportOptions_conclude = 83, + ServiceSupportOptions_cancel = 84 +} e_ServiceSupportOptions; + +/* ServiceSupportOptions */ +typedef BIT_STRING_t ServiceSupportOptions_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ServiceSupportOptions; +asn_struct_free_f ServiceSupportOptions_free; +asn_struct_print_f ServiceSupportOptions_print; +asn_constr_check_f ServiceSupportOptions_constraint; +ber_type_decoder_f ServiceSupportOptions_decode_ber; +der_type_encoder_f ServiceSupportOptions_encode_der; +xer_type_decoder_f ServiceSupportOptions_decode_xer; +xer_type_encoder_f ServiceSupportOptions_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _ServiceSupportOptions_H_ */ diff --git a/src/mms/iso_mms/asn1c/StructComponent.c b/src/mms/iso_mms/asn1c/StructComponent.c new file mode 100644 index 0000000..192425d --- /dev/null +++ b/src/mms/iso_mms/asn1c/StructComponent.c @@ -0,0 +1,71 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "StructComponent.h" + +static asn_TYPE_member_t asn_MBR_StructComponent_1[] = { + { ATF_POINTER, 1, offsetof(struct StructComponent, componentName), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Identifier, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "componentName" + }, + { ATF_POINTER, 0, offsetof(struct StructComponent, componentType), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_TypeSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "componentType" + }, +}; +static ber_tlv_tag_t asn_DEF_StructComponent_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_StructComponent_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* componentName at 533 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* componentType at 535 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_StructComponent_specs_1 = { + sizeof(struct StructComponent), + offsetof(struct StructComponent, _asn_ctx), + asn_MAP_StructComponent_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_StructComponent = { + "StructComponent", + "StructComponent", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_StructComponent_tags_1, + sizeof(asn_DEF_StructComponent_tags_1) + /sizeof(asn_DEF_StructComponent_tags_1[0]), /* 1 */ + asn_DEF_StructComponent_tags_1, /* Same as above */ + sizeof(asn_DEF_StructComponent_tags_1) + /sizeof(asn_DEF_StructComponent_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_StructComponent_1, + 2, /* Elements count */ + &asn_SPC_StructComponent_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/StructComponent.h b/src/mms/iso_mms/asn1c/StructComponent.h new file mode 100644 index 0000000..436841c --- /dev/null +++ b/src/mms/iso_mms/asn1c/StructComponent.h @@ -0,0 +1,44 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _StructComponent_H_ +#define _StructComponent_H_ + + +#include + +/* Including external dependencies */ +#include "Identifier.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct TypeSpecification; + +/* StructComponent */ +typedef struct StructComponent { + Identifier_t *componentName /* OPTIONAL */; + struct TypeSpecification *componentType; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} StructComponent_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_StructComponent; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "TypeSpecification.h" + +#endif /* _StructComponent_H_ */ diff --git a/src/mms/iso_mms/asn1c/TimeOfDay.c b/src/mms/iso_mms/asn1c/TimeOfDay.c new file mode 100644 index 0000000..498c1ab --- /dev/null +++ b/src/mms/iso_mms/asn1c/TimeOfDay.c @@ -0,0 +1,110 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "TimeOfDay.h" + +int +TimeOfDay_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_OCTET_STRING.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using OCTET_STRING, + * so here we adjust the DEF accordingly. + */ +static void +TimeOfDay_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_OCTET_STRING.free_struct; + td->print_struct = asn_DEF_OCTET_STRING.print_struct; + td->ber_decoder = asn_DEF_OCTET_STRING.ber_decoder; + td->der_encoder = asn_DEF_OCTET_STRING.der_encoder; + td->xer_decoder = asn_DEF_OCTET_STRING.xer_decoder; + td->xer_encoder = asn_DEF_OCTET_STRING.xer_encoder; + td->uper_decoder = asn_DEF_OCTET_STRING.uper_decoder; + td->uper_encoder = asn_DEF_OCTET_STRING.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_OCTET_STRING.per_constraints; + td->elements = asn_DEF_OCTET_STRING.elements; + td->elements_count = asn_DEF_OCTET_STRING.elements_count; + td->specifics = asn_DEF_OCTET_STRING.specifics; +} + +void +TimeOfDay_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + TimeOfDay_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +TimeOfDay_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + TimeOfDay_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +TimeOfDay_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + TimeOfDay_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +TimeOfDay_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + TimeOfDay_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +TimeOfDay_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + TimeOfDay_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +TimeOfDay_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + TimeOfDay_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_TimeOfDay_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_TimeOfDay = { + "TimeOfDay", + "TimeOfDay", + TimeOfDay_free, + TimeOfDay_print, + TimeOfDay_constraint, + TimeOfDay_decode_ber, + TimeOfDay_encode_der, + TimeOfDay_decode_xer, + TimeOfDay_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_TimeOfDay_tags_1, + sizeof(asn_DEF_TimeOfDay_tags_1) + /sizeof(asn_DEF_TimeOfDay_tags_1[0]), /* 1 */ + asn_DEF_TimeOfDay_tags_1, /* Same as above */ + sizeof(asn_DEF_TimeOfDay_tags_1) + /sizeof(asn_DEF_TimeOfDay_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/TimeOfDay.h b/src/mms/iso_mms/asn1c/TimeOfDay.h new file mode 100644 index 0000000..a507a26 --- /dev/null +++ b/src/mms/iso_mms/asn1c/TimeOfDay.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _TimeOfDay_H_ +#define _TimeOfDay_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* TimeOfDay */ +typedef OCTET_STRING_t TimeOfDay_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_TimeOfDay; +asn_struct_free_f TimeOfDay_free; +asn_struct_print_f TimeOfDay_print; +asn_constr_check_f TimeOfDay_constraint; +ber_type_decoder_f TimeOfDay_decode_ber; +der_type_encoder_f TimeOfDay_encode_der; +xer_type_decoder_f TimeOfDay_decode_xer; +xer_type_encoder_f TimeOfDay_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _TimeOfDay_H_ */ diff --git a/src/mms/iso_mms/asn1c/TypeSpecification.c b/src/mms/iso_mms/asn1c/TypeSpecification.c new file mode 100644 index 0000000..8d6ea27 --- /dev/null +++ b/src/mms/iso_mms/asn1c/TypeSpecification.c @@ -0,0 +1,448 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "TypeSpecification.h" + +static asn_TYPE_member_t asn_MBR_array_3[] = { + { ATF_POINTER, 1, offsetof(struct TypeSpecification__array, packed), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "packed" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification__array, numberOfElements), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "numberOfElements" + }, + { ATF_POINTER, 0, offsetof(struct TypeSpecification__array, elementType), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_TypeSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "elementType" + }, +}; +static ber_tlv_tag_t asn_DEF_array_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_array_tag2el_3[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* packed at 498 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* numberOfElements at 499 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* elementType at 501 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_array_specs_3 = { + sizeof(struct TypeSpecification__array), + offsetof(struct TypeSpecification__array, _asn_ctx), + asn_MAP_array_tag2el_3, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_array_3 = { + "array", + "array", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_array_tags_3, + sizeof(asn_DEF_array_tags_3) + /sizeof(asn_DEF_array_tags_3[0]) - 1, /* 1 */ + asn_DEF_array_tags_3, /* Same as above */ + sizeof(asn_DEF_array_tags_3) + /sizeof(asn_DEF_array_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_array_3, + 3, /* Elements count */ + &asn_SPC_array_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_components_9[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_StructComponent, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_components_tags_9[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_components_specs_9 = { + sizeof(struct TypeSpecification__structure__components), + offsetof(struct TypeSpecification__structure__components, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_components_9 = { + "components", + "components", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_components_tags_9, + sizeof(asn_DEF_components_tags_9) + /sizeof(asn_DEF_components_tags_9[0]) - 1, /* 1 */ + asn_DEF_components_tags_9, /* Same as above */ + sizeof(asn_DEF_components_tags_9) + /sizeof(asn_DEF_components_tags_9[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_components_9, + 1, /* Single element */ + &asn_SPC_components_specs_9 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_structure_7[] = { + { ATF_POINTER, 1, offsetof(struct TypeSpecification__structure, packed), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "packed" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification__structure, components), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_components_9, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "components" + }, +}; +static ber_tlv_tag_t asn_DEF_structure_tags_7[] = { + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_structure_tag2el_7[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* packed at 504 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* components at 506 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_structure_specs_7 = { + sizeof(struct TypeSpecification__structure), + offsetof(struct TypeSpecification__structure, _asn_ctx), + asn_MAP_structure_tag2el_7, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_structure_7 = { + "structure", + "structure", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_structure_tags_7, + sizeof(asn_DEF_structure_tags_7) + /sizeof(asn_DEF_structure_tags_7[0]) - 1, /* 1 */ + asn_DEF_structure_tags_7, /* Same as above */ + sizeof(asn_DEF_structure_tags_7) + /sizeof(asn_DEF_structure_tags_7[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_structure_7, + 2, /* Elements count */ + &asn_SPC_structure_specs_7 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_floatingpoint_15[] = { + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification__floatingpoint, formatwidth), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), + 0, + &asn_DEF_Unsigned8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "formatwidth" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification__floatingpoint, exponentwidth), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), + 0, + &asn_DEF_Unsigned8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "exponentwidth" + }, +}; +static ber_tlv_tag_t asn_DEF_floatingpoint_tags_15[] = { + (ASN_TAG_CLASS_CONTEXT | (7 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_floatingpoint_tag2el_15[] = { + { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 1 }, /* formatwidth at 514 */ + { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 1, -1, 0 } /* exponentwidth at 520 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_floatingpoint_specs_15 = { + sizeof(struct TypeSpecification__floatingpoint), + offsetof(struct TypeSpecification__floatingpoint, _asn_ctx), + asn_MAP_floatingpoint_tag2el_15, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_floatingpoint_15 = { + "floatingpoint", + "floatingpoint", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_floatingpoint_tags_15, + sizeof(asn_DEF_floatingpoint_tags_15) + /sizeof(asn_DEF_floatingpoint_tags_15[0]) - 1, /* 1 */ + asn_DEF_floatingpoint_tags_15, /* Same as above */ + sizeof(asn_DEF_floatingpoint_tags_15) + /sizeof(asn_DEF_floatingpoint_tags_15[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_floatingpoint_15, + 2, /* Elements count */ + &asn_SPC_floatingpoint_specs_15 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_TypeSpecification_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.typeName), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_ObjectName, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "typeName" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.array), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_array_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "array" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.structure), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_structure_7, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "structure" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.boolean), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "boolean" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.bitstring), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "bitstring" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.integer), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "integer" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.Unsigned), + (ASN_TAG_CLASS_CONTEXT | (6 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unsigned" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.floatingpoint), + (ASN_TAG_CLASS_CONTEXT | (7 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_floatingpoint_15, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "floatingpoint" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.octetstring), + (ASN_TAG_CLASS_CONTEXT | (9 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "octetstring" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.visiblestring), + (ASN_TAG_CLASS_CONTEXT | (10 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "visiblestring" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.generalizedtime), + (ASN_TAG_CLASS_CONTEXT | (11 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "generalizedtime" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.binarytime), + (ASN_TAG_CLASS_CONTEXT | (12 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "binarytime" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.bcd), + (ASN_TAG_CLASS_CONTEXT | (13 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Unsigned8, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "bcd" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.objId), + (ASN_TAG_CLASS_CONTEXT | (15 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "objId" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.mMSString), + (ASN_TAG_CLASS_CONTEXT | (16 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Integer32, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "mMSString" + }, + { ATF_NOFLAGS, 0, offsetof(struct TypeSpecification, choice.utctime), + (ASN_TAG_CLASS_CONTEXT | (17 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "utctime" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_TypeSpecification_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* typeName at 495 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* array at 498 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* structure at 504 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* boolean at 509 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* bitstring at 510 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* integer at 511 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 6, 0, 0 }, /* unsigned at 512 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 7, 0, 0 }, /* floatingpoint at 514 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 8, 0, 0 }, /* octetstring at 521 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 9, 0, 0 }, /* visiblestring at 522 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 10, 0, 0 }, /* generalizedtime at 523 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 11, 0, 0 }, /* binarytime at 524 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 12, 0, 0 }, /* bcd at 525 */ + { (ASN_TAG_CLASS_CONTEXT | (15 << 2)), 13, 0, 0 }, /* objId at 526 */ + { (ASN_TAG_CLASS_CONTEXT | (16 << 2)), 14, 0, 0 }, /* mMSString at 527 */ + { (ASN_TAG_CLASS_CONTEXT | (17 << 2)), 15, 0, 0 } /* utctime at 528 */ +}; +static asn_CHOICE_specifics_t asn_SPC_TypeSpecification_specs_1 = { + sizeof(struct TypeSpecification), + offsetof(struct TypeSpecification, _asn_ctx), + offsetof(struct TypeSpecification, present), + sizeof(((struct TypeSpecification *)0)->present), + asn_MAP_TypeSpecification_tag2el_1, + 16, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_TypeSpecification = { + "TypeSpecification", + "TypeSpecification", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_TypeSpecification_1, + 16, /* Elements count */ + &asn_SPC_TypeSpecification_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/TypeSpecification.h b/src/mms/iso_mms/asn1c/TypeSpecification.h new file mode 100644 index 0000000..cea38d7 --- /dev/null +++ b/src/mms/iso_mms/asn1c/TypeSpecification.h @@ -0,0 +1,124 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _TypeSpecification_H_ +#define _TypeSpecification_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectName.h" +#include +#include "Integer32.h" +#include "Unsigned8.h" +#include +#include "Unsigned32.h" +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum TypeSpecification_PR { + TypeSpecification_PR_NOTHING, /* No components present */ + TypeSpecification_PR_typeName, + TypeSpecification_PR_array, + TypeSpecification_PR_structure, + TypeSpecification_PR_boolean, + TypeSpecification_PR_bitstring, + TypeSpecification_PR_integer, + TypeSpecification_PR_unsigned, + TypeSpecification_PR_floatingpoint, + TypeSpecification_PR_octetstring, + TypeSpecification_PR_visiblestring, + TypeSpecification_PR_generalizedtime, + TypeSpecification_PR_binarytime, + TypeSpecification_PR_bcd, + TypeSpecification_PR_objId, + TypeSpecification_PR_mMSString, + TypeSpecification_PR_utctime +} TypeSpecification_PR; + +/* Forward declarations */ +struct TypeSpecification; +struct StructComponent; + +struct TypeSpecification__array { + BOOLEAN_t *packed /* DEFAULT FALSE */; + Unsigned32_t numberOfElements; + struct TypeSpecification *elementType; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +struct TypeSpecification__structure__components { + A_SEQUENCE_OF(struct StructComponent) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +struct TypeSpecification__structure { + BOOLEAN_t *packed /* DEFAULT FALSE */; + struct TypeSpecification__structure__components components; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +struct TypeSpecification__floatingpoint { + Unsigned8_t formatwidth; + Unsigned8_t exponentwidth; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* TypeSpecification */ +typedef struct TypeSpecification { + TypeSpecification_PR present; + union TypeSpecification_u { + ObjectName_t typeName; + struct TypeSpecification__array array; + struct TypeSpecification__structure structure; + NULL_t boolean; + Integer32_t bitstring; + Unsigned8_t integer; + Unsigned8_t Unsigned; + struct TypeSpecification__floatingpoint floatingpoint; + Integer32_t octetstring; + Integer32_t visiblestring; + NULL_t generalizedtime; + BOOLEAN_t binarytime; + Unsigned8_t bcd; + NULL_t objId; + Integer32_t mMSString; + NULL_t utctime; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} TypeSpecification_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_TypeSpecification; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "TypeSpecification.h" +#include "StructComponent.h" + +#endif /* _TypeSpecification_H_ */ diff --git a/src/mms/iso_mms/asn1c/UTF8String.c b/src/mms/iso_mms/asn1c/UTF8String.c new file mode 100644 index 0000000..c89ff7a --- /dev/null +++ b/src/mms/iso_mms/asn1c/UTF8String.c @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2003, 2004, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* + * UTF8String basic type description. + */ +static ber_tlv_tag_t asn_DEF_UTF8String_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (12 << 2)), /* [UNIVERSAL 12] IMPLICIT ...*/ + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)), /* ... OCTET STRING */ +}; +asn_TYPE_descriptor_t asn_DEF_UTF8String = { + "UTF8String", + "UTF8String", + OCTET_STRING_free, + UTF8String_print, + UTF8String_constraint, /* Check for invalid codes, etc. */ + OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_der, + OCTET_STRING_decode_xer_utf8, + OCTET_STRING_encode_xer_utf8, + 0, 0, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_UTF8String_tags, + sizeof(asn_DEF_UTF8String_tags) + / sizeof(asn_DEF_UTF8String_tags[0]) - 1, + asn_DEF_UTF8String_tags, + sizeof(asn_DEF_UTF8String_tags) + / sizeof(asn_DEF_UTF8String_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * This is the table of length expectations. + * The second half of this table is only applicable to the long sequences. + */ +static int UTF8String_ht[2][16] = { + { /* 0x0 ... 0x7 */ + /* 0000..0111 */ + 1, 1, 1, 1, 1, 1, 1, 1, + /* 1000..1011(0), 1100..1101(2), 1110(3), 1111(-1) */ + 0, 0, 0, 0, 2, 2, 3, -1 }, + { /* 0xF0 .. 0xF7 */ + /* 11110000..11110111 */ + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 6, 6, -1, -1 } +}; +static int32_t UTF8String_mv[7] = { 0, 0, + 0x00000080, + 0x00000800, + 0x00010000, + 0x00200000, + 0x04000000 +}; + +/* Internal aliases for return codes */ +#define U8E_TRUNC -1 /* UTF-8 sequence truncated */ +#define U8E_ILLSTART -2 /* Illegal UTF-8 sequence start */ +#define U8E_NOTCONT -3 /* Continuation expectation failed */ +#define U8E_NOTMIN -4 /* Not minimal length encoding */ +#define U8E_EINVAL -5 /* Invalid arguments */ + +int +UTF8String_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + ssize_t len = UTF8String_length((const UTF8String_t *)sptr); +// switch(len) { +// case U8E_EINVAL: +// _ASN_CTFAIL(app_key, td, +// "%s: value not given", td->name); +// break; +// case U8E_TRUNC: +// _ASN_CTFAIL(app_key, td, +// "%s: truncated UTF-8 sequence (%s:%d)", +// td->name, __FILE__, __LINE__); +// break; +// case U8E_ILLSTART: +// _ASN_CTFAIL(app_key, td, +// "%s: UTF-8 illegal start of encoding (%s:%d)", +// td->name, __FILE__, __LINE__); +// break; +// case U8E_NOTCONT: +// _ASN_CTFAIL(app_key, td, +// "%s: UTF-8 not continuation (%s:%d)", +// td->name, __FILE__, __LINE__); +// break; +// case U8E_NOTMIN: +// _ASN_CTFAIL(app_key, td, +// "%s: UTF-8 not minimal sequence (%s:%d)", +// td->name, __FILE__, __LINE__); +// break; +// } + return (len < 0) ? -1 : 0; +} + +static ssize_t +UTF8String__process(const UTF8String_t *st, uint32_t *dst, size_t dstlen) { + size_t length; + uint8_t *buf = st->buf; + uint8_t *end = buf + st->size; + uint32_t *dstend = dst + dstlen; + + for(length = 0; buf < end; length++) { + int ch = *buf; + uint8_t *cend; + int32_t value; + int want; + + /* Compute the sequence length */ + want = UTF8String_ht[0][ch >> 4]; + switch(want) { + case -1: + /* Second half of the table, long sequence */ + want = UTF8String_ht[1][ch & 0x0F]; + if(want != -1) break; + /* Fall through */ + case 0: + return U8E_ILLSTART; + } + + /* assert(want >= 1 && want <= 6) */ + + /* Check character sequence length */ + if(buf + want > end) return U8E_TRUNC; + + value = ch & (0xff >> want); + cend = buf + want; + for(buf++; buf < cend; buf++) { + ch = *buf; + if(ch < 0x80 || ch > 0xbf) return U8E_NOTCONT; + value = (value << 6) | (ch & 0x3F); + } + if(value < UTF8String_mv[want]) + return U8E_NOTMIN; + if(dst < dstend) + *dst++ = value; /* Record value */ + } + + if(dst < dstend) *dst = 0; /* zero-terminate */ + + return length; +} + + +ssize_t +UTF8String_length(const UTF8String_t *st) { + if(st && st->buf) { + return UTF8String__process(st, 0, 0); + } else { + return U8E_EINVAL; + } +} + +size_t +UTF8String_to_wcs(const UTF8String_t *st, uint32_t *dst, size_t dstlen) { + if(st && st->buf) { + ssize_t ret = UTF8String__process(st, dst, dstlen); + return (ret < 0) ? 0 : ret; + } else { + return 0; + } +} + +int +UTF8String_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const UTF8String_t *st = (const UTF8String_t *)sptr; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st && st->buf) { + return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} diff --git a/src/mms/iso_mms/asn1c/UTF8String.h b/src/mms/iso_mms/asn1c/UTF8String.h new file mode 100644 index 0000000..3bc8ea6 --- /dev/null +++ b/src/mms/iso_mms/asn1c/UTF8String.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _UTF8String_H_ +#define _UTF8String_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef OCTET_STRING_t UTF8String_t; /* Implemented via OCTET STRING */ + +extern asn_TYPE_descriptor_t asn_DEF_UTF8String; + +asn_struct_print_f UTF8String_print; +asn_constr_check_f UTF8String_constraint; + +/* + * Returns length of the given UTF-8 string in characters, + * or a negative error code: + * -1: UTF-8 sequence truncated + * -2: Illegal UTF-8 sequence start + * -3: Continuation expectation failed + * -4: Not minimal length encoding + * -5: Invalid arguments + */ +ssize_t UTF8String_length(const UTF8String_t *st); + +/* + * Convert the UTF-8 string into a sequence of wide characters. + * Returns the number of characters necessary. + * Returned value might be greater than dstlen. + * In case of conversion error, 0 is returned. + * + * If st points to a valid UTF-8 string, calling + * UTF8String_to_wcs(st, 0, 0); + * is equivalent to + * UTF8String_length(const UTF8String_t *st); + */ +size_t UTF8String_to_wcs(const UTF8String_t *st, uint32_t *dst, size_t dstlen); + +#ifdef __cplusplus +} +#endif + +#endif /* _UTF8String_H_ */ diff --git a/src/mms/iso_mms/asn1c/UnconfirmedPDU.c b/src/mms/iso_mms/asn1c/UnconfirmedPDU.c new file mode 100644 index 0000000..4778f35 --- /dev/null +++ b/src/mms/iso_mms/asn1c/UnconfirmedPDU.c @@ -0,0 +1,61 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "UnconfirmedPDU.h" + +static asn_TYPE_member_t asn_MBR_UnconfirmedPDU_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct UnconfirmedPDU, unconfirmedService), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_UnconfirmedService, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "unconfirmedService" + }, +}; +static ber_tlv_tag_t asn_DEF_UnconfirmedPDU_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_UnconfirmedPDU_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* informationReport at 110 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_UnconfirmedPDU_specs_1 = { + sizeof(struct UnconfirmedPDU), + offsetof(struct UnconfirmedPDU, _asn_ctx), + asn_MAP_UnconfirmedPDU_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_UnconfirmedPDU = { + "UnconfirmedPDU", + "UnconfirmedPDU", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_UnconfirmedPDU_tags_1, + sizeof(asn_DEF_UnconfirmedPDU_tags_1) + /sizeof(asn_DEF_UnconfirmedPDU_tags_1[0]), /* 1 */ + asn_DEF_UnconfirmedPDU_tags_1, /* Same as above */ + sizeof(asn_DEF_UnconfirmedPDU_tags_1) + /sizeof(asn_DEF_UnconfirmedPDU_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_UnconfirmedPDU_1, + 1, /* Elements count */ + &asn_SPC_UnconfirmedPDU_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/UnconfirmedPDU.h b/src/mms/iso_mms/asn1c/UnconfirmedPDU.h new file mode 100644 index 0000000..fc2366a --- /dev/null +++ b/src/mms/iso_mms/asn1c/UnconfirmedPDU.h @@ -0,0 +1,37 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _UnconfirmedPDU_H_ +#define _UnconfirmedPDU_H_ + + +#include + +/* Including external dependencies */ +#include "UnconfirmedService.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* UnconfirmedPDU */ +typedef struct UnconfirmedPDU { + UnconfirmedService_t unconfirmedService; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} UnconfirmedPDU_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_UnconfirmedPDU; + +#ifdef __cplusplus +} +#endif + +#endif /* _UnconfirmedPDU_H_ */ diff --git a/src/mms/iso_mms/asn1c/UnconfirmedService.c b/src/mms/iso_mms/asn1c/UnconfirmedService.c new file mode 100644 index 0000000..1ad3983 --- /dev/null +++ b/src/mms/iso_mms/asn1c/UnconfirmedService.c @@ -0,0 +1,57 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "UnconfirmedService.h" + +static asn_TYPE_member_t asn_MBR_UnconfirmedService_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct UnconfirmedService, choice.informationReport), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_InformationReport, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "informationReport" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_UnconfirmedService_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* informationReport at 110 */ +}; +static asn_CHOICE_specifics_t asn_SPC_UnconfirmedService_specs_1 = { + sizeof(struct UnconfirmedService), + offsetof(struct UnconfirmedService, _asn_ctx), + offsetof(struct UnconfirmedService, present), + sizeof(((struct UnconfirmedService *)0)->present), + asn_MAP_UnconfirmedService_tag2el_1, + 1, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_UnconfirmedService = { + "UnconfirmedService", + "UnconfirmedService", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_UnconfirmedService_1, + 1, /* Elements count */ + &asn_SPC_UnconfirmedService_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/UnconfirmedService.h b/src/mms/iso_mms/asn1c/UnconfirmedService.h new file mode 100644 index 0000000..20ed9e9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/UnconfirmedService.h @@ -0,0 +1,46 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _UnconfirmedService_H_ +#define _UnconfirmedService_H_ + + +#include + +/* Including external dependencies */ +#include "InformationReport.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum UnconfirmedService_PR { + UnconfirmedService_PR_NOTHING, /* No components present */ + UnconfirmedService_PR_informationReport +} UnconfirmedService_PR; + +/* UnconfirmedService */ +typedef struct UnconfirmedService { + UnconfirmedService_PR present; + union UnconfirmedService_u { + InformationReport_t informationReport; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} UnconfirmedService_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_UnconfirmedService; + +#ifdef __cplusplus +} +#endif + +#endif /* _UnconfirmedService_H_ */ diff --git a/src/mms/iso_mms/asn1c/Unsigned16.c b/src/mms/iso_mms/asn1c/Unsigned16.c new file mode 100644 index 0000000..6615a34 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Unsigned16.c @@ -0,0 +1,127 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Unsigned16.h" + +int +Unsigned16_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 65535)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +Unsigned16_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + td->specifics = asn_DEF_NativeInteger.specifics; +} + +void +Unsigned16_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Unsigned16_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Unsigned16_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned16_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Unsigned16_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Unsigned16_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Unsigned16_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned16_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Unsigned16_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Unsigned16_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Unsigned16_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned16_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Unsigned16_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Unsigned16 = { + "Unsigned16", + "Unsigned16", + Unsigned16_free, + Unsigned16_print, + Unsigned16_constraint, + Unsigned16_decode_ber, + Unsigned16_encode_der, + Unsigned16_decode_xer, + Unsigned16_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Unsigned16_tags_1, + sizeof(asn_DEF_Unsigned16_tags_1) + /sizeof(asn_DEF_Unsigned16_tags_1[0]), /* 1 */ + asn_DEF_Unsigned16_tags_1, /* Same as above */ + sizeof(asn_DEF_Unsigned16_tags_1) + /sizeof(asn_DEF_Unsigned16_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Unsigned16.h b/src/mms/iso_mms/asn1c/Unsigned16.h new file mode 100644 index 0000000..8edf3dc --- /dev/null +++ b/src/mms/iso_mms/asn1c/Unsigned16.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Unsigned16_H_ +#define _Unsigned16_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Unsigned16 */ +typedef long Unsigned16_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Unsigned16; +asn_struct_free_f Unsigned16_free; +asn_struct_print_f Unsigned16_print; +asn_constr_check_f Unsigned16_constraint; +ber_type_decoder_f Unsigned16_decode_ber; +der_type_encoder_f Unsigned16_encode_der; +xer_type_decoder_f Unsigned16_decode_xer; +xer_type_encoder_f Unsigned16_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Unsigned16_H_ */ diff --git a/src/mms/iso_mms/asn1c/Unsigned32.c b/src/mms/iso_mms/asn1c/Unsigned32.c new file mode 100644 index 0000000..18d4ce2 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Unsigned32.c @@ -0,0 +1,133 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Unsigned32.h" + +int +Unsigned32_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if(asn_INTEGER2long(st, &value)) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value too large (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + if((value >= 0 && value <= 4294967295)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using INTEGER, + * so here we adjust the DEF accordingly. + */ +static void +Unsigned32_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_INTEGER.free_struct; + td->print_struct = asn_DEF_INTEGER.print_struct; + td->ber_decoder = asn_DEF_INTEGER.ber_decoder; + td->der_encoder = asn_DEF_INTEGER.der_encoder; + td->xer_decoder = asn_DEF_INTEGER.xer_decoder; + td->xer_encoder = asn_DEF_INTEGER.xer_encoder; + td->uper_decoder = asn_DEF_INTEGER.uper_decoder; + td->uper_encoder = asn_DEF_INTEGER.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_INTEGER.per_constraints; + td->elements = asn_DEF_INTEGER.elements; + td->elements_count = asn_DEF_INTEGER.elements_count; + td->specifics = asn_DEF_INTEGER.specifics; +} + +void +Unsigned32_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Unsigned32_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Unsigned32_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned32_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Unsigned32_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Unsigned32_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Unsigned32_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned32_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Unsigned32_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Unsigned32_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Unsigned32_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned32_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Unsigned32_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Unsigned32 = { + "Unsigned32", + "Unsigned32", + Unsigned32_free, + Unsigned32_print, + Unsigned32_constraint, + Unsigned32_decode_ber, + Unsigned32_encode_der, + Unsigned32_decode_xer, + Unsigned32_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Unsigned32_tags_1, + sizeof(asn_DEF_Unsigned32_tags_1) + /sizeof(asn_DEF_Unsigned32_tags_1[0]), /* 1 */ + asn_DEF_Unsigned32_tags_1, /* Same as above */ + sizeof(asn_DEF_Unsigned32_tags_1) + /sizeof(asn_DEF_Unsigned32_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Unsigned32.h b/src/mms/iso_mms/asn1c/Unsigned32.h new file mode 100644 index 0000000..3fbe1b5 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Unsigned32.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Unsigned32_H_ +#define _Unsigned32_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Unsigned32 */ +typedef INTEGER_t Unsigned32_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Unsigned32; +asn_struct_free_f Unsigned32_free; +asn_struct_print_f Unsigned32_print; +asn_constr_check_f Unsigned32_constraint; +ber_type_decoder_f Unsigned32_decode_ber; +der_type_encoder_f Unsigned32_encode_der; +xer_type_decoder_f Unsigned32_decode_xer; +xer_type_encoder_f Unsigned32_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Unsigned32_H_ */ diff --git a/src/mms/iso_mms/asn1c/Unsigned8.c b/src/mms/iso_mms/asn1c/Unsigned8.c new file mode 100644 index 0000000..12db506 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Unsigned8.c @@ -0,0 +1,127 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "Unsigned8.h" + +int +Unsigned8_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 0 && value <= 255)) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +Unsigned8_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + td->specifics = asn_DEF_NativeInteger.specifics; +} + +void +Unsigned8_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + Unsigned8_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +Unsigned8_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned8_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +Unsigned8_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + Unsigned8_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +Unsigned8_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned8_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +Unsigned8_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + Unsigned8_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +Unsigned8_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + Unsigned8_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_Unsigned8_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_Unsigned8 = { + "Unsigned8", + "Unsigned8", + Unsigned8_free, + Unsigned8_print, + Unsigned8_constraint, + Unsigned8_decode_ber, + Unsigned8_encode_der, + Unsigned8_decode_xer, + Unsigned8_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Unsigned8_tags_1, + sizeof(asn_DEF_Unsigned8_tags_1) + /sizeof(asn_DEF_Unsigned8_tags_1[0]), /* 1 */ + asn_DEF_Unsigned8_tags_1, /* Same as above */ + sizeof(asn_DEF_Unsigned8_tags_1) + /sizeof(asn_DEF_Unsigned8_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/Unsigned8.h b/src/mms/iso_mms/asn1c/Unsigned8.h new file mode 100644 index 0000000..0b813b3 --- /dev/null +++ b/src/mms/iso_mms/asn1c/Unsigned8.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _Unsigned8_H_ +#define _Unsigned8_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Unsigned8 */ +typedef long Unsigned8_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Unsigned8; +asn_struct_free_f Unsigned8_free; +asn_struct_print_f Unsigned8_print; +asn_constr_check_f Unsigned8_constraint; +ber_type_decoder_f Unsigned8_decode_ber; +der_type_encoder_f Unsigned8_encode_der; +xer_type_decoder_f Unsigned8_decode_xer; +xer_type_encoder_f Unsigned8_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _Unsigned8_H_ */ diff --git a/src/mms/iso_mms/asn1c/UtcTime.c b/src/mms/iso_mms/asn1c/UtcTime.c new file mode 100644 index 0000000..c188f6a --- /dev/null +++ b/src/mms/iso_mms/asn1c/UtcTime.c @@ -0,0 +1,128 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "UtcTime.h" + +int +UtcTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if (size == 8) { + /* Constraint check succeeded */ + return 0; + } else { + _ASN_CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +/* + * This type is implemented using OCTET_STRING, + * so here we adjust the DEF accordingly. + */ +static void +UtcTime_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_OCTET_STRING.free_struct; + td->print_struct = asn_DEF_OCTET_STRING.print_struct; + td->ber_decoder = asn_DEF_OCTET_STRING.ber_decoder; + td->der_encoder = asn_DEF_OCTET_STRING.der_encoder; + td->xer_decoder = asn_DEF_OCTET_STRING.xer_decoder; + td->xer_encoder = asn_DEF_OCTET_STRING.xer_encoder; + td->uper_decoder = asn_DEF_OCTET_STRING.uper_decoder; + td->uper_encoder = asn_DEF_OCTET_STRING.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_OCTET_STRING.per_constraints; + td->elements = asn_DEF_OCTET_STRING.elements; + td->elements_count = asn_DEF_OCTET_STRING.elements_count; + td->specifics = asn_DEF_OCTET_STRING.specifics; +} + +void +UtcTime_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + UtcTime_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +UtcTime_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + UtcTime_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +UtcTime_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + UtcTime_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +UtcTime_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + UtcTime_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +UtcTime_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + UtcTime_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +UtcTime_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + UtcTime_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static ber_tlv_tag_t asn_DEF_UtcTime_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_UtcTime = { + "UtcTime", + "UtcTime", + UtcTime_free, + UtcTime_print, + UtcTime_constraint, + UtcTime_decode_ber, + UtcTime_encode_der, + UtcTime_decode_xer, + UtcTime_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_UtcTime_tags_1, + sizeof(asn_DEF_UtcTime_tags_1) + /sizeof(asn_DEF_UtcTime_tags_1[0]), /* 1 */ + asn_DEF_UtcTime_tags_1, /* Same as above */ + sizeof(asn_DEF_UtcTime_tags_1) + /sizeof(asn_DEF_UtcTime_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + diff --git a/src/mms/iso_mms/asn1c/UtcTime.h b/src/mms/iso_mms/asn1c/UtcTime.h new file mode 100644 index 0000000..17d6225 --- /dev/null +++ b/src/mms/iso_mms/asn1c/UtcTime.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _UtcTime_H_ +#define _UtcTime_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* UtcTime */ +typedef OCTET_STRING_t UtcTime_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_UtcTime; +asn_struct_free_f UtcTime_free; +asn_struct_print_f UtcTime_print; +asn_constr_check_f UtcTime_constraint; +ber_type_decoder_f UtcTime_decode_ber; +der_type_encoder_f UtcTime_encode_der; +xer_type_decoder_f UtcTime_decode_xer; +xer_type_encoder_f UtcTime_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _UtcTime_H_ */ diff --git a/src/mms/iso_mms/asn1c/VariableAccessSpecification.c b/src/mms/iso_mms/asn1c/VariableAccessSpecification.c new file mode 100644 index 0000000..f375996 --- /dev/null +++ b/src/mms/iso_mms/asn1c/VariableAccessSpecification.c @@ -0,0 +1,112 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "VariableAccessSpecification.h" + +static asn_TYPE_member_t asn_MBR_listOfVariable_2[] = { + { ATF_POINTER, 0, 0, + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), + 0, + &asn_DEF_ListOfVariableSeq, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfVariable_tags_2[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfVariable_specs_2 = { + sizeof(struct VariableAccessSpecification__listOfVariable), + offsetof(struct VariableAccessSpecification__listOfVariable, _asn_ctx), + 0, /* XER encoding is XMLDelimitedItemList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfVariable_2 = { + "listOfVariable", + "listOfVariable", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfVariable_tags_2, + sizeof(asn_DEF_listOfVariable_tags_2) + /sizeof(asn_DEF_listOfVariable_tags_2[0]) - 1, /* 1 */ + asn_DEF_listOfVariable_tags_2, /* Same as above */ + sizeof(asn_DEF_listOfVariable_tags_2) + /sizeof(asn_DEF_listOfVariable_tags_2[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfVariable_2, + 1, /* Single element */ + &asn_SPC_listOfVariable_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_VariableAccessSpecification_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct VariableAccessSpecification, choice.listOfVariable), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfVariable_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfVariable" + }, + { ATF_NOFLAGS, 0, offsetof(struct VariableAccessSpecification, choice.variableListName), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_ObjectName, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableListName" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_VariableAccessSpecification_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* listOfVariable at 760 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* variableListName at 762 */ +}; +static asn_CHOICE_specifics_t asn_SPC_VariableAccessSpecification_specs_1 = { + sizeof(struct VariableAccessSpecification), + offsetof(struct VariableAccessSpecification, _asn_ctx), + offsetof(struct VariableAccessSpecification, present), + sizeof(((struct VariableAccessSpecification *)0)->present), + asn_MAP_VariableAccessSpecification_tag2el_1, + 2, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_VariableAccessSpecification = { + "VariableAccessSpecification", + "VariableAccessSpecification", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_VariableAccessSpecification_1, + 2, /* Elements count */ + &asn_SPC_VariableAccessSpecification_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/VariableAccessSpecification.h b/src/mms/iso_mms/asn1c/VariableAccessSpecification.h new file mode 100644 index 0000000..7b16064 --- /dev/null +++ b/src/mms/iso_mms/asn1c/VariableAccessSpecification.h @@ -0,0 +1,63 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _VariableAccessSpecification_H_ +#define _VariableAccessSpecification_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectName.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum VariableAccessSpecification_PR { + VariableAccessSpecification_PR_NOTHING, /* No components present */ + VariableAccessSpecification_PR_listOfVariable, + VariableAccessSpecification_PR_variableListName +} VariableAccessSpecification_PR; + +/* Forward declarations */ +struct ListOfVariableSeq; + +struct VariableAccessSpecification__listOfVariable { + A_SEQUENCE_OF(struct ListOfVariableSeq) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* VariableAccessSpecification */ +typedef struct VariableAccessSpecification { + VariableAccessSpecification_PR present; + union VariableAccessSpecification_u { + struct VariableAccessSpecification__listOfVariable listOfVariable; + ObjectName_t variableListName; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} VariableAccessSpecification_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_VariableAccessSpecification; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "ListOfVariableSeq.h" + +#endif /* _VariableAccessSpecification_H_ */ diff --git a/src/mms/iso_mms/asn1c/VariableSpecification.c b/src/mms/iso_mms/asn1c/VariableSpecification.c new file mode 100644 index 0000000..4ddf8ee --- /dev/null +++ b/src/mms/iso_mms/asn1c/VariableSpecification.c @@ -0,0 +1,176 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "VariableSpecification.h" + +static asn_TYPE_member_t asn_MBR_variableDescription_4[] = { + { ATF_NOFLAGS, 0, offsetof(struct VariableSpecification__variableDescription, address), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Address, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "address" + }, + { ATF_NOFLAGS, 0, offsetof(struct VariableSpecification__variableDescription, typeSpecification), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_TypeSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "typeSpecification" + }, +}; +static ber_tlv_tag_t asn_DEF_variableDescription_tags_4[] = { + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_variableDescription_tag2el_4[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 1 }, /* numericAddress at 792 */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 1, -1, 0 }, /* typeName at 495 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 1 }, /* symbolicAddress at 793 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, -1, 0 }, /* array at 498 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 1 }, /* unconstrainedAddress at 794 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, -1, 0 }, /* structure at 504 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 1, 0, 0 }, /* boolean at 509 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 1, 0, 0 }, /* bitstring at 510 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 1, 0, 0 }, /* integer at 511 */ + { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 1, 0, 0 }, /* unsigned at 512 */ + { (ASN_TAG_CLASS_CONTEXT | (7 << 2)), 1, 0, 0 }, /* floatingpoint at 514 */ + { (ASN_TAG_CLASS_CONTEXT | (9 << 2)), 1, 0, 0 }, /* octetstring at 521 */ + { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 1, 0, 0 }, /* visiblestring at 522 */ + { (ASN_TAG_CLASS_CONTEXT | (11 << 2)), 1, 0, 0 }, /* generalizedtime at 523 */ + { (ASN_TAG_CLASS_CONTEXT | (12 << 2)), 1, 0, 0 }, /* binarytime at 524 */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 1, 0, 0 }, /* bcd at 525 */ + { (ASN_TAG_CLASS_CONTEXT | (15 << 2)), 1, 0, 0 }, /* objId at 526 */ + { (ASN_TAG_CLASS_CONTEXT | (16 << 2)), 1, 0, 0 }, /* mMSString at 527 */ + { (ASN_TAG_CLASS_CONTEXT | (17 << 2)), 1, 0, 0 } /* utctime at 528 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_variableDescription_specs_4 = { + sizeof(struct VariableSpecification__variableDescription), + offsetof(struct VariableSpecification__variableDescription, _asn_ctx), + asn_MAP_variableDescription_tag2el_4, + 19, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_variableDescription_4 = { + "variableDescription", + "variableDescription", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_variableDescription_tags_4, + sizeof(asn_DEF_variableDescription_tags_4) + /sizeof(asn_DEF_variableDescription_tags_4[0]) - 1, /* 1 */ + asn_DEF_variableDescription_tags_4, /* Same as above */ + sizeof(asn_DEF_variableDescription_tags_4) + /sizeof(asn_DEF_variableDescription_tags_4[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_variableDescription_4, + 2, /* Elements count */ + &asn_SPC_variableDescription_specs_4 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_VariableSpecification_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct VariableSpecification, choice.name), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_ObjectName, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "name" + }, + { ATF_NOFLAGS, 0, offsetof(struct VariableSpecification, choice.address), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_Address, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "address" + }, + { ATF_NOFLAGS, 0, offsetof(struct VariableSpecification, choice.variableDescription), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_variableDescription_4, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableDescription" + }, + { ATF_POINTER, 0, offsetof(struct VariableSpecification, choice.scatteredAccessDescription), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ScatteredAccessDescription, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "scatteredAccessDescription" + }, + { ATF_NOFLAGS, 0, offsetof(struct VariableSpecification, choice.invalidated), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "invalidated" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_VariableSpecification_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* name at 772 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* address at 773 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* variableDescription at 776 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* scatteredAccessDescription at 779 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 } /* invalidated at 780 */ +}; +static asn_CHOICE_specifics_t asn_SPC_VariableSpecification_specs_1 = { + sizeof(struct VariableSpecification), + offsetof(struct VariableSpecification, _asn_ctx), + offsetof(struct VariableSpecification, present), + sizeof(((struct VariableSpecification *)0)->present), + asn_MAP_VariableSpecification_tag2el_1, + 5, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_VariableSpecification = { + "VariableSpecification", + "VariableSpecification", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_VariableSpecification_1, + 5, /* Elements count */ + &asn_SPC_VariableSpecification_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/VariableSpecification.h b/src/mms/iso_mms/asn1c/VariableSpecification.h new file mode 100644 index 0000000..efc2a9a --- /dev/null +++ b/src/mms/iso_mms/asn1c/VariableSpecification.h @@ -0,0 +1,72 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _VariableSpecification_H_ +#define _VariableSpecification_H_ + + +#include + +/* Including external dependencies */ +#include "ObjectName.h" +#include "Address.h" +#include +#include "TypeSpecification.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum VariableSpecification_PR { + VariableSpecification_PR_NOTHING, /* No components present */ + VariableSpecification_PR_name, + VariableSpecification_PR_address, + VariableSpecification_PR_variableDescription, + VariableSpecification_PR_scatteredAccessDescription, + VariableSpecification_PR_invalidated +} VariableSpecification_PR; + +/* Forward declarations */ +struct ScatteredAccessDescription; + +struct VariableSpecification__variableDescription { + Address_t address; + TypeSpecification_t typeSpecification; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* VariableSpecification */ +typedef struct VariableSpecification { + VariableSpecification_PR present; + union VariableSpecification_u { + ObjectName_t name; + Address_t address; + struct VariableSpecification__variableDescription variableDescription; + struct ScatteredAccessDescription *scatteredAccessDescription; + NULL_t invalidated; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} VariableSpecification_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_VariableSpecification; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "ScatteredAccessDescription.h" + +#endif /* _VariableSpecification_H_ */ diff --git a/src/mms/iso_mms/asn1c/VisibleString.c b/src/mms/iso_mms/asn1c/VisibleString.c new file mode 100644 index 0000000..8796582 --- /dev/null +++ b/src/mms/iso_mms/asn1c/VisibleString.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* + * VisibleString basic type description. + */ +static ber_tlv_tag_t asn_DEF_VisibleString_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ +}; +asn_TYPE_descriptor_t asn_DEF_VisibleString = { + "VisibleString", + "VisibleString", + OCTET_STRING_free, + OCTET_STRING_print_utf8, /* ASCII subset */ + VisibleString_constraint, + OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_der, + OCTET_STRING_decode_xer_utf8, + OCTET_STRING_encode_xer_utf8, + 0, 0, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_VisibleString_tags, + sizeof(asn_DEF_VisibleString_tags) + / sizeof(asn_DEF_VisibleString_tags[0]) - 1, + asn_DEF_VisibleString_tags, + sizeof(asn_DEF_VisibleString_tags) + / sizeof(asn_DEF_VisibleString_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +int +VisibleString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const VisibleString_t *st = (const VisibleString_t *)sptr; + + if(st && st->buf) { + uint8_t *buf = st->buf; + uint8_t *end = buf + st->size; + + /* + * Check the alphabet of the VisibleString. + * ISO646, ISOReg#6 + * The alphabet is a subset of ASCII between the space + * and "~" (tilde). + */ + for(; buf < end; buf++) { + if(*buf < 0x20 || *buf > 0x7e) { + _ASN_CTFAIL(app_key, td, + "%s: value byte %ld (%d) " + "not in VisibleString alphabet (%s:%d)", + td->name, + (long)((buf - st->buf) + 1), + *buf, + __FILE__, __LINE__); + return -1; + } + } + } else { + _ASN_CTFAIL(app_key, td, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + return 0; +} diff --git a/src/mms/iso_mms/asn1c/VisibleString.h b/src/mms/iso_mms/asn1c/VisibleString.h new file mode 100644 index 0000000..20ba8cc --- /dev/null +++ b/src/mms/iso_mms/asn1c/VisibleString.h @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _VisibleString_H_ +#define _VisibleString_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef OCTET_STRING_t VisibleString_t; /* Implemented via OCTET STRING */ + +extern asn_TYPE_descriptor_t asn_DEF_VisibleString; + +asn_constr_check_f VisibleString_constraint; + +#ifdef __cplusplus +} +#endif + +#endif /* _VisibleString_H_ */ diff --git a/src/mms/iso_mms/asn1c/WriteRequest.c b/src/mms/iso_mms/asn1c/WriteRequest.c new file mode 100644 index 0000000..10910cf --- /dev/null +++ b/src/mms/iso_mms/asn1c/WriteRequest.c @@ -0,0 +1,117 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "WriteRequest.h" + +static asn_TYPE_member_t asn_MBR_listOfData_3[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Data, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_listOfData_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_listOfData_specs_3 = { + sizeof(struct WriteRequest__listOfData), + offsetof(struct WriteRequest__listOfData, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_listOfData_3 = { + "listOfData", + "listOfData", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_listOfData_tags_3, + sizeof(asn_DEF_listOfData_tags_3) + /sizeof(asn_DEF_listOfData_tags_3[0]) - 1, /* 1 */ + asn_DEF_listOfData_tags_3, /* Same as above */ + sizeof(asn_DEF_listOfData_tags_3) + /sizeof(asn_DEF_listOfData_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_listOfData_3, + 1, /* Single element */ + &asn_SPC_listOfData_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_WriteRequest_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct WriteRequest, variableAccessSpecification), + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_VariableAccessSpecification, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "variableAccessSpecification" + }, + { ATF_NOFLAGS, 0, offsetof(struct WriteRequest, listOfData), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_listOfData_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "listOfData" + }, +}; +static ber_tlv_tag_t asn_DEF_WriteRequest_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_TYPE_tag2member_t asn_MAP_WriteRequest_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 1 }, /* listOfVariable at 760 */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 1, -1, 0 }, /* listOfData at 594 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 } /* variableListName at 762 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_WriteRequest_specs_1 = { + sizeof(struct WriteRequest), + offsetof(struct WriteRequest, _asn_ctx), + asn_MAP_WriteRequest_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_WriteRequest = { + "WriteRequest", + "WriteRequest", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_WriteRequest_tags_1, + sizeof(asn_DEF_WriteRequest_tags_1) + /sizeof(asn_DEF_WriteRequest_tags_1[0]), /* 1 */ + asn_DEF_WriteRequest_tags_1, /* Same as above */ + sizeof(asn_DEF_WriteRequest_tags_1) + /sizeof(asn_DEF_WriteRequest_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_WriteRequest_1, + 2, /* Elements count */ + &asn_SPC_WriteRequest_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/WriteRequest.h b/src/mms/iso_mms/asn1c/WriteRequest.h new file mode 100644 index 0000000..6b1a5ab --- /dev/null +++ b/src/mms/iso_mms/asn1c/WriteRequest.h @@ -0,0 +1,53 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _WriteRequest_H_ +#define _WriteRequest_H_ + + +#include + +/* Including external dependencies */ +#include "VariableAccessSpecification.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct Data; + +struct WriteRequest__listOfData { + A_SEQUENCE_OF(struct Data) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* WriteRequest */ +typedef struct WriteRequest { + VariableAccessSpecification_t variableAccessSpecification; + struct WriteRequest__listOfData listOfData; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} WriteRequest_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_WriteRequest; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "Data.h" + +#endif /* _WriteRequest_H_ */ diff --git a/src/mms/iso_mms/asn1c/WriteResponse.c b/src/mms/iso_mms/asn1c/WriteResponse.c new file mode 100644 index 0000000..e72a201 --- /dev/null +++ b/src/mms/iso_mms/asn1c/WriteResponse.c @@ -0,0 +1,111 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#include + +#include "WriteResponse.h" + +static asn_TYPE_member_t asn_MBR_Member_2[] = { + { ATF_NOFLAGS, 0, offsetof(struct WriteResponse__Member, choice.failure), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_DataAccessError, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "failure" + }, + { ATF_NOFLAGS, 0, offsetof(struct WriteResponse__Member, choice.success), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NULL, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "success" + }, +}; +static asn_TYPE_tag2member_t asn_MAP_Member_tag2el_2[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* failure at 598 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* success at 599 */ +}; +static asn_CHOICE_specifics_t asn_SPC_Member_specs_2 = { + sizeof(struct WriteResponse__Member), + offsetof(struct WriteResponse__Member, _asn_ctx), + offsetof(struct WriteResponse__Member, present), + sizeof(((struct WriteResponse__Member *)0)->present), + asn_MAP_Member_tag2el_2, + 2, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_Member_2 = { + "CHOICE", + "CHOICE", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_Member_2, + 2, /* Elements count */ + &asn_SPC_Member_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_WriteResponse_1[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Member_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static ber_tlv_tag_t asn_DEF_WriteResponse_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_WriteResponse_specs_1 = { + sizeof(struct WriteResponse), + offsetof(struct WriteResponse, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +asn_TYPE_descriptor_t asn_DEF_WriteResponse = { + "WriteResponse", + "WriteResponse", + SEQUENCE_OF_free, + SEQUENCE_OF_print, + SEQUENCE_OF_constraint, + SEQUENCE_OF_decode_ber, + SEQUENCE_OF_encode_der, + SEQUENCE_OF_decode_xer, + SEQUENCE_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_WriteResponse_tags_1, + sizeof(asn_DEF_WriteResponse_tags_1) + /sizeof(asn_DEF_WriteResponse_tags_1[0]), /* 1 */ + asn_DEF_WriteResponse_tags_1, /* Same as above */ + sizeof(asn_DEF_WriteResponse_tags_1) + /sizeof(asn_DEF_WriteResponse_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_WriteResponse_1, + 1, /* Single element */ + &asn_SPC_WriteResponse_specs_1 /* Additional specs */ +}; + diff --git a/src/mms/iso_mms/asn1c/WriteResponse.h b/src/mms/iso_mms/asn1c/WriteResponse.h new file mode 100644 index 0000000..5561ed6 --- /dev/null +++ b/src/mms/iso_mms/asn1c/WriteResponse.h @@ -0,0 +1,58 @@ +/* + * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) + * From ASN.1 module "MMS" + * found in "../mms-extended.asn" + * `asn1c -fskeletons-copy` + */ + +#ifndef _WriteResponse_H_ +#define _WriteResponse_H_ + + +#include + +/* Including external dependencies */ +#include +#include "DataAccessError.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum WriteResponse__Member_PR { + WriteResponse__Member_PR_NOTHING, /* No components present */ + WriteResponse__Member_PR_failure, + WriteResponse__Member_PR_success +} WriteResponse__Member_PR; + +struct WriteResponse__Member { + WriteResponse__Member_PR present; + union WriteResponse__Member_u { + DataAccessError_t failure; + NULL_t success; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + }; + +/* WriteResponse */ +typedef struct WriteResponse { + A_SEQUENCE_OF(struct WriteResponse__Member) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} WriteResponse_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_WriteResponse; + +#ifdef __cplusplus +} +#endif + +#endif /* _WriteResponse_H_ */ diff --git a/src/mms/iso_mms/asn1c/asn_SEQUENCE_OF.c b/src/mms/iso_mms/asn1c/asn_SEQUENCE_OF.c new file mode 100644 index 0000000..ec952fc --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_SEQUENCE_OF.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +typedef A_SEQUENCE_OF(void) asn_sequence; + +void +asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free) { + asn_sequence *as = (asn_sequence *)asn_sequence_of_x; + + if(as) { + void *ptr; + int n; + + if(number < 0 || number >= as->count) + return; /* Nothing to delete */ + + if(_do_free && as->free) { + ptr = as->array[number]; + } else { + ptr = 0; + } + + /* + * Shift all elements to the left to hide the gap. + */ + --as->count; + for(n = number; n < as->count; n++) + as->array[n] = as->array[n+1]; + + /* + * Invoke the third-party function only when the state + * of the parent structure is consistent. + */ + if(ptr) as->free(ptr); + } +} + diff --git a/src/mms/iso_mms/asn1c/asn_SEQUENCE_OF.h b/src/mms/iso_mms/asn1c/asn_SEQUENCE_OF.h new file mode 100644 index 0000000..e678f03 --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_SEQUENCE_OF.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_SEQUENCE_OF_H +#define ASN_SEQUENCE_OF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SEQUENCE OF is the same as SET OF with a tiny difference: + * the delete operation preserves the initial order of elements + * and thus MAY operate in non-constant time. + */ +#define A_SEQUENCE_OF(type) A_SET_OF(type) + +#define ASN_SEQUENCE_ADD(headptr, ptr) \ + asn_sequence_add((headptr), (ptr)) + +/*********************************************** + * Implementation of the SEQUENCE OF structure. + */ + +#define asn_sequence_add asn_set_add +#define asn_sequence_empty asn_set_empty + +/* + * Delete the element from the set by its number (base 0). + * This is NOT a constant-time operation. + * The order of elements is preserved. + * If _do_free is given AND the (*free) is initialized, the element + * will be freed using the custom (*free) function as well. + */ +void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); + +/* + * Cope with different conversions requirements to/from void in C and C++. + * This is mostly useful for support library. + */ +typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; +#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) +#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_SEQUENCE_OF_H */ diff --git a/src/mms/iso_mms/asn1c/asn_SET_OF.c b/src/mms/iso_mms/asn1c/asn_SET_OF.c new file mode 100644 index 0000000..944f2cb --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_SET_OF.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Add another element into the set. + */ +int +asn_set_add(void *asn_set_of_x, void *ptr) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as == 0 || ptr == 0) { + errno = EINVAL; /* Invalid arguments */ + return -1; + } + + /* + * Make sure there's enough space to insert an element. + */ + if(as->count == as->size) { + int _newsize = as->size ? (as->size << 1) : 4; + void *_new_arr; + _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0])); + if(_new_arr) { + as->array = (void **)_new_arr; + as->size = _newsize; + } else { + /* ENOMEM */ + return -1; + } + } + + as->array[as->count++] = ptr; + + return 0; +} + +void +asn_set_del(void *asn_set_of_x, int number, int _do_free) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as) { + void *ptr; + if(number < 0 || number >= as->count) + return; + + if(_do_free && as->free) { + ptr = as->array[number]; + } else { + ptr = 0; + } + + as->array[number] = as->array[--as->count]; + + /* + * Invoke the third-party function only when the state + * of the parent structure is consistent. + */ + if(ptr) as->free(ptr); + } +} + +/* + * Free the contents of the set, do not free the set itself. + */ +void +asn_set_empty(void *asn_set_of_x) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as) { + if(as->array) { + if(as->free) { + while(as->count--) + as->free(as->array[as->count]); + } + FREEMEM(as->array); + as->array = 0; + } + as->count = 0; + as->size = 0; + } + +} + diff --git a/src/mms/iso_mms/asn1c/asn_SET_OF.h b/src/mms/iso_mms/asn1c/asn_SET_OF.h new file mode 100644 index 0000000..7edf14b --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_SET_OF.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_SET_OF_H +#define ASN_SET_OF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define A_SET_OF(type) \ + struct { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(type *); \ + } + +#define ASN_SET_ADD(headptr, ptr) \ + asn_set_add((headptr), (ptr)) + +/******************************************* + * Implementation of the SET OF structure. + */ + +/* + * Add another structure into the set by its pointer. + * RETURN VALUES: + * 0 for success and -1/errno for failure. + */ +int asn_set_add(void *asn_set_of_x, void *ptr); + +/* + * Delete the element from the set by its number (base 0). + * This is a constant-time operation. The order of elements before the + * deleted ones is guaranteed, the order of elements after the deleted + * one is NOT guaranteed. + * If _do_free is given AND the (*free) is initialized, the element + * will be freed using the custom (*free) function as well. + */ +void asn_set_del(void *asn_set_of_x, int number, int _do_free); + +/* + * Empty the contents of the set. Will free the elements, if (*free) is given. + * Will NOT free the set itself. + */ +void asn_set_empty(void *asn_set_of_x); + +/* + * Cope with different conversions requirements to/from void in C and C++. + * This is mostly useful for support library. + */ +typedef A_SET_OF(void) asn_anonymous_set_; +#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) +#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_SET_OF_H */ diff --git a/src/mms/iso_mms/asn1c/asn_application.h b/src/mms/iso_mms/asn1c/asn_application.h new file mode 100644 index 0000000..f40cd86 --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_application.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Application-level ASN.1 callbacks. + */ +#ifndef _ASN_APPLICATION_H_ +#define _ASN_APPLICATION_H_ + +#include "asn_system.h" /* for platform-dependent types */ +#include "asn_codecs.h" /* for ASN.1 codecs specifics */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Generic type of an application-defined callback to return various + * types of data to the application. + * EXPECTED RETURN VALUES: + * -1: Failed to consume bytes. Abort the mission. + * Non-negative return values indicate success, and ignored. + */ +typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, + void *application_specific_key); + +/* + * A callback of this type is called whenever constraint validation fails + * on some ASN.1 type. See "constraints.h" for more details on constraint + * validation. + * This callback specifies a descriptor of the ASN.1 type which failed + * the constraint check, as well as human readable message on what + * particular constraint has failed. + */ +typedef void (asn_app_constraint_failed_f)(void *application_specific_key, + struct asn_TYPE_descriptor_s *type_descriptor_which_failed, + const void *structure_which_failed_ptr, + const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); + +#ifdef __cplusplus +} +#endif + +#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ + +#endif /* _ASN_APPLICATION_H_ */ diff --git a/src/mms/iso_mms/asn1c/asn_codecs.h b/src/mms/iso_mms/asn1c/asn_codecs.h new file mode 100644 index 0000000..4a251d9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_codecs.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _ASN_CODECS_H_ +#define _ASN_CODECS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * This structure defines a set of parameters that may be passed + * to every ASN.1 encoder or decoder function. + * WARNING: if max_stack_size member is set, and you are calling the + * function pointers of the asn_TYPE_descriptor_t directly, + * this structure must be ALLOCATED ON THE STACK! + * If you can't always satisfy this requirement, use ber_decode(), + * xer_decode() and uper_decode() functions instead. + */ +typedef struct asn_codec_ctx_s { + /* + * Limit the decoder routines to use no (much) more stack than a given + * number of bytes. Most of decoders are stack-based, and this + * would protect against stack overflows if the number of nested + * encodings is high. + * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based, + * and are safe from this kind of overflow. + * A value from getrlimit(RLIMIT_STACK) may be used to initialize + * this variable. Be careful in multithreaded environments, as the + * stack size is rather limited. + */ + size_t max_stack_size; /* 0 disables stack bounds checking */ +} asn_codec_ctx_t; + +/* + * Type of the return value of the encoding functions (der_encode, xer_encode). + */ +typedef struct asn_enc_rval_s { + /* + * Number of bytes encoded. + * -1 indicates failure to encode the structure. + * In this case, the members below this one are meaningful. + */ + ssize_t encoded; + + /* + * Members meaningful when (encoded == -1), for post mortem analysis. + */ + + /* Type which cannot be encoded */ + struct asn_TYPE_descriptor_s *failed_type; + + /* Pointer to the structure of that type */ + void *structure_ptr; +} asn_enc_rval_t; +#define _ASN_ENCODE_FAILED do { \ + asn_enc_rval_t tmp_error; \ + tmp_error.encoded = -1; \ + tmp_error.failed_type = td; \ + tmp_error.structure_ptr = sptr; \ + ASN_DEBUG("Failed to encode element %s", td->name); \ + return tmp_error; \ +} while(0) +#define _ASN_ENCODED_OK(rval) do { \ + rval.structure_ptr = 0; \ + rval.failed_type = 0; \ + return rval; \ +} while(0) + +/* + * Type of the return value of the decoding functions (ber_decode, xer_decode) + * + * Please note that the number of consumed bytes is ALWAYS meaningful, + * even if code==RC_FAIL. This is to indicate the number of successfully + * decoded bytes, hence providing a possibility to fail with more diagnostics + * (i.e., print the offending remainder of the buffer). + */ +enum asn_dec_rval_code_e { + RC_OK, /* Decoded successfully */ + RC_WMORE, /* More data expected, call again */ + RC_FAIL /* Failure to decode data */ +}; +typedef struct asn_dec_rval_s { + enum asn_dec_rval_code_e code; /* Result code */ + size_t consumed; /* Number of bytes consumed */ +} asn_dec_rval_t; +#define _ASN_DECODE_FAILED do { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_FAIL; \ + tmp_error.consumed = 0; \ + ASN_DEBUG("Failed to decode element %s", td->name); \ + return tmp_error; \ +} while(0) +#define _ASN_DECODE_STARVED do { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_WMORE; \ + tmp_error.consumed = 0; \ + return tmp_error; \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* _ASN_CODECS_H_ */ diff --git a/src/mms/iso_mms/asn1c/asn_codecs_prim.c b/src/mms/iso_mms/asn1c/asn_codecs_prim.c new file mode 100644 index 0000000..4e5c639 --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_codecs_prim.c @@ -0,0 +1,295 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Decode an always-primitive type. + */ +asn_dec_rval_t +ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **sptr, const void *buf_ptr, size_t size, int tag_mode) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; + asn_dec_rval_t rval; + ber_tlv_len_t length; + + /* + * If the structure is not there, allocate it. + */ + if(st == NULL) { + st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st)); + if(st == NULL) _ASN_DECODE_FAILED; + *sptr = (void *)st; + } + + ASN_DEBUG("Decoding %s as plain primitive (tm=%d)", + td->name, tag_mode); + + /* + * Check tags and extract value length. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("%s length is %d bytes", td->name, (int)length); + + /* + * Make sure we have this length. + */ + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + st->size = (int)length; + /* The following better be optimized away. */ + if(sizeof(st->size) != sizeof(length) + && (ber_tlv_len_t)st->size != length) { + st->size = 0; + _ASN_DECODE_FAILED; + } + + st->buf = (uint8_t *)MALLOC(length + 1); + if(!st->buf) { + st->size = 0; + _ASN_DECODE_FAILED; + } + + memcpy(st->buf, buf_ptr, length); + st->buf[length] = '\0'; /* Just in case */ + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s", + (long)rval.consumed, + (long)length, td->name); + + return rval; +} + +/* + * Encode an always-primitive type using DER. + */ +asn_enc_rval_t +der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t erval; + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; + + ASN_DEBUG("%s %s as a primitive type (tm=%d)", + cb?"Encoding":"Estimating", td->name, tag_mode); + + erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag, + cb, app_key); + ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded); + if(erval.encoded == -1) { + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + + if(cb && st->buf) { + if(cb(st->buf, st->size, app_key) < 0) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + } else { + assert(st->buf || st->size == 0); + } + + erval.encoded += st->size; + _ASN_ENCODED_OK(erval); +} + +void +ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr, + int contents_only) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; + + if(!td || !sptr) + return; + + ASN_DEBUG("Freeing %s as a primitive type", td->name); + + if(st->buf) + FREEMEM(st->buf); + + if(!contents_only) + FREEMEM(st); +} + + +/* + * Local internal type passed around as an argument. + */ +struct xdp_arg_s { + asn_TYPE_descriptor_t *type_descriptor; + void *struct_key; + xer_primitive_body_decoder_f *prim_body_decoder; + int decoded_something; + int want_more; +}; + + +static int +xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { + struct xdp_arg_s *arg = (struct xdp_arg_s *)key; + enum xer_pbd_rval bret; + + if(arg->decoded_something) { + if(xer_is_whitespace(chunk_buf, chunk_size)) + return 0; /* Skip it. */ + /* + * Decoding was done once already. Prohibit doing it again. + */ + return -1; + } + + bret = arg->prim_body_decoder(arg->type_descriptor, + arg->struct_key, chunk_buf, chunk_size); + switch(bret) { + case XPBD_SYSTEM_FAILURE: + case XPBD_DECODER_LIMIT: + case XPBD_BROKEN_ENCODING: + break; + case XPBD_BODY_CONSUMED: + /* Tag decoded successfully */ + arg->decoded_something = 1; + /* Fall through */ + case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ + return 0; + } + + return -1; +} + +static ssize_t +xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { + struct xdp_arg_s *arg = (struct xdp_arg_s *)key; + enum xer_pbd_rval bret; + + if(arg->decoded_something) { + if(xer_is_whitespace(chunk_buf, chunk_size)) + return chunk_size; + /* + * Decoding was done once already. Prohibit doing it again. + */ + return -1; + } + + if(!have_more) { + /* + * If we've received something like "1", we can't really + * tell whether it is really `1` or `123`, until we know + * that there is no more data coming. + * The have_more argument will be set to 1 once something + * like this is available to the caller of this callback: + * "1want_more = 1; + return -1; + } + + bret = arg->prim_body_decoder(arg->type_descriptor, + arg->struct_key, chunk_buf, chunk_size); + switch(bret) { + case XPBD_SYSTEM_FAILURE: + case XPBD_DECODER_LIMIT: + case XPBD_BROKEN_ENCODING: + break; + case XPBD_BODY_CONSUMED: + /* Tag decoded successfully */ + arg->decoded_something = 1; + /* Fall through */ + case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ + return chunk_size; + } + + return -1; +} + + +asn_dec_rval_t +xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **sptr, + size_t struct_size, + const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder +) { + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + asn_struct_ctx_t s_ctx; + struct xdp_arg_s s_arg; + asn_dec_rval_t rc; + + /* + * Create the structure if does not exist. + */ + if(!*sptr) { + *sptr = CALLOC(1, struct_size); + if(!*sptr) _ASN_DECODE_FAILED; + } + + memset(&s_ctx, 0, sizeof(s_ctx)); + s_arg.type_descriptor = td; + s_arg.struct_key = *sptr; + s_arg.prim_body_decoder = prim_body_decoder; + s_arg.decoded_something = 0; + s_arg.want_more = 0; + + rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, + xml_tag, buf_ptr, size, + xer_decode__unexpected_tag, xer_decode__body); + switch(rc.code) { + case RC_OK: + if(!s_arg.decoded_something) { + char ch; + ASN_DEBUG("Primitive body is not recognized, " + "supplying empty one"); + /* + * Decoding opportunity has come and gone. + * Where's the result? + * Try to feed with empty body, see if it eats it. + */ + if(prim_body_decoder(s_arg.type_descriptor, + s_arg.struct_key, &ch, 0) + != XPBD_BODY_CONSUMED) { + /* + * This decoder does not like empty stuff. + */ + _ASN_DECODE_FAILED; + } + } + break; + case RC_WMORE: + /* + * Redo the whole thing later. + * We don't have a context to save intermediate parsing state. + */ + rc.consumed = 0; + break; + case RC_FAIL: + rc.consumed = 0; + if(s_arg.want_more) + rc.code = RC_WMORE; + else + _ASN_DECODE_FAILED; + break; + } + return rc; +} + diff --git a/src/mms/iso_mms/asn1c/asn_codecs_prim.h b/src/mms/iso_mms/asn1c/asn_codecs_prim.h new file mode 100644 index 0000000..0f683fd --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_codecs_prim.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_CODECS_PRIM_H +#define ASN_CODECS_PRIM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ASN__PRIMITIVE_TYPE_s { + uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ + int size; /* Size of the buffer */ +} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ + +asn_struct_free_f ASN__PRIMITIVE_TYPE_free; +ber_type_decoder_f ber_decode_primitive; +der_type_encoder_f der_encode_primitive; + +/* + * A callback specification for the xer_decode_primitive() function below. + */ +enum xer_pbd_rval { + XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ + XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ + XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ + XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ + XPBD_BODY_CONSUMED /* Body is recognized and consumed */ +}; +typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) + (asn_TYPE_descriptor_t *td, void *struct_ptr, + const void *chunk_buf, size_t chunk_size); + +/* + * Specific function to decode simple primitive types. + * Also see xer_decode_general() in xer_decoder.h + */ +asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *type_descriptor, + void **struct_ptr, size_t struct_size, + const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder +); + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_CODECS_PRIM_H */ diff --git a/src/mms/iso_mms/asn1c/asn_internal.h b/src/mms/iso_mms/asn1c/asn_internal.h new file mode 100644 index 0000000..2ba232b --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_internal.h @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Declarations internally useful for the ASN.1 support code. + */ +#ifndef _ASN_INTERNAL_H_ +#define _ASN_INTERNAL_H_ + +#include "asn_application.h" /* Application-visible API */ + +//#include "libiec61850_platform_includes.h" +#include "lib_memory.h" + +#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ +#include /* for assert() macro */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Environment version might be used to avoid running with the old library */ +#define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */ +int get_asn1c_environment_version(void); /* Run-time version */ + +#if 0 +#ifndef CALLOC +#define CALLOC(nmemb, size) calloc(nmemb, size) +#endif + +#ifndef MALLOC +#define MALLOC(size) malloc(size) +#endif + +#ifndef REALLOC +#define REALLOC(oldptr, size) realloc(oldptr, size) +#endif + +#ifndef FREEMEM +#define FREEMEM(ptr) free(ptr) +#endif +#endif + +/* + * A macro for debugging the ASN.1 internals. + * You may enable or override it. + */ + +#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ +#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ +#ifdef __GNUC__ +#define ASN_DEBUG(fmt, args...) do { \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ + __FILE__, __LINE__); \ + } while(0) +#else /* !__GNUC__ */ +void ASN_DEBUG_f(const char *fmt, ...); +#define ASN_DEBUG ASN_DEBUG_f +#endif /* __GNUC__ */ +#else /* EMIT_ASN_DEBUG != 1 */ +static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } +#endif /* EMIT_ASN_DEBUG */ +#endif /* ASN_DEBUG */ + +/* + * Invoke the application-supplied callback and fail, if something is wrong. + */ +#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) +#define _ASN_E_CALLBACK(foo) do { \ + if(foo) goto cb_failed; \ + } while(0) +#define _ASN_CALLBACK(buf, size) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) +#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) +#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ + _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) \ + || __ASN_E_cbc(buf2, size2) \ + || __ASN_E_cbc(buf3, size3)) + +#define _i_ASN_TEXT_INDENT(nl, level) do { \ + int __level = (level); \ + int __nl = ((nl) != 0); \ + int __i; \ + if(__nl) _ASN_CALLBACK("\n", 1); \ + for(__i = 0; __i < __level; __i++) \ + _ASN_CALLBACK(" ", 4); \ + er.encoded += __nl + 4 * __level; \ +} while(0) + +#define _i_INDENT(nl) do { \ + int __i; \ + if((nl) && cb("\n", 1, app_key) < 0) return -1; \ + for(__i = 0; __i < ilevel; __i++) \ + if(cb(" ", 4, app_key) < 0) return -1; \ +} while(0) + +/* + * Check stack against overflow, if limit is set. + */ +#define _ASN_DEFAULT_STACK_MAX (30000) +static inline int +_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { + if(ctx && ctx->max_stack_size) { + + /* ctx MUST be allocated on the stack */ + ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); + if(usedstack > 0) usedstack = -usedstack; /* grows up! */ + + /* double negative required to avoid int wrap-around */ + if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { + ASN_DEBUG("Stack limit %ld reached", + (long)ctx->max_stack_size); + return -1; + } + } + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASN_INTERNAL_H_ */ diff --git a/src/mms/iso_mms/asn1c/asn_system.h b/src/mms/iso_mms/asn1c/asn_system.h new file mode 100644 index 0000000..0fdb37f --- /dev/null +++ b/src/mms/iso_mms/asn1c/asn_system.h @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Miscellaneous system-dependent types. + */ +#ifndef _ASN_SYSTEM_H_ +#define _ASN_SYSTEM_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* For snprintf(3) */ +#include /* For *alloc(3) */ +#include /* For memcpy(3) */ + +#include "stack_config.h" +#if CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS +#include "libiec61850_platform_specific.h" +#else +#include /* For size_t */ +#endif + +#include /* For va_start */ +#include /* for offsetof and ptrdiff_t */ + + + +#ifdef _WIN32 +#ifndef WIN32 +#define WIN32 +#endif +#endif + +#ifdef WIN32 + +#include +#include +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +#ifdef _MSC_VER /* MSVS.Net */ +#ifndef __cplusplus +#define inline __inline +#endif +#define ssize_t SSIZE_T +//typedef char int8_t; +//typedef short int16_t; +//typedef int int32_t; +//typedef unsigned char uint8_t; +//typedef unsigned short uint16_t; +//typedef unsigned int uint32_t; +#define WIN32_LEAN_AND_MEAN +#include +#include +#define isnan _isnan +#define finite _finite +#define copysign _copysign +#define ilogb _logb +#endif /* _MSC_VER */ + +#else /* !WIN32 */ + +#if defined(__vxworks) +#include +#else /* !defined(__vxworks) */ + +#include /* C99 specifies this file */ +/* + * 1. Earlier FreeBSD version didn't have , + * but was present. + * 2. Sun Solaris requires for alloca(3), + * but does not have . + */ +#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) +#if defined(sun) +#include /* For alloca(3) */ +#include /* for finite(3) */ +#elif defined(__hpux) +#ifdef __GNUC__ +#include /* For alloca(3) */ +#else /* !__GNUC__ */ +#define inline +#endif /* __GNUC__ */ +#else +#include /* SUSv2+ and C99 specify this file, for uintXX_t */ +#endif /* defined(sun) */ +#endif + +#endif /* defined(__vxworks) */ + +#endif /* WIN32 */ + +#if __GNUC__ >= 3 +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +#endif +#else +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt,var) /* nothing */ +#endif +#endif + +#ifndef offsetof /* If not defined by */ +#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) +#endif /* offsetof */ + +#ifndef MIN /* Suitable for comparing primitive types (integers) */ +#if defined(__GNUC__) +#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ + ((_a)<(_b)?(_a):(_b)); }) +#else /* !__GNUC__ */ +#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ +#endif /* __GNUC__ */ +#endif /* MIN */ + +#endif /* _ASN_SYSTEM_H_ */ diff --git a/src/mms/iso_mms/asn1c/ber_decoder.c b/src/mms/iso_mms/asn1c/ber_decoder.c new file mode 100644 index 0000000..601f66c --- /dev/null +++ b/src/mms/iso_mms/asn1c/ber_decoder.c @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) +#undef RETURN +#define RETURN(_code) do { \ + asn_dec_rval_t rval; \ + rval.code = _code; \ + if(opt_ctx) opt_ctx->step = step; /* Save context */ \ + if(_code == RC_OK || opt_ctx) \ + rval.consumed = consumed_myself; \ + else \ + rval.consumed = 0; /* Context-free */ \ + return rval; \ + } while(0) + +/* + * The BER decoder of any type. + */ +asn_dec_rval_t +ber_decode(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *type_descriptor, + void **struct_ptr, const void *ptr, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + ptr, size, /* Buffer and its size */ + 0 /* Default tag mode is 0 */ + ); +} + +/* + * Check the set of >> tags matches the definition. + */ +asn_dec_rval_t +ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, + const void *ptr, size_t size, int tag_mode, int last_tag_form, + ber_tlv_len_t *last_length, int *opt_tlv_form) { + ssize_t consumed_myself = 0; + ssize_t tag_len; + ssize_t len_len; + ber_tlv_tag_t tlv_tag; + ber_tlv_len_t tlv_len; + ber_tlv_len_t limit_len = -1; + int expect_00_terminators = 0; + int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ + int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ + int tagno; + + /* + * Make sure we didn't exceed the maximum stack size. + */ + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + RETURN(RC_FAIL); + + /* + * So what does all this implicit skip stuff mean? + * Imagine two types, + * A ::= [5] IMPLICIT T + * B ::= [2] EXPLICIT T + * Where T is defined as + * T ::= [4] IMPLICIT SEQUENCE { ... } + * + * Let's say, we are starting to decode type A, given the + * following TLV stream: <5> <0>. What does this mean? + * It means that the type A contains type T which is, + * in turn, empty. + * Remember though, that we are still in A. We cannot + * just pass control to the type T decoder. Why? Because + * the type T decoder expects <4> <0>, not <5> <0>. + * So, we must make sure we are going to receive <5> while + * still in A, then pass control to the T decoder, indicating + * that the tag <4> was implicitly skipped. The decoder of T + * hence will be prepared to treat <4> as valid tag, and decode + * it appropriately. + */ + + tagno = step /* Continuing where left previously */ + + (tag_mode==1?-1:0) + ; + ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)", + td->name, (long)size, tag_mode, step, tagno); + /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ + + if(tag_mode == 0 && tagno == td->tags_count) { + /* + * This must be the _untagged_ ANY type, + * which outermost tag isn't known in advance. + * Fetch the tag and length separately. + */ + tag_len = ber_fetch_tag(ptr, size, &tlv_tag); + switch(tag_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + tlv_constr = BER_TLV_CONSTRUCTED(ptr); + len_len = ber_fetch_length(tlv_constr, + (const char *)ptr + tag_len, size - tag_len, &tlv_len); + switch(len_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + ASN_DEBUG("Advancing %ld in ANY case", + (long)(tag_len + len_len)); + ADVANCE(tag_len + len_len); + } else { + assert(tagno < td->tags_count); /* At least one loop */ + } + for((void)tagno; tagno < td->tags_count; tagno++, step++) { + + /* + * Fetch and process T from TLV. + */ + tag_len = ber_fetch_tag(ptr, size, &tlv_tag); + ASN_DEBUG("Fetching tag from {%p,%ld}: " + "len %ld, step %d, tagno %d got %s", + ptr, (long)size, + (long)tag_len, step, tagno, + ber_tlv_tag_string(tlv_tag)); + switch(tag_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + tlv_constr = BER_TLV_CONSTRUCTED(ptr); + + /* + * If {I}, don't check anything. + * If {I,B,C}, check B and C unless we're at I. + */ + if(tag_mode != 0 && step == 0) { + /* + * We don't expect tag to match here. + * It's just because we don't know how the tag + * is supposed to look like. + */ + } else { + assert(tagno >= 0); /* Guaranteed by the code above */ + if(tlv_tag != td->tags[tagno]) { + /* + * Unexpected tag. Too bad. + */ + ASN_DEBUG("Expected: %s, " + "expectation failed (tn=%d, tm=%d)", + ber_tlv_tag_string(td->tags[tagno]), + tagno, tag_mode + ); + RETURN(RC_FAIL); + } + } + + /* + * Attention: if there are more tags expected, + * ensure that the current tag is presented + * in constructed form (it contains other tags!). + * If this one is the last one, check that the tag form + * matches the one given in descriptor. + */ + if(tagno < (td->tags_count - 1)) { + if(tlv_constr == 0) { + ASN_DEBUG("tlv_constr = %d, expfail", + tlv_constr); + RETURN(RC_FAIL); + } + } else { + if(last_tag_form != tlv_constr + && last_tag_form != -1) { + ASN_DEBUG("last_tag_form %d != %d", + last_tag_form, tlv_constr); + RETURN(RC_FAIL); + } + } + + /* + * Fetch and process L from TLV. + */ + len_len = ber_fetch_length(tlv_constr, + (const char *)ptr + tag_len, size - tag_len, &tlv_len); + ASN_DEBUG("Fetchinig len = %ld", (long)len_len); + switch(len_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + /* + * FIXME + * As of today, the chain of tags + * must either contain several indefinite length TLVs, + * or several definite length ones. + * No mixing is allowed. + */ + if(tlv_len == -1) { + /* + * Indefinite length. + */ + if(limit_len == -1) { + expect_00_terminators++; + } else { + ASN_DEBUG("Unexpected indefinite length " + "in a chain of definite lengths"); + RETURN(RC_FAIL); + } + ADVANCE(tag_len + len_len); + continue; + } else { + if(expect_00_terminators) { + ASN_DEBUG("Unexpected definite length " + "in a chain of indefinite lengths"); + RETURN(RC_FAIL); + } + } + + /* + * Check that multiple TLVs specify ever decreasing length, + * which is consistent. + */ + if(limit_len == -1) { + limit_len = tlv_len + tag_len + len_len; + if(limit_len < 0) { + /* Too great tlv_len value? */ + RETURN(RC_FAIL); + } + } else if(limit_len != tlv_len + tag_len + len_len) { + /* + * Inner TLV specifies length which is inconsistent + * with the outer TLV's length value. + */ + ASN_DEBUG("Outer TLV is %ld and inner is %ld", + (long)limit_len, (long)tlv_len); + RETURN(RC_FAIL); + } + + ADVANCE(tag_len + len_len); + + limit_len -= (tag_len + len_len); + if((ssize_t)size > limit_len) { + /* + * Make sure that we won't consume more bytes + * from the parent frame than the inferred limit. + */ + size = limit_len; + } + } + + if(opt_tlv_form) + *opt_tlv_form = tlv_constr; + if(expect_00_terminators) + *last_length = -expect_00_terminators; + else + *last_length = tlv_len; + + RETURN(RC_OK); +} diff --git a/src/mms/iso_mms/asn1c/ber_decoder.h b/src/mms/iso_mms/asn1c/ber_decoder.h new file mode 100644 index 0000000..768133b --- /dev/null +++ b/src/mms/iso_mms/asn1c/ber_decoder.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_DECODER_H_ +#define _BER_DECODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_codec_ctx_s; /* Forward declaration */ + +/* + * The BER decoder of any type. + * This function may be invoked directly from the application. + */ +asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ + ); + +/* + * Type of generic function which decodes the byte stream into the structure. + */ +typedef asn_dec_rval_t (ber_type_decoder_f)( + struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, const void *buf_ptr, size_t size, + int tag_mode); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Check that all tags correspond to the type definition (as given in head). + * On return, last_length would contain either a non-negative length of the + * value part of the last TLV, or the negative number of expected + * "end of content" sequences. The number may only be negative if the + * head->last_tag_form is non-zero. + */ +asn_dec_rval_t ber_check_tags( + struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ + struct asn_TYPE_descriptor_s *type_descriptor, + asn_struct_ctx_t *opt_ctx, /* saved decoding context */ + const void *ptr, size_t size, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {-1,0:1}: any, primitive, constr */ + ber_tlv_len_t *last_length, + int *opt_tlv_form /* optional tag form */ + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_DECODER_H_ */ diff --git a/src/mms/iso_mms/asn1c/ber_tlv_length.c b/src/mms/iso_mms/asn1c/ber_tlv_length.c new file mode 100644 index 0000000..b87e75e --- /dev/null +++ b/src/mms/iso_mms/asn1c/ber_tlv_length.c @@ -0,0 +1,178 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +ssize_t +ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r) { + const uint8_t *buf = (const uint8_t *)bufptr; + unsigned oct; + + if(size == 0) + return 0; /* Want more */ + + oct = *(const uint8_t *)buf; + if((oct & 0x80) == 0) { + /* + * Short definite length. + */ + *len_r = oct; /* & 0x7F */ + return 1; + } else { + ber_tlv_len_t len; + size_t skipped; + + if(_is_constructed && oct == 0x80) { + *len_r = -1; /* Indefinite length */ + return 1; + } + + if(oct == 0xff) { + /* Reserved in standard for future use. */ + return -1; + } + + oct &= 0x7F; /* Leave only the 7 LS bits */ + for(len = 0, buf++, skipped = 1; + oct && (++skipped <= size); buf++, oct--) { + + len = (len << 8) | *buf; + if(len < 0 + || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) { + /* + * Too large length value. + */ + return -1; + } + } + + if(oct == 0) { + ber_tlv_len_t lenplusepsilon = (size_t)len + 1024; + /* + * Here length may be very close or equal to 2G. + * However, the arithmetics used in some decoders + * may add some (small) quantities to the length, + * to check the resulting value against some limits. + * This may result in integer wrap-around, which + * we try to avoid by checking it earlier here. + */ + if(lenplusepsilon < 0) { + /* Too large length value */ + return -1; + } + + *len_r = len; + return skipped; + } + + return 0; /* Want more */ + } + +} + +ssize_t +ber_skip_length(asn_codec_ctx_t *opt_codec_ctx, + int _is_constructed, const void *ptr, size_t size) { + ber_tlv_len_t vlen; /* Length of V in TLV */ + ssize_t tl; /* Length of L in TLV */ + ssize_t ll; /* Length of L in TLV */ + size_t skip; + + /* + * Make sure we didn't exceed the maximum stack size. + */ + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + return -1; + + /* + * Determine the size of L in TLV. + */ + ll = ber_fetch_length(_is_constructed, ptr, size, &vlen); + if(ll <= 0) return ll; + + /* + * Definite length. + */ + if(vlen >= 0) { + skip = ll + vlen; + if(skip > size) + return 0; /* Want more */ + return skip; + } + + /* + * Indefinite length! + */ + ASN_DEBUG("Skipping indefinite length"); + for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) { + ber_tlv_tag_t tag; + + /* Fetch the tag */ + tl = ber_fetch_tag(ptr, size, &tag); + if(tl <= 0) return tl; + + ll = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + ((const char *)ptr) + tl, size - tl); + if(ll <= 0) return ll; + + skip += tl + ll; + + /* + * This may be the end of the indefinite length structure, + * two consecutive 0 octets. + * Check if it is true. + */ + if(((const uint8_t *)ptr)[0] == 0 + && ((const uint8_t *)ptr)[1] == 0) + return skip; + + ptr = ((const char *)ptr) + tl + ll; + size -= tl + ll; + } + + /* UNREACHABLE */ +} + +size_t +der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) { + size_t required_size; /* Size of len encoding */ + uint8_t *buf = (uint8_t *)bufp; + uint8_t *end; + size_t i; + + if(len <= 127) { + /* Encoded in 1 octet */ + if(size) *buf = (uint8_t)len; + return 1; + } + + /* + * Compute the size of the subsequent bytes. + */ + for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) { + if(len >> i) + required_size++; + else + break; + } + + if(size <= required_size) + return required_size + 1; + + *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */ + + /* + * Produce the len encoding, space permitting. + */ + end = buf + required_size; + for(i -= 8; buf < end; i -= 8, buf++) + *buf = (uint8_t)(len >> i); + + return required_size + 1; +} + diff --git a/src/mms/iso_mms/asn1c/ber_tlv_length.h b/src/mms/iso_mms/asn1c/ber_tlv_length.h new file mode 100644 index 0000000..3496802 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ber_tlv_length.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_TLV_LENGTH_H_ +#define _BER_TLV_LENGTH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ssize_t ber_tlv_len_t; + +/* + * This function tries to fetch the length of the BER TLV value and place it + * in *len_r. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + * On return with >0, len_r is constrained as -1..MAX, where -1 mean + * that the value is of indefinite length. + */ +ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r); + +/* + * This function expects bufptr to be positioned over L in TLV. + * It returns number of bytes occupied by L and V together, suitable + * for skipping. The function properly handles indefinite length. + * RETURN VALUES: + * Standard {-1,0,>0} convention. + */ +ssize_t ber_skip_length( + struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ + int _is_constructed, const void *bufptr, size_t size); + +/* + * This function serializes the length (L from TLV) in DER format. + * It always returns number of bytes necessary to represent the length, + * it is a caller's responsibility to check the return value + * against the supplied buffer's size. + */ +size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_TLV_LENGTH_H_ */ diff --git a/src/mms/iso_mms/asn1c/ber_tlv_tag.c b/src/mms/iso_mms/asn1c/ber_tlv_tag.c new file mode 100644 index 0000000..588d9ee --- /dev/null +++ b/src/mms/iso_mms/asn1c/ber_tlv_tag.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +ssize_t +ber_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { + ber_tlv_tag_t val; + ber_tlv_tag_t tclass; + size_t skipped; + + if(size == 0) + return 0; + + val = *(const uint8_t *)ptr; + tclass = (val >> 6); + if((val &= 0x1F) != 0x1F) { + /* + * Simple form: everything encoded in a single octet. + * Tag Class is encoded using two least significant bits. + */ + *tag_r = (val << 2) | tclass; + return 1; + } + + /* + * Each octet contains 7 bits of useful information. + * The MSB is 0 if it is the last octet of the tag. + */ + for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; + skipped <= size; + ptr = ((const char *)ptr) + 1, skipped++) { + unsigned int oct = *(const uint8_t *)ptr; + if(oct & 0x80) { + val = (val << 7) | (oct & 0x7F); + /* + * Make sure there are at least 9 bits spare + * at the MS side of a value. + */ + if(val >> ((8 * sizeof(val)) - 9)) { + /* + * We would not be able to accomodate + * any more tag bits. + */ + return -1; + } + } else { + val = (val << 7) | oct; + *tag_r = (val << 2) | tclass; + return skipped; + } + } + + return 0; /* Want more */ +} + + +ssize_t +ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) { + char buf[sizeof("[APPLICATION ]") + 32]; + ssize_t ret; + + ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf)); + if(ret >= (ssize_t)sizeof(buf) || ret < 2) { + errno = EPERM; + return -1; + } + + return fwrite(buf, 1, ret, f); +} + +ssize_t +ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) { + char *type = 0; + int ret; + + switch(tag & 0x3) { + case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break; + case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break; + case ASN_TAG_CLASS_CONTEXT: type = ""; break; + case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break; + } + + ret = snprintf(buf, size, "[%s%u](%02x)", type, ((unsigned)tag) >> 2, tag); + if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */ + + return ret; +} + +char * +ber_tlv_tag_string(ber_tlv_tag_t tag) { + static char buf[sizeof("[APPLICATION ]") + 32]; + + (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf)); + + return buf; +} + + +size_t +ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) { + int tclass = BER_TAG_CLASS(tag); + ber_tlv_tag_t tval = BER_TAG_VALUE(tag); + uint8_t *buf = (uint8_t *)bufp; + uint8_t *end; + size_t required_size; + size_t i; + + if(tval <= 30) { + /* Encoded in 1 octet */ + if(size) buf[0] = (tclass << 6) | tval; + return 1; + } else if(size) { + *buf++ = (tclass << 6) | 0x1F; + size--; + } + + /* + * Compute the size of the subsequent bytes. + */ + for(required_size = 1, i = 7; i < 8 * sizeof(tval); i += 7) { + if(tval >> i) + required_size++; + else + break; + } + + if(size < required_size) + return required_size + 1; + + /* + * Fill in the buffer, space permitting. + */ + end = buf + required_size - 1; + for(i -= 7; buf < end; i -= 7, buf++) + *buf = 0x80 | ((tval >> i) & 0x7F); + *buf = (tval & 0x7F); /* Last octet without high bit */ + + return required_size + 1; +} + diff --git a/src/mms/iso_mms/asn1c/ber_tlv_tag.h b/src/mms/iso_mms/asn1c/ber_tlv_tag.h new file mode 100644 index 0000000..60e8668 --- /dev/null +++ b/src/mms/iso_mms/asn1c/ber_tlv_tag.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_TLV_TAG_H_ +#define _BER_TLV_TAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum asn_tag_class { + ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ + ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ + ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ + ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ +}; +typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ + +/* + * Tag class is encoded together with tag value for optimization purposes. + */ +#define BER_TAG_CLASS(tag) ((tag) & 0x3) +#define BER_TAG_VALUE(tag) ((tag) >> 2) +#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) + +#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) + +/* + * Several functions for printing the TAG in the canonical form + * (i.e. "[PRIVATE 0]"). + * Return values correspond to their libc counterparts (if any). + */ +ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); +ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); +char *ber_tlv_tag_string(ber_tlv_tag_t tag); + + +/* + * This function tries to fetch the tag from the input stream. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering tag. + * >0: Number of bytes used from bufptr. tag_r will contain the tag. + */ +ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); + +/* + * This function serializes the tag (T from TLV) in BER format. + * It always returns number of bytes necessary to represent the tag, + * it is a caller's responsibility to check the return value + * against the supplied buffer's size. + */ +size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_TLV_TAG_H_ */ diff --git a/src/mms/iso_mms/asn1c/constr_CHOICE.c b/src/mms/iso_mms/asn1c/constr_CHOICE.c new file mode 100644 index 0000000..b8d6fa9 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_CHOICE.c @@ -0,0 +1,1101 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * See the definitions. + */ +static int _fetch_present_idx(const void *struct_ptr, int off, int size); +static void _set_present_idx(void *sptr, int offset, int size, int pres); + +/* + * Tags are canonically sorted in the tag to member table. + */ +static int +_search4tag(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) + return 0; + else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + +/* + * The decoder of the CHOICE type. + */ +asn_dec_rval_t +CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + ssize_t tag_len; /* Length of TLV's T */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + ASN_DEBUG("Decoding %s as CHOICE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + if(tag_mode || td->tags_count) { + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, -1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) { + /* ?Substracted below! */ + ctx->left += rval.consumed; + } + ADVANCE(rval.consumed); + } else { + ctx->left = -1; + } + + NEXT_PHASE(ctx); + + ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", + (long)ctx->left, (long)size); + + /* Fall through */ + case 1: + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + do { + asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key; + + key.el_tag = tlv_tag; + t2m = (asn_TYPE_tag2member_t *)bsearch(&key, + specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _search4tag); + if(t2m) { + /* + * Found the element corresponding to the tag. + */ + NEXT_PHASE(ctx); + ctx->step = t2m->el_no; + break; + } else if(specs->ext_start == -1) { + ASN_DEBUG("Unexpected tag %s " + "in non-extensible CHOICE %s", + ber_tlv_tag_string(tlv_tag), td->name); + RETURN(RC_FAIL); + } else { + /* Skip this tag */ + ssize_t skip; + + ASN_DEBUG("Skipping unknown tag %s", + ber_tlv_tag_string(tlv_tag)); + + skip = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tag_len, + LEFT - tag_len); + + switch(skip) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(skip + tag_len); + RETURN(RC_OK); + } + } while(0); + + case 2: + /* + * PHASE 2. + * Read in the element. + */ + do { + asn_TYPE_member_t *elm;/* CHOICE's element */ + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &elements[ctx->step]; + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + /* Set presence to be able to free it properly at any time */ + _set_present_idx(st, specs->pres_offset, + specs->pres_size, ctx->step + 1); + /* + * Invoke the member fetch routine according to member's type + */ + rval = elm->type->ber_decoder(opt_codec_ctx, elm->type, + memb_ptr2, ptr, LEFT, elm->tag_mode); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + RETURN(RC_FAIL); + case RC_FAIL: /* Fatal error */ + RETURN(rval.code); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } while(0); + + NEXT_PHASE(ctx); + + /* Fall through */ + case 3: + ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d", + td->name, (long)ctx->left, (long)size, + tag_mode, td->tags_count); + + if(ctx->left > 0) { + /* + * The type must be fully decoded + * by the CHOICE member-specific decoder. + */ + RETURN(RC_FAIL); + } + + if(ctx->left == -1 + && !(tag_mode || td->tags_count)) { + /* + * This is an untagged CHOICE. + * It doesn't contain nothing + * except for the member itself, including all its tags. + * The decoding is completed. + */ + NEXT_PHASE(ctx); + break; + } + + /* + * Read in the "end of data chunks"'s. + */ + while(ctx->left < 0) { + ssize_t tl; + + tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tl) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + /* + * Expected <0><0>... + */ + if(((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + continue; + } + } else { + ASN_DEBUG("Unexpected continuation in %s", + td->name); + RETURN(RC_FAIL); + } + + /* UNREACHABLE */ + } + + NEXT_PHASE(ctx); + case 4: + /* No meaningful work here */ + break; + } + + RETURN(RC_OK); +} + +asn_enc_rval_t +CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE element */ + asn_enc_rval_t erval; + void *memb_ptr; + size_t computed_size = 0; + int present; + + if(!sptr) _ASN_ENCODE_FAILED; + + ASN_DEBUG("%s %s as CHOICE", + cb?"Encoding":"Estimating", td->name); + + present = _fetch_present_idx(sptr, + specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present <= 0 || present > td->elements_count) { + if(present == 0 && td->elements_count == 0) { + /* The CHOICE is empty?! */ + erval.encoded = 0; + _ASN_ENCODED_OK(erval); + } + _ASN_ENCODE_FAILED; + } + + /* + * Seek over the present member of the structure. + */ + elm = &td->elements[present-1]; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(memb_ptr == 0) { + if(elm->optional) { + erval.encoded = 0; + _ASN_ENCODED_OK(erval); + } + /* Mandatory element absent */ + _ASN_ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + /* + * If the CHOICE itself is tagged EXPLICIT: + * T ::= [2] EXPLICIT CHOICE { ... } + * Then emit the appropriate tags. + */ + if(tag_mode == 1 || td->tags_count) { + /* + * For this, we need to pre-compute the member. + */ + ssize_t ret; + + /* Encode member with its tag */ + erval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, 0, 0); + if(erval.encoded == -1) + return erval; + + /* Encode CHOICE with parent or my own tag */ + ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag, + cb, app_key); + if(ret == -1) + _ASN_ENCODE_FAILED; + computed_size += ret; + } + + /* + * Encode the single underlying member. + */ + erval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, cb, app_key); + if(erval.encoded == -1) + return erval; + + ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)", + (long)erval.encoded, (long)computed_size); + + erval.encoded += computed_size; + + return erval; +} + +ber_tlv_tag_t +CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + assert(tag_mode == 0); (void)tag_mode; + assert(tag == 0); (void)tag; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); + + if(present > 0 || present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *) + ((const char *)ptr + elm->memb_offset); + } else { + memb_ptr = (const void *) + ((const char *)ptr + elm->memb_offset); + } + + return asn_TYPE_outmost_tag(elm->type, memb_ptr, + elm->tag_mode, elm->tag); + } else { + return (ber_tlv_tag_t)-1; + } +} + +int +CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + return 0; + _ASN_CTFAIL(app_key, td, + "%s: mandatory CHOICE element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(elm->memb_constraints) { + return elm->memb_constraints(elm->type, memb_ptr, + ctfailcb, app_key); + } else { + int ret = elm->type->check_constraints(elm->type, + memb_ptr, ctfailcb, app_key); + /* + * Cannot inherit it eralier: + * need to make sure we get the updated version. + */ + elm->memb_constraints = elm->type->check_constraints; + return ret; + } + } else { + _ASN_CTFAIL(app_key, td, + "%s: no CHOICE element given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = ((const char *)buf_ptr) + num;\ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value of a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + int edx; /* Element index */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + if(ctx->phase == 0 && !*xml_tag) + ctx->phase = 1; /* Skip the outer tag checking phase */ + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + * Phase 3: Only waiting for closing tag. + * Phase 4: Skipping unknown extensions. + * Phase 5: PHASED OUT + */ + for(edx = ctx->step; ctx->phase <= 4;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + asn_TYPE_member_t *elm; + + /* + * Go inside the member. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &td->elements[edx]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Start/Continue decoding the inner member */ + tmprval = elm->type->xer_decoder(opt_codec_ctx, + elm->type, memb_ptr2, elm->name, + buf_ptr, size); + XER_ADVANCE(tmprval.consumed); + ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d", + elm->type->name, tmprval.code); + if(tmprval.code != RC_OK) + RETURN(tmprval.code); + assert(_fetch_present_idx(st, + specs->pres_offset, specs->pres_size) == 0); + /* Record what we've got */ + _set_present_idx(st, + specs->pres_offset, specs->pres_size, edx + 1); + ctx->phase = 3; + /* Fall through */ + } + + /* No need to wait for closing tag; special mode. */ + if(ctx->phase == 3 && !*xml_tag) { + ctx->phase = 5; /* Phase out */ + RETURN(RC_OK); + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); + switch(ch_size) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + default: + switch(ch_type) { + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d", + ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', + ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', + ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', + ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', + xml_tag, tcv); + + /* Skip the extensions section */ + if(ctx->phase == 4) { + ASN_DEBUG("skip_unknown(%d, %ld)", + tcv, (long)ctx->left); + switch(xer_skip_unknown(tcv, &ctx->left)) { + case -1: + ctx->phase = 5; + RETURN(RC_FAIL); + continue; + case 1: + ctx->phase = 3; + /* Fall through */ + case 0: + XER_ADVANCE(ch_size); + continue; + case 2: + ctx->phase = 3; + break; + } + } + + switch(tcv) { + case XCT_BOTH: + break; /* No CHOICE? */ + case XCT_CLOSING: + if(ctx->phase != 3) + break; + XER_ADVANCE(ch_size); + ctx->phase = 5; /* Phase out */ + RETURN(RC_OK); + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + if(ctx->phase != 1) + break; /* Really unexpected */ + + /* + * Search which inner member corresponds to this tag. + */ + for(edx = 0; edx < td->elements_count; edx++) { + elm = &td->elements[edx]; + tcv = xer_check_tag(buf_ptr,ch_size,elm->name); + switch(tcv) { + case XCT_BOTH: + case XCT_OPENING: + /* + * Process this member. + */ + ctx->step = edx; + ctx->phase = 2; + break; + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + continue; + default: + edx = td->elements_count; + break; /* Phase out */ + } + break; + } + if(edx != td->elements_count) + continue; + + /* It is expected extension */ + if(specs->ext_start != -1) { + ASN_DEBUG("Got anticipated extension"); + /* + * Check for (XCT_BOTH or XCT_UNKNOWN_BO) + * By using a mask. Only record a pure + * tags. + */ + if(tcv & XCT_CLOSING) { + /* Found without body */ + ctx->phase = 3; /* Terminating */ + } else { + ctx->left = 1; + ctx->phase = 4; /* Skip ...'s */ + } + XER_ADVANCE(ch_size); + continue; + } + + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]" + " (ph=%d, tag=%s)", + ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', + ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', + ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', + ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', + td->name, ctx->phase, xml_tag); + break; + } + + ctx->phase = 5; /* Phase out, just in case */ + RETURN(RC_FAIL); +} + + +asn_enc_rval_t +CHOICE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_CHOICE_specifics_t *specs=(asn_CHOICE_specifics_t *)td->specifics; + asn_enc_rval_t er; + int present; + + if(!sptr) + _ASN_ENCODE_FAILED; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + + if(present <= 0 || present > td->elements_count) { + _ASN_ENCODE_FAILED; + } else { + asn_enc_rval_t tmper; + asn_TYPE_member_t *elm = &td->elements[present-1]; + void *memb_ptr; + const char *mname = elm->name; + unsigned int mlen = strlen(mname); + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) _ASN_ENCODE_FAILED; + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + er.encoded = 0; + + if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel); + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + 1, flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + + _ASN_CALLBACK3("", 1); + + er.encoded += 5 + (2 * mlen) + tmper.encoded; + } + + if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel - 1); + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +asn_dec_rval_t +CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_dec_rval_t rv; + asn_per_constraint_t *ct; + asn_TYPE_member_t *elm; /* CHOICE's element */ + void *memb_ptr; + void **memb_ptr2; + void *st = *sptr; + int value; + + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + _ASN_DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; + } + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + value = per_get_few_bits(pd, 1); + if(value < 0) _ASN_DECODE_STARVED; + if(value) ct = 0; /* Not restricted */ + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + ASN_DEBUG("CHOICE %s got index %d in range %d", + td->name, value, ct->range_bits); + if(value > ct->upper_bound) + _ASN_DECODE_FAILED; + } else { + if(specs->ext_start == -1) + _ASN_DECODE_FAILED; + value = uper_get_nsnnwn(pd); + if(value < 0) _ASN_DECODE_STARVED; + value += specs->ext_start; + if(value >= td->elements_count) + _ASN_DECODE_FAILED; + ASN_DEBUG("NOT IMPLEMENTED YET"); + _ASN_DECODE_FAILED; + } + + /* Adjust if canonical order is different from natural order */ + if(specs->canonical_order) + value = specs->canonical_order[value]; + + /* Set presence to be able to free it later */ + _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); + + elm = &td->elements[value]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); + + rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + if(rv.code != RC_OK) + ASN_DEBUG("Failed to decode %s in %s (CHOICE)", + elm->name, td->name); + return rv; +} + +asn_enc_rval_t +CHOICE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE's element */ + asn_per_constraint_t *ct; + void *memb_ptr; + int present; + + if(!sptr) _ASN_ENCODE_FAILED; + + ASN_DEBUG("Encoding %s as CHOICE", td->name); + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ct = 0; + + present = _fetch_present_idx(sptr, + specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized properly, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present <= 0 || present > td->elements_count) + _ASN_ENCODE_FAILED; + else + present--; + + /* Adjust if canonical order is different from natural order */ + if(specs->canonical_order) + present = specs->canonical_order[present]; + + ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); + + if(ct && ct->range_bits >= 0) { + if(present < ct->lower_bound + || present > ct->upper_bound) { + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, 1, 1)) + _ASN_ENCODE_FAILED; + } else { + _ASN_ENCODE_FAILED; + } + ct = 0; + } + } + if(ct && ct->flags & APC_EXTENSIBLE) + if(per_put_few_bits(po, 0, 1)) + _ASN_ENCODE_FAILED; + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, present, ct->range_bits)) + _ASN_ENCODE_FAILED; + } else { + if(specs->ext_start == -1) + _ASN_ENCODE_FAILED; + if(uper_put_nsnnwn(po, present - specs->ext_start)) + _ASN_ENCODE_FAILED; + ASN_DEBUG("NOT IMPLEMENTED YET"); + _ASN_ENCODE_FAILED; + } + + elm = &td->elements[present]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) _ASN_ENCODE_FAILED; + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + } + + return elm->type->uper_encoder(elm->type, elm->per_constraints, + memb_ptr, po); +} + + +int +CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + + /* + * Print that element. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* Print member's name and stuff */ + if(0) { + if(cb(elm->name, strlen(elm->name), app_key) < 0 + || cb(": ", 2, app_key) < 0) + return -1; + } + + return elm->type->print_struct(elm->type, memb_ptr, ilevel, + cb, app_key); + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + if(!td || !ptr) + return; + + ASN_DEBUG("Freeing %s as CHOICE", td->name); + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); + + /* + * Free that element. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)ptr + elm->memb_offset); + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } else { + memb_ptr = (void *)((char *)ptr + elm->memb_offset); + ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); + } + } + + if(!contents_only) { + FREEMEM(ptr); + } +} + + +/* + * The following functions functions offer protection against -fshort-enums, + * compatible with little- and big-endian machines. + * If assertion is triggered, either disable -fshort-enums, or add an entry + * here with the ->pres_size of your target stracture. + * Unless the target structure is packed, the ".present" member + * is guaranteed to be aligned properly. ASN.1 compiler itself does not + * produce packed code. + */ +static int +_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) { + const void *present_ptr; + int present; + + present_ptr = ((const char *)struct_ptr) + pres_offset; + + switch(pres_size) { + case sizeof(int): present = *(const int *)present_ptr; break; + case sizeof(short): present = *(const short *)present_ptr; break; + case sizeof(char): present = *(const char *)present_ptr; break; + default: + /* ANSI C mandates enum to be equivalent to integer */ + assert(pres_size != sizeof(int)); + return 0; /* If not aborted, pass back safe value */ + } + + return present; +} + +static void +_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) { + void *present_ptr; + present_ptr = ((char *)struct_ptr) + pres_offset; + + switch(pres_size) { + case sizeof(int): *(int *)present_ptr = present; break; + case sizeof(short): *(short *)present_ptr = present; break; + case sizeof(char): *(char *)present_ptr = present; break; + default: + /* ANSI C mandates enum to be equivalent to integer */ + assert(pres_size != sizeof(int)); + } +} diff --git a/src/mms/iso_mms/asn1c/constr_CHOICE.h b/src/mms/iso_mms/asn1c/constr_CHOICE.h new file mode 100644 index 0000000..83404e6 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_CHOICE.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_CHOICE_H_ +#define _CONSTR_CHOICE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct asn_CHOICE_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_codec_ctx_t member */ + int pres_offset; /* Identifier of the present member */ + int pres_size; /* Size of the identifier (enum) */ + + /* + * Tags to members mapping table. + */ + asn_TYPE_tag2member_t *tag2el; + int tag2el_count; + + /* Canonical ordering of CHOICE elements, for PER */ + int *canonical_order; + + /* + * Extensions-related stuff. + */ + int ext_start; /* First member of extensions, or -1 */ +} asn_CHOICE_specifics_t; + +/* + * A set specialized functions dealing with the CHOICE type. + */ +asn_struct_free_f CHOICE_free; +asn_struct_print_f CHOICE_print; +asn_constr_check_f CHOICE_constraint; +ber_type_decoder_f CHOICE_decode_ber; +der_type_encoder_f CHOICE_encode_der; +xer_type_decoder_f CHOICE_decode_xer; +xer_type_encoder_f CHOICE_encode_xer; +per_type_decoder_f CHOICE_decode_uper; +per_type_encoder_f CHOICE_encode_uper; +asn_outmost_tag_f CHOICE_outmost_tag; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_CHOICE_H_ */ diff --git a/src/mms/iso_mms/asn1c/constr_SEQUENCE.c b/src/mms/iso_mms/asn1c/constr_SEQUENCE.c new file mode 100644 index 0000000..b769434 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_SEQUENCE.c @@ -0,0 +1,1251 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * Check whether we are inside the extensions group. + */ +#define IN_EXTENSION_GROUP(specs, memb_idx) \ + ( ((memb_idx) > (specs)->ext_after) \ + &&((memb_idx) < (specs)->ext_before)) + + +/* + * Tags are canonically sorted in the tag2element map. + */ +static int +_t2e_cmp(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) { + if(a->el_no > b->el_no) + return 1; + /* + * Important: we do not check + * for a->el_no <= b->el_no! + */ + return 0; + } else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + + +/* + * The decoder of the SEQUENCE type. + */ +asn_dec_rval_t +SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + int edx; /* SEQUENCE element's index */ + + ASN_DEBUG("Decoding %s as SEQUENCE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, 1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) + ctx->left += rval.consumed; /* ?Substracted below! */ + ADVANCE(rval.consumed); + + NEXT_PHASE(ctx); + + ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", + (long)ctx->left, (long)size); + + /* Fall through */ + case 1: + /* + * PHASE 1. + * From the place where we've left it previously, + * try to decode the next member from the list of + * this structure's elements. + * (ctx->step) stores the member being processed + * between invocations and the microphase {0,1} of parsing + * that member: + * step = ( * 2 + ). + */ + for(edx = (ctx->step >> 1); edx < td->elements_count; + edx++, ctx->step = (ctx->step & ~1) + 2) { + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + ssize_t tag_len; /* Length of TLV's T */ + int opt_edx_end; /* Next non-optional element */ + int use_bsearch; + int n; + + if(ctx->step & 1) + goto microphase2; + + /* + * MICROPHASE 1: Synchronize decoding. + */ + ASN_DEBUG("In %s SEQUENCE left %d, edx=%d flags=%d" + " opt=%d ec=%d", + td->name, (int)ctx->left, edx, + elements[edx].flags, elements[edx].optional, + td->elements_count); + + if(ctx->left == 0 /* No more stuff is expected */ + && ( + /* Explicit OPTIONAL specification reaches the end */ + (edx + elements[edx].optional + == td->elements_count) + || + /* All extensions are optional */ + (IN_EXTENSION_GROUP(specs, edx) + && specs->ext_before > td->elements_count) + ) + ) { + ASN_DEBUG("End of SEQUENCE %s", td->name); + /* + * Found the legitimate end of the structure. + */ + PHASE_OUT(ctx); + RETURN(RC_OK); + } + + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + ASN_DEBUG("Current tag in %s SEQUENCE for element %d " + "(%s) is %s encoded in %d bytes, of frame %ld", + td->name, edx, elements[edx].name, + ber_tlv_tag_string(tlv_tag), (int)tag_len, (long)LEFT); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + ASN_DEBUG("edx = %d, opt = %d, ec=%d", + edx, elements[edx].optional, + td->elements_count); + if((edx + elements[edx].optional + == td->elements_count) + || (IN_EXTENSION_GROUP(specs, edx) + && specs->ext_before + > td->elements_count)) { + /* + * Yeah, baby! Found the terminator + * of the indefinite length structure. + */ + /* + * Proceed to the canonical + * finalization function. + * No advancing is necessary. + */ + goto phase3; + } + } + } + + /* + * Find the next available type with this tag. + */ + use_bsearch = 0; + opt_edx_end = edx + elements[edx].optional + 1; + if(opt_edx_end > td->elements_count) + opt_edx_end = td->elements_count; /* Cap */ + else if(opt_edx_end - edx > 8) { + /* Limit the scope of linear search... */ + opt_edx_end = edx + 8; + use_bsearch = 1; + /* ... and resort to bsearch() */ + } + for(n = edx; n < opt_edx_end; n++) { + if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { + /* + * Found element corresponding to the tag + * being looked at. + * Reposition over the right element. + */ + edx = n; + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].flags & ATF_OPEN_TYPE) { + /* + * This is the ANY type, which may bear + * any flag whatsoever. + */ + edx = n; + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].tag == (ber_tlv_tag_t)-1) { + use_bsearch = 1; + break; + } + } + if(use_bsearch) { + /* + * Resort to a binary search over + * sorted array of tags. + */ + asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key; + key.el_tag = tlv_tag; + key.el_no = edx; + t2m = (asn_TYPE_tag2member_t *)bsearch(&key, + specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _t2e_cmp); + if(t2m) { + asn_TYPE_tag2member_t *best = 0; + asn_TYPE_tag2member_t *t2m_f, *t2m_l; + int edx_max = edx + elements[edx].optional; + /* + * Rewind to the first element with that tag, + * `cause bsearch() does not guarantee order. + */ + t2m_f = t2m + t2m->toff_first; + t2m_l = t2m + t2m->toff_last; + for(t2m = t2m_f; t2m <= t2m_l; t2m++) { + if(t2m->el_no > edx_max) break; + if(t2m->el_no < edx) continue; + best = t2m; + } + if(best) { + edx = best->el_no; + ctx->step = 1 + 2 * edx; + goto microphase2; + } + } + n = opt_edx_end; + } + if(n == opt_edx_end) { + /* + * If tag is unknown, it may be either + * an unknown (thus, incorrect) tag, + * or an extension (...), + * or an end of the indefinite-length structure. + */ + if(!IN_EXTENSION_GROUP(specs, edx)) { + ASN_DEBUG("Unexpected tag %s (at %d)", + ber_tlv_tag_string(tlv_tag), edx); + ASN_DEBUG("Expected tag %s (%s)%s", + ber_tlv_tag_string(elements[edx].tag), + elements[edx].name, + elements[edx].optional + ?" or alternatives":""); + RETURN(RC_FAIL); + } else { + /* Skip this tag */ + ssize_t skip; + + skip = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tag_len, + LEFT - tag_len); + ASN_DEBUG("Skip length %d in %s", + (int)skip, td->name); + switch(skip) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(skip + tag_len); + ctx->step -= 2; + edx--; + continue; /* Try again with the next tag */ + } + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2: + ASN_DEBUG("Inside SEQUENCE %s MF2", td->name); + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elements[edx].flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elements[edx].memb_offset; + memb_ptr2 = &memb_ptr; + } + /* + * Invoke the member fetch routine according to member's type + */ + rval = elements[edx].type->ber_decoder(opt_codec_ctx, + elements[edx].type, + memb_ptr2, ptr, LEFT, + elements[edx].tag_mode); + ASN_DEBUG("In %s SEQUENCE decoded %d %s of %d " + "in %d bytes rval.code %d, size=%d", + td->name, edx, elements[edx].type->name, + (int)LEFT, (int)rval.consumed, rval.code, (int)size); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + ASN_DEBUG("Size violation (c->l=%ld <= s=%ld)", + (long)ctx->left, (long)size); + /* Fall through */ + case RC_FAIL: /* Fatal error */ + RETURN(RC_FAIL); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } /* for(all structure members) */ + + phase3: + ctx->phase = 3; + case 3: /* 00 and other tags expected */ + case 4: /* only 00's expected */ + + ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld", + td->name, (long)ctx->left, (long)size); + + /* + * Skip everything until the end of the SEQUENCE. + */ + while(ctx->left) { + ssize_t tl, ll; + + tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tl) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + /* + * If expected <0><0>... + */ + if(ctx->left < 0 + && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + ctx->phase = 4; + continue; + } + } + + if(!IN_EXTENSION_GROUP(specs, td->elements_count) + || ctx->phase == 4) { + ASN_DEBUG("Unexpected continuation " + "of a non-extensible type " + "%s (SEQUENCE): %s", + td->name, + ber_tlv_tag_string(tlv_tag)); + RETURN(RC_FAIL); + } + + ll = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tl, LEFT - tl); + switch(ll) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(tl + ll); + } + + PHASE_OUT(ctx); + } + + RETURN(RC_OK); +} + + +/* + * The DER encoder of the SEQUENCE type. + */ +asn_enc_rval_t +SEQUENCE_encode_der(asn_TYPE_descriptor_t *td, + void *sptr, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + size_t computed_size = 0; + asn_enc_rval_t erval; + ssize_t ret; + int edx; + + ASN_DEBUG("%s %s as SEQUENCE", + cb?"Encoding":"Estimating", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) continue; + /* Mandatory element is missing */ + _ASN_ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + erval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, + 0, 0); + if(erval.encoded == -1) + return erval; + computed_size += erval.encoded; + ASN_DEBUG("Member %d %s estimated %ld bytes", + edx, elm->name, (long)erval.encoded); + } + + /* + * Encode the TLV for the sequence itself. + */ + ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); + ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size); + if(ret == -1) + _ASN_ENCODE_FAILED; + erval.encoded = computed_size + ret; + + if(!cb) _ASN_ENCODED_OK(erval); + + /* + * Encode all members. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + asn_enc_rval_t tmperval; + void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) continue; + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + tmperval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, + cb, app_key); + if(tmperval.encoded == -1) + return tmperval; + computed_size -= tmperval.encoded; + ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %ld bytes", + edx, elm->name, td->name, (long)tmperval.encoded); + } + + if(computed_size != 0) + /* + * Encoded size is not equal to the computed size. + */ + _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(erval); +} + + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = ((const char *)buf_ptr) + num;\ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * ... and parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value from a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + int edx; /* Element index */ + int edx_end; + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + * Phase 3: Skipping unknown extensions. + * Phase 4: PHASED OUT + */ + for(edx = ctx->step; ctx->phase <= 3;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + asn_TYPE_member_t *elm; + int n; + + /* + * Go inside the inner member of a sequence. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &td->elements[edx]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Invoke the inner type decoder, m.b. multiple times */ + tmprval = elm->type->xer_decoder(opt_codec_ctx, + elm->type, memb_ptr2, elm->name, + buf_ptr, size); + XER_ADVANCE(tmprval.consumed); + if(tmprval.code != RC_OK) + RETURN(tmprval.code); + ctx->phase = 1; /* Back to body processing */ + ctx->step = ++edx; + ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d", + ctx->phase, ctx->step); + /* Fall through */ + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, + &ch_type); + switch(ch_size) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + default: + switch(ch_type) { + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]", + tcv, ctx->phase, xml_tag); + + /* Skip the extensions section */ + if(ctx->phase == 3) { + switch(xer_skip_unknown(tcv, &ctx->left)) { + case -1: + ctx->phase = 4; + RETURN(RC_FAIL); + case 0: + XER_ADVANCE(ch_size); + continue; + case 1: + XER_ADVANCE(ch_size); + ctx->phase = 1; + continue; + case 2: + ctx->phase = 1; + break; + } + } + + switch(tcv) { + case XCT_CLOSING: + if(ctx->phase == 0) break; + ctx->phase = 0; + /* Fall through */ + case XCT_BOTH: + if(ctx->phase == 0) { + if(edx >= td->elements_count + || + /* Explicit OPTIONAL specs reaches the end */ + (edx + elements[edx].optional + == td->elements_count) + || + /* All extensions are optional */ + (IN_EXTENSION_GROUP(specs, edx) + && specs->ext_before + > td->elements_count) + ) { + XER_ADVANCE(ch_size); + ctx->phase = 4; /* Phase out */ + RETURN(RC_OK); + } else { + ASN_DEBUG("Premature end of XER SEQUENCE"); + RETURN(RC_FAIL); + } + } + /* Fall through */ + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%d", + tcv, ctx->phase, edx); + if(ctx->phase != 1) { + break; /* Really unexpected */ + } + + if(edx < td->elements_count) { + /* + * Search which member corresponds to this tag. + */ + edx_end = edx + elements[edx].optional + 1; + if(edx_end > td->elements_count) + edx_end = td->elements_count; + for(n = edx; n < edx_end; n++) { + elm = &td->elements[n]; + tcv = xer_check_tag(buf_ptr, + ch_size, elm->name); + switch(tcv) { + case XCT_BOTH: + case XCT_OPENING: + /* + * Process this member. + */ + ctx->step = edx = n; + ctx->phase = 2; + break; + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + continue; + default: + n = edx_end; + break; /* Phase out */ + } + break; + } + if(n != edx_end) + continue; + } else { + ASN_DEBUG("Out of defined members: %d/%d", + edx, td->elements_count); + } + + /* It is expected extension */ + if(IN_EXTENSION_GROUP(specs, + edx + (edx < td->elements_count + ? elements[edx].optional : 0))) { + ASN_DEBUG("Got anticipated extension at %d", + edx); + /* + * Check for (XCT_BOTH or XCT_UNKNOWN_BO) + * By using a mask. Only record a pure + * tags. + */ + if(tcv & XCT_CLOSING) { + /* Found without body */ + } else { + ctx->left = 1; + ctx->phase = 3; /* Skip ...'s */ + } + XER_ADVANCE(ch_size); + continue; + } + + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]", + size>0?((const char *)buf_ptr)[0]:'.', + size>1?((const char *)buf_ptr)[1]:'.', + size>2?((const char *)buf_ptr)[2]:'.', + size>3?((const char *)buf_ptr)[3]:'.', + size>4?((const char *)buf_ptr)[4]:'.', + size>5?((const char *)buf_ptr)[5]:'.'); + break; + } + + ctx->phase = 4; /* "Phase out" on hard failure */ + RETURN(RC_FAIL); +} + +asn_enc_rval_t +SEQUENCE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + int xcan = (flags & XER_F_CANONICAL); + int edx; + + if(!sptr) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_enc_rval_t tmper; + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + const char *mname = elm->name; + unsigned int mlen = strlen(mname); + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + continue; + /* Mandatory element is missing */ + _ASN_ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + + /* Print the member itself */ + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + 1, flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + + _ASN_CALLBACK3("", 1); + er.encoded += 5 + (2 * mlen) + tmper.encoded; + } + + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +int +SEQUENCE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + int edx; + int ret; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* Dump preamble */ + if(cb(td->name, strlen(td->name), app_key) < 0 + || cb(" ::= {", 6, app_key) < 0) + return -1; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) continue; + /* Print line */ + /* Fall through */ + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* Indentation */ + _i_INDENT(1); + + /* Print the member's name and stuff */ + if(cb(elm->name, strlen(elm->name), app_key) < 0 + || cb(": ", 2, app_key) < 0) + return -1; + + /* Print the member itself */ + ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 1, + cb, app_key); + if(ret) return ret; + } + + ilevel--; + _i_INDENT(1); + + return (cb("}", 1, app_key) < 0) ? -1 : 0; +} + +void +SEQUENCE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { + int edx; + + if(!td || !sptr) + return; + + ASN_DEBUG("Freeing %s as SEQUENCE", td->name); + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); + } + } + + if(!contents_only) { + FREEMEM(sptr); + } +} + +int +SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + int edx; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + /* + * Iterate over structure members and check their validity. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + continue; + _ASN_CTFAIL(app_key, td, + "%s: mandatory element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(elm->memb_constraints) { + int ret = elm->memb_constraints(elm->type, memb_ptr, + ctfailcb, app_key); + if(ret) return ret; + } else { + int ret = elm->type->check_constraints(elm->type, + memb_ptr, ctfailcb, app_key); + if(ret) return ret; + /* + * Cannot inherit it earlier: + * need to make sure we get the updated version. + */ + elm->memb_constraints = elm->type->check_constraints; + } + } + + return 0; +} + +asn_dec_rval_t +SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; + void *st = *sptr; /* Target structure. */ + int extpresent = 0; /* Extension additions are present */ + uint8_t *opres; /* Presence of optional root members */ + asn_per_data_t opmd; + asn_dec_rval_t rv; + int edx; + + (void)constraints; + + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + _ASN_DECODE_FAILED; + + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); + + /* Handle extensions */ + if(specs->ext_before >= 0) { + extpresent = per_get_few_bits(pd, 1); + if(extpresent < 0) _ASN_DECODE_STARVED; + } + + /* Prepare a place and read-in the presence bitmap */ + if(specs->roms_count) { + opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); + if(!opres) _ASN_DECODE_FAILED; + /* Get the presence map */ + if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { + FREEMEM(opres); + _ASN_DECODE_STARVED; + } + opmd.buffer = opres; + opmd.nboff = 0; + opmd.nbits = specs->roms_count; + ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", + td->name, specs->roms_count, *opres); + } else { + opres = 0; + memset(&opmd, 0, sizeof opmd); + } + + /* + * Get the sequence ROOT elements. + */ + for(edx = 0; edx < ((specs->ext_before < 0) + ? td->elements_count : specs->ext_before + 1); edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Deal with optionality */ + if(elm->optional) { + int present = per_get_few_bits(&opmd, 1); + ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", + td->name, elm->name, present, + (int)opmd.nboff, (int)opmd.nbits); + if(present == 0) { + /* This element is not present */ + if(elm->default_value) { + /* Fill-in DEFAULT */ + if(elm->default_value(1, memb_ptr2)) { + FREEMEM(opres); + _ASN_DECODE_FAILED; + } + } + /* The member is just not present */ + continue; + } + /* Fall through */ + } + + /* Fetch the member from the stream */ + ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); + rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + if(rv.code != RC_OK) { + ASN_DEBUG("Failed decode %s in %s", + elm->name, td->name); + FREEMEM(opres); + return rv; + } + } + + /* + * Deal with extensions. + */ + if(extpresent) { + ASN_DEBUG("Extensibility for %s: NOT IMPLEMENTED", td->name); + _ASN_DECODE_FAILED; + } else { + for(edx = specs->roms_count; edx < specs->roms_count + + specs->aoms_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + if(!elm->default_value) continue; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Set default value */ + if(elm->default_value(1, memb_ptr2)) { + FREEMEM(opres); + _ASN_DECODE_FAILED; + } + } + } + + rv.consumed = 0; + rv.code = RC_OK; + FREEMEM(opres); + return rv; +} + +asn_enc_rval_t +SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_enc_rval_t er; + int edx; + int i; + + (void)constraints; + + if(!sptr) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); + if(specs->ext_before >= 0) + _ASN_ENCODE_FAILED; /* We don't encode extensions yet */ + + /* Encode a presence bitmap */ + for(i = 0; i < specs->roms_count; i++) { + asn_TYPE_member_t *elm; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + edx = specs->oms[i]; + elm = &td->elements[edx]; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + present = (*memb_ptr2 != 0); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + present = 1; + } + + /* Eliminate default values */ + if(present && elm->default_value + && elm->default_value(0, memb_ptr2) == 1) + present = 0; + + ASN_DEBUG("Element %s %s %s->%s is %s", + elm->flags & ATF_POINTER ? "ptr" : "inline", + elm->default_value ? "def" : "wtv", + td->name, elm->name, present ? "present" : "absent"); + if(per_put_few_bits(po, present, 1)) + _ASN_ENCODE_FAILED; + } + + /* + * Get the sequence ROOT elements. + */ + for(edx = 0; edx < ((specs->ext_before < 0) + ? td->elements_count : specs->ext_before + 1); edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + if(!*memb_ptr2) { + ASN_DEBUG("Element %s %d not present", + elm->name, edx); + if(elm->optional) + continue; + /* Mandatory element is missing */ + _ASN_ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + /* Eliminate default values */ + if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) + continue; + + er = elm->type->uper_encoder(elm->type, elm->per_constraints, + *memb_ptr2, po); + if(er.encoded == -1) + return er; + } + + _ASN_ENCODED_OK(er); +} + diff --git a/src/mms/iso_mms/asn1c/constr_SEQUENCE.h b/src/mms/iso_mms/asn1c/constr_SEQUENCE.h new file mode 100644 index 0000000..5f589d5 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_SEQUENCE.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_SEQUENCE_H_ +#define _CONSTR_SEQUENCE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct asn_SEQUENCE_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + /* + * Tags to members mapping table (sorted). + */ + asn_TYPE_tag2member_t *tag2el; + int tag2el_count; + + /* + * Optional members of the extensions root (roms) or additions (aoms). + * Meaningful for PER. + */ + int *oms; /* Optional MemberS */ + int roms_count; /* Root optional members count */ + int aoms_count; /* Additions optional members count */ + + /* + * Description of an extensions group. + */ + int ext_after; /* Extensions start after this member */ + int ext_before; /* Extensions stop before this member */ +} asn_SEQUENCE_specifics_t; + + +/* + * A set specialized functions dealing with the SEQUENCE type. + */ +asn_struct_free_f SEQUENCE_free; +asn_struct_print_f SEQUENCE_print; +asn_constr_check_f SEQUENCE_constraint; +ber_type_decoder_f SEQUENCE_decode_ber; +der_type_encoder_f SEQUENCE_encode_der; +xer_type_decoder_f SEQUENCE_decode_xer; +xer_type_encoder_f SEQUENCE_encode_xer; +per_type_decoder_f SEQUENCE_decode_uper; +per_type_encoder_f SEQUENCE_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_SEQUENCE_H_ */ diff --git a/src/mms/iso_mms/asn1c/constr_SEQUENCE_OF.c b/src/mms/iso_mms/asn1c/constr_SEQUENCE_OF.c new file mode 100644 index 0000000..aa10117 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_SEQUENCE_OF.c @@ -0,0 +1,208 @@ +/*- + * Copyright (c) 2003, 2004, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * The DER encoder of the SEQUENCE OF type. + */ +asn_enc_rval_t +SEQUENCE_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_sequence_ *list = _A_SEQUENCE_FROM_VOID(ptr); + size_t computed_size = 0; + ssize_t encoding_size = 0; + asn_enc_rval_t erval; + int edx; + + ASN_DEBUG("Estimating size of SEQUENCE OF %s", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + if(!memb_ptr) continue; + erval = elm->type->der_encoder(elm->type, memb_ptr, + 0, elm->tag, + 0, 0); + if(erval.encoded == -1) + return erval; + computed_size += erval.encoded; + } + + /* + * Encode the TLV for the sequence itself. + */ + encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, + cb, app_key); + if(encoding_size == -1) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + + computed_size += encoding_size; + if(!cb) { + erval.encoded = computed_size; + _ASN_ENCODED_OK(erval); + } + + ASN_DEBUG("Encoding members of SEQUENCE OF %s", td->name); + + /* + * Encode all members. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + if(!memb_ptr) continue; + erval = elm->type->der_encoder(elm->type, memb_ptr, + 0, elm->tag, + cb, app_key); + if(erval.encoded == -1) + return erval; + encoding_size += erval.encoded; + } + + if(computed_size != (size_t)encoding_size) { + /* + * Encoded size is not equal to the computed size. + */ + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + } else { + erval.encoded = computed_size; + erval.structure_ptr = 0; + erval.failed_type = 0; + } + + return erval; +} + +asn_enc_rval_t +SEQUENCE_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_sequence_ *list = _A_SEQUENCE_FROM_VOID(sptr); + const char *mname = specs->as_XMLValueList + ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); + unsigned int mlen = mname ? strlen(mname) : 0; + int xcan = (flags & XER_F_CANONICAL); + int i; + + if(!sptr) _ASN_ENCODE_FAILED; + + er.encoded = 0; + + for(i = 0; i < list->count; i++) { + asn_enc_rval_t tmper; + void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + if(mname) { + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + } + + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + 1, flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + if(tmper.encoded == 0 && specs->as_XMLValueList) { + const char *name = elm->type->xml_tag; + size_t len = strlen(name); + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel + 1); + _ASN_CALLBACK3("<", 1, name, len, "/>", 2); + } + + if(mname) { + _ASN_CALLBACK3("", 1); + er.encoded += 5; + } + + er.encoded += (2 * mlen) + tmper.encoded; + } + + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +asn_enc_rval_t +SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_anonymous_sequence_ *list; + asn_per_constraint_t *ct; + asn_enc_rval_t er; + asn_TYPE_member_t *elm = td->elements; + int seq; + + if(!sptr) _ASN_ENCODE_FAILED; + list = _A_SEQUENCE_FROM_VOID(sptr); + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count); + + if(constraints) ct = &constraints->size; + else if(td->per_constraints) ct = &td->per_constraints->size; + else ct = 0; + + /* If extensible constraint, check if size is in root */ + if(ct) { + int not_in_root = (list->count < ct->lower_bound + || list->count > ct->upper_bound); + ASN_DEBUG("lb %ld ub %ld %s", + ct->lower_bound, ct->upper_bound, + ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); + if(ct->flags & APC_EXTENSIBLE) { + /* Declare whether size is in extension root */ + if(per_put_few_bits(po, not_in_root, 1)) + _ASN_ENCODE_FAILED; + if(not_in_root) ct = 0; + } else if(not_in_root && ct->effective_bits >= 0) + _ASN_ENCODE_FAILED; + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + if(per_put_few_bits(po, list->count - ct->lower_bound, + ct->effective_bits)) + _ASN_ENCODE_FAILED; + } + + for(seq = -1; seq < list->count;) { + ssize_t mayEncode; + if(seq < 0) seq = 0; + if(ct && ct->effective_bits >= 0) { + mayEncode = list->count; + } else { + mayEncode = uper_put_length(po, list->count - seq); + if(mayEncode < 0) _ASN_ENCODE_FAILED; + } + + while(mayEncode--) { + void *memb_ptr = list->array[seq++]; + if(!memb_ptr) _ASN_ENCODE_FAILED; + er = elm->type->uper_encoder(elm->type, + elm->per_constraints, memb_ptr, po); + if(er.encoded == -1) + _ASN_ENCODE_FAILED; + } + } + + _ASN_ENCODED_OK(er); +} + diff --git a/src/mms/iso_mms/asn1c/constr_SEQUENCE_OF.h b/src/mms/iso_mms/asn1c/constr_SEQUENCE_OF.h new file mode 100644 index 0000000..e2272f3 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_SEQUENCE_OF.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_SEQUENCE_OF_H_ +#define _CONSTR_SEQUENCE_OF_H_ + +#include +#include /* Implemented using SET OF */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A set specialized functions dealing with the SEQUENCE OF type. + * Generally implemented using SET OF. + */ +#define SEQUENCE_OF_free SET_OF_free +#define SEQUENCE_OF_print SET_OF_print +#define SEQUENCE_OF_constraint SET_OF_constraint +#define SEQUENCE_OF_decode_ber SET_OF_decode_ber +#define SEQUENCE_OF_decode_xer SET_OF_decode_xer +#define SEQUENCE_OF_decode_uper SET_OF_decode_uper +der_type_encoder_f SEQUENCE_OF_encode_der; +xer_type_encoder_f SEQUENCE_OF_encode_xer; +per_type_encoder_f SEQUENCE_OF_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/mms/iso_mms/asn1c/constr_SET_OF.c b/src/mms/iso_mms/asn1c/constr_SET_OF.c new file mode 100644 index 0000000..c4928e2 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_SET_OF.c @@ -0,0 +1,939 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * The decoder of the SET OF type. + */ +asn_dec_rval_t +SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; /* Single one */ + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + ASN_DEBUG("Decoding %s as SET OF", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, 1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) + ctx->left += rval.consumed; /* ?Substracted below! */ + ADVANCE(rval.consumed); + + ASN_DEBUG("Structure consumes %ld bytes, " + "buffer %ld", (long)ctx->left, (long)size); + + NEXT_PHASE(ctx); + /* Fall through */ + case 1: + /* + * PHASE 1. + * From the place where we've left it previously, + * try to decode the next item. + */ + for(;; ctx->step = 0) { + ssize_t tag_len; /* Length of TLV's T */ + + if(ctx->step & 1) + goto microphase2; + + /* + * MICROPHASE 1: Synchronize decoding. + */ + + if(ctx->left == 0) { + ASN_DEBUG("End of SET OF %s", td->name); + /* + * No more things to decode. + * Exit out of here. + */ + PHASE_OUT(ctx); + RETURN(RC_OK); + } + + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Found the terminator of the + * indefinite length structure. + */ + break; + } + } + + /* Outmost tag may be unknown and cannot be fetched/compared */ + if(elm->tag != (ber_tlv_tag_t)-1) { + if(BER_TAGS_EQUAL(tlv_tag, elm->tag)) { + /* + * The new list member of expected type has arrived. + */ + } else { + ASN_DEBUG("Unexpected tag %s fixed SET OF %s", + ber_tlv_tag_string(tlv_tag), td->name); + ASN_DEBUG("%s SET OF has tag %s", + td->name, ber_tlv_tag_string(elm->tag)); + RETURN(RC_FAIL); + } + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2: + + /* + * Invoke the member fetch routine according to member's type + */ + rval = elm->type->ber_decoder(opt_codec_ctx, + elm->type, &ctx->ptr, ptr, LEFT, 0); + ASN_DEBUG("In %s SET OF %s code %d consumed %d", + td->name, elm->type->name, + rval.code, (int)rval.consumed); + switch(rval.code) { + case RC_OK: + { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + if(ASN_SET_ADD(list, ctx->ptr) != 0) + RETURN(RC_FAIL); + else + ctx->ptr = 0; + } + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + /* Fall through */ + case RC_FAIL: /* Fatal error */ + RETURN(RC_FAIL); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } /* for(all list members) */ + + NEXT_PHASE(ctx); + case 2: + /* + * Read in all "end of content" TLVs. + */ + while(ctx->left < 0) { + if(LEFT < 2) { + if(LEFT > 0 && ((const char *)ptr)[0] != 0) { + /* Unexpected tag */ + RETURN(RC_FAIL); + } else { + RETURN(RC_WMORE); + } + } + if(((const char *)ptr)[0] == 0 + && ((const char *)ptr)[1] == 0) { + ADVANCE(2); + ctx->left++; + } else { + RETURN(RC_FAIL); + } + } + + PHASE_OUT(ctx); + } + + RETURN(RC_OK); +} + +/* + * Internally visible buffer holding a single encoded element. + */ +struct _el_buffer { + uint8_t *buf; + size_t length; + size_t size; +}; +/* Append bytes to the above structure */ +static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) { + struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; + + if(el_buf->length + size > el_buf->size) + return -1; + + memcpy(el_buf->buf + el_buf->length, buffer, size); + + el_buf->length += size; + return 0; +} +static int _el_buf_cmp(const void *ap, const void *bp) { + const struct _el_buffer *a = (const struct _el_buffer *)ap; + const struct _el_buffer *b = (const struct _el_buffer *)bp; + int ret; + size_t common_len; + + if(a->length < b->length) + common_len = a->length; + else + common_len = b->length; + + ret = memcmp(a->buf, b->buf, common_len); + if(ret == 0) { + if(a->length < b->length) + ret = -1; + else if(a->length > b->length) + ret = 1; + } + + return ret; +} + +/* + * The DER encoder of the SET OF type. + */ +asn_enc_rval_t +SET_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + asn_TYPE_descriptor_t *elm_type = elm->type; + der_type_encoder_f *der_encoder = elm_type->der_encoder; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); + size_t computed_size = 0; + ssize_t encoding_size = 0; + struct _el_buffer *encoded_els; + ssize_t eels_count = 0; + size_t max_encoded_len = 1; + asn_enc_rval_t erval; + int ret; + int edx; + + ASN_DEBUG("Estimating size for SET OF %s", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + if(!memb_ptr) continue; + erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, 0, 0); + if(erval.encoded == -1) + return erval; + computed_size += erval.encoded; + + /* Compute maximum encoding's size */ + if(max_encoded_len < (size_t)erval.encoded) + max_encoded_len = erval.encoded; + } + + /* + * Encode the TLV for the sequence itself. + */ + encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, + cb, app_key); + if(encoding_size == -1) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + computed_size += encoding_size; + + if(!cb || list->count == 0) { + erval.encoded = computed_size; + _ASN_ENCODED_OK(erval); + } + + /* + * DER mandates dynamic sorting of the SET OF elements + * according to their encodings. Build an array of the + * encoded elements. + */ + encoded_els = (struct _el_buffer *)MALLOC( + list->count * sizeof(encoded_els[0])); + if(encoded_els == NULL) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + + ASN_DEBUG("Encoding members of %s SET OF", td->name); + + /* + * Encode all members. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + struct _el_buffer *encoded_el = &encoded_els[eels_count]; + + if(!memb_ptr) continue; + + /* + * Prepare space for encoding. + */ + encoded_el->buf = (uint8_t *)MALLOC(max_encoded_len); + if(encoded_el->buf) { + encoded_el->length = 0; + encoded_el->size = max_encoded_len; + } else { + for(edx--; edx >= 0; edx--) + FREEMEM(encoded_els[edx].buf); + FREEMEM(encoded_els); + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + + /* + * Encode the member into the prepared space. + */ + erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, + _el_addbytes, encoded_el); + if(erval.encoded == -1) { + for(; edx >= 0; edx--) + FREEMEM(encoded_els[edx].buf); + FREEMEM(encoded_els); + return erval; + } + encoding_size += erval.encoded; + eels_count++; + } + + /* + * Sort the encoded elements according to their encoding. + */ + qsort(encoded_els, eels_count, sizeof(encoded_els[0]), _el_buf_cmp); + + /* + * Report encoded elements to the application. + * Dispose of temporary sorted members table. + */ + ret = 0; + for(edx = 0; edx < eels_count; edx++) { + struct _el_buffer *encoded_el = &encoded_els[edx]; + /* Report encoded chunks to the application */ + if(ret == 0 + && cb(encoded_el->buf, encoded_el->length, app_key) < 0) + ret = -1; + FREEMEM(encoded_el->buf); + } + FREEMEM(encoded_els); + + if(ret || computed_size != (size_t)encoding_size) { + /* + * Standard callback failed, or + * encoded size is not equal to the computed size. + */ + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + } else { + erval.encoded = computed_size; + } + + _ASN_ENCODED_OK(erval); +} + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = ((const char *)buf_ptr) + num;\ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *element = td->elements; + const char *elm_tag; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * ... and parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value from a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* Which tag is expected for the downstream */ + if(specs->as_XMLValueList) { + elm_tag = (specs->as_XMLValueList == 1) ? 0 : ""; + } else { + elm_tag = (*element->name) + ? element->name : element->type->xml_tag; + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + */ + for(; ctx->phase <= 2;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + + /* + * Go inside the inner member of a set. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + + /* Invoke the inner type decoder, m.b. multiple times */ + ASN_DEBUG("XER/SET OF element [%s]", elm_tag); + tmprval = element->type->xer_decoder(opt_codec_ctx, + element->type, &ctx->ptr, elm_tag, + buf_ptr, size); + if(tmprval.code == RC_OK) { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + if(ASN_SET_ADD(list, ctx->ptr) != 0) + RETURN(RC_FAIL); + ctx->ptr = 0; + XER_ADVANCE(tmprval.consumed); + } else { + XER_ADVANCE(tmprval.consumed); + RETURN(tmprval.code); + } + ctx->phase = 1; /* Back to body processing */ + ASN_DEBUG("XER/SET OF phase => %d", ctx->phase); + /* Fall through */ + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, + buf_ptr, size, &ch_type); + switch(ch_size) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + default: + switch(ch_type) { + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s", + tcv, ctx->phase, xml_tag); + switch(tcv) { + case XCT_CLOSING: + if(ctx->phase == 0) break; + ctx->phase = 0; + /* Fall through */ + case XCT_BOTH: + if(ctx->phase == 0) { + /* No more things to decode */ + XER_ADVANCE(ch_size); + ctx->phase = 3; /* Phase out */ + RETURN(RC_OK); + } + /* Fall through */ + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase); + if(ctx->phase == 1) { + /* + * Process a single possible member. + */ + ctx->phase = 2; + continue; + } + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag in SET OF"); + break; + } + + ctx->phase = 3; /* "Phase out" on hard failure */ + RETURN(RC_FAIL); +} + + + +typedef struct xer_tmp_enc_s { + void *buffer; + size_t offset; + size_t size; +} xer_tmp_enc_t; +static int +SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) { + xer_tmp_enc_t *t = (xer_tmp_enc_t *)key; + if(t->offset + size >= t->size) { + size_t newsize = (t->size << 2) + size; + void *p = REALLOC(t->buffer, newsize); + if(!p) return -1; + t->buffer = p; + t->size = newsize; + } + memcpy((char *)t->buffer + t->offset, buffer, size); + t->offset += size; + return 0; +} +static int +SET_OF_xer_order(const void *aptr, const void *bptr) { + const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr; + const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr; + size_t minlen = a->offset; + int ret; + if(b->offset < minlen) minlen = b->offset; + /* Well-formed UTF-8 has this nice lexicographical property... */ + ret = memcmp(a->buffer, b->buffer, minlen); + if(ret != 0) return ret; + if(a->offset == b->offset) + return 0; + if(a->offset == minlen) + return -1; + return 1; +} + + +asn_enc_rval_t +SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(sptr); + const char *mname = specs->as_XMLValueList + ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); + size_t mlen = mname ? strlen(mname) : 0; + int xcan = (flags & XER_F_CANONICAL); + xer_tmp_enc_t *encs = 0; + size_t encs_count = 0; + void *original_app_key = app_key; + asn_app_consume_bytes_f *original_cb = cb; + int i; + + if(!sptr) _ASN_ENCODE_FAILED; + + if(xcan) { + encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0])); + if(!encs) _ASN_ENCODE_FAILED; + cb = SET_OF_encode_xer_callback; + } + + er.encoded = 0; + + for(i = 0; i < list->count; i++) { + asn_enc_rval_t tmper; + + void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + if(encs) { + memset(&encs[encs_count], 0, sizeof(encs[0])); + app_key = &encs[encs_count]; + encs_count++; + } + + if(mname) { + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + } + + if(!xcan && specs->as_XMLValueList == 1) + _i_ASN_TEXT_INDENT(1, ilevel + 1); + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + (specs->as_XMLValueList != 2), + flags, cb, app_key); + if(tmper.encoded == -1) { + td = tmper.failed_type; + sptr = tmper.structure_ptr; + goto cb_failed; + } + if(tmper.encoded == 0 && specs->as_XMLValueList) { + const char *name = elm->type->xml_tag; + size_t len = strlen(name); + _ASN_CALLBACK3("<", 1, name, len, "/>", 2); + } + + if(mname) { + _ASN_CALLBACK3("", 1); + er.encoded += 5; + } + + er.encoded += (2 * mlen) + tmper.encoded; + } + + if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); + + if(encs) { + xer_tmp_enc_t *enc = encs; + xer_tmp_enc_t *end = encs + encs_count; + ssize_t control_size = 0; + + cb = original_cb; + app_key = original_app_key; + qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order); + + for(; enc < end; enc++) { + _ASN_CALLBACK(enc->buffer, enc->offset); + FREEMEM(enc->buffer); + enc->buffer = 0; + control_size += enc->offset; + } + assert(control_size == er.encoded); + } + + goto cleanup; +cb_failed: + er.encoded = -1; + er.failed_type = td; + er.structure_ptr = sptr; +cleanup: + if(encs) { + while(encs_count-- > 0) { + if(encs[encs_count].buffer) + FREEMEM(encs[encs_count].buffer); + } + FREEMEM(encs); + } + _ASN_ENCODED_OK(er); +} + +int +SET_OF_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + int ret; + int i; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* Dump preamble */ + if(cb(td->name, strlen(td->name), app_key) < 0 + || cb(" ::= {", 6, app_key) < 0) + return -1; + + for(i = 0; i < list->count; i++) { + const void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + _i_INDENT(1); + + ret = elm->type->print_struct(elm->type, memb_ptr, + ilevel + 1, cb, app_key); + if(ret) return ret; + } + + ilevel--; + _i_INDENT(1); + + return (cb("}", 1, app_key) < 0) ? -1 : 0; +} + +void +SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + if(td && ptr) { + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); + int i; + + /* + * Could not use set_of_empty() because of (*free) + * incompatibility. + */ + for(i = 0; i < list->count; i++) { + void *memb_ptr = list->array[i]; + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } + list->count = 0; /* No meaningful elements left */ + + asn_set_empty(list); /* Remove (list->array) */ + + if(!contents_only) { + FREEMEM(ptr); + } + } +} + +int +SET_OF_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + asn_constr_check_f *constr; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + int i; + + if(!sptr) { + _ASN_CTFAIL(app_key, td, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + constr = elm->memb_constraints; + if(!constr) constr = elm->type->check_constraints; + + /* + * Iterate over the members of an array. + * Validate each in turn, until one fails. + */ + for(i = 0; i < list->count; i++) { + const void *memb_ptr = list->array[i]; + int ret; + + if(!memb_ptr) continue; + + ret = constr(elm->type, memb_ptr, ctfailcb, app_key); + if(ret) return ret; + } + + /* + * Cannot inherit it eralier: + * need to make sure we get the updated version. + */ + if(!elm->memb_constraints) + elm->memb_constraints = elm->type->check_constraints; + + return 0; +} + +asn_dec_rval_t +SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; /* Single one */ + void *st = *sptr; + asn_anonymous_set_ *list; + asn_per_constraint_t *ct; + int repeat = 0; + ssize_t nelems; + + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + _ASN_DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; + } + list = _A_SET_FROM_VOID(st); + + /* Figure out which constraints to use */ + if(constraints) ct = &constraints->size; + else if(td->per_constraints) ct = &td->per_constraints->size; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int value = per_get_few_bits(pd, 1); + if(value < 0) _ASN_DECODE_STARVED; + if(value) ct = 0; /* Not restricted! */ + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + nelems = per_get_few_bits(pd, ct->effective_bits); + ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", + (long)nelems, ct->lower_bound, td->name); + if(nelems < 0) _ASN_DECODE_STARVED; + nelems += ct->lower_bound; + } else { + nelems = -1; + } + + do { + int i; + if(nelems < 0) { + nelems = uper_get_length(pd, + ct ? ct->effective_bits : -1, &repeat); + if(nelems < 0) _ASN_DECODE_STARVED; + } + + for(i = 0; i < nelems; i++) { + void *ptr = 0; + ASN_DEBUG("SET OF %s decoding", elm->type->name); + rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, &ptr, pd); + ASN_DEBUG("%s SET OF %s decoded %d, %p", + td->name, elm->type->name, rv.code, ptr); + if(rv.code == RC_OK) { + if(ASN_SET_ADD(list, ptr) == 0) + continue; + ASN_DEBUG("Failed to add element into %s", + td->name); + /* Fall through */ + } else { + ASN_DEBUG("Failed decoding %s of %s (SET OF)", + elm->type->name, td->name); + } + if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); + return rv; + } + + nelems = -1; /* Allow uper_get_length() */ + } while(repeat); + + ASN_DEBUG("Decoded %s as SET OF", td->name); + + rv.code = RC_OK; + rv.consumed = 0; + return rv; +} + diff --git a/src/mms/iso_mms/asn1c/constr_SET_OF.h b/src/mms/iso_mms/asn1c/constr_SET_OF.h new file mode 100644 index 0000000..bcd0966 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_SET_OF.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_SET_OF_H_ +#define _CONSTR_SET_OF_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct asn_SET_OF_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + /* XER-specific stuff */ + int as_XMLValueList; /* The member type must be encoded like this */ +} asn_SET_OF_specifics_t; + +/* + * A set specialized functions dealing with the SET OF type. + */ +asn_struct_free_f SET_OF_free; +asn_struct_print_f SET_OF_print; +asn_constr_check_f SET_OF_constraint; +ber_type_decoder_f SET_OF_decode_ber; +der_type_encoder_f SET_OF_encode_der; +xer_type_decoder_f SET_OF_decode_xer; +xer_type_encoder_f SET_OF_encode_xer; +per_type_decoder_f SET_OF_decode_uper; +per_type_encoder_f SET_OF_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/mms/iso_mms/asn1c/constr_TYPE.c b/src/mms/iso_mms/asn1c/constr_TYPE.c new file mode 100644 index 0000000..4bc88d4 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_TYPE.c @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Version of the ASN.1 infrastructure shipped with compiler. + */ +int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; } + +static asn_app_consume_bytes_f _print2fp; + +/* + * Return the outmost tag of the type. + */ +ber_tlv_tag_t +asn_TYPE_outmost_tag(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { + + if(tag_mode) + return tag; + + if(type_descriptor->tags_count) + return type_descriptor->tags[0]; + + return type_descriptor->outmost_tag(type_descriptor, struct_ptr, 0, 0); +} + +/* + * Print the target language's structure in human readable form. + */ +int +asn_fprint(FILE *stream, asn_TYPE_descriptor_t *td, const void *struct_ptr) { + if(!stream) stream = stdout; + if(!td || !struct_ptr) { + errno = EINVAL; + return -1; + } + + /* Invoke type-specific printer */ + if(td->print_struct(td, struct_ptr, 1, _print2fp, stream)) + return -1; + + /* Terminate the output */ + if(_print2fp("\n", 1, stream)) + return -1; + + return fflush(stream); +} + +/* Dump the data into the specified stdio stream */ +static int +_print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + + +/* + * Some compilers do not support variable args macros. + * This function is a replacement of ASN_DEBUG() macro. + */ +void ASN_DEBUG_f(const char *fmt, ...); +void ASN_DEBUG_f(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} diff --git a/src/mms/iso_mms/asn1c/constr_TYPE.h b/src/mms/iso_mms/asn1c/constr_TYPE.h new file mode 100644 index 0000000..95507c8 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constr_TYPE.h @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This file contains the declaration structure called "ASN.1 Type Definition", + * which holds all information necessary for encoding and decoding routines. + * This structure even contains pointer to these encoding and decoding routines + * for each defined ASN.1 type. + */ +#ifndef _CONSTR_TYPE_H_ +#define _CONSTR_TYPE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_TYPE_member_s; /* Forward declaration */ + +/* + * This type provides the context information for various ASN.1 routines, + * primarily ones doing decoding. A member _asn_ctx of this type must be + * included into certain target language's structures, such as compound types. + */ +typedef struct asn_struct_ctx_s { + short phase; /* Decoding phase */ + short step; /* Elementary step of a phase */ + int context; /* Other context information */ + void *ptr; /* Decoder-specific stuff (stack elements) */ + ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ +} asn_struct_ctx_t; + +#include /* Basic Encoding Rules decoder */ +#include /* Distinguished Encoding Rules encoder */ +#include /* Decoder of XER (XML, text) */ +#include /* Encoder into XER (XML, text) */ +#include /* Packet Encoding Rules decoder */ +#include /* Packet Encoding Rules encoder */ +#include /* Subtype constraints support */ + +/* + * Free the structure according to its specification. + * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) + * will not be freed. (It may be useful in case the structure is allocated + * statically or arranged on the stack, yet its elements are allocated + * dynamically.) + */ +typedef void (asn_struct_free_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, int free_contents_only); +#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) +#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ + (asn_DEF).free_struct(&(asn_DEF),ptr,1) + +/* + * Print the structure according to its specification. + */ +typedef int (asn_struct_print_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + int level, /* Indentation level */ + asn_app_consume_bytes_f *callback, void *app_key); + +/* + * Return the outmost tag of the type. + * If the type is untagged CHOICE, the dynamic operation is performed. + * NOTE: This function pointer type is only useful internally. + * Do not use it in your application. + */ +typedef ber_tlv_tag_t (asn_outmost_tag_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); +/* The instance of the above function type; used internally. */ +asn_outmost_tag_f asn_TYPE_outmost_tag; + + +/* + * The definitive description of the destination language's structure. + */ +typedef struct asn_TYPE_descriptor_s { + char *name; /* A name of the ASN.1 type. "" in some cases. */ + char *xml_tag; /* Name used in XML tag */ + + /* + * Generalized functions for dealing with the specific type. + * May be directly invoked by applications. + */ + asn_struct_free_f *free_struct; /* Free the structure */ + asn_struct_print_f *print_struct; /* Human readable output */ + asn_constr_check_f *check_constraints; /* Constraints validator */ + ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ + der_type_encoder_f *der_encoder; /* Canonical DER encoder */ + xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ + xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ + per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ + + /*********************************************************************** + * Internally useful members. Not to be used by applications directly. * + **********************************************************************/ + + /* + * Tags that are expected to occur. + */ + asn_outmost_tag_f *outmost_tag; /* */ + ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ + int tags_count; /* Number of tags which are expected */ + ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ + int all_tags_count; /* Number of tags */ + + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + + /* + * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). + */ + struct asn_TYPE_member_s *elements; + int elements_count; + + /* + * Additional information describing the type, used by appropriate + * functions above. + */ + void *specifics; +} asn_TYPE_descriptor_t; + +/* + * This type describes an element of the constructed type, + * i.e. SEQUENCE, SET, CHOICE, etc. + */ + enum asn_TYPE_flags_e { + ATF_NOFLAGS, + ATF_POINTER = 0x01, /* Represented by the pointer */ + ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ + }; +typedef struct asn_TYPE_member_s { + enum asn_TYPE_flags_e flags; /* Element's presentation flags */ + int optional; /* Following optional members, including current */ + int memb_offset; /* Offset of the element */ + ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ + int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ + asn_TYPE_descriptor_t *type; /* Member type descriptor */ + asn_constr_check_f *memb_constraints; /* Constraints validator */ + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + int (*default_value)(int setval, void **sptr); /* DEFAULT */ + char *name; /* ASN.1 identifier of the element */ +} asn_TYPE_member_t; + +/* + * BER tag to element number mapping. + */ +typedef struct asn_TYPE_tag2member_s { + ber_tlv_tag_t el_tag; /* Outmost tag of the member */ + int el_no; /* Index of the associated member, base 0 */ + int toff_first; /* First occurence of the el_tag, relative */ + int toff_last; /* Last occurence of the el_tag, relatvie */ +} asn_TYPE_tag2member_t; + +/* + * This function is a wrapper around (td)->print_struct, which prints out + * the contents of the target language's structure (struct_ptr) into the + * file pointer (stream) in human readable form. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem dumping the structure. + * (See also xer_fprint() in xer_encoder.h) + */ +int asn_fprint(FILE *stream, /* Destination stream descriptor */ + asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ + const void *struct_ptr); /* Structure to be printed */ + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_TYPE_H_ */ diff --git a/src/mms/iso_mms/asn1c/constraints.c b/src/mms/iso_mms/asn1c/constraints.c new file mode 100644 index 0000000..f958d15 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constraints.c @@ -0,0 +1,93 @@ +#include "asn_internal.h" +#include "constraints.h" + +int +asn_generic_no_constraint(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { + + (void)type_descriptor; /* Unused argument */ + (void)struct_ptr; /* Unused argument */ + (void)cb; /* Unused argument */ + (void)key; /* Unused argument */ + + /* Nothing to check */ + return 0; +} + +int +asn_generic_unknown_constraint(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { + + (void)type_descriptor; /* Unused argument */ + (void)struct_ptr; /* Unused argument */ + (void)cb; /* Unused argument */ + (void)key; /* Unused argument */ + + /* Unknown how to check */ + return 0; +} + +struct errbufDesc { + asn_TYPE_descriptor_t *failed_type; + const void *failed_struct_ptr; + char *errbuf; + size_t errlen; +}; + +static void +_asn_i_ctfailcb(void *key, asn_TYPE_descriptor_t *td, const void *sptr, const char *fmt, ...) { + struct errbufDesc *arg = (struct errbufDesc *) key; + va_list ap; + ssize_t vlen; + ssize_t maxlen; + + arg->failed_type = td; + arg->failed_struct_ptr = sptr; + + maxlen = arg->errlen; + if(maxlen <= 0) + return; + + va_start(ap, fmt); + vlen = vsnprintf(arg->errbuf, maxlen, fmt, ap); + va_end(ap); + if(vlen >= maxlen) { + arg->errbuf[maxlen-1] = '\0'; /* Ensuring libc correctness */ + arg->errlen = maxlen - 1; /* Not counting termination */ + return; + } else if(vlen >= 0) { + arg->errbuf[vlen] = '\0'; /* Ensuring libc correctness */ + arg->errlen = vlen; /* Not counting termination */ + } else { + /* + * The libc on this system is broken. + */ + vlen = sizeof("") - 1; + maxlen--; + arg->errlen = vlen < maxlen ? vlen : maxlen; + memcpy(arg->errbuf, "", arg->errlen); + arg->errbuf[arg->errlen] = 0; + } + + return; +} + +int +asn_check_constraints(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, char *errbuf, size_t *errlen) { + struct errbufDesc arg; + int ret; + + arg.failed_type = 0; + arg.failed_struct_ptr = 0; + arg.errbuf = errbuf; + arg.errlen = errlen ? *errlen : 0; + + ret = type_descriptor->check_constraints(type_descriptor, + struct_ptr, _asn_i_ctfailcb, &arg); + if(ret == -1 && errlen) + *errlen = arg.errlen; + + return ret; +} + diff --git a/src/mms/iso_mms/asn1c/constraints.h b/src/mms/iso_mms/asn1c/constraints.h new file mode 100644 index 0000000..5032345 --- /dev/null +++ b/src/mms/iso_mms/asn1c/constraints.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ +#define _ASN1_CONSTRAINTS_VALIDATOR_H_ + +#include /* Platform-dependent types */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Validate the structure according to the ASN.1 constraints. + * If errbuf and errlen are given, they shall be pointing to the appropriate + * buffer space and its length before calling this function. Alternatively, + * they could be passed as NULL's. If constraints validation fails, + * errlen will contain the actual number of bytes taken from the errbuf + * to encode an error message (properly 0-terminated). + * + * RETURN VALUES: + * This function returns 0 in case all ASN.1 constraints are met + * and -1 if one or more constraints were failed. + */ +int +asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Target language's structure */ + char *errbuf, /* Returned error description */ + size_t *errlen /* Length of the error description */ + ); + + +/* + * Generic type for constraint checking callback, + * associated with every type descriptor. + */ +typedef int (asn_constr_check_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + asn_app_constraint_failed_f *optional_callback, /* Log the error */ + void *optional_app_key /* Opaque key passed to a callback */ + ); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ +asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ + +/* + * Invoke the callback with a complete error message. + */ +#define _ASN_CTFAIL if(ctfailcb) ctfailcb + +#ifdef __cplusplus +} +#endif + +#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ diff --git a/src/mms/iso_mms/asn1c/der_encoder.c b/src/mms/iso_mms/asn1c/der_encoder.c new file mode 100644 index 0000000..cc2000e --- /dev/null +++ b/src/mms/iso_mms/asn1c/der_encoder.c @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, + asn_app_consume_bytes_f *cb, void *app_key, int constructed); + +/* + * The DER encoder of any type. + */ +asn_enc_rval_t +der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, + asn_app_consume_bytes_f *consume_bytes, void *app_key) { + + ASN_DEBUG("DER encoder invoked for %s", + type_descriptor->name); + + /* + * Invoke type-specific encoder. + */ + return type_descriptor->der_encoder(type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + 0, 0, + consume_bytes, app_key); +} + +/* + * Argument type and callback necessary for der_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +/* + * A variant of the der_encode() which encodes the data into the provided buffer + */ +asn_enc_rval_t +der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, + void *buffer, size_t buffer_size) { + enc_to_buf_arg arg; + asn_enc_rval_t ec; + + arg.buffer = buffer; + arg.left = buffer_size; + + ec = type_descriptor->der_encoder(type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + 0, 0, encode_to_buffer_cb, &arg); + if(ec.encoded != -1) { + assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); + /* Return the encoded contents size */ + } + return ec; +} + + +/* + * Write out leading TL[v] sequence according to the type definition. + */ +ssize_t +der_write_tags(asn_TYPE_descriptor_t *sd, + size_t struct_length, + int tag_mode, int last_tag_form, + ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ + asn_app_consume_bytes_f *cb, + void *app_key) { + ber_tlv_tag_t tag_mem[5]; /* Copy of tags stream */ + ber_tlv_tag_t* tags; + int tags_count; /* Number of tags */ + size_t overall_length; + ssize_t lens[5]; + int i; + + if (sd->tags_count > 4) { + printf("TO MUCH TAGS"); + errno = ENOMEM; + return -1; + } + + if(tag_mode) { + /* + * Instead of doing shaman dance like we do in ber_check_tags(), + * allocate a small array on the stack + * and initialize it appropriately. + */ + int stag_offset; + + tags = tag_mem; + + tags_count = sd->tags_count + + 1 /* EXPLICIT or IMPLICIT tag is given */ + - ((tag_mode == -1) && sd->tags_count); + /* Copy tags over */ + tags[0] = tag; + stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); + for(i = 1; i < tags_count; i++) + tags[i] = sd->tags[i + stag_offset]; + } else { + tags = sd->tags; + tags_count = sd->tags_count; + } + + /* No tags to write */ + if(tags_count == 0) + return 0; + + /* + * Array of tags is initialized. + * Now, compute the size of the TLV pairs, from right to left. + */ + overall_length = struct_length; + for(i = tags_count - 1; i >= 0; --i) { + lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0); + if(lens[i] == -1) return -1; + overall_length += lens[i]; + lens[i] = overall_length - lens[i]; + } + + if(!cb) return overall_length - struct_length; + + ASN_DEBUG("%s %s TL sequence (%d elements)", + cb?"Encoding":"Estimating", sd->name, tags_count); + + /* + * Encode the TL sequence for real. + */ + for(i = 0; i < tags_count; i++) { + ssize_t len; + int _constr; + + /* Check if this tag happens to be constructed */ + _constr = (last_tag_form || i < (tags_count - 1)); + + len = der_write_TL(tags[i], lens[i], cb, app_key, _constr); + if(len == -1) return -1; + } + + return overall_length - struct_length; +} + +static ssize_t +der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, + asn_app_consume_bytes_f *cb, void *app_key, + int constructed) { + uint8_t buf[32]; + size_t size = 0; + int buf_size = cb?sizeof(buf):0; + ssize_t tmp; + + /* Serialize tag (T from TLV) into possibly zero-length buffer */ + tmp = ber_tlv_tag_serialize(tag, buf, buf_size); + if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1; + size += tmp; + + /* Serialize length (L from TLV) into possibly zero-length buffer */ + tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0); + if(tmp == -1) return -1; + size += tmp; + + if(size > sizeof(buf)) + return -1; + + /* + * If callback is specified, invoke it, and check its return value. + */ + if(cb) { + if(constructed) *buf |= 0x20; + if(cb(buf, size, app_key) < 0) + return -1; + } + + return size; +} diff --git a/src/mms/iso_mms/asn1c/der_encoder.h b/src/mms/iso_mms/asn1c/der_encoder.h new file mode 100644 index 0000000..4e2fb06 --- /dev/null +++ b/src/mms/iso_mms/asn1c/der_encoder.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _DER_ENCODER_H_ +#define _DER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The DER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); + +/* A variant of der_encode() which encodes data into the pre-allocated buffer */ +asn_enc_rval_t der_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ + ); + +/* + * Type of the generic DER encoder. + */ +typedef asn_enc_rval_t (der_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); + + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Write out leading TL[v] sequence according to the type definition. + */ +ssize_t der_write_tags( + struct asn_TYPE_descriptor_s *type_descriptor, + size_t struct_length, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {0,!0}: prim, constructed */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _DER_ENCODER_H_ */ diff --git a/src/mms/iso_mms/asn1c/per_decoder.c b/src/mms/iso_mms/asn1c/per_decoder.c new file mode 100644 index 0000000..16dee36 --- /dev/null +++ b/src/mms/iso_mms/asn1c/per_decoder.c @@ -0,0 +1,55 @@ +#include +#include +#include + +asn_dec_rval_t +uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { + asn_codec_ctx_t s_codec_ctx; + asn_dec_rval_t rval; + asn_per_data_t pd; + + if(skip_bits < 0 || skip_bits > 7 + || unused_bits < 0 || unused_bits > 7 + || (unused_bits > 0 && !size)) + _ASN_DECODE_FAILED; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* Fill in the position indicator */ + pd.buffer = (const uint8_t *)buffer; + pd.nboff = skip_bits; + pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ + if(pd.nboff > pd.nbits) + _ASN_DECODE_FAILED; + + /* + * Invoke type-specific decoder. + */ + if(!td->uper_decoder) + _ASN_DECODE_FAILED; /* PER is not compiled in */ + rval = td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd); + if(rval.code == RC_OK) { + /* Return the number of consumed bits */ + rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) + + pd.nboff - skip_bits; + } else { + /* PER codec is not a restartable */ + rval.consumed = 0; + } + return rval; +} + diff --git a/src/mms/iso_mms/asn1c/per_decoder.h b/src/mms/iso_mms/asn1c/per_decoder.h new file mode 100644 index 0000000..26aaf59 --- /dev/null +++ b/src/mms/iso_mms/asn1c/per_decoder.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_DECODER_H_ +#define _PER_DECODER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. + */ +asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size, /* Size of data buffer */ + int skip_bits, /* Number of unused leading bits, 0..7 */ + int unused_bits /* Number of unused tailing bits, 0..7 */ + ); + + +/* + * Type of the type-specific PER decoder function. + */ +typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void **struct_ptr, + asn_per_data_t *per_data + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_DECODER_H_ */ diff --git a/src/mms/iso_mms/asn1c/per_encoder.c b/src/mms/iso_mms/asn1c/per_encoder.c new file mode 100644 index 0000000..614dd23 --- /dev/null +++ b/src/mms/iso_mms/asn1c/per_encoder.c @@ -0,0 +1,95 @@ +#include +#include +#include + +/* Flush partially filled buffer */ +static int _uper_encode_flush_outp(asn_per_outp_t *po); + +asn_enc_rval_t +uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { + asn_per_outp_t po; + asn_enc_rval_t er; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->uper_encoder) + _ASN_ENCODE_FAILED; /* PER is not compiled in */ + + po.buffer = po.tmpspace; + po.nboff = 0; + po.nbits = 8 * sizeof(po.tmpspace); + po.outper = cb; + po.op_key = app_key; + po.flushed_bytes = 0; + + er = td->uper_encoder(td, 0, sptr, &po); + if(er.encoded != -1) { + size_t bits_to_flush; + + bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; + + /* Set number of bits encoded to a firm value */ + er.encoded = (po.flushed_bytes << 3) + bits_to_flush; + + if(_uper_encode_flush_outp(&po)) + _ASN_ENCODE_FAILED; + } + + return er; +} + +/* + * Argument type and callback necessary for uper_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +asn_enc_rval_t +uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { + enc_to_buf_arg key; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->uper_encoder) + _ASN_ENCODE_FAILED; /* PER is not compiled in */ + + key.buffer = buffer; + key.left = buffer_size; + + ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); + + return uper_encode(td, sptr, encode_to_buffer_cb, &key); +} + +static int +_uper_encode_flush_outp(asn_per_outp_t *po) { + uint8_t *buf; + + if(po->nboff == 0 && po->buffer == po->tmpspace) + return 0; + + buf = po->buffer + (po->nboff >> 3); + /* Make sure we account for the last, partially filled */ + if(po->nboff & 0x07) { + buf[0] &= 0xff << (8 - (po->nboff & 0x07)); + buf++; + } + + return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); +} diff --git a/src/mms/iso_mms/asn1c/per_encoder.h b/src/mms/iso_mms/asn1c/per_encoder.h new file mode 100644 index 0000000..9ac130b --- /dev/null +++ b/src/mms/iso_mms/asn1c/per_encoder.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_ENCODER_H_ +#define _PER_ENCODER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. + */ +asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ + void *app_key /* Arbitrary callback argument */ +); + +/* A variant of uper_encode() which encodes data into the existing buffer */ +asn_enc_rval_t uper_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (max) */ +); + + +/* + * Type of the generic PER encoder function. + */ +typedef asn_enc_rval_t (per_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, + asn_per_outp_t *per_output +); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_ENCODER_H_ */ diff --git a/src/mms/iso_mms/asn1c/per_support.c b/src/mms/iso_mms/asn1c/per_support.c new file mode 100644 index 0000000..c834419 --- /dev/null +++ b/src/mms/iso_mms/asn1c/per_support.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + */ +int32_t +per_get_few_bits(asn_per_data_t *pd, int nbits) { + size_t off; /* Next after last bit offset */ + uint32_t accum; + const uint8_t *buf; + + if(nbits < 0 || pd->nboff + nbits > pd->nbits) + return -1; + + ASN_DEBUG("[PER get %d bits from %p+%d bits]", + nbits, pd->buffer, pd->nboff); + + /* + * Normalize position indicator. + */ + if(pd->nboff >= 8) { + pd->buffer += (pd->nboff >> 3); + pd->nbits -= (pd->nboff & ~0x07); + pd->nboff &= 0x07; + } + off = (pd->nboff += nbits); + buf = pd->buffer; + + /* + * Extract specified number of bits. + */ + if(off <= 8) + accum = nbits ? (buf[0]) >> (8 - off) : 0; + else if(off <= 16) + accum = ((buf[0] << 8) + buf[1]) >> (16 - off); + else if(off <= 24) + accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); + else if(off <= 31) + accum = ((buf[0] << 24) + (buf[1] << 16) + + (buf[2] << 8) + (buf[3])) >> (32 - off); + else if(nbits <= 31) { + asn_per_data_t tpd = *pd; + /* Here are we with our 31-bits limit plus 1..7 bits offset. */ + tpd.nboff -= nbits; + accum = per_get_few_bits(&tpd, nbits - 24) << 24; + accum |= per_get_few_bits(&tpd, 24); + } else { + pd->nboff -= nbits; /* Oops, revert back */ + return -1; + } + + return (accum & (((uint32_t)1 << nbits) - 1)); +} + +/* + * Extract a large number of bits from the specified PER data pointer. + */ +int +per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { + int32_t value; + + if(alright && (nbits & 7)) { + /* Perform right alignment of a first few bits */ + value = per_get_few_bits(pd, nbits & 0x07); + if(value < 0) return -1; + *dst++ = value; /* value is already right-aligned */ + nbits &= ~7; + } + + while(nbits) { + if(nbits >= 24) { + value = per_get_few_bits(pd, 24); + if(value < 0) return -1; + *(dst++) = value >> 16; + *(dst++) = value >> 8; + *(dst++) = value; + nbits -= 24; + } else { + value = per_get_few_bits(pd, nbits); + if(value < 0) return -1; + if(nbits & 7) { /* implies left alignment */ + value <<= 8 - (nbits & 7), + nbits += 8 - (nbits & 7); + if(nbits > 24) + *dst++ = value >> 24; + } + if(nbits > 16) + *dst++ = value >> 16; + if(nbits > 8) + *dst++ = value >> 8; + *dst++ = value; + break; + } + } + + return 0; +} + +/* + * Get the length "n" from the stream. + */ +ssize_t +uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { + ssize_t value; + + *repeat = 0; + + if(ebits >= 0) return per_get_few_bits(pd, ebits); + + value = per_get_few_bits(pd, 8); + if(value < 0) return -1; + if((value & 128) == 0) /* #10.9.3.6 */ + return (value & 0x7F); + if((value & 64) == 0) { /* #10.9.3.7 */ + value = ((value & 63) << 8) | per_get_few_bits(pd, 8); + if(value < 0) return -1; + return value; + } + value &= 63; /* this is "m" from X.691, #10.9.3.8 */ + if(value < 1 || value > 4) + return -1; + *repeat = 1; + return (16384 * value); +} + +/* + * Get the normally small non-negative whole number. + * X.691, #10.6 + */ +ssize_t +uper_get_nsnnwn(asn_per_data_t *pd) { + ssize_t value; + + value = per_get_few_bits(pd, 7); + if(value & 64) { /* implicit (value < 0) */ + value &= 63; + value <<= 2; + value |= per_get_few_bits(pd, 2); + if(value & 128) /* implicit (value < 0) */ + return -1; + if(value == 0) + return 0; + if(value >= 3) + return -1; + value = per_get_few_bits(pd, 8 * value); + return value; + } + + return value; +} + +/* + * Put the normally small non-negative whole number. + * X.691, #10.6 + */ +int +uper_put_nsnnwn(asn_per_outp_t *po, int n) { + int bytes; + + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); + } + if(n < 256) + bytes = 1; + else if(n < 65536) + bytes = 2; + else if(n < 256 * 65536) + bytes = 3; + else + return -1; /* This is not a "normally small" value */ + if(per_put_few_bits(po, bytes, 8)) + return -1; + + return per_put_few_bits(po, n, 8 * bytes); +} + + +/* + * Put a small number of bits (<= 31). + */ +int +per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { + size_t off; /* Next after last bit offset */ + size_t omsk; /* Existing last byte meaningful bits mask */ + uint8_t *buf; + + if(obits <= 0 || obits >= 32) return obits ? -1 : 0; + + ASN_DEBUG("[PER put %d bits to %p+%d bits]", + obits, po->buffer, po->nboff); + + /* + * Normalize position indicator. + */ + if(po->nboff >= 8) { + po->buffer += (po->nboff >> 3); + po->nbits -= (po->nboff & ~0x07); + po->nboff &= 0x07; + } + + /* + * Flush whole-bytes output, if necessary. + */ + if(po->nboff + obits > po->nbits) { + int complete_bytes = (po->buffer - po->tmpspace); + if(po->outper(po->buffer, complete_bytes, po->op_key) < 0) + return -1; + if(po->nboff) + po->tmpspace[0] = po->buffer[0]; + po->buffer = po->tmpspace; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + } + + /* + * Now, due to sizeof(tmpspace), we are guaranteed large enough space. + */ + buf = po->buffer; + omsk = ~((1 << (8 - po->nboff)) - 1); + off = (po->nboff += obits); + + /* Clear data of debris before meaningful bits */ + bits &= (((uint32_t)1 << obits) - 1); + + ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, bits, bits, + po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); + + if(off <= 8) /* Completely within 1 byte */ + bits <<= (8 - off), + buf[0] = (buf[0] & omsk) | bits; + else if(off <= 16) + bits <<= (16 - off), + buf[0] = (buf[0] & omsk) | (bits >> 8), + buf[1] = bits; + else if(off <= 24) + bits <<= (24 - off), + buf[0] = (buf[0] & omsk) | (bits >> 16), + buf[1] = bits >> 8, + buf[2] = bits; + else if(off <= 31) + bits <<= (32 - off), + buf[0] = (buf[0] & omsk) | (bits >> 24), + buf[1] = bits >> 16, + buf[2] = bits >> 8, + buf[3] = bits; + else { + ASN_DEBUG("->[PER out split %d]", obits); + per_put_few_bits(po, bits >> 8, 24); + per_put_few_bits(po, bits, obits - 24); + ASN_DEBUG("<-[PER out split %d]", obits); + } + + ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", + bits, bits, buf[0], po->buffer - po->tmpspace); + + return 0; +} + + +/* + * Output a large number of bits. + */ +int +per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { + + while(nbits) { + uint32_t value; + + if(nbits >= 24) { + value = (src[0] << 16) | (src[1] << 8) | src[2]; + src += 3; + nbits -= 24; + if(per_put_few_bits(po, value, 24)) + return -1; + } else { + value = src[0]; + if(nbits > 8) + value = (value << 8) | src[1]; + if(nbits > 16) + value = (value << 8) | src[2]; + if(nbits & 0x07) + value >>= (8 - (nbits & 0x07)); + if(per_put_few_bits(po, value, nbits)) + return -1; + break; + } + } + + return 0; +} + +/* + * Put the length "n" (or part of it) into the stream. + */ +ssize_t +uper_put_length(asn_per_outp_t *po, size_t length) { + + if(length <= 127) /* #10.9.3.6 */ + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; + else if(length < 16384) /* #10.9.3.7 */ + return per_put_few_bits(po, length|0x8000, 16) + ? -1 : (ssize_t)length; + + length >>= 14; + if(length > 4) length = 4; + + return per_put_few_bits(po, 0xC0 | length, 8) + ? -1 : (ssize_t)(length << 14); +} + diff --git a/src/mms/iso_mms/asn1c/per_support.h b/src/mms/iso_mms/asn1c/per_support.h new file mode 100644 index 0000000..face6ca --- /dev/null +++ b/src/mms/iso_mms/asn1c/per_support.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_SUPPORT_H_ +#define _PER_SUPPORT_H_ + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum asn_per_constraint_flags { + APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ + APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ + APC_CONSTRAINED = 0x2, /* Fully constrained */ + APC_EXTENSIBLE = 0x4 /* May have extension */ + }; + +/* + * Pre-computed PER constraints. + */ +typedef struct asn_per_constraint_s { + enum asn_per_constraint_flags flags; + int range_bits; /* Full number of bits in the range */ + int effective_bits; /* Effective bits */ + long lower_bound; /* "lb" value */ + long upper_bound; /* "ub" value */ +} asn_per_constraint_t; +typedef struct asn_per_constraints_s { + asn_per_constraint_t value; + asn_per_constraint_t size; +} asn_per_constraints_t; + +/* + * This structure describes a position inside an incoming PER bit stream. + */ +typedef struct asn_per_data_s { + const uint8_t *buffer; /* Pointer to the octet stream */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits in the stream */ +} asn_per_data_t; + +/* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + * This function returns -1 if the specified number of bits could not be + * extracted due to EOD or other conditions. + */ +int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); + +/* + * Extract a large number of bits from the specified PER data pointer. + * This function returns -1 if the specified number of bits could not be + * extracted due to EOD or other conditions. + */ +int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, + int get_nbits); + +/* + * Get the length "n" from the Unaligned PER stream. + */ +ssize_t uper_get_length(asn_per_data_t *pd, + int effective_bound_bits, + int *repeat); + +/* + * Get the normally small non-negative whole number. + */ +ssize_t uper_get_nsnnwn(asn_per_data_t *pd); + +/* + * This structure supports forming PER output. + */ +typedef struct asn_per_outp_s { + uint8_t *buffer; /* Pointer into the (tmpspace) */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits left in (tmpspace) */ + uint8_t tmpspace[32]; /* Preliminary storage to hold data */ + int (*outper)(const void *data, size_t size, void *op_key); + void *op_key; /* Key for (outper) data callback */ + size_t flushed_bytes; /* Bytes already flushed through (outper) */ +} asn_per_outp_t; + +/* Output a small number of bits (<= 31) */ +int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); + +/* Output a large number of bits */ +int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); + +/* + * Put the length "n" to the Unaligned PER stream. + * This function returns the number of units which may be flushed + * in the next units saving iteration. + */ +ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); + +/* + * Put the normally small non-negative whole number. + */ +int uper_put_nsnnwn(asn_per_outp_t *po, int n); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_SUPPORT_H_ */ diff --git a/src/mms/iso_mms/asn1c/xer_decoder.c b/src/mms/iso_mms/asn1c/xer_decoder.c new file mode 100644 index 0000000..161dc78 --- /dev/null +++ b/src/mms/iso_mms/asn1c/xer_decoder.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2004, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* XER/XML parsing support */ + + +/* + * Decode the XER encoding of a given type. + */ +asn_dec_rval_t +xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *buffer, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size); +} + + + +struct xer__cb_arg { + pxml_chunk_type_e chunk_type; + size_t chunk_size; + const void *chunk_buf; + int callback_not_invoked; +}; + +static int +xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) { + struct xer__cb_arg *arg = (struct xer__cb_arg *)key; + arg->chunk_type = type; + arg->chunk_size = _chunk_size; + arg->chunk_buf = _chunk_data; + arg->callback_not_invoked = 0; + return -1; /* Terminate the XML parsing */ +} + +/* + * Fetch the next token from the XER/XML stream. + */ +ssize_t +xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) { + struct xer__cb_arg arg; + int new_stateContext = *stateContext; + ssize_t ret; + + arg.callback_not_invoked = 1; + ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg); + if(ret < 0) return -1; + if(arg.callback_not_invoked) { + assert(ret == 0); /* No data was consumed */ + return 0; /* Try again with more data */ + } else { + assert(arg.chunk_size); + assert(arg.chunk_buf == buffer); + } + + /* + * Translate the XML chunk types into more convenient ones. + */ + switch(arg.chunk_type) { + case PXML_TEXT: + *ch_type = PXER_TEXT; + break; + case PXML_TAG: return 0; /* Want more */ + case PXML_TAG_END: + *ch_type = PXER_TAG; + break; + case PXML_COMMENT: + case PXML_COMMENT_END: + *ch_type = PXER_COMMENT; + break; + } + + *stateContext = new_stateContext; + return arg.chunk_size; +} + +#define CSLASH 0x2f /* '/' */ +#define LANGLE 0x3c /* '<' */ +#define RANGLE 0x3e /* '>' */ + +xer_check_tag_e +xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { + const char *buf = (const char *)buf_ptr; + const char *end; + xer_check_tag_e ct = XCT_OPENING; + + if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { + if(size >= 2) + ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]); + return XCT_BROKEN; + } + + /* + * Determine the tag class. + */ + if(buf[1] == CSLASH) { + buf += 2; /* advance past "" */ + ct = XCT_CLOSING; + if(size > 0 && buf[size-1] == CSLASH) + return XCT_BROKEN; /* */ + } else { + buf++; /* advance past "<" */ + size -= 2; /* strip "<" and ">" */ + if(size > 0 && buf[size-1] == CSLASH) { + ct = XCT_BOTH; + size--; /* One more, for "/" */ + } + } + + /* Sometimes we don't care about the tag */ + if(!need_tag || !*need_tag) + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + + /* + * Determine the tag name. + */ + for(end = buf + size; buf < end; buf++, need_tag++) { + int b = *buf, n = *need_tag; + if(b != n) { + if(n == 0) { + switch(b) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* "": whitespace is normal */ + return ct; + } + } + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + } + if(b == 0) + return XCT_BROKEN; /* Embedded 0 in buf?! */ + } + if(*need_tag) + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + + return ct; +} + + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = (num_bytes); \ + buf_ptr = ((const char *)buf_ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself; \ + if(rval.code != RC_OK) \ + ASN_DEBUG("Failed with %d", rval.code); \ + return rval; \ + } while(0) + +#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ + ssize_t converted_size = body_receiver \ + (struct_key, chunk_buf, chunk_size, \ + (size_t)chunk_size < size); \ + if(converted_size == -1) RETURN(RC_FAIL); \ + if(converted_size == 0 \ + && size == (size_t)chunk_size) \ + RETURN(RC_WMORE); \ + chunk_size = converted_size; \ + } while(0) +#define XER_GOT_EMPTY() do { \ + if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ + RETURN(RC_FAIL); \ + } while(0) + +/* + * Generalized function for decoding the primitive values. + */ +asn_dec_rval_t +xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, + const char *xml_tag, /* Expected XML tag */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more) + ) { + + asn_dec_rval_t rval; + ssize_t consumed_myself = 0; + + (void)opt_codec_ctx; + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + */ + if(ctx->phase > 1) RETURN(RC_FAIL); + for(;;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, + &ch_type); + switch(ch_size) { + case -1: RETURN(RC_FAIL); + case 0: + RETURN(RC_WMORE); + default: + switch(ch_type) { + case PXER_COMMENT: /* Got XML comment */ + ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TEXT: + if(ctx->phase == 0) { + /* + * We have to ignore whitespace here, + * but in order to be forward compatible + * with EXTENDED-XER (EMBED-VALUES, #25) + * any text is just ignored here. + */ + } else { + XER_GOT_BODY(buf_ptr, ch_size, size); + } + ADVANCE(ch_size); + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + assert(ch_type == PXER_TAG && size); + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + /* + * Phase 0: + * Expecting the opening tag + * for the type being processed. + * Phase 1: + * Waiting for the closing XML tag. + */ + switch(tcv) { + case XCT_BOTH: + if(ctx->phase) break; + /* Finished decoding of an empty element */ + XER_GOT_EMPTY(); + ADVANCE(ch_size); + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + case XCT_OPENING: + if(ctx->phase) break; + ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + case XCT_CLOSING: + if(!ctx->phase) break; + ADVANCE(ch_size); + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + case XCT_UNKNOWN_BO: + /* + * Certain tags in the body may be expected. + */ + if(opt_unexpected_tag_decoder + && opt_unexpected_tag_decoder(struct_key, + buf_ptr, ch_size) >= 0) { + /* Tag's processed fine */ + ADVANCE(ch_size); + if(!ctx->phase) { + /* We are not expecting + * the closing tag anymore. */ + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + } + continue; + } + /* Fall through */ + default: + break; /* Unexpected tag */ + } + + ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag); + break; /* Dark and mysterious things have just happened */ + } + + RETURN(RC_FAIL); +} + + +int +xer_is_whitespace(const void *chunk_buf, size_t chunk_size) { + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + + for(; p < pend; p++) { + switch(*p) { + /* X.693, #8.1.4 + * HORISONTAL TAB (9) + * LINE FEED (10) + * CARRIAGE RETURN (13) + * SPACE (32) + */ + case 0x09: case 0x0a: case 0x0d: case 0x20: + break; + default: + return 0; + } + } + return 1; /* All whitespace */ +} + +/* + * This is a vastly simplified, non-validating XML tree skipper. + */ +int +xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) { + assert(*depth > 0); + switch(tcv) { + case XCT_BOTH: + case XCT_UNKNOWN_BO: + /* These negate each other. */ + return 0; + case XCT_OPENING: + case XCT_UNKNOWN_OP: + ++(*depth); + return 0; + case XCT_CLOSING: + case XCT_UNKNOWN_CL: + if(--(*depth) == 0) + return (tcv == XCT_CLOSING) ? 2 : 1; + return 0; + default: + return -1; + } +} diff --git a/src/mms/iso_mms/asn1c/xer_decoder.h b/src/mms/iso_mms/asn1c/xer_decoder.h new file mode 100644 index 0000000..cf0d846 --- /dev/null +++ b/src/mms/iso_mms/asn1c/xer_decoder.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_DECODER_H_ +#define _XER_DECODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The XER decoder of any ASN.1 type. May be invoked by the application. + */ +asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); + +/* + * Type of the type-specific XER decoder function. + */ +typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, + const char *opt_mname, /* Member name */ + const void *buf_ptr, size_t size + ); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Generalized function for decoding the primitive values. + * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 + * and others. This function should not be used by applications, as its API + * is subject to changes. + */ +asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, /* Treated as opaque pointer */ + const char *xml_tag, /* Expected XML tag name */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more) + ); + + +/* + * Fetch the next XER (XML) token from the stream. + * The function returns the number of bytes occupied by the chunk type, + * returned in the _ch_type. The _ch_type is only set (and valid) when + * the return value is greater than 0. + */ + typedef enum pxer_chunk_type { + PXER_TAG, /* Complete XER tag */ + PXER_TEXT, /* Plain text between XER tags */ + PXER_COMMENT /* A comment, may be part of */ + } pxer_chunk_type_e; +ssize_t xer_next_token(int *stateContext, + const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); + +/* + * This function checks the buffer against the tag name is expected to occur. + */ + typedef enum xer_check_tag { + XCT_BROKEN = 0, /* The tag is broken */ + XCT_OPENING = 1, /* This is the tag */ + XCT_CLOSING = 2, /* This is the tag */ + XCT_BOTH = 3, /* This is the tag */ + XCT__UNK__MASK = 4, /* Mask of everything unexpected */ + XCT_UNKNOWN_OP = 5, /* Unexpected tag */ + XCT_UNKNOWN_CL = 6, /* Unexpected tag */ + XCT_UNKNOWN_BO = 7 /* Unexpected tag */ + } xer_check_tag_e; +xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, + const char *need_tag); + +/* + * Check whether this buffer consists of entirely XER whitespace characters. + * RETURN VALUES: + * 1: Whitespace or empty string + * 0: Non-whitespace + */ +int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); + +/* + * Skip the series of anticipated extensions. + */ +int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_DECODER_H_ */ diff --git a/src/mms/iso_mms/asn1c/xer_encoder.c b/src/mms/iso_mms/asn1c/xer_encoder.c new file mode 100644 index 0000000..aa7cf04 --- /dev/null +++ b/src/mms/iso_mms/asn1c/xer_encoder.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * The XER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t +xer_encode(asn_TYPE_descriptor_t *td, void *sptr, + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er, tmper; + const char *mname; + size_t mlen; + int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; + + if(!td || !sptr) goto cb_failed; + + mname = td->xml_tag; + mlen = strlen(mname); + + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = td->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + + _ASN_CALLBACK3("\n", xcan); + + er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +/* + * This is a helper function for xer_fprint, which directs all incoming data + * into the provided file descriptor. + */ +static int +xer__print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + +int +xer_fprint(FILE *stream, asn_TYPE_descriptor_t *td, void *sptr) { + asn_enc_rval_t er; + + if(!stream) stream = stdout; + if(!td || !sptr) + return -1; + + er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); + if(er.encoded == -1) + return -1; + + return fflush(stream); +} diff --git a/src/mms/iso_mms/asn1c/xer_encoder.h b/src/mms/iso_mms/asn1c/xer_encoder.h new file mode 100644 index 0000000..1cb546a --- /dev/null +++ b/src/mms/iso_mms/asn1c/xer_encoder.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_ENCODER_H_ +#define _XER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ +enum xer_encoder_flags_e { + /* Mode of encoding */ + XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ + XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ +}; + +/* + * The XER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); + +/* + * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) + * output into the chosen file pointer. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem printing the structure. + * WARNING: No sensible errno value is returned. + */ +int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); + +/* + * Type of the generic XER encoder. + */ +typedef asn_enc_rval_t (xer_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int ilevel, /* Level of indentation */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_ENCODER_H_ */ diff --git a/src/mms/iso_mms/asn1c/xer_support.c b/src/mms/iso_mms/asn1c/xer_support.c new file mode 100644 index 0000000..9e34e69 --- /dev/null +++ b/src/mms/iso_mms/asn1c/xer_support.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* Parser states */ +typedef enum { + ST_TEXT, + ST_TAG_START, + ST_TAG_BODY, + ST_TAG_QUOTE_WAIT, + ST_TAG_QUOTED_STRING, + ST_TAG_UNQUOTED_STRING, + ST_COMMENT_WAIT_DASH1, /* ""[0] */ + ST_COMMENT_CLO_RT /* "-->"[1] */ +} pstate_e; + +static pxml_chunk_type_e final_chunk_type[] = { + PXML_TEXT, + PXML_TAG_END, + PXML_COMMENT_END, + PXML_TAG_END, + PXML_COMMENT_END, +}; + + +static int +_charclass[256] = { + 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0, /* 01234567 89 */ + 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* ABCDEFG HIJKLMNO */ + 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0, /* PQRSTUVW XYZ */ + 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* abcdefg hijklmno */ + 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0 /* pqrstuvw xyz */ +}; +#define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1) +#define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2) +#define ALPHA(c) (_charclass[(unsigned char)(c)] == 3) + +/* Aliases for characters, ASCII/UTF-8 */ +#define EXCLAM 0x21 /* '!' */ +#define CQUOTE 0x22 /* '"' */ +#define CDASH 0x2d /* '-' */ +#define CSLASH 0x2f /* '/' */ +#define LANGLE 0x3c /* '<' */ +#define CEQUAL 0x3d /* '=' */ +#define RANGLE 0x3e /* '>' */ +#define CQUEST 0x3f /* '?' */ + +/* Invoke token callback */ +#define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ + int _ret; \ + pstate_e ns = _ns; \ + ssize_t _sz = (p - chunk_start) + _current_too; \ + if (!_sz) { \ + /* Shortcut */ \ + state = _ns; \ + break; \ + } \ + _ret = cb(type, chunk_start, _sz, key); \ + if(_ret < _sz) { \ + if(_current_too && _ret == -1) \ + state = ns; \ + goto finish; \ + } \ + chunk_start = p + _current_too; \ + state = ns; \ + } while(0) + +#define TOKEN_CB(_type, _ns, _current_too) \ + TOKEN_CB_CALL(_type, _ns, _current_too, 0) + +#define TOKEN_CB_FINAL(_type, _ns, _current_too) \ + TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1) + +/* + * Parser itself + */ +ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) { + pstate_e state = (pstate_e)*stateContext; + const char *chunk_start = (const char *)xmlbuf; + const char *p = chunk_start; + const char *end = p + size; + + for(; p < end; p++) { + int C = *(const unsigned char *)p; + switch(state) { + case ST_TEXT: + /* + * Initial state: we're in the middle of some text, + * or just have started. + */ + if (C == LANGLE) + /* We're now in the tag, probably */ + TOKEN_CB(PXML_TEXT, ST_TAG_START, 0); + break; + case ST_TAG_START: + if (ALPHA(C) || (C == CSLASH)) + state = ST_TAG_BODY; + else if (C == EXCLAM) + state = ST_COMMENT_WAIT_DASH1; + else + /* + * Not characters and not whitespace. + * Must be something like "3 < 4". + */ + TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */ + break; + case ST_TAG_BODY: + switch(C) { + case RANGLE: + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + break; + case LANGLE: + /* + * The previous tag wasn't completed, but still + * recognized as valid. (Mozilla-compatible) + */ + TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0); + break; + case CEQUAL: + state = ST_TAG_QUOTE_WAIT; + break; + } + break; + case ST_TAG_QUOTE_WAIT: + /* + * State after the equal sign ("=") in the tag. + */ + switch(C) { + case CQUOTE: + state = ST_TAG_QUOTED_STRING; + break; + case RANGLE: + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + break; + default: + if(!WHITESPACE(C)) + /* Unquoted string value */ + state = ST_TAG_UNQUOTED_STRING; + } + break; + case ST_TAG_QUOTED_STRING: + /* + * Tag attribute's string value in quotes. + */ + if(C == CQUOTE) { + /* Return back to the tag state */ + state = ST_TAG_BODY; + } + break; + case ST_TAG_UNQUOTED_STRING: + if(C == RANGLE) { + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + } else if(WHITESPACE(C)) { + /* Return back to the tag state */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT_WAIT_DASH1: + if(C == CDASH) { + state = ST_COMMENT_WAIT_DASH2; + } else { + /* Some ordinary tag. */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT_WAIT_DASH2: + if(C == CDASH) { + /* Seen "<--" */ + state = ST_COMMENT; + } else { + /* Some ordinary tag */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT: + if(C == CDASH) { + state = ST_COMMENT_CLO_DASH2; + } + break; + case ST_COMMENT_CLO_DASH2: + if(C == CDASH) { + state = ST_COMMENT_CLO_RT; + } else { + /* This is not an end of a comment */ + state = ST_COMMENT; + } + break; + case ST_COMMENT_CLO_RT: + if(C == RANGLE) { + TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1); + } else if(C == CDASH) { + /* Maintain current state, still waiting for '>' */ + } else { + state = ST_COMMENT; + } + break; + } /* switch(*ptr) */ + } /* for() */ + + /* + * Flush the partially processed chunk, state permitting. + */ + if(p - chunk_start) { + switch (state) { + case ST_COMMENT: + TOKEN_CB(PXML_COMMENT, state, 0); + break; + case ST_TEXT: + TOKEN_CB(PXML_TEXT, state, 0); + break; + default: break; /* a no-op */ + } + } + +finish: + *stateContext = (int)state; + return chunk_start - (const char *)xmlbuf; +} + diff --git a/src/mms/iso_mms/asn1c/xer_support.h b/src/mms/iso_mms/asn1c/xer_support.h new file mode 100644 index 0000000..8b01944 --- /dev/null +++ b/src/mms/iso_mms/asn1c/xer_support.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_SUPPORT_H_ +#define _XER_SUPPORT_H_ + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Types of data transferred to the application. + */ +typedef enum { + PXML_TEXT, /* Plain text between XML tags. */ + PXML_TAG, /* A tag, starting with '<'. */ + PXML_COMMENT, /* An XML comment, including "". */ + /* + * The following chunk types are reported if the chunk + * terminates the specified XML element. + */ + PXML_TAG_END, /* Tag ended */ + PXML_COMMENT_END /* Comment ended */ +} pxml_chunk_type_e; + +/* + * Callback function that is called by the parser when parsed data is + * available. The _opaque is the pointer to a field containing opaque user + * data specified in pxml_create() call. The chunk type is _type and the text + * data is the piece of buffer identified by _bufid (as supplied to + * pxml_feed() call) starting at offset _offset and of _size bytes size. + * The chunk is NOT '\0'-terminated. + */ +typedef int (pxml_callback_f)(pxml_chunk_type_e _type, + const void *_chunk_data, size_t _chunk_size, void *_key); + +/* + * Parse the given buffer as it were a chunk of XML data. + * Invoke the specified callback each time the meaninful data is found. + * This function returns number of bytes consumed from the bufer. + * It will always be lesser than or equal to the specified _size. + * The next invocation of this function must account the difference. + */ +ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, + pxml_callback_f *cb, void *_key); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_SUPPORT_H_ */ diff --git a/src/mms/iso_mms/client/mms_client_common.c b/src/mms/iso_mms/client/mms_client_common.c new file mode 100644 index 0000000..9fd9470 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_common.c @@ -0,0 +1,60 @@ +/* + * mms_client_common.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "mms_client_internal.h" + +int +mmsClient_write_out(void *buffer, size_t size, void *app_key) +{ + ByteBuffer* writeBuffer = (ByteBuffer*) app_key; + return ByteBuffer_append(writeBuffer, (uint8_t*) buffer, size); +} + + +uint32_t +mmsClient_getInvokeId(ConfirmedResponsePdu_t* confirmedResponse) +{ + long invokeId; + + asn_INTEGER2long(&confirmedResponse->invokeID, &invokeId); + + return (uint32_t) invokeId; +} + + +MmsPdu_t* +mmsClient_createConfirmedRequestPdu(uint32_t invokeId) +{ + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); + mmsPdu->present = MmsPdu_PR_confirmedRequestPdu; + + asn_long2INTEGER(&(mmsPdu->choice.confirmedRequestPdu.invokeID), invokeId); + + return mmsPdu; +} diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c new file mode 100644 index 0000000..c91005c --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -0,0 +1,1913 @@ +/* + * mms_client_connection.c + * + * Copyright 2013, 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "mms_client_connection.h" +#include "iso_client_connection.h" +#include "mms_client_internal.h" +#include "stack_config.h" + +#include + +#include "byte_buffer.h" +#include "ber_decode.h" + +#include + +#define CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT 5000 +#define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000 +#define OUTSTANDING_CALLS 10 + +static void +handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) +{ + if (self->reportHandler != NULL) { + MmsPdu_t* mmsPdu = 0; /* allow asn1c to allocate structure */ + + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: report handler rcvd size:%i\n", ByteBuffer_getSize(message)); + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); + + if (rval.code == RC_OK) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: received report (size:%i)\n", (int) rval.consumed); + + if (mmsPdu->present == MmsPdu_PR_unconfirmedPDU) { + + if (mmsPdu->choice.unconfirmedPDU.unconfirmedService.present == + UnconfirmedService_PR_informationReport) + { + char* domainId = NULL; + + InformationReport_t* report = + &(mmsPdu->choice.unconfirmedPDU.unconfirmedService.choice.informationReport); + + if (report->variableAccessSpecification.present == + VariableAccessSpecification_PR_variableListName) + { + if (report->variableAccessSpecification.choice.variableListName.present + == ObjectName_PR_vmdspecific) + { + int nameSize = + report->variableAccessSpecification.choice.variableListName.choice.vmdspecific.size; + uint8_t* buffer = + report->variableAccessSpecification.choice.variableListName.choice.vmdspecific.buf; + + char* variableListName = createStringFromBuffer(buffer, nameSize); + + int listSize = report->listOfAccessResult.list.count; + + MmsValue* values = mmsClient_parseListOfAccessResults( + report->listOfAccessResult.list.array, listSize, true); + + self->reportHandler(self->reportHandlerParameter, domainId, variableListName, values, true); + + GLOBAL_FREEMEM(variableListName); + } + else { + // Ignore domain and association specific information reports (not used by IEC 61850) + } + + } + else if (report->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) + { + int listSize = report->listOfAccessResult.list.count; + int variableSpecSize = report->variableAccessSpecification.choice.listOfVariable.list.count; + + if (listSize != variableSpecSize) { + if (DEBUG_MMS_CLIENT) + printf("report contains wrong number of access results\n"); + return; + } + + MmsValue* values = mmsClient_parseListOfAccessResults( + report->listOfAccessResult.list.array, listSize, false); + + int i; + for (i = 0; i < variableSpecSize; i++) { + if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification.present + == VariableSpecification_PR_name) + { + if (report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) + { + int nameSize = + report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.choice.vmdspecific.size; + + uint8_t* buffer = + report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.choice.vmdspecific.buf; + + if (nameSize < 129) { + char variableListName[129]; + memcpy(variableListName, buffer, nameSize); + variableListName[nameSize] = 0; + + MmsValue* value = values; + + if (variableSpecSize != 1) + value = MmsValue_getElement(values, i); + + self->reportHandler(self->reportHandlerParameter, domainId, variableListName, + value, false); + + // report handler should have deleted the MmsValue! + if (variableSpecSize != 1) + MmsValue_setElement(values, i, NULL); + else + values = NULL; + } + } + else if (report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) { + + int domainNameSize = + report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.choice.domainspecific.domainId.size; + + int itemNameSize = + report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.choice.domainspecific.itemId.size; + + if (domainNameSize < 65 && itemNameSize < 65) { + char domainNameStr[65]; + char itemNameStr[65]; + + uint8_t* domainNameBuffer = + report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.choice.domainspecific.domainId.buf; + + uint8_t* itemNamebuffer = + report->variableAccessSpecification.choice.listOfVariable.list.array[i] + ->variableSpecification.choice.name.choice.domainspecific.itemId.buf; + + memcpy(domainNameStr, domainNameBuffer, domainNameSize); + domainNameStr[domainNameSize] = 0; + memcpy(itemNameStr, itemNamebuffer, itemNameSize); + itemNameStr[itemNameSize] = 0; + + MmsValue* value = values; + + if (variableSpecSize != 1) + value = MmsValue_getElement(values, i); + + self->reportHandler(self->reportHandlerParameter, domainNameStr, itemNameStr, + value, false); + + // report handler should have deleted the MmsValue! + if (variableSpecSize != 1) + MmsValue_setElement(values, i, NULL); + else + values = NULL; + + } + } + } + } + + if (values != NULL) + MmsValue_delete(values); + } + else { + // Ignore + if (DEBUG_MMS_CLIENT) + printf("unrecognized information report\n"); + } + + } + + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("handleUnconfirmedMmsPdu: error parsing PDU at %u\n", (uint32_t) rval.consumed); + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + } +} + +static uint32_t +getNextInvokeId(MmsConnection self) +{ + uint32_t nextInvokeId; + + Semaphore_wait(self->lastInvokeIdLock); + self->lastInvokeId++; + nextInvokeId = self->lastInvokeId; + Semaphore_post(self->lastInvokeIdLock); + + return nextInvokeId; +} + +static bool +checkForOutstandingCall(MmsConnection self, uint32_t invokeId) +{ + int i = 0; + + Semaphore_wait(self->outstandingCallsLock); + + for (i = 0; i < OUTSTANDING_CALLS; i++) { + if (self->outstandingCalls[i] == invokeId) { + Semaphore_post(self->outstandingCallsLock); + return true; + } + } + + Semaphore_post(self->outstandingCallsLock); + + return false; +} + +static bool +addToOutstandingCalls(MmsConnection self, uint32_t invokeId) +{ + int i = 0; + + Semaphore_wait(self->outstandingCallsLock); + + for (i = 0; i < OUTSTANDING_CALLS; i++) { + if (self->outstandingCalls[i] == 0) { + self->outstandingCalls[i] = invokeId; + Semaphore_post(self->outstandingCallsLock); + return true; + } + } + + Semaphore_post(self->outstandingCallsLock); + + return false; +} + +static void +removeFromOutstandingCalls(MmsConnection self, uint32_t invokeId) +{ + int i = 0; + + Semaphore_wait(self->outstandingCallsLock); + + for (i = 0; i < OUTSTANDING_CALLS; i++) { + if (self->outstandingCalls[i] == invokeId) { + self->outstandingCalls[i] = 0; + break; + } + } + + Semaphore_post(self->outstandingCallsLock); +} + +static ByteBuffer* +sendRequestAndWaitForResponse(MmsConnection self, uint32_t invokeId, ByteBuffer* message) +{ + ByteBuffer* receivedMessage = NULL; + + uint64_t startTime = Hal_getTimeInMs(); + + uint64_t waitUntilTime = startTime + self->requestTimeout; + + uint64_t currentTime = startTime; + + bool success = false; + + addToOutstandingCalls(self, invokeId); + + IsoClientConnection_sendMessage(self->isoClient, message); + + while (currentTime < waitUntilTime) { + uint32_t receivedInvokeId; + + if (self->associationState == MMS_STATE_CLOSED) + goto connection_lost; + + Semaphore_wait(self->lastResponseLock); + receivedInvokeId = self->responseInvokeId; + Semaphore_post(self->lastResponseLock); + + if (receivedInvokeId == invokeId) { + receivedMessage = self->lastResponse; + success = true; + break; + } + + Thread_sleep(10); + + currentTime = Hal_getTimeInMs(); + } + + if (!success) { + if (DEBUG_MMS_CLIENT) + printf("TIMEOUT for request %u: \n", invokeId); + self->lastResponseError = MMS_ERROR_SERVICE_TIMEOUT; + } + + connection_lost: + + removeFromOutstandingCalls(self, invokeId); + + return receivedMessage; +} + +static void +releaseResponse(MmsConnection self) +{ + Semaphore_wait(self->lastResponseLock); + self->responseInvokeId = 0; + self->lastResponseError = MMS_ERROR_NONE; + Semaphore_post(self->lastResponseLock); + + IsoClientConnection_releaseReceiveBuffer(self->isoClient); +} + +static uint32_t +getResponseInvokeId(MmsConnection self) +{ + uint32_t currentInvokeId; + + Semaphore_wait(self->lastResponseLock); + currentInvokeId = self->responseInvokeId; + Semaphore_post(self->lastResponseLock); + + return currentInvokeId; +} + +static void +waitUntilLastResponseHasBeenProcessed(MmsConnection self) +{ + uint32_t currentInvokeId = getResponseInvokeId(self); + + while (currentInvokeId != 0) { + Thread_sleep(1); + currentInvokeId = getResponseInvokeId(self); + } +} + +typedef struct sMmsServiceError +{ + int errorClass; + int errorCode; +} MmsServiceError; + +static MmsError +convertServiceErrorToMmsError(MmsServiceError serviceError) +{ + MmsError mmsError; + + switch (serviceError.errorClass) { + case 0: /* class: vmd-state */ + mmsError = MMS_ERROR_VMDSTATE_OTHER; + break; + + case 1: /* class: application-reference */ + mmsError = MMS_ERROR_APPLICATION_REFERENCE_OTHER; + break; + + case 2: /* class: definition */ + switch (serviceError.errorCode) { + case 1: + mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED; + break; + case 2: + mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS; + break; + case 3: + mmsError = MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED; + break; + case 4: + mmsError = MMS_ERROR_DEFINITION_TYPE_INCONSISTENT; + break; + case 5: + mmsError = MMS_ERROR_DEFINITION_OBJECT_EXISTS; + break; + case 6: + mmsError = MMS_ERROR_DEFINITION_OBJECT_ATTRIBUTE_INCONSISTENT; + break; + default: + mmsError = MMS_ERROR_DEFINITION_OTHER; + break; + } + break; + + case 3: /* class: resource */ + mmsError = MMS_ERROR_RESOURCE_OTHER; + break; + + case 4: /* class: service */ + mmsError = MMS_ERROR_SERVICE_OTHER; + break; + + case 5: /* class: service-preempt */ + mmsError = MMS_ERROR_SERVICE_PREEMPT_OTHER; + break; + + case 6: /* class: time-resolution */ + mmsError = MMS_ERROR_TIME_RESOLUTION_OTHER; + break; + + case 7: /* class: access */ + switch (serviceError.errorCode) { + case 1: + mmsError = MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED; + break; + case 2: + mmsError = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; + break; + case 3: + mmsError = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + break; + case 4: + mmsError = MMS_ERROR_ACCESS_OBJECT_INVALIDATED; + break; + default: + mmsError = MMS_ERROR_ACCESS_OTHER; + break; + } + break; + + case 11: /* class: file */ + switch (serviceError.errorCode) { + case 7: + mmsError = MMS_ERROR_FILE_FILE_NON_EXISTENT; + break; + default: + mmsError = MMS_ERROR_FILE_OTHER; + break; + } + break; + + + default: + mmsError = MMS_ERROR_OTHER; + } + + return mmsError; +} + +static int +parseServiceError(uint8_t* buffer, int bufPos, int maxLength, MmsServiceError* error) +{ + int endPos = bufPos + maxLength; + int length; + + while (bufPos < endPos) { + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos); + + if (bufPos < 0) + return -1; + + switch (tag) { + case 0xa0: /* errorClass */ + { + uint8_t errorClassTag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos); + + if (bufPos < 0) + return -1; + + error->errorClass = errorClassTag - 0x80; + error->errorCode = BerDecoder_decodeUint32(buffer, length, bufPos); + + bufPos += length; + } + break; + case 0x81: /* additionalCode */ + bufPos += length; /* ignore */ + break; + case 0x82: /* additionalDescription */ + bufPos += length; /* ignore */ + break; + case 0xa3: /* serviceSpecificInfo */ + bufPos += length; /* ignore */ + break; + default: + bufPos += length; /* ignore */ + break; + } + } + + return bufPos; +} + +static int +parseConfirmedErrorPDU(ByteBuffer* message, uint32_t* invokeId, MmsServiceError* serviceError) +{ + uint8_t* buffer = message->buffer; + int maxBufPos = message->size; + int bufPos = 0; + int length; + + uint8_t tag = buffer[bufPos++]; + if (tag != 0xa2) + goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) + goto exit_error; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("parseConfirmedErrorPDU: message to short!\n"); + goto exit_error; + } + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) + goto exit_error; + + switch (tag) { + case 0x80: /* invoke Id */ + if (invokeId != NULL) + *invokeId = BerDecoder_decodeUint32(buffer, length, bufPos); + bufPos += length; + break; + case 0x81: /* modifierPosition */ + bufPos += length; /* ignore */ + break; + case 0xa2: /* serviceError */ + bufPos = parseServiceError(buffer, bufPos, length, serviceError); + if (bufPos < 0) + goto exit_error; + break; + default: + bufPos += length; /* ignore */ + break; + } + } + + return bufPos; + +exit_error: + return -1; +} + +static void +mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) +{ + MmsConnection self = (MmsConnection) parameter; + + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsIsoCallback called with indication %i\n", indication); + + if (indication == ISO_IND_CLOSED) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n"); + self->connectionState = MMS_CON_IDLE; + self->associationState = MMS_STATE_CLOSED; + + /* Call user provided callback function */ + if (self->connectionLostHandler != NULL) + self->connectionLostHandler(self, self->connectionLostHandlerParameter); + + return; + } + + if (indication == ISO_IND_ASSOCIATION_FAILED) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mmsIsoCallback: association failed!\n"); + self->connectionState = MMS_CON_ASSOCIATION_FAILED; + self->associationState = MMS_STATE_CLOSED; + return; + } + + if (payload != NULL) { + if (ByteBuffer_getSize(payload) < 1) { + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + return; + } + } + + uint8_t* buf = ByteBuffer_getBuffer(payload); + + uint8_t tag = buf[0]; + + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: MMS-PDU: %02x\n", tag); + + if (tag == 0xa9) { /* initiate response PDU */ + if (indication == ISO_IND_ASSOCIATION_SUCCESS) { + self->connectionState = MMS_CON_ASSOCIATED; + } + else { + self->connectionState = MMS_CON_ASSOCIATION_FAILED; + } + self->lastResponse = payload; + + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + } + else if (tag == 0xa3) { /* unconfirmed PDU */ + handleUnconfirmedMmsPdu(self, payload); + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + } + else if (tag == 0x8b) { /* conclude request PDU */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: received conclude.request\n"); + + self->concludeState = CONCLUDE_STATE_REQUESTED; + + /* TODO block all new user requests */ + + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + } + else if (tag == 0x8c) { /* conclude response PDU */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: received conclude.reponse+\n"); + + self->concludeState = CONCLUDE_STATE_ACCEPTED; + + IsoClientConnection_release(self->isoClient); + + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + } + else if (tag == 0x8d) { /* conclude error PDU */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: received conclude.reponse-\n"); + + self->concludeState = CONCLUDE_STATE_REJECTED; + + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + } + else if (tag == 0xa2) { /* confirmed error PDU */ + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: Confirmed error PDU!\n"); + uint32_t invokeId; + MmsServiceError serviceError = {0, 0}; + + if (parseConfirmedErrorPDU(payload, &invokeId, &serviceError) < 0) { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: Error parsing confirmedErrorPDU!\n"); + } + else { + if (checkForOutstandingCall(self, invokeId)) { + + waitUntilLastResponseHasBeenProcessed(self); + + Semaphore_wait(self->lastResponseLock); + self->lastResponseError = convertServiceErrorToMmsError(serviceError); + self->responseInvokeId = invokeId; + Semaphore_post(self->lastResponseLock); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: unexpected message from server!\n"); + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + return; + } + } + } + else if (tag == 0xa1) { /* confirmed response PDU */ + + int length; + int bufPos = 1; + + bufPos = BerDecoder_decodeLength(buf, &length, bufPos, payload->size); + if (bufPos == -1) + goto exit_with_error; + + if (buf[bufPos++] == 0x02) { + int invokeIdLength; + + bufPos = BerDecoder_decodeLength(buf, &invokeIdLength, bufPos, payload->size); + if (bufPos == -1) + goto exit_with_error; + + uint32_t invokeId = + BerDecoder_decodeUint32(buf, invokeIdLength, bufPos); + + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: mms_client_connection: rcvd confirmed resp - invokeId: %i length: %i bufLen: %i\n", + invokeId, length, payload->size); + + bufPos += invokeIdLength; + + if (checkForOutstandingCall(self, invokeId)) { + + waitUntilLastResponseHasBeenProcessed(self); + + Semaphore_wait(self->lastResponseLock); + self->lastResponse = payload; + self->lastResponseBufPos = bufPos; + self->responseInvokeId = invokeId; + Semaphore_post(self->lastResponseLock); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: unexpected message from server!\n"); + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + return; + } + } + else + goto exit_with_error; + } + + if (DEBUG_MMS_CLIENT) + printf("MMS_CLIENT: LEAVE mmsIsoCallback - OK\n"); + + return; + + exit_with_error: + + if (DEBUG_MMS_CLIENT) + printf("received malformed message from server!\n"); + IsoClientConnection_releaseReceiveBuffer(self->isoClient); + + + if (DEBUG_MMS_CLIENT) + printf("LEAVE mmsIsoCallback - NOT OK!\n"); + return; +} + +MmsConnection +MmsConnection_create() +{ + MmsConnection self = (MmsConnection) GLOBAL_CALLOC(1, sizeof(struct sMmsConnection)); + + self->parameters.dataStructureNestingLevel = -1; + self->parameters.maxServOutstandingCalled = -1; + self->parameters.maxServOutstandingCalling = -1; + self->parameters.maxPduSize = -1; + + self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE; + + self->requestTimeout = CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT; + + self->lastInvokeIdLock = Semaphore_create(1); + self->lastResponseLock = Semaphore_create(1); + self->outstandingCallsLock = Semaphore_create(1); + + self->lastResponseError = MMS_ERROR_NONE; + + self->outstandingCalls = (uint32_t*) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(uint32_t)); + + self->isoParameters = IsoConnectionParameters_create(); + + /* Load default values for connection parameters */ + TSelector selector1 = { 2, { 0, 1 } }; + TSelector selector2 = { 2, { 0, 1 } }; + + IsoConnectionParameters_setLocalAddresses(self->isoParameters, 1, 1, selector1); + IsoConnectionParameters_setLocalApTitle(self->isoParameters, "1.1.1.999", 12); + IsoConnectionParameters_setRemoteAddresses(self->isoParameters, 1, 1, selector2); + IsoConnectionParameters_setRemoteApTitle(self->isoParameters, "1.1.1.999.1", 12); + + self->connectTimeout = CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT; + + self->isoClient = IsoClientConnection_create((IsoIndicationCallback) mmsIsoCallback, (void*) self); + + return self; +} + +void +MmsConnection_destroy(MmsConnection self) +{ + if (self->isoClient != NULL) + IsoClientConnection_destroy(self->isoClient); + + if (self->isoParameters != NULL) + IsoConnectionParameters_destroy(self->isoParameters); + + Semaphore_destroy(self->lastInvokeIdLock); + Semaphore_destroy(self->lastResponseLock); + Semaphore_destroy(self->outstandingCallsLock); + + GLOBAL_FREEMEM(self->outstandingCalls); + + GLOBAL_FREEMEM(self); +} + +void +MmsConnection_setConnectionLostHandler(MmsConnection self, MmsConnectionLostHandler handler, void* handlerParameter) +{ + self->connectionLostHandler = handler; + self->connectionLostHandlerParameter = handlerParameter; +} + +void +MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs) +{ + self->requestTimeout = timeoutInMs; +} + +void +MmsConnection_setConnectTimeout(MmsConnection self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + +void +MmsConnection_setLocalDetail(MmsConnection self, int32_t localDetail) +{ + self->parameters.maxPduSize = localDetail; +} + +int32_t +MmsConnection_getLocalDetail(MmsConnection self) +{ + return self->parameters.maxPduSize; +} + +IsoConnectionParameters +MmsConnection_getIsoConnectionParameters(MmsConnection self) +{ + return self->isoParameters; +} + +static void +waitForConnectResponse(MmsConnection self) +{ + uint64_t startTime = Hal_getTimeInMs(); + + uint64_t waitUntilTime = startTime + self->requestTimeout; + + uint64_t currentTime = startTime; + + while (currentTime < waitUntilTime) { + if (self->connectionState != MMS_CON_WAITING) + break; + + Thread_sleep(10); + + currentTime = Hal_getTimeInMs(); + } + +} + +bool +MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort) +{ + IsoConnectionParameters_setTcpParameters(self->isoParameters, serverName, serverPort); + + if (self->parameters.maxPduSize == -1) + self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE; + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + mmsClient_createInitiateRequest(self, payload); + + self->connectionState = MMS_CON_WAITING; + + IsoClientConnection_associate(self->isoClient, self->isoParameters, payload, + self->connectTimeout); + + waitForConnectResponse(self); + + if (DEBUG_MMS_CLIENT) + printf("MmsConnection_connect: received response conState: %i\n", self->connectionState); + + if (self->connectionState == MMS_CON_ASSOCIATED) { + mmsClient_parseInitiateResponse(self); + + releaseResponse(self); + + self->associationState = MMS_STATE_CONNECTED; + } + else { + self->associationState = MMS_STATE_CLOSED; + } + + self->connectionState = MMS_CON_IDLE; + + if (DEBUG_MMS_CLIENT) + printf("MmsConnection_connect: states: con %i ass %i\n", self->connectionState, self->associationState); + + if (self->associationState == MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_NONE; + return true; + } + else { + *mmsError = MMS_ERROR_CONNECTION_REJECTED; + return false; + } +} + +void +MmsConnection_close(MmsConnection self) +{ + self->connectionLostHandler = NULL; + + if (self->associationState == MMS_STATE_CONNECTED) + IsoClientConnection_close(self->isoClient); +} + +void +MmsConnection_abort(MmsConnection self, MmsError* mmsError) +{ + *mmsError = MMS_ERROR_NONE; + + self->connectionLostHandler = NULL; + + bool success = true; + + if (self->associationState == MMS_STATE_CONNECTED) + success = IsoClientConnection_abort(self->isoClient); + + if (success == false) { + IsoClientConnection_close(self->isoClient); + *mmsError = MMS_ERROR_SERVICE_TIMEOUT; + } +} + +static void +sendConcludeRequestAndWaitForResponse(MmsConnection self) +{ + uint64_t startTime = Hal_getTimeInMs(); + + uint64_t waitUntilTime = startTime + self->requestTimeout; + + uint64_t currentTime = startTime; + + bool success = false; + + ByteBuffer* concludeMessage = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + mmsClient_createConcludeRequest(self, concludeMessage); + + self->concludeState = CONCLUDE_STATE_REQUESTED; + + IsoClientConnection_sendMessage(self->isoClient, concludeMessage); + + while (currentTime < waitUntilTime) { + + if (self->associationState == MMS_STATE_CLOSED) + goto exit_function; + + if (self->concludeState != CONCLUDE_STATE_REQUESTED) { + success = true; + break; + } + + Thread_sleep(1); + + currentTime = Hal_getTimeInMs(); + } + + if (!success) { + if (DEBUG_MMS_CLIENT) + printf("TIMEOUT for conclude request\n"); + self->lastResponseError = MMS_ERROR_SERVICE_TIMEOUT; + } + +exit_function: + return; +} + +void +MmsConnection_conclude(MmsConnection self, MmsError* mmsError) +{ + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + *mmsError = MMS_ERROR_NONE; + + sendConcludeRequestAndWaitForResponse(self); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + + releaseResponse(self); + + if (self->concludeState != CONCLUDE_STATE_ACCEPTED) { + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + + if (self->concludeState == CONCLUDE_STATE_REJECTED) + *mmsError = MMS_ERROR_CONCLUDE_REJECTED; + } + + self->connectionLostHandler = NULL; + +exit_function: + return; +} + +void +MmsConnection_setInformationReportHandler(MmsConnection self, MmsInformationReportHandler handler, + void* parameter) +{ + self->reportHandler = handler; + self->reportHandlerParameter = parameter; +} + +static bool +mmsClient_getNameListSingleRequest( + LinkedList* nameList, + MmsConnection self, + MmsError* mmsError, + const char* domainId, + MmsObjectClass objectClass, + bool associationSpecific, + const char* continueAfter) +{ + bool moreFollows = false; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + if (associationSpecific) + mmsClient_createMmsGetNameListRequestAssociationSpecific(invokeId, + payload, continueAfter); + else { + + if (objectClass == MMS_DOMAIN_NAMES) + mmsClient_createMmsGetNameListRequestVMDspecific(invokeId, + payload, continueAfter); + else + mmsClient_createGetNameListRequestDomainOrVMDSpecific(invokeId, domainId, + payload, objectClass, continueAfter); + } + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (responseMessage != NULL) + moreFollows = mmsClient_parseGetNameListResponse(nameList, self->lastResponse, NULL); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return moreFollows; +} + +static LinkedList /* */ +mmsClient_getNameList(MmsConnection self, MmsError *mmsError, + const char* domainId, + MmsObjectClass objectClass, + bool associationSpecific) +{ + LinkedList list = NULL; + + bool moreFollows; + + moreFollows = mmsClient_getNameListSingleRequest(&list, self, mmsError, domainId, + objectClass, associationSpecific, NULL); + + while ((moreFollows == true) && (list != NULL)) { + LinkedList lastElement = LinkedList_getLastElement(list); + + char* lastIdentifier = (char*) lastElement->data; + + if (DEBUG_MMS_CLIENT) + printf("getNameList: identifier: %s\n", lastIdentifier); + + moreFollows = mmsClient_getNameListSingleRequest(&list, self, mmsError, domainId, + objectClass, associationSpecific, lastIdentifier); + } + + return list; +} + +LinkedList /* */ +MmsConnection_getVMDVariableNames(MmsConnection self, MmsError* mmsError) +{ + return mmsClient_getNameList(self, mmsError, NULL, MMS_NAMED_VARIABLE, false); +} + +LinkedList /* */ +MmsConnection_getDomainNames(MmsConnection self, MmsError* mmsError) +{ + return mmsClient_getNameList(self, mmsError, NULL, MMS_DOMAIN_NAMES, false); +} + +LinkedList /* */ +MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, const char* domainId) +{ + return mmsClient_getNameList(self, mmsError, domainId, MMS_NAMED_VARIABLE, false); +} + +LinkedList /* */ +MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, const char* domainId) +{ + return mmsClient_getNameList(self, mmsError, domainId, MMS_NAMED_VARIABLE_LIST, false); +} + +LinkedList /* */ +MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsError* mmsError) +{ + return mmsClient_getNameList(self, mmsError, NULL, MMS_NAMED_VARIABLE_LIST, true); +} + +MmsValue* +MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId) +{ + MmsValue* value = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createReadRequest(invokeId, domainId, itemId, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + value = mmsClient_parseReadResponse(self->lastResponse, NULL, false); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return value; +} + +MmsValue* +MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, + uint32_t startIndex, uint32_t numberOfElements) +{ + MmsValue* value = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createReadRequestAlternateAccessIndex(invokeId, domainId, itemId, startIndex, + numberOfElements, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + value = mmsClient_parseReadResponse(self->lastResponse, NULL, false); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return value; +} + +MmsValue* +MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, + const char* domainId, LinkedList /**/items) +{ + MmsValue* value = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createReadRequestMultipleValues(invokeId, domainId, items, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + value = mmsClient_parseReadResponse(self->lastResponse, NULL, true); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return value; +} + +MmsValue* +MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* listName, + bool specWithResult) +{ + MmsValue* value = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createReadNamedVariableListRequest(invokeId, domainId, listName, + payload, specWithResult); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) { + *mmsError = self->lastResponseError; + } + else if (responseMessage != NULL) { + value = mmsClient_parseReadResponse(self->lastResponse, NULL, true); + } + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return value; +} + +MmsValue* +MmsConnection_readNamedVariableListValuesAssociationSpecific( + MmsConnection self, MmsError* mmsError, + const char* listName, + bool specWithResult) +{ + MmsValue* value = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createReadAssociationSpecificNamedVariableListRequest(invokeId, listName, + payload, specWithResult); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + value = mmsClient_parseReadResponse(self->lastResponse, NULL, true); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return value; +} + +LinkedList /* */ +MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* listName, bool* deletable) +{ + LinkedList attributes = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createGetNamedVariableListAttributesRequest(invokeId, payload, domainId, + listName); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + attributes = mmsClient_parseGetNamedVariableListAttributesResponse(self->lastResponse, NULL, + deletable); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return attributes; +} + +LinkedList /* */ +MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection self, MmsError* mmsError, + const char* listName, bool* deletable) +{ + LinkedList attributes = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(invokeId, payload, + listName); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + attributes = mmsClient_parseGetNamedVariableListAttributesResponse(self->lastResponse, NULL, + deletable); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return attributes; +} + +void +MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* listName, LinkedList variableSpecs) +{ + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createDefineNamedVariableListRequest(invokeId, payload, domainId, + listName, variableSpecs, false); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + if (!mmsClient_parseDefineNamedVariableResponse(self->lastResponse, NULL)) + *mmsError = MMS_ERROR_DEFINITION_OTHER; + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return; +} + +void +MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self, + MmsError* mmsError, const char* listName, LinkedList variableSpecs) +{ + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createDefineNamedVariableListRequest(invokeId, payload, NULL, + listName, variableSpecs, true); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + if (!mmsClient_parseDefineNamedVariableResponse(self->lastResponse, NULL)) + *mmsError = MMS_ERROR_DEFINITION_OTHER; + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return; +} + +void +MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* listName) +{ + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createDeleteNamedVariableListRequest(invokeId, payload, domainId, listName); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + if (!mmsClient_parseDeleteNamedVariableListResponse(self->lastResponse, NULL)) + *mmsError = MMS_ERROR_ACCESS_OTHER; + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return; +} + +void +MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self, + MmsError* mmsError, const char* listName) +{ + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createDeleteAssociationSpecificNamedVariableListRequest( + invokeId, payload, listName); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + if (!mmsClient_parseDeleteNamedVariableListResponse(self->lastResponse, NULL)) + *mmsError = MMS_ERROR_ACCESS_OTHER; + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return; +} + +MmsVariableSpecification* +MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId) +{ + MmsVariableSpecification* typeSpec = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createGetVariableAccessAttributesRequest(invokeId, domainId, itemId, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + typeSpec = mmsClient_parseGetVariableAccessAttributesResponse(self->lastResponse, NULL); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return typeSpec; +} + +MmsServerIdentity* +MmsConnection_identify(MmsConnection self, MmsError* mmsError) +{ + MmsServerIdentity* identity = NULL; + + if (self->associationState != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createIdentifyRequest(invokeId, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + identity = mmsClient_parseIdentifyResponse(self); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + +exit_function: + return identity; +} + +void +MmsConnection_getServerStatus(MmsConnection self, MmsError* mmsError, int* vmdLogicalStatus, int* vmdPhysicalStatus, + bool extendedDerivation) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createStatusRequest(invokeId, payload, extendedDerivation); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) { + if (mmsClient_parseStatusResponse(self, vmdLogicalStatus, vmdPhysicalStatus) == false) + *mmsError = MMS_ERROR_PARSING_RESPONSE; + } + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + + +} + + +int32_t +MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filename, uint32_t initialPosition, + uint32_t* fileSize, uint64_t* lastModified) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + int32_t frsmId = -1; + + mmsClient_createFileOpenRequest(invokeId, payload, filename, initialPosition); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) { + if (mmsClient_parseFileOpenResponse(self, &frsmId, fileSize, lastModified) == false) + *mmsError = MMS_ERROR_PARSING_RESPONSE; + } + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + + return frsmId; +} + +void +MmsConnection_fileClose(MmsConnection self, MmsError* mmsError, int32_t frsmId) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createFileCloseRequest(invokeId, payload, frsmId); + + sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + + /* nothing to do - response contains no data to evaluate */ + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; +} + +void +MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, const char* fileName) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createFileDeleteRequest(invokeId, payload, fileName); + + + sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + + /* nothing to do - response contains no data to evaluate */ + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; +} + +bool +MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, MmsFileReadHandler handler, + void* handlerParameter) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + bool moreFollows = false; + mmsClient_createFileReadRequest(invokeId, payload, frsmId); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) { + if (mmsClient_parseFileReadResponse(self, frsmId, &moreFollows, handler, handlerParameter) == false) + *mmsError = MMS_ERROR_PARSING_RESPONSE; + } + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + + return moreFollows; +} + + +bool +MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, const char* fileSpecification, const char* continueAfter, + MmsFileDirectoryHandler handler, void* handlerParameter) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createFileDirectoryRequest(invokeId, payload, fileSpecification, continueAfter); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + bool moreFollows = false; + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) { + if (mmsClient_parseFileDirectoryResponse(self, handler, handlerParameter, &moreFollows) == false) + *mmsError = MMS_ERROR_PARSING_RESPONSE; + } + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; + + return moreFollows; +} + +void +MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, const char* currentFileName, const char* newFileName) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createFileRenameRequest(invokeId, payload, currentFileName, newFileName); + + sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + + /* nothing to do - response contains no data to evaluate */ + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; +} + + +void +MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, + MmsValue* value) +{ + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createWriteRequest(invokeId, domainId, itemId, value, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) + mmsClient_parseWriteResponse(self->lastResponse, self->lastResponseBufPos, mmsError); + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; +} + +void +MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId, + LinkedList /**/items, + LinkedList /* */values, + /* OUTPUT */LinkedList* /* */accessResults) +{ + *mmsError = MMS_ERROR_NONE; + + uint32_t invokeId = getNextInvokeId(self); + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + mmsClient_createWriteMultipleItemsRequest(invokeId, domainId, items, values, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload); + + if (self->lastResponseError != MMS_ERROR_NONE) + *mmsError = self->lastResponseError; + else if (responseMessage != NULL) { + + int numberOfItems = LinkedList_size(items); + + mmsClient_parseWriteMultipleItemsResponse(self->lastResponse, self->lastResponseBufPos, mmsError, + numberOfItems, accessResults); + } + + releaseResponse(self); + + if (self->associationState == MMS_STATE_CLOSED) + *mmsError = MMS_ERROR_CONNECTION_LOST; +} + +void +MmsServerIdentity_destroy(MmsServerIdentity* self) +{ + if (self->modelName != NULL) + GLOBAL_FREEMEM(self->modelName); + + if (self->vendorName != NULL) + GLOBAL_FREEMEM(self->vendorName); + + if (self->revision != NULL) + GLOBAL_FREEMEM(self->revision); + + GLOBAL_FREEMEM(self); +} + +MmsVariableAccessSpecification* +MmsVariableAccessSpecification_create(char* domainId, char* itemId) +{ + MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*) + GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification)); + + self->domainId = domainId; + self->itemId = itemId; + self->arrayIndex = -1; + self->componentName = NULL; + + return self; +} + +MmsVariableAccessSpecification* +MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemId, int32_t index, + char* componentName) +{ + MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*) + GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification)); + + self->domainId = domainId; + self->itemId = itemId; + self->arrayIndex = index; + self->componentName = componentName; + + return self; +} + +void +MmsVariableAccessSpecification_destroy(MmsVariableAccessSpecification* self) +{ + if (self->domainId != NULL) + GLOBAL_FREEMEM((void*) self->domainId); + + if (self->itemId != NULL) + GLOBAL_FREEMEM((void*) self->itemId); + + if (self->componentName != NULL) + GLOBAL_FREEMEM((void*) self->componentName); + + GLOBAL_FREEMEM(self); +} + diff --git a/src/mms/iso_mms/client/mms_client_files.c b/src/mms/iso_mms/client/mms_client_files.c new file mode 100644 index 0000000..17c0790 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_files.c @@ -0,0 +1,559 @@ +/* + * mms_client_files.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "mms_client_internal.h" +#include "ber_encoder.h" +#include "ber_decode.h" +#include "conversions.h" + +void +mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName, uint32_t initialPosition) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + + uint32_t fileNameStringSize = strlen(fileName); + uint32_t fileNameSize = 1+ BerEncoder_determineLengthSize(fileNameStringSize) + fileNameStringSize; + + uint32_t fileNameSeqSize = fileNameSize; + + uint32_t fileOpenRequestSize = fileNameSeqSize + 2 + BerEncoder_UInt32determineEncodedSize(initialPosition) + 2; + + uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + fileOpenRequestSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* Encode FileOpen tag (context | structured ) [72 = 48h] */ + buffer[bufPos++] = 0xbf; + buffer[bufPos++] = 0x48; + bufPos = BerEncoder_encodeLength(fileOpenRequestSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, fileNameSeqSize, buffer, bufPos); + + bufPos = BerEncoder_encodeOctetString(0x19, (uint8_t*) fileName, fileNameStringSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32WithTL(0x81, initialPosition, buffer, bufPos); + + request->size = bufPos; +} + +void +mmsClient_createFileDeleteRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + + uint32_t fileNameStringSize = strlen(fileName); + uint32_t fileNameSize = 1 + BerEncoder_determineLengthSize(fileNameStringSize) + fileNameStringSize; + + uint32_t fileNameSeqSize = fileNameSize; + + uint32_t fileDeleteRequestSize = fileNameSeqSize; // + 2; + + uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + fileDeleteRequestSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* Encode FileOpen tag (context | structured ) [76 = 4ch] */ + buffer[bufPos++] = 0xbf; + buffer[bufPos++] = 0x4c; + + bufPos = BerEncoder_encodeLength(fileDeleteRequestSize, buffer, bufPos); + bufPos = BerEncoder_encodeOctetString(0x19, (uint8_t*) fileName, fileNameStringSize, buffer, bufPos); + + request->size = bufPos; +} + +void +mmsClient_createFileReadRequest(uint32_t invokeId, ByteBuffer* request, int32_t frsmId) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + + uint32_t frsmIdSize = BerEncoder_UInt32determineEncodedSize(frsmId); + + uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + frsmIdSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* Encode FileRead tag (context | primitive ) [73 = 49h] */ + buffer[bufPos++] = 0x9f; + buffer[bufPos++] = 0x49; + bufPos = BerEncoder_encodeLength(frsmIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(frsmId, buffer, bufPos); + + request->size = bufPos; +} + +static int +encodeFileSpecification(uint8_t tag, const char* fileSpecification, uint8_t* buffer, int bufPos) +{ + uint32_t fileNameStringSize = strlen(fileSpecification); + uint32_t fileNameSeqSize = 1 + BerEncoder_determineLengthSize(fileNameStringSize) + fileNameStringSize; + + if (buffer != NULL) { + + bufPos = BerEncoder_encodeTL(tag, fileNameSeqSize, buffer, bufPos); + bufPos = BerEncoder_encodeOctetString(0x19, (uint8_t*) fileSpecification, fileNameStringSize, buffer, bufPos); + + return bufPos; + } + else { + return fileNameSeqSize + 1 + BerEncoder_determineLengthSize(fileNameSeqSize); + } +} + +void +mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, const char* fileSpecification, const char* continueAfter) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + + uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + 0; + + uint32_t parameterSize = 0; + + if (fileSpecification) + parameterSize += encodeFileSpecification(0xa0, fileSpecification, NULL, 0); + + if (continueAfter) + parameterSize += encodeFileSpecification(0xa1, continueAfter, NULL, 0); + + confirmedRequestPduSize += parameterSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* Encode FileRead tag (context | structured ) [77 = 4dh] */ + buffer[bufPos++] = 0xbf; + buffer[bufPos++] = 0x4d; + bufPos = BerEncoder_encodeLength(parameterSize, buffer, bufPos); + + if (fileSpecification) + bufPos = encodeFileSpecification(0xa0, fileSpecification, buffer, bufPos); + + if (continueAfter) + bufPos = encodeFileSpecification(0xa1, continueAfter, buffer, bufPos); + + request->size = bufPos; +} + + +void +mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, const char* currentFileName, const char* newFileName) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + + uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + 0; + + uint32_t parameterSize = 0; + + parameterSize += encodeFileSpecification(0xa0, currentFileName, NULL, 0); + + parameterSize += encodeFileSpecification(0xa1, newFileName, NULL, 0); + + confirmedRequestPduSize += parameterSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* Encode FileRead tag (context | structured ) [75 = 4bh] */ + buffer[bufPos++] = 0xbf; + buffer[bufPos++] = 0x4b; + bufPos = BerEncoder_encodeLength(parameterSize, buffer, bufPos); + + bufPos = encodeFileSpecification(0xa0, currentFileName, buffer, bufPos); + + bufPos = encodeFileSpecification(0xa1, newFileName, buffer, bufPos); + + request->size = bufPos; +} + +static bool +parseFileAttributes(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* fileSize, uint64_t* lastModified) +{ + int endPos = maxBufPos; + + while (bufPos < endPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos); + if (bufPos < 0) + return false; + + switch (tag) { + case 0x80: /* sizeOfFile */ + if (fileSize != NULL) + *fileSize = BerDecoder_decodeUint32(buffer, length, bufPos); + break; + case 0x81: /* lastModified */ + { + if (lastModified != NULL) { + char gtString[40]; + memcpy(gtString, buffer + bufPos, length); + gtString[length] = 0; + *lastModified = Conversions_generalizedTimeToMsTime(gtString); + } + } + break; + default: + return false; + } + + bufPos += length; + } + + return true; +} + +static bool +parseDirectoryEntry(uint8_t* buffer, int bufPos, int maxBufPos, MmsFileDirectoryHandler handler, void* handlerParameter) +{ + char fileNameMemory[400]; + char* filename = NULL; + uint32_t fileSize = 0; + uint64_t lastModified = 0; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0xa0: /* file-name */ + + filename = fileNameMemory; + + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + memcpy(filename, buffer + bufPos, length); + filename[length] = 0; + + bufPos += length; + break; + case 0xa1: /* file-attributes */ + if (!parseFileAttributes(buffer, bufPos, bufPos + length, &fileSize, &lastModified)) + return false; + bufPos += length; + break; + default: + bufPos += length; + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileDirectoryResponse: message contains unknown tag!\n"); + + return false; + } + } + + if (filename != NULL) + handler(handlerParameter, filename, fileSize, lastModified); + else + return false; + + return true; +} + +static bool +parseListOfDirectoryEntries(uint8_t* buffer, int bufPos, int maxBufPos, + MmsFileDirectoryHandler handler, void* handlerParameter) +{ + uint8_t tag = buffer[bufPos++]; + + if (tag != 0x30) + return false; + + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) return false; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("parseListOfDirectoryEntries: message to short!\n"); + return false; + } + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0x30: /* Sequence */ + parseDirectoryEntry(buffer, bufPos, bufPos + length, handler, handlerParameter); + bufPos += length; + break; + default: + bufPos += length; + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileDirectoryResponse: message contains unknown tag!\n"); + return false; + } + } + + return true; +} + + +bool +mmsClient_parseFileDirectoryResponse(MmsConnection self, MmsFileDirectoryHandler handler, void* handlerParameter, + bool* moreFollows) +{ + uint8_t* buffer = self->lastResponse->buffer; + int maxBufPos = self->lastResponse->size; + int bufPos = self->lastResponseBufPos; + int length; + + uint8_t tag = buffer[bufPos++]; + + if (tag != 0xbf) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileDirectoryResponse: unknown tag %02x\n", tag); + return false; + } + + tag = buffer[bufPos++]; + + if (tag != 0x4d) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileDirectoryResponse: unknown tag %02x\n", tag); + return false; + } + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) return false; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileDirectoryResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos); + return false; + } + + *moreFollows = false; + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0xa0: /* listOfDirectoryEntries */ + parseListOfDirectoryEntries(buffer, bufPos, bufPos + length, handler, handlerParameter); + + bufPos += length; + break; + case 0x81: /* moreFollows */ + *moreFollows = BerDecoder_decodeBoolean(buffer, bufPos); + bufPos += length; + break; + default: + bufPos += length; + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileDirectoryResponse: message contains unknown tag!\n"); + break; + } + } + + return true; +} + +bool +mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified) +{ + uint8_t* buffer = self->lastResponse->buffer; + int maxBufPos = self->lastResponse->size; + int bufPos = self->lastResponseBufPos; + int length; + + uint8_t tag = buffer[bufPos++]; + + if (tag != 0xbf) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileOpenResponse: unknown tag %02x\n", tag); + return false; + } + + tag = buffer[bufPos++]; + + if (tag != 0x48) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileOpenResponse: unknown tag %02x\n", tag); + return false; + } + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) + return false; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileOpenResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos); + return false; + } + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0x80: /* frsmId */ + *frsmId = (int32_t) BerDecoder_decodeUint32(buffer, length, bufPos); + + bufPos += length; + break; + case 0xa1: /* fileAttributes */ + if (!parseFileAttributes(buffer, bufPos, bufPos + length, fileSize, lastModified)) + return false; + bufPos += length; + break; + default: + bufPos += length; + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileOpenResponse: message contains unknown tag %02x!\n", tag); + break; + } + } + + return true; +} + + +bool +mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreFollows, MmsFileReadHandler handler, void* handlerParameter) +{ + uint8_t* buffer = self->lastResponse->buffer; + int maxBufPos = self->lastResponse->size; + int bufPos = self->lastResponseBufPos; + int length; + + uint8_t tag = buffer[bufPos++]; + + if (tag != 0xbf) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileReadResponse: unknown tag %02x\n", tag); + return false; + } + + tag = buffer[bufPos++]; + + *moreFollows = true; + + if (tag != 0x49) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileReadResponse: unknown tag %02x\n", tag); + return false; + } + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) + return false; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileReadResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos); + return false; + } + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0x80: /* fileData */ + handler(handlerParameter, frsmId, buffer + bufPos, length); + + bufPos += length; + break; + case 0x81: /* moreFollows */ + *moreFollows = BerDecoder_decodeBoolean(buffer, bufPos); + bufPos += length; + break; + default: + bufPos += length; + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseFileReadResponse: message contains unknown tag %02x!\n", tag); + + return false; + } + } + + return true; +} + +void +mmsClient_createFileCloseRequest(uint32_t invokeId, ByteBuffer* request, int32_t frsmId) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + + uint32_t frsmIdSize = BerEncoder_UInt32determineEncodedSize(frsmId); + + uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + frsmIdSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* Encode FileClose tag (context | primitive) [74 = 4ah] */ + buffer[bufPos++] = 0x9f; + buffer[bufPos++] = 0x4a; + bufPos = BerEncoder_encodeLength(frsmIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(frsmId, buffer, bufPos); + + request->size = bufPos; +} + + diff --git a/src/mms/iso_mms/client/mms_client_get_namelist.c b/src/mms/iso_mms/client/mms_client_get_namelist.c new file mode 100644 index 0000000..b0b03b7 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_get_namelist.c @@ -0,0 +1,250 @@ +/* + * mms_client_get_namelist.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "stack_config.h" +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" +#include "mms_client_internal.h" + +#include "ber_decode.h" + +int +mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writeBuffer, + const char* continueAfter) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_getNameList; + + GetNameListRequest_t* request; + + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList); + + if (continueAfter != NULL) { + request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); + request->continueAfter->buf = (uint8_t*) copyString(continueAfter); + request->continueAfter->size = strlen(continueAfter); + } + else + request->continueAfter = NULL; + + request->objectScope.present = GetNameListRequest__objectScope_PR_vmdSpecific; + request->objectClass.present = ObjectClass_PR_basicObjectClass; + + asn_long2INTEGER(&request->objectClass.choice.basicObjectClass, + ObjectClass__basicObjectClass_domain); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +int +mmsClient_createMmsGetNameListRequestAssociationSpecific(long invokeId, ByteBuffer* writeBuffer, + const char* continueAfter) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_getNameList; + + GetNameListRequest_t* request; + + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList); + + + if (continueAfter != NULL) { + request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); + request->continueAfter->buf = (uint8_t*) copyString(continueAfter); + request->continueAfter->size = strlen(continueAfter); + } + else + request->continueAfter = NULL; + + + request->objectScope.present = GetNameListRequest__objectScope_PR_aaSpecific; + request->objectClass.present = ObjectClass_PR_basicObjectClass; + + asn_long2INTEGER(&request->objectClass.choice.basicObjectClass, + ObjectClass__basicObjectClass_namedVariableList); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +bool +mmsClient_parseGetNameListResponse(LinkedList* nameList, ByteBuffer* message, uint32_t* invokeId) +{ + bool moreFollows = true; + + uint8_t* buffer = message->buffer; + int maxBufPos = message->size; + int bufPos = 0; + int length; + + uint8_t tag = buffer[bufPos++]; + if (tag == 0xa2) { + // TODO parse confirmed error PDU + goto exit_error; + } + if (tag != 0xa1) goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + /* get invokeId */ + tag = buffer[bufPos++]; + if (tag != 0x02) goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + if (invokeId != NULL) + *invokeId = BerDecoder_decodeUint32(buffer, length, bufPos); + + bufPos += length; + + tag = buffer[bufPos++]; + if (tag != 0xa1) goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + tag = buffer[bufPos++]; + if (tag != 0xa0) goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + int listEndPos = bufPos + length; + if (listEndPos > maxBufPos) goto exit_error; + + if (*nameList == NULL) + *nameList = LinkedList_create(); + + LinkedList element = LinkedList_getLastElement(*nameList); + + while (bufPos < listEndPos) { + tag = buffer[bufPos++]; + if (tag != 0x1a) goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + char* variableName = createStringFromBuffer(buffer + bufPos, length); + + element = LinkedList_insertAfter(element, variableName); + + bufPos += length; + } + + if (bufPos < maxBufPos) { + tag = buffer[bufPos++]; + if (tag != 0x81) goto exit_error; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + if (length != 1) goto exit_error; + if (buffer[bufPos++] > 0) + moreFollows = true; + else + moreFollows = false; + } + + return moreFollows; + +exit_error: + if (*nameList != NULL) { + LinkedList_destroy(*nameList); + } + + if (DEBUG) printf("parseNameListResponse: error parsing message!\n"); + return false; +} + +int +mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, const char* domainName, + ByteBuffer* writeBuffer, MmsObjectClass objectClass, const char* continueAfter) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_getNameList; + + GetNameListRequest_t* request; + + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList); + + if (continueAfter != NULL) { + request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); + request->continueAfter->buf = (uint8_t*) copyString(continueAfter); + request->continueAfter->size = strlen(continueAfter); + } + else + request->continueAfter = NULL; + + + if (domainName != NULL) { + request->objectScope.present = GetNameListRequest__objectScope_PR_domainSpecific; + request->objectScope.choice.domainSpecific.buf = (uint8_t*) domainName; + request->objectScope.choice.domainSpecific.size = strlen(domainName); + } + else { + request->objectScope.present = GetNameListRequest__objectScope_PR_vmdSpecific; + } + + request->objectClass.present = ObjectClass_PR_basicObjectClass; + + if (objectClass == MMS_NAMED_VARIABLE) + asn_long2INTEGER(&request->objectClass.choice.basicObjectClass, + ObjectClass__basicObjectClass_namedVariable); + else if (objectClass == MMS_NAMED_VARIABLE_LIST) + asn_long2INTEGER(&request->objectClass.choice.basicObjectClass, + ObjectClass__basicObjectClass_namedVariableList); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + request->objectScope.choice.domainSpecific.buf = 0; + request->objectScope.choice.domainSpecific.size = 0; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} diff --git a/src/mms/iso_mms/client/mms_client_get_var_access.c b/src/mms/iso_mms/client/mms_client_get_var_access.c new file mode 100644 index 0000000..7ec1e23 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_get_var_access.c @@ -0,0 +1,203 @@ +/* + * mms_client_get_var_access.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "stack_config.h" +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "mms_client_internal.h" + +static MmsVariableSpecification* +createTypeSpecification(TypeSpecification_t* asnTypeSpec) { + MmsVariableSpecification* typeSpec = (MmsVariableSpecification*) + GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + + switch (asnTypeSpec->present) { + case TypeSpecification_PR_structure: + { + typeSpec->type = MMS_STRUCTURE; + + int elementCount = asnTypeSpec->choice.structure.components.list.count; + typeSpec->typeSpec.structure.elementCount = elementCount; + + typeSpec->typeSpec.structure.elements = (MmsVariableSpecification**) + GLOBAL_CALLOC(elementCount, sizeof(MmsVariableSpecification*)); + + int i; + + for (i = 0; i < elementCount; i++) { + + char* name = createStringFromBuffer( + asnTypeSpec->choice.structure.components.list.array[i]->componentName->buf, + asnTypeSpec->choice.structure.components.list.array[i]->componentName->size); + + typeSpec->typeSpec.structure.elements[i] = + createTypeSpecification(asnTypeSpec->choice.structure.components. + list.array[i]->componentType); + + typeSpec->typeSpec.structure.elements[i]->name = name; + } + } + break; + case TypeSpecification_PR_array: + { + typeSpec->type = MMS_ARRAY; + + long elementCount; + asn_INTEGER2long(&asnTypeSpec->choice.array.numberOfElements, &elementCount); + + typeSpec->typeSpec.array.elementCount = elementCount; + + typeSpec->typeSpec.array.elementTypeSpec = + createTypeSpecification(asnTypeSpec->choice.array.elementType); + } + break; + case TypeSpecification_PR_boolean: + typeSpec->type = MMS_BOOLEAN; + break; + case TypeSpecification_PR_bitstring: + typeSpec->type = MMS_BIT_STRING; + typeSpec->typeSpec.bitString = asnTypeSpec->choice.bitstring; + break; + case TypeSpecification_PR_integer: + typeSpec->type = MMS_INTEGER; + typeSpec->typeSpec.integer = asnTypeSpec->choice.integer; + break; + case TypeSpecification_PR_unsigned: + typeSpec->type = MMS_UNSIGNED; + typeSpec->typeSpec.unsignedInteger = asnTypeSpec->choice.Unsigned; + break; + case TypeSpecification_PR_floatingpoint: + typeSpec->type = MMS_FLOAT; + typeSpec->typeSpec.floatingpoint.exponentWidth = + asnTypeSpec->choice.floatingpoint.exponentwidth; + typeSpec->typeSpec.floatingpoint.formatWidth = + asnTypeSpec->choice.floatingpoint.formatwidth; + break; + case TypeSpecification_PR_octetstring: + typeSpec->type = MMS_OCTET_STRING; + typeSpec->typeSpec.octetString = asnTypeSpec->choice.octetstring; + break; + case TypeSpecification_PR_visiblestring: + typeSpec->type = MMS_VISIBLE_STRING; + typeSpec->typeSpec.visibleString = asnTypeSpec->choice.visiblestring; + break; + case TypeSpecification_PR_mMSString: + typeSpec->type = MMS_STRING; + typeSpec->typeSpec.mmsString = asnTypeSpec->choice.mMSString; + break; + case TypeSpecification_PR_utctime: + typeSpec->type = MMS_UTC_TIME; + break; + case TypeSpecification_PR_binarytime: + typeSpec->type = MMS_BINARY_TIME; + if (asnTypeSpec->choice.binarytime == 0) + typeSpec->typeSpec.binaryTime = 4; + else + typeSpec->typeSpec.binaryTime = 6; + break; + default: + printf("ERROR: unknown type in type specification\n"); + break; + } + + return typeSpec; +} + +MmsVariableSpecification* +mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t* invokeId) +{ + MmsPdu_t* mmsPdu = 0; /* allow asn1c to allocate structure */ + MmsVariableSpecification* typeSpec = NULL; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); + + if (rval.code != RC_OK) + return NULL; + + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == + ConfirmedServiceResponse_PR_getVariableAccessAttributes) + { + GetVariableAccessAttributesResponse_t* response; + + response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.getVariableAccessAttributes); + TypeSpecification_t* asnTypeSpec = &response->typeSpecification; + + typeSpec = createTypeSpecification(asnTypeSpec); + } + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return typeSpec; +} + +int +mmsClient_createGetVariableAccessAttributesRequest( + uint32_t invokeId, + const char* domainId, const char* itemId, + ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_getVariableAccessAttributes; + + GetVariableAccessAttributesRequest_t* request; + + request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getVariableAccessAttributes); + + request->present = GetVariableAccessAttributesRequest_PR_name; + + request->choice.name.present = ObjectName_PR_domainspecific; + + request->choice.name.choice.domainspecific.domainId.buf = (uint8_t*) domainId; + request->choice.name.choice.domainspecific.domainId.size = strlen(domainId); + request->choice.name.choice.domainspecific.itemId.buf = (uint8_t*) itemId; + request->choice.name.choice.domainspecific.itemId.size = strlen(itemId); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + request->choice.name.choice.domainspecific.domainId.buf = 0; + request->choice.name.choice.domainspecific.domainId.size = 0; + request->choice.name.choice.domainspecific.itemId.buf = 0; + request->choice.name.choice.domainspecific.itemId.size = 0; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + diff --git a/src/mms/iso_mms/client/mms_client_identify.c b/src/mms/iso_mms/client/mms_client_identify.c new file mode 100644 index 0000000..7d1b946 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_identify.c @@ -0,0 +1,118 @@ +/* + * mms_client_identify.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "mms_client_internal.h" +#include "ber_encoder.h" +#include "ber_decode.h" + +void +mmsClient_createIdentifyRequest(uint32_t invokeId, ByteBuffer* request) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + uint32_t confirmedRequestPduSize = 2 + 2 + invokeIdSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x82, 0, buffer, bufPos); + + request->size = bufPos; +} + +MmsServerIdentity* +mmsClient_parseIdentifyResponse(MmsConnection self) +{ + uint8_t* buffer = self->lastResponse->buffer; + int maxBufPos = self->lastResponse->size; + int bufPos = self->lastResponseBufPos; + int length; + MmsServerIdentity* identityInfo = NULL; + + uint8_t tag = buffer[bufPos++]; + if (tag != 0xa2) + goto exit_error; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseIdentifyResponse: Message to short!\n"); + goto exit_error; + } + + char* vendorName = NULL; + char* modelName = NULL; + char* revision = NULL; + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0x80: /* vendorName */ + vendorName = createStringFromBuffer(buffer + bufPos, length); + bufPos += length; + break; + case 0x81: /* modelName */ + modelName = createStringFromBuffer(buffer + bufPos, length); + bufPos += length; + break; + case 0x82: /* revision */ + revision = createStringFromBuffer(buffer + bufPos, length); + bufPos += length; + break; + case 0x83: /* list of abstract syntaxes */ + bufPos += length; + break; + default: /* ignore unknown tags */ + bufPos += length; + break; + } + } + + identityInfo = (MmsServerIdentity*) GLOBAL_MALLOC(sizeof(MmsServerIdentity)); + + identityInfo->vendorName = vendorName; + identityInfo->modelName = modelName; + identityInfo->revision = revision; + +exit_error: + return identityInfo; +} + + + diff --git a/src/mms/iso_mms/client/mms_client_initiate.c b/src/mms/iso_mms/client/mms_client_initiate.c new file mode 100644 index 0000000..6458ae2 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_initiate.c @@ -0,0 +1,142 @@ +/* + * mms_client_initiate.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "mms_common.h" +#include "mms_common_internal.h" +#include "mms_indication.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "stack_config.h" + +#include "mms_client_internal.h" + +/* servicesSupported = {GetNameList} - required by initiate request, other services are required by some servers to work properly */ +static uint8_t servicesSupported[] = { 0xee, 0x1c, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x79, 0xef, 0x18 }; + +static InitiateRequestPdu_t +createInitiateRequestPdu(MmsConnection self) +{ + InitiateRequestPdu_t request; + + request.localDetailCalling = (Integer32_t*) GLOBAL_CALLOC(1, sizeof(Integer32_t)); + *(request.localDetailCalling) = self->parameters.maxPduSize; + + request.proposedMaxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + request.proposedMaxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + + request.proposedDataStructureNestingLevel = (Integer8_t*) GLOBAL_CALLOC(1, sizeof(Integer8_t)); + *(request.proposedDataStructureNestingLevel) = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL; + + request.mmsInitRequestDetail.proposedParameterCBB.size = 2; + request.mmsInitRequestDetail.proposedParameterCBB.bits_unused = 5; + request.mmsInitRequestDetail.proposedParameterCBB.buf = (uint8_t*) GLOBAL_CALLOC(2, sizeof(uint8_t)); + request.mmsInitRequestDetail.proposedParameterCBB.buf[0] = 0xf1; + request.mmsInitRequestDetail.proposedParameterCBB.buf[1] = 0x00; + + request.mmsInitRequestDetail.proposedVersionNumber = 1; + + request.mmsInitRequestDetail.servicesSupportedCalling.size = 11; + request.mmsInitRequestDetail.servicesSupportedCalling.bits_unused = 3; + + request.mmsInitRequestDetail.servicesSupportedCalling.buf = servicesSupported; + + return request; +} + +static void +freeInitiateRequestPdu(InitiateRequestPdu_t request) +{ + GLOBAL_FREEMEM(request.localDetailCalling); + GLOBAL_FREEMEM(request.proposedDataStructureNestingLevel); + GLOBAL_FREEMEM(request.mmsInitRequestDetail.proposedParameterCBB.buf); +} + +int +mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message) +{ + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); + + mmsPdu->present = MmsPdu_PR_initiateRequestPdu; + + mmsPdu->choice.initiateRequestPdu = createInitiateRequestPdu(self); + + asn_enc_rval_t rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) message); + + freeInitiateRequestPdu(mmsPdu->choice.initiateRequestPdu); + GLOBAL_FREEMEM(mmsPdu); + + return rval.encoded; +} + +int +mmsClient_createConcludeRequest(MmsConnection self, ByteBuffer* message) +{ + if (message->maxSize > 1) { + message->buffer[0] = 0x8b; + message->buffer[1] = 0; + message->size = 2; + return 2; + } + else + return -1; +} + +bool +mmsClient_parseInitiateResponse(MmsConnection self) +{ + bool result = false; + MmsPdu_t* mmsPdu = 0; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(self->lastResponse), + ByteBuffer_getSize(self->lastResponse)); + + if (rval.code != RC_OK) goto exit_function; + + if (mmsPdu->present == MmsPdu_PR_initiateResponsePdu) { + InitiateResponsePdu_t* initiateResponse = &(mmsPdu->choice.initiateResponsePdu); + + if (initiateResponse->localDetailCalled != NULL) + self->parameters.maxPduSize = *(initiateResponse->localDetailCalled); + + if (initiateResponse->negotiatedDataStructureNestingLevel != NULL) + self->parameters.dataStructureNestingLevel = *(initiateResponse->negotiatedDataStructureNestingLevel);; + + self->parameters.maxServOutstandingCalled = initiateResponse->negotiatedMaxServOutstandingCalled; + + self->parameters.maxServOutstandingCalling = initiateResponse->negotiatedMaxServOutstandingCalling; + + result = true; + } + else + result = false; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + +exit_function: + return result; +} 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 new file mode 100644 index 0000000..43b6727 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_named_variable_list.c @@ -0,0 +1,411 @@ +/* + * mms_client_named_variable_list.c + * + * MMS named variable list services (client) + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "stack_config.h" +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" +#include "mms_client_internal.h" +#include "mms_common_internal.h" + + +void +mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeBuffer, + const char* domainId, const char* listNameId) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_deleteNamedVariableList; + + DeleteNamedVariableListRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); + + request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1, + sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName)); + + request->listOfVariableListName->list.count = 1; + request->listOfVariableListName->list.size = 1; + + request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*)); + request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t)); + + request->listOfVariableListName->list.array[0]->present = ObjectName_PR_domainspecific; + request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.size = strlen(domainId); + request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.buf = (uint8_t*) copyString(domainId); + request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.size = strlen(listNameId); + request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.buf = (uint8_t*) copyString(listNameId); + + request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t)); + asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific); + + der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +void +mmsClient_createDeleteAssociationSpecificNamedVariableListRequest( + long invokeId, + ByteBuffer* writeBuffer, + const char* listNameId) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_deleteNamedVariableList; + + DeleteNamedVariableListRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); + + request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1, + sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName)); + + request->listOfVariableListName->list.count = 1; + request->listOfVariableListName->list.size = 1; + + request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*)); + request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t)); + + request->listOfVariableListName->list.array[0]->present = ObjectName_PR_aaspecific; + + request->listOfVariableListName->list.array[0]->choice.aaspecific.size = strlen(listNameId); + request->listOfVariableListName->list.array[0]->choice.aaspecific.buf = (uint8_t*) copyString(listNameId); + + request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t)); + asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific); + + der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +bool +mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* invokeId) +{ + MmsPdu_t* mmsPdu = 0; + + bool retVal = false; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); + + if (rval.code == RC_OK) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == + ConfirmedServiceResponse_PR_deleteNamedVariableList) + { + DeleteNamedVariableListResponse_t* response = + &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.deleteNamedVariableList); + + long numberDeleted; + + asn_INTEGER2long(&(response->numberDeleted), &numberDeleted); + + if (numberDeleted == 1) + retVal = true; + } + } + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return retVal; +} + + +void +mmsClient_createGetNamedVariableListAttributesRequest(uint32_t invokeId, ByteBuffer* writeBuffer, + const char* domainId, const char* listNameId) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_getNamedVariableListAttributes; + + GetNamedVariableListAttributesRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNamedVariableListAttributes); + + request->present = ObjectName_PR_domainspecific; + + request->choice.domainspecific.domainId.size = strlen(domainId); + request->choice.domainspecific.domainId.buf = (uint8_t*) copyString(domainId); + + request->choice.domainspecific.itemId.size = strlen(listNameId); + request->choice.domainspecific.itemId.buf = (uint8_t*) copyString(listNameId); + + der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +void +mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(uint32_t invokeId, + ByteBuffer* writeBuffer, const char* listNameId) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_getNamedVariableListAttributes; + + GetNamedVariableListAttributesRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNamedVariableListAttributes); + + request->present = ObjectName_PR_aaspecific; + + request->choice.aaspecific.size = strlen(listNameId); + request->choice.aaspecific.buf = (uint8_t*) copyString(listNameId); + + der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +static LinkedList /* */ +parseNamedVariableAttributes(GetNamedVariableListAttributesResponse_t* response, bool* deletable) +{ + if (deletable != NULL) + *deletable = response->mmsDeletable; + + int attributesCount = response->listOfVariable.list.count; + int i; + + LinkedList attributes = LinkedList_create(); + + for (i = 0; i < attributesCount; i++) { + char* domainId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]-> + variableSpecification.choice.name.choice.domainspecific.domainId); + + char* itemId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]-> + variableSpecification.choice.name.choice.domainspecific.itemId); + + MmsVariableAccessSpecification* listEntry = MmsVariableAccessSpecification_create(domainId, itemId); + + LinkedList_add(attributes, listEntry); + } + + return attributes; +} + +LinkedList /* */ +mmsClient_parseGetNamedVariableListAttributesResponse(ByteBuffer* message, uint32_t* invokeId, + bool* /*OUT*/ deletable) +{ + MmsPdu_t* mmsPdu = 0; + + LinkedList attributes = NULL; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); + + + if (rval.code == RC_OK) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == + ConfirmedServiceResponse_PR_getNamedVariableListAttributes) + { + attributes = parseNamedVariableAttributes( + &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.getNamedVariableListAttributes), + deletable); + } + } + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return attributes; +} + + +void +mmsClient_createDefineNamedVariableListRequest( + uint32_t invokeId, + ByteBuffer* writeBuffer, + const char* domainId, + const char* listNameId, + LinkedList /**/ listOfVariables, + bool associationSpecific) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_defineNamedVariableList; + + DefineNamedVariableListRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.defineNamedVariableList); + + if (associationSpecific) { + request->variableListName.present = ObjectName_PR_aaspecific; + + request->variableListName.choice.aaspecific.size = strlen(listNameId); + request->variableListName.choice.aaspecific.buf = (uint8_t*) copyString(listNameId); + } + else { + request->variableListName.present = ObjectName_PR_domainspecific; + + request->variableListName.choice.domainspecific.domainId.size = strlen(domainId); + request->variableListName.choice.domainspecific.domainId.buf = (uint8_t*) copyString(domainId); + + request->variableListName.choice.domainspecific.itemId.size = strlen(listNameId); + request->variableListName.choice.domainspecific.itemId.buf = (uint8_t*) copyString(listNameId); + } + + int listSize = LinkedList_size(listOfVariables); + + request->listOfVariable.list.count = listSize; + request->listOfVariable.list.size = listSize; + + request->listOfVariable.list.array = + (struct DefineNamedVariableListRequest__listOfVariable__Member**) GLOBAL_CALLOC(listSize, sizeof(void*)); + + int i = 0; + LinkedList element = LinkedList_getNext(listOfVariables); + while (i < listSize) { + + MmsVariableAccessSpecification* variableSpec = (MmsVariableAccessSpecification*) element->data; + + request->listOfVariable.list.array[i] = (struct DefineNamedVariableListRequest__listOfVariable__Member*) + GLOBAL_CALLOC(1, sizeof(struct DefineNamedVariableListRequest__listOfVariable__Member)); + + request->listOfVariable.list.array[i]->variableSpecification.present = + VariableSpecification_PR_name; + + request->listOfVariable.list.array[i]->variableSpecification.choice.name.present = + ObjectName_PR_domainspecific; + + request->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.domainId.size = strlen(variableSpec->domainId); + + request->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.domainId.buf = (uint8_t*) copyString(variableSpec->domainId); + + request->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.itemId.size = strlen(variableSpec->itemId); + + request->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.itemId.buf = (uint8_t*) copyString(variableSpec->itemId); + + //TODO add alternate access + 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*) copyString(variableSpec->componentName); + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess + = componentAccess; + } + + request->listOfVariable.list.array[i]->alternateAccess = alternateAccess; + } + + + element = LinkedList_getNext(element); + + i++; + } + + der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +bool +mmsClient_parseDefineNamedVariableResponse(ByteBuffer* message, uint32_t* invokeId) +{ + MmsPdu_t* mmsPdu = 0; + bool retVal = false; + + asn_dec_rval_t rval; + + rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); + + + if (rval.code == RC_OK) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == + ConfirmedServiceResponse_PR_defineNamedVariableList) + retVal = true; + } + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return retVal; +} diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c new file mode 100644 index 0000000..b3b3b14 --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_read.c @@ -0,0 +1,565 @@ +/* + * mms_client_read.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" +#include "stack_config.h" + +#include "mms_client_internal.h" +#include "mms_common_internal.h" +#include "mms_value_internal.h" + +MmsValue* +mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSize, bool createArray) +{ + MmsValue* valueList = NULL; + MmsValue* value = NULL; + + int elementCount = listSize; + + if ((elementCount > 1) || createArray) + valueList = MmsValue_createEmptyArray(elementCount); + + int i = 0; + + for (i = 0; i < elementCount; i++) { + AccessResult_PR presentType = accessResultList[i]->present; + + if (presentType == AccessResult_PR_failure) { + if (DEBUG_MMS_CLIENT) printf("access error!\n"); + + if (accessResultList[i]->choice.failure.size > 0) { + int errorCode = (int) accessResultList[i]->choice.failure.buf[0]; + + MmsDataAccessError dataAccessError = DATA_ACCESS_ERROR_UNKNOWN; + + if ((errorCode >= 0) && (errorCode < 12)) + dataAccessError = (MmsDataAccessError) errorCode; + + value = MmsValue_newDataAccessError(dataAccessError); + } + else + value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); + } + else if (presentType == AccessResult_PR_array) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_ARRAY; + + int arrayElementCount = + accessResultList[i]->choice.array.list.count; + + value->value.structure.size = arrayElementCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); + + int j; + + for (j = 0; j < arrayElementCount; j++) { + value->value.structure.components[j] = mmsMsg_parseDataElement( + accessResultList[i]->choice.array.list.array[j]); + } + } + else if (presentType == AccessResult_PR_structure) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_STRUCTURE; + + int componentCount = + accessResultList[i]->choice.structure.list.count; + + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int j; + for (j = 0; j < componentCount; j++) { + value->value.structure.components[j] = mmsMsg_parseDataElement( + accessResultList[i]->choice.structure.list.array[j]); + } + } + else if (presentType == AccessResult_PR_bitstring) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BIT_STRING; + int size = accessResultList[i]->choice.bitstring.size; + + value->value.bitString.size = (size * 8) + - accessResultList[i]->choice.bitstring.bits_unused; + + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + accessResultList[i]->choice.bitstring.buf, size); + + } + else if (presentType == AccessResult_PR_integer) { + Asn1PrimitiveValue* berInteger = + BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, + accessResultList[i]->choice.integer.size); + + value = MmsValue_newIntegerFromBerInteger(berInteger); + } + else if (presentType == AccessResult_PR_unsigned) { + Asn1PrimitiveValue* berInteger = + BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, + accessResultList[i]->choice.Unsigned.size); + + value = MmsValue_newUnsignedFromBerInteger(berInteger); + } + else if (presentType == AccessResult_PR_floatingpoint) { + int size = accessResultList[i]->choice.floatingpoint.size; + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; + + if (size == 5) { /* FLOAT32 */ + value->value.floatingPoint.formatWidth = 32; + value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; + + uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); + + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); +#else + memcpy(value->value.floatingPoint.buf, floatBuf, 4); +#endif + + } + + if (size == 9) { /* FLOAT64 */ + value->value.floatingPoint.formatWidth = 64; + value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; + + uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); + + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); +#else + memcpy(value->value.floatingPoint.buf, floatBuf, 8); +#endif + } + + } + else if (presentType == AccessResult_PR_visiblestring) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_VISIBLE_STRING; + + int strSize = accessResultList[i]->choice.visiblestring.size; + + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; + + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.visiblestring.buf, + strSize); + + value->value.visibleString.buf[strSize] = 0; + } + else if (presentType == AccessResult_PR_mMSString) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_STRING; + + int strSize = accessResultList[i]->choice.mMSString.size; + + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; + + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.mMSString.buf, strSize); + + value->value.visibleString.buf[strSize] = 0; + + } + else if (presentType == AccessResult_PR_utctime) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_UTC_TIME; + memcpy(value->value.utcTime, + accessResultList[i]->choice.utctime.buf, 8); + } + else if (presentType == AccessResult_PR_boolean) { + value = MmsValue_newBoolean(accessResultList[i]->choice.boolean); + } + else if (presentType == AccessResult_PR_binarytime) { + int size = accessResultList[i]->choice.binarytime.size; + + if (size <= 6) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BINARY_TIME; + value->value.binaryTime.size = size; + memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); + } + } + else if (presentType == AccessResult_PR_octetstring) { + int size = accessResultList[i]->choice.octetstring.size; + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_OCTET_STRING; + value->value.octetString.maxSize = size; + value->value.octetString.size = size; + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + } + else { + printf("unknown type %i\n", presentType); + value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID); + } + + if ((elementCount > 1) || createArray) + MmsValue_setElement(valueList, i, value); + } + + if (valueList == NULL) + valueList = value; + + return valueList; +} + + +/* + * \param createArray if multiple variables should be read (e.g. if a data set is read) an array should + * be created that contains the access results. + */ +MmsValue* +mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool createArray) +{ + MmsPdu_t* mmsPdu = 0; /* allow asn1c to allocate structure */ + + MmsValue* valueList = NULL; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, + (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); + + if (rval.code != RC_OK) + return NULL; + + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == ConfirmedServiceResponse_PR_read) { + ReadResponse_t* response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.read); + + int elementCount = response->listOfAccessResult.list.count; + + valueList = mmsClient_parseListOfAccessResults(response->listOfAccessResult.list.array, + elementCount, createArray); + } + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return valueList; +} + + +static ReadRequest_t* +createReadRequest (MmsPdu_t* mmsPdu) +{ + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_read; + + return &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.read); +} + + +int +mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, const char* domainId, const char* itemId, + ByteBuffer* writeBuffer, bool specWithResult) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + ReadRequest_t* readRequest = createReadRequest(mmsPdu); + + if (specWithResult) { + readRequest->specificationWithResult = (BOOLEAN_t*) GLOBAL_CALLOC(1, sizeof(BOOLEAN_t)); + (*(readRequest->specificationWithResult)) = true; + } + else + readRequest->specificationWithResult = NULL; + + readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_variableListName; + + ObjectName_t* objectName = &(readRequest->variableAccessSpecification.choice.variableListName); + + objectName->present = ObjectName_PR_domainspecific; + + objectName->choice.domainspecific.domainId.buf = (uint8_t*) copyString(domainId); + objectName->choice.domainspecific.domainId.size = strlen(domainId); + + objectName->choice.domainspecific.itemId.buf = (uint8_t*) copyString(itemId); + objectName->choice.domainspecific.itemId.size = strlen(itemId); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +int +mmsClient_createReadAssociationSpecificNamedVariableListRequest( + uint32_t invokeId, + const char* itemId, + ByteBuffer* writeBuffer, + bool specWithResult) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + ReadRequest_t* readRequest = createReadRequest(mmsPdu); + + if (specWithResult) { + readRequest->specificationWithResult = (BOOLEAN_t*) GLOBAL_CALLOC(1, sizeof(BOOLEAN_t)); + (*(readRequest->specificationWithResult)) = true; + } + else + readRequest->specificationWithResult = NULL; + + readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_variableListName; + + ObjectName_t* objectName = &(readRequest->variableAccessSpecification.choice.variableListName); + + objectName->present = ObjectName_PR_aaspecific; + + objectName->choice.aaspecific.buf = (uint8_t*) copyString(itemId); + objectName->choice.aaspecific.size = strlen(itemId); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +/** + * Request a single value + */ +int +mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* itemId, ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + ReadRequest_t* readRequest = createReadRequest(mmsPdu); + + readRequest->specificationWithResult = NULL; + + readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = + (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1; + + ListOfVariableSeq_t* listOfVars = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); + + readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = listOfVars; + + listOfVars->alternateAccess = NULL; + listOfVars->variableSpecification.present = VariableSpecification_PR_name; + + if (domainId != NULL) { + listOfVars->variableSpecification.choice.name.present = ObjectName_PR_domainspecific; + listOfVars->variableSpecification.choice.name.choice.domainspecific.domainId.buf = (uint8_t*) domainId; + listOfVars->variableSpecification.choice.name.choice.domainspecific.domainId.size = strlen(domainId); + listOfVars->variableSpecification.choice.name.choice.domainspecific.itemId.buf = (uint8_t*) itemId; + listOfVars->variableSpecification.choice.name.choice.domainspecific.itemId.size = strlen(itemId); + } + else { + listOfVars->variableSpecification.choice.name.present = ObjectName_PR_vmdspecific; + listOfVars->variableSpecification.choice.name.choice.vmdspecific.buf = (uint8_t*) itemId; + listOfVars->variableSpecification.choice.name.choice.vmdspecific.size = strlen(itemId); + } + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + /* clean up data structures */ + GLOBAL_FREEMEM(listOfVars); + GLOBAL_FREEMEM(readRequest->variableAccessSpecification.choice.listOfVariable.list.array); + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = NULL; + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0; + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +static AlternateAccess_t* +createAlternateAccess(uint32_t index, uint32_t elementCount) +{ + 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_selectAccess; + + if (elementCount > 0) { + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_indexRange; + + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex); + + asn_long2INTEGER(asnIndex, index); + + asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements); + + asn_long2INTEGER(asnIndex, elementCount); + } + else { + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_index; + + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); + + asn_long2INTEGER(asnIndex, index); + } + + return alternateAccess; +} + +static ListOfVariableSeq_t* +createVariableIdentifier(const char* domainId, const char* itemId) +{ + ListOfVariableSeq_t* variableIdentifier = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); + + variableIdentifier->variableSpecification.present = VariableSpecification_PR_name; + variableIdentifier->variableSpecification.choice.name.present = ObjectName_PR_domainspecific; + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.domainId.buf = (uint8_t*) domainId; + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.domainId.size = strlen(domainId); + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.itemId.buf = (uint8_t*) itemId; + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.itemId.size = strlen(itemId); + + return variableIdentifier; +} + +int +mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* domainId, const char* itemId, + uint32_t index, uint32_t elementCount, ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + ReadRequest_t* readRequest = createReadRequest(mmsPdu); + + readRequest->specificationWithResult = NULL; + + readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1; + + ListOfVariableSeq_t* variableIdentifier = createVariableIdentifier(domainId, itemId); + + readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier; + + variableIdentifier->alternateAccess = createAlternateAccess(index, elementCount); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.domainId.buf = 0; + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.domainId.size = 0; + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.itemId.buf = 0; + variableIdentifier->variableSpecification.choice.name.choice.domainspecific.itemId.size = 0; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +static ListOfVariableSeq_t** +createListOfVariables(ReadRequest_t* readRequest, int valuesCount) { + readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) + GLOBAL_CALLOC(valuesCount, sizeof(ListOfVariableSeq_t*)); + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = valuesCount; + readRequest->variableAccessSpecification.choice.listOfVariable.list.size = valuesCount; + + return readRequest->variableAccessSpecification.choice.listOfVariable.list.array; +} + +/** + * Request multiple values of a single domain + */ +int +mmsClient_createReadRequestMultipleValues(uint32_t invokeId, const char* domainId, LinkedList items, + ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + ReadRequest_t* readRequest = createReadRequest(mmsPdu); + + readRequest->specificationWithResult = NULL; + + int valuesCount = LinkedList_size(items); + + ListOfVariableSeq_t** listOfVars = createListOfVariables(readRequest, valuesCount); + + LinkedList item = items; + + int i = 0; + + while ((item = LinkedList_getNext(item)) != NULL) { + listOfVars[i] = createVariableIdentifier(domainId, (char*) (item->data)); + i++; + } + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + for (i = 0; i < valuesCount; i++) { + GLOBAL_FREEMEM(listOfVars[i]); + } + GLOBAL_FREEMEM(listOfVars); + + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0; + readRequest->variableAccessSpecification.choice.listOfVariable.list.size = 0; + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = NULL; + + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + diff --git a/src/mms/iso_mms/client/mms_client_status.c b/src/mms/iso_mms/client/mms_client_status.c new file mode 100644 index 0000000..c693d2b --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_status.c @@ -0,0 +1,117 @@ +/* + * mms_client_status.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "mms_client_internal.h" +#include "ber_encoder.h" +#include "ber_decode.h" + +void +mmsClient_createStatusRequest(uint32_t invokeId, ByteBuffer* request, bool extendedDerivation) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); + uint32_t confirmedRequestPduSize = 2 + 2 + 1 + invokeIdSize; + + int bufPos = 0; + uint8_t* buffer = request->buffer; + + bufPos = BerEncoder_encodeTL(0xa0, confirmedRequestPduSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeBoolean(0x80, extendedDerivation, buffer, bufPos); + + request->size = bufPos; +} + +bool +mmsClient_parseStatusResponse(MmsConnection self, int* vmdLogicalStatus, int* vmdPhysicalStatus) +{ + uint8_t* buffer = self->lastResponse->buffer; + int maxBufPos = self->lastResponse->size; + int bufPos = self->lastResponseBufPos; + int length; + + uint8_t tag = buffer[bufPos++]; + + if (tag != 0xa0) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseStatusResponse: unknown tag %02x\n", tag); + goto exit_error; + } + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + if (bufPos < 0) goto exit_error; + + int endPos = bufPos + length; + + if (endPos > maxBufPos) { + if (DEBUG_MMS_CLIENT) + printf("mmsClient_parseStatusResponse: message to short!\n"); + goto exit_error; + } + + bool hasPhysicalStatus = false; + bool hasLogicalStatus = false; + + while (bufPos < endPos) { + tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (tag) { + case 0x80: /* vmdLogicalStatus */ + if (vmdLogicalStatus != NULL) + *vmdLogicalStatus = BerDecoder_decodeUint32(buffer, length, bufPos); + + hasLogicalStatus = true; + bufPos += length; + break; + case 0x81: /* vmdPhysicalStatus */ + if (vmdPhysicalStatus != NULL) + *vmdPhysicalStatus = BerDecoder_decodeUint32(buffer, length, bufPos); + + hasPhysicalStatus = true; + bufPos += length; + break; + case 0x82: /* localDetail */ + bufPos += length; + break; + default: + return false; + } + } + + if (hasPhysicalStatus && hasLogicalStatus) + return true; + +exit_error: + return false; +} + + + diff --git a/src/mms/iso_mms/client/mms_client_write.c b/src/mms/iso_mms/client/mms_client_write.c new file mode 100644 index 0000000..8163cdd --- /dev/null +++ b/src/mms/iso_mms/client/mms_client_write.c @@ -0,0 +1,348 @@ +/* + * mms_client_write.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include +#include "mms_common.h" +#include "mms_client_connection.h" +#include "byte_buffer.h" + +#include "mms_client_internal.h" +#include "mms_common_internal.h" + +#include "stack_config.h" + +static MmsError +mapDataAccessErrorToMmsError(uint32_t dataAccessError) +{ + switch (dataAccessError) { + case 0: + return MMS_ERROR_ACCESS_OBJECT_INVALIDATED; + case 1: + return MMS_ERROR_HARDWARE_FAULT; + case 2: + return MMS_ERROR_ACCESS_TEMPORARILY_UNAVAILABLE; + case 3: + return MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + case 4: + return MMS_ERROR_DEFINITION_OBJECT_UNDEFINED; + case 5: + return MMS_ERROR_DEFINITION_INVALID_ADDRESS; + case 6: + return MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED; + case 7: + return MMS_ERROR_DEFINITION_TYPE_INCONSISTENT; + case 8: + return MMS_ERROR_DEFINITION_OBJECT_ATTRIBUTE_INCONSISTENT; + case 9: + return MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED; + case 10: + return MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; + case 11: + return MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID; + default: + return MMS_ERROR_OTHER; + } +} + +void +mmsClient_parseWriteMultipleItemsResponse(ByteBuffer* message, int32_t bufPos, MmsError* mmsError, + int itemCount, LinkedList* accessResults) +{ + uint8_t* buf = message->buffer; + int size = message->size; + + int length; + + *mmsError = MMS_ERROR_NONE; + + uint8_t tag = buf[bufPos++]; + + if (tag == 0xa5) { + + bufPos = BerDecoder_decodeLength(buf, &length, bufPos, size); + + if (bufPos == -1) { + *mmsError = MMS_ERROR_PARSING_RESPONSE; + return; + } + + *accessResults = LinkedList_create(); + + int endPos = bufPos + length; + + int numberOfAccessResults = 0; + + while (bufPos < endPos) { + + tag = buf[bufPos++]; + bufPos = BerDecoder_decodeLength(buf, &length, bufPos, size); + + if (bufPos == -1) goto exit_with_error; + + if (tag == 0x81) { + MmsValue* value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_SUCCESS); + LinkedList_add(*accessResults, (void*) value); + } + + if (tag == 0x80) { + uint32_t dataAccessErrorCode = + BerDecoder_decodeUint32(buf, length, bufPos); + + MmsValue* value = MmsValue_newDataAccessError((MmsDataAccessError) dataAccessErrorCode); + + LinkedList_add(*accessResults, (void*) value); + } + + bufPos += length; + + numberOfAccessResults++; + } + + if (itemCount != numberOfAccessResults) + goto exit_with_error; + } + else + *mmsError = MMS_ERROR_PARSING_RESPONSE; + + return; + +exit_with_error: + *mmsError = MMS_ERROR_PARSING_RESPONSE; + LinkedList_destroyDeep(*accessResults, (LinkedListValueDeleteFunction) MmsValue_delete); +} + + +void +mmsClient_parseWriteResponse(ByteBuffer* message, int32_t bufPos, MmsError* mmsError) +{ + uint8_t* buf = message->buffer; + int size = message->size; + + int length; + + *mmsError = MMS_ERROR_NONE; + + uint8_t tag = buf[bufPos++]; + + if (tag == 0xa5) { + + bufPos = BerDecoder_decodeLength(buf, &length, bufPos, size); + + if (bufPos == -1) { + *mmsError = MMS_ERROR_PARSING_RESPONSE; + return; + } + + tag = buf[bufPos++]; + + if (tag == 0x81) + return; + + if (tag == 0x80) { + bufPos = BerDecoder_decodeLength(buf, &length, bufPos, size); + + uint32_t dataAccessErrorCode = + BerDecoder_decodeUint32(buf, length, bufPos); + + *mmsError = mapDataAccessErrorToMmsError(dataAccessErrorCode); + } + } + else + *mmsError = MMS_ERROR_PARSING_RESPONSE; +} + +static VariableSpecification_t* +createNewDomainVariableSpecification(const char* domainId, const char* itemId) +{ + VariableSpecification_t* varSpec = (VariableSpecification_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); + + varSpec->present = VariableSpecification_PR_name; + varSpec->choice.name.present = ObjectName_PR_domainspecific; + varSpec->choice.name.choice.domainspecific.domainId.buf = (uint8_t*) domainId; + varSpec->choice.name.choice.domainspecific.domainId.size = strlen(domainId); + varSpec->choice.name.choice.domainspecific.itemId.buf = (uint8_t*) itemId; + varSpec->choice.name.choice.domainspecific.itemId.size = strlen(itemId); + + return varSpec; +} + +static void +deleteDataElement(Data_t* dataElement) +{ + if (dataElement == NULL) + return; + + if (dataElement->present == Data_PR_structure) { + int elementCount = dataElement->choice.structure->list.count; + + int i; + for (i = 0; i < elementCount; i++) { + deleteDataElement(dataElement->choice.structure->list.array[i]); + } + + GLOBAL_FREEMEM(dataElement->choice.structure->list.array); + GLOBAL_FREEMEM(dataElement->choice.structure); + } + else if (dataElement->present == Data_PR_array) { + int elementCount = dataElement->choice.array->list.count; + + int i; + for (i = 0; i < elementCount; i++) { + deleteDataElement(dataElement->choice.array->list.array[i]); + } + + GLOBAL_FREEMEM(dataElement->choice.array->list.array); + GLOBAL_FREEMEM(dataElement->choice.array); + } + else if (dataElement->present == Data_PR_floatingpoint) { + GLOBAL_FREEMEM(dataElement->choice.floatingpoint.buf); + } + else if (dataElement->present == Data_PR_utctime) { + GLOBAL_FREEMEM(dataElement->choice.utctime.buf); + } + + GLOBAL_FREEMEM(dataElement); +} + +int +mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, const char* domainId, LinkedList itemIds, LinkedList values, + ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_write; + WriteRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.write); + + int numberOfItems = LinkedList_size(itemIds); + + /* Create list of variable specifications */ + request->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + request->variableAccessSpecification.choice.listOfVariable.list.count = numberOfItems; + request->variableAccessSpecification.choice.listOfVariable.list.size = numberOfItems; + request->variableAccessSpecification.choice.listOfVariable.list.array = + (ListOfVariableSeq_t**) GLOBAL_CALLOC(numberOfItems, sizeof(ListOfVariableSeq_t*)); + + /* Create list of data values */ + request->listOfData.list.count = numberOfItems; + request->listOfData.list.size = numberOfItems; + request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(numberOfItems, sizeof(struct Data*)); + + int i; + + LinkedList item = LinkedList_getNext(itemIds); + LinkedList valueElement = LinkedList_getNext(values); + + for (i = 0; i < numberOfItems; i++) { + if (item == NULL) return -1; + if (valueElement == NULL) return -1; + + char* itemId = (char*) item->data; + MmsValue* value = (MmsValue*) valueElement->data; + + request->variableAccessSpecification.choice.listOfVariable.list.array[i] = (ListOfVariableSeq_t*) + createNewDomainVariableSpecification(domainId, itemId); + + request->listOfData.list.array[i] = mmsMsg_createBasicDataElement(value); + + item = LinkedList_getNext(item); + valueElement = LinkedList_getNext(valueElement); + } + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + /* Free ASN structure */ + request->variableAccessSpecification.choice.listOfVariable.list.count = 0; + + for (i = 0; i < numberOfItems; i++) { + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[i]); + deleteDataElement(request->listOfData.list.array[i]); + } + + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array); + request->variableAccessSpecification.choice.listOfVariable.list.array = 0; + + request->listOfData.list.count = 0; + GLOBAL_FREEMEM(request->listOfData.list.array); + request->listOfData.list.array = 0; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; + +} + +int +mmsClient_createWriteRequest(uint32_t invokeId, const char* domainId, const char* itemId, MmsValue* value, + ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_write; + WriteRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.write); + + /* Create list of variable specifications */ + request->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + request->variableAccessSpecification.choice.listOfVariable.list.count = 1; + request->variableAccessSpecification.choice.listOfVariable.list.size = 1; + request->variableAccessSpecification.choice.listOfVariable.list.array = + (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); + request->variableAccessSpecification.choice.listOfVariable.list.array[0] = (ListOfVariableSeq_t*) + createNewDomainVariableSpecification(domainId, itemId); + + /* Create list of typed data values */ + request->listOfData.list.count = 1; + request->listOfData.list.size = 1; + request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(1, sizeof(struct Data*)); + request->listOfData.list.array[0] = mmsMsg_createBasicDataElement(value); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + /* Free ASN structure */ + request->variableAccessSpecification.choice.listOfVariable.list.count = 0; + + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[0]); + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array); + request->variableAccessSpecification.choice.listOfVariable.list.array = 0; + + request->listOfData.list.count = 0; + + deleteDataElement(request->listOfData.list.array[0]); + + GLOBAL_FREEMEM(request->listOfData.list.array); + request->listOfData.list.array = 0; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c new file mode 100644 index 0000000..3feee82 --- /dev/null +++ b/src/mms/iso_mms/common/mms_common_msg.c @@ -0,0 +1,344 @@ +/* + * mms_common_msg.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_common_internal.h" +#include "stack_config.h" +#include "mms_value_internal.h" + +static void +mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf) +{ + if (value->value.floatingPoint.formatWidth == 64) { + *size = 9; + *buf = (uint8_t*) GLOBAL_MALLOC(9); + (*buf)[0] = 11; +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder((*buf) + 1, value->value.floatingPoint.buf, 8); +#else + memcpy((*buf) + 1, value->value.floatingPoint.buf, 8); +#endif + } else { + *size = 5; + *buf = (uint8_t*) GLOBAL_MALLOC(5); + (*buf)[0] = 8; +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder((*buf) + 1, value->value.floatingPoint.buf, 4); +#else + memcpy((*buf) + 1, value->value.floatingPoint.buf, 4); +#endif + } +} + +Data_t* +mmsMsg_createBasicDataElement(MmsValue* value) +{ + Data_t* dataElement = (Data_t*) GLOBAL_CALLOC(1, sizeof(Data_t)); + + switch (value->type) { + case MMS_ARRAY: + { + int size = MmsValue_getArraySize(value); + dataElement->present = Data_PR_array; + dataElement->choice.array = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t)); + dataElement->choice.array->list.count = size; + dataElement->choice.array->list.size = size; + dataElement->choice.array->list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*)); + int i; + for (i = 0; i < size; i++) { + dataElement->choice.array->list.array[i] = + mmsMsg_createBasicDataElement(MmsValue_getElement(value, i)); + } + } + break; + + case MMS_STRUCTURE: + { + int size = value->value.structure.size; + + dataElement->present = Data_PR_structure; + dataElement->choice.structure = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t)); + dataElement->choice.structure->list.count = size; + dataElement->choice.structure->list.size = size; + dataElement->choice.structure->list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*)); + int i; + for (i = 0; i < size; i++) { + dataElement->choice.structure->list.array[i] = mmsMsg_createBasicDataElement( + value->value.structure.components[i]); + } + } + break; + + case MMS_BIT_STRING: + { + dataElement->present = Data_PR_bitstring; + dataElement->choice.bitstring.buf = value->value.bitString.buf; + int size = (value->value.bitString.size / 8) + ((value->value.bitString.size % 8) > 0); + int unused = 8 - (value->value.bitString.size % 8); + dataElement->choice.bitstring.size = size; /* size in bytes */ + dataElement->choice.bitstring.bits_unused = unused; + } + break; + + case MMS_BOOLEAN: + dataElement->present = Data_PR_boolean; + dataElement->choice.boolean = value->value.boolean; + break; + + case MMS_FLOAT: + dataElement->present = Data_PR_floatingpoint; + + mmsMsg_createFloatData(value, &dataElement->choice.floatingpoint.size, + &dataElement->choice.floatingpoint.buf); + break; + + case MMS_UTC_TIME: + dataElement->present = Data_PR_utctime; + + dataElement->choice.utctime.buf = (uint8_t*) GLOBAL_MALLOC(8); + memcpy(dataElement->choice.utctime.buf, value->value.utcTime, 8); + dataElement->choice.utctime.size = 8; + break; + + case MMS_INTEGER: + dataElement->present = Data_PR_integer; + + dataElement->choice.integer.size = value->value.integer->size; + dataElement->choice.integer.buf = value->value.integer->octets; + + break; + + case MMS_UNSIGNED: + dataElement->present = Data_PR_unsigned; + + dataElement->choice.Unsigned.size = value->value.integer->size; + dataElement->choice.Unsigned.buf = value->value.integer->octets; + + break; + + case MMS_VISIBLE_STRING: + dataElement->present = Data_PR_visiblestring; + if (value->value.visibleString.buf != NULL ) { + dataElement->choice.visiblestring.buf = (uint8_t*) value->value.visibleString.buf; + dataElement->choice.visiblestring.size = strlen(value->value.visibleString.buf); + } else + dataElement->choice.visiblestring.size = 0; + break; + + case MMS_OCTET_STRING: + dataElement->present = Data_PR_octetstring; + if (value->value.octetString.buf != NULL ) { + dataElement->choice.octetstring.buf = value->value.octetString.buf; + dataElement->choice.octetstring.size = + value->value.octetString.size; + } else + dataElement->choice.octetstring.size = 0; + break; + + case MMS_STRING: + dataElement->present = Data_PR_mMSString; + if (value->value.visibleString.buf != NULL ) { + dataElement->choice.mMSString.buf = (uint8_t*) value->value.visibleString.buf; + dataElement->choice.mMSString.size = strlen(value->value.visibleString.buf); + } else + dataElement->choice.mMSString.size = 0; + break; + + case MMS_BINARY_TIME: + dataElement->present = Data_PR_binarytime; + dataElement->choice.binarytime.size = value->value.binaryTime.size; + dataElement->choice.binarytime.buf = value->value.binaryTime.buf; + break; + + default: + dataElement->present = Data_PR_NOTHING; + + break; + } + + return dataElement; +} + +MmsValue* +mmsMsg_parseDataElement(Data_t* dataElement) +{ + MmsValue* value = NULL; + + if (dataElement->present == Data_PR_structure) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + int componentCount = dataElement->choice.structure->list.count; + + value->type = MMS_STRUCTURE; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int i; + + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); + } + } + else if (dataElement->present == Data_PR_array) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + int componentCount = dataElement->choice.array->list.count; + + value->type = MMS_ARRAY; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int i; + + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); + } + } + else { + if (dataElement->present == Data_PR_integer) { + Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( + dataElement->choice.integer.buf, dataElement->choice.integer.size); + + value = MmsValue_newIntegerFromBerInteger(berInteger); + } + else if (dataElement->present == Data_PR_unsigned) { + Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( + dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); + + value = MmsValue_newUnsignedFromBerInteger(berInteger); + } + else if (dataElement->present == Data_PR_visiblestring) { + value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, + dataElement->choice.visiblestring.size); + } + else if (dataElement->present == Data_PR_mMSString) { + value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, + dataElement->choice.mMSString.size); + } + else if (dataElement->present == Data_PR_bitstring) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_BIT_STRING; + int size = dataElement->choice.bitstring.size; + + value->value.bitString.size = (size * 8) + - dataElement->choice.bitstring.bits_unused; + + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + dataElement->choice.bitstring.buf, size); + + } + else if (dataElement->present == Data_PR_floatingpoint) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + int size = dataElement->choice.floatingpoint.size; + + value->type = MMS_FLOAT; + + if (size == 5) { /* FLOAT32 */ + value->value.floatingPoint.formatWidth = 32; + value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; + + uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); + + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); +#else + memcpy(value->value.floatingPoint.buf, floatBuf, 4); +#endif + } + + if (size == 9) { /* FLOAT64 */ + value->value.floatingPoint.formatWidth = 64; + value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; + + uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); + + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); +#else + memcpy(value->value.floatingPoint.buf, floatBuf, 8); +#endif + } + } + else if (dataElement->present == Data_PR_utctime) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_UTC_TIME; + memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); + } + else if (dataElement->present == Data_PR_octetstring) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_OCTET_STRING; + int size = dataElement->choice.octetstring.size; + value->value.octetString.size = size; + value->value.octetString.maxSize = size; + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); + } + else if (dataElement->present == Data_PR_binarytime) { + int size = dataElement->choice.binarytime.size; + + if (size <= 6) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BINARY_TIME; + value->value.binaryTime.size = size; + memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size); + } + } + else if (dataElement->present == Data_PR_boolean) { + value = MmsValue_newBoolean(dataElement->choice.boolean); + } + + } + + return value; +} + +char* +mmsMsg_createStringFromAsnIdentifier(Identifier_t identifier) +{ + char* str = createStringFromBuffer(identifier.buf, identifier.size); + + return str; +} + + +void +mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, int bufSize) +{ + if (identifier.size < bufSize) { + memcpy(buffer, identifier.buf, identifier.size); + buffer[identifier.size] = 0; + } + else { + + if (DEBUG_MMS_SERVER || DEBUG_MMS_CLIENT) + printf("MMS_COMMON: mms_common_msg.c: ASN1 identifier to long!\n"); + + buffer[0] = 0; + } +} diff --git a/src/mms/iso_mms/common/mms_type_spec.c b/src/mms/iso_mms/common/mms_type_spec.c new file mode 100644 index 0000000..e88e70d --- /dev/null +++ b/src/mms/iso_mms/common/mms_type_spec.c @@ -0,0 +1,235 @@ +/* + * mms_type_spec.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_common.h" +#include "mms_type_spec.h" +#include "mms_value_internal.h" + +void +MmsVariableSpecification_destroy(MmsVariableSpecification* typeSpec) +{ + if (typeSpec->name != NULL) + GLOBAL_FREEMEM(typeSpec->name); + + if (typeSpec->type == MMS_STRUCTURE) { + int elementCount = typeSpec->typeSpec.structure.elementCount; + int i; + for (i = 0; i < elementCount; i++) { + MmsVariableSpecification_destroy(typeSpec->typeSpec.structure.elements[i]); + } + + GLOBAL_FREEMEM(typeSpec->typeSpec.structure.elements); + } + else if (typeSpec->type == MMS_ARRAY) { + MmsVariableSpecification_destroy(typeSpec->typeSpec.array.elementTypeSpec); + } + + GLOBAL_FREEMEM(typeSpec); +} + +static size_t +directChildStrLen(const char* childId) +{ + size_t i = 0; + size_t childIdLen = strlen(childId); + while (i < childIdLen) { + if (*(childId + i) == '$') + break; + i++; + } + + return i; +} + +MmsValue* +MmsVariableSpecification_getChildValue(MmsVariableSpecification* typeSpec, MmsValue* value, const char* childId) +{ + if (typeSpec->type == MMS_STRUCTURE) { + size_t childLen = directChildStrLen(childId); + int i; + for (i = 0; i < typeSpec->typeSpec.structure.elementCount; i++) { + + if (strlen(typeSpec->typeSpec.structure.elements[i]->name) == childLen) { + + if (strncmp(typeSpec->typeSpec.structure.elements[i]->name, childId, childLen) == 0) { + if (childLen == strlen(childId)) { + return value->value.structure.components[i]; + } + else { + return MmsVariableSpecification_getChildValue(typeSpec->typeSpec.structure.elements[i], + value->value.structure.components[i], childId + childLen + 1); + } + } + } + } + return NULL; + } + else + return NULL; +} + +MmsType +MmsVariableSpecification_getType(MmsVariableSpecification* self) +{ + return self->type; +} + +const char* +MmsVariableSpecification_getName(MmsVariableSpecification* self) +{ + return self->name; +} + +LinkedList /* */ +MmsVariableSpecification_getStructureElements(MmsVariableSpecification* self) +{ + if (self->type != MMS_STRUCTURE) + return NULL; + + LinkedList elementNames = LinkedList_create(); + + int i; + for (i = 0; i < self->typeSpec.structure.elementCount; i++) { + MmsVariableSpecification* typeSpec = self->typeSpec.structure.elements[i]; + + LinkedList_add(elementNames, copyString(typeSpec->name)); + } + + return elementNames; +} + +MmsVariableSpecification* +MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* variable, const char* nameId) +{ + const char* separator = strchr(nameId, '$'); + + int i; + + if (separator == NULL) { + + i = 0; + + if (variable->type == MMS_STRUCTURE) { + for (i = 0; i < variable->typeSpec.structure.elementCount; i++) { + if (strcmp(variable->typeSpec.structure.elements[i]->name, nameId) == 0) { + return variable->typeSpec.structure.elements[i]; + } + } + } + + return NULL; + } + else { + MmsVariableSpecification* namedVariable = NULL; + i = 0; + + for (i = 0; i < variable->typeSpec.structure.elementCount; i++) { + + if (strlen(variable->typeSpec.structure.elements[i]->name) == (unsigned) (separator - nameId)) { + + if (strncmp(variable->typeSpec.structure.elements[i]->name, nameId, separator - nameId) == 0) { + namedVariable = variable->typeSpec.structure.elements[i]; + break; + } + + } + } + + if (namedVariable != NULL) { + if (namedVariable->type == MMS_STRUCTURE) { + namedVariable = MmsVariableSpecification_getNamedVariableRecursive(namedVariable, separator + 1); + } + else if (namedVariable->type == MMS_ARRAY) { + namedVariable = namedVariable->typeSpec.array.elementTypeSpec; + + namedVariable = MmsVariableSpecification_getNamedVariableRecursive(namedVariable, separator + 1); + } + } + + return namedVariable; + } +} + +int +MmsVariableSpecification_getSize(MmsVariableSpecification* self) +{ + switch (self->type) { + case MMS_STRUCTURE: + return self->typeSpec.structure.elementCount; + case MMS_ARRAY: + return self->typeSpec.array.elementCount; + case MMS_INTEGER: + return self->typeSpec.integer; + case MMS_UNSIGNED: + return self->typeSpec.unsignedInteger; + case MMS_FLOAT: + return self->typeSpec.floatingpoint.formatWidth; + case MMS_BIT_STRING: + return self->typeSpec.bitString; + case MMS_BINARY_TIME: + return self->typeSpec.binaryTime; + case MMS_OCTET_STRING: + return self->typeSpec.octetString; + case MMS_VISIBLE_STRING: + return self->typeSpec.visibleString; + case MMS_STRING: + return self->typeSpec.mmsString; + default: + return -1; + } + +} + +MmsVariableSpecification* +MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification* self, int index) +{ + if (self->type != MMS_STRUCTURE) + return NULL; + + if (index >= self->typeSpec.structure.elementCount) + return NULL; + + if (index < 0) + return NULL; + + return self->typeSpec.structure.elements[index]; +} + +MmsVariableSpecification* +MmsVariableSpecification_getArrayElementSpecification(MmsVariableSpecification* self) +{ + if (self->type != MMS_ARRAY) + return NULL; + + return self->typeSpec.array.elementTypeSpec; +} + +int +MmsVariableSpecification_getExponentWidth(MmsVariableSpecification* self) +{ + if (self->type != MMS_FLOAT) + return -1; + + return (int) self->typeSpec.floatingpoint.exponentWidth; +} diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c new file mode 100644 index 0000000..8c9492a --- /dev/null +++ b/src/mms/iso_mms/common/mms_value.c @@ -0,0 +1,2070 @@ +/* + * MmsValue.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_common.h" +#include "mms_value.h" +#include "mms_type_spec.h" + +#include "mms_common_internal.h" + +#include "mms_value_internal.h" + +#include "conversions.h" + +#include /* for ctime_r */ + +static inline int +bitStringByteSize(const MmsValue* value) +{ + int bitSize = value->value.bitString.size; + return (bitSize / 8) + ((bitSize % 8) > 0); +} + +int +MmsValue_getBitStringByteSize(const MmsValue* self) +{ + return bitStringByteSize(self); +} + +static void +updateStructuredComponent(MmsValue* self, const MmsValue* update) +{ + int componentCount; + MmsValue** selfValues; + MmsValue** updateValues; + + componentCount = self->value.structure.size; + selfValues = self->value.structure.components; + updateValues = update->value.structure.components; + + int i; + for (i = 0; i < componentCount; i++) { + MmsValue_update(selfValues[i], updateValues[i]); + } +} + +MmsValue* +MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_INTEGER; + self->value.integer = berInteger; + + return self; +} + +MmsValue* +MmsValue_newUnsignedFromBerInteger(Asn1PrimitiveValue* berInteger) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_UNSIGNED; + self->value.integer = berInteger; + + return self; +} + +bool +MmsValue_equals(const MmsValue* self, const MmsValue* otherValue) +{ + if (self->type == otherValue->type) { + switch (self->type) { + case MMS_ARRAY: + case MMS_STRUCTURE: + if (self->value.structure.size == otherValue->value.structure.size) { + int componentCount = self->value.structure.size; + + int i; + for (i = 0; i < componentCount; i++) { + if (!MmsValue_equals(self->value.structure.components[i], + otherValue->value.structure.components[i])) + return false; + } + + return true; + } + break; + + case MMS_BOOLEAN: + if (self->value.boolean == otherValue->value.boolean) + return true; + break; + case MMS_FLOAT: + if (memcmp(self->value.floatingPoint.buf, otherValue->value.floatingPoint.buf, + self->value.floatingPoint.formatWidth / 8) == 0) + return true; + break; + case MMS_INTEGER: + case MMS_UNSIGNED: + return Asn1PrimitivaValue_compare(self->value.integer, otherValue->value.integer); + break; + case MMS_UTC_TIME: + if (memcmp(self->value.utcTime, otherValue->value.utcTime, 8) == 0) + return true; + break; + case MMS_BIT_STRING: + if (self->value.bitString.size == otherValue->value.bitString.size) { + if (memcmp(self->value.bitString.buf, otherValue->value.bitString.buf, + bitStringByteSize(self)) == 0) + return true; + + } + break; + case MMS_BINARY_TIME: + if (self->value.binaryTime.size == otherValue->value.binaryTime.size) { + if (memcmp(self->value.binaryTime.buf, otherValue->value.binaryTime.buf, + self->value.binaryTime.size) == 0) + return true; + } + break; + + case MMS_OCTET_STRING: + if (self->value.octetString.size == otherValue->value.octetString.size) { + if (memcmp(self->value.octetString.buf, otherValue->value.octetString.buf, + self->value.octetString.size) == 0) + return true; + } + break; + + case MMS_VISIBLE_STRING: + case MMS_STRING: + if (self->value.visibleString.buf != NULL) { + if (otherValue->value.visibleString.buf != NULL) { + if (strcmp(self->value.visibleString.buf, otherValue->value.visibleString.buf) == 0) + return true; + } + } + else { + if (otherValue->value.visibleString.buf == NULL) + return true; + } + break; + + + + case MMS_DATA_ACCESS_ERROR: + if (self->value.dataAccessError == otherValue->value.dataAccessError) + return true; + break; + + default: + break; + } + return false; + + } + else + return false; +} + +bool +MmsValue_equalTypes(const MmsValue* self, const MmsValue* otherValue) +{ + if (self->type == otherValue->type) { + switch (self->type) { + case MMS_ARRAY: + case MMS_STRUCTURE: + if (self->value.structure.size == otherValue->value.structure.size) { + int componentCount = self->value.structure.size; + + int i; + for (i = 0; i < componentCount; i++) { + if (!MmsValue_equalTypes(self->value.structure.components[i], + otherValue->value.structure.components[i])) + return false; + } + + return true; + } + else + return false; + break; + + default: + return true; + } + } + else + return false; +} + +bool +MmsValue_update(MmsValue* self, const MmsValue* update) +{ + if (self->type == update->type) { + switch (self->type) { + case MMS_STRUCTURE: + case MMS_ARRAY: + updateStructuredComponent(self, update); + break; + case MMS_BOOLEAN: + self->value.boolean = update->value.boolean; + break; + case MMS_FLOAT: + if (self->value.floatingPoint.formatWidth == update->value.floatingPoint.formatWidth) { + self->value.floatingPoint.exponentWidth = update->value.floatingPoint.exponentWidth; + memcpy(self->value.floatingPoint.buf, update->value.floatingPoint.buf, + self->value.floatingPoint.formatWidth / 8); + } + else return false; + break; + case MMS_INTEGER: + case MMS_UNSIGNED: + if (BerInteger_setFromBerInteger(self->value.integer, update->value.integer)) + return true; + else + return false; + break; + case MMS_UTC_TIME: + memcpy(self->value.utcTime, update->value.utcTime, 8); + break; + case MMS_BIT_STRING: + if (self->value.bitString.size == update->value.bitString.size) + memcpy(self->value.bitString.buf, update->value.bitString.buf, bitStringByteSize(self)); + else return false; + break; + case MMS_OCTET_STRING: + if (self->value.octetString.maxSize == update->value.octetString.maxSize) { + memcpy(self->value.octetString.buf, update->value.octetString.buf, + update->value.octetString.size); + + self->value.octetString.size = update->value.octetString.size; + } + else return false; + break; + case MMS_VISIBLE_STRING: + MmsValue_setVisibleString(self, update->value.visibleString.buf); + break; + case MMS_STRING: + MmsValue_setMmsString(self, update->value.visibleString.buf); + break; + case MMS_BINARY_TIME: + self->value.binaryTime.size = update->value.binaryTime.size; + memcpy(self->value.binaryTime.buf, update->value.binaryTime.buf, + update->value.binaryTime.size); + break; + default: + return false; + break; + } + return true; + } + else + return false; +} + +MmsValue* +MmsValue_newDataAccessError(MmsDataAccessError accessError) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_DATA_ACCESS_ERROR; + self->value.dataAccessError = accessError; + + return self; +} + +MmsValue* +MmsValue_newBitString(int bitSize) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; + + if (self == NULL) + return NULL; + + self->type = MMS_BIT_STRING; + self->value.bitString.size = abs(bitSize); + self->value.bitString.buf = (uint8_t*) GLOBAL_CALLOC(bitStringByteSize(self), 1); + + return self; +} + +static int +getBitStringByteSize(const MmsValue* self) +{ + int byteSize; + + if (self->value.bitString.size % 8) + byteSize = (self->value.bitString.size / 8) + 1; + else + byteSize = self->value.bitString.size / 8; + + return byteSize; +} + +void +MmsValue_deleteAllBitStringBits(MmsValue* self) +{ + int byteSize = getBitStringByteSize(self); + + int i; + for (i = 0; i < byteSize; i++) { + self->value.bitString.buf[i] = 0; + } +} + +void +MmsValue_setAllBitStringBits(MmsValue* self) +{ + int byteSize = getBitStringByteSize(self); + + int i; + for (i = 0; i < byteSize; i++) { + self->value.bitString.buf[i] = 0xff; + } + + int padding = (byteSize * 8) - self->value.bitString.size; + + uint8_t paddingMask = 0; + + for (i = 0; i < padding; i++) { + paddingMask += (1 << i); + } + + paddingMask = ~paddingMask; + + self->value.bitString.buf[byteSize - 1] = self->value.bitString.buf[byteSize - 1] & paddingMask; +} + +int +MmsValue_getBitStringSize(const MmsValue* self) +{ + return self->value.bitString.size; +} + +int +MmsValue_getNumberOfSetBits(const MmsValue* self) +{ + int setBitsCount = 0; + + int byteSize = getBitStringByteSize(self); + + int i; + for (i = 0; i < byteSize; i++) { + uint8_t currentByte = self->value.bitString.buf[i]; + + while (currentByte != 0) { + if ((currentByte & 1) == 1) + setBitsCount++; + currentByte >>= 1; + } + } + + return setBitsCount; +} + +void +MmsValue_setBitStringBit(MmsValue* self, int bitPos, bool value) +{ + if (bitPos < self->value.bitString.size) { + int bytePos = bitPos / 8; + int bitPosInByte = 7 - (bitPos % 8); + + int bitMask = (1 << bitPosInByte); + + if (value) + self->value.bitString.buf[bytePos] |= bitMask; + else + self->value.bitString.buf[bytePos] &= (~bitMask); + } +} + +bool +MmsValue_getBitStringBit(const MmsValue* self, int bitPos) +{ + if (bitPos < self->value.bitString.size) { + int bytePos = bitPos / 8; + + int bitPosInByte = 7 - (bitPos % 8); + + int bitMask = (1 << bitPosInByte); + + if ((self->value.bitString.buf[bytePos] & bitMask) > 0) + return true; + else + return false; + + } + else return false; /* out of range bits are always zero */ +} + +uint32_t +MmsValue_getBitStringAsInteger(const MmsValue* self) +{ + uint32_t value = 0; + + int bitPos; + + for (bitPos = 0; bitPos < self->value.bitString.size; bitPos++) { + if (MmsValue_getBitStringBit(self, bitPos)) { + value += (1 << bitPos); + } + } + + return value; +} + +void +MmsValue_setBitStringFromInteger(MmsValue* self, uint32_t intValue) +{ + int bitPos; + + for (bitPos = 0; bitPos < self->value.bitString.size; bitPos++) { + if ((intValue & 1) == 1) + MmsValue_setBitStringBit(self, bitPos, true); + else + MmsValue_setBitStringBit(self, bitPos, false); + + intValue = intValue >> 1; + } +} + +uint32_t +MmsValue_getBitStringAsIntegerBigEndian(const MmsValue* self) +{ + uint32_t value = 0; + + int bitPos; + int i = 0; + + for (bitPos = (self->value.bitString.size - 1); bitPos >= 0; bitPos--) { + + if (MmsValue_getBitStringBit(self, bitPos)) { + value += (1 << i); + } + + i++; + } + + return value; +} + +void +MmsValue_setBitStringFromIntegerBigEndian(MmsValue* self, uint32_t intValue) +{ + int bitPos; + + for (bitPos = (self->value.bitString.size - 1); bitPos >= 0; bitPos--) { + if ((intValue & 1) == 1) + MmsValue_setBitStringBit(self, bitPos, true); + else + MmsValue_setBitStringBit(self, bitPos, false); + + intValue = intValue >> 1; + } +} + + +MmsValue* +MmsValue_newFloat(float variable) +{ + MmsValue* self = (MmsValue*) GLOBAL_MALLOC(sizeof(MmsValue));; + + if (self == NULL) + return NULL; + + self->type = MMS_FLOAT; + self->value.floatingPoint.formatWidth = 32; + self->value.floatingPoint.exponentWidth = 8; + self->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); + + *((float*) self->value.floatingPoint.buf) = variable; + + return self; +} + +void +MmsValue_setFloat(MmsValue* value, float newFloatValue) +{ + if (value->type == MMS_FLOAT) { + if (value->value.floatingPoint.formatWidth == 32) { + *((float*) value->value.floatingPoint.buf) = newFloatValue; + } + else if (value->value.floatingPoint.formatWidth == 64) { + *((double*) value->value.floatingPoint.buf) = (double) newFloatValue; + } + } +} + +void +MmsValue_setDouble(MmsValue* value, double newFloatValue) +{ + if (value->type == MMS_FLOAT) { + if (value->value.floatingPoint.formatWidth == 32) { + *((float*) value->value.floatingPoint.buf) = (float) newFloatValue; + } + else if (value->value.floatingPoint.formatWidth == 64) { + *((double*) value->value.floatingPoint.buf) = newFloatValue; + } + } +} + +MmsValue* +MmsValue_newDouble(double variable) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_FLOAT; + self->value.floatingPoint.formatWidth = 64; + self->value.floatingPoint.exponentWidth = 11; + self->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); + + *((double*) self->value.floatingPoint.buf) = variable; + + return self; +} + +MmsValue* +MmsValue_newIntegerFromInt8(int8_t integer) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; + + self->type = MMS_INTEGER; + self->value.integer = BerInteger_createFromInt32((int32_t) integer); + + return self; +} + +MmsValue* +MmsValue_newIntegerFromInt16(int16_t integer) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; + + self->type = MMS_INTEGER; + self->value.integer = BerInteger_createFromInt32((int32_t) integer); + + return self; +} + +void +MmsValue_setInt8(MmsValue* self, int8_t integer) +{ + if (self->type == MMS_INTEGER) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 1) { + BerInteger_setInt32(self->value.integer, (int32_t) integer); + } + } +} + +void +MmsValue_setInt16(MmsValue* self, int16_t integer) +{ + if (self->type == MMS_INTEGER) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 1) { + BerInteger_setInt32(self->value.integer, (int32_t) integer); + } + } +} + +void +MmsValue_setInt32(MmsValue* self, int32_t integer) +{ + if (self->type == MMS_INTEGER) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 4) { + BerInteger_setInt32(self->value.integer, integer); + } + } +} + +void +MmsValue_setInt64(MmsValue* self, int64_t integer) +{ + if (self->type == MMS_INTEGER) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 8) { + BerInteger_setInt64(self->value.integer, integer); + } + } +} + +void +MmsValue_setUint32(MmsValue* self, uint32_t integer) +{ + if (self->type == MMS_UNSIGNED) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 4) { + BerInteger_setUint32(self->value.integer, integer); + } + } +} + + +void +MmsValue_setUint16(MmsValue* self, uint16_t integer) +{ + if (self->type == MMS_UNSIGNED) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 2) { + BerInteger_setUint16(self->value.integer, integer); + } + } +} + + +void +MmsValue_setUint8(MmsValue* self, uint8_t integer) +{ + if (self->type == MMS_UNSIGNED) { + if (Asn1PrimitiveValue_getMaxSize(self->value.integer) >= 1) { + BerInteger_setUint8(self->value.integer, integer); + } + } + +} + + +void +MmsValue_setBoolean(MmsValue* self, bool boolValue) +{ + self->value.boolean = boolValue; +} + +bool +MmsValue_getBoolean(const MmsValue* self) +{ + return self->value.boolean; +} + + +MmsValue* +MmsValue_setUtcTime(MmsValue* self, uint32_t timeval) +{ + uint8_t* timeArray = (uint8_t*) &timeval; + uint8_t* valueArray = self->value.utcTime; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(valueArray, timeArray, 4); +#else + memcpy(valueArray, timeArray, 4); +#endif + + return self; +} + + +MmsValue* +MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval) +{ + uint32_t timeval32 = (timeval / 1000LL); + + uint8_t* timeArray = (uint8_t*) &timeval32; + uint8_t* valueArray = self->value.utcTime; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder(valueArray, timeArray, 4); +#else + memcpy(valueArray, timeArray, 4); +#endif + + uint32_t remainder = (timeval % 1000LL); + uint32_t fractionOfSecond = (remainder) * 16777 + ((remainder * 216) / 1000); + + /* encode fraction of second */ + valueArray[4] = ((fractionOfSecond >> 16) & 0xff); + valueArray[5] = ((fractionOfSecond >> 8) & 0xff); + valueArray[6] = (fractionOfSecond & 0xff); + + /* encode time quality */ + valueArray[7] = 0x0a; /* 10 bit sub-second time accuracy */ + + return self; +} + +void +MmsValue_setUtcTimeQuality(MmsValue* self, uint8_t timeQuality) +{ + self->value.utcTime[7] = timeQuality; +} + +uint8_t +MmsValue_getUtcTimeQuality(const MmsValue* self) +{ + return self->value.utcTime[7]; +} + +void +MmsValue_setUtcTimeByBuffer(MmsValue* self, const uint8_t* buffer) +{ + uint8_t* valueArray = self->value.utcTime; + + int i; + for (i = 0; i < 8; i++) { + valueArray[i] = buffer[i]; + } +} + +uint8_t* +MmsValue_getUtcTimeBuffer(MmsValue* self) +{ + return self->value.utcTime; +} + +uint64_t +MmsValue_getUtcTimeInMs(const MmsValue* self) +{ + uint32_t timeval32; + const uint8_t* valueArray = self->value.utcTime; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder((uint8_t*) &timeval32, valueArray, 4); +#else + memcpy((uint8_t*) &timeval32, valueArray, 4); +#endif + + uint32_t fractionOfSecond = 0; + + fractionOfSecond = (valueArray[4] << 16); + fractionOfSecond += (valueArray[5] << 8); + fractionOfSecond += (valueArray[6]); + + uint32_t remainder = fractionOfSecond / 16777; + + uint64_t msVal = (timeval32 * 1000LL) + remainder; + + return msVal; +} + +uint64_t +MmsValue_getUtcTimeInMsWithUs(const MmsValue* self, uint32_t* usec) +{ + uint32_t timeval32; + const uint8_t* valueArray = self->value.utcTime; + +#if (ORDER_LITTLE_ENDIAN == 1) + memcpyReverseByteOrder((uint8_t*) &timeval32, valueArray, 4); +#else + memcpy((uint8_t*)&timeval32, valueArray, 4); +#endif + + uint64_t fractionOfSecond = 0; + + fractionOfSecond = (valueArray[4] << 16); + fractionOfSecond += (valueArray[5] << 8); + fractionOfSecond += (valueArray[6]); + + uint64_t remainder = fractionOfSecond * 1000000ULL / 0x1000000ULL; // in usec + + uint64_t msVal = (timeval32 * 1000LL) + (remainder / 1000LL); + + if (usec != NULL) + *usec = remainder % 1000LL; + + return msVal; +} + + +MmsValue* +MmsValue_newIntegerFromInt32(int32_t integer) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_INTEGER; + self->value.integer = BerInteger_createFromInt32(integer); + + return self; +} + +MmsValue* +MmsValue_newUnsignedFromUint32(uint32_t integer) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; + + if (self == NULL) + return NULL; + + self->type = MMS_UNSIGNED; + self->value.integer = BerInteger_createFromUint32(integer); + + return self; +} + +MmsValue* +MmsValue_newIntegerFromInt64(int64_t integer) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; + + if (self == NULL) + return NULL; + + self->type = MMS_INTEGER; + self->value.integer = BerInteger_createFromInt64(integer); + + return self; +} + +/** + * Convert signed integer to int32_t + */ +int32_t +MmsValue_toInt32(const MmsValue* self) +{ + int32_t integerValue = 0; + + if ((self->type == MMS_INTEGER) || (self->type == MMS_UNSIGNED)) + BerInteger_toInt32(self->value.integer, &integerValue); + + return integerValue; +} + +uint32_t +MmsValue_toUint32(const MmsValue* self) +{ + uint32_t integerValue = 0; + + if ((self->type == MMS_INTEGER) || (self->type == MMS_UNSIGNED)) + BerInteger_toUint32(self->value.integer, &integerValue); + + return integerValue; +} + +/** + * Convert signed integer to int64_t and do sign extension if required + */ +int64_t +MmsValue_toInt64(const MmsValue* self) +{ + int64_t integerValue = 0; + + if ((self->type == MMS_INTEGER) || (self->type == MMS_UNSIGNED)) + BerInteger_toInt64(self->value.integer, &integerValue); + + return integerValue; +} + +float +MmsValue_toFloat(const MmsValue* self) +{ + if (self->type == MMS_FLOAT) { + if (self->value.floatingPoint.formatWidth == 32) { + float val; + + val = *((float*) (self->value.floatingPoint.buf)); + return val; + } + else if (self->value.floatingPoint.formatWidth == 64) { + float val; + val = *((double*) (self->value.floatingPoint.buf)); + return val; + } + } + else + printf("MmsValue_toFloat: conversion error. Wrong type!\n"); + + return 0.f; +} + +double +MmsValue_toDouble(const MmsValue* self) +{ + if (self->type == MMS_FLOAT) { + double val; + if (self->value.floatingPoint.formatWidth == 32) { + val = (double) *((float*) (self->value.floatingPoint.buf)); + return val; + } + if (self->value.floatingPoint.formatWidth == 64) { + val = *((double*) (self->value.floatingPoint.buf)); + return val; + } + } + + return 0.f; +} + + + +uint32_t +MmsValue_toUnixTimestamp(const MmsValue* self) +{ + uint32_t timestamp; + uint8_t* timeArray = (uint8_t*) ×tamp; + +#if (ORDER_LITTLE_ENDIAN == 1) + timeArray[0] = self->value.utcTime[3]; + timeArray[1] = self->value.utcTime[2]; + timeArray[2] = self->value.utcTime[1]; + timeArray[3] = self->value.utcTime[0]; +#else + timeArray[0] = self->value.utcTime[0]; + timeArray[1] = self->value.utcTime[1]; + timeArray[2] = self->value.utcTime[2]; + timeArray[3] = self->value.utcTime[3]; +#endif + + return timestamp; +} + +int +MmsValue_getSizeInMemory(const MmsValue* self) +{ + int memorySize = sizeof(MmsValue); + + switch(self->type) { + case MMS_ARRAY: + case MMS_STRUCTURE: + { + memorySize += (sizeof(MmsValue*) * self->value.structure.size); + + int i; + for (i = 0; i < self->value.structure.size; i++) + memorySize += MmsValue_getSizeInMemory(self->value.structure.components[i]); + } + break; + + case MMS_BIT_STRING: + memorySize += bitStringByteSize(self); + break; + + case MMS_INTEGER: + case MMS_UNSIGNED: + memorySize += sizeof(Asn1PrimitiveValue); + memorySize += self->value.integer->maxSize; + break; + + case MMS_FLOAT: + memorySize += (self->value.floatingPoint.formatWidth / 8); + break; + + case MMS_OCTET_STRING: + memorySize += self->value.octetString.maxSize; + break; + + case MMS_STRING: + case MMS_VISIBLE_STRING: + memorySize += strlen(self->value.visibleString.buf); + memorySize += 1; /* add space for 0 character */ + break; + + default: + break; + } + + return memorySize; +} + +uint8_t* +MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress) +{ + MmsValue* newValue = (MmsValue*) destinationAddress; + + memcpy(destinationAddress, self, sizeof(MmsValue)); + destinationAddress += sizeof(MmsValue); + + switch (self->type) { + case MMS_ARRAY: + case MMS_STRUCTURE: + { + newValue->value.structure.components = (MmsValue**) destinationAddress; + destinationAddress += (sizeof(MmsValue*) * self->value.structure.size); + + int i; + for (i = 0; i < self->value.structure.size; i++) { + newValue->value.structure.components[i] = (MmsValue*) destinationAddress; + destinationAddress = MmsValue_cloneToBuffer(self->value.structure.components[i], destinationAddress); + } + } + break; + + case MMS_BIT_STRING: + memcpy(destinationAddress, self->value.bitString.buf, bitStringByteSize(self)); + newValue->value.bitString.buf = destinationAddress; + destinationAddress += bitStringByteSize(self); + break; + + case MMS_INTEGER: + case MMS_UNSIGNED: + { + newValue->value.integer = (Asn1PrimitiveValue*) destinationAddress; + Asn1PrimitiveValue* newAsn1Value = (Asn1PrimitiveValue*) destinationAddress; + memcpy(destinationAddress, self->value.integer, sizeof(Asn1PrimitiveValue)); + destinationAddress += sizeof(Asn1PrimitiveValue); + newAsn1Value->octets = destinationAddress; + memcpy(destinationAddress, self->value.integer->octets, self->value.integer->maxSize); + destinationAddress += self->value.integer->maxSize; + } + break; + + case MMS_FLOAT: + { + int floatSizeInBytes = (self->value.floatingPoint.formatWidth / 8); + + newValue->value.floatingPoint.buf = destinationAddress; + memcpy(destinationAddress, self->value.floatingPoint.buf, floatSizeInBytes); + destinationAddress += floatSizeInBytes; + } + break; + + case MMS_OCTET_STRING: + newValue->value.octetString.buf = destinationAddress; + memcpy(destinationAddress, self->value.octetString.buf, self->value.octetString.maxSize); + destinationAddress += self->value.octetString.maxSize; + break; + + case MMS_STRING: + case MMS_VISIBLE_STRING: + newValue->value.visibleString.buf = (char*) destinationAddress; + newValue->value.visibleString.size = self->value.visibleString.size; + strcpy((char*) destinationAddress, self->value.visibleString.buf); + destinationAddress += (strlen(self->value.visibleString.buf) + 1); + break; + + default: + break; + } + + return destinationAddress; +} + +// create a deep clone +MmsValue* +MmsValue_clone(const MmsValue* self) +{ + MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (newValue == NULL) + goto exit_function; + + newValue->deleteValue = self->deleteValue; + newValue->type = self->type; + int size; + + switch(self->type) { + + case MMS_ARRAY: + case MMS_STRUCTURE: + { + int componentCount = self->value.structure.size; + newValue->value.structure.size = componentCount; + newValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + int i; + for (i = 0; i < componentCount; i++) { + newValue->value.structure.components[i] = + MmsValue_clone(self->value.structure.components[i]); + } + } + break; + + case MMS_INTEGER: + case MMS_UNSIGNED: + newValue->value.integer = Asn1PrimitiveValue_clone(self->value.integer); + break; + + case MMS_FLOAT: + newValue->value.floatingPoint.formatWidth = self->value.floatingPoint.formatWidth; + newValue->value.floatingPoint.exponentWidth = self->value.floatingPoint.exponentWidth; + size = self->value.floatingPoint.formatWidth / 8; + newValue->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(newValue->value.floatingPoint.buf, self->value.floatingPoint.buf, size); + break; + + case MMS_BIT_STRING: + newValue->value.bitString.size = self->value.bitString.size; + size = bitStringByteSize(self); + newValue->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(newValue->value.bitString.buf, self->value.bitString.buf, size); + break; + + case MMS_BOOLEAN: + newValue->value.boolean = self->value.boolean; + break; + + case MMS_OCTET_STRING: + size = self->value.octetString.size; + newValue->value.octetString.size = size; + newValue->value.octetString.maxSize = self->value.octetString.maxSize; + newValue->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(self->value.octetString.maxSize); + memcpy(newValue->value.octetString.buf, self->value.octetString.buf, size); + break; + + case MMS_UTC_TIME: + memcpy(newValue->value.utcTime, self->value.utcTime, 8); + break; + + case MMS_BINARY_TIME: + newValue->value.binaryTime.size = self->value.binaryTime.size; + memcpy(newValue->value.binaryTime.buf, self->value.binaryTime.buf, 6); + break; + + case MMS_VISIBLE_STRING: + case MMS_STRING: + size = self->value.visibleString.size; + newValue->value.visibleString.buf = (char*) GLOBAL_MALLOC(size + 1); + newValue->value.visibleString.size = size; + strcpy(newValue->value.visibleString.buf, self->value.visibleString.buf); + break; + + case MMS_DATA_ACCESS_ERROR: + newValue->value.dataAccessError = self->value.dataAccessError; + break; + + default: + break; + } + +exit_function: + return newValue; +} + +uint32_t +MmsValue_getArraySize(const MmsValue* self) +{ + return self->value.structure.size; +} + +void +MmsValue_deleteIfNotNull(MmsValue* self) +{ + if (self != NULL) + MmsValue_delete(self); +} + +void +MmsValue_delete(MmsValue* self) +{ + switch (self->type) { + case MMS_INTEGER: + case MMS_UNSIGNED: + Asn1PrimitiveValue_destroy(self->value.integer); + break; + case MMS_FLOAT: + GLOBAL_FREEMEM(self->value.floatingPoint.buf); + break; + case MMS_BIT_STRING: + GLOBAL_FREEMEM(self->value.bitString.buf); + break; + case MMS_OCTET_STRING: + GLOBAL_FREEMEM(self->value.octetString.buf); + break; + case MMS_VISIBLE_STRING: + case MMS_STRING: + if (self->value.visibleString.buf != NULL) + GLOBAL_FREEMEM(self->value.visibleString.buf); + break; + case MMS_ARRAY: + case MMS_STRUCTURE: + { + int componentCount = self->value.structure.size; + int i; + + for (i = 0; i < componentCount; i++) { + if (self->value.structure.components[i] != NULL) + MmsValue_delete(self->value.structure.components[i]); + } + } + GLOBAL_FREEMEM(self->value.structure.components); + break; + default: + break; + } + + GLOBAL_FREEMEM(self); +} + +/* delete only when deleteValue field set */ +void +MmsValue_deleteConditional(MmsValue* self) +{ + if (self->deleteValue == 1) { + + switch (self->type) { + case MMS_INTEGER: + case MMS_UNSIGNED: + Asn1PrimitiveValue_destroy(self->value.integer); + break; + case MMS_FLOAT: + GLOBAL_FREEMEM(self->value.floatingPoint.buf); + break; + case MMS_BIT_STRING: + GLOBAL_FREEMEM(self->value.bitString.buf); + break; + case MMS_OCTET_STRING: + GLOBAL_FREEMEM(self->value.octetString.buf); + break; + case MMS_VISIBLE_STRING: + case MMS_STRING: + if (self->value.visibleString.buf != NULL) + GLOBAL_FREEMEM(self->value.visibleString.buf); + break; + case MMS_ARRAY: + case MMS_STRUCTURE: + { + int componentCount = self->value.structure.size; + int i; + + for (i = 0; i < componentCount; i++) { + if (self->value.structure.components[i] != NULL) + MmsValue_deleteConditional(self->value.structure.components[i]); + } + } + GLOBAL_FREEMEM(self->value.structure.components); + break; + default: + break; + } + + GLOBAL_FREEMEM(self); + } +} + +MmsValue* +MmsValue_newInteger(int size /*integer size in bits*/) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_INTEGER; + + if (size <= 32) + self->value.integer = BerInteger_createInt32(); + else + self->value.integer = BerInteger_createInt64(); + + return self; +} + +MmsValue* +MmsValue_newUnsigned(int size /*integer size in bits*/) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_UNSIGNED; + + if (size <= 32) + self->value.integer = BerInteger_createInt32(); + else + self->value.integer = BerInteger_createInt64(); + + return self; +} + +MmsValue* +MmsValue_newBoolean(bool boolean) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_BOOLEAN; + + if (boolean == true) + self->value.boolean = 1; + else + self->value.boolean = 0; + + return self; +} + +MmsValue* +MmsValue_newOctetString(int size, int maxSize) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_OCTET_STRING; + self->value.octetString.size = size; + self->value.octetString.maxSize = maxSize; + self->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, maxSize); + + return self; +} + +void +MmsValue_setOctetString(MmsValue* self, uint8_t* buf, int size) +{ + if (size <= self->value.octetString.maxSize) { + memcpy(self->value.octetString.buf, buf, size); + self->value.octetString.size = size; + } +} + +uint16_t +MmsValue_getOctetStringSize(const MmsValue* self) +{ + return self->value.octetString.size; +} + +uint16_t +MmsValue_getOctetStringMaxSize(MmsValue* self) +{ + return self->value.octetString.maxSize; +} + +uint8_t* +MmsValue_getOctetStringBuffer(MmsValue* self) +{ + return self->value.octetString.buf; +} + +MmsValue* +MmsValue_newStructure(const MmsVariableSpecification* typeSpec) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_STRUCTURE; + int componentCount = typeSpec->typeSpec.structure.elementCount; + self->value.structure.size = componentCount; + self->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int i; + for (i = 0; i < componentCount; i++) { + self->value.structure.components[i] = + MmsValue_newDefaultValue(typeSpec->typeSpec.structure.elements[i]); + } + + return self; +} + +MmsValue* +MmsValue_newDefaultValue(const MmsVariableSpecification* typeSpec) +{ + MmsValue* self = NULL; + + switch (typeSpec->type) { + case MMS_INTEGER: + self = MmsValue_newInteger(typeSpec->typeSpec.integer); + break; + + case MMS_UNSIGNED: + self = MmsValue_newUnsigned(typeSpec->typeSpec.unsignedInteger); + break; + + case MMS_FLOAT: + self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_FLOAT; + self->value.floatingPoint.exponentWidth = typeSpec->typeSpec.floatingpoint.exponentWidth; + self->value.floatingPoint.formatWidth = typeSpec->typeSpec.floatingpoint.formatWidth; + self->value.floatingPoint.buf = (uint8_t*) GLOBAL_CALLOC(1, typeSpec->typeSpec.floatingpoint.formatWidth / 8); + break; + + case MMS_BIT_STRING: + self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_BIT_STRING; + { + int bitSize = abs(typeSpec->typeSpec.bitString); + self->value.bitString.size = bitSize; + int size = (bitSize / 8) + ((bitSize % 8) > 0); + self->value.bitString.buf = (uint8_t*) GLOBAL_CALLOC(1, size); + } + break; + + case MMS_OCTET_STRING: + self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_OCTET_STRING; + + if (typeSpec->typeSpec.octetString < 0) + self->value.octetString.size = 0; + else + self->value.octetString.size = typeSpec->typeSpec.octetString; + + self->value.octetString.maxSize = abs(typeSpec->typeSpec.octetString); + self->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, abs(typeSpec->typeSpec.octetString)); + break; + + case MMS_VISIBLE_STRING: + self = MmsValue_newVisibleStringWithSize(abs(typeSpec->typeSpec.visibleString)); + break; + + case MMS_BOOLEAN: + self = MmsValue_newBoolean(false); + break; + + case MMS_UTC_TIME: + self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_UTC_TIME; + break; + + case MMS_ARRAY: + self = MmsValue_createArray(typeSpec->typeSpec.array.elementTypeSpec, + typeSpec->typeSpec.array.elementCount); + break; + + case MMS_STRUCTURE: + self = MmsValue_newStructure(typeSpec); + break; + + case MMS_STRING: + self = MmsValue_newMmsStringWithSize(abs(typeSpec->typeSpec.visibleString)); + break; + + case MMS_BINARY_TIME: + if (typeSpec->typeSpec.binaryTime == 4) + self = MmsValue_newBinaryTime(true); + else + self = MmsValue_newBinaryTime(false); + break; + + default: + break; + } + + if (self != NULL) + self->deleteValue = 0; + +exit_function: + return self; +} + +static inline void +setVisibleStringValue(MmsValue* self, const char* string) +{ + if (self->value.visibleString.buf != NULL) { + if (string != NULL) { + + int newStringSize = strlen(string); + + if (newStringSize > self->value.visibleString.size) { + GLOBAL_FREEMEM(self->value.visibleString.buf); + self->value.visibleString.buf = (char*) GLOBAL_MALLOC(newStringSize + 1); + + if (self->value.visibleString.buf == NULL) + goto exit_function; + + self->value.visibleString.size = newStringSize; + } + + strncpy(self->value.visibleString.buf, string, self->value.visibleString.size + 1); + self->value.visibleString.buf[self->value.visibleString.size] = 0; + } + else + self->value.visibleString.buf[0] = 0; + } + +exit_function: + return; +} + +static MmsValue* +MmsValue_newString(const char* string, MmsType type) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = type; + + if (string == NULL) { + self->value.visibleString.size = 0; + self->value.visibleString.buf = NULL; + } + else { + int stringSize = strlen(string); + + self->value.visibleString.size = stringSize; + self->value.visibleString.buf = (char*) GLOBAL_MALLOC(stringSize + 1); + + if (self->value.visibleString.buf == NULL) { + GLOBAL_FREEMEM(self); + self = NULL; + goto exit_function; + } + + setVisibleStringValue(self, string); + } + +exit_function: + return self; +} + +MmsValue* +MmsValue_newVisibleString(const char* string) +{ + return MmsValue_newString(string, MMS_VISIBLE_STRING); +} + +static MmsValue* +MmsValue_newStringWithSize(int size, MmsType type) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = type; + + self->value.visibleString.size = size; + self->value.visibleString.buf = (char*) GLOBAL_MALLOC(size + 1); + + if (self->value.visibleString.buf == NULL) { + GLOBAL_FREEMEM(self); + self = NULL; + goto exit_function; + } + + self->value.visibleString.buf[0] = 0; + +exit_function: + return self; +} + +MmsValue* +MmsValue_newVisibleStringWithSize(int size) +{ + return MmsValue_newStringWithSize(size, MMS_VISIBLE_STRING); +} + +MmsValue* +MmsValue_newMmsString(char* string) +{ + return MmsValue_newString(string, MMS_STRING); +} + +MmsValue* +MmsValue_newMmsStringWithSize(int size) +{ + return MmsValue_newStringWithSize(size, MMS_STRING); +} + + +MmsValue* +MmsValue_newBinaryTime(bool timeOfDay) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_BINARY_TIME; + + if (timeOfDay == true) + self->value.binaryTime.size = 4; + else + self->value.binaryTime.size = 6; + + return self; +} + +void +MmsValue_setBinaryTime(MmsValue* self, uint64_t timestamp) +{ + uint64_t mmsTime = timestamp - (441763200000LL); + + uint8_t* binaryTimeBuf = self->value.binaryTime.buf; + + if (self->value.binaryTime.size == 6) { + uint16_t daysDiff = mmsTime / (86400000LL); + uint8_t* daysDiffBuf = (uint8_t*) &daysDiff; + +#if (ORDER_LITTLE_ENDIAN == 1) + binaryTimeBuf[4] = daysDiffBuf[1]; + binaryTimeBuf[5] = daysDiffBuf[0]; +#else + binaryTimeBuf[4] = daysDiffBuf[0]; + binaryTimeBuf[5] = daysDiffBuf[1]; +#endif + + } + + uint32_t msSinceMidnight = mmsTime % (86400000LL); + uint8_t* msSinceMidnightBuf = (uint8_t*) &msSinceMidnight; + +#if (ORDER_LITTLE_ENDIAN == 1) + binaryTimeBuf[0] = msSinceMidnightBuf[3]; + binaryTimeBuf[1] = msSinceMidnightBuf[2]; + binaryTimeBuf[2] = msSinceMidnightBuf[1]; + binaryTimeBuf[3] = msSinceMidnightBuf[0]; +#else + binaryTimeBuf[0] = msSinceMidnightBuf[0]; + binaryTimeBuf[1] = msSinceMidnightBuf[1]; + binaryTimeBuf[2] = msSinceMidnightBuf[2]; + binaryTimeBuf[3] = msSinceMidnightBuf[3]; +#endif +} + +uint64_t +MmsValue_getBinaryTimeAsUtcMs(const MmsValue* self) +{ + uint64_t timestamp = 0; + + const uint8_t* binaryTimeBuf = self->value.binaryTime.buf; + + if (self->value.binaryTime.size == 6) { + + uint16_t daysDiff; + + daysDiff = binaryTimeBuf[4] * 256; + daysDiff += binaryTimeBuf[5]; + + uint64_t mmsTime; + + mmsTime = daysDiff * (86400000LL); + + + timestamp = mmsTime + (441763200000LL); + } + + uint32_t msSinceMidnight = 0; + + msSinceMidnight = binaryTimeBuf[0] << 24; + msSinceMidnight += binaryTimeBuf[1] << 16; + msSinceMidnight += binaryTimeBuf[2] << 8; + msSinceMidnight += binaryTimeBuf[3]; + + timestamp += msSinceMidnight; + + return timestamp; +} + +MmsDataAccessError +MmsValue_getDataAccessError(const MmsValue* self) +{ + return self->value.dataAccessError; +} + +void +MmsValue_setMmsString(MmsValue* self, const char* string) +{ + if (self->type == MMS_STRING) { + assert(self->value.visibleString.buf != NULL); + + setVisibleStringValue(self, string); + } +} + +static MmsValue* +MmsValue_newStringFromByteArray(const uint8_t* byteArray, int size, MmsType type) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = type; + + self->value.visibleString.size = size; + + self->value.visibleString.buf = createStringFromBuffer(byteArray, size); + + if (self->value.visibleString.buf == NULL) { + GLOBAL_FREEMEM(self); + self = NULL; + } + +exit_function: + return self; +} + +MmsValue* +MmsValue_newVisibleStringFromByteArray(uint8_t* byteArray, int size) +{ + return MmsValue_newStringFromByteArray(byteArray, size, MMS_VISIBLE_STRING); +} + +MmsValue* +MmsValue_newMmsStringFromByteArray(uint8_t* byteArray, int size) +{ + return MmsValue_newStringFromByteArray(byteArray, size, MMS_STRING); +} + +void +MmsValue_setVisibleString(MmsValue* self, const char* string) +{ + if (self->type == MMS_VISIBLE_STRING) { + assert(self->value.visibleString.buf != NULL); + + setVisibleStringValue(self, string); + } +} + +const char* +MmsValue_toString(MmsValue* self) +{ + if ((self->type == MMS_VISIBLE_STRING) || (self->type == MMS_STRING)) + return self->value.visibleString.buf; + + return NULL; +} + +int +MmsValue_getStringSize(MmsValue* self) +{ + if ((self->type == MMS_VISIBLE_STRING) || (self->type == MMS_STRING)) + return self->value.visibleString.size; + else + return 0; +} + +MmsValue* +MmsValue_newUtcTime(uint32_t timeval) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_UTC_TIME; + + uint8_t* timeArray = (uint8_t*) &timeval; + uint8_t* valueArray = self->value.utcTime; + +#if (ORDER_LITTLE_ENDIAN == 1) + valueArray[0] = timeArray[3]; + valueArray[1] = timeArray[2]; + valueArray[2] = timeArray[1]; + valueArray[3] = timeArray[0]; +#else + valueArray[0] = timeArray[0]; + valueArray[1] = timeArray[1]; + valueArray[2] = timeArray[2]; + valueArray[3] = timeArray[3]; +#endif + +exit_function: + return self; +} + + +MmsValue* +MmsValue_newUtcTimeByMsTime(uint64_t timeval) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + return NULL; + + self->type = MMS_UTC_TIME; + MmsValue_setUtcTimeMs(self, timeval); + + return self; +} + +MmsValue* +MmsValue_createArray(MmsVariableSpecification* elementType, int size) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_ARRAY; + self->value.structure.size = size; + self->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*)); + + if (self->value.structure.components == NULL) { + GLOBAL_FREEMEM(self); + self = NULL; + goto exit_function; + } + + int i; + for (i = 0; i < size; i++) { + self->value.structure.components[i] = MmsValue_newDefaultValue(elementType); + + if (self->value.structure.components[i] == NULL) { + MmsValue_delete(self); + self = NULL; + goto exit_function; + } + } + +exit_function: + return self; +} + +MmsValue* +MmsValue_createEmptyArray(int size) +{ + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + if (self == NULL) + goto exit_function; + + self->type = MMS_ARRAY; + self->value.structure.size = size; + self->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*)); + + if (self->value.structure.components == NULL) { + GLOBAL_FREEMEM(self); + self = NULL; + goto exit_function; + } + + int i; + for (i = 0; i < size; i++) { + self->value.structure.components[i] = NULL; + } + +exit_function: + return self; +} + +MmsValue* +MmsValue_createEmptyStructure(int size) +{ + MmsValue* self = MmsValue_createEmptyArray(size); + + if (self == NULL) + return NULL; + + self->type = MMS_STRUCTURE; + + return self; +} + +void +MmsValue_setElement(MmsValue* complexValue, int index, MmsValue* elementValue) +{ + if ((complexValue->type != MMS_ARRAY) && (complexValue->type != MMS_STRUCTURE)) + return; + + if ((index < 0) || (index >= complexValue->value.structure.size)) + return; + + complexValue->value.structure.components[index] = elementValue; +} + +MmsValue* +MmsValue_getElement(MmsValue* complexValue, int index) +{ + if ((complexValue->type != MMS_ARRAY) && (complexValue->type != MMS_STRUCTURE)) + return NULL; + + if ((index < 0) || (index >= complexValue->value.structure.size)) + return NULL; + + return complexValue->value.structure.components[index]; +} + +void +MmsValue_setDeletable(MmsValue* self) +{ + self->deleteValue = 1; +} + +void +MmsValue_setDeletableRecursive(MmsValue* self) +{ + if (self != NULL) { + + if ((MmsValue_getType(self) == MMS_ARRAY) || (MmsValue_getType(self) == MMS_STRUCTURE)) { + int i; + int elementCount = MmsValue_getArraySize(self); + + for (i = 0; i < elementCount; i++) + MmsValue_setDeletableRecursive(MmsValue_getElement(self, i)); + } + + MmsValue_setDeletable(self); + } +} + +int +MmsValue_isDeletable(MmsValue* self) +{ + return self->deleteValue; +} + +MmsType +MmsValue_getType(MmsValue* self) +{ + return self->type; +} + +MmsValue* +MmsValue_getSubElement(MmsValue* self, MmsVariableSpecification* varSpec, char* mmsPath) +{ + return MmsVariableSpecification_getChildValue(varSpec, self, mmsPath); +} + +char* +MmsValue_getTypeString(MmsValue* self) +{ + switch (MmsValue_getType(self)) { + case MMS_ARRAY: + return "array"; + case MMS_BCD: + return "bcd"; + case MMS_BINARY_TIME: + return "binary-time"; + case MMS_BIT_STRING: + return "bit-string"; + case MMS_BOOLEAN: + return "boolean"; + case MMS_DATA_ACCESS_ERROR: + return "access-error"; + case MMS_FLOAT: + return "float"; + case MMS_GENERALIZED_TIME: + return "generalized-time"; + case MMS_INTEGER: + return "integer"; + case MMS_OBJ_ID: + return "oid"; + case MMS_STRING: + return "mms-string"; + case MMS_STRUCTURE: + return "structure"; + case MMS_OCTET_STRING: + return "octet-string"; + case MMS_UNSIGNED: + return "unsigned"; + case MMS_UTC_TIME: + return "utc-time"; + case MMS_VISIBLE_STRING: + return "visible-string"; + default: + return "unknown(error)"; + } +} + +char* +MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize) +{ + switch (MmsValue_getType(self)) { + case MMS_STRUCTURE: + case MMS_ARRAY: + { + buffer[0] = '{'; + + int bufPos = 1; + + int arraySize = MmsValue_getArraySize(self); + int i; + for (i = 0; i < arraySize; i++) { + + char* currentStr = MmsValue_printToBuffer(MmsValue_getElement(self, i), buffer + bufPos, bufferSize - bufPos); + + bufPos += strlen(currentStr); + + if (bufPos >= bufferSize) + break; + + if (i != (arraySize - 1)) { + buffer[bufPos++] = ','; + } + } + + buffer[bufPos++] = '}'; + buffer[bufPos] = 0; + } + break; + case MMS_BINARY_TIME: + Conversions_msTimeToGeneralizedTime(MmsValue_getBinaryTimeAsUtcMs(self), (uint8_t*) buffer); + break; + case MMS_BIT_STRING: + { + int bufPos = 0; + + int size = MmsValue_getBitStringSize(self); + + int i; + for (i = 0; i < size; i++) { + if (MmsValue_getBitStringBit(self, i)) + buffer[bufPos++] = '1'; + else + buffer[bufPos++] = '0'; + } + buffer[bufPos] = 0; + } + break; + case MMS_BOOLEAN: + if (MmsValue_getBoolean(self)) + strncpy(buffer, "true", bufferSize); + else + strncpy(buffer, "false", bufferSize); + break; + case MMS_DATA_ACCESS_ERROR: + snprintf(buffer, bufferSize, "error %i", self->value.dataAccessError); + break; + case MMS_FLOAT: + snprintf(buffer, bufferSize, "%f", MmsValue_toFloat(self)); + break; + case MMS_GENERALIZED_TIME: + strncpy(buffer, "generalized time", bufferSize); + break; + case MMS_INTEGER: + snprintf(buffer, bufferSize, "%i", MmsValue_toInt32(self)); + break; + case MMS_OCTET_STRING: + { + int size = MmsValue_getOctetStringSize(self); + int bufPos = 0; + int i; + for (i = 0; i < size; i++) { + snprintf(buffer + bufPos, bufferSize - bufPos, "%02x", self->value.octetString.buf[i]); + bufPos += 2; + + if (bufPos >= bufferSize) + break; + } + } + + break; + case MMS_UNSIGNED: + snprintf(buffer, bufferSize, "%u", MmsValue_toUint32(self)); + break; + case MMS_UTC_TIME: + Conversions_msTimeToGeneralizedTime(MmsValue_getUtcTimeInMs(self), (uint8_t*) buffer); + break; + case MMS_STRING: + case MMS_VISIBLE_STRING: + strncpy(buffer, MmsValue_toString(self), bufferSize); + break; + default: + strncpy(buffer, "unknown type", bufferSize); + break; + } + + return buffer; +} diff --git a/src/mms/iso_mms/server/mms_access_result.c b/src/mms/iso_mms/server/mms_access_result.c new file mode 100644 index 0000000..59d52ab --- /dev/null +++ b/src/mms/iso_mms/server/mms_access_result.c @@ -0,0 +1,226 @@ +/* + * mms_access_result.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_access_result.h" +#include "mms_server_internal.h" +#include "mms_value_internal.h" + +static int +encodeArrayAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode) +{ + if (value == NULL) // TODO report internal error + return 0; + + int elementsSize = 0; + int i; + int size; + + int arraySize = MmsValue_getArraySize(value); + + for (i = 0; i < arraySize; i++) { + MmsValue* element = MmsValue_getElement(value, i); + + elementsSize += mmsServer_encodeAccessResult(element, NULL, 0, false); + } + + if (encode) { + buffer[bufPos++] = 0xa1; /* tag for array */ + bufPos = BerEncoder_encodeLength(elementsSize, buffer, bufPos); + + for (i = 0; i < arraySize; i++) { + MmsValue* element = MmsValue_getElement(value, i); + + bufPos = mmsServer_encodeAccessResult(element, buffer, bufPos, true); + } + + size = bufPos; + } + else { + size = 1 + elementsSize + BerEncoder_determineLengthSize(elementsSize); + } + + return size; +} + +static int +encodeStructuredAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode) +{ + if (value == NULL) // TODO report internal error + return 0; + + int componentsSize = 0; + int i; + int size; + + int components = value->value.structure.size; + + for (i = 0; i < components; i++) { + MmsValue* component = value->value.structure.components[i]; + + componentsSize += mmsServer_encodeAccessResult(component, NULL, 0, false); + } + + if (encode) { + buffer[bufPos++] = 0xa2; /* tag for structure */ + bufPos = BerEncoder_encodeLength(componentsSize, buffer, bufPos); + + for (i = 0; i < components; i++) { + MmsValue* component = value->value.structure.components[i]; + + bufPos = mmsServer_encodeAccessResult(component, buffer, bufPos, true); + } + + size = bufPos; + } + else { + size = 1 + componentsSize + BerEncoder_determineLengthSize(componentsSize); + } + + return size; +} + +int +mmsServer_encodeAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode) +{ +// if (value == NULL) // TODO report internal error +// return 0; + + int size; + + switch (value->type) { + case MMS_BOOLEAN: + if (encode) + bufPos = BerEncoder_encodeBoolean(0x83, value->value.boolean, buffer, bufPos); + else + size = 3; + break; + + case MMS_STRUCTURE: + if (encode) + bufPos = encodeStructuredAccessResult(value, buffer, bufPos, true); + else + size = encodeStructuredAccessResult(value, buffer, bufPos, false); + + break; + + case MMS_ARRAY: + if (encode) + bufPos = encodeArrayAccessResult(value, buffer, bufPos, true); + else + size = encodeArrayAccessResult(value, buffer, bufPos, false); + break; + + case MMS_DATA_ACCESS_ERROR: + if (encode) { + int length = BerEncoder_UInt32determineEncodedSize((uint32_t) value->value.dataAccessError); + + bufPos = BerEncoder_encodeTL(0x80, length, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) value->value.dataAccessError, buffer, bufPos); + } + else + size = 2 + BerEncoder_UInt32determineEncodedSize((uint32_t) value->value.dataAccessError); + break; + + case MMS_VISIBLE_STRING: + if (encode) + bufPos = BerEncoder_encodeStringWithTag(0x8a, value->value.visibleString.buf, buffer, bufPos); + else + size = BerEncoder_determineEncodedStringSize(value->value.visibleString.buf); + break; + case MMS_UNSIGNED: + if (encode) + bufPos = BerEncoder_encodeAsn1PrimitiveValue(0x86, value->value.integer, buffer, bufPos); + else + size = 2 + value->value.integer->size; + break; + case MMS_INTEGER: + if (encode) + bufPos = BerEncoder_encodeAsn1PrimitiveValue(0x85, value->value.integer, buffer, bufPos); + else + size = 2 + value->value.integer->size; + break; + case MMS_UTC_TIME: + if (encode) + bufPos = BerEncoder_encodeOctetString(0x91, value->value.utcTime, 8, buffer, bufPos); + else + size = 10; + break; + case MMS_BIT_STRING: + if (encode) + bufPos = BerEncoder_encodeBitString(0x84, value->value.bitString.size, + value->value.bitString.buf, buffer, bufPos); + else + size = BerEncoder_determineEncodedBitStringSize(value->value.bitString.size); + break; + + case MMS_BINARY_TIME: + if (encode) + bufPos = BerEncoder_encodeOctetString(0x8c, value->value.binaryTime.buf, + value->value.binaryTime.size, buffer, bufPos); + else + size = 2 + value->value.binaryTime.size; + break; + case MMS_OCTET_STRING: + if (encode) + bufPos = BerEncoder_encodeOctetString(0x89, value->value.octetString.buf, + value->value.octetString.size, buffer, bufPos); + else + size = 1 + BerEncoder_determineLengthSize(value->value.octetString.size) + + value->value.octetString.size; + break; + + case MMS_FLOAT: + { + int floatSize = (value->value.floatingPoint.formatWidth / 8) + 1; + + if (encode) { + bufPos = BerEncoder_encodeTL(0x87, floatSize, buffer, bufPos); + bufPos = BerEncoder_encodeFloat(value->value.floatingPoint.buf, + value->value.floatingPoint.formatWidth, + value->value.floatingPoint.exponentWidth, + buffer, bufPos); + } + else + size = floatSize + 2; /* 2 for tag and length */ + } + break; + case MMS_STRING: + if (encode) + bufPos = BerEncoder_encodeStringWithTag(0x90, value->value.visibleString.buf, buffer, bufPos); + else + size = BerEncoder_determineEncodedStringSize(value->value.visibleString.buf); + break; + default: + if (DEBUG_MMS_SERVER) + printf("encodeAccessResult: error unsupported type!\n"); + size = 0; + break; + } + + if (encode) + return bufPos; + else + return size; +} + diff --git a/src/mms/iso_mms/server/mms_association_service.c b/src/mms/iso_mms/server/mms_association_service.c new file mode 100644 index 0000000..6cce6be --- /dev/null +++ b/src/mms/iso_mms/server/mms_association_service.c @@ -0,0 +1,259 @@ +/* + * mms_association_service.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +/********************************************************************************************** + * MMS Server Capabilities + *********************************************************************************************/ + +#define MMS_SERVICE_STATUS 0x80 +#define MMS_SERVICE_GET_NAME_LIST 0x40 +#define MMS_SERVICE_IDENTIFY 0x20 +#define MMS_SERVICE_RENAME 0x10 +#define MMS_SERVICE_READ 0x08 +#define MMS_SERVICE_WRITE 0x04 +#define MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES 0x02 +#define MMS_SERVICE_DEFINE_NAMED_VARIABLE 0x01 + +#define MMS_SERVICE_DEFINE_SCATTERED_ACCESS 0x80 +#define MMS_SERVICE_GET_SCATTERED_ACCESS_ATTRIBUTES 0x40 +#define MMS_SERVICE_DELETE_VARIABLE_ACCESS 0x20 +#define MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST 0x10 +#define MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES 0x08 +#define MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST 0x04 +#define MMS_SERVICE_DEFINE_NAMED_TYPE 0x02 +#define MMS_SERVICE_GET_NAMED_TYPE_ATTRIBUTES 0x01 + +#define MMS_SERVICE_FILE_OPEN 0x80 +#define MMS_SERVICE_FILE_READ 0x40 +#define MMS_SERVICE_FILE_CLOSE 0x20 +#define MMS_SERVICE_FILE_RENAME 0x01 +#define MMS_SERVICE_FILE_DELETE 0x08 +#define MMS_SERVICE_FILE_DIRECTORY 0x04 +#define MMS_SERVICE_UNSOLICITED_STATUS 0x02 +#define MMS_SERVICE_INFORMATION_REPORT 0x01 + +#define MMS_SERVICE_CONCLUDE 0x10 +#define MMS_SERVICE_CANCEL 0x08 + +//TODO make dependent on stack configuration! +/* servicesSupported MMS bitstring */ +static uint8_t servicesSupported[] = +{ + 0x00 +#if MMS_STATUS_SERVICE == 1 + | MMS_SERVICE_STATUS +#endif + | MMS_SERVICE_GET_NAME_LIST +#if MMS_IDENTIFY_SERVICE == 1 + | MMS_SERVICE_IDENTIFY +#endif + | MMS_SERVICE_READ + | MMS_SERVICE_WRITE + | MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES + , + 0x00 + | MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST + | MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST + | MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES + , + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +#if MMS_FILE_SERVICE == 1 + | MMS_SERVICE_FILE_OPEN + | MMS_SERVICE_FILE_READ + | MMS_SERVICE_FILE_CLOSE + | MMS_SERVICE_FILE_RENAME + | MMS_SERVICE_FILE_DELETE + | MMS_SERVICE_FILE_DIRECTORY +#endif + | MMS_SERVICE_INFORMATION_REPORT + , + 0x00 + | MMS_SERVICE_CONCLUDE + | MMS_SERVICE_CANCEL +}; + +/* negotiated parameter CBB */ +static uint8_t parameterCBB[] = +{ + 0xf1, + 0x00 +}; + + +/********************************************************************************************** + * MMS Initiate Service + *********************************************************************************************/ + +static int +encodeInitResponseDetail(uint8_t* buffer, int bufPos, bool encode) +{ + int initResponseDetailSize = 14 + 5 + 3; + + if (encode == false) + return initResponseDetailSize + 2; + + bufPos = BerEncoder_encodeTL(0xa4, initResponseDetailSize, buffer, bufPos); + + bufPos = BerEncoder_encodeUInt32WithTL(0x80, 1, buffer, bufPos); /* negotiated protocol version */ + + bufPos = BerEncoder_encodeBitString(0x81, 11, parameterCBB, buffer, bufPos); + + bufPos = BerEncoder_encodeBitString(0x82, 85, servicesSupported, buffer, bufPos); + + return bufPos; +} + + +static int +createInitiateResponse(MmsServerConnection self, ByteBuffer* writeBuffer) +{ + uint8_t* buffer = writeBuffer->buffer; + int bufPos = 0; + + int initiateResponseLength = 0; + + initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxPduSize); + initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxServOutstandingCalling); + initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxServOutstandingCalled); + initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->dataStructureNestingLevel); + + initiateResponseLength += encodeInitResponseDetail(NULL, 0, false); + + /* Initiate response pdu */ + bufPos = BerEncoder_encodeTL(0xa9, initiateResponseLength, buffer, bufPos); + + bufPos = BerEncoder_encodeUInt32WithTL(0x80, self->maxPduSize, buffer, bufPos); + + bufPos = BerEncoder_encodeUInt32WithTL(0x81, self->maxServOutstandingCalling, buffer, bufPos); + + bufPos = BerEncoder_encodeUInt32WithTL(0x82, self->maxServOutstandingCalled, buffer, bufPos); + + bufPos = BerEncoder_encodeUInt32WithTL(0x83, self->dataStructureNestingLevel, buffer, bufPos); + + bufPos = encodeInitResponseDetail(buffer, bufPos, true); + + writeBuffer->size = bufPos; + + return bufPos; +} + +static bool +parseInitiateRequestPdu(MmsServerConnection self, uint8_t* buffer, int bufPos, int maxBufPos) +{ + self->maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE; + + self->dataStructureNestingLevel = + DEFAULT_DATA_STRUCTURE_NESTING_LEVEL; + + self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + + self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) { + // TODO write initiate error PDU! + return false; + } + + switch (tag) { + case 0x80: /* local-detail-calling */ + self->maxPduSize = BerDecoder_decodeUint32(buffer, length, bufPos); + + if (self->maxPduSize > CONFIG_MMS_MAXIMUM_PDU_SIZE) + self->maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE; + + break; + + case 0x81: /* proposed-max-serv-outstanding-calling */ + self->maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos); + + if (self->maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING) + self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + + break; + + case 0x82: /* proposed-max-serv-outstanding-called */ + self->maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos); + + if (self->maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED) + self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + + break; + case 0x83: /* proposed-data-structure-nesting-level */ + self->dataStructureNestingLevel = BerDecoder_decodeUint32(buffer, length, bufPos); + break; + + case 0xa4: /* mms-init-request-detail */ + /* we ignore this */ + break; + + default: + break; /* Ignore unknown tags */ + } + + bufPos += length; + } + + return true; +} + +void +mmsServer_handleInitiateRequest ( + MmsServerConnection self, + uint8_t* buffer, int bufPos, int maxBufPos, + ByteBuffer* response) +{ + + if (parseInitiateRequestPdu(self, buffer, bufPos, maxBufPos)) + createInitiateResponse(self, response); + else { + //TODO send initiate error PDU + } + +} + +/********************************************************************************************** + * MMS Conclude Service + *********************************************************************************************/ + +void +mmsServer_writeConcludeResponsePdu(ByteBuffer* response) +{ + ByteBuffer_appendByte(response, 0x8c); + ByteBuffer_appendByte(response, 0x00); +} diff --git a/src/mms/iso_mms/server/mms_device.c b/src/mms/iso_mms/server/mms_device.c new file mode 100644 index 0000000..e0968bf --- /dev/null +++ b/src/mms/iso_mms/server/mms_device.c @@ -0,0 +1,129 @@ +/* + * mms_device.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" +#include "mms_device_model.h" +#include "stack_config.h" + +MmsDevice* +MmsDevice_create(char* deviceName) +{ + MmsDevice* self = (MmsDevice*) GLOBAL_CALLOC(1, sizeof(MmsDevice)); + self->deviceName = deviceName; + + self->namedVariableLists = LinkedList_create(); + + return self; +} + +void +MmsDevice_destroy(MmsDevice* self) +{ + + int i; + for (i = 0; i < self->domainCount; i++) { + MmsDomain_destroy(self->domains[i]); + } + +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + if (self->namedVariables != NULL) { + for (i = 0; i < self->namedVariablesCount; i++) { + MmsVariableSpecification_destroy(self->namedVariables[i]); + } + + GLOBAL_FREEMEM(self->namedVariables); + } +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + + LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy); + + GLOBAL_FREEMEM(self->domains); + GLOBAL_FREEMEM(self); +} + +MmsDomain* +MmsDevice_getDomain(MmsDevice* self, char* domainId) +{ + int i; + + for (i = 0; i < self->domainCount; i++) { + if (strcmp(self->domains[i]->domainName, domainId) == 0) { + return self->domains[i]; + } + + } + + return NULL; +} + +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) +MmsVariableSpecification* +MmsDevice_getNamedVariable(MmsDevice* self, char* variableName) +{ + if (self->namedVariables != NULL) { + char* separator = strchr(variableName, '$'); + + int i; + + if (separator == NULL) { + + for (i = 0; i < self->namedVariablesCount; i++) { + if (strcmp(self->namedVariables[i]->name, variableName) == 0) { + return self->namedVariables[i]; + } + } + + return NULL; + } + else { + MmsVariableSpecification* namedVariable = NULL; + + for (i = 0; i < self->namedVariablesCount; i++) { + + if (strlen(self->namedVariables[i]->name) == (unsigned) (separator - variableName)) { + + if (strncmp(self->namedVariables[i]->name, variableName, separator - variableName) == 0) { + namedVariable = self->namedVariables[i]; + break; + } + } + } + + if (namedVariable != NULL) { + namedVariable = MmsVariableSpecification_getNamedVariableRecursive(namedVariable, separator + 1); + } + + return namedVariable; + } + } + + return NULL; +} +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + +LinkedList +MmsDevice_getNamedVariableLists(MmsDevice* self) +{ + return self->namedVariableLists; +} diff --git a/src/mms/iso_mms/server/mms_domain.c b/src/mms/iso_mms/server/mms_domain.c new file mode 100644 index 0000000..c70567d --- /dev/null +++ b/src/mms/iso_mms/server/mms_domain.c @@ -0,0 +1,158 @@ +/* + * mms_domain.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_device_model.h" +#include "mms_server_internal.h" + +static void +freeNamedVariables(MmsVariableSpecification** variables, int variablesCount) +{ + int i; + for (i = 0; i < variablesCount; i++) { + MmsVariableSpecification_destroy(variables[i]); + } +} + +MmsDomain* +MmsDomain_create(char* domainName) +{ + MmsDomain* self = (MmsDomain*) GLOBAL_CALLOC(1, sizeof(MmsDomain)); + + self->domainName = copyString(domainName); + self->namedVariableLists = LinkedList_create(); + + return self; +} + +void +MmsDomain_destroy(MmsDomain* self) +{ + GLOBAL_FREEMEM(self->domainName); + + if (self->namedVariables != NULL) { + freeNamedVariables(self->namedVariables, + self->namedVariablesCount); + + GLOBAL_FREEMEM(self->namedVariables); + } + + LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy); + + GLOBAL_FREEMEM(self); +} + +char* +MmsDomain_getName(MmsDomain* self) +{ + return self->domainName; +} + +bool +MmsDomain_addNamedVariableList(MmsDomain* self, MmsNamedVariableList variableList) +{ + LinkedList_add(self->namedVariableLists, variableList); + + return true; +} + +MmsNamedVariableList +MmsDomain_getNamedVariableList(MmsDomain* self, char* variableListName) +{ + MmsNamedVariableList variableList = NULL; + + if (self == NULL) + goto exit_function; + + LinkedList element = LinkedList_getNext(self->namedVariableLists); + + while (element != NULL) { + MmsNamedVariableList varList = (MmsNamedVariableList) element->data; + + if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { + variableList = varList; + break; + } + + element = LinkedList_getNext(element); + } + + +exit_function: + return variableList; +} + +void +MmsDomain_deleteNamedVariableList(MmsDomain* self, char* variableListName) +{ + mmsServer_deleteVariableList(self->namedVariableLists, variableListName); +} + +LinkedList +MmsDomain_getNamedVariableLists(MmsDomain* self) +{ + return self->namedVariableLists; +} + +MmsVariableSpecification* +MmsDomain_getNamedVariable(MmsDomain* self, char* nameId) +{ + if (self->namedVariables != NULL) { + + char* separator = strchr(nameId, '$'); + + int i; + + if (separator == NULL) { + + for (i = 0; i < self->namedVariablesCount; i++) { + if (strcmp(self->namedVariables[i]->name, nameId) == 0) { + return self->namedVariables[i]; + } + } + + return NULL; + } + else { + MmsVariableSpecification* namedVariable = NULL; + + for (i = 0; i < self->namedVariablesCount; i++) { + + if (strlen(self->namedVariables[i]->name) == (unsigned) (separator - nameId)) { + + if (strncmp(self->namedVariables[i]->name, nameId, separator - nameId) == 0) { + namedVariable = self->namedVariables[i]; + break; + } + } + } + + if (namedVariable != NULL) { + namedVariable = MmsVariableSpecification_getNamedVariableRecursive(namedVariable, separator + 1); + } + + return namedVariable; + } + } + return NULL; +} diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c new file mode 100644 index 0000000..74c60d5 --- /dev/null +++ b/src/mms/iso_mms/server/mms_file_service.c @@ -0,0 +1,715 @@ +/* + * mms_file_service.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +#if (MMS_FILE_SERVICE == 1) + +#include "hal_filesystem.h" +#include "conversions.h" + +#define CONFIG_MMS_FILE_SERVICE_MAX_FILENAME_LENGTH 256 + +static void +createNullResponseExtendedTag(uint32_t invokeId, ByteBuffer* response, uint8_t tag) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; + + uint32_t confirmedResponsePDUSize = invokeIdSize + 3 ; + + uint8_t* buffer = response->buffer; + + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + buffer[bufPos++] = 0x9f; /* Context specific / primitive / extended */ + bufPos = BerEncoder_encodeTL(tag, 0, buffer, bufPos); + + response->size = bufPos; +} + +static MmsFileReadStateMachine* +getFreeFrsm(MmsServerConnection connection) +{ + int i; + + MmsFileReadStateMachine* freeFrsm = NULL; + + for (i = 0; i < CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION; i++) { + if (connection->frsms[i].fileHandle == NULL) { + freeFrsm = &(connection->frsms[i]); + break; + } + } + + return freeFrsm; +} + + +static MmsFileReadStateMachine* +getFrsm(MmsServerConnection connection, int32_t frsmId) +{ + int i; + + MmsFileReadStateMachine* frsm = NULL; + + for (i = 0; i < CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION; i++) { + if (connection->frsms[i].fileHandle != NULL) { + if (connection->frsms[i].frsmId == frsmId) { + frsm = &(connection->frsms[i]); + break; + } + } + } + + return frsm; +} + +static int32_t +getNextFrsmId(MmsServerConnection connection) +{ + uint32_t nextFrsmId = connection->nextFrsmId; + connection->nextFrsmId++; + + return nextFrsmId; +} + +static int +encodeFileAttributes(uint8_t tag, uint32_t fileSize, char* gtString, uint8_t* buffer, int bufPos) +{ + uint32_t sizeOfFileSize = BerEncoder_UInt32determineEncodedSize(fileSize); + + uint32_t gtStringSize = strlen(gtString); + + uint32_t fileAttributesSize = 1 + BerEncoder_determineLengthSize(sizeOfFileSize) + sizeOfFileSize + + 2 + gtStringSize; + + if (buffer == NULL) { + + + return fileAttributesSize; + } + else { + bufPos = BerEncoder_encodeTL(tag, fileAttributesSize, buffer, bufPos); /* file attributes */ + bufPos = BerEncoder_encodeTL(0x80, sizeOfFileSize, buffer, bufPos); /* file size */ + bufPos = BerEncoder_encodeUInt32(fileSize, buffer, bufPos); + bufPos = BerEncoder_encodeOctetString(0x81, (uint8_t*) gtString, gtStringSize, buffer, bufPos); + return bufPos; + } +} + + +static void +createFileOpenResponse(uint32_t invokeId, ByteBuffer* response, char* fullPath, MmsFileReadStateMachine* frsm) +{ + uint64_t msTime; + + FileSystem_getFileInfo(fullPath, &(frsm->fileSize), &msTime); + + char gtString[30]; + + Conversions_msTimeToGeneralizedTime(msTime, (uint8_t*) gtString); + + uint32_t fileAttributesSize = encodeFileAttributes(0xa1, frsm->fileSize, gtString, NULL, 0) + 2; + + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; + + uint32_t frsmIdSize = BerEncoder_UInt32determineEncodedSize(frsm->frsmId) + 2; + + uint32_t openFileResponseSize = fileAttributesSize + frsmIdSize; + + uint32_t confirmedResponsePDUSize = invokeIdSize + 2 + BerEncoder_determineLengthSize(openFileResponseSize) + + openFileResponseSize; + + uint8_t* buffer = response->buffer; + + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + buffer[bufPos++] = 0xbf; + bufPos = BerEncoder_encodeTL(0x48, openFileResponseSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, frsmIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(frsm->frsmId, buffer, bufPos); + bufPos = encodeFileAttributes(0xa1, frsm->fileSize, gtString, buffer, bufPos); + + response->size = bufPos; +} + +static bool +parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response) +{ + uint8_t tag = buffer[(*bufPos)++]; + int length; + + if (tag != 0x19) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return false; + } + + *bufPos = BerDecoder_decodeLength(buffer, &length, *bufPos, maxBufPos); + + if (*bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return false; + } + + if (length > 255) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return false; + } + + memcpy(filename, buffer + *bufPos, length); + filename[length] = 0; + *bufPos += length; + + return true; +} + +void +mmsServer_handleFileDeleteRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + if (buffer[bufPos++] != 0x19) + goto exit_reject_invalid_pdu; + + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + char filename[256]; + + memcpy(filename, buffer + bufPos, length); + filename[length] = 0; + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: mms_file_service.c: Delete file (%s)\n", filename); + + if (!FileSystem_getFileInfo(filename, NULL, NULL)) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: mms_file_service.c: File (%s) not found\n", filename); + + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT); + return; + } + + if (!FileSystem_deleteFile(filename)) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: mms_file_service.c: Delete file (%s) failed\n", filename); + + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_ACCESS_DENIED); + return; + } + + createNullResponseExtendedTag(invokeId, response, 0x4c); + return; + +exit_reject_invalid_pdu: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); +} + +void +mmsServer_handleFileOpenRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + char filename[256]; + bool hasFileName = false; + uint32_t filePosition = 0; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) goto exit_reject_invalid_pdu; + + switch(tag) { + case 0xa0: /* filename */ + + if (!parseFileName(filename, buffer, &bufPos, bufPos + length, invokeId, response)) + return; + + hasFileName = true; + + break; + + case 0x81: /* initial position */ + filePosition = BerDecoder_decodeUint32(buffer, length, bufPos); + bufPos += length; + break; + + default: /* unrecognized parameter */ + bufPos += length; + goto exit_reject_invalid_pdu; + } + } + + if (hasFileName) { + + MmsFileReadStateMachine* frsm = getFreeFrsm(connection); + + if (frsm != NULL) { + FileHandle fileHandle = FileSystem_openFile(filename, false); + + if (fileHandle != NULL) { + frsm->fileHandle = fileHandle; + frsm->readPosition = filePosition; + frsm->frsmId = getNextFrsmId(connection); + + createFileOpenResponse(invokeId, response, filename, frsm); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT); + + + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + else + goto exit_invalid_parameter; + + return; + +exit_invalid_parameter: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + +exit_reject_invalid_pdu: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); +} + + +static void +createFileReadResponse(MmsServerConnection connection, uint32_t invokeId, + ByteBuffer* response, MmsFileReadStateMachine* frsm) +{ + /* determine remaining bytes in file */ + uint32_t bytesLeft = frsm->fileSize - frsm->readPosition; + + uint32_t fileChunkSize = 0; + + uint32_t maxFileChunkSize = connection->maxPduSize - 20; + + uint32_t fileReadResponseSize = 1; /* for tag */ + + bool moreFollows = true; + + if (bytesLeft > maxFileChunkSize) { + fileChunkSize = maxFileChunkSize; + } + else { + fileChunkSize = bytesLeft; + moreFollows = false; + fileReadResponseSize += 3; /* for moreFollows */ + } + + fileReadResponseSize += fileChunkSize; + fileReadResponseSize += BerEncoder_determineLengthSize(fileChunkSize); + + frsm->readPosition += fileChunkSize; + + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; + + uint32_t confirmedResponsePDUSize = invokeIdSize + 2 + BerEncoder_determineLengthSize(fileReadResponseSize) + + fileReadResponseSize; + + uint8_t* buffer = response->buffer; + + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + buffer[bufPos++] = 0xbf; + bufPos = BerEncoder_encodeTL(0x49, fileReadResponseSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x80, fileChunkSize, buffer, bufPos); + FileSystem_readFile(frsm->fileHandle, buffer + bufPos, fileChunkSize); + bufPos += fileChunkSize; + + if (!moreFollows) + bufPos = BerEncoder_encodeBoolean(0x81, false, buffer, bufPos); + + response->size = bufPos; +} + +void +mmsServer_handleFileReadRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + int32_t frsmId = (int32_t) BerDecoder_decodeUint32(buffer, maxBufPos - bufPos, bufPos); + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: mmsServer_handleFileReadRequest read request for frsmId: %i\n", frsmId); + + MmsFileReadStateMachine* frsm = getFrsm(connection, frsmId); + + if (frsm != NULL) + createFileReadResponse(connection, invokeId, response, frsm); + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_FILE_OTHER); +} + +static void +createFileCloseResponse(uint32_t invokeId, ByteBuffer* response) +{ + createNullResponseExtendedTag(invokeId, response, 0x4a); +} + + +void +mmsServer_handleFileCloseRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + int32_t frsmId = (int32_t) BerDecoder_decodeUint32(buffer, maxBufPos - bufPos, bufPos); + + MmsFileReadStateMachine* frsm = getFrsm(connection, frsmId); + + FileSystem_closeFile(frsm->fileHandle); + frsm->fileHandle = NULL; + frsm->frsmId = 0; + + createFileCloseResponse(invokeId, response); +} + + + +static int //TODO remove redundancy - same as in client code! +encodeFileSpecification(uint8_t tag, char* fileSpecification, uint8_t* buffer, int bufPos) +{ + uint32_t fileNameStringSize = strlen(fileSpecification); + uint32_t fileNameSeqSize = 1 + BerEncoder_determineLengthSize(fileNameStringSize) + fileNameStringSize; + + if (buffer != NULL) { + + bufPos = BerEncoder_encodeTL(tag, fileNameSeqSize, buffer, bufPos); + bufPos = BerEncoder_encodeOctetString(0x19, (uint8_t*) fileSpecification, fileNameStringSize, buffer, bufPos); + + return bufPos; + } + else { + return fileNameSeqSize + 1 + BerEncoder_determineLengthSize(fileNameSeqSize); + } +} + +static int +addFileEntriesToResponse(uint8_t* buffer, int bufPos, int maxBufSize, char* directoryName, char* continueAfterFileName, bool* moreFollows) +{ + int directoryNameLength = strlen(directoryName); + + DirectoryHandle directory = FileSystem_openDirectory(directoryName); + + if (directory != NULL) { + bool isDirectory; + char* fileName = FileSystem_readDirectory(directory, &isDirectory); + + while (fileName != NULL) { + directoryName[directoryNameLength] = 0; + + if (directoryNameLength > 0) { + if (directoryName[directoryNameLength - 1] != '/') + strcat(directoryName, "/"); + } + + strcat(directoryName, fileName); + + if (isDirectory) { + bufPos = addFileEntriesToResponse(buffer, bufPos, maxBufSize, directoryName, continueAfterFileName, moreFollows); + + if (*moreFollows == true) + break; + } + else { + if (continueAfterFileName != NULL) { + if (strcmp(continueAfterFileName, directoryName) == 0) + continueAfterFileName = NULL; + } + else { + uint64_t msTime; + + uint32_t fileSize; + + FileSystem_getFileInfo(directoryName, &fileSize, &msTime); + + char gtString[30]; + + Conversions_msTimeToGeneralizedTime(msTime, (uint8_t*) gtString); + + int fileAttributesSize = encodeFileAttributes(0xa1, fileSize, gtString, NULL, 0); + + int filenameSize = encodeFileSpecification(0xa0, directoryName, NULL, 0); + + int dirEntrySize = 2 + fileAttributesSize + filenameSize; + + int overallEntrySize = 1 + BerEncoder_determineLengthSize(dirEntrySize) + dirEntrySize; + + int bufferSpaceLeft = maxBufSize - bufPos; + + if (overallEntrySize > bufferSpaceLeft) { + *moreFollows = true; + break; + } + + bufPos = BerEncoder_encodeTL(0x30, dirEntrySize, buffer, bufPos); /* SEQUENCE (DirectoryEntry) */ + bufPos = encodeFileSpecification(0xa0, directoryName, buffer, bufPos); /* fileName */ + bufPos = encodeFileAttributes(0xa1, fileSize, gtString, buffer, bufPos); /* file attributes */ + + } + + } + + + fileName = FileSystem_readDirectory(directory, &isDirectory); + } + + FileSystem_closeDirectory(directory); + } + else + bufPos = -1; + + directoryName[directoryNameLength] = 0; + + return bufPos; +} + +static void +createFileDirectoryResponse(uint32_t invokeId, ByteBuffer* response, char* directoryName, char* continueAfterFileName) +{ + int maxSize = response->maxSize - 3; /* reserve space for moreFollows */ + uint8_t* buffer = response->buffer; + + bool moreFollows = false; + + int tempStartPos = 30; /* estimated header part with safety margin */ + int tempCurPos = tempStartPos; + int tempEncoded = 0; + + if (continueAfterFileName != NULL) { + if (strlen(continueAfterFileName) == 0) + continueAfterFileName = NULL; + } + + tempCurPos = addFileEntriesToResponse(buffer, tempCurPos, maxSize, directoryName, continueAfterFileName, &moreFollows); + + if (tempCurPos < 0) { + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: Error opening directory!\n"); + + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT); + + return; + } + + tempEncoded = tempCurPos - tempStartPos; + + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2; + + uint32_t listOfDirectoryEntrySeqSize = tempEncoded; + + uint32_t listOfDirectoryEntrySize = 1 + BerEncoder_determineLengthSize(tempEncoded) + tempEncoded; + + uint32_t fileDirectoryResponseSize = 1 + BerEncoder_determineLengthSize(listOfDirectoryEntrySize) + + listOfDirectoryEntrySize; + + if (moreFollows) + fileDirectoryResponseSize += 3; /* for moreFollows */ + + uint32_t confirmedResponsePDUSize = invokeIdSize + 2 + BerEncoder_determineLengthSize(fileDirectoryResponseSize) + + fileDirectoryResponseSize; + + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) invokeId, buffer, bufPos); + + buffer[bufPos++] = 0xbf; + bufPos = BerEncoder_encodeTL(0x4d, fileDirectoryResponseSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, listOfDirectoryEntrySize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x30, listOfDirectoryEntrySeqSize, buffer, bufPos); /* SEQUENCE OF (DirectoryEntry) */ + + /* memmove is required instead of memcpy since memory areas overlap */ + memmove(buffer + bufPos, buffer + tempStartPos, tempEncoded); + + bufPos += tempEncoded; + + if (moreFollows) + bufPos = BerEncoder_encodeBoolean(0x81, moreFollows, buffer, bufPos); + + response->size = bufPos; +} + +void +mmsServer_handleFileRenameRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + char currentFileName[256] = ""; + char newFileName[256] = ""; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + switch(tag) { + case 0xa0: /* currentFilename */ + if (!parseFileName(currentFileName, buffer, &bufPos, bufPos + length, invokeId, response)) + return; + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: currentFileName: (%s)\n", currentFileName); + + break; + + case 0xa1: /* newFilename */ + if (!parseFileName(newFileName, buffer, &bufPos, bufPos + length, invokeId, response)) + return; + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: newFileName: (%s)\n", newFileName); + + break; + default: /* ignore unknown tag */ + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: unknown tag: (%02x)\n", tag); + + bufPos += length; + break; + } + } + + if ((strlen(currentFileName) != 0) && (strlen(newFileName) != 0)) { + if (FileSystem_renameFile(currentFileName, newFileName)){ + /* send positive response */ + createNullResponseExtendedTag(invokeId, response, 0x4b); + } + else + { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: rename file failed!\n"); + + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_FILE_OTHER); + } + } + else + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + +} + +void +mmsServer_handleFileDirectoryRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: handleFileDirectoryRequest bufPos:%i, maxBufPus:%i\n", bufPos, maxBufPos); + + char filename[256] = ""; + + char continueAfterFileName[256]; + + char* continueAfter = NULL; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + switch(tag) { + case 0xa0: /* filename */ + if (!parseFileName(filename, buffer, &bufPos, bufPos + length, invokeId, response)) + return; + + /* check for wildcard character(*) */ + if ((strcmp(filename, "*") == 0) || (strcmp(filename, "/") == 0) || (strcmp(filename, "\\") == 0)) + filename[0] = 0; + + break; + + case 0xa1: /* continue-after */ + if (!parseFileName(continueAfterFileName, buffer, &bufPos, bufPos + length, invokeId, response)) + return; + + continueAfter = continueAfterFileName; + + break; + + default: /* unrecognized parameter */ + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: handleFileDirectoryRequest: unrecognized parameter\n"); + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + + } + + createFileDirectoryResponse(invokeId, response, filename, continueAfter); +} + +#endif /* MMS_FILE_SERVICE == 1 */ + diff --git a/src/mms/iso_mms/server/mms_get_namelist_service.c b/src/mms/iso_mms/server/mms_get_namelist_service.c new file mode 100644 index 0000000..7719e1c --- /dev/null +++ b/src/mms/iso_mms/server/mms_get_namelist_service.c @@ -0,0 +1,618 @@ +/* + * mms_get_namelist_service.c + * + * Copyright 2013, 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" +#include "ber_encoder.h" +#include "ber_decode.h" + +#if (MMS_GET_NAME_LIST == 1) + +/********************************************************************************************** + * MMS GetNameList Service + *********************************************************************************************/ + +#ifndef CONFIG_MMS_SORT_NAME_LIST +#define CONFIG_MMS_SORT_NAME_LIST 1 +#endif + +#define OBJECT_CLASS_NAMED_VARIABLE 0 +#define OBJECT_CLASS_NAMED_VARIABLE_LIST 2 +#define OBJECT_CLASS_JOURNAL 8 +#define OBJECT_CLASS_DOMAIN 9 + +#define OBJECT_SCOPE_VMD 0 +#define OBJECT_SCOPE_DOMAIN 1 +#define OBJECT_SCOPE_ASSOCIATION 2 + +static LinkedList +getDomainNames(MmsServerConnection connection) +{ + MmsDevice* device = MmsServer_getDevice(connection->server); + + LinkedList list = LinkedList_create(); + + int i; + + for (i = 0; i < device->domainCount; i++) { + LinkedList_add(list, device->domains[i]->domainName); + } + + return list; +} + + +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) +static LinkedList +getNameListVMDSpecific(MmsServerConnection connection) +{ + MmsDevice* device = MmsServer_getDevice(connection->server); + + LinkedList list = LinkedList_create(); + + int i; + + for (i = 0; i < device->namedVariablesCount; i++) { + LinkedList_add(list, device->namedVariables[i]->name); + } + + return list; +} +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) +static void +sortIndex(int* index, int size, MmsVariableSpecification** namedVariables) +{ + int n; + int i; + + for (n = size; n > 1; n = n - 1) { + for (i = 0; i < n - 1; i = i + 1) { + if (StringUtils_compareStrings(namedVariables[index[i]]->name, namedVariables[index[i + 1]]->name) > 0) { + int storedIndex = index[i]; + index[i] = index[i + 1]; + index[i + 1] = storedIndex; + } + } + } +} +#endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ + +#if (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) +static char* +appendMmsSubVariable(char* name, char* child) +{ + int nameLen = strlen(name); + int childLen = strlen(child); + + int newSize = nameLen + childLen + 2; + + char* newName = (char*) GLOBAL_MALLOC(newSize); + + int bufPos = 0; + int i; + for (i = 0; i < nameLen; i++) { + newName[bufPos++] = name[i]; + } + newName[bufPos++] = '$'; + + for (i = 0; i < childLen; i++) { + newName[bufPos++] = child[i]; + } + + newName[bufPos] = 0; + + return newName; +} + +static LinkedList +addSubNamedVaribleNamesToList(LinkedList nameList, char* prefix, MmsVariableSpecification* variable) +{ + LinkedList listElement = nameList; + + if (variable->type == MMS_STRUCTURE) { + + int i; + + MmsVariableSpecification** variables = variable->typeSpec.structure.elements; + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + int* index = (int*) GLOBAL_MALLOC(sizeof(int) * variable->typeSpec.structure.elementCount); + + for (i = 0; i < variable->typeSpec.structure.elementCount; i++) + index[i] = i; + + sortIndex(index, variable->typeSpec.structure.elementCount, variables); +#endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ + + for (i = 0; i < variable->typeSpec.structure.elementCount; i++) { +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + char* variableName = appendMmsSubVariable(prefix, variables[index[i]]->name); +#else + char* variableName = appendMmsSubVariable(prefix, variables[i]->name); +#endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ + + listElement = LinkedList_insertAfter(listElement, variableName); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + listElement = addSubNamedVaribleNamesToList(listElement, variableName, variables[index[i]]); +#else + listElement = addSubNamedVaribleNamesToList(listElement, variableName, variables[i]); +#endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ + } + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + GLOBAL_FREEMEM(index); +#endif + } + + return listElement; +} + +#endif /* (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) */ + +static LinkedList +getNameListDomainSpecific(MmsServerConnection connection, char* domainName) +{ + MmsDevice* device = MmsServer_getDevice(connection->server); + + LinkedList nameList = NULL; + + MmsDomain* domain = MmsDevice_getDomain(device, domainName); + + if (domain != NULL) { + nameList = LinkedList_create(); + MmsVariableSpecification** variables = domain->namedVariables; + + int i; + + LinkedList element = nameList; + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + int* index = (int*) GLOBAL_MALLOC(sizeof(int) * domain->namedVariablesCount); + + for (i = 0; i < domain->namedVariablesCount; i++) + index[i] = i; + + sortIndex(index, domain->namedVariablesCount, domain->namedVariables); +#endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ + + for (i = 0; i < domain->namedVariablesCount; i++) { + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + element = LinkedList_insertAfter(element, copyString(variables[index[i]]->name)); +#else + element = LinkedList_insertAfter(element, copyString(variables[i]->name)); +#endif + +#if (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + char* prefix = variables[index[i]]->name; + element = addSubNamedVaribleNamesToList(element, prefix, variables[index[i]]); +#else + char* prefix = variables[i]->name; + element = addSubNamedVaribleNamesToList(element, prefix, variables[i]); +#endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ +#endif /* (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) */ + + } + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + GLOBAL_FREEMEM(index); +#endif + } + + return nameList; +} + + +#if (MMS_DATA_SET_SERVICE == 1) + +static LinkedList +createStringsFromNamedVariableList(LinkedList nameList, LinkedList variableLists) +{ + nameList = LinkedList_create(); + LinkedList variableListsElement = LinkedList_getNext(variableLists); + while (variableListsElement != NULL) { + MmsNamedVariableList variableList = + (MmsNamedVariableList) variableListsElement->data; + + LinkedList_add(nameList, + copyString(MmsNamedVariableList_getName(variableList))); + + variableListsElement = LinkedList_getNext(variableListsElement); + } + return nameList; +} + +static LinkedList +getNamedVariableListsDomainSpecific(MmsServerConnection connection, char* domainName) +{ + MmsDevice* device = MmsServer_getDevice(connection->server); + + LinkedList nameList = NULL; + + MmsDomain* domain = MmsDevice_getDomain(device, domainName); + + if (domain != NULL) { + LinkedList variableLists = MmsDomain_getNamedVariableLists(domain); + + nameList = createStringsFromNamedVariableList(nameList, variableLists); + } + + return nameList; +} + +static LinkedList +getnamedVariableListsVMDSpecific(MmsServerConnection connection) +{ + MmsDevice* device = MmsServer_getDevice(connection->server); + + LinkedList nameList = NULL; + + LinkedList variableLists = MmsDevice_getNamedVariableLists(device); + + nameList = createStringsFromNamedVariableList(nameList, variableLists); + + return nameList; +} + +#if (MMS_DYNAMIC_DATA_SETS == 1) +static LinkedList +getNamedVariableListAssociationSpecific(MmsServerConnection connection) +{ + LinkedList nameList = NULL; + + LinkedList variableLists = MmsServerConnection_getNamedVariableLists(connection); + + nameList = createStringsFromNamedVariableList(nameList, variableLists); + + return nameList; +} +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + +#endif /* (MMS_DATA_SET_SERVICE == 1) */ + +static void +createNameListResponse( + MmsServerConnection connection, + int invokeId, + LinkedList nameList, + ByteBuffer* response, + char* continueAfter) +{ + LinkedList startElement = NULL; + + if (continueAfter != NULL) { + LinkedList element = nameList; + + while ((element = LinkedList_getNext(element)) != NULL) { + if (strcmp((char*) (element->data), continueAfter) == 0) { + startElement = element; + break; + } + } + + if (startElement == NULL) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + return; + } + } + + /* determine number of identifiers to include in response */ + if (startElement == NULL) + startElement = nameList; + + int nameCount = 0; + int estimatedMmsPduLength = 27; /* estimated overhead size of PDU encoding */ + int maxPduSize = connection->maxPduSize; + + bool moreFollows = false; + + LinkedList element = startElement; + + uint32_t identifierListSize = 0; + + while ((element = LinkedList_getNext(element)) != NULL) { + int elementLength; + + elementLength = BerEncoder_determineEncodedStringSize((char*) element->data); + + if ((estimatedMmsPduLength + elementLength) > maxPduSize) { + moreFollows = true; + break; + } + else { + estimatedMmsPduLength += elementLength; + identifierListSize += elementLength; + nameCount++; + } + + } + + uint32_t listOfIdentifierSize = 1 + BerEncoder_determineLengthSize(identifierListSize) + identifierListSize; + + uint32_t getNameListSize = listOfIdentifierSize; + + if (moreFollows == false) + getNameListSize += 3; + + uint32_t confirmedServiceResponseSize = 1 + BerEncoder_determineLengthSize(getNameListSize) + getNameListSize; + + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2; + + uint32_t confirmedResponsePDUSize = confirmedServiceResponseSize + invokeIdSize; + + /* encode response */ + element = startElement; + + uint8_t* buffer = response->buffer; + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xa1, getNameListSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, identifierListSize, buffer, bufPos); + + int i = 0; + + while ((element = LinkedList_getNext(element)) != NULL) { + bufPos = BerEncoder_encodeStringWithTag(0x1a, (char*) element->data, buffer, bufPos); + + i++; + + if (i == nameCount) + break; + } + + if (moreFollows == false) + bufPos = BerEncoder_encodeBoolean(0x81, moreFollows, buffer, bufPos); + + response->size = bufPos; + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: getNameList: encoded %i bytes\n", response->size); +} + +void +mmsServer_handleGetNameListRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + int objectClass = -1; + + int objectScope = -1; + + char* domainId = NULL; + int domainIdLength; + + char* continueAfter = NULL; + int continueAfterLength; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + switch (tag) { + + case 0xa0: /* objectClass */ + bufPos++; + length = buffer[bufPos++]; + objectClass = BerDecoder_decodeUint32(buffer, length, bufPos); + break; + + case 0xa1: /* objectScope */ + { + uint8_t objectScopeTag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + switch (objectScopeTag) { + case 0x80: /* vmd-specific */ + objectScope = OBJECT_SCOPE_VMD; + break; + case 0x81: /* domain-specific */ + domainIdLength = length; + domainId = (char*) (buffer + bufPos); + objectScope = OBJECT_SCOPE_DOMAIN; + break; + case 0x82: /* association-specific */ + objectScope = OBJECT_SCOPE_ASSOCIATION; + break; + default: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_MODIFIER, response); + return; + } + } + break; + + case 0x82: /* continueAfter */ + continueAfter = (char*) (buffer + bufPos); + continueAfterLength = length; + break; + default: + /* ignore unknown tag */ + break; + } + + bufPos += length; + } + + + char continueAfterIdMemory[130]; + char* continueAfterId = NULL; + + if (continueAfter != NULL) { + continueAfterId = continueAfterIdMemory; + memcpy(continueAfterId, continueAfter, continueAfterLength); + continueAfterId[continueAfterLength] = 0; + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: getNameListRequest - continue after: (%s)\n", continueAfterId); + } + + if (objectScope == OBJECT_SCOPE_DOMAIN) { + char domainSpecificName[130]; + + memcpy(domainSpecificName, domainId, domainIdLength); + domainSpecificName[domainIdLength] = 0; + + if (objectClass == OBJECT_CLASS_NAMED_VARIABLE) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: get namelist for (%s)\n", domainSpecificName); + + LinkedList nameList = getNameListDomainSpecific(connection, domainSpecificName); + + if (nameList == NULL) + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + else { + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + LinkedList_destroy(nameList); + } + } +#if (MMS_DATA_SET_SERVICE == 1) + else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) { + LinkedList nameList = getNamedVariableListsDomainSpecific(connection, domainSpecificName); + + if (nameList == NULL) + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + else { + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfter); + LinkedList_destroy(nameList); + } + } +#endif /* (MMS_DATA_SET_SERVICE == 1) */ + + else { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getNameList domain specific objectClass %i not supported!\n", objectClass); + + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } + } + + else if (objectScope == OBJECT_SCOPE_VMD) { /* vmd-specific */ + + if (objectClass == OBJECT_CLASS_DOMAIN) { + + LinkedList nameList = getDomainNames(connection); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfter); + + LinkedList_destroyStatic(nameList); + } + +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE) { + LinkedList nameList = getNameListVMDSpecific(connection); + + createNameListResponse(connection, invokeId, nameList, response, continueAfter); + + LinkedList_destroyStatic(nameList); + } +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + +#if (MMS_DATA_SET_SERVICE == 1) + else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) { + LinkedList nameList = getnamedVariableListsVMDSpecific(connection); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfter); + + LinkedList_destroy(nameList); + } +#endif /* (MMS_DATA_SET_SERVICE == 1) */ + + else if (objectClass == OBJECT_CLASS_JOURNAL) { + LinkedList nameList = LinkedList_create(); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfter); + + LinkedList_destroy(nameList); + } + + else { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getNameList VMD specific objectClass %i not supported!\n", objectClass); + + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } + } + +#if (MMS_DATA_SET_SERVICE == 1) +#if (MMS_DYNAMIC_DATA_SETS == 1) + else if (objectScope == OBJECT_SCOPE_ASSOCIATION) { /* association-specific */ + + if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) { + LinkedList nameList = getNamedVariableListAssociationSpecific(connection); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfter); + + LinkedList_destroy(nameList); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ +#endif /* (MMS_DATA_SET_SERVICE == 1) */ + + else { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getNameList(%i) not supported!\n", objectScope); + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } + +} + + +#endif /* (MMS_GET_NAME_LIST == 1) */ diff --git a/src/mms/iso_mms/server/mms_get_var_access_service.c b/src/mms/iso_mms/server/mms_get_var_access_service.c new file mode 100644 index 0000000..d47ecb0 --- /dev/null +++ b/src/mms/iso_mms/server/mms_get_var_access_service.c @@ -0,0 +1,350 @@ +/* + * mms_get_var_access_service.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +#if (MMS_GET_VARIABLE_ACCESS_ATTRIBUTES == 1) + +/********************************************************************************************** + * MMS GetVariableAccessAttributes Service + *********************************************************************************************/ + +static int +createTypeSpecification ( + MmsVariableSpecification* namedVariable, + TypeSpecification_t* typeSpec) +{ + + if (namedVariable->type == MMS_ARRAY) { + typeSpec->present = TypeSpecification_PR_array; + + asn_long2INTEGER(&(typeSpec->choice.array.numberOfElements), + (long) namedVariable->typeSpec.array.elementCount); + + typeSpec->choice.array.packed = NULL; + typeSpec->choice.array.elementType = (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); + + createTypeSpecification(namedVariable->typeSpec.array.elementTypeSpec, + typeSpec->choice.array.elementType); + } + else if (namedVariable->type == MMS_STRUCTURE) { + + typeSpec->present = TypeSpecification_PR_structure; + + int componentCount = namedVariable->typeSpec.structure.elementCount; + + typeSpec->choice.structure.components.list.count = componentCount; + typeSpec->choice.structure.components.list.size = componentCount; + + typeSpec->choice.structure.components.list.array + = (StructComponent_t**) GLOBAL_CALLOC(componentCount, sizeof(StructComponent_t*)); + + int i; + + for (i = 0; i < componentCount; i++) { + + typeSpec->choice.structure.components.list.array[i] = + (StructComponent_t*) GLOBAL_CALLOC(1, sizeof(StructComponent_t)); + + typeSpec->choice.structure.components.list.array[i]->componentName = + (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); + + typeSpec->choice.structure.components.list.array[i]->componentName->buf = + (uint8_t*) copyString(namedVariable->typeSpec.structure.elements[i]->name); + + typeSpec->choice.structure.components.list.array[i]->componentName->size = + strlen(namedVariable->typeSpec.structure.elements[i]->name); + + typeSpec->choice.structure.components.list.array[i]->componentType = + (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); + + createTypeSpecification(namedVariable->typeSpec.structure.elements[i], + typeSpec->choice.structure.components.list.array[i]->componentType); + } + } + else { + + switch (namedVariable->type) { + case MMS_BOOLEAN: + typeSpec->present = TypeSpecification_PR_boolean; + break; + case MMS_BIT_STRING: + typeSpec->present = TypeSpecification_PR_bitstring; + typeSpec->choice.bitstring = namedVariable->typeSpec.bitString; + break; + case MMS_INTEGER: + typeSpec->present = TypeSpecification_PR_integer; + typeSpec->choice.integer = namedVariable->typeSpec.integer; + break; + case MMS_UNSIGNED: + typeSpec->present = TypeSpecification_PR_unsigned; + typeSpec->choice.Unsigned = namedVariable->typeSpec.unsignedInteger; + break; + case MMS_FLOAT: + typeSpec->present = TypeSpecification_PR_floatingpoint; + typeSpec->choice.floatingpoint.exponentwidth = + namedVariable->typeSpec.floatingpoint.exponentWidth; + typeSpec->choice.floatingpoint.formatwidth = + namedVariable->typeSpec.floatingpoint.formatWidth; + break; + case MMS_OCTET_STRING: + typeSpec->present = TypeSpecification_PR_octetstring; + typeSpec->choice.octetstring = namedVariable->typeSpec.octetString; + break; + case MMS_VISIBLE_STRING: + typeSpec->present = TypeSpecification_PR_visiblestring; + typeSpec->choice.visiblestring = namedVariable->typeSpec.visibleString; + break; + case MMS_STRING: + typeSpec->present = TypeSpecification_PR_mMSString; + typeSpec->choice.mMSString = namedVariable->typeSpec.mmsString; + break; + case MMS_UTC_TIME: + typeSpec->present = TypeSpecification_PR_utctime; + break; + case MMS_BINARY_TIME: + typeSpec->present = TypeSpecification_PR_binarytime; + + if (namedVariable->typeSpec.binaryTime == 6) + typeSpec->choice.binarytime = 1; + else + typeSpec->choice.binarytime = 0; + + break; + default: + if (DEBUG_MMS_SERVER) + printf("MMS-SERVER: Unsupported type %i!\n", namedVariable->type); + return -1; + break; + } + } + + return 1; +} + +static void +freeTypeSpecRecursive(TypeSpecification_t* typeSpec) { + if (typeSpec->present == TypeSpecification_PR_structure) { + int elementCount = + typeSpec->choice.structure.components.list.count; + + int i; + + for (i = 0; i < elementCount; i++) { + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName->buf); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName); + freeTypeSpecRecursive(typeSpec->choice.structure.components.list.array[i]->componentType); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentType); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]); + } + + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array); + } + else if (typeSpec->present == TypeSpecification_PR_array) { + GLOBAL_FREEMEM(typeSpec->choice.array.numberOfElements.buf); + freeTypeSpecRecursive(typeSpec->choice.array.elementType); + GLOBAL_FREEMEM(typeSpec->choice.array.elementType); + } +} + +static void +deleteVariableAccessAttributesResponse( + GetVariableAccessAttributesResponse_t* getVarAccessAttr) +{ + if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_structure) { + int count = getVarAccessAttr->typeSpecification.choice.structure.components.list.count; + + int i; + for (i = 0; i < count; i++) { + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName); + TypeSpecification_t* typeSpec = + getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentType; + freeTypeSpecRecursive(typeSpec); + GLOBAL_FREEMEM(typeSpec); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]); + } + + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array); + + getVarAccessAttr->typeSpecification.choice.structure.components.list.array = NULL; + getVarAccessAttr->typeSpecification.choice.structure.components.list.count = 0; + getVarAccessAttr->typeSpecification.choice.structure.components.list.size = 0; + } else if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_array) { + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf); + getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf = NULL; + getVarAccessAttr->typeSpecification.choice.array.numberOfElements.size = 0; + freeTypeSpecRecursive(getVarAccessAttr->typeSpecification.choice.array.elementType); + + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.elementType); + + getVarAccessAttr->typeSpecification.choice.array.elementType = NULL; + } +} + +static void +createVariableAccessAttributesResponse( + MmsServerConnection connection, + char* domainId, + char* nameId, + int invokeId, + ByteBuffer* response) +{ + MmsDevice* device = MmsServer_getDevice(connection->server); + + MmsVariableSpecification* namedVariable = NULL; + + if (domainId != NULL) { + MmsDomain* domain = MmsDevice_getDomain(device, domainId); + + if (domain == NULL) { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: domain %s not known\n", domainId); + + mmsServer_createConfirmedErrorPdu(invokeId, response, + MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_function; + } + + namedVariable = MmsDomain_getNamedVariable(domain, nameId); + } +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + else + namedVariable = MmsDevice_getNamedVariable(device, nameId); +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + + + if (namedVariable == NULL) { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: named variable %s not known\n", nameId); + + mmsServer_createConfirmedErrorPdu(invokeId, response, + MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + + goto exit_function; + } + + MmsPdu_t* mmsPdu = mmsServer_createConfirmedResponse(invokeId); + + mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present = + ConfirmedServiceResponse_PR_getVariableAccessAttributes; + + GetVariableAccessAttributesResponse_t* getVarAccessAttr; + + getVarAccessAttr = &(mmsPdu->choice.confirmedResponsePdu. + confirmedServiceResponse.choice.getVariableAccessAttributes); + + getVarAccessAttr->mmsDeletable = 0; + + createTypeSpecification(namedVariable, &getVarAccessAttr->typeSpecification); + + asn_enc_rval_t rval = + der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); + + if (rval.encoded == -1) { + response->size = 0; + + if (DEBUG_MMS_SERVER) + printf("MMS getVariableAccessAttributes: message to large! send error PDU!\n"); + + mmsServer_createConfirmedErrorPdu(invokeId, response, + MMS_ERROR_SERVICE_OTHER); + + goto exit_function; + } + + deleteVariableAccessAttributesResponse(getVarAccessAttr); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + +exit_function: + return; +} + +int +mmsServer_handleGetVariableAccessAttributesRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + int retVal = 0; + + GetVariableAccessAttributesRequest_t* request = 0; + + asn_dec_rval_t rval; /* Decoder return value */ + + rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest, + (void**) &request, buffer + bufPos, maxBufPos - bufPos); + + if (rval.code == RC_OK) { + if (request->present == GetVariableAccessAttributesRequest_PR_name) { + if (request->choice.name.present == ObjectName_PR_domainspecific) { + Identifier_t domainId = request->choice.name.choice.domainspecific.domainId; + Identifier_t nameId = request->choice.name.choice.domainspecific.itemId; + + char* domainIdStr = createStringFromBuffer(domainId.buf, domainId.size); + char* nameIdStr = createStringFromBuffer(nameId.buf, nameId.size); + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: getVariableAccessAttributes domainId: %s nameId: %s\n", domainIdStr, nameIdStr); + + createVariableAccessAttributesResponse(connection, domainIdStr, nameIdStr, invokeId, response); + + GLOBAL_FREEMEM(domainIdStr); + GLOBAL_FREEMEM(nameIdStr); + } +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + else if (request->choice.name.present == ObjectName_PR_vmdspecific) { + Identifier_t nameId = request->choice.name.choice.vmdspecific; + + char* nameIdStr = createStringFromBuffer(nameId.buf, nameId.size); + + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getVariableAccessAttributes (VMD specific) nameId: %s\n", nameIdStr); + + createVariableAccessAttributesResponse(connection, NULL, nameIdStr, invokeId, response); + + GLOBAL_FREEMEM(nameIdStr); + } +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + else { + if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest with name other than domainspecific is not supported!\n"); + retVal = -1; + } + } + else { + if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest with address not supported!\n"); + retVal = -1; + } + } + else { + if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest parsing request failed!\n"); + retVal = -1; + } + + asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetVariableAccessAttributesRequest, request, 0); + + return retVal; +} + +#endif /* (MMS_GET_VARIABLE_ACCESS_ATTRIBUTES == 1) */ + diff --git a/src/mms/iso_mms/server/mms_identify_service.c b/src/mms/iso_mms/server/mms_identify_service.c new file mode 100644 index 0000000..b8ff70b --- /dev/null +++ b/src/mms/iso_mms/server/mms_identify_service.c @@ -0,0 +1,104 @@ +/* + * mms_identify_service.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +#if MMS_IDENTIFY_SERVICE == 1 + +void +mmsServer_handleIdentifyRequest( + MmsServerConnection connection, + int invokeId, + ByteBuffer* response) +{ + int bufPos = 0; + uint8_t* buffer = response->buffer; + + uint32_t invokeIdLength = BerEncoder_UInt32determineEncodedSize(invokeId); + + MmsServer mmsServer = connection->server; + + uint32_t vendorNameLength = strlen(MmsServer_getVendorName(mmsServer)); + uint32_t modelNameLength = strlen(MmsServer_getModelName(mmsServer)); + uint32_t revisionLength = strlen(MmsServer_getRevision(mmsServer)); + + uint32_t identityLength = 3 + BerEncoder_determineLengthSize(vendorNameLength) + + BerEncoder_determineLengthSize(modelNameLength) + BerEncoder_determineLengthSize(revisionLength) + + vendorNameLength + modelNameLength + revisionLength; + + uint32_t identifyResponseLength = invokeIdLength + 2 + 1 + BerEncoder_determineLengthSize(identityLength) + + identityLength; + + /* Identify response pdu */ + bufPos = BerEncoder_encodeTL(0xa1, identifyResponseLength, buffer, bufPos); + + /* invokeId */ + bufPos = BerEncoder_encodeTL(0x02, invokeIdLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xa2, identityLength, buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x80, MmsServer_getVendorName(mmsServer), buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x81, MmsServer_getModelName(mmsServer), buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x82, MmsServer_getRevision(mmsServer), buffer, bufPos); + + response->size = bufPos; +} + +void +MmsServer_setServerIdentity(MmsServer self, char* vendorName, char* modelName, char* revision) +{ + self->vendorName = vendorName; + self->modelName = modelName; + self->revision = revision; +} + +char* +MmsServer_getVendorName(MmsServer self) +{ + if (self->vendorName != NULL) + return self->vendorName; + else + return CONFIG_DEFAULT_MMS_VENDOR_NAME; +} + +char* +MmsServer_getModelName(MmsServer self) +{ + if (self->modelName != NULL) + return self->modelName; + else + return CONFIG_DEFAULT_MMS_MODEL_NAME; +} + +char* +MmsServer_getRevision(MmsServer self) +{ + if (self->revision != NULL) + return self->revision; + else + return CONFIG_DEFAULT_MMS_REVISION; +} + +#endif /* MMS_IDENTIFY_SERVICE == 1 */ + diff --git a/src/mms/iso_mms/server/mms_information_report.c b/src/mms/iso_mms/server/mms_information_report.c new file mode 100644 index 0000000..eee0bb2 --- /dev/null +++ b/src/mms/iso_mms/server/mms_information_report.c @@ -0,0 +1,307 @@ +/* + * mms_information_report.c + * + * Copyright 2013, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "mms_server_internal.h" +#include "mms_common_internal.h" +#include "mms_access_result.h" + +#include "ber_encoder.h" + +void +MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConnection self, + char* itemId, MmsValue* value, bool handlerMode) +{ + uint32_t itemIdSize = strlen(itemId); + uint32_t varSpecSize = 1 + BerEncoder_determineLengthSize(itemIdSize) + itemIdSize; + uint32_t sequenceSize = 1 + BerEncoder_determineLengthSize(varSpecSize) + varSpecSize; + uint32_t listOfVariableSize = 1 + BerEncoder_determineLengthSize(sequenceSize) + sequenceSize; + + uint32_t accessResultSize = mmsServer_encodeAccessResult(value, NULL, 0, false); + + uint32_t listOfAccessResultSize = 1 + BerEncoder_determineLengthSize(accessResultSize) + accessResultSize; + + uint32_t variableSpecSize = 1 + BerEncoder_determineLengthSize(listOfVariableSize) + listOfVariableSize; + + uint32_t informationReportContentSize = variableSpecSize + listOfAccessResultSize; + + uint32_t informationReportSize = 1 + BerEncoder_determineLengthSize(informationReportContentSize) + + informationReportContentSize; + + uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); + + if (completeMessageSize > self->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, self->maxPduSize); + + goto exit_function; + } + + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReportSingle variable: %s\n", itemId); + + ByteBuffer* reportBuffer = self->server->reportBuffer; + + uint8_t* buffer = reportBuffer->buffer; + int bufPos = 0; + + /* encode information report header */ + bufPos = BerEncoder_encodeTL(0xa3, informationReportSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, informationReportContentSize, buffer, bufPos); + + /* encode list of variable access specifications */ + bufPos = BerEncoder_encodeTL(0xa0, listOfVariableSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, varSpecSize, buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x80, itemId, buffer, bufPos); + + /* encode access result (variable value) */ + bufPos = BerEncoder_encodeTL(0xa0, accessResultSize, buffer, bufPos); + bufPos = mmsServer_encodeAccessResult(value, buffer, bufPos, true); + + reportBuffer->size = bufPos; + + IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode); + +exit_function: + return; +} + +void +MmsServerConnection_sendInformationReportListOfVariables( + MmsServerConnection self, + LinkedList /* MmsVariableAccessSpecification */ variableAccessDeclarations, + LinkedList /* MmsValue */ values, + bool handlerMode + ) +{ + /* determine message size */ + uint32_t listOfVarSpecSize = 0; + + int i = 0; + + LinkedList specElement = LinkedList_getNext(variableAccessDeclarations); + + while (specElement != NULL) { + MmsVariableAccessSpecification* spec = (MmsVariableAccessSpecification*) specElement->data; + + uint32_t varSpecSize = BerEncoder_determineEncodedStringSize(spec->itemId); + + if (spec->domainId != NULL) + varSpecSize += BerEncoder_determineEncodedStringSize(spec->domainId); + + uint32_t sequenceSize = (varSpecSize + 1 + BerEncoder_determineLengthSize(varSpecSize)); + + listOfVarSpecSize += (1 + BerEncoder_determineLengthSize(sequenceSize) + sequenceSize); + + i++; + specElement = LinkedList_getNext(specElement); + } + + uint32_t listOfVariableSize = 1 + BerEncoder_determineLengthSize(listOfVarSpecSize) + listOfVarSpecSize; + + + uint32_t accessResultSize = 0; + + LinkedList valueElement = LinkedList_getNext(values); + + while (valueElement != NULL) { + MmsValue* value = (MmsValue*) valueElement->data; + + accessResultSize += mmsServer_encodeAccessResult(value, NULL, 0, false); + + valueElement = LinkedList_getNext(valueElement); + } + + uint32_t listOfAccessResultSize = 1 + BerEncoder_determineLengthSize(accessResultSize) + accessResultSize; + + uint32_t variableSpecSize = 1 + BerEncoder_determineLengthSize(listOfVariableSize) + listOfVariableSize; + + uint32_t informationReportContentSize = variableSpecSize + listOfAccessResultSize; + + uint32_t informationReportSize = 1 + BerEncoder_determineLengthSize(informationReportContentSize) + + informationReportContentSize; + + uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); + + if (completeMessageSize > self->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, self->maxPduSize); + + goto exit_function; + } + + /* encode message */ + ByteBuffer* reportBuffer = self->server->reportBuffer; + + uint8_t* buffer = reportBuffer->buffer; + int bufPos = 0; + + /* encode information report header */ + bufPos = BerEncoder_encodeTL(0xa3, informationReportSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, informationReportContentSize, buffer, bufPos); + + /* encode list of variable access specifications */ + bufPos = BerEncoder_encodeTL(0xa0, listOfVariableSize, buffer, bufPos); + + specElement = LinkedList_getNext(variableAccessDeclarations); + i = 0; + + while (specElement != NULL) { + MmsVariableAccessSpecification* spec = (MmsVariableAccessSpecification*) specElement->data; + + uint32_t varSpecSize = BerEncoder_determineEncodedStringSize(spec->itemId); + + if (spec->domainId != NULL) { + + varSpecSize += BerEncoder_determineEncodedStringSize(spec->domainId); + uint32_t varSpecSizeComplete = varSpecSize + BerEncoder_determineLengthSize(varSpecSize) + 1; + uint32_t sequenceSize = varSpecSizeComplete + BerEncoder_determineLengthSize(varSpecSizeComplete) + 1; + + bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, varSpecSizeComplete, buffer, bufPos); /* domain-specific */ + bufPos = BerEncoder_encodeTL(0xa1, varSpecSize, buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x1a, spec->domainId, buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x1a, spec->itemId, buffer, bufPos); + } + else { + uint32_t sequenceSize = varSpecSize + BerEncoder_determineLengthSize(varSpecSize) + 1; + bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, varSpecSize, buffer, bufPos); /* vmd-specific */ + bufPos = BerEncoder_encodeStringWithTag(0x80, spec->itemId, buffer, bufPos); + } + + + i++; + specElement = LinkedList_getNext(specElement); + } + + /* encode list of access results (variable values) */ + bufPos = BerEncoder_encodeTL(0xa0, accessResultSize, buffer, bufPos); + + valueElement = LinkedList_getNext(values); + + while (valueElement != NULL) { + MmsValue* value = (MmsValue*) valueElement->data; + + bufPos = mmsServer_encodeAccessResult(value, buffer, bufPos, true); + + valueElement = LinkedList_getNext(valueElement); + } + + reportBuffer->size = bufPos; + + IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode); + +exit_function: + return; +} + + +void /* send information report for a named variable list */ +MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, char* itemId, LinkedList values, + bool handlerMode) +{ + uint32_t variableAccessSpecSize = 0; + uint32_t objectNameSize = 0; + + uint32_t accessResultSize = 0; + uint32_t listOfAccessResultSize; + uint32_t informationReportSize; + + objectNameSize = BerEncoder_determineEncodedStringSize(itemId); + variableAccessSpecSize += objectNameSize; + variableAccessSpecSize += BerEncoder_determineLengthSize(objectNameSize); + variableAccessSpecSize += 1; /* space for tag (a1) */ + + int variableCount = LinkedList_size(values); + + /* iterate values list and add values to the accessResultList */ + LinkedList value = LinkedList_getNext(values); + + int i; + + for (i = 0; i < variableCount; i++) { + + MmsValue* data = (MmsValue*) value->data; + + accessResultSize += mmsServer_encodeAccessResult(data, NULL, 0, false); + + value = LinkedList_getNext(value); + } + + listOfAccessResultSize = accessResultSize + + BerEncoder_determineLengthSize(accessResultSize) + 1; + + uint32_t informationReportContentSize = variableAccessSpecSize + listOfAccessResultSize; + + informationReportSize = 1 + informationReportContentSize + + BerEncoder_determineLengthSize(informationReportContentSize); + + uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); + + if (completeMessageSize > self->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, self->maxPduSize); + + goto exit_function; + } + + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReport: %i items\n", variableCount); + + ByteBuffer* reportBuffer = self->server->reportBuffer; + + uint8_t* buffer = reportBuffer->buffer; + int bufPos = 0; + + + /* encode */ + bufPos = BerEncoder_encodeTL(0xa3, informationReportSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa0, informationReportContentSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xa1, objectNameSize, buffer, bufPos); + bufPos = BerEncoder_encodeStringWithTag(0x80, itemId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xa0, accessResultSize, buffer, bufPos); + + value = LinkedList_getNext(values); + + for (i = 0; i < variableCount; i++) { + + MmsValue* data = (MmsValue*) value->data; + + bufPos = mmsServer_encodeAccessResult(data, buffer, bufPos, true); + + value = LinkedList_getNext(value); + } + + reportBuffer->size = bufPos; + + IsoConnection_sendMessage(self->isoConnection, reportBuffer, false); + +exit_function: + return; +} + + + diff --git a/src/mms/iso_mms/server/mms_named_variable_list.c b/src/mms/iso_mms/server/mms_named_variable_list.c new file mode 100644 index 0000000..6489428 --- /dev/null +++ b/src/mms/iso_mms/server/mms_named_variable_list.c @@ -0,0 +1,122 @@ +/* + * mms_named_variable_list.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "mms_named_variable_list.h" + +MmsNamedVariableListEntry +MmsNamedVariableListEntry_create(MmsAccessSpecifier accessSpecifier) +{ + MmsNamedVariableListEntry listEntry = (MmsNamedVariableListEntry) GLOBAL_MALLOC(sizeof(MmsAccessSpecifier)); + + listEntry->domain = accessSpecifier.domain; + listEntry->variableName = copyString(accessSpecifier.variableName); + listEntry->arrayIndex = accessSpecifier.arrayIndex; + + if (accessSpecifier.componentName != NULL) + listEntry->componentName = copyString(accessSpecifier.componentName); + else + listEntry->componentName = NULL; + + return listEntry; +} + +void +MmsNamedVariableListEntry_destroy(MmsNamedVariableListEntry self) +{ + GLOBAL_FREEMEM(self->variableName); + GLOBAL_FREEMEM(self); +} + + +MmsDomain* +MmsNamedVariableListEntry_getDomain(MmsNamedVariableListEntry self) +{ + return self->domain; +} + +char* +MmsNamedVariableListEntry_getVariableName(MmsNamedVariableListEntry self) { + return self->variableName; +} + +MmsNamedVariableList +MmsNamedVariableList_create(MmsDomain* domain, char* name, bool deletable) +{ + MmsNamedVariableList self = (MmsNamedVariableList) GLOBAL_MALLOC(sizeof(struct sMmsNamedVariableList)); + + self->deletable = deletable; + self->name = copyString(name); + self->listOfVariables = LinkedList_create(); + self->domain = domain; + + return self; +} + +MmsDomain* +MmsNamedVariableList_getDomain(MmsNamedVariableList self) +{ + return self->domain; +} + +char* +MmsNamedVariableList_getName(MmsNamedVariableList self) +{ + return self->name; +} + +bool +MmsNamedVariableList_isDeletable(MmsNamedVariableList self) +{ + return self->deletable; +} + +void +MmsNamedVariableList_addVariable(MmsNamedVariableList self, MmsNamedVariableListEntry variable) +{ + LinkedList_add(self->listOfVariables, variable); +} + +LinkedList +MmsNamedVariableList_getVariableList(MmsNamedVariableList self) +{ + return self->listOfVariables; +} + +static void +deleteVariableListEntry(void* listEntry) +{ + MmsNamedVariableListEntry entry = (MmsNamedVariableListEntry) listEntry; + MmsNamedVariableListEntry_destroy(entry); +} + +void +MmsNamedVariableList_destroy(MmsNamedVariableList self) +{ + LinkedList_destroyDeep(self->listOfVariables, deleteVariableListEntry); + GLOBAL_FREEMEM(self->name); + 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 new file mode 100644 index 0000000..954da06 --- /dev/null +++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c @@ -0,0 +1,650 @@ +/* + * mms_named_variable_list_service.c + * + * Copyright 2013-2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" +#include "mms_named_variable_list.h" + +#include "ber_encoder.h" + +#if (MMS_DATA_SET_SERVICE == 1) + +#if (MMS_DYNAMIC_DATA_SETS == 1) + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS +#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10 +#endif + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS +#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10 +#endif + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS +#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10 +#endif + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS +#define CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 50 +#endif + +MmsError +mmsServer_callVariableListChangedHandler(bool create, MmsVariableListType listType, MmsDomain* domain, + char* listName, MmsServerConnection connection) +{ + MmsServer self = connection->server; + + if (self->variableListChangedHandler != NULL) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: call MmsNamedVariableListChangedHandler for new list %s\n", listName); + + return self->variableListChangedHandler(self->variableListChangedHandlerParameter, + create, listType, domain, listName, connection); + } + else + return MMS_ERROR_NONE; +} + +static void +createDeleteNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response, + uint32_t numberMatched, uint32_t numberDeleted) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; + + uint32_t numberMatchedSize = + 2 + BerEncoder_UInt32determineEncodedSize(numberMatched); + + uint32_t numberDeletedSize = + 2 + BerEncoder_UInt32determineEncodedSize(numberDeleted); + + uint32_t deleteNVLSize = 2 + numberMatchedSize + numberDeletedSize; + + uint32_t confirmedResponsePDUSize = invokeIdSize + deleteNVLSize; + + int bufPos = 0; + uint8_t* buffer = response->buffer; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xad, numberMatchedSize + numberDeletedSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x80, numberMatchedSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(numberMatched, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x81, numberDeletedSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(numberDeleted, buffer, bufPos); + + response->size = bufPos; +} + +void +mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + DeleteNamedVariableListRequest_t* request = 0; + + MmsPdu_t* mmsPdu = 0; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, maxBufPos); + + if (rval.code != RC_OK) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; + } + + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); + + long scopeOfDelete; + + asn_INTEGER2long(request->scopeOfDelete, &scopeOfDelete); + + MmsDevice* device = MmsServer_getDevice(connection->server); + + if (scopeOfDelete == DeleteNamedVariableListRequest__scopeOfDelete_specific) { + int numberMatched = 0; + int numberDeleted = 0; + + int numberItems = request->listOfVariableListName->list.count; + + int i; + + for (i = 0; i < numberItems; i++) { + if (request->listOfVariableListName->list.array[i]->present == ObjectName_PR_domainspecific) { + char domainName[65]; + char listName[65]; + + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.domainspecific.domainId, + domainName, 65); + + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.domainspecific.itemId, + listName, 65); + + MmsDomain* domain = MmsDevice_getDomain(device, domainName); + + if (domain != NULL) { + + MmsNamedVariableList variableList = MmsDomain_getNamedVariableList(domain, listName); + + if (variableList != NULL) { + numberMatched++; + + if (MmsNamedVariableList_isDeletable(variableList)) { + + if (mmsServer_callVariableListChangedHandler(false, MMS_DOMAIN_SPECIFIC, domain, listName, connection) == MMS_ERROR_NONE) { + MmsDomain_deleteNamedVariableList(domain, listName); + numberDeleted++; + } + } + } + } + } + else if (request->listOfVariableListName->list.array[i]->present == ObjectName_PR_aaspecific) { + char listName[65]; + + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.aaspecific, + listName, 65); + + MmsNamedVariableList variableList = MmsServerConnection_getNamedVariableList(connection, listName); + + if (variableList != NULL) { + numberMatched++; + + if (mmsServer_callVariableListChangedHandler(false, MMS_ASSOCIATION_SPECIFIC, NULL, listName, connection) == MMS_ERROR_NONE) { + numberDeleted++; + MmsServerConnection_deleteNamedVariableList(connection, listName); + } + } + } + } + + createDeleteNamedVariableListResponse(invokeId, response, numberMatched, numberDeleted); + } + else { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + +exit_function: + return; +} + +static void +createDefineNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response) +{ + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2; + + uint32_t confirmedResponsePDUSize = 2 + invokeIdSize; + + int bufPos = 0; + uint8_t* buffer = response->buffer; + + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x8b, 0, buffer, bufPos); + + response->size = bufPos; +} + +static bool +checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier) +{ + if (accessSpecifier->domain == NULL) + return false; + + MmsVariableSpecification* variableSpec = + MmsDomain_getNamedVariable(accessSpecifier->domain, accessSpecifier->variableName); + + if (variableSpec == NULL) + return false; + + if (accessSpecifier->arrayIndex != -1) { + if (variableSpec->type != MMS_ARRAY) + return false; + + if (accessSpecifier->arrayIndex >= variableSpec->typeSpec.array.elementCount) + return false; + + if (accessSpecifier->componentName != NULL) { + if (MmsVariableSpecification_getNamedVariableRecursive(variableSpec, accessSpecifier->componentName) == NULL) + return false; + } + } + + return true; +} + + +static MmsNamedVariableList +createNamedVariableList(MmsDomain* domain, MmsDevice* device, + DefineNamedVariableListRequest_t* request, + char* variableListName, MmsError* mmsError) +{ + MmsNamedVariableList namedVariableList = NULL; + + int variableCount = request->listOfVariable.list.count; + + if ((variableCount == 0 ) || (variableCount > CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS)) { + *mmsError = MMS_ERROR_DEFINITION_OTHER; + goto exit_function; + } + + namedVariableList = MmsNamedVariableList_create(domain, variableListName, true); + + int i; + for (i = 0; i < variableCount; i++) { + VariableSpecification_t* varSpec = + &request->listOfVariable.list.array[i]->variableSpecification; + + long arrayIndex = -1; + + char componentNameBuf[65]; + char* componentName = NULL; + + /* Handle alternate access specification - for array element definition */ + if (request->listOfVariable.list.array[i]->alternateAccess != NULL) { + + if (request->listOfVariable.list.array[i]->alternateAccess->list.count != 1) { + MmsNamedVariableList_destroy(namedVariableList); + namedVariableList = NULL; + break; + } + else { + + struct AlternateAccess__Member* alternateAccess = + 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->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); + + } + else { + MmsNamedVariableList_destroy(namedVariableList); + namedVariableList = NULL; + *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS; + break; + } + + } + + } + + if (varSpec->present == VariableSpecification_PR_name) { + + char variableName[65]; + char domainId[65]; + + StringUtils_createStringFromBufferInBuffer(variableName, + varSpec->choice.name.choice.domainspecific.itemId.buf, + varSpec->choice.name.choice.domainspecific.itemId.size); + + StringUtils_createStringFromBufferInBuffer(domainId, + varSpec->choice.name.choice.domainspecific.domainId.buf, + varSpec->choice.name.choice.domainspecific.domainId.size); + + MmsDomain* elementDomain = MmsDevice_getDomain(device, domainId); + + MmsAccessSpecifier accessSpecifier; + + accessSpecifier.domain = elementDomain; + accessSpecifier.variableName = variableName; + accessSpecifier.arrayIndex = arrayIndex; + accessSpecifier.componentName = componentName; + + // check if element exists + if (checkIfVariableExists(device, &accessSpecifier) == true) { + + MmsNamedVariableListEntry variable = + MmsNamedVariableListEntry_create(accessSpecifier); + + MmsNamedVariableList_addVariable(namedVariableList, variable); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + namedVariableList = NULL; + i = variableCount; // exit loop after freeing loop variables + *mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED; + } + } + else { + MmsNamedVariableList_destroy(namedVariableList); + namedVariableList = NULL; + *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS; + break; + } + } + +exit_function: + + return namedVariableList; +} + +void +mmsServer_handleDefineNamedVariableListRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + DefineNamedVariableListRequest_t* request = 0; + + MmsPdu_t* mmsPdu = 0; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, maxBufPos); + + if (rval.code != RC_OK) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; + } + + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.defineNamedVariableList); + + MmsDevice* device = MmsServer_getDevice(connection->server); + + if (request->variableListName.present == ObjectName_PR_domainspecific) { + + char domainName[65]; + + if (request->variableListName.choice.domainspecific.domainId.size > 64) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } + + StringUtils_createStringFromBufferInBuffer(domainName, + request->variableListName.choice.domainspecific.domainId.buf, + request->variableListName.choice.domainspecific.domainId.size); + + MmsDomain* domain = MmsDevice_getDomain(device, domainName); + + if (domain == NULL) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } + + if (LinkedList_size(domain->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS) { + char variableListName[65]; + + if (request->variableListName.choice.domainspecific.itemId.size > 64) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } + + StringUtils_createStringFromBufferInBuffer(variableListName, + request->variableListName.choice.domainspecific.itemId.buf, + request->variableListName.choice.domainspecific.itemId.size); + + if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; + + MmsNamedVariableList namedVariableList = createNamedVariableList(domain, device, + request, variableListName, &mmsError); + + if (namedVariableList != NULL) { + + mmsError = mmsServer_callVariableListChangedHandler(true, MMS_DOMAIN_SPECIFIC, domain, variableListName, connection); + + if (mmsError == MMS_ERROR_NONE) { + MmsDomain_addNamedVariableList(domain, namedVariableList); + createDefineNamedVariableListResponse(invokeId, response); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError); + } + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError); + } + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); + + + } + else if (request->variableListName.present == ObjectName_PR_aaspecific) { + + if (LinkedList_size(connection->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS) { + + char variableListName[65]; + + if (request->variableListName.choice.aaspecific.size > 64) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } + + StringUtils_createStringFromBufferInBuffer(variableListName, + request->variableListName.choice.aaspecific.buf, + request->variableListName.choice.aaspecific.size); + + if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; + + MmsNamedVariableList namedVariableList = createNamedVariableList(NULL, device, + request, variableListName, &mmsError); + + if (namedVariableList != NULL) { + + if (mmsServer_callVariableListChangedHandler(true, MMS_ASSOCIATION_SPECIFIC, NULL, variableListName, connection) == MMS_ERROR_NONE) { + MmsServerConnection_addNamedVariableList(connection, namedVariableList); + createDefineNamedVariableListResponse(invokeId, response); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } + + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError); + } + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED); + +exit_free_struct: + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + +exit_function: + return; +} + +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + +#if (MMS_GET_DATA_SET_ATTRIBUTES == 1) + +static void +createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, + MmsNamedVariableList variableList) +{ + MmsPdu_t* mmsPdu = mmsServer_createConfirmedResponse(invokeId); + + mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present = + ConfirmedServiceResponse_PR_getNamedVariableListAttributes; + + GetNamedVariableListAttributesResponse_t* varListResponse = + &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse. + choice.getNamedVariableListAttributes); + + varListResponse->mmsDeletable = MmsNamedVariableList_isDeletable(variableList); + + LinkedList variables = MmsNamedVariableList_getVariableList(variableList); + + int variableCount = LinkedList_size(variables); + + varListResponse->listOfVariable.list.count = variableCount; + varListResponse->listOfVariable.list.size = variableCount; + + varListResponse->listOfVariable.list.array = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member**) + GLOBAL_CALLOC(variableCount, sizeof(void*)); + + LinkedList variable = LinkedList_getNext(variables); + + int i; + for (i = 0; i < variableCount; i++) { + MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data; + + varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*) + GLOBAL_CALLOC(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member)); + + varListResponse->listOfVariable.list.array[i]->variableSpecification.present = + VariableSpecification_PR_name; + + varListResponse->listOfVariable.list.array[i]->variableSpecification.choice.name.present = + ObjectName_PR_domainspecific; + + char* variableDomainName = MmsDomain_getName(variableEntry->domain); + + varListResponse->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.domainId.buf = (uint8_t*) copyString(variableDomainName); + + varListResponse->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.domainId.size = strlen(variableDomainName); + + varListResponse->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.itemId.buf = (uint8_t*) copyString(variableEntry->variableName); + + varListResponse->listOfVariable.list.array[i]->variableSpecification.choice.name.choice. + domainspecific.itemId.size = strlen(variableEntry->variableName); + + variable = LinkedList_getNext(variable); + } + + der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +void +mmsServer_handleGetNamedVariableListAttributesRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + GetNamedVariableListAttributesRequest_t* request = 0; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_GetNamedVariableListAttributesRequest, + (void**) &request, buffer + bufPos, maxBufPos - bufPos); + + if (rval.code != RC_OK) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + if (request->present == ObjectName_PR_domainspecific) { + + char domainName[65]; + char itemName[65]; + + if ((request->choice.domainspecific.domainId.size > 64) || + (request->choice.domainspecific.itemId.size > 64)) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); + goto exit_function; + } + + StringUtils_createStringFromBufferInBuffer(domainName, request->choice.domainspecific.domainId.buf, + request->choice.domainspecific.domainId.size); + + StringUtils_createStringFromBufferInBuffer(itemName, request->choice.domainspecific.itemId.buf, + request->choice.domainspecific.itemId.size); + + MmsDevice* mmsDevice = MmsServer_getDevice(connection->server); + + MmsDomain* domain = MmsDevice_getDomain(mmsDevice, domainName); + + if (domain != NULL) { + MmsNamedVariableList variableList = + MmsDomain_getNamedVariableList(domain, itemName); + + if (variableList != NULL) + createGetNamedVariableListAttributesResponse(invokeId, response, variableList); + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + + } +#if (MMS_DYNAMIC_DATA_SETS == 1) + else if (request->present == ObjectName_PR_aaspecific) { + + char listName[65]; + + if (request->choice.aaspecific.size > 64) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); + goto exit_function; + } + + StringUtils_createStringFromBufferInBuffer(listName, request->choice.aaspecific.buf, + request->choice.aaspecific.size); + + MmsNamedVariableList varList = MmsServerConnection_getNamedVariableList(connection, listName); + + if (varList != NULL) + createGetNamedVariableListAttributesResponse(invokeId, response, varList); + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + } +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + else { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } + +exit_function: + + asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetNamedVariableListAttributesRequest, + request, 0); +} + +#endif /* (MMS_GET_DATA_SET_ATTRIBUTES == 1) */ + +#endif /* (MMS_DATA_SET_SERVICE == 1) */ diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c new file mode 100644 index 0000000..6ad75e4 --- /dev/null +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -0,0 +1,730 @@ +/* + * mms_read_service.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "mms_server_internal.h" +#include "mms_common_internal.h" +#include "mms_value_internal.h" + +#include "mms_access_result.h" + +#include "linked_list.h" + +#include "ber_encoder.h" + +/********************************************************************************************** + * MMS Read Service + *********************************************************************************************/ + +typedef struct sVarAccessSpec { + bool isNamedVariableList; + int specific; /* 0 - vmd, 1 - domain, 2 - association */ + + char* itemId; + char* domainId; +} VarAccessSpec; + +static MmsValue* +addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnection connection, + MmsDomain* domain, char* itemId) +{ + MmsValue* value = NULL; + + if (namedVariable->type == MMS_STRUCTURE) { + + value = mmsServer_getValue(connection->server, domain, itemId, connection); + + if (value != NULL) + goto exit_function; + else { + + int componentCount = namedVariable->typeSpec.structure.elementCount; + + value = MmsValue_createEmptyStructure(componentCount); + + value->deleteValue = 1; + + int i; + + for (i = 0; i < componentCount; i++) { + char newNameIdStr[65]; + + StringUtils_createStringInBuffer(newNameIdStr, 3, itemId, "$", + namedVariable->typeSpec.structure.elements[i]->name); + + MmsValue* element = + addNamedVariableValue(namedVariable->typeSpec.structure.elements[i], + connection, domain, newNameIdStr); + + if (element == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + + MmsValue_setElement(value, i, element); + } + } + } + else { + value = mmsServer_getValue(connection->server, domain, itemId, connection); + } + +exit_function: + return value; +} + +static void +addComplexValueToResultList(MmsVariableSpecification* namedVariable, + LinkedList typedValues, MmsServerConnection connection, + MmsDomain* domain, char* nameIdStr) +{ + + MmsValue* value = addNamedVariableValue(namedVariable, connection, domain, nameIdStr); + + if (value != NULL) + LinkedList_add(typedValues, value); +} + + +static void +appendValueToResultList(MmsValue* value, LinkedList values) +{ + + if (value != NULL ) + LinkedList_add(values, value); +} + +static void +appendErrorToResultList(LinkedList values, uint32_t errorCode) { + MmsValue* value = MmsValue_newDataAccessError((MmsDataAccessError) errorCode); + MmsValue_setDeletable(value); + appendValueToResultList(value, values); +} + +static void +deleteValueList(LinkedList values) +{ + LinkedList value = LinkedList_getNext(values); + + while (value != NULL ) { + MmsValue* typedValue = (MmsValue*) (value->data); + + MmsValue_deleteConditional(typedValue); + + value = LinkedList_getNext(value); + } + + LinkedList_destroyStatic(values); +} + +static bool +isAccessToArrayComponent(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess. + alternateAccess != NULL) + return true; + else + return false; +} + +static MmsValue* +getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, + MmsValue* structuredValue) +{ + 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; + + int elementCount = namedVariable->typeSpec.structure.elementCount; + + + MmsVariableSpecification* structSpec = namedVariable->typeSpec.array.elementTypeSpec; + + int i; + for (i = 0; i < elementCount; i++) { + if (strncmp (structSpec->typeSpec.structure.elements[i]->name, (char*) component.buf, + component.size) == 0) + { + MmsValue* value = MmsValue_getElement(structuredValue, i); + + retValue = value; + + goto exit_function; + } + } + } + +exit_function: + return retValue; +} + +static void +alternateArrayAccess(MmsServerConnection connection, + AlternateAccess_t* alternateAccess, MmsDomain* domain, + char* itemId, LinkedList values, + MmsVariableSpecification* namedVariable) +{ + if (mmsServer_isIndexAccess(alternateAccess)) + { + 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); + + if (arrayValue != NULL) { + + MmsValue* value = NULL; + + if (numberOfElements == 0) + if (isAccessToArrayComponent(alternateAccess)) { + if (namedVariable->typeSpec.array.elementTypeSpec->type == MMS_STRUCTURE) { + MmsValue* structValue = MmsValue_getElement(arrayValue, index); + + if (structValue != NULL) + value = getComponentOfArrayElement(alternateAccess, + namedVariable, structValue); + } + } + else + value = MmsValue_getElement(arrayValue, index); + else { + value = MmsValue_createEmptyArray(numberOfElements); + + MmsValue_setDeletable(value); + + int resultIndex = 0; + while (index < lowIndex + numberOfElements) { + MmsValue* elementValue = NULL; + + elementValue = MmsValue_getElement(arrayValue, index); + + if (!MmsValue_isDeletable(elementValue)) { + elementValue = MmsValue_clone(elementValue); + elementValue->deleteValue = 1; + } + + MmsValue_setElement(value, resultIndex, elementValue); + + index++; + resultIndex++; + } + } + + appendValueToResultList(value, values); + + } + else /* access error */ + appendErrorToResultList(values, 10 /* object-non-existant*/); + + } + else { // invalid access + if (DEBUG_MMS_SERVER) printf("Invalid alternate access\n"); + + appendErrorToResultList(values, 10 /* object-non-existant*/); + } +} + +static void +addNamedVariableToResultList(MmsVariableSpecification* namedVariable, MmsDomain* domain, char* nameIdStr, + LinkedList /**/ values, MmsServerConnection connection, AlternateAccess_t* alternateAccess) +{ + if (namedVariable != NULL) { + + if (DEBUG_MMS_SERVER) printf("MMS read: found named variable %s with search string %s\n", + namedVariable->name, nameIdStr); + + if (namedVariable->type == MMS_STRUCTURE) { + + MmsValue* value = mmsServer_getValue(connection->server, domain, nameIdStr, connection); + + if (value != NULL) { + appendValueToResultList(value, values); + } + else { + addComplexValueToResultList(namedVariable, + values, connection, domain, nameIdStr); + } + } + else if (namedVariable->type == MMS_ARRAY) { + + if (alternateAccess != NULL) { + alternateArrayAccess(connection, alternateAccess, domain, + nameIdStr, values, namedVariable); + } + else { //getCompleteArray + MmsValue* value = mmsServer_getValue(connection->server, domain, nameIdStr, connection); + appendValueToResultList(value, values); + } + } + else { + MmsValue* value = mmsServer_getValue(connection->server, domain, nameIdStr, connection); + + if (value == NULL) { + if (DEBUG_MMS_SERVER) + printf("MMS read: value of known variable is not found. Maybe illegal access to array element!\n"); + + appendErrorToResultList(values, 10 /* object-non-existant*/); + } + else + appendValueToResultList(value, values); + } + + } + else + appendErrorToResultList(values, 10 /* object-non-existant*/); +} + + +static bool +isSpecWithResult(ReadRequest_t* read) +{ + if (read->specificationWithResult != NULL) + if (*(read->specificationWithResult) != false) + return true; + + return false; +} + +static int +encodeVariableAccessSpecification(VarAccessSpec* accessSpec, uint8_t* buffer, int bufPos, bool encode) +{ + /* determine size */ + uint32_t varAccessSpecSize = 0; + + uint32_t itemIdLen = strlen(accessSpec->itemId); + + varAccessSpecSize += itemIdLen + BerEncoder_determineLengthSize(itemIdLen) + 1; + + if (accessSpec->domainId != NULL) { + uint32_t domainIdLen = strlen(accessSpec->domainId); + + varAccessSpecSize += domainIdLen + BerEncoder_determineLengthSize(domainIdLen) + 1; + } + + uint32_t specificityLength = varAccessSpecSize; + + varAccessSpecSize += 1 + BerEncoder_determineLengthSize(specificityLength); + + uint32_t variableListNameLength = varAccessSpecSize; + + varAccessSpecSize += 1 + BerEncoder_determineLengthSize(variableListNameLength); + + uint32_t varAccessSpecLength = varAccessSpecSize; + + varAccessSpecSize += 1 + BerEncoder_determineLengthSize(varAccessSpecLength); + + if (encode == false) { + bufPos = varAccessSpecSize; + goto exit_function; + } + + /* encode to buffer */ + bufPos = BerEncoder_encodeTL(0xa0, varAccessSpecLength, buffer, bufPos); + + if (accessSpec->isNamedVariableList == true) { + + bufPos = BerEncoder_encodeTL(0xa1, variableListNameLength, buffer, bufPos); + + if (accessSpec->specific == 0) { /* vmd-specific */ + bufPos = BerEncoder_encodeTL(0xa0, specificityLength, buffer, bufPos); + } + else if (accessSpec->specific == 1) { /* domain-specific */ + bufPos = BerEncoder_encodeTL(0xa1, specificityLength, buffer, bufPos); + + } + else { /* association-specific */ + bufPos = BerEncoder_encodeTL(0xa2, specificityLength, buffer, bufPos); + } + + + if (accessSpec->domainId != NULL) + bufPos = BerEncoder_encodeStringWithTag(0x1a, accessSpec->domainId, buffer, bufPos); + + bufPos = BerEncoder_encodeStringWithTag(0x1a, accessSpec->itemId, buffer, bufPos); + } + +exit_function: + return bufPos; +} + +static void +encodeReadResponse(MmsServerConnection connection, + uint32_t invokeId, ByteBuffer* response, LinkedList values, + VarAccessSpec* accessSpec) +{ + int i; + + int variableCount = LinkedList_size(values); + + uint32_t varAccessSpecSize = 0; + + if (accessSpec != NULL) { + varAccessSpecSize = encodeVariableAccessSpecification(accessSpec, NULL, 0, false); + } + + /* determine BER encoded message sizes */ + uint32_t accessResultSize = 0; + + /* iterate values list to determine encoded size */ + LinkedList value = LinkedList_getNext(values); + + for (i = 0; i < variableCount; i++) { + + MmsValue* data = (MmsValue*) value->data; + + accessResultSize += mmsServer_encodeAccessResult(data, NULL, 0, false); + + value = LinkedList_getNext(value); + } + + uint32_t listOfAccessResultsLength = 1 + + BerEncoder_determineLengthSize(accessResultSize) + + accessResultSize; + + uint32_t confirmedServiceResponseContentLength = listOfAccessResultsLength + varAccessSpecSize; + + uint32_t confirmedServiceResponseLength = 1 + + BerEncoder_determineLengthSize(confirmedServiceResponseContentLength) + + confirmedServiceResponseContentLength; + + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; + + uint32_t confirmedResponseContentSize = confirmedServiceResponseLength + invokeIdSize; + + uint32_t mmsPduSize = 1 + BerEncoder_determineLengthSize(confirmedResponseContentSize) + + confirmedResponseContentSize; + + /* Check if message would fit in the MMS PDU */ + if (mmsPduSize > connection->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS read: message to large! send error PDU!\n"); + + mmsServer_createConfirmedErrorPdu(invokeId, response, + MMS_ERROR_SERVICE_OTHER); + + goto exit_function; + } + + /* encode message */ + + uint8_t* buffer = response->buffer; + int bufPos = 0; + + /* confirmed response PDU */ + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponseContentSize, buffer, bufPos); + + /* invoke id */ + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + /* confirmed-service-response read */ + bufPos = BerEncoder_encodeTL(0xa4, confirmedServiceResponseContentLength, buffer, bufPos); + + /* encode variable access specification */ + if (accessSpec != NULL) + bufPos = encodeVariableAccessSpecification(accessSpec, buffer, bufPos, true); + + /* encode list of access results */ + bufPos = BerEncoder_encodeTL(0xa1, accessResultSize, buffer, bufPos); + + /* encode access results */ + value = LinkedList_getNext(values); + + for (i = 0; i < variableCount; i++) { + MmsValue* data = (MmsValue*) value->data; + + bufPos = mmsServer_encodeAccessResult(data, buffer, bufPos, true); + + value = LinkedList_getNext(value); + } + + response->size = bufPos; + + if (DEBUG_MMS_SERVER) + printf("MMS read: sent message for request with id %u (size = %i)\n", invokeId, bufPos); + +exit_function: + return; +} + +static void +handleReadListOfVariablesRequest( + MmsServerConnection connection, + ReadRequest_t* read, + uint32_t invokeId, + ByteBuffer* response) +{ + int variableCount = read->variableAccessSpecification.choice.listOfVariable.list.count; + + LinkedList /**/ values = LinkedList_create(); + + if (isSpecWithResult(read)) { /* add specification to result */ + // ignore - not required for IEC 61850 + } + + int i; + + for (i = 0; i < variableCount; i++) { + VariableSpecification_t varSpec = + read->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification; + + AlternateAccess_t* alternateAccess = + read->variableAccessSpecification.choice.listOfVariable.list.array[i]->alternateAccess; + + if (varSpec.present == VariableSpecification_PR_name) { + + if (varSpec.choice.name.present == ObjectName_PR_domainspecific) { + char domainIdStr[65]; + char nameIdStr[65]; + + mmsMsg_copyAsn1IdentifierToStringBuffer(varSpec.choice.name.choice.domainspecific.domainId, + domainIdStr, 65); + + mmsMsg_copyAsn1IdentifierToStringBuffer(varSpec.choice.name.choice.domainspecific.itemId, + nameIdStr, 65); + + MmsDomain* domain = MmsDevice_getDomain(MmsServer_getDevice(connection->server), domainIdStr); + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: READ domainId: (%s) nameId: (%s)\n", domainIdStr, nameIdStr); + + if (domain == NULL) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: READ domain %s not found!\n", domainIdStr); + + appendErrorToResultList(values, 10 /* object-non-existent*/); + } + else { + MmsVariableSpecification* namedVariable = MmsDomain_getNamedVariable(domain, nameIdStr); + + if (namedVariable == NULL) + appendErrorToResultList(values, 10 /* object-non-existent*/); + else + addNamedVariableToResultList(namedVariable, domain, nameIdStr, + values, connection, alternateAccess); + } + } +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + + else if (varSpec.choice.name.present == ObjectName_PR_vmdspecific) { + char nameIdStr[65]; + + mmsMsg_copyAsn1IdentifierToStringBuffer(varSpec.choice.name.choice.vmdspecific, nameIdStr, 65); + + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: READ vmd-specific nameId:%s\n", nameIdStr); + + MmsVariableSpecification* namedVariable = MmsDevice_getNamedVariable(MmsServer_getDevice(connection->server), nameIdStr); + + if (namedVariable == NULL) + appendErrorToResultList(values, 10 /* object-non-existent*/); + else + addNamedVariableToResultList(namedVariable, (MmsDomain*) MmsServer_getDevice(connection->server), nameIdStr, + values, connection, alternateAccess); + + } +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + + else { + appendErrorToResultList(values, 10 /* object-non-existent*/); + + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: READ object name type not supported!\n"); + } + } + else { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: READ varspec type not supported!\n"); + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + goto exit; + } + } + + encodeReadResponse(connection, invokeId, response, values, NULL); + +exit: + + deleteValueList(values); +} + +#if (MMS_DATA_SET_SERVICE == 1) + +static void +createNamedVariableListResponse(MmsServerConnection connection, MmsNamedVariableList namedList, + int invokeId, ByteBuffer* response, ReadRequest_t* read, VarAccessSpec* accessSpec) +{ + + LinkedList /**/ values = LinkedList_create(); + LinkedList variables = MmsNamedVariableList_getVariableList(namedList); + + int variableCount = LinkedList_size(variables); + + int i; + + LinkedList variable = LinkedList_getNext(variables); + + for (i = 0; i < variableCount; i++) { + + MmsNamedVariableListEntry variableListEntry = (MmsNamedVariableListEntry) variable->data; + + MmsDomain* variableDomain = MmsNamedVariableListEntry_getDomain(variableListEntry); + char* variableName = MmsNamedVariableListEntry_getVariableName(variableListEntry); + + MmsVariableSpecification* namedVariable = MmsDomain_getNamedVariable(variableDomain, + variableName); + + addNamedVariableToResultList(namedVariable, variableDomain, variableName, + values, connection, NULL); + + variable = LinkedList_getNext(variable); + } + + if (isSpecWithResult(read)) /* add specification to result */ + encodeReadResponse(connection, invokeId, response, values, accessSpec); + else + encodeReadResponse(connection, invokeId, response, values, NULL); + + deleteValueList(values); +} + +static void +handleReadNamedVariableListRequest( + MmsServerConnection connection, + ReadRequest_t* read, + int invokeId, + ByteBuffer* response) +{ + if (read->variableAccessSpecification.choice.variableListName.present == + ObjectName_PR_domainspecific) + { + char domainIdStr[65]; + char nameIdStr[65]; + + mmsMsg_copyAsn1IdentifierToStringBuffer(read->variableAccessSpecification.choice.variableListName.choice.domainspecific.domainId, + domainIdStr, 65); + + mmsMsg_copyAsn1IdentifierToStringBuffer(read->variableAccessSpecification.choice.variableListName.choice.domainspecific.itemId, + nameIdStr, 65); + + VarAccessSpec accessSpec; + + accessSpec.isNamedVariableList = true; + accessSpec.specific = 1; + accessSpec.domainId = domainIdStr; + accessSpec.itemId = nameIdStr; + + MmsDomain* domain = MmsDevice_getDomain(MmsServer_getDevice(connection->server), domainIdStr); + + if (domain == NULL) { + if (DEBUG_MMS_SERVER) printf("MMS read: domain %s not found!\n", domainIdStr); + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + } + else { + MmsNamedVariableList namedList = MmsDomain_getNamedVariableList(domain, nameIdStr); + + if (namedList != NULL) { + createNamedVariableListResponse(connection, namedList, invokeId, response, read, + &accessSpec); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS read: named variable list %s not found!\n", nameIdStr); + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + } + } + } +#if (MMS_DYNAMIC_DATA_SETS == 1) + else if (read->variableAccessSpecification.choice.variableListName.present == + ObjectName_PR_aaspecific) + { + char listName[65]; + + mmsMsg_copyAsn1IdentifierToStringBuffer(read->variableAccessSpecification.choice.variableListName.choice.aaspecific, + listName, 65); + + MmsNamedVariableList namedList = MmsServerConnection_getNamedVariableList(connection, listName); + + VarAccessSpec accessSpec; + + accessSpec.isNamedVariableList = true; + accessSpec.specific = 2; + accessSpec.domainId = NULL; + accessSpec.itemId = listName; + + if (namedList == NULL) + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + else + createNamedVariableListResponse(connection, namedList, invokeId, response, read, &accessSpec); + } +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); +} + +#endif /* MMS_DATA_SET_SERVICE == 1 */ + +void +mmsServer_handleReadRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + ReadRequest_t* request = 0; /* allow asn1c to allocate structure */ + + MmsPdu_t* mmsPdu = 0; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, CONFIG_MMS_MAXIMUM_PDU_SIZE); + + if (rval.code != RC_OK) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.read); + + if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) { + handleReadListOfVariablesRequest(connection, request, invokeId, response); + } +#if (MMS_DATA_SET_SERVICE == 1) + else if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName) { + handleReadNamedVariableListRequest(connection, request, invokeId, response); + } +#endif + else { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c new file mode 100644 index 0000000..f2ee46b --- /dev/null +++ b/src/mms/iso_mms/server/mms_server.c @@ -0,0 +1,319 @@ +/* + * mms_server.c + * + * Copyright 2013, 2014, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server.h" +#include "mms_server_connection.h" +#include "mms_value_cache.h" +#include "mms_server_internal.h" +#include "iso_server_private.h" + +static Map +createValueCaches(MmsDevice* device) +{ + Map valueCaches = Map_create(); + + int i; + for (i = 0; i < device->domainCount; i++) { + MmsValueCache valueCache = MmsValueCache_create(device->domains[i]); + Map_addEntry(valueCaches, device->domains[i], valueCache); + } + +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + MmsValueCache valueCache = MmsValueCache_create((MmsDomain*) device); + Map_addEntry(valueCaches, (MmsDomain*) device, valueCache); +#endif + + return valueCaches; +} + +MmsServer +MmsServer_create(IsoServer isoServer, MmsDevice* device) +{ + MmsServer self = (MmsServer) GLOBAL_MALLOC(sizeof(struct sMmsServer)); + + memset(self, 0, sizeof(struct sMmsServer)); + + self->isoServer = isoServer; + self->device = device; + self->openConnections = Map_create(); + self->valueCaches = createValueCaches(device); + self->isLocked = false; + + self->reportBuffer = ByteBuffer_create(NULL, CONFIG_MMS_MAXIMUM_PDU_SIZE); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->modelMutex = Semaphore_create(1); + + IsoServer_setUserLock(isoServer, self->modelMutex); +#endif + + return self; +} + +void +MmsServer_lockModel(MmsServer self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->modelMutex); +#endif +} + +void +MmsServer_unlockModel(MmsServer self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->modelMutex); +#endif +} + +void +MmsServer_installReadHandler(MmsServer self, MmsReadVariableHandler readHandler, void* parameter) +{ + self->readHandler = readHandler; + self->readHandlerParameter = parameter; +} + +void +MmsServer_installReadAccessHandler(MmsServer self, MmsReadAccessHandler readAccessHandler, void* parameter) +{ + self->readAccessHandler = readAccessHandler; + self->readAccessHandlerParameter = parameter; +} + +void +MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler writeHandler, void* parameter) +{ + self->writeHandler = writeHandler; + self->writeHandlerParameter = parameter; +} + +void +MmsServer_installConnectionHandler(MmsServer self, MmsConnectionHandler connectionHandler, void* parameter) +{ + self->connectionHandler = connectionHandler; + self->connectionHandlerParameter = parameter; +} + +void +MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableListChangedHandler handler, void* parameter) +{ + self->variableListChangedHandler = handler; + self->variableListChangedHandlerParameter = parameter; +} + +void +MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter) +{ + IsoServer_setAuthenticator(self->isoServer, authenticator, authenticatorParameter); +} + + +static void +closeConnection(void* con) +{ + MmsServerConnection connection = (MmsServerConnection) con; + + MmsServerConnection_destroy(connection); +} + +static void +deleteSingleCache(MmsValueCache cache) +{ + MmsValueCache_destroy(cache); +} + +void +MmsServer_destroy(MmsServer self) +{ + Map_deleteDeep(self->openConnections, false, closeConnection); + Map_deleteDeep(self->valueCaches, false, (void (*) (void*)) deleteSingleCache); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->modelMutex); +#endif + + ByteBuffer_destroy(self->reportBuffer); + + GLOBAL_FREEMEM(self); +} + +MmsValue* +MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, char* itemId) +{ + MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); + + if (cache != NULL) + return MmsValueCache_lookupValue(cache, itemId); + + return NULL ; +} + +void +MmsServer_insertIntoCache(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value) +{ + MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain); + + if (cache != NULL) { + MmsValueCache_insertValue(cache, itemId, value); + } +} + +MmsDataAccessError +mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, + MmsServerConnection connection) +{ + MmsDataAccessError indication; + + if (self->writeHandler != NULL) { + indication = self->writeHandler(self->writeHandlerParameter, domain, + itemId, value, connection); + } else { + MmsValue* cachedValue; + + if (domain == NULL) + domain = (MmsDomain*) self->device; + + cachedValue = MmsServer_getValueFromCache(self, domain, itemId); + + if (cachedValue != NULL) { + MmsValue_update(cachedValue, value); + indication = DATA_ACCESS_ERROR_SUCCESS; + } else + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } + + return indication; +} + + +MmsValue* +mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection) +{ + MmsValue* value = NULL; + + if (self->readAccessHandler != NULL) { + MmsDataAccessError accessError = + self->readAccessHandler(self->readAccessHandlerParameter, domain, itemId, connection); + + if (accessError != DATA_ACCESS_ERROR_SUCCESS) { + value = MmsValue_newDataAccessError(accessError); + MmsValue_setDeletable(value); + goto exit_function; + } + } + + value = MmsServer_getValueFromCache(self, domain, itemId); + + if (value == NULL) + if (self->readHandler != NULL) + value = self->readHandler(self->readHandlerParameter, domain, + itemId, connection); + +exit_function: + return value; +} + + +MmsDevice* +MmsServer_getDevice(MmsServer self) +{ + return self->device; +} + +inline void +MmsServer_setDevice(MmsServer server, MmsDevice* device) +{ + server->device = device; +} + +static void /* will be called by ISO server stack */ +isoConnectionIndicationHandler(IsoConnectionIndication indication, + void* parameter, IsoConnection connection) +{ + MmsServer mmsServer = (MmsServer) parameter; + + if (indication == ISO_CONNECTION_OPENED) { + MmsServerConnection mmsCon = MmsServerConnection_init(0, mmsServer, connection); + + Map_addEntry(mmsServer->openConnections, connection, mmsCon); + + if (mmsServer->connectionHandler != NULL) + mmsServer->connectionHandler(mmsServer->connectionHandlerParameter, + mmsCon, MMS_SERVER_NEW_CONNECTION); + } + else if (indication == ISO_CONNECTION_CLOSED) { + MmsServerConnection mmsCon = (MmsServerConnection) + Map_removeEntry(mmsServer->openConnections, connection, false); + + if (mmsServer->connectionHandler != NULL) + mmsServer->connectionHandler(mmsServer->connectionHandlerParameter, + mmsCon, MMS_SERVER_CONNECTION_CLOSED); + + if (mmsCon != NULL) + MmsServerConnection_destroy(mmsCon); + } +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +MmsServer_startListening(MmsServer server, int tcpPort) +{ + IsoServer_setConnectionHandler(server->isoServer, isoConnectionIndicationHandler, (void*) server); + IsoServer_setTcpPort(server->isoServer, tcpPort); + IsoServer_startListening(server->isoServer); +} + +void +MmsServer_stopListening(MmsServer server) +{ + IsoServer_stopListening(server->isoServer); +} +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1)*/ + +void +MmsServer_startListeningThreadless(MmsServer self, int tcpPort) +{ + IsoServer_setConnectionHandler(self->isoServer, isoConnectionIndicationHandler, (void*) self); + IsoServer_setTcpPort(self->isoServer, tcpPort); + IsoServer_startListeningThreadless(self->isoServer); +} + +int +MmsServer_waitReady(MmsServer self, unsigned int timeoutMs) +{ + return IsoServer_waitReady(self->isoServer, timeoutMs); +} + +void +MmsServer_handleIncomingMessages(MmsServer self) +{ + IsoServer_processIncomingMessages(self->isoServer); +} + +void +MmsServer_stopListeningThreadless(MmsServer self) +{ + IsoServer_stopListeningThreadless(self->isoServer); +} + diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c new file mode 100644 index 0000000..f5a16e4 --- /dev/null +++ b/src/mms/iso_mms/server/mms_server_common.c @@ -0,0 +1,227 @@ +/* + * mms_server_common.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +/* write_out function required for ASN.1 encoding */ +int +mmsServer_write_out(const void *buffer, size_t size, void *app_key) +{ + ByteBuffer* writeBuffer = (ByteBuffer*) app_key; + return ByteBuffer_append(writeBuffer, (uint8_t*) buffer, size); +} + +MmsPdu_t* +mmsServer_createConfirmedResponse(uint32_t invokeId) +{ + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); + + mmsPdu->present = MmsPdu_PR_confirmedResponsePdu; + + asn_long2INTEGER(&(mmsPdu->choice.confirmedResponsePdu.invokeID), + invokeId); + + return mmsPdu; +} + + +void +mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsError errorType) +{ + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); + mmsPdu->present = MmsPdu_PR_confirmedErrorPDU; + + asn_long2INTEGER(&(mmsPdu->choice.confirmedErrorPDU.invokeID), + invokeId); + + if (errorType == MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_access; + + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__access_objectnonexistent); + } + else if (errorType == MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_access; + + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__access_objectaccessdenied); + } + else if (errorType == MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_access; + + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__access_objectaccessunsupported); + } + else if (errorType == MMS_ERROR_SERVICE_OTHER) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_service; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__service_other); + } + else if (errorType == MMS_ERROR_DEFINITION_OTHER) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_definition; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__definition_other); + } + else if (errorType == MMS_ERROR_DEFINITION_OBJECT_EXISTS) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_definition; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__definition_objectexists); + } + else if (errorType == MMS_ERROR_DEFINITION_OBJECT_UNDEFINED) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_definition; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__definition_objectundefined); + } + else if (errorType == MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_definition; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__definition_typeunsupported); + } + else if (errorType == MMS_ERROR_FILE_FILE_NON_EXISTENT) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_file; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__file_filenonexistent); + } + else if (errorType == MMS_ERROR_FILE_OTHER) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_file; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__file_other); + } + else if (errorType == MMS_ERROR_RESOURCE_OTHER) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_resource; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__resource_other); + } + else if (errorType == MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_resource; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__resource_capabilityunavailable); + } + + der_encode(&asn_DEF_MmsPdu, mmsPdu, + mmsServer_write_out, (void*) response); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +int +mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) { + if ((alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present + == AlternateAccessSelection__selectAccess_PR_index) || + (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present + == AlternateAccessSelection__selectAccess_PR_indexRange)) + { + return 1; + } + else + return 0; + } + else + return 0; +} + +int +mmsServer_getLowIndex(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present + == AlternateAccessSelection__selectAccess_PR_index) + { + long index; + asn_INTEGER2long( + &alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index, + &index); + + return (int) index; + } + + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present + == AlternateAccessSelection__selectAccess_PR_indexRange) + { + long index; + asn_INTEGER2long( + &alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex, + &index); + + return (int) index; + } + + return -1; +} + +int +mmsServer_getNumberOfElements(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present + == AlternateAccessSelection__selectAccess_PR_indexRange) + { + long number; + + asn_INTEGER2long( + &alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements, + &number); + + return (int) number; + } + + return 0; +} + +void +mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListName) +{ + LinkedList previousElement = namedVariableLists; + LinkedList element = LinkedList_getNext(namedVariableLists); + + while (element != NULL ) { + MmsNamedVariableList varList = (MmsNamedVariableList) element->data; + + if (strcmp(MmsNamedVariableList_getName(varList), variableListName) + == 0) { + previousElement->next = element->next; + GLOBAL_FREEMEM(element); + MmsNamedVariableList_destroy(varList); + + break; + } + + previousElement = element; + element = LinkedList_getNext(element); + } +} + + diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c new file mode 100644 index 0000000..60bc654 --- /dev/null +++ b/src/mms/iso_mms/server/mms_server_connection.c @@ -0,0 +1,403 @@ +/* + * mms_server_connection.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + * + * + * MMS client connection handling code for libiec61850. + * + * Handles a MMS client connection. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" +#include "iso_server.h" +#include "ber_encoder.h" +#include "ber_decode.h" + +/********************************************************************************************** + * MMS Common support functions + *********************************************************************************************/ + +void +mmsServer_writeMmsRejectPdu(uint32_t* invokeId, int reason, ByteBuffer* response) { + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); + + mmsPdu->present = MmsPdu_PR_rejectPDU; + + if (invokeId != NULL) { + mmsPdu->choice.rejectPDU.originalInvokeID = (Unsigned32_t*) GLOBAL_CALLOC(1, sizeof(Unsigned32_t)); + asn_long2INTEGER(mmsPdu->choice.rejectPDU.originalInvokeID, *invokeId); + } + + if (reason == MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE) { + mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_confirmedRequestPDU; + mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU = + RejectPDU__rejectReason__confirmedRequestPDU_unrecognizedService; + } + else if(reason == MMS_ERROR_REJECT_UNKNOWN_PDU_TYPE) { + mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_pduError; + asn_long2INTEGER(&mmsPdu->choice.rejectPDU.rejectReason.choice.pduError, + RejectPDU__rejectReason__pduError_unknownPduType); + } + else if (reason == MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT) { + mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_confirmedRequestPDU; + mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU = + RejectPDU__rejectReason__confirmedRequestPDU_invalidArgument; + } + else if (reason == MMS_ERROR_REJECT_INVALID_PDU) { + mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_pduError; + mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU = + RejectPDU__rejectReason__pduError_invalidPdu; + } + else { + mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_confirmedRequestPDU; + mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU = + RejectPDU__rejectReason__confirmedRequestPDU_other; + } + + der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +/********************************************************************************************** + * MMS General service handling functions + *********************************************************************************************/ + +static void +handleConfirmedRequestPdu( + MmsServerConnection self, + uint8_t* buffer, int bufPos, int maxBufPos, + ByteBuffer* response) +{ + uint32_t invokeId = 0; + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bool extendedTag = false; + + if ((tag & 0x1f) == 0x1f) { + extendedTag = true; + tag = buffer[bufPos++]; + } + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + return; + } + + if (DEBUG_MMS_SERVER) printf("tag %02x extended tag: %i size: %i\n", tag, extendedTag, length); + + if (extendedTag) { + switch(tag) { + +#if (MMS_FILE_SERVICE == 1) + case 0x48: /* file-open-request */ + mmsServer_handleFileOpenRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; + + case 0x49: /* file-read-request */ + mmsServer_handleFileReadRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; + + case 0x4a: /* file-close-request */ + mmsServer_handleFileCloseRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; + + case 0x4b: /* file-rename-request */ + mmsServer_handleFileRenameRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; + + case 0x4c: /* file-delete-request */ + mmsServer_handleFileDeleteRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; + + case 0x4d: /* file-directory-request */ + mmsServer_handleFileDirectoryRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; +#endif /* MMS_FILE_SERVICE == 1 */ + + default: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + return; + break; + } + } + else { + switch(tag) { + case 0x02: /* invoke Id */ + invokeId = BerDecoder_decodeUint32(buffer, length, bufPos); + if (DEBUG_MMS_SERVER) printf("invokeId: %i\n", invokeId); + self->lastInvokeId = invokeId; + break; + +#if (MMS_STATUS_SERVICE == 1) + case 0x80: /* status-request */ + mmsServer_handleStatusRequest(self, buffer, bufPos, invokeId, response); + break; +#endif /* MMS_STATUS_SERVICE == 1 */ + +#if (MMS_GET_NAME_LIST == 1) + case 0xa1: /* get-name-list-request */ + mmsServer_handleGetNameListRequest(self, buffer, bufPos, bufPos + length, + invokeId, response); + break; +#endif /* (MMS_GET_NAME_LIST == 1) */ + +#if (MMS_IDENTIFY_SERVICE == 1) + case 0x82: /* identify */ + mmsServer_handleIdentifyRequest(self, invokeId, response); + break; +#endif /* MMS_IDENTIFY_SERVICE == 1 */ + + case 0xa4: /* read-request */ + mmsServer_handleReadRequest(self, buffer, bufPos, bufPos + length, + invokeId, response); + break; + +#if (MMS_WRITE_SERVICE == 1) + case 0xa5: /* write-request */ + mmsServer_handleWriteRequest(self, buffer, bufPos, bufPos + length, + invokeId, response); + break; +#endif /* (MMS_WRITE_SERVICE == 1) */ + +#if (MMS_GET_VARIABLE_ACCESS_ATTRIBUTES == 1) + case 0xa6: /* get-variable-access-attributes-request */ + mmsServer_handleGetVariableAccessAttributesRequest(self, + buffer, bufPos, bufPos + length, + invokeId, response); + break; +#endif /* MMS_GET_VARIABLE_ACCESS_ATTRIBUTES == 1 */ + + +#if (MMS_DYNAMIC_DATA_SETS == 1) + case 0xab: /* define-named-variable-list */ + mmsServer_handleDefineNamedVariableListRequest(self, + buffer, bufPos, bufPos + length, + invokeId, response); + break; +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + + +#if (MMS_GET_DATA_SET_ATTRIBUTES == 1) + case 0xac: /* get-named-variable-list-attributes-request */ + mmsServer_handleGetNamedVariableListAttributesRequest(self, + buffer, bufPos, bufPos + length, + invokeId, response); + break; +#endif /* (MMS_GET_DATA_SET_ATTRIBUTES == 1) */ + +#if (MMS_DYNAMIC_DATA_SETS == 1) + case 0xad: /* delete-named-variable-list-request */ + mmsServer_handleDeleteNamedVariableListRequest(self, + buffer, bufPos, bufPos + length, + invokeId, response); + break; +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + + default: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + return; + break; + } + } + + bufPos += length; + } +} + +MmsIndication +MmsServerConnection_parseMessage(MmsServerConnection self, ByteBuffer* message, ByteBuffer* response) +{ + MmsIndication retVal; + + uint8_t* buffer = message->buffer; + + if (message->size < 2) + return MMS_ERROR; + + int bufPos = 0; + + uint8_t pduType = buffer[bufPos++]; + int pduLength; + + bufPos = BerDecoder_decodeLength(buffer, &pduLength, bufPos, message->size); + + if (bufPos < 0) + return MMS_ERROR; + + if (DEBUG_MMS_SERVER) + printf("mms_server: recvd MMS-PDU type: %02x size: %i\n", pduType, pduLength); + + switch (pduType) { + case 0xa8: /* Initiate request PDU */ + mmsServer_handleInitiateRequest(self, buffer, bufPos, bufPos + pduLength, response); + retVal = MMS_INITIATE; + break; + case 0xa0: /* Confirmed request PDU */ + handleConfirmedRequestPdu(self, buffer, bufPos, bufPos + pduLength, response); + retVal = MMS_CONFIRMED_REQUEST; + break; + case 0x8b: /* Conclude request PDU */ + mmsServer_writeConcludeResponsePdu(response); + retVal = MMS_CONCLUDE; + break; + case 0xa4: /* Reject PDU - silently ignore */ + if (DEBUG) printf("received reject PDU!\n"); + retVal = MMS_OK; + break; + default: + mmsServer_writeMmsRejectPdu(NULL, MMS_ERROR_REJECT_UNKNOWN_PDU_TYPE, response); + retVal = MMS_ERROR; + break; + } + + return retVal; +} + +static void /* will be called by IsoConnection */ +messageReceived(void* parameter, ByteBuffer* message, ByteBuffer* response) +{ + MmsServerConnection self = (MmsServerConnection) parameter; + + MmsServerConnection_parseMessage(self, message, response); +} + +/********************************************************************************************** + * MMS server connection public API functions + *********************************************************************************************/ + +MmsServerConnection +MmsServerConnection_init(MmsServerConnection connection, MmsServer server, IsoConnection isoCon) +{ + MmsServerConnection self; + + if (connection == NULL) + self = (MmsServerConnection) GLOBAL_CALLOC(1, sizeof(struct sMmsServerConnection)); + else + self = connection; + + self->maxServOutstandingCalled = 0; + self->maxServOutstandingCalling = 0; + self->maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE; + self->dataStructureNestingLevel = 0; + self->server = server; + self->isoConnection = isoCon; + +#if (MMS_DYNAMIC_DATA_SETS == 1) + self->namedVariableLists = LinkedList_create(); +#endif + + IsoConnection_installListener(isoCon, messageReceived, (void*) self); + + return self; +} + +void +MmsServerConnection_destroy(MmsServerConnection self) +{ + +#if (MMS_FILE_SERVICE == 1) + int frsmIndex = 0; + + for (frsmIndex = 0; frsmIndex < CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION; frsmIndex++) + if (self->frsms[frsmIndex].fileHandle != NULL) + FileSystem_closeFile(self->frsms[frsmIndex].fileHandle); +#endif + +#if (MMS_DYNAMIC_DATA_SETS == 1) + LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy); +#endif + + GLOBAL_FREEMEM(self); +} + +#if (MMS_DYNAMIC_DATA_SETS == 1) +bool +MmsServerConnection_addNamedVariableList(MmsServerConnection self, MmsNamedVariableList variableList) +{ + //TODO check if operation is allowed! + + LinkedList_add(self->namedVariableLists, variableList); + + return true; +} + +void +MmsServerConnection_deleteNamedVariableList(MmsServerConnection self, char* listName) +{ + mmsServer_deleteVariableList(self->namedVariableLists, listName); +} + +MmsNamedVariableList +MmsServerConnection_getNamedVariableList(MmsServerConnection self, const char* variableListName) +{ + //TODO remove code duplication - similar to MmsDomain_getNamedVariableList ! + MmsNamedVariableList variableList = NULL; + + LinkedList element = LinkedList_getNext(self->namedVariableLists); + + while (element != NULL) { + MmsNamedVariableList varList = (MmsNamedVariableList) element->data; + + if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { + variableList = varList; + break; + } + + element = LinkedList_getNext(element); + } + + return variableList; +} +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + + +char* +MmsServerConnection_getClientAddress(MmsServerConnection self) +{ + return IsoConnection_getPeerAddress(self->isoConnection); +} + +IsoConnection +MmsServerConnection_getIsoConnection(MmsServerConnection self) +{ + return self->isoConnection; +} + +#if (MMS_DYNAMIC_DATA_SETS == 1) +LinkedList +MmsServerConnection_getNamedVariableLists(MmsServerConnection self) +{ + return self->namedVariableLists; +} +#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ + +uint32_t +MmsServerConnection_getLastInvokeId(MmsServerConnection self) +{ + return self->lastInvokeId; +} diff --git a/src/mms/iso_mms/server/mms_status_service.c b/src/mms/iso_mms/server/mms_status_service.c new file mode 100644 index 0000000..d0d8f14 --- /dev/null +++ b/src/mms/iso_mms/server/mms_status_service.c @@ -0,0 +1,103 @@ +/* + * mms_status_service.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +#if MMS_STATUS_SERVICE == 1 + +void +mmsServer_handleStatusRequest( + MmsServerConnection connection, + uint8_t* requestBuffer, + int bufPos, + int invokeId, + ByteBuffer* response) +{ + /* check for extended derivation */ + bool extendedDerivation = BerDecoder_decodeBoolean(requestBuffer, bufPos); + + if (DEBUG_MMS_SERVER) + printf("mms_status_service.c: statusRequest (extendedDerivation: %i)\n", extendedDerivation); + + bufPos = 0; + uint8_t* buffer = response->buffer; + + uint32_t invokeIdLength = BerEncoder_UInt32determineEncodedSize(invokeId); + + MmsServer mmsServer = connection->server; + + /* Invoke user provided callback */ + if (mmsServer->statusRequestListener != NULL) + mmsServer->statusRequestListener(mmsServer->statusRequestListenerParameter, mmsServer, connection, extendedDerivation); + + uint32_t vmdPhysicalStatusLength = BerEncoder_UInt32determineEncodedSize((uint32_t) mmsServer->vmdPhysicalStatus); + uint32_t vmdLogicalStatusLength = BerEncoder_UInt32determineEncodedSize((uint32_t) mmsServer->vmdLogicalStatus); + + uint32_t statusLength = 2 + vmdPhysicalStatusLength + 2 + vmdLogicalStatusLength; + + uint32_t statusResponseLength = invokeIdLength + 2 + 1 + BerEncoder_determineLengthSize(statusLength) + statusLength; + + /* Status response pdu */ + bufPos = BerEncoder_encodeTL(0xa1, statusResponseLength, buffer, bufPos); + + /* invokeId */ + bufPos = BerEncoder_encodeTL(0x02, invokeIdLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0xa0, statusLength, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, vmdLogicalStatusLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) mmsServer->vmdLogicalStatus, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x81, vmdPhysicalStatusLength, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32((uint32_t) mmsServer->vmdPhysicalStatus, buffer, bufPos); + + response->size = bufPos; +} + +void +MmsServer_setVMDStatus(MmsServer self, int vmdLogicalStatus, int vmdPhysicalStatus) +{ + self->vmdLogicalStatus = vmdLogicalStatus; + self->vmdPhysicalStatus = vmdPhysicalStatus; +} + +int +MmsServer_getVMDLogicalStatus(MmsServer self) +{ + return self->vmdLogicalStatus; +} + +int +MmsServer_getVMDPhysicalStatus(MmsServer self) +{ + return self->vmdPhysicalStatus; +} + +void +MmsServer_setStatusRequestListener(MmsServer self, MmsStatusRequestListener listener, void* parameter) +{ + self->statusRequestListener = listener; + self->statusRequestListenerParameter = parameter; +} + +#endif /* MMS_STATUS_SERVICE == 1 */ diff --git a/src/mms/iso_mms/server/mms_value_cache.c b/src/mms/iso_mms/server/mms_value_cache.c new file mode 100644 index 0000000..03be3f7 --- /dev/null +++ b/src/mms/iso_mms/server/mms_value_cache.c @@ -0,0 +1,160 @@ +/* + * mms_value_cache.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_value_cache.h" +#include "string_map.h" +#include "stack_config.h" + +struct sMmsValueCache { + MmsDomain* domain; + Map map; +}; + +typedef struct sMmsValueCacheEntry { + MmsValue* value; + MmsVariableSpecification* typeSpec; +} MmsValueCacheEntry; + +MmsValueCache +MmsValueCache_create(MmsDomain* domain) +{ + MmsValueCache self = (MmsValueCache) GLOBAL_CALLOC(1, sizeof(struct sMmsValueCache)); + + self->domain = domain; + + self->map = StringMap_create(); + + return self; +} + +void +MmsValueCache_insertValue(MmsValueCache self, char* itemId, MmsValue* value) +{ + MmsVariableSpecification* typeSpec = MmsDomain_getNamedVariable(self->domain, itemId); + + if (typeSpec != NULL) { + MmsValueCacheEntry* cacheEntry = (MmsValueCacheEntry*) GLOBAL_MALLOC(sizeof(MmsValueCacheEntry)); + + cacheEntry->value = value; + cacheEntry->typeSpec = typeSpec; + + Map_addEntry(self->map, copyString(itemId), cacheEntry); + } + else + if (DEBUG) printf("Cannot insert value into cache %s : no typeSpec found!\n", itemId); +} + +static char* +getParentSubString(char* itemId) +{ + int len = strlen(itemId); + + char* strPos = itemId + len; + + while (--strPos > itemId) { + if (*strPos == '$') { + *strPos = 0; + return itemId; + } + } + + return NULL; +} + +static char* +getChildSubString (char* itemId, char* parentId) +{ + return itemId + strlen(parentId) + 1; +} + +static MmsValue* +searchCacheForValue(MmsValueCache self, char* itemId, char* parentId) +{ + MmsValueCacheEntry* cacheEntry; + MmsValue* value = NULL; + + cacheEntry = (MmsValueCacheEntry*) Map_getEntry(self->map, parentId); + + if (cacheEntry == NULL) { + char* parentItemId = getParentSubString(parentId); + + if (parentItemId != NULL) { + value = searchCacheForValue(self, itemId, parentItemId); + } + } + else { + + char* childId = getChildSubString(itemId, parentId); + + MmsVariableSpecification* typeSpec = MmsDomain_getNamedVariable(self->domain, parentId); + value = MmsVariableSpecification_getChildValue(typeSpec, cacheEntry->value, childId); + } + + return value; +} + +MmsValue* +MmsValueCache_lookupValue(MmsValueCache self, char* itemId) +{ + // get value for first matching key substring! + // Then iterate the value for the exact value. + + MmsValue* value = NULL; + + MmsValueCacheEntry* cacheEntry; + + cacheEntry = (MmsValueCacheEntry*) Map_getEntry(self->map, itemId); + + if (cacheEntry == NULL) { + char* itemIdCopy = copyString(itemId); + char* parentItemId = getParentSubString(itemIdCopy); + + if (parentItemId != NULL) { + value = searchCacheForValue(self, itemId, parentItemId); + } + + GLOBAL_FREEMEM(itemIdCopy); + } + + if (cacheEntry != NULL) + return cacheEntry->value; + else + return value; +} + +static void +cacheEntryDelete(MmsValueCacheEntry* entry) +{ + if (entry != NULL) { + MmsValue_delete(entry->value); + GLOBAL_FREEMEM(entry); + } +} + +void +MmsValueCache_destroy(MmsValueCache self) +{ + Map_deleteDeep(self->map, true, (void (*) (void*)) cacheEntryDelete); + GLOBAL_FREEMEM(self); +} diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c new file mode 100644 index 0000000..291cf14 --- /dev/null +++ b/src/mms/iso_mms/server/mms_write_service.c @@ -0,0 +1,282 @@ +/* + * mms_write_service.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" +#include "mms_common_internal.h" +#include "mms_types.h" + +#if (MMS_WRITE_SERVICE == 1) + +#define CONFIG_MMS_WRITE_SERVICE_MAX_NUMBER_OF_WRITE_ITEMS 100 + +/********************************************************************************************** + * MMS Write Service + *********************************************************************************************/ + +int +mmsServer_createMmsWriteResponse(MmsServerConnection connection, + int invokeId, ByteBuffer* response, int numberOfItems, MmsDataAccessError* accessResults) +{ + MmsPdu_t* mmsPdu = mmsServer_createConfirmedResponse(invokeId); + + mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present = + ConfirmedServiceResponse_PR_write; + + WriteResponse_t* writeResponse = + &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.write); + + writeResponse->list.count = numberOfItems; + writeResponse->list.size = numberOfItems; + writeResponse->list.array = (struct WriteResponse__Member**) GLOBAL_CALLOC(numberOfItems, + sizeof(struct WriteResponse__Member*)); + + int i; + + for (i = 0; i < numberOfItems; i++) { + writeResponse->list.array[i] = (struct WriteResponse__Member*) GLOBAL_CALLOC(1, sizeof(struct WriteResponse__Member)); + + if (accessResults[i] == DATA_ACCESS_ERROR_SUCCESS) + writeResponse->list.array[i]->present = WriteResponse__Member_PR_success; + else { + writeResponse->list.array[i]->present = WriteResponse__Member_PR_failure; + asn_long2INTEGER(&writeResponse->list.array[i]->choice.failure, (long) accessResults[i]); + } + } + + der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return 0; +} + + +void +MmsServerConnection_sendWriteResponse(MmsServerConnection self, uint32_t invokeId, MmsDataAccessError indication, bool handlerMode) +{ + ByteBuffer* response = ByteBuffer_create(NULL, self->maxPduSize); + + mmsServer_createMmsWriteResponse(self, invokeId, response, 1, &indication); + + IsoConnection_sendMessage(self->isoConnection, response, handlerMode); + + ByteBuffer_destroy(response); +} + +void +mmsServer_handleWriteRequest( + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + WriteRequest_t* writeRequest = 0; + + MmsPdu_t* mmsPdu = 0; + + asn_dec_rval_t rval; /* Decoder return value */ + + rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, CONFIG_MMS_MAXIMUM_PDU_SIZE); + + if (rval.code != RC_OK) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + writeRequest = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.write); + + int numberOfWriteItems = writeRequest->variableAccessSpecification.choice.listOfVariable.list.count; + + if (numberOfWriteItems < 1) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + } + + if (numberOfWriteItems > CONFIG_MMS_WRITE_SERVICE_MAX_NUMBER_OF_WRITE_ITEMS) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_OTHER, response); + return; + } + + if (writeRequest->listOfData.list.count != numberOfWriteItems) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + } + + MmsDataAccessError accessResults[CONFIG_MMS_WRITE_SERVICE_MAX_NUMBER_OF_WRITE_ITEMS * sizeof(MmsDataAccessError)]; + + bool sendResponse = true; + + int i; + + for (i = 0; i < numberOfWriteItems; i++) { + ListOfVariableSeq_t* varSpec = + writeRequest->variableAccessSpecification.choice.listOfVariable.list.array[i]; + + if (varSpec->variableSpecification.present != VariableSpecification_PR_name) { + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; + continue; + } + + MmsVariableSpecification* variable; + + MmsDevice* device = MmsServer_getDevice(connection->server); + + MmsDomain* domain = NULL; + + char* nameIdStr; + + if (varSpec->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) { + Identifier_t domainId = varSpec->variableSpecification.choice.name.choice.domainspecific.domainId; + char* domainIdStr = createStringFromBuffer(domainId.buf, domainId.size); + + domain = MmsDevice_getDomain(device, domainIdStr); + + GLOBAL_FREEMEM(domainIdStr); + + if (domain == NULL) { + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + continue; + } + + Identifier_t nameId = varSpec->variableSpecification.choice.name.choice.domainspecific.itemId; + nameIdStr = createStringFromBuffer(nameId.buf, nameId.size); + + variable = MmsDomain_getNamedVariable(domain, nameIdStr); + } + +#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) + else if (varSpec->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) { + + Identifier_t nameId = varSpec->variableSpecification.choice.name.choice.vmdspecific; + nameIdStr = createStringFromBuffer(nameId.buf, nameId.size); + + variable = MmsDevice_getNamedVariable(device, nameIdStr); + } +#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + + else { + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; + continue; + } + + if (variable == NULL) { + GLOBAL_FREEMEM(nameIdStr); + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + continue; + } + + AlternateAccess_t* alternateAccess = varSpec->alternateAccess; + + if (alternateAccess != NULL) { + if (variable->type != MMS_ARRAY) { + GLOBAL_FREEMEM(nameIdStr); + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + continue; + } + + if (!mmsServer_isIndexAccess(alternateAccess)) { + GLOBAL_FREEMEM(nameIdStr); + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; + continue; + } + } + + Data_t* dataElement = writeRequest->listOfData.list.array[i]; + + MmsValue* value = mmsMsg_parseDataElement(dataElement); + + if (value == NULL) { + GLOBAL_FREEMEM(nameIdStr); + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + continue; + } + + /* Check for correct type */ + if (MmsValue_getType(value) != MmsVariableSpecification_getType(variable)) { + GLOBAL_FREEMEM(nameIdStr); + MmsValue_delete(value); + accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + continue; + } + + if (alternateAccess != NULL) { + + if (domain != NULL) + domain = (MmsDomain*) device; + + MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); + + if (cachedArray == NULL) { + GLOBAL_FREEMEM(nameIdStr); + MmsValue_delete(value); + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + continue; + } + + int index = mmsServer_getLowIndex(alternateAccess); + + MmsValue* elementValue = MmsValue_getElement(cachedArray, index); + + if (elementValue == NULL) { + GLOBAL_FREEMEM(nameIdStr); + MmsValue_delete(value); + accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; + continue; + } + + if (MmsValue_update(elementValue, value) == false) { + GLOBAL_FREEMEM(nameIdStr); + MmsValue_delete(value); + accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + continue; + } + + GLOBAL_FREEMEM(nameIdStr); + MmsValue_delete(value); + accessResults[i] = DATA_ACCESS_ERROR_SUCCESS; + continue; + + } + + MmsDataAccessError valueIndication = + mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); + + if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE) + sendResponse = false; + + accessResults[i] = valueIndication; + + MmsValue_delete(value); + + GLOBAL_FREEMEM(nameIdStr); + } + + if (sendResponse) { + mmsServer_createMmsWriteResponse(connection, invokeId, response, numberOfWriteItems, accessResults); + } + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); +} + +#endif /* (MMS_WRITE_SERVICE == 1) */ diff --git a/src/mms/iso_presentation/iso_presentation.c b/src/mms/iso_presentation/iso_presentation.c new file mode 100644 index 0000000..1aab913 --- /dev/null +++ b/src/mms/iso_presentation/iso_presentation.c @@ -0,0 +1,752 @@ +/* + * iso_presentation.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "iso_presentation.h" +#include "stack_config.h" +#include "ber_encoder.h" +#include "ber_decode.h" +#include "buffer_chain.h" + +#if ((DEBUG_ISO_SERVER == 1) || (DEBUG_ISO_CLIENT == 1)) +#define DEBUG_PRES 1 +#else +#define DEBUG_PRES 0 +#endif + + +static uint8_t calledPresentationSelector[] = { 0x00, 0x00, 0x00, 0x01 }; + +static uint8_t asn_id_as_acse[] = { 0x52, 0x01, 0x00, 0x01 }; + +static uint8_t asn_id_mms[] = { 0x28, 0xca, 0x22, 0x02, 0x01 }; + +static uint8_t ber_id[] = { 0x51, 0x01 }; + +static int +encodeAcceptBer(uint8_t* buffer, int bufPos) +{ + bufPos = BerEncoder_encodeTL(0x30, 7, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, 1, buffer, bufPos); + buffer[bufPos++] = 0; + bufPos = BerEncoder_encodeTL(0x81, 2, buffer, bufPos); + buffer[bufPos++] = 0x51; + buffer[bufPos++] = 0x01; + + return bufPos; +} + +static int +encodeUserData(uint8_t* buffer, int bufPos, + BufferChain payload, bool encode, uint8_t contextId) +{ + int payloadLength = payload->length; + + int encodedDataSetLength = 3; /* presentation-selector */ + + /* presentation-data */ + encodedDataSetLength += payloadLength + 1; + encodedDataSetLength += BerEncoder_determineLengthSize(payloadLength); + + int fullyEncodedDataLength = encodedDataSetLength; + + fullyEncodedDataLength += BerEncoder_determineLengthSize(encodedDataSetLength) + 1; + + if (encode) { + /* fully-encoded-data */ + bufPos = BerEncoder_encodeTL(0x61, fullyEncodedDataLength, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x30, encodedDataSetLength, buffer, bufPos); + + /* presentation-selector acse */ + bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos); + buffer[bufPos++] = contextId; + + /* presentation-data (= acse payload) */ + bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos); + + return bufPos; + } + else { + int encodedUserDataLength = fullyEncodedDataLength + 1; + encodedUserDataLength += BerEncoder_determineLengthSize(fullyEncodedDataLength); + + return encodedUserDataLength; + } +} + +static void +createConnectPdu(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload) +{ + int contentLength = 0; + + /* mode-selector */ + contentLength += 5; + + int normalModeLength = 0; + + /* called- and calling-presentation-selector */ + normalModeLength += 12; + + int pclLength = 35; + + normalModeLength += pclLength; + + normalModeLength += encodeUserData(NULL, 0, payload, false, self->acseContextId); + + normalModeLength += 2; + + contentLength += normalModeLength; // + 2; + + contentLength += 1 + BerEncoder_determineLengthSize(normalModeLength); + + uint8_t* buffer = writeBuffer->buffer; + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0x31, contentLength, buffer, bufPos); + + /* mode-selector */ + bufPos = BerEncoder_encodeTL(0xa0, 3, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, 1, buffer, bufPos); + buffer[bufPos++] = 1; /* 1 = normal-mode */ + + /* normal-mode-parameters */ + bufPos = BerEncoder_encodeTL(0xa2, normalModeLength, buffer, bufPos); + + /* calling-presentation-selector */ + bufPos = BerEncoder_encodeTL(0x81, 4, buffer, bufPos); + buffer[bufPos++] = (uint8_t) ((self->callingPresentationSelector >> 24) & 0xff); + buffer[bufPos++] = (uint8_t) ((self->callingPresentationSelector >> 16) & 0xff); + buffer[bufPos++] = (uint8_t) ((self->callingPresentationSelector >> 8) & 0xff); + buffer[bufPos++] = (uint8_t) (self->callingPresentationSelector & 0xff); + +// memcpy(buffer + bufPos, callingPresentationSelector, 4); +// bufPos += 4; + + /* called-presentation-selector */ + bufPos = BerEncoder_encodeTL(0x82, 4, buffer, bufPos); + buffer[bufPos++] = (uint8_t) ((self->calledPresentationSelector >> 24) & 0xff); + buffer[bufPos++] = (uint8_t) ((self->calledPresentationSelector >> 16) & 0xff); + buffer[bufPos++] = (uint8_t) ((self->calledPresentationSelector >> 8) & 0xff); + buffer[bufPos++] = (uint8_t) (self->calledPresentationSelector & 0xff); + +// memcpy(buffer + bufPos, calledPresentationSelector, 4); +// bufPos += 4; + + /* presentation-context-id list */ + bufPos = BerEncoder_encodeTL(0xa4, 35, buffer, bufPos); + + /* acse context list item */ + bufPos = BerEncoder_encodeTL(0x30, 15, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos); + buffer[bufPos++] = 1; + + bufPos = BerEncoder_encodeTL(0x06, 4, buffer, bufPos); + memcpy(buffer + bufPos, asn_id_as_acse, 4); + bufPos += 4; + + bufPos = BerEncoder_encodeTL(0x30, 4, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x06, 2, buffer, bufPos); + memcpy(buffer + bufPos, ber_id, 2); + bufPos += 2; + + /* mms context list item */ + bufPos = BerEncoder_encodeTL(0x30, 16, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x02, 1, buffer, bufPos); + buffer[bufPos++] = 3; + + bufPos = BerEncoder_encodeTL(0x06, 5, buffer, bufPos); + memcpy(buffer + bufPos, asn_id_mms, 5); + bufPos += 5; + + bufPos = BerEncoder_encodeTL(0x30, 4, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x06, 2, buffer, bufPos); + memcpy(buffer + bufPos, ber_id, 2); + bufPos += 2; + + /* encode user data */ + bufPos = encodeUserData(buffer, bufPos, payload, true, self->acseContextId); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payload->length; + writeBuffer->nextPart = payload; +} + +static int +parseFullyEncodedData(IsoPresentation* self, uint8_t* buffer, int len, int bufPos) +{ + int presentationSelector = -1; + bool userDataPresent = false; + + int endPos = bufPos + len; + + if (buffer[bufPos++] != 0x30) { + if (DEBUG_PRES) + printf("PRES: user-data parse error\n"); + return -1; + } + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); + + endPos = bufPos + len; + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: wrong parameter length\n"); + return -1; + } + + while (bufPos < endPos) { + uint8_t tag = buffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos); + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: wrong parameter length\n"); + return -1; + } + + switch (tag) { + case 0x02: /* presentation-context-identifier */ + if (DEBUG_PRES) + printf("PRES: presentation-context-identifier\n"); + { + presentationSelector = BerDecoder_decodeUint32(buffer, length, bufPos); + self->nextContextId = presentationSelector; + bufPos += length; + } + break; + + case 0xa0: + if (DEBUG_PRES) + printf("PRES: fully-encoded-data\n"); + + userDataPresent = true; + + self->nextPayload.buffer = buffer + bufPos; + self->nextPayload.size = length; + + bufPos += length; + break; + default: + if (DEBUG_PRES) + printf("PRES: fed: unknown tag %02x\n", tag); + + bufPos += length; + break; + } + } + + if (!userDataPresent) { + if (DEBUG_PRES) + printf("PRES: user-data not present\n"); + return -1; + } + + return bufPos; +} + +static int +parsePCDLEntry(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufPos) +{ + int endPos = bufPos + totalLength; + + int contextId = -1; + bool isAcse = false; + bool isMms = false; + + while (bufPos < endPos) { + uint8_t tag = buffer[bufPos++]; + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); + + switch (tag) { + case 0x02: /* presentation-context-identifier */ + contextId = BerDecoder_decodeUint32(buffer, len, bufPos); + bufPos += len; + break; + case 0x06: /* abstract-syntax-name */ + if (DEBUG_PRES) + printf("PRES: abstract-syntax-name with len %i\n", len); + + if (len == 5) { + if (memcmp(buffer + bufPos, asn_id_mms, 5) == 0) + isMms = true; + } + else if (len == 4) { + if (memcmp(buffer + bufPos, asn_id_as_acse, 4) == 0) + isAcse = true; + } + + bufPos += len; + + break; + case 0x30: /* transfer-syntax-name */ + if (DEBUG_PRES) + printf("PRES: ignore transfer-syntax-name\n"); + + bufPos += len; + break; + default: + if (DEBUG_PRES) + printf("PRES: unknown tag in presentation-context-definition-list-entry\n"); + bufPos += len; + break; + } + } + + if (contextId < 0) { + if (DEBUG_PRES) + printf("PRES: ContextId not defined!\n"); + return -1; + } + + if ((isAcse == false) && (isMms == false)) { + if (DEBUG_PRES) + printf("PRES: not an ACSE or MMS context definition\n"); + + return -1; + } + + if (isMms) { + self->mmsContextId = (uint8_t) contextId; + if (DEBUG_PRES) + printf("PRES: MMS context id is %i\n", contextId); + } + else { + self->acseContextId = (uint8_t) contextId; + if (DEBUG_PRES) + printf("PRES: ACSE context id is %i\n", contextId); + } + + return bufPos; +} + +static int +parsePresentationContextDefinitionList(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufPos) +{ + int endPos = bufPos + totalLength; + + while (bufPos < endPos) { + uint8_t tag = buffer[bufPos++]; + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); + + switch (tag) { + case 0x30: + if (DEBUG_PRES) + printf("PRES: parse pcd entry\n"); + bufPos = parsePCDLEntry(self, buffer, len, bufPos); + if (bufPos < 0) + return -1; + break; + default: + if (DEBUG_PRES) + printf("PRES: unknown tag in presentation-context-definition-list\n"); + bufPos += len; + break; + } + } + + return bufPos; +} + +static int +parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufPos) +{ + int endPos = bufPos + totalLength; + + while (bufPos < endPos) { + uint8_t tag = buffer[bufPos++]; + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: wrong parameter length\n"); + return -1; + } + + switch (tag) { + case 0x81: /* calling-presentation-selector */ + if (DEBUG_PRES) + printf("PRES: calling-pres-sel\n"); + bufPos += len; + break; + case 0x82: /* calling-presentation-selector */ + if (DEBUG_PRES) + printf("PRES: calling-pres-sel\n"); + bufPos += len; + break; + case 0xa4: /* presentation-context-definition list */ + if (DEBUG_PRES) + printf("PRES: pcd list\n"); + bufPos = parsePresentationContextDefinitionList(self, buffer, len, bufPos); + break; + case 0x61: /* user data */ + if (DEBUG_PRES) + printf("PRES: user-data\n"); + + bufPos = parseFullyEncodedData(self, buffer, len, bufPos); + + if (bufPos < 0) + return -1; + + break; + + default: + if (DEBUG_PRES) + printf("PRES: unknown tag in normal-mode\n"); + bufPos += len; + break; + } + } + + return bufPos; +} + +int +IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer) +{ + uint8_t* buffer = byteBuffer->buffer; + int maxBufPos = byteBuffer->size; + + int bufPos = 0; + + uint8_t cpTag = buffer[bufPos++]; + + if (cpTag != 0x31) { + if (DEBUG_PRES) + printf("PRES: not a CPA message\n"); + return 0; + } + + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: wrong parameter length\n"); + return 0; + } + + switch (tag) { + case 0xa0: /* mode-selector */ + bufPos += len; /* ignore content since only normal mode is allowed */ + break; + case 0xa2: /* normal-mode-parameters */ + bufPos = parseNormalModeParameters(self, buffer, len, bufPos); + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: error parsing normal-mode-parameters\n"); + return 0; + } + + break; + default: + if (DEBUG_PRES) + printf("PRES: CPA unknown tag %i\n", tag); + bufPos += len; + break; + } + } + + return 1; +} + +void +IsoPresentation_init(IsoPresentation* self) +{ + +} + +void +IsoPresentation_createUserData(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload) +{ + int bufPos = 0; + uint8_t* buffer = writeBuffer->buffer; + + int payloadLength = payload->length; + + int userDataLengthFieldSize = BerEncoder_determineLengthSize(payloadLength); + ; + int pdvListLength = payloadLength + (userDataLengthFieldSize + 4); + + int pdvListLengthFieldSize = BerEncoder_determineLengthSize(pdvListLength); + int presentationLength = pdvListLength + (pdvListLengthFieldSize + 1); + + bufPos = BerEncoder_encodeTL(0x61, presentationLength, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x30, pdvListLength, buffer, bufPos); + + buffer[bufPos++] = (uint8_t) 0x02; + buffer[bufPos++] = (uint8_t) 0x01; + buffer[bufPos++] = (uint8_t) self->mmsContextId; /* mms context id */ + + bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payloadLength; + writeBuffer->nextPart = payload; +} + +void +IsoPresentation_createUserDataACSE(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload) +{ + int bufPos = 0; + uint8_t* buffer = writeBuffer->buffer; + + int payloadLength = payload->length; + + int userDataLengthFieldSize = BerEncoder_determineLengthSize(payloadLength); + ; + int pdvListLength = payloadLength + (userDataLengthFieldSize + 4); + + int pdvListLengthFieldSize = BerEncoder_determineLengthSize(pdvListLength); + int presentationLength = pdvListLength + (pdvListLengthFieldSize + 1); + + bufPos = BerEncoder_encodeTL(0x61, presentationLength, buffer, bufPos); + + bufPos = BerEncoder_encodeTL(0x30, pdvListLength, buffer, bufPos); + + buffer[bufPos++] = (uint8_t) 0x02; + buffer[bufPos++] = (uint8_t) 0x01; + buffer[bufPos++] = (uint8_t) self->acseContextId; /* ACSE context id */ + + bufPos = BerEncoder_encodeTL(0xa0, payloadLength, buffer, bufPos); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payloadLength; + writeBuffer->nextPart = payload; +} + +int +IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* readBuffer) +{ + int length = readBuffer->size; + uint8_t* buffer = readBuffer->buffer; + + int bufPos = 0; + + if (length < 9) + return 0; + + if (buffer[bufPos++] != 0x61) + return 0; + + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, length); + + if (buffer[bufPos++] != 0x30) + return 0; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, length); + + if (buffer[bufPos++] != 0x02) + return 0; + + if (buffer[bufPos++] != 0x01) + return 0; + + self->nextContextId = buffer[bufPos++]; + + if (buffer[bufPos++] != 0xa0) + return 0; + + int userDataLength; + + bufPos = BerDecoder_decodeLength(buffer, &userDataLength, bufPos, length); + + ByteBuffer_wrap(&(self->nextPayload), buffer + bufPos, userDataLength, userDataLength); + + return 1; +} + +int +IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer) +{ + uint8_t* buffer = byteBuffer->buffer; + int maxBufPos = byteBuffer->size; + + int bufPos = 0; + + uint8_t cpTag = buffer[bufPos++]; + + if (cpTag != 0x31) { + if (DEBUG_PRES) + printf("PRES: not a CP type\n"); + return 0; + } + + int len; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + if (DEBUG_PRES) + printf("PRES: CPType with len %i\n", len); + + while (bufPos < maxBufPos) { + uint8_t tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: wrong parameter length\n"); + return 0; + } + + switch (tag) { + case 0xa0: /* mode-selection */ + { + if (buffer[bufPos++] != 0x80) { + if (DEBUG_PRES) + printf("PRES: mode-value of wrong type!\n"); + return 0; + } + bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); + uint32_t modeSelector = BerDecoder_decodeUint32(buffer, len, bufPos); + if (DEBUG_PRES) + printf("PRES: modesel %ui\n", modeSelector); + bufPos += len; + } + break; + case 0xa2: /* normal-mode-parameters */ + bufPos = parseNormalModeParameters(self, buffer, len, bufPos); + + if (bufPos < 0) { + if (DEBUG_PRES) + printf("PRES: error parsing normal-mode-parameters\n"); + return 0; + } + + break; + default: /* unsupported element */ + if (DEBUG_PRES) + printf("PRES: tag %i not recognized\n", tag); + bufPos += len; + break; + } + } + + return 1; +} + +void +IsoPresentation_createConnectPdu(IsoPresentation* self, IsoConnectionParameters parameters, + BufferChain buffer, BufferChain payload) +{ + self->acseContextId = 1; + self->mmsContextId = 3; + self->callingPresentationSelector = parameters->localPSelector; + self->calledPresentationSelector = parameters->remotePSelector; + createConnectPdu(self, buffer, payload); +} + +void +IsoPresentation_createAbortUserMessage(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload) +{ + int contentLength = 0; + + contentLength = +encodeUserData(NULL, 0, payload, false, self->acseContextId); + + contentLength += BerEncoder_determineLengthSize(contentLength) + 1; + + uint8_t* buffer = writeBuffer->buffer; + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0xa0, contentLength, buffer, bufPos); + + /* encode user data */ + bufPos = encodeUserData(buffer, bufPos, payload, true, self->acseContextId); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payload->length; + writeBuffer->nextPart = payload; +} + +void +IsoPresentation_createCpaMessage(IsoPresentation* self, BufferChain writeBuffer, BufferChain payload) +{ + int contentLength = 0; + + /* mode-selector */ + contentLength += 5; + + int normalModeLength = 0; + + normalModeLength += 6; /* responding-presentation-selector */ + + normalModeLength += 20; /* context-definition-result-list */ + + normalModeLength += encodeUserData(NULL, 0, payload, false, self->acseContextId); + + contentLength += normalModeLength; + + contentLength += BerEncoder_determineLengthSize(normalModeLength) + 1; + + uint8_t* buffer = writeBuffer->buffer; + int bufPos = 0; + + bufPos = BerEncoder_encodeTL(0x31, contentLength, buffer, bufPos); + + /* mode-selector */ + bufPos = BerEncoder_encodeTL(0xa0, 3, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, 1, buffer, bufPos); + buffer[bufPos++] = 1; /* 1 = normal-mode */ + + /* normal-mode-parameters */ + bufPos = BerEncoder_encodeTL(0xa2, normalModeLength, buffer, bufPos); + + /* responding-presentation-selector */ + bufPos = BerEncoder_encodeTL(0x83, 4, buffer, bufPos); + memcpy(buffer + bufPos, calledPresentationSelector, 4); + bufPos += 4; + + /* context-definition-result-list */ + bufPos = BerEncoder_encodeTL(0xa5, 18, buffer, bufPos); + bufPos = encodeAcceptBer(buffer, bufPos); /* accept for acse */ + bufPos = encodeAcceptBer(buffer, bufPos); /* accept for mms */ + + /* encode user data */ + bufPos = encodeUserData(buffer, bufPos, payload, true, self->acseContextId); + + writeBuffer->partLength = bufPos; + writeBuffer->length = bufPos + payload->length; + writeBuffer->nextPart = payload; +} diff --git a/src/mms/iso_server/iso_connection.c b/src/mms/iso_server/iso_connection.c new file mode 100644 index 0000000..8ae5168 --- /dev/null +++ b/src/mms/iso_server/iso_connection.c @@ -0,0 +1,597 @@ +/* + * iso_connection.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" +#include "buffer_chain.h" +#include "cotp.h" +#include "iso_session.h" +#include "iso_presentation.h" +#include "acse.h" +#include "iso_server.h" +#include "hal_socket.h" +#include "hal_thread.h" + +#include "iso_server_private.h" + +#ifndef DEBUG_ISO_SERVER +#ifdef DEBUG +#define DEBUG_ISO_SERVER 1 +#else +#define DEBUG_ISO_SERVER 0 +#endif /*DEBUG */ +#endif /* DEBUG_ISO_SERVER */ + +#define RECEIVE_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100 +#define SEND_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100 + +#define TPKT_RFC1006_HEADER_SIZE 4 + +#define ISO_CON_STATE_RUNNING 1 +#define ISO_CON_STATE_STOPPED 0 + +struct sIsoConnection +{ + uint8_t* receiveBuffer; + uint8_t* sendBuffer; + + ByteBuffer rcvBuffer; + + uint8_t* cotpReadBuf; + uint8_t* cotpWriteBuf; + ByteBuffer cotpReadBuffer; + ByteBuffer cotpWriteBuffer; + + MessageReceivedHandler msgRcvdHandler; + void* msgRcvdHandlerParameter; + + IsoServer isoServer; + + Socket socket; + int state; + IsoSession* session; + IsoPresentation* presentation; + CotpConnection* cotpConnection; + + AcseConnection* acseConnection; + + char* clientAddress; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Thread thread; + Semaphore conMutex; + + bool isInsideCallback; +#endif +}; + +static void +finalizeIsoConnection(IsoConnection self) +{ + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: finalizeIsoConnection --> close transport connection\n"); + + IsoServer_closeConnection(self->isoServer, self); + if (self->socket != NULL) + Socket_destroy(self->socket); + + GLOBAL_FREEMEM(self->session); + GLOBAL_FREEMEM(self->presentation); + AcseConnection_destroy(self->acseConnection); + GLOBAL_FREEMEM(self->acseConnection); + + GLOBAL_FREEMEM(self->cotpReadBuf); + GLOBAL_FREEMEM(self->cotpWriteBuf); + + GLOBAL_FREEMEM(self->cotpConnection); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->conMutex); +#endif + + GLOBAL_FREEMEM(self->receiveBuffer); + GLOBAL_FREEMEM(self->sendBuffer); + GLOBAL_FREEMEM(self->clientAddress); + IsoServer isoServer = self->isoServer; + GLOBAL_FREEMEM(self); + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: connection %p closed\n", self); + + private_IsoServer_decreaseConnectionCounter(isoServer); +} + +void +IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles) +{ + Handleset_addSocket(handles, self->socket); +} + +void +IsoConnection_handleTcpConnection(IsoConnection self) +{ + TpktState tpktState = CotpConnection_readToTpktBuffer(self->cotpConnection); + + if (tpktState == TPKT_ERROR) + self->state = ISO_CON_STATE_STOPPED; + + if (tpktState != TPKT_PACKET_COMPLETE) + goto exit_function; + + CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + switch (cotpIndication) { + case COTP_MORE_FRAGMENTS_FOLLOW: + goto exit_function; + + case COTP_CONNECT_INDICATION: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: COTP connection indication\n"); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->conMutex); +#endif + + CotpConnection_sendConnectionResponseMessage(self->cotpConnection); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->conMutex); +#endif + + break; + case COTP_DATA_INDICATION: + { + ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection); + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: COTP data indication (payload size = %i)\n", cotpPayload->size); + + IsoSessionIndication sIndication = IsoSession_parseMessage(self->session, cotpPayload); + + ByteBuffer* sessionUserData = IsoSession_getUserData(self->session); + + switch (sIndication) { + case SESSION_CONNECT: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session connect indication\n"); + + if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: presentation ok\n"); + + ByteBuffer* acseBuffer = &(self->presentation->nextPayload); + + AcseIndication aIndication = AcseConnection_parseMessage(self->acseConnection, acseBuffer); + + if (aIndication == ACSE_ASSOCIATE) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->conMutex); +#endif + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: cotp_server: acse associate\n"); + + ByteBuffer mmsRequest; + + ByteBuffer_wrap(&mmsRequest, self->acseConnection->userDataBuffer, + self->acseConnection->userDataBufferSize, self->acseConnection->userDataBufferSize); + ByteBuffer mmsResponseBuffer; /* new */ + + ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); + + if (self->msgRcvdHandler != NULL) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = true; +#endif + + self->msgRcvdHandler(self->msgRcvdHandlerParameter, + &mmsRequest, &mmsResponseBuffer); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = false; +#endif + } + + struct sBufferChain mmsBufferPartStruct; + BufferChain mmsBufferPart = &mmsBufferPartStruct; + + BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL, + self->sendBuffer); + + if (mmsResponseBuffer.size > 0) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: application payload size: %i\n", + mmsResponseBuffer.size); + + struct sBufferChain acseBufferPartStruct; + BufferChain acseBufferPart = &acseBufferPartStruct; + + acseBufferPart->buffer = self->sendBuffer + mmsBufferPart->length; + acseBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length; + + AcseConnection_createAssociateResponseMessage(self->acseConnection, + ACSE_RESULT_ACCEPT, acseBufferPart, mmsBufferPart); + + struct sBufferChain presentationBufferPartStruct; + BufferChain presentationBufferPart = &presentationBufferPartStruct; + + presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length; + presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length; + + IsoPresentation_createCpaMessage(self->presentation, presentationBufferPart, + acseBufferPart); + + struct sBufferChain sessionBufferPartStruct; + BufferChain sessionBufferPart = &sessionBufferPartStruct; + sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; + sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; + + IsoSession_createAcceptSpdu(self->session, sessionBufferPart, presentationBufferPart); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); + } + else { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: association error. No response from application!\n"); + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->conMutex); +#endif + } + else { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: acse association failed\n"); + self->state = ISO_CON_STATE_STOPPED; + } + + } + break; + case SESSION_DATA: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session data indication\n"); + + if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: presentation layer error\n"); + self->state = ISO_CON_STATE_STOPPED; + break; + } + + if (self->presentation->nextContextId == self->presentation->mmsContextId) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: mms message\n"); + + ByteBuffer* mmsRequest = &(self->presentation->nextPayload); + + ByteBuffer mmsResponseBuffer; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + IsoServer_userLock(self->isoServer); + Semaphore_wait(self->conMutex); +#endif + + ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); + + if (self->msgRcvdHandler != NULL) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = true; +#endif + + self->msgRcvdHandler(self->msgRcvdHandlerParameter, + mmsRequest, &mmsResponseBuffer); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = false; +#endif + } + + /* send a response if required */ + if (mmsResponseBuffer.size > 0) { + + struct sBufferChain mmsBufferPartStruct; + BufferChain mmsBufferPart = &mmsBufferPartStruct; + + BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, + mmsResponseBuffer.size, NULL, self->sendBuffer); + + struct sBufferChain presentationBufferPartStruct; + BufferChain presentationBufferPart = &presentationBufferPartStruct; + presentationBufferPart->buffer = self->sendBuffer + mmsBufferPart->length; + presentationBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length; + + IsoPresentation_createUserData(self->presentation, + presentationBufferPart, mmsBufferPart); + + struct sBufferChain sessionBufferPartStruct; + BufferChain sessionBufferPart = &sessionBufferPartStruct; + sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; + sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; + + IsoSession_createDataSpdu(self->session, sessionBufferPart, presentationBufferPart); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->conMutex); + IsoServer_userUnlock(self->isoServer); +#endif + } + else { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: unknown presentation layer context!"); + } + + break; + + case SESSION_FINISH: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session finish indication\n"); + + if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: presentation ok\n"); + + struct sBufferChain acseBufferPartStruct; + BufferChain acseBufferPart = &acseBufferPartStruct; + acseBufferPart->buffer = self->sendBuffer; + acseBufferPart->partMaxLength = SEND_BUF_SIZE; + + AcseConnection_createReleaseResponseMessage(self->acseConnection, acseBufferPart); + + struct sBufferChain presentationBufferPartStruct; + BufferChain presentationBufferPart = &presentationBufferPartStruct; + presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length; + presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length; + + IsoPresentation_createUserDataACSE(self->presentation, presentationBufferPart, acseBufferPart); + + struct sBufferChain sessionBufferPartStruct; + BufferChain sessionBufferPart = &sessionBufferPartStruct; + sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; + sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; + + IsoSession_createDisconnectSpdu(self->session, sessionBufferPart, presentationBufferPart); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); + } + + self->state = ISO_CON_STATE_STOPPED; + + break; + + case SESSION_ABORT: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session abort indication\n"); + self->state = ISO_CON_STATE_STOPPED; + break; + + case SESSION_ERROR: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session error indication\n"); + self->state = ISO_CON_STATE_STOPPED; + break; + + default: /* illegal state */ + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session illegal state\n"); + + self->state = ISO_CON_STATE_STOPPED; + break; + } + + CotpConnection_resetPayload(self->cotpConnection); + } + break; + case COTP_ERROR: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: Connection closed\n"); + self->state = ISO_CON_STATE_STOPPED; + break; + default: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: COTP unknown indication: %i\n", cotpIndication); + self->state = ISO_CON_STATE_STOPPED; + break; + } + +exit_function: + return; +} + +#if (CONFIG_MMS_SINGLE_THREADED == 0) +static void +handleTcpConnection(void* parameter) +{ + IsoConnection self = (IsoConnection) parameter; + + while(self->state == ISO_CON_STATE_RUNNING) { + IsoConnection_handleTcpConnection(self); + Thread_sleep(1); + } + + finalizeIsoConnection(self); +} +#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */ + +IsoConnection +IsoConnection_create(Socket socket, IsoServer isoServer) +{ + IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection)); + self->socket = socket; + self->receiveBuffer = (uint8_t*) GLOBAL_MALLOC(RECEIVE_BUF_SIZE); + self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(SEND_BUF_SIZE); + self->msgRcvdHandler = NULL; + self->msgRcvdHandlerParameter = NULL; + self->isoServer = isoServer; + self->state = ISO_CON_STATE_RUNNING; + self->clientAddress = Socket_getPeerAddress(self->socket); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = false; + self->conMutex = Semaphore_create(1); +#endif + + ByteBuffer_wrap(&(self->rcvBuffer), self->receiveBuffer, 0, RECEIVE_BUF_SIZE); + + self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + ByteBuffer_wrap(&(self->cotpReadBuffer), self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + ByteBuffer_wrap(&(self->cotpWriteBuffer), self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection)); + CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer)); + + self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession)); + IsoSession_init(self->session); + + self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation)); + IsoPresentation_init(self->presentation); + + self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection)); + AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer), + IsoServer_getAuthenticatorParameter(self->isoServer)); + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress); + +#if (CONFIG_MMS_SINGLE_THREADED == 0) +#if (CONFIG_MMS_THREADLESS_STACK == 0) + self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, true); + + Thread_start(self->thread); +#endif +#endif + + return self; +} + +void +IsoConnection_destroy(IsoConnection self) +{ + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: destroy called for IsoConnection.\n"); + + finalizeIsoConnection(self); +} + +char* +IsoConnection_getPeerAddress(IsoConnection self) +{ + return self->clientAddress; +} + +void +IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerMode) +{ + if (self->state == ISO_CON_STATE_STOPPED) { + if (DEBUG_ISO_SERVER) + printf("DEBUG_ISO_SERVER: sendMessage: connection already stopped!\n"); + goto exit_error; + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->isInsideCallback == false) + Semaphore_wait(self->conMutex); +#endif + + struct sBufferChain payloadBufferStruct; + BufferChain payloadBuffer = &payloadBufferStruct; + payloadBuffer->length = message->size; + payloadBuffer->partLength = message->size; + payloadBuffer->partMaxLength = message->size; + payloadBuffer->buffer = message->buffer; + payloadBuffer->nextPart = NULL; + + struct sBufferChain presentationBufferStruct; + BufferChain presentationBuffer = &presentationBufferStruct; + presentationBuffer->buffer = self->sendBuffer; + presentationBuffer->partMaxLength = SEND_BUF_SIZE; + + IsoPresentation_createUserData(self->presentation, + presentationBuffer, payloadBuffer); + + struct sBufferChain sessionBufferStruct; + BufferChain sessionBuffer = &sessionBufferStruct; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->partLength; + + IsoSession_createDataSpdu(self->session, sessionBuffer, presentationBuffer); + + CotpIndication indication; + + indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + if (DEBUG_ISO_SERVER) { + if (indication != COTP_OK) + printf("ISO_SERVER: IsoConnection_sendMessage failed!\n"); + else + printf("ISO_SERVER: IsoConnection_sendMessage success!\n"); + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->isInsideCallback == false) + Semaphore_post(self->conMutex); +#endif + +exit_error: + return; +} + +void +IsoConnection_close(IsoConnection self) +{ + if (self->state != ISO_CON_STATE_STOPPED) { + Socket socket = self->socket; + self->state = ISO_CON_STATE_STOPPED; + self->socket = NULL; + + Socket_destroy(socket); + } +} + +void +IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler, + void* parameter) +{ + self->msgRcvdHandler = handler; + self->msgRcvdHandlerParameter = parameter; +} + +void* +IsoConnection_getSecurityToken(IsoConnection self) +{ + return self->acseConnection->securityToken; +} + +bool +IsoConnection_isRunning(IsoConnection self) +{ + if (self->state == ISO_CON_STATE_RUNNING) + return true; + else + return false; +} diff --git a/src/mms/iso_server/iso_server.c b/src/mms/iso_server/iso_server.c new file mode 100644 index 0000000..577a95e --- /dev/null +++ b/src/mms/iso_server/iso_server.c @@ -0,0 +1,758 @@ +/* + * iso_server.c + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#ifndef DEBUG_ISO_SERVER +#ifdef DEBUG +#define DEBUG_ISO_SERVER 1 +#else +#define DEBUG_ISO_SERVER 0 +#endif /*DEBUG */ +#endif /* DEBUG_ISO_SERVER */ + +#include "mms_server_connection.h" + +#include "hal_thread.h" + +#include "iso_server.h" + +#include "iso_server_private.h" + +#ifndef CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS +#define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 +#endif + +#define TCP_PORT 102 +#define SECURE_TCP_PORT 3782 +#define BACKLOG 10 + +struct sIsoServer { + IsoServerState state; + ConnectionIndicationHandler connectionHandler; + void* connectionHandlerParameter; + + AcseAuthenticator authenticator; + void* authenticatorParameter; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Thread serverThread; +#endif + + Socket serverSocket; + int tcpPort; + char* localIpAddress; + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + LinkedList openClientConnections; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore openClientConnectionsMutex; /* mutex for openClientConnections list */ +#endif + +#else + IsoConnection* openClientConnections; +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore userLock; + + Semaphore connectionCounterMutex; +#endif + int connectionCounter; +}; + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) +static inline void +lockClientConnections(IsoServer self) +{ + Semaphore_wait(self->openClientConnectionsMutex); +} + +static inline void +unlockClientConnections(IsoServer self) +{ + Semaphore_post(self->openClientConnectionsMutex); +} +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + +static void +addClientConnection(IsoServer self, IsoConnection connection) +{ + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + LinkedList_add(self->openClientConnections, connection); +#else + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] == NULL) { + self->openClientConnections[i] = connection; + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: added connection (%p) index:%i\n", connection, i); + + break; + } + } +#endif +} + +static void +removeClientConnection(IsoServer self, IsoConnection connection) +{ +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + + +#if (CONFIG_MMS_SINGLE_THREADED == 0) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + + LinkedList_remove(self->openClientConnections, connection); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + +#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */ + + +#else + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] == connection) { + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: removed connection (%p) index:%i\n", connection, i); + + self->openClientConnections[i] = NULL; + break; + } + } +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ +} + +static void +closeAllOpenClientConnections(IsoServer self) +{ + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + + LinkedList openConnection = LinkedList_getNext(self->openClientConnections); + while (openConnection != NULL) { + IsoConnection isoConnection = (IsoConnection) openConnection->data; + + IsoConnection_close(isoConnection); + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + /* if CONFIG_MMS_SINGLE_THREADED == 0 connection instance will be destroyed by connection thread. */ + IsoConnection_destroy(isoConnection); +#endif + + openConnection = LinkedList_getNext(openConnection); + } + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + LinkedList_destroyStatic(self->openClientConnections); + self->openClientConnections = NULL; +#endif + + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + +#else + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] != NULL) { + + IsoConnection_close(self->openClientConnections[i]); + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + /* if CONFIG_MMS_SINGLE_THREADED == 0 connection instance will be destroyed by connection thread. */ + IsoConnection_destroy(self->openClientConnections[i]); +#endif + + } + } +#endif +} + +static void +handleClientConnections(IsoServer self) +{ +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + + LinkedList openConnection = LinkedList_getNext(self->openClientConnections); + LinkedList lastConnection = self->openClientConnections; + + while (openConnection != NULL) { + IsoConnection isoConnection = (IsoConnection) openConnection->data; + + if (IsoConnection_isRunning(isoConnection)) + IsoConnection_handleTcpConnection(isoConnection); + else { + IsoConnection_destroy(isoConnection); + + lastConnection->next = openConnection->next; + + GLOBAL_FREEMEM(openConnection); + } + + openConnection = LinkedList_getNext(openConnection); + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + +#else + + + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] != NULL) { + if (IsoConnection_isRunning(self->openClientConnections[i])) { + + IsoConnection_handleTcpConnection(self->openClientConnections[i]); + } + else { + IsoConnection_destroy(self->openClientConnections[i]); + + self->openClientConnections[i] = NULL; + } + + } + } +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ +} + +static bool +setupIsoServer(IsoServer self) +{ + bool success = true; + + self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort); + + if (self->serverSocket == NULL) { + self->state = ISO_SVR_STATE_ERROR; + success = false; + + goto exit_function; + } + + ServerSocket_setBacklog((ServerSocket) self->serverSocket, BACKLOG); + + ServerSocket_listen((ServerSocket) self->serverSocket); + + self->state = ISO_SVR_STATE_RUNNING; + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: server is limited to %i client connections.\n", (int) CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS); +#endif + +exit_function: + return success; +} + + +#if (CONFIG_MMS_THREADLESS_STACK == 0) +// used by single and multi-threaded versions +static void +handleIsoConnections(IsoServer self) +{ + Socket connectionSocket; + + if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) { + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) + if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); + + Socket_destroy(connectionSocket); + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + handleClientConnections(self); +#endif + + return; + } +#endif + + IsoConnection isoConnection = IsoConnection_create(connectionSocket, self); + + private_IsoServer_increaseConnectionCounter(self); + + addClientConnection(self, isoConnection); + + self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter, + isoConnection); + + } + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + handleClientConnections(self); +#endif +} +#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */ + +// used by non-threaded version +static void +handleIsoConnectionsThreadless(IsoServer self) +{ + Socket connectionSocket; + + if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) { + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) + if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); + + Socket_destroy(connectionSocket); + + handleClientConnections(self); + + return; + } +#endif + + IsoConnection isoConnection = IsoConnection_create(connectionSocket, self); + + private_IsoServer_increaseConnectionCounter(self); + + addClientConnection(self, isoConnection); + + self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter, + isoConnection); + + } + + handleClientConnections(self); +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +// only required for multi-threaded server! +static void +isoServerThread(void* isoServerParam) +{ + IsoServer self = (IsoServer) isoServerParam; + + if (!setupIsoServer(self)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: starting server failed!\n"); + + goto cleanUp; + } + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: isoServerThread %p started\n", &isoServerParam); + + while (self->state == ISO_SVR_STATE_RUNNING) + { + handleIsoConnections(self); + + Thread_sleep(1); + } + + self->state = ISO_SVR_STATE_STOPPED; + + cleanUp: + self->serverSocket = NULL; + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: isoServerThread %p stopped\n", &isoServerParam); + +} +#endif + +IsoServer +IsoServer_create() +{ + IsoServer self = (IsoServer) GLOBAL_CALLOC(1, sizeof(struct sIsoServer)); + + self->state = ISO_SVR_STATE_IDLE; + self->tcpPort = TCP_PORT; + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + self->openClientConnections = LinkedList_create(); +#else + self->openClientConnections = (IsoConnection*) + GLOBAL_CALLOC(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS, sizeof(IsoConnection)); +#endif + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->connectionCounterMutex = Semaphore_create(1); +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + self->openClientConnectionsMutex = Semaphore_create(1); +#endif + +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + + self->connectionCounter = 0; + + return self; +} + +void +IsoServer_setTcpPort(IsoServer self, int port) +{ + self->tcpPort = port; +} + +void +IsoServer_setLocalIpAddress(IsoServer self, char* ipAddress) +{ + self->localIpAddress = ipAddress; +} + +IsoServerState +IsoServer_getState(IsoServer self) +{ + return self->state; +} + +void +IsoServer_setAuthenticator(IsoServer self, AcseAuthenticator authenticator, void* authenticatorParameter) +{ + self->authenticator = authenticator; + self->authenticatorParameter = authenticatorParameter; +} + +AcseAuthenticator +IsoServer_getAuthenticator(IsoServer self) +{ + return self->authenticator; +} + +void* +IsoServer_getAuthenticatorParameter(IsoServer self) +{ + return self->authenticatorParameter; +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +IsoServer_startListening(IsoServer self) +{ + if (self->state == ISO_SVR_STATE_RUNNING) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: server already in RUNNING state!\n"); + + goto exit_function; + } + + self->state = ISO_SVR_STATE_IDLE; + + self->serverThread = Thread_create((ThreadExecutionFunction) isoServerThread, self, false); + + Thread_start(self->serverThread); + + /* wait until server is up */ + while (self->state == ISO_SVR_STATE_IDLE) + Thread_sleep(1); + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: new iso server thread started\n"); + +exit_function: + return; +} +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + +void +IsoServer_startListeningThreadless(IsoServer self) +{ + if (!setupIsoServer(self)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: starting server failed!\n"); + + self->serverSocket = NULL; + } + else { + self->state = ISO_SVR_STATE_RUNNING; + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: new iso server (threadless) started\n"); + } +} + +int +IsoServer_waitReady(IsoServer self, unsigned int timeoutMs) +{ + int result; + + if (self->state == ISO_SVR_STATE_RUNNING) { + HandleSet handles; + + handles = Handleset_new(); + if (handles != NULL) { +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + + LinkedList openConnection = LinkedList_getNext(self->openClientConnections); + LinkedList lastConnection = self->openClientConnections; + + while (openConnection != NULL) { + IsoConnection isoConnection = (IsoConnection) openConnection->data; + + if (IsoConnection_isRunning(isoConnection)) { + IsoConnection_addHandleSet(isoConnection, handles); + openConnection = LinkedList_getNext(openConnection); + } else { + IsoConnection_destroy(isoConnection); + lastConnection->next = openConnection->next; + GLOBAL_FREEMEM(openConnection); + openConnection = lastConnection->next; + } + + lastConnection = lastConnection->next; + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + +#else + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] != NULL) { + if (IsoConnection_isRunning(self->openClientConnections[i])) { + IsoConnection_addHandleSet(self->openClientConnections[i], handles); + } else { + IsoConnection_destroy(self->openClientConnections[i]); + self->openClientConnections[i] = NULL; + } + } + } +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + Handleset_addSocket(handles, self->serverSocket); + result = Handleset_waitReady(handles, timeoutMs); + Handleset_destroy(handles); + } else { + result = -1; + } + } else { + result = -1; + } + + return result; +} + + +void +IsoServer_processIncomingMessages(IsoServer self) +{ + if (self->state == ISO_SVR_STATE_RUNNING) + handleIsoConnectionsThreadless(self); +} + +static void +stopListening(IsoServer self) +{ + self->state = ISO_SVR_STATE_STOPPED; + if (self->serverSocket != NULL) { + ServerSocket_destroy((ServerSocket) self->serverSocket); + self->serverSocket = NULL; + } +} + +void +IsoServer_stopListeningThreadless(IsoServer self) +{ + stopListening(self); + + closeAllOpenClientConnections(self); + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: IsoServer_stopListeningThreadless finished!\n"); +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +IsoServer_stopListening(IsoServer self) +{ + stopListening(self); + + if (self->serverThread != NULL) + Thread_destroy(self->serverThread); + + closeAllOpenClientConnections(self); + + /* Wait for connection threads to finish */ + while (private_IsoServer_getConnectionCounter(self) > 0) + Thread_sleep(10); + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: IsoServer_stopListening finished!\n"); +} +#endif + +void +IsoServer_closeConnection(IsoServer self, IsoConnection isoConnection) +{ + if (self->state != ISO_SVR_STATE_IDLE) { + self->connectionHandler(ISO_CONNECTION_CLOSED, self->connectionHandlerParameter, + isoConnection); + } + + removeClientConnection(self, isoConnection); +} + +void +IsoServer_setConnectionHandler(IsoServer self, ConnectionIndicationHandler handler, + void* parameter) +{ + self->connectionHandler = handler; + self->connectionHandlerParameter = parameter; +} + +void +IsoServer_destroy(IsoServer self) +{ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->state == ISO_SVR_STATE_RUNNING) + IsoServer_stopListening(self); +#endif + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + if (self->openClientConnections != NULL) + LinkedList_destroy(self->openClientConnections); +#else + if (self->openClientConnections != NULL) + LinkedList_destroyStatic(self->openClientConnections); +#endif /* (CONFIG_MMS_SINGLE_THREADED == 1) */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); + Semaphore_destroy(self->openClientConnectionsMutex); +#endif + +#else + GLOBAL_FREEMEM(self->openClientConnections); +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->connectionCounterMutex); +#endif + + GLOBAL_FREEMEM(self); +} + +void +private_IsoServer_increaseConnectionCounter(IsoServer self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->connectionCounterMutex); +#endif + + self->connectionCounter++; + if (DEBUG_ISO_SERVER) + printf("IsoServer: increase connection counter to %i!\n", self->connectionCounter); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->connectionCounterMutex); +#endif +} + +void +private_IsoServer_decreaseConnectionCounter(IsoServer self) +{ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->connectionCounterMutex); +#endif + + self->connectionCounter--; + + if (DEBUG_ISO_SERVER) + printf("IsoServer: decrease connection counter to %i!\n", self->connectionCounter); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->connectionCounterMutex); +#endif +} + +int +private_IsoServer_getConnectionCounter(IsoServer self) +{ + int connectionCounter; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->connectionCounterMutex); +#endif + + connectionCounter = self->connectionCounter; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->connectionCounterMutex); +#endif + + return connectionCounter; +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +IsoServer_setUserLock(IsoServer self, Semaphore userLock) +{ + self->userLock = userLock; +} + +void +IsoServer_userLock(IsoServer self) +{ + if (self->userLock != NULL) + Semaphore_wait(self->userLock); +} + +void +IsoServer_userUnlock(IsoServer self) +{ + if (self->userLock != NULL) + Semaphore_post(self->userLock); +} +#endif diff --git a/src/mms/iso_session/iso_session.c b/src/mms/iso_session/iso_session.c new file mode 100644 index 0000000..e3db269 --- /dev/null +++ b/src/mms/iso_session/iso_session.c @@ -0,0 +1,501 @@ +/* + * iso_session.c + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "stack_config.h" +#include "iso_session.h" +#include "buffer_chain.h" + +#if ((DEBUG_ISO_SERVER == 1) || (DEBUG_ISO_CLIENT == 1)) +#define DEBUG_SESSION 1 +#else +#define DEBUG_SESSION 0 +#endif + +static int +parseAcceptParameters(IsoSession* session, ByteBuffer* message, int startOffset, int parameterLength) +{ + uint8_t pi; + uint8_t param_len; + uint8_t param_val; + uint8_t hasProtocolOptions = 0; + uint8_t hasProtocolVersion = 0; + int offset = startOffset; + int maxOffset = offset + parameterLength; + + while (offset < maxOffset) { + pi = message->buffer[offset++]; + param_len = message->buffer[offset++]; + + switch (pi) { + case 19: /* Protocol options */ + if (param_len != 1) + return -1; + session->protocolOptions = message->buffer[offset++]; + if (DEBUG_SESSION) + printf("SESSION: Param - Protocol Options: %02x\n", session->protocolOptions); + hasProtocolOptions = 1; + break; + case 21: /* TSDU Maximum Size */ + if (DEBUG_SESSION) + printf("SESSION: Param - TODO TSDU Maximum Size\n"); + offset += 4; + break; + case 22: /* Version Number */ + param_val = message->buffer[offset++]; + if (DEBUG_SESSION) + printf("SESSION: Param - Version number\n"); + if (param_val != 2) + return -1; + hasProtocolVersion = 1; + break; + case 23: /* Initial Serial Number */ + if (DEBUG_SESSION) + printf("SESSION: Param - TODO Initial Serial Number\n"); + offset += param_len; + break; + case 26: /* Token Setting Item */ + param_val = message->buffer[offset++]; + if (DEBUG_SESSION) + printf("SESSION: Param - Token Setting Item: %02x\n", param_val); + break; + case 55: /* Second Initial Serial Number */ + if (DEBUG_SESSION) + printf("SESSION: Param - TODO Second Initial Serial Number\n"); + offset += param_len; + break; + case 56: /* Upper Limit Serial Number */ + if (DEBUG_SESSION) + printf("SESSION: Param - TODO Upper Limit Serial Number\n"); + offset += param_len; + break; + case 57: /* Large Initial Serial Number */ + if (DEBUG_SESSION) + printf("SESSION: Param - TODO Large Initial Serial Number\n"); + offset += param_len; + break; + case 58: /* Large Second Initial Serial Number */ + if (DEBUG_SESSION) + printf("SESSION: Param - TODO Large Second Initial Serial Number\n"); + offset += param_len; + break; + default: + if (DEBUG_SESSION) + printf("SESSION: Param - Invalid Parameter with ID %02x\n", pi); + break; + } + } + + if (hasProtocolOptions && hasProtocolVersion) + return offset - startOffset; + else + return -1; +} + +static IsoSessionIndication +parseSessionHeaderParameters(IsoSession* session, ByteBuffer* message, int parametersOctets) +{ + int offset = 2; + uint8_t pgi; + uint8_t parameterLength; + + while (offset < (parametersOctets + 2)) { + pgi = message->buffer[offset++]; + parameterLength = message->buffer[offset++]; + + switch (pgi) { + case 1: /* Connection Identifier */ + if (DEBUG_SESSION) + printf("SESSION: PGI - connection identifier\n"); + + offset += parameterLength; + break; + case 5: /* Connection/Accept Item */ + if (DEBUG_SESSION) + printf("SESSION: PGI - Connection/Accept Item\n"); + + int connectAcceptLen; + + connectAcceptLen = parseAcceptParameters(session, message, offset, parameterLength); + + if (connectAcceptLen == -1) + return SESSION_ERROR; + + offset += connectAcceptLen; + break; + case 17: /* Transport disconnect */ + offset += parameterLength; + break; + case 20: /* Session User Requirements */ + if (DEBUG_SESSION) + printf("SESSION: Parameter - Session User Req\n"); + if (parameterLength != 2) + return SESSION_ERROR; + + session->sessionRequirement = message->buffer[offset++] * 0x100; + session->sessionRequirement += message->buffer[offset++]; + break; + case 25: /* Enclosure item */ + offset += parameterLength; + break; + case 49: + offset += parameterLength; + break; + case 51: /* Calling Session Selector */ + if (DEBUG_SESSION) + printf("SESSION: Parameter - Calling Session Selector\n"); + + if (parameterLength != 2) + return SESSION_ERROR; + + session->callingSessionSelector = message->buffer[offset++] * 0x100; + session->callingSessionSelector += message->buffer[offset++]; + break; + case 52: /* Called Session Selector */ + if (DEBUG_SESSION) + printf("SESSION: Parameter - Called Session Selector\n"); + + if (parameterLength != 2) + return SESSION_ERROR; + + session->calledSessionSelector = message->buffer[offset++] * 0x100; + session->calledSessionSelector += message->buffer[offset++]; + break; + case 60: /* Data Overflow */ + if (DEBUG_SESSION) + printf("SESSION: Parameter - Data Overflow\n"); + offset += parameterLength; + break; + case 193: /* User Data */ + if (DEBUG_SESSION) + printf("SESSION: PGI - user data\n"); + + /* here we should return - the remaining data is for upper layers ! */ + ByteBuffer_wrap(&session->userData, message->buffer + offset, + message->size - offset, message->maxSize - offset); + + return SESSION_OK; + + case 194: /* Extended User Data */ + if (DEBUG_SESSION) + printf("SESSION: PGI - extended user data\n"); + break; + default: + if (DEBUG_SESSION) + printf("SESSION: invalid parameter/PGI\n"); + break; + } + } + + return SESSION_ERROR; +} + +static const uint8_t dataSpdu[] = { 0x01, 0x00, 0x01, 0x00 }; + +void +IsoSession_createDataSpdu(IsoSession* session, BufferChain buffer, BufferChain payload) +{ + buffer->buffer = (uint8_t*) dataSpdu; + buffer->partLength = 4; + buffer->length = 4 + payload->length; + buffer->nextPart = payload; +} + +static int +encodeConnectAcceptItem(uint8_t* buf, int offset, uint8_t options) +{ + buf[offset++] = 5; + buf[offset++] = 6; + buf[offset++] = 0x13; /* Protocol Options */ + buf[offset++] = 1; + buf[offset++] = options; + buf[offset++] = 0x16; /* Version Number */ + buf[offset++] = 1; + buf[offset++] = 2; /* Version = 2 */ + + return offset; +} + +static int +encodeSessionRequirement(IsoSession* self, uint8_t* buf, int offset) +{ + buf[offset++] = 0x14; + buf[offset++] = 2; + buf[offset++] = (uint8_t) (self->sessionRequirement / 0x100); + buf[offset++] = (uint8_t) (self->sessionRequirement & 0x00ff); + + return offset; +} + +static int +encodeCallingSessionSelector(IsoSession* self, uint8_t* buf, int offset) +{ + buf[offset++] = 0x33; + buf[offset++] = 2; + buf[offset++] = (uint8_t) (self->callingSessionSelector / 0x100); + buf[offset++] = (uint8_t) (self->callingSessionSelector & 0x00ff); + + return offset; +} + +static int +encodeCalledSessionSelector(IsoSession* self, uint8_t* buf, int offset) +{ + buf[offset++] = 0x34; + buf[offset++] = 2; + buf[offset++] = (uint8_t) (self->calledSessionSelector / 0x100); + buf[offset++] = (uint8_t) (self->calledSessionSelector & 0x00ff); + + return offset; +} + +static int +encodeSessionUserData(IsoSession* self, uint8_t* buf, int offset, uint8_t payloadLength) +{ + buf[offset++] = 0xc1; + buf[offset++] = payloadLength; + + return offset; +} + +void +IsoSession_createConnectSpdu(IsoSession* self, IsoConnectionParameters isoParameters, BufferChain buffer, BufferChain payload) +{ + int offset = 0; + uint8_t* buf = buffer->buffer; + int lengthOffset; + + buf[offset++] = 13; /* CONNECT SPDU */ + lengthOffset = offset; + offset++; /* Skip byte for length - fill it later */ + + self->calledSessionSelector = isoParameters->remoteSSelector; + self->callingSessionSelector = isoParameters->localSSelector; + + offset = encodeConnectAcceptItem(buf, offset, 0); + + offset = encodeSessionRequirement(self, buf, offset); + + offset = encodeCallingSessionSelector(self, buf, offset); + + offset = encodeCalledSessionSelector(self, buf, offset); + + offset = encodeSessionUserData(self, buf, offset, payload->length); + + int spduLength = (offset - lengthOffset - 1) + payload->length; + + buf[lengthOffset] = spduLength; + + buffer->partLength = offset; + buffer->length = offset + payload->length; + buffer->nextPart = payload; +} + +void +IsoSession_createAbortSpdu(IsoSession* self, BufferChain buffer, BufferChain payload) +{ + int offset = 0; + uint8_t* buf = buffer->buffer; + + buf[offset++] = 25; /* ABORT-SPDU code */ + buf[offset++] = 5 + payload->length; /* LI */ + buf[offset++] = 17; /* PI-Code transport-disconnect */ + buf[offset++] = 1; /* LI = 1 */ + buf[offset++] = 11; /* transport-connection-released | user-abort | no-reason */ + buf[offset++] = 193; /* PGI-Code user data */ + buf[offset++] = payload->length; /* LI of user data */ + + buffer->partLength = offset; + buffer->length = payload->length + offset; + buffer->nextPart = payload; +} + +void +IsoSession_createFinishSpdu(IsoSession* self, BufferChain buffer, BufferChain payload) +{ + int offset = 0; + uint8_t* buf = buffer->buffer; + + buf[offset++] = 9; /* FINISH-SPDU code */ + + buf[offset++] = 2 + payload->length; /* LI */ + buf[offset++] = 193; /* PGI-Code user data */ + buf[offset++] = payload->length; /* LI of user data */ + + buffer->partLength = offset; + buffer->length = payload->length + offset; + buffer->nextPart = payload; +} + +void +IsoSession_createDisconnectSpdu(IsoSession* self, BufferChain buffer, BufferChain payload) +{ + int offset = 0; + uint8_t* buf = buffer->buffer; + + buf[offset++] = 10; /* DISCONNECT-SPDU code */ + + buf[offset++] = 2 + payload->length; /* LI */ + buf[offset++] = 193; /* PGI-Code user data */ + buf[offset++] = payload->length; /* LI of user data */ + + buffer->partLength = offset; + buffer->length = payload->length + offset; + buffer->nextPart = payload; +} + +void +IsoSession_createAcceptSpdu(IsoSession* self, BufferChain buffer, BufferChain payload) +{ + int offset = 0; + uint8_t* buf = buffer->buffer; + int lengthOffset; + + int payloadLength = payload->length; + + buf[offset++] = 14; /* ACCEPT SPDU */ + lengthOffset = offset; + offset++; + + offset = encodeConnectAcceptItem(buf, offset, self->protocolOptions); + + offset = encodeSessionRequirement(self, buf, offset); + + offset = encodeCalledSessionSelector(self, buf, offset); + + offset = encodeSessionUserData(self, buf, offset, payloadLength); + + int spduLength = (offset - lengthOffset - 1) + payloadLength; + + buf[lengthOffset] = spduLength; + + buffer->partLength = offset; + buffer->length = offset + payloadLength; + buffer->nextPart = payload; +} + +void +IsoSession_init(IsoSession* session) +{ + memset(session, 0, sizeof(IsoSession)); + session->sessionRequirement = 0x0002; /* default = duplex functional unit */ + session->callingSessionSelector = 0x0001; + session->calledSessionSelector = 0x0001; +} + +ByteBuffer* +IsoSession_getUserData(IsoSession* session) +{ + return &session->userData; +} + +IsoSessionIndication +IsoSession_parseMessage(IsoSession* session, ByteBuffer* message) +{ + uint8_t* buffer = message->buffer; + uint8_t id; + uint8_t length; + + if (message->size > 1) { + id = buffer[0]; + length = buffer[1]; + } + else + return SESSION_ERROR; + + switch (id) { + case 13: /* CONNECT(CN) SPDU */ + if (length != (message->size - 2)) + return SESSION_ERROR; + if (parseSessionHeaderParameters(session, message, length) == SESSION_OK) + return SESSION_CONNECT; + else { + if (DEBUG_SESSION) + printf("SESSION: error parsing connect spdu\n"); + return SESSION_ERROR; + } + break; + case 14: /* ACCEPT SPDU */ + if (length != (message->size - 2)) + return SESSION_ERROR; + if (parseSessionHeaderParameters(session, message, length) == SESSION_OK) + return SESSION_CONNECT; + else { + if (DEBUG_SESSION) + printf("SESSION: error parsing accept spdu\n"); + return SESSION_ERROR; + } + + break; + case 1: /* Give token / data SPDU */ + if (message->size < 4) + return SESSION_ERROR; + + if ((length == 0) && (buffer[2] == 1) && (buffer[3] == 0)) { + ByteBuffer_wrap(&session->userData, message->buffer + 4, message->size - 4, message->maxSize - 4); + + return SESSION_DATA; + } + return SESSION_ERROR; + + case 8: /* NOT-FINISHED SPDU */ + return SESSION_NOT_FINISHED; + + case 9: /* FINISH SPDU */ + if (DEBUG_SESSION) + printf("SESSION: recvd FINISH SPDU\n"); + + if (length != (message->size - 2)) + return SESSION_ERROR; + + if (parseSessionHeaderParameters(session, message, length) == SESSION_OK) + return SESSION_FINISH; + else + return SESSION_ERROR; + + break; + + case 10: /* DISCONNECT SPDU */ + if (DEBUG_SESSION) + printf("SESSION: recvd DISCONNECT SPDU\n"); + + if (length != (message->size - 2)) + return SESSION_ERROR; + + if (parseSessionHeaderParameters(session, message, length) == SESSION_OK) + return SESSION_DISCONNECT; + else + return SESSION_ERROR; + + break; + + case 25: /* ABORT SPDU */ + return SESSION_ABORT; + + default: + break; + } + + return SESSION_ERROR; +} + diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def new file mode 100644 index 0000000..9b30b7d --- /dev/null +++ b/src/vs/libiec61850-wo-goose.def @@ -0,0 +1,497 @@ +EXPORTS + Asn1PrimitivaValue_compare @13 + Asn1PrimitiveValue_clone @14 + Asn1PrimitiveValue_create @15 + Asn1PrimitiveValue_destroy @16 + Asn1PrimitiveValue_getMaxSize @17 + Asn1PrimitiveValue_getSize @18 + CAC_Point_create @90 + CAC_ScaledValueConfig_create @91 + CAC_Unit_create @92 + CAC_ValWithTrans_create @93 + CAC_Vector_create @94 + CDC_ACD_create @95 + CDC_ACT_create @96 + CDC_ASG_create @97 + CDC_BCR_create @98 + CDC_BSC_create @99 + CDC_CMV_create @100 + CDC_DEL_create @101 + CDC_DPC_create @102 + CDC_DPS_create @103 + CDC_ENC_create @104 + CDC_ENG_create @105 + CDC_ENS_create @106 + CDC_HST_create @107 + CDC_INC_create @108 + CDC_ING_create @109 + CDC_INS_create @110 + CDC_LPL_create @111 + CDC_MV_create @112 + CDC_SAV_create @113 + CDC_SEC_create @114 + CDC_SPC_create @115 + CDC_SPG_create @116 + CDC_SPS_create @117 + CDC_WYE_create @118 + ClientConnection_getPeerAddress @129 + ClientConnection_getSecurityToken @130 + ClientDataSet_destroy @131 + ClientDataSet_getDataSetSize @132 + ClientDataSet_getReference @133 + ClientDataSet_getValues @134 + ClientReportControlBlock_create @156 + ClientReportControlBlock_destroy @157 + ClientReportControlBlock_getBufTm @158 + ClientReportControlBlock_getDataSetReference @160 + ClientReportControlBlock_getEntryId @161 + ClientReportControlBlock_getEntryTime @162 + ClientReportControlBlock_getGI @163 + ClientReportControlBlock_getIntgPd @164 + ClientReportControlBlock_getObjectReference @165 + ClientReportControlBlock_getOptFlds @166 + ClientReportControlBlock_getOwner @167 + ClientReportControlBlock_getPurgeBuf @168 + ClientReportControlBlock_getResv @169 + ClientReportControlBlock_getResvTms @170 + ClientReportControlBlock_getRptEna @171 + ClientReportControlBlock_getRptId @172 + ClientReportControlBlock_getSqNum @173 + ClientReportControlBlock_getTrgOps @174 + ClientReportControlBlock_isBuffered @175 + ClientReportControlBlock_setBufTm @176 + ClientReportControlBlock_setDataSetReference @177 + ClientReportControlBlock_setEntryId @178 + ClientReportControlBlock_setGI @179 + ClientReportControlBlock_setIntgPd @180 + ClientReportControlBlock_setOptFlds @181 + ClientReportControlBlock_setPurgeBuf @182 + ClientReportControlBlock_setResv @183 + ClientReportControlBlock_setResvTms @184 + ClientReportControlBlock_setRptEna @185 + ClientReportControlBlock_setRptId @186 + ClientReportControlBlock_setTrgOps @187 + ClientReport_create @188 + ClientReport_destroy @189 + ClientReport_getDataSetValues + ClientReport_getEntryId @191 + ClientReport_getRcbReference @192 + ClientReport_getReasonForInclusion @193 + ClientReport_getTimestamp @194 + ClientReport_hasTimestamp @195 + ClientReport_getRptId + ConfigFileParser_createModelFromConfigFile @210 + ControlObjectClient_cancel @211 + ControlObjectClient_create @212 + ControlObjectClient_destroy @213 + ControlObjectClient_enableInterlockCheck @214 + ControlObjectClient_enableSynchroCheck @215 + ControlObjectClient_getControlModel @216 + ControlObjectClient_getLastApplError @217 + ControlObjectClient_getObjectReference @218 + ControlObjectClient_operate @219 + ControlObjectClient_select @220 + ControlObjectClient_selectWithValue @221 + ControlObjectClient_setLastApplError @222 + ControlObjectClient_setCommandTerminationHandler + DataAttribute_create @273 + DataObject_create @274 + DataObject_hasFCData @275 + DataSetEntry_create @276 + DataSet_create @277 + FileDirectoryEntry_create @291 + FileDirectoryEntry_destroy @292 + FileDirectoryEntry_getFileName @293 + FileDirectoryEntry_getFileSize @294 + FileDirectoryEntry_getLastModified @295 + FileSystem_closeDirectory @296 + FileSystem_closeFile @297 + FileSystem_deleteFile @298 + FileSystem_getFileInfo @299 + FileSystem_openDirectory @300 + FileSystem_openFile @301 + FileSystem_readDirectory @302 + FileSystem_readFile @303 + FileSystem_renameFile @304 + FileSystem_setBasePath @305 + FunctionalConstraint_fromString @313 + FunctionalConstraint_toString @314 + GSEControlBlock_create @316 + Hal_getTimeInMs @354 + IedConnection_abort @366 + IedConnection_close @367 + IedConnection_connect @368 + IedConnection_create @369 + IedConnection_createDataSet @370 + IedConnection_deleteDataSet @371 + IedConnection_deleteFile @372 + IedConnection_destroy @373 + IedConnection_getDataDirectory @376 + IedConnection_getDataDirectoryFC @377 + IedConnection_getDataSetDirectory @378 + IedConnection_getDeviceModelFromServer @379 + IedConnection_getFile @380 + IedConnection_getFileDirectory @381 + IedConnection_getLastApplError @383 + IedConnection_getLogicalDeviceDirectory @384 + IedConnection_getLogicalDeviceList @385 + IedConnection_getLogicalNodeDirectory @386 + IedConnection_getLogicalNodeVariables @387 + IedConnection_getMmsConnection @388 + IedConnection_getRCBValues @389 + IedConnection_getServerDirectory @390 + IedConnection_getState @391 + IedConnection_getVariableSpecification @392 + IedConnection_installConnectionClosedHandler @393 + IedConnection_installReportHandler @394 + IedConnection_readDataSetValues @395 + IedConnection_readObject @396 + IedConnection_release @397 + IedConnection_setRCBValues @401 + IedConnection_triggerGIReport @402 + IedConnection_uninstallReportHandler @403 + IedConnection_writeObject @404 + IedModel_create @405 + IedModel_destroy @406 + IedModel_getDevice @407 + IedModel_getLogicalDeviceCount @408 + IedModel_getModelNodeByObjectReference @409 + IedModel_getModelNodeByShortAddress @410 + IedModel_lookupDataSet @411 + IedModel_setAttributeValuesToNull @412 + IedServer_create @413 + IedServer_destroy @414 + IedServer_getAttributeValue @416 + IedServer_getDataModel @417 + IedServer_getFunctionalConstrainedData @418 + IedServer_getIsoServer @419 + IedServer_getMmsServer @420 + IedServer_handleWriteAccess @421 + IedServer_isRunning @422 + IedServer_lockDataModel @423 + IedServer_observeDataAttribute @424 + IedServer_setAuthenticator @425 + IedServer_setConnectionIndicationHandler @426 + IedServer_setControlHandler @427 + IedServer_setPerformCheckHandler @428 + IedServer_setWaitForExecutionHandler @429 + IedServer_setWriteAccessPolicy @430 + IedServer_start @431 + IedServer_stop @432 + IedServer_unlockDataModel @433 + IedServer_updateAttributeValue @434 + IedServer_updateBitStringAttributeValue @435 + IedServer_updateBooleanAttributeValue @436 + IedServer_updateFloatAttributeValue @437 + IedServer_updateInt32AttributeValue @438 + IedServer_updateQuality @439 + IedServer_updateUTCTimeAttributeValue @440 + IedServer_updateUnsignedAttributeValue @441 + IsoConnectionParameters_create @479 + IsoConnectionParameters_destroy @480 + IsoConnectionParameters_setAcseAuthenticationParameter @481 + IsoConnectionParameters_setLocalAddresses @482 + IsoConnectionParameters_setLocalApTitle @483 + IsoConnectionParameters_setRemoteAddresses @484 + IsoConnectionParameters_setRemoteApTitle @485 + IsoConnectionParameters_setTcpParameters @486 + IsoConnection_close @487 + IsoConnection_create @488 + IsoConnection_getPeerAddress @489 + IsoConnection_getSecurityToken @490 + IsoServer_closeConnection @502 + IsoServer_create @503 + IsoServer_destroy @504 + IsoServer_getAuthenticator @505 + IsoServer_getAuthenticatorParameter @506 + IsoServer_getState @507 + IsoServer_setAuthenticator @508 + IsoServer_setConnectionHandler @509 + IsoServer_setLocalIpAddress @510 + IsoServer_setTcpPort @511 + IsoServer_startListening @512 + IsoServer_stopListening @513 + LinkedList_add @523 + LinkedList_create @524 + LinkedList_destroy @525 + LinkedList_destroyDeep @526 + LinkedList_destroyStatic @527 + LinkedList_get @528 + LinkedList_getLastElement @529 + LinkedList_getNext @530 + LinkedList_insertAfter @531 + LinkedList_printStringList @532 + LinkedList_remove @533 + LinkedList_size @534 + LinkedList_getData + LogicalDevice_create @535 + LogicalDevice_getLogicalNodeCount @537 + LogicalNode_create @538 + LogicalNode_hasFCData @539 + MmsConnection_abort @559 + MmsConnection_conclude @560 + MmsConnection_connect @561 + MmsConnection_create @562 + MmsConnection_defineNamedVariableList @563 + MmsConnection_defineNamedVariableListAssociationSpecific @564 + MmsConnection_deleteAssociationSpecificNamedVariableList @565 + MmsConnection_deleteNamedVariableList @566 + MmsConnection_destroy @567 + MmsConnection_fileClose @568 + MmsConnection_fileDelete @569 + MmsConnection_fileOpen @570 + MmsConnection_fileRead @571 + MmsConnection_fileRename @572 + MmsConnection_getDomainNames @573 + MmsConnection_getDomainVariableListNames @574 + MmsConnection_getDomainVariableNames @575 + MmsConnection_getFileDirectory @576 + MmsConnection_getIsoConnectionParameters @577 + MmsConnection_getLocalDetail @578 + MmsConnection_getServerStatus @579 + MmsConnection_getVMDVariableNames @580 + MmsConnection_getVariableAccessAttributes @581 + MmsConnection_getVariableListNamesAssociationSpecific @582 + MmsConnection_identify @583 + MmsConnection_readArrayElements @584 + MmsConnection_readMultipleVariables @585 + MmsConnection_readNamedVariableListDirectory @586 + MmsConnection_readNamedVariableListDirectoryAssociationSpecific @587 + MmsConnection_readNamedVariableListValues @588 + MmsConnection_readNamedVariableListValuesAssociationSpecific @589 + MmsConnection_readVariable @590 + MmsConnection_setConnectionLostHandler @591 + MmsConnection_setInformationReportHandler @592 + MmsConnection_setLocalDetail @593 + MmsConnection_setRequestTimeout @594 + MmsConnection_writeMultipleVariables @595 + MmsConnection_writeVariable @596 + MmsDevice_create @597 + MmsDevice_destroy @598 + MmsDevice_getDomain @599 + MmsDomain_addNamedVariableList @600 + MmsDomain_create @601 + MmsDomain_deleteNamedVariableList @602 + MmsDomain_destroy @603 + MmsDomain_getName @604 + MmsDomain_getNamedVariable @605 + MmsDomain_getNamedVariableList @606 + MmsDomain_getNamedVariableLists @607 + MmsServerIdentity_destroy @669 + MmsServer_create @670 + MmsServer_destroy @671 + MmsServer_getDevice @672 + MmsServer_getModelName @673 + MmsServer_getRevision @674 + MmsServer_getVMDLogicalStatus @675 + MmsServer_getVMDPhysicalStatus @676 + MmsServer_getValueFromCache @677 + MmsServer_getVendorName @678 + MmsServer_insertIntoCache @679 + MmsServer_installConnectionHandler @680 + MmsServer_installReadHandler @681 + MmsServer_installWriteHandler @682 + MmsServer_lockModel @683 + MmsServer_setClientAuthenticator @684 + MmsServer_setServerIdentity @686 + MmsServer_setStatusRequestListener @687 + MmsServer_setVMDStatus @688 + MmsServer_startListening @689 + MmsServer_stopListening @690 + MmsServer_unlockModel @691 + MmsValue_clone @696 + MmsValue_cloneToBuffer @697 + MmsValue_createArray @698 + MmsValue_createEmptyStructure @699 + MmsValue_createEmptyArray @700 + MmsValue_delete @701 + MmsValue_deleteAllBitStringBits @702 + MmsValue_deleteConditional @703 + MmsValue_deleteIfNotNull @704 + MmsValue_equalTypes @705 + MmsValue_equals @706 + MmsValue_getArraySize @707 + MmsValue_getBinaryTimeAsUtcMs @708 + MmsValue_getBitStringAsInteger @709 + MmsValue_getBitStringBit @710 + MmsValue_getBitStringByteSize @711 + MmsValue_getBitStringSize @712 + MmsValue_getBoolean @713 + MmsValue_getDataAccessError @714 + MmsValue_getElement @715 + MmsValue_getNumberOfSetBits @716 + MmsValue_getOctetStringBuffer @717 + MmsValue_getOctetStringMaxSize @718 + MmsValue_getOctetStringSize @719 + MmsValue_getSizeInMemory @720 + MmsValue_getSubElement @721 + MmsValue_getType @722 + MmsValue_getUtcTimeInMs @723 + MmsValue_isDeletable @724 + MmsValue_newBinaryTime @726 + MmsValue_newBitString @727 + MmsValue_newBoolean @728 + MmsValue_newDataAccessError @729 + MmsValue_newDefaultValue @730 + MmsValue_newDouble @731 + MmsValue_newFloat @732 + MmsValue_newInteger @733 + MmsValue_newIntegerFromBerInteger @734 + MmsValue_newIntegerFromInt16 @735 + MmsValue_newIntegerFromInt32 @736 + MmsValue_newIntegerFromInt64 @737 + MmsValue_newMmsString @738 + MmsValue_newOctetString @739 + MmsValue_newStructure @740 + MmsValue_newUnsigned @741 + MmsValue_newUnsignedFromBerInteger @742 + MmsValue_newUnsignedFromUint32 @743 + MmsValue_newUtcTime @744 + MmsValue_newUtcTimeByMsTime @745 + MmsValue_newVisibleString @746 + MmsValue_newVisibleStringFromByteArray @747 + MmsValue_setAllBitStringBits @748 + MmsValue_setBinaryTime @749 + MmsValue_setBitStringBit @750 + MmsValue_setBitStringFromInteger @751 + MmsValue_setBoolean @752 + MmsValue_setDeletable @753 + MmsValue_setDeletableRecursive @754 + MmsValue_setDouble @755 + MmsValue_setElement @756 + MmsValue_setFloat @757 + MmsValue_setInt32 @758 + MmsValue_setInt64 @759 + MmsValue_setMmsString @760 + MmsValue_setOctetString @761 + MmsValue_setUint16 @762 + MmsValue_setUint32 @763 + MmsValue_setUint8 @764 + MmsValue_setUtcTime @765 + MmsValue_setUtcTimeByBuffer @766 + MmsValue_setUtcTimeMs @767 + MmsValue_setVisibleString @768 + MmsValue_toDouble @769 + MmsValue_toFloat @770 + MmsValue_toInt32 @771 + MmsValue_toInt64 @772 + MmsValue_toString @773 + MmsValue_toUint32 @774 + MmsValue_toUnixTimestamp @775 + MmsValue_update @776 + MmsValue_getBitStringAsIntegerBigEndian + MmsValue_setBitStringFromIntegerBigEndian + MmsVariableAccessSpecification_create @777 + MmsVariableAccessSpecification_createAlternateAccess @778 + MmsVariableAccessSpecification_destroy @779 + MmsVariableSpecification_destroy @780 + MmsVariableSpecification_getArrayElementSpecification @781 + MmsVariableSpecification_getChildSpecificationByIndex @782 + MmsVariableSpecification_getChildValue @783 + MmsVariableSpecification_getExponentWidth @784 + MmsVariableSpecification_getName @785 + MmsVariableSpecification_getSize @786 + MmsVariableSpecification_getStructureElements @787 + MmsVariableSpecification_getType @788 + MmsVariableSpecification_getNamedVariableRecursive + ModelNode_getChild @789 + ModelNode_getChildCount @790 + ModelNode_getObjectReference @791 + PhyComAddress_create @827 + Quality_fromMmsValue @828 + Quality_getValidity @829 + Quality_isFlagSet @830 + Quality_setFlag @831 + Quality_setValidity @832 + Quality_unsetFlag @833 + Thread_create @893 + Thread_destroy @894 + Thread_sleep @895 + Thread_start @896 + ReportControlBlock_create + IedConnection_readBooleanValue + IedConnection_readFloatValue + IedConnection_readStringValue + IedConnection_readInt32Value + IedConnection_readUnsigned32Value + IedConnection_readTimestampValue + IedConnection_readQualityValue + IedConnection_writeBooleanValue + IedConnection_writeInt32Value + IedConnection_writeUnsigned32Value + IedConnection_writeFloatValue + IedConnection_writeVisibleStringValue + IedConnection_writeOctetString + Timestamp_getTimeInSeconds + Timestamp_getTimeInMs + Timestamp_isLeapSecondKnown + Timestamp_setLeapSecondKnown + Timestamp_hasClockFailure + Timestamp_setClockFailure + Timestamp_isClockNotSynchronized + Timestamp_setClockNotSynchronized + Timestamp_getSubsecondPrecision + Timestamp_setSubsecondPrecision + Timestamp_setTimeInSeconds + Timestamp_setTimeInMilliseconds + MmsValue_getTypeString + IedModel_getModelNodeByShortObjectReference + ClientReportControlBlock_getConfRev + MmsValue_newIntegerFromInt8 + AcseAuthenticationParameter_create + AcseAuthenticationParameter_destroy + AcseAuthenticationParameter_setAuthMechanism + AcseAuthenticationParameter_setPassword + IedServer_startThreadless + IedServer_processIncomingData + IedServer_performPeriodicTasks + IedServer_stopThreadless + Dbpos_fromMmsValue + Dbpos_toMmsValue + SettingGroupControlBlock_create + MmsConnection_setConnectTimeout + IedConnection_setConnectTimeout + MmsValue_newVisibleStringWithSize + MmsValue_newMmsStringWithSize + MmsValue_setInt8 + MmsValue_setInt16 + LogicalDevice_getSettingGroupControlBlock + IedServer_changeActiveSettingGroup + IedServer_setActiveSettingGroupChangedHandler + IedServer_disableGoosePublishing + IedServer_setEditSettingGroupChangedHandler + IedServer_setEditSettingGroupConfirmationHandler + IedConnection_getDataDirectoryByFC + IedServer_getActiveSettingGroup + ClientReport_hasSeqNum + ClientReport_getSeqNum + ClientReport_hasDataSetName + ClientReport_hasReasonForInclusion + ClientReport_hasConfRev + ClientReport_getConfRev + ClientReport_hasBufOvfl + ClientReport_hasDataReference + LibIEC61850_getVersionString + ClientReport_getDataReference + IedServer_getBooleanAttributeValue + IedServer_getInt32AttributeValue + IedServer_getInt64AttributeValue + IedServer_getUInt32AttributeValue + IedServer_getFloatAttributeValue + IedServer_getUTCTimeAttributeValue + IedServer_getBitStringAttributeValue + IedServer_getStringAttributeValue + ModelNode_getChildWithFc + IedServer_updateTimestampAttributeValue + MmsValue_getUtcTimeBuffer + Timestamp_clearFlags + IedServer_setGooseInterfaceId + ClientReport_getBufOvfl + MmsValue_getUtcTimeInMsWithUs + IedModel_setIedNameForDynamicModel + ControlObjectClient_useConstantT + ControlObjectClient_setOrigin + LogicalDevice_getChildByMmsVariableName + LogicalNode_getDataSet + ClientReport_getDataSetName + MmsValue_getStringSize \ No newline at end of file diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def new file mode 100644 index 0000000..a88a7fc --- /dev/null +++ b/src/vs/libiec61850.def @@ -0,0 +1,521 @@ +EXPORTS + Asn1PrimitivaValue_compare @13 + Asn1PrimitiveValue_clone @14 + Asn1PrimitiveValue_create @15 + Asn1PrimitiveValue_destroy @16 + Asn1PrimitiveValue_getMaxSize @17 + Asn1PrimitiveValue_getSize @18 + CAC_Point_create @90 + CAC_ScaledValueConfig_create @91 + CAC_Unit_create @92 + CAC_ValWithTrans_create @93 + CAC_Vector_create @94 + CDC_ACD_create @95 + CDC_ACT_create @96 + CDC_ASG_create @97 + CDC_BCR_create @98 + CDC_BSC_create @99 + CDC_CMV_create @100 + CDC_DEL_create @101 + CDC_DPC_create @102 + CDC_DPS_create @103 + CDC_ENC_create @104 + CDC_ENG_create @105 + CDC_ENS_create @106 + CDC_HST_create @107 + CDC_INC_create @108 + CDC_ING_create @109 + CDC_INS_create @110 + CDC_LPL_create @111 + CDC_MV_create @112 + CDC_SAV_create @113 + CDC_SEC_create @114 + CDC_SPC_create @115 + CDC_SPG_create @116 + CDC_SPS_create @117 + CDC_WYE_create @118 + ClientConnection_getPeerAddress @129 + ClientConnection_getSecurityToken @130 + ClientDataSet_destroy @131 + ClientDataSet_getDataSetSize @132 + ClientDataSet_getReference @133 + ClientDataSet_getValues @134 + ClientReportControlBlock_create @156 + ClientReportControlBlock_destroy @157 + ClientReportControlBlock_getBufTm @158 + ClientReportControlBlock_getDataSetReference @160 + ClientReportControlBlock_getEntryId @161 + ClientReportControlBlock_getEntryTime @162 + ClientReportControlBlock_getGI @163 + ClientReportControlBlock_getIntgPd @164 + ClientReportControlBlock_getObjectReference @165 + ClientReportControlBlock_getOptFlds @166 + ClientReportControlBlock_getOwner @167 + ClientReportControlBlock_getPurgeBuf @168 + ClientReportControlBlock_getResv @169 + ClientReportControlBlock_getResvTms @170 + ClientReportControlBlock_getRptEna @171 + ClientReportControlBlock_getRptId @172 + ClientReportControlBlock_getSqNum @173 + ClientReportControlBlock_getTrgOps @174 + ClientReportControlBlock_isBuffered @175 + ClientReportControlBlock_setBufTm @176 + ClientReportControlBlock_setDataSetReference @177 + ClientReportControlBlock_setEntryId @178 + ClientReportControlBlock_setGI @179 + ClientReportControlBlock_setIntgPd @180 + ClientReportControlBlock_setOptFlds @181 + ClientReportControlBlock_setPurgeBuf @182 + ClientReportControlBlock_setResv @183 + ClientReportControlBlock_setResvTms @184 + ClientReportControlBlock_setRptEna @185 + ClientReportControlBlock_setRptId @186 + ClientReportControlBlock_setTrgOps @187 + ClientReport_create @188 + ClientReport_destroy @189 + ClientReport_getDataSetValues + ClientReport_getEntryId @191 + ClientReport_getRcbReference @192 + ClientReport_getReasonForInclusion @193 + ClientReport_getTimestamp @194 + ClientReport_hasTimestamp @195 + ClientReport_getRptId + ConfigFileParser_createModelFromConfigFile @210 + ControlObjectClient_cancel @211 + ControlObjectClient_create @212 + ControlObjectClient_destroy @213 + ControlObjectClient_enableInterlockCheck @214 + ControlObjectClient_enableSynchroCheck @215 + ControlObjectClient_getControlModel @216 + ControlObjectClient_getLastApplError @217 + ControlObjectClient_getObjectReference @218 + ControlObjectClient_operate @219 + ControlObjectClient_select @220 + ControlObjectClient_selectWithValue @221 + ControlObjectClient_setLastApplError @222 + ControlObjectClient_setCommandTerminationHandler + DataAttribute_create @273 + DataObject_create @274 + DataObject_hasFCData @275 + DataSetEntry_create @276 + DataSet_create @277 + FileDirectoryEntry_create @291 + FileDirectoryEntry_destroy @292 + FileDirectoryEntry_getFileName @293 + FileDirectoryEntry_getFileSize @294 + FileDirectoryEntry_getLastModified @295 + FileSystem_closeDirectory @296 + FileSystem_closeFile @297 + FileSystem_deleteFile @298 + FileSystem_getFileInfo @299 + FileSystem_openDirectory @300 + FileSystem_openFile @301 + FileSystem_readDirectory @302 + FileSystem_readFile @303 + FileSystem_renameFile @304 + FileSystem_setBasePath @305 + FunctionalConstraint_fromString @313 + FunctionalConstraint_toString @314 + GSEControlBlock_create @316 + GoosePublisher_create @328 + GoosePublisher_destroy @329 + GoosePublisher_increaseStNum @330 + GoosePublisher_publish @331 + GoosePublisher_reset @332 + GoosePublisher_setConfRev @333 + GoosePublisher_setDataSetRef @334 + GoosePublisher_setGoCbRef @335 + GoosePublisher_setGoID @336 + GoosePublisher_setNeedsCommission @337 + GoosePublisher_setSimulation @338 + GoosePublisher_setTimeAllowedToLive @339 + GooseSubscriber_create @340 + GooseSubscriber_destroy @341 + GooseSubscriber_getDataSetValues @342 + GooseSubscriber_getSqNum @343 + GooseSubscriber_getStNum @344 + GooseSubscriber_getTimeAllowedToLive @345 + GooseSubscriber_getTimestamp @346 + GooseSubscriber_isTest @347 + GooseSubscriber_needsCommission @348 + GooseSubscriber_setAppId @349 + GooseSubscriber_setListener @351 + Hal_getTimeInMs @354 + IedConnection_abort @366 + IedConnection_close @367 + IedConnection_connect @368 + IedConnection_create @369 + IedConnection_createDataSet @370 + IedConnection_deleteDataSet @371 + IedConnection_deleteFile @372 + IedConnection_destroy @373 + IedConnection_getDataDirectory @376 + IedConnection_getDataDirectoryFC @377 + IedConnection_getDataSetDirectory @378 + IedConnection_getDeviceModelFromServer @379 + IedConnection_getFile @380 + IedConnection_getFileDirectory @381 + IedConnection_getLastApplError @383 + IedConnection_getLogicalDeviceDirectory @384 + IedConnection_getLogicalDeviceList @385 + IedConnection_getLogicalNodeDirectory @386 + IedConnection_getLogicalNodeVariables @387 + IedConnection_getMmsConnection @388 + IedConnection_getRCBValues @389 + IedConnection_getServerDirectory @390 + IedConnection_getState @391 + IedConnection_getVariableSpecification @392 + IedConnection_installConnectionClosedHandler @393 + IedConnection_installReportHandler @394 + IedConnection_readDataSetValues @395 + IedConnection_readObject @396 + IedConnection_release @397 + IedConnection_setRCBValues @401 + IedConnection_triggerGIReport @402 + IedConnection_uninstallReportHandler @403 + IedConnection_writeObject @404 + IedModel_create @405 + IedModel_destroy @406 + IedModel_getDevice @407 + IedModel_getLogicalDeviceCount @408 + IedModel_getModelNodeByObjectReference @409 + IedModel_getModelNodeByShortAddress @410 + IedModel_lookupDataSet @411 + IedModel_setAttributeValuesToNull @412 + IedServer_create @413 + IedServer_destroy @414 + IedServer_enableGoosePublishing @415 + IedServer_getAttributeValue @416 + IedServer_getDataModel @417 + IedServer_getFunctionalConstrainedData @418 + IedServer_getIsoServer @419 + IedServer_getMmsServer @420 + IedServer_handleWriteAccess @421 + IedServer_isRunning @422 + IedServer_lockDataModel @423 + IedServer_observeDataAttribute @424 + IedServer_setAuthenticator @425 + IedServer_setConnectionIndicationHandler @426 + IedServer_setControlHandler @427 + IedServer_setPerformCheckHandler @428 + IedServer_setWaitForExecutionHandler @429 + IedServer_setWriteAccessPolicy @430 + IedServer_start @431 + IedServer_stop @432 + IedServer_unlockDataModel @433 + IedServer_updateAttributeValue @434 + IedServer_updateBitStringAttributeValue @435 + IedServer_updateBooleanAttributeValue @436 + IedServer_updateFloatAttributeValue @437 + IedServer_updateInt32AttributeValue @438 + IedServer_updateQuality @439 + IedServer_updateUTCTimeAttributeValue @440 + IedServer_updateUnsignedAttributeValue @441 + IsoConnectionParameters_create @479 + IsoConnectionParameters_destroy @480 + IsoConnectionParameters_setAcseAuthenticationParameter @481 + IsoConnectionParameters_setLocalAddresses @482 + IsoConnectionParameters_setLocalApTitle @483 + IsoConnectionParameters_setRemoteAddresses @484 + IsoConnectionParameters_setRemoteApTitle @485 + IsoConnectionParameters_setTcpParameters @486 + IsoConnection_close @487 + IsoConnection_create @488 + IsoConnection_getPeerAddress @489 + IsoConnection_getSecurityToken @490 + IsoServer_closeConnection @502 + IsoServer_create @503 + IsoServer_destroy @504 + IsoServer_getAuthenticator @505 + IsoServer_getAuthenticatorParameter @506 + IsoServer_getState @507 + IsoServer_setAuthenticator @508 + IsoServer_setConnectionHandler @509 + IsoServer_setLocalIpAddress @510 + IsoServer_setTcpPort @511 + IsoServer_startListening @512 + IsoServer_stopListening @513 + LinkedList_add @523 + LinkedList_create @524 + LinkedList_destroy @525 + LinkedList_destroyDeep @526 + LinkedList_destroyStatic @527 + LinkedList_get @528 + LinkedList_getLastElement @529 + LinkedList_getNext @530 + LinkedList_insertAfter @531 + LinkedList_printStringList @532 + LinkedList_remove @533 + LinkedList_size @534 + LinkedList_getData + LogicalDevice_create @535 + LogicalDevice_getLogicalNodeCount @537 + LogicalNode_create @538 + LogicalNode_hasFCData @539 + MmsConnection_abort @559 + MmsConnection_conclude @560 + MmsConnection_connect @561 + MmsConnection_create @562 + MmsConnection_defineNamedVariableList @563 + MmsConnection_defineNamedVariableListAssociationSpecific @564 + MmsConnection_deleteAssociationSpecificNamedVariableList @565 + MmsConnection_deleteNamedVariableList @566 + MmsConnection_destroy @567 + MmsConnection_fileClose @568 + MmsConnection_fileDelete @569 + MmsConnection_fileOpen @570 + MmsConnection_fileRead @571 + MmsConnection_fileRename @572 + MmsConnection_getDomainNames @573 + MmsConnection_getDomainVariableListNames @574 + MmsConnection_getDomainVariableNames @575 + MmsConnection_getFileDirectory @576 + MmsConnection_getIsoConnectionParameters @577 + MmsConnection_getLocalDetail @578 + MmsConnection_getServerStatus @579 + MmsConnection_getVMDVariableNames @580 + MmsConnection_getVariableAccessAttributes @581 + MmsConnection_getVariableListNamesAssociationSpecific @582 + MmsConnection_identify @583 + MmsConnection_readArrayElements @584 + MmsConnection_readMultipleVariables @585 + MmsConnection_readNamedVariableListDirectory @586 + MmsConnection_readNamedVariableListDirectoryAssociationSpecific @587 + MmsConnection_readNamedVariableListValues @588 + MmsConnection_readNamedVariableListValuesAssociationSpecific @589 + MmsConnection_readVariable @590 + MmsConnection_setConnectionLostHandler @591 + MmsConnection_setInformationReportHandler @592 + MmsConnection_setLocalDetail @593 + MmsConnection_setRequestTimeout @594 + MmsConnection_writeMultipleVariables @595 + MmsConnection_writeVariable @596 + MmsDevice_create @597 + MmsDevice_destroy @598 + MmsDevice_getDomain @599 + MmsDomain_addNamedVariableList @600 + MmsDomain_create @601 + MmsDomain_deleteNamedVariableList @602 + MmsDomain_destroy @603 + MmsDomain_getName @604 + MmsDomain_getNamedVariable @605 + MmsDomain_getNamedVariableList @606 + MmsDomain_getNamedVariableLists @607 + MmsServerIdentity_destroy @669 + MmsServer_create @670 + MmsServer_destroy @671 + MmsServer_getDevice @672 + MmsServer_getModelName @673 + MmsServer_getRevision @674 + MmsServer_getVMDLogicalStatus @675 + MmsServer_getVMDPhysicalStatus @676 + MmsServer_getValueFromCache @677 + MmsServer_getVendorName @678 + MmsServer_insertIntoCache @679 + MmsServer_installConnectionHandler @680 + MmsServer_installReadHandler @681 + MmsServer_installWriteHandler @682 + MmsServer_lockModel @683 + MmsServer_setClientAuthenticator @684 + MmsServer_setServerIdentity @686 + MmsServer_setStatusRequestListener @687 + MmsServer_setVMDStatus @688 + MmsServer_startListening @689 + MmsServer_stopListening @690 + MmsServer_unlockModel @691 + MmsValue_clone @696 + MmsValue_cloneToBuffer @697 + MmsValue_createArray @698 + MmsValue_createEmptyStructure @699 + MmsValue_createEmptyArray @700 + MmsValue_delete @701 + MmsValue_deleteAllBitStringBits @702 + MmsValue_deleteConditional @703 + MmsValue_deleteIfNotNull @704 + MmsValue_equalTypes @705 + MmsValue_equals @706 + MmsValue_getArraySize @707 + MmsValue_getBinaryTimeAsUtcMs @708 + MmsValue_getBitStringAsInteger @709 + MmsValue_getBitStringBit @710 + MmsValue_getBitStringByteSize @711 + MmsValue_getBitStringSize @712 + MmsValue_getBoolean @713 + MmsValue_getDataAccessError @714 + MmsValue_getElement @715 + MmsValue_getNumberOfSetBits @716 + MmsValue_getOctetStringBuffer @717 + MmsValue_getOctetStringMaxSize @718 + MmsValue_getOctetStringSize @719 + MmsValue_getSizeInMemory @720 + MmsValue_getSubElement @721 + MmsValue_getType @722 + MmsValue_getUtcTimeInMs @723 + MmsValue_isDeletable @724 + MmsValue_newBinaryTime @726 + MmsValue_newBitString @727 + MmsValue_newBoolean @728 + MmsValue_newDataAccessError @729 + MmsValue_newDefaultValue @730 + MmsValue_newDouble @731 + MmsValue_newFloat @732 + MmsValue_newInteger @733 + MmsValue_newIntegerFromBerInteger @734 + MmsValue_newIntegerFromInt16 @735 + MmsValue_newIntegerFromInt32 @736 + MmsValue_newIntegerFromInt64 @737 + MmsValue_newMmsString @738 + MmsValue_newOctetString @739 + MmsValue_newStructure @740 + MmsValue_newUnsigned @741 + MmsValue_newUnsignedFromBerInteger @742 + MmsValue_newUnsignedFromUint32 @743 + MmsValue_newUtcTime @744 + MmsValue_newUtcTimeByMsTime @745 + MmsValue_newVisibleString @746 + MmsValue_newVisibleStringFromByteArray @747 + MmsValue_setAllBitStringBits @748 + MmsValue_setBinaryTime @749 + MmsValue_setBitStringBit @750 + MmsValue_setBitStringFromInteger @751 + MmsValue_setBoolean @752 + MmsValue_setDeletable @753 + MmsValue_setDeletableRecursive @754 + MmsValue_setDouble @755 + MmsValue_setElement @756 + MmsValue_setFloat @757 + MmsValue_setInt32 @758 + MmsValue_setInt64 @759 + MmsValue_setMmsString @760 + MmsValue_setOctetString @761 + MmsValue_setUint16 @762 + MmsValue_setUint32 @763 + MmsValue_setUint8 @764 + MmsValue_setUtcTime @765 + MmsValue_setUtcTimeByBuffer @766 + MmsValue_setUtcTimeMs @767 + MmsValue_setVisibleString @768 + MmsValue_toDouble @769 + MmsValue_toFloat @770 + MmsValue_toInt32 @771 + MmsValue_toInt64 @772 + MmsValue_toString @773 + MmsValue_toUint32 @774 + MmsValue_toUnixTimestamp @775 + MmsValue_update @776 + MmsValue_getBitStringAsIntegerBigEndian + MmsValue_setBitStringFromIntegerBigEndian + MmsVariableAccessSpecification_create @777 + MmsVariableAccessSpecification_createAlternateAccess @778 + MmsVariableAccessSpecification_destroy @779 + MmsVariableSpecification_destroy @780 + MmsVariableSpecification_getArrayElementSpecification @781 + MmsVariableSpecification_getChildSpecificationByIndex @782 + MmsVariableSpecification_getChildValue @783 + MmsVariableSpecification_getExponentWidth @784 + MmsVariableSpecification_getName @785 + MmsVariableSpecification_getSize @786 + MmsVariableSpecification_getStructureElements @787 + MmsVariableSpecification_getType @788 + MmsVariableSpecification_getNamedVariableRecursive + ModelNode_getChild @789 + ModelNode_getChildCount @790 + ModelNode_getObjectReference @791 + PhyComAddress_create @827 + Quality_fromMmsValue @828 + Quality_getValidity @829 + Quality_isFlagSet @830 + Quality_setFlag @831 + Quality_setValidity @832 + Quality_unsetFlag @833 + Thread_create @893 + Thread_destroy @894 + Thread_sleep @895 + Thread_start @896 + ReportControlBlock_create + IedConnection_readBooleanValue + IedConnection_readFloatValue + IedConnection_readStringValue + IedConnection_readInt32Value + IedConnection_readUnsigned32Value + IedConnection_readTimestampValue + IedConnection_readQualityValue + IedConnection_writeBooleanValue + IedConnection_writeInt32Value + IedConnection_writeUnsigned32Value + IedConnection_writeFloatValue + IedConnection_writeVisibleStringValue + IedConnection_writeOctetString + Timestamp_getTimeInSeconds + Timestamp_getTimeInMs + Timestamp_isLeapSecondKnown + Timestamp_setLeapSecondKnown + Timestamp_hasClockFailure + Timestamp_setClockFailure + Timestamp_isClockNotSynchronized + Timestamp_setClockNotSynchronized + Timestamp_getSubsecondPrecision + Timestamp_setSubsecondPrecision + Timestamp_setTimeInSeconds + Timestamp_setTimeInMilliseconds + MmsValue_getTypeString + IedModel_getModelNodeByShortObjectReference + ClientReportControlBlock_getConfRev + MmsValue_newIntegerFromInt8 + AcseAuthenticationParameter_create + AcseAuthenticationParameter_destroy + AcseAuthenticationParameter_setAuthMechanism + AcseAuthenticationParameter_setPassword + IedServer_startThreadless + IedServer_processIncomingData + IedServer_performPeriodicTasks + IedServer_stopThreadless + Dbpos_fromMmsValue + Dbpos_toMmsValue + SettingGroupControlBlock_create + MmsConnection_setConnectTimeout + IedConnection_setConnectTimeout + MmsValue_newVisibleStringWithSize + MmsValue_newMmsStringWithSize + MmsValue_setInt8 + MmsValue_setInt16 + LogicalDevice_getSettingGroupControlBlock + IedServer_changeActiveSettingGroup + IedServer_setActiveSettingGroupChangedHandler + IedServer_disableGoosePublishing + IedServer_setEditSettingGroupChangedHandler + IedServer_setEditSettingGroupConfirmationHandler + IedConnection_getDataDirectoryByFC + IedServer_getActiveSettingGroup + ClientReport_hasSeqNum + ClientReport_getSeqNum + ClientReport_hasDataSetName + ClientReport_hasReasonForInclusion + ClientReport_hasConfRev + ClientReport_getConfRev + ClientReport_hasBufOvfl + ClientReport_hasDataReference + LibIEC61850_getVersionString + ClientReport_getDataReference + IedServer_getBooleanAttributeValue + IedServer_getInt32AttributeValue + IedServer_getInt64AttributeValue + IedServer_getUInt32AttributeValue + IedServer_getFloatAttributeValue + IedServer_getUTCTimeAttributeValue + IedServer_getBitStringAttributeValue + IedServer_getStringAttributeValue + ModelNode_getChildWithFc + IedServer_updateTimestampAttributeValue + MmsValue_getUtcTimeBuffer + Timestamp_clearFlags + IedServer_setGooseInterfaceId + ClientReport_getBufOvfl + MmsValue_getUtcTimeInMsWithUs + IedModel_setIedNameForDynamicModel + ControlObjectClient_useConstantT + ControlObjectClient_setOrigin + LogicalDevice_getChildByMmsVariableName + LogicalNode_getDataSet + ClientReport_getDataSetName + MmsValue_getStringSize diff --git a/src/vs/stdbool.h b/src/vs/stdbool.h new file mode 100644 index 0000000..b949d59 --- /dev/null +++ b/src/vs/stdbool.h @@ -0,0 +1 @@ +// just to make Visual Studio Compiler happy! diff --git a/tools/model_generator/.classpath b/tools/model_generator/.classpath new file mode 100644 index 0000000..015a06a --- /dev/null +++ b/tools/model_generator/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tools/model_generator/.project b/tools/model_generator/.project new file mode 100644 index 0000000..4e451f8 --- /dev/null +++ b/tools/model_generator/.project @@ -0,0 +1,17 @@ + + + model_generator + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/tools/model_generator/.settings/org.eclipse.jdt.core.prefs b/tools/model_generator/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..8000cd6 --- /dev/null +++ b/tools/model_generator/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/tools/model_generator/build.sh b/tools/model_generator/build.sh new file mode 100644 index 0000000..7bca489 --- /dev/null +++ b/tools/model_generator/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +mkdir build + +find src/ -name "*.java" > listFile.tmp + +javac -target 1.6 -source 1.6 -d build @listFile.tmp + +jar cfm genmodel.jar manifest.mf -C build/ com/ + +rm listFile.tmp +rm -r build diff --git a/tools/model_generator/build2.sh b/tools/model_generator/build2.sh new file mode 100644 index 0000000..8bf31df --- /dev/null +++ b/tools/model_generator/build2.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +mkdir build + +find src/ -name "*.java" > listFile.tmp + +javac -target 1.6 -source 1.6 -d build @listFile.tmp + +jar cfm genconfig.jar manifest-dynamic.mf -C build/ com/ + +rm listFile.tmp +rm -r build diff --git a/tools/model_generator/complexModel.icd b/tools/model_generator/complexModel.icd new file mode 100644 index 0000000..6a81040 --- /dev/null +++ b/tools/model_generator/complexModel.icd @@ -0,0 +1,340 @@ + + +
+ + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + + + + + + + status-only + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + + rad + sr + m + Gy + q + °C + Sv + F + C + S + H + V + kg + ohm + J + N + Hz + Ix + Lm + Wb + T + W + Pa + s + m² + m³ + m/s + m/s² + m³/s + m/m³ + M + kg/m³ + m²/s + A + W/m K + J/K + ppm + 1/s + rad/s + K + VA + Watts + VAr + theta + cos(theta) + Vs + V² + As + A² + mol + A²t + VAh + Wh + VArh + V/Hz + cd + deg + + + Yocto + Zepto + Atto + Femto + Pico + Nano + Micro + Milli + Centi + Deci + zeroNoValue + Deca + Hecto + Kilo + Mega + Giga + Tera + Petra + Exa + Zetta + Yotta + + + normal + high + low + high-high + low-low + + + diff --git a/tools/model_generator/genconfig.jar b/tools/model_generator/genconfig.jar new file mode 100644 index 0000000..3a36f54 Binary files /dev/null and b/tools/model_generator/genconfig.jar differ diff --git a/tools/model_generator/genericIO.icd b/tools/model_generator/genericIO.icd new file mode 100644 index 0000000..79df371 --- /dev/null +++ b/tools/model_generator/genericIO.icd @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + status-only + + + + + status-only + + + + + status-only + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar new file mode 100644 index 0000000..28621fa Binary files /dev/null and b/tools/model_generator/genmodel.jar differ diff --git a/tools/model_generator/inverter3ph.icd b/tools/model_generator/inverter3ph.icd new file mode 100644 index 0000000..a5c9513 --- /dev/null +++ b/tools/model_generator/inverter3ph.icd @@ -0,0 +1,181 @@ + + +
+ + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + 3 + + + + + + + status-only + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + diff --git a/tools/model_generator/inverter_with_report.icd b/tools/model_generator/inverter_with_report.icd new file mode 100644 index 0000000..703c3c6 --- /dev/null +++ b/tools/model_generator/inverter_with_report.icd @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + MegaSolar + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + + rad + sr + m + Gy + q + °C + Sv + F + C + S + H + V + kg + ohm + J + N + Hz + Ix + Lm + Wb + T + W + Pa + s + m² + m³ + m/s + m/s² + m³/s + m/m³ + M + kg/m³ + m²/s + A + W/m K + J/K + ppm + 1/s + rad/s + K + VA + Watts + VAr + theta + cos(theta) + Vs + V² + As + A² + mol + A²t + VAh + Wh + VArh + V/Hz + cd + deg + + + Yocto + Zepto + Atto + Femto + Pico + Nano + Micro + Milli + Centi + Deci + zeroNoValue + Deca + Hecto + Kilo + Mega + Giga + Tera + Petra + Exa + Zetta + Yotta + + + normal + high + low + high-high + low-low + + + diff --git a/tools/model_generator/manifest-dynamic.mf b/tools/model_generator/manifest-dynamic.mf new file mode 100644 index 0000000..371d3ca --- /dev/null +++ b/tools/model_generator/manifest-dynamic.mf @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: com.libiec61850.tools.DynamicModelGenerator diff --git a/tools/model_generator/manifest.mf b/tools/model_generator/manifest.mf new file mode 100644 index 0000000..78ab5c1 --- /dev/null +++ b/tools/model_generator/manifest.mf @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: com.libiec61850.tools.StaticModelGenerator diff --git a/tools/model_generator/sampleModel.icd b/tools/model_generator/sampleModel.icd new file mode 100644 index 0000000..06ec956 --- /dev/null +++ b/tools/model_generator/sampleModel.icd @@ -0,0 +1,171 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + diff --git a/tools/model_generator/sampleModel_errors.icd b/tools/model_generator/sampleModel_errors.icd new file mode 100644 index 0000000..b4bd445 --- /dev/null +++ b/tools/model_generator/sampleModel_errors.icd @@ -0,0 +1,171 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + diff --git a/tools/model_generator/sampleModel_with_dataset.icd b/tools/model_generator/sampleModel_with_dataset.icd new file mode 100644 index 0000000..50e2409 --- /dev/null +++ b/tools/model_generator/sampleModel_with_dataset.icd @@ -0,0 +1,208 @@ + + +
+ + + + +
+

1,1,9999,1

+

12

+

00000001

+

0001

+

0001

+

127.0.0.1

+
+ +
+

111

+

4

+

01-0c-cd-01-00-01

+

1000

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + status-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + diff --git a/tools/model_generator/simpleIO_direct_control_goose.scd b/tools/model_generator/simpleIO_direct_control_goose.scd new file mode 100644 index 0000000..03017bf --- /dev/null +++ b/tools/model_generator/simpleIO_direct_control_goose.scd @@ -0,0 +1,252 @@ + + +
+
+ + + Station bus + 10 + +
+

10.0.0.2

+

255.255.255.0

+

10.0.0.1

+

0001

+

00000001

+

0001

+
+ +
+

111

+

4

+

01-0c-cd-01-00-01

+

1000

+
+
+ +
+

111

+

4

+

01-0c-cd-01-00-02

+

1000

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + status-only + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + +
diff --git a/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java b/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java new file mode 100644 index 0000000..e554aa4 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java @@ -0,0 +1,162 @@ +package com.libiec61850.scl; + +/* + * DataAttributeDefinition.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.libiec61850.scl.model.AttributeType; +import com.libiec61850.scl.model.DataModelValue; +import com.libiec61850.scl.model.FunctionalConstraint; +import com.libiec61850.scl.model.TriggerOptions; +import com.libiec61850.scl.types.IllegalValueException; +import com.libiec61850.scl.types.SclType; + +public class DataAttributeDefinition { + + private String name = null; + private String bType = null; + private String type = null; + private int count = 0; + private FunctionalConstraint fc = null; + private AttributeType attributeType = null; + private TriggerOptions triggerOptions = null; + private DataModelValue value = null; + + public DataAttributeDefinition(Node node) throws SclParserException { + this.name = ParserUtils.parseAttribute(node, "name"); + this.bType = ParserUtils.parseAttribute(node, "bType"); + this.type = ParserUtils.parseAttribute(node, "type"); + String fcString = ParserUtils.parseAttribute(node, "fc"); + + if (this.name == null) + throw new SclParserException(node, "attribute name is missing"); + + if (fcString != null) + this.fc = FunctionalConstraint.createFromString(fcString); + + if (this.bType == null) + throw new SclParserException(node, "attribute bType is missing"); + else { + if (this.bType.equals("Tcmd")) + this.type = "Tcmd"; + else if (this.bType.equals("Dbpos")) + this.type = "Dbpos"; + else if (this.bType.equals("Check")) + this.type = "Check"; + + attributeType = AttributeType.createFromSclString(this.bType); + } + + boolean dchgTrigger = false; + boolean qchgTrigger = false; + boolean dupdTrigger = false; + + String dchg = ParserUtils.parseAttribute(node, "dchg"); + + if (dchg != null) + dchgTrigger = new Boolean(dchg); + + String dupd = ParserUtils.parseAttribute(node, "dupd"); + + if (dupd != null) + dupdTrigger = new Boolean(dupd); + + String qchg = ParserUtils.parseAttribute(node, "qchg"); + + if (qchg != null) + qchgTrigger = new Boolean(qchg); + + this.triggerOptions = new TriggerOptions(dchgTrigger, qchgTrigger, dupdTrigger, false, false); + + String countStr = ParserUtils.parseAttribute(node, "count"); + if (countStr != null) + count = new Integer(countStr); + + + if (this.bType != null) { + + NodeList elementNodes = node.getChildNodes(); + + if (elementNodes != null) { + + for (int i = 0; i < elementNodes.getLength(); i++) { + Node elementNode = elementNodes.item(i); + if (elementNode.getNodeName().equals("Val")) { + + String value = elementNode.getTextContent(); + + if (attributeType == AttributeType.ENUMERATED) { + this.value = new DataModelValue(attributeType, this.type, value); + } + else { + try { + this.value = new DataModelValue(attributeType, (SclType) null, value); + } catch (IllegalValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } + } + } + } + } + + public String getName() { + return name; + } + + public String getbType() { + return bType; + } + + public String getType() { + return type; + } + + public FunctionalConstraint getFc() { + return fc; + } + + public AttributeType getAttributeType() { + return attributeType; + } + + public int getCount() { + return count; + } + + public DataModelValue getValue() { + return value; + } + + public TriggerOptions getTriggerOptions() { + return this.triggerOptions; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/DataObjectDefinition.java b/tools/model_generator/src/com/libiec61850/scl/DataObjectDefinition.java new file mode 100644 index 0000000..29c0120 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/DataObjectDefinition.java @@ -0,0 +1,57 @@ +package com.libiec61850.scl; + +/* + * DataObjectDefinition.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +public class DataObjectDefinition { + private String name; + private String type; + private int count = 0; + + public DataObjectDefinition(Node dataObjectNode) throws SclParserException { + this.name = ParserUtils.parseAttribute(dataObjectNode, "name"); + this.type = ParserUtils.parseAttribute(dataObjectNode, "type"); + + if ((this.type == null) || (this.name == null)) + throw new SclParserException(dataObjectNode, "DO misses required attribute."); + + String countStr = ParserUtils.parseAttribute(dataObjectNode, "count"); + if (countStr != null) + count = new Integer(countStr); + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public int getCount() { + return count; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/ParserUtils.java b/tools/model_generator/src/com/libiec61850/scl/ParserUtils.java new file mode 100644 index 0000000..2ffa9fe --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/ParserUtils.java @@ -0,0 +1,107 @@ +package com.libiec61850.scl; + +/* + * ParserUtils.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class ParserUtils { + public static String parseAttribute(Node lnNode, String attributeName) { + NamedNodeMap attributes = lnNode.getAttributes(); + String attributeValue = null; + + if (attributes != null) { + + Node attributeNode; + + for (int i = 0; i < attributes.getLength(); i++) { + attributeNode = attributes.item(i); + + if (attributeNode.getNodeName().equals(attributeName)) + attributeValue = attributeNode.getNodeValue(); + } + } + + return attributeValue; + } + + public static Node getChildNodeWithTag(Node node, String nodeTag) { + NodeList elements = node.getChildNodes(); + + if (elements != null) { + Node childNode; + + for (int i = 0; i < elements.getLength(); i++) { + childNode = elements.item(i); + + if (childNode.getNodeName().equals(nodeTag)) + return childNode; + } + } + + return null; + } + + public static List getChildNodesWithTag(Node node, String nodeTag) { + List nodeList = new LinkedList(); + NodeList elements = node.getChildNodes(); + + if (elements != null) { + Node childNode; + + for (int i = 0; i < elements.getLength(); i++) { + childNode = elements.item(i); + + if (childNode.getNodeName().equals(nodeTag)) + nodeList.add(childNode); + + } + } + + return nodeList; + } + + public static Boolean parseBooleanAttribute(Node xmlNode, String attributeName) throws SclParserException { + String valueStr = parseAttribute(xmlNode, attributeName); + + boolean value; + + if (valueStr == null) + return null; + + if (valueStr.toUpperCase().equals("TRUE")) + value = true; + else if (valueStr.toUpperCase().equals("FALSE")) + value = false; + else + throw new SclParserException(xmlNode, "Illegal value for boolean attribute \"" + attributeName + "\""); + + return new Boolean(value); + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/SclParser.java b/tools/model_generator/src/com/libiec61850/scl/SclParser.java new file mode 100644 index 0000000..8ed6b2c --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/SclParser.java @@ -0,0 +1,297 @@ +package com.libiec61850.scl; + +/* + * SclParser.java + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.Attributes; + +import com.libiec61850.scl.communication.Communication; +import com.libiec61850.scl.communication.ConnectedAP; +import com.libiec61850.scl.communication.SubNetwork; +import com.libiec61850.scl.model.AccessPoint; +import com.libiec61850.scl.model.IED; +import com.libiec61850.scl.types.DataAttributeType; +import com.libiec61850.scl.types.DataObjectType; +import com.libiec61850.scl.types.EnumerationType; +import com.libiec61850.scl.types.LogicalNodeType; +import com.libiec61850.scl.types.TypeDeclarations; + +public class SclParser { + + private List ieds; + private Communication communication; + private TypeDeclarations typeDeclarations; + private Node scl; + + public SclParser(InputStream stream) throws SclParserException { + Document doc = parseXmlDocument(stream); + + scl = getRootNode(doc); + + System.out.println("parse data type templates ..."); + typeDeclarations = parseTypeDeclarations(); + + System.out.println("parse IED section ..."); + + parseIedSections(); + + System.out.println("parse communication section ..."); + communication = parseCommunicationSection(); + + if (communication == null) + System.out.println("WARNING: No communication section found!"); + } + + public IED getIedByteName(String iedName) { + for (IED ied : ieds) { + if (ied.getName().equals(iedName)) + return ied; + } + + return null; + } + + public IED getFirstIed() { + return ieds.get(0); + } + + public Communication getCommunication() { + return communication; + } + + public static Document parseXmlWithLineNumberInformation(InputStream xmlInputStream) throws IOException, SAXException { + final Document xmlDocument; + + SAXParser saxParser; + + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + saxParser = factory.newSAXParser(); + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = docBuilderFactory.newDocumentBuilder(); + xmlDocument = documentBuilder.newDocument(); + } catch (ParserConfigurationException e) { + throw new RuntimeException(e); + } + + final Stack elementStack = new Stack(); + + DefaultHandler handler = new DefaultHandler() { + + private Locator documentLocator; + + private StringBuilder textNodeContent = new StringBuilder(); + + @Override + public void setDocumentLocator(Locator locator) { + documentLocator = locator; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + if (textNodeContent.length() > 0) + createTextNode(); + + Element element = xmlDocument.createElement(qName); + + element.setUserData("START_LINE_NUMBER_ATTR", new Integer(documentLocator.getLineNumber()), null); + element.setUserData("START_COLUMN_NUMBER_ATTR", new Integer(documentLocator.getColumnNumber()), null); + + for (int i = 0; i < attributes.getLength(); i++) { + element.setAttribute(attributes.getQName(i), attributes.getValue(i)); + } + + elementStack.push(element); + } + + @Override + public void endElement(String uri, String localName, String qName) { + + if (textNodeContent.length() > 0) + createTextNode(); + + Element element = elementStack.pop(); + + element.setUserData("END_LINE_NUMBER_ATTR", new Integer(documentLocator.getLineNumber()), null); + element.setUserData("END_COLUMN_NUMBER_ATTR", new Integer(documentLocator.getColumnNumber()), null); + + if (elementStack.isEmpty()) + xmlDocument.appendChild(element); + else { + Element parentElement = elementStack.peek(); + parentElement.appendChild(element); + } + } + + @Override + public void characters(char ch[], int start, int length) throws SAXException { + textNodeContent.append(ch, start, length); + } + + private void createTextNode() { + Element element = elementStack.peek(); + Node textNode = xmlDocument.createTextNode(textNodeContent.toString()); + element.appendChild(textNode); + textNodeContent.delete(0, textNodeContent.length()); + } + }; + + saxParser.parse(xmlInputStream, handler); + + return xmlDocument; + } + + private Document parseXmlDocument(InputStream stream) throws SclParserException { + Document xmlDocument = null; + + try { + xmlDocument = parseXmlWithLineNumberInformation(stream); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SAXException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return xmlDocument; + } + + private Communication parseCommunicationSection() throws SclParserException { + + Node comSection = ParserUtils.getChildNodeWithTag(scl, "Communication"); + + Communication com = null; + + if (comSection != null) + com = new Communication(comSection); + + return com; + } + + private void parseIedSections() throws SclParserException { + + List iedNodes = ParserUtils.getChildNodesWithTag(scl, "IED"); + + ieds = new LinkedList(); + + for (Node iedNode : iedNodes) + ieds.add(new IED(iedNode, typeDeclarations)); + } + + private TypeDeclarations parseTypeDeclarations() throws SclParserException { + TypeDeclarations typeDeclarations = new TypeDeclarations(); + + Node dataTypeTemplateSection = ParserUtils.getChildNodeWithTag(scl, "DataTypeTemplates"); + + if (dataTypeTemplateSection == null) + throw new SclParserException("No DataTypeTemplates section found in SCL file!"); + + NodeList typeTemplates = dataTypeTemplateSection.getChildNodes(); + + for (int i = 0; i < typeTemplates.getLength(); i++) { + Node element = typeTemplates.item(i); + + String nodeName = element.getNodeName(); + + if (nodeName.equals("LNodeType")) + typeDeclarations.addType(new LogicalNodeType(element)); + else if (nodeName.equals("DOType")) + typeDeclarations.addType(new DataObjectType(element)); + else if (nodeName.equals("DAType")) + typeDeclarations.addType(new DataAttributeType(element)); + else if (nodeName.equals("EnumType")) + typeDeclarations.addType(new EnumerationType(element)); + } + + return typeDeclarations; + } + + private static Node getRootNode(Document doc) throws SclParserException { + NodeList sclSections = doc.getElementsByTagName("SCL"); + + if (sclSections.getLength() != 1) + throw new SclParserException("Document contains more then one SCL section!"); + + return sclSections.item(0); + } + + public static void main(String[] args) throws FileNotFoundException, SclParserException { + String fileName = args[0]; + + InputStream stream = new FileInputStream(fileName); + + SclParser sclParser = new SclParser(stream); + } + + public ConnectedAP getConnectedAP(IED ied, String accessPointName) { + communication = this.getCommunication(); + + if (communication != null) { + List subNetworks = communication.getSubNetworks(); + + for (SubNetwork subNetwork : subNetworks) { + List connectedAPs = subNetwork.getConnectedAPs(); + + for (ConnectedAP connectedAP : connectedAPs) { + if (connectedAP.getIedName().equals(ied.getName())) { + + if (connectedAP.getApName().equals(accessPointName)) { + + System.out.println("Found connectedAP " + accessPointName + " for IED " + ied.getName()); + + return connectedAP; + } + + } + } + + } + } + + return null; + } + +} \ No newline at end of file diff --git a/tools/model_generator/src/com/libiec61850/scl/SclParserException.java b/tools/model_generator/src/com/libiec61850/scl/SclParserException.java new file mode 100644 index 0000000..5f33a8c --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/SclParserException.java @@ -0,0 +1,59 @@ +package com.libiec61850.scl; + +import org.w3c.dom.Node; + +/* + * SclParserException.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +public class SclParserException extends Exception { + + private Node node = null; + + public SclParserException() { + } + + public SclParserException(String message) { + super(message); + } + + public SclParserException(Node node, String message) { + super(message); + this.node = node; + } + + @Override + public String getMessage() { + String message = null; + + if (node != null) { + message = node.getNodeName() + " starting at line " + node.getUserData("START_LINE_NUMBER_ATTR") + " column " + + node.getUserData("START_COLUMN_NUMBER_ATTR") + ": " + super.getMessage(); + } else + message = super.getMessage(); + + return message; + } + + private static final long serialVersionUID = 6243253854159814835L; + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/Communication.java b/tools/model_generator/src/com/libiec61850/scl/communication/Communication.java new file mode 100644 index 0000000..07f904a --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/Communication.java @@ -0,0 +1,53 @@ +package com.libiec61850.scl.communication; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class Communication { + + private List subNetworks; + + public Communication(Node comSection) throws SclParserException { + List subnetworks = ParserUtils.getChildNodesWithTag(comSection, "SubNetwork"); + + if (subnetworks.size() == 0) + throw new SclParserException(comSection, "no subnetworks defined"); + + subNetworks = new LinkedList(); + + for (Node node : subnetworks) { + subNetworks.add(new SubNetwork(node)); + } + } + + public List getSubNetworks() { + return subNetworks; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java b/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java new file mode 100644 index 0000000..46579aa --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java @@ -0,0 +1,79 @@ +package com.libiec61850.scl.communication; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class ConnectedAP { + + private String iedName; + private String apName; + + private List gses; + + public ConnectedAP(Node node) throws SclParserException { + iedName = ParserUtils.parseAttribute(node, "iedName"); + apName = ParserUtils.parseAttribute(node, "apName"); + + if ((iedName == null) || (apName == null)) + throw new SclParserException(node, "ConnectedAP is missing required attribute"); + + gses = new LinkedList(); + + List gseNodes = ParserUtils.getChildNodesWithTag(node, "GSE"); + + for (Node gseNode : gseNodes) { + gses.add(new GSE(gseNode)); + } + } + + public String getIedName() { + return iedName; + } + + public String getApName() { + return apName; + } + + public List getGses() { + return gses; + } + + public GSEAddress lookupGSEAddress(String logicalDeviceName, String name) { + + for (GSE gse : this.getGses()) { + if (gse.getLdInst().equals(logicalDeviceName)) { + if (gse.getCbName().equals(name)) + return gse.getAddress(); + } + } + + return null; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java b/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java new file mode 100644 index 0000000..1bb0427 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java @@ -0,0 +1,63 @@ +package com.libiec61850.scl.communication; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class GSE { + + private String ldInst; + private String cbName; + + private GSEAddress address; + + public GSE(Node gseNode) throws SclParserException { + ldInst = ParserUtils.parseAttribute(gseNode, "ldInst"); + cbName = ParserUtils.parseAttribute(gseNode, "cbName"); + + if ((ldInst == null) || (cbName == null)) + throw new SclParserException(gseNode, "GSE is missing required attribute"); + + Node addressNode = ParserUtils.getChildNodeWithTag(gseNode, "Address"); + + if (addressNode == null) + throw new SclParserException(gseNode, "GSE is missing address definition!"); + + address = new GSEAddress(addressNode); + } + + public String getLdInst() { + return ldInst; + } + + public String getCbName() { + return cbName; + } + + public GSEAddress getAddress() { + return address; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/GSEAddress.java b/tools/model_generator/src/com/libiec61850/scl/communication/GSEAddress.java new file mode 100644 index 0000000..151033e --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/GSEAddress.java @@ -0,0 +1,114 @@ +package com.libiec61850.scl.communication; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.List; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class GSEAddress { + + private Integer vlanId = null; + private Integer vlanPriority = null; + private Integer appId = null; + private int[] macAddress = null; + + public GSEAddress(Node addressNode) throws DOMException, SclParserException { + + List pNodes = ParserUtils.getChildNodesWithTag(addressNode, "P"); + + for (Node pNode : pNodes) { + String type = ParserUtils.parseAttribute(pNode, "type"); + + if (type.equals("VLAN-ID")) { + vlanId = Integer.parseInt(pNode.getTextContent(), 16); + + if (vlanId > 0xfff) + throw new SclParserException(addressNode, "VLAN-ID value out of range"); + } + else if (type.equals("VLAN-PRIORITY")) { + vlanPriority = new Integer(pNode.getTextContent()); + } + else if (type.equals("APPID")) { + appId = Integer.parseInt(pNode.getTextContent(), 16); + + if (appId > 0xffff) + throw new SclParserException(addressNode, "APPID value out of range"); + } + else if (type.equals("MAC-Address")) { + String[] addressElements = pNode.getTextContent().split("-"); + + if (addressElements.length != 6) + throw new SclParserException(addressNode, "malformed address " + pNode.getTextContent()); + + macAddress = new int[6]; + + for (int i = 0; i < addressElements.length; i++) { + macAddress[i] = Integer.parseInt(addressElements[i], 16); + } + } + + } + + if (vlanId == null) + vlanId = new Integer(0); + + if (vlanPriority == null) + vlanPriority = new Integer(4); + + if (macAddress == null) { + macAddress = new int[6]; + /* default MAC address: 01-0C-CD-01-00-00 */ + + macAddress[0] = 0x01; + macAddress[1] = 0x0c; + macAddress[2] = 0xcd; + macAddress[3] = 0x01; + macAddress[4] = 0x00; + macAddress[5] = 0x00; + } + + if (appId == null) + appId = new Integer(0); + } + + public Integer getVlanId() { + return vlanId; + } + + public Integer getVlanPriority() { + return vlanPriority; + } + + public Integer getAppId() { + return appId; + } + + public int[] getMacAddress() { + return macAddress; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/SubNetwork.java b/tools/model_generator/src/com/libiec61850/scl/communication/SubNetwork.java new file mode 100644 index 0000000..9bdde10 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/SubNetwork.java @@ -0,0 +1,67 @@ +package com.libiec61850.scl.communication; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class SubNetwork { + + private String name; + private String type; + + private List connectedAPs; + + public SubNetwork(Node netNode) throws SclParserException { + name = ParserUtils.parseAttribute(netNode, "name"); + type = ParserUtils.parseAttribute(netNode, "type"); + + if (name == null) + throw new SclParserException(netNode, "SubNetwork is missing attribute name!"); + + connectedAPs = new LinkedList(); + + List nodes = ParserUtils.getChildNodesWithTag(netNode, "ConnectedAP"); + + for (Node node : nodes) { + connectedAPs.add(new ConnectedAP(node)); + } + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public List getConnectedAPs() { + return connectedAPs; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/AccessPoint.java b/tools/model_generator/src/com/libiec61850/scl/model/AccessPoint.java new file mode 100644 index 0000000..91fec81 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/AccessPoint.java @@ -0,0 +1,60 @@ +package com.libiec61850.scl.model; + +/* + * AccessPoint.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.TypeDeclarations; + +public class AccessPoint { + + private String name; + private Server server; + + public AccessPoint(Node apNode, TypeDeclarations typeDeclarations) throws SclParserException { + this.name = ParserUtils.parseAttribute(apNode, "name"); + + if (this.name == null) + throw new SclParserException(apNode, "AccessPoint as no name defined!"); + + Node serverNode = ParserUtils.getChildNodeWithTag(apNode, "Server"); + + if (serverNode == null) + throw new SclParserException(apNode, "AccessPoint has no server defined!"); + + this.server = new Server(serverNode, typeDeclarations); + + } + + public String getName() { + return name; + } + + public Server getServer() { + return server; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/AttributeType.java b/tools/model_generator/src/com/libiec61850/scl/model/AttributeType.java new file mode 100644 index 0000000..b927e7e --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/AttributeType.java @@ -0,0 +1,141 @@ +package com.libiec61850.scl.model; + +/* + * AttributeType.java + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import com.libiec61850.scl.SclParserException; + +public enum AttributeType { + BOOLEAN(0), /* int */ + INT8(1), /* int8_t */ + INT16(2), /* int16_t */ + INT32(3), /* int32_t */ + INT64(4), /* int64_t */ + INT128(5), + INT8U(6), /* uint8_t */ + INT16U(7), /* uint16_t */ + INT24U(8), /* uint32_t */ + INT32U(9), /* uint32_t */ + FLOAT32(10), /* float */ + FLOAT64(11), /* double */ + ENUMERATED(12), + OCTET_STRING_64(13), + OCTET_STRING_6(14), + OCTET_STRING_8(15), + VISIBLE_STRING_32(16), + VISIBLE_STRING_64(17), + VISIBLE_STRING_65(18), + VISIBLE_STRING_129(19), + VISIBLE_STRING_255(20), + UNICODE_STRING_255(21), + TIMESTAMP(22), + QUALITY(23), + CHECK(24), + CODEDENUM(25), + GENERIC_BITSTRING(26), + CONSTRUCTED(27), + ENTRY_TIME(28), + PHYCOMADDR(29); + + private int intValue; + + AttributeType(int intValue) { + this.intValue = intValue; + } + + public int getIntValue() { + return this.intValue; + } + + public static AttributeType createFromSclString(String typeString) + throws SclParserException { + if (typeString.equals("BOOLEAN")) + return BOOLEAN; + else if (typeString.equals("INT8")) + return INT8; + else if (typeString.equals("INT16")) + return INT16; + else if (typeString.equals("INT32")) + return INT32; + else if (typeString.equals("INT64")) + return INT64; + else if (typeString.equals("INT128")) + return INT128; + else if (typeString.equals("INT8U")) + return INT8U; + else if (typeString.equals("INT16U")) + return INT16U; + else if (typeString.equals("INT24U")) + return INT24U; + else if (typeString.equals("INT32U")) + return INT32U; + else if (typeString.equals("FLOAT32")) + return FLOAT32; + else if (typeString.equals("FLOAT64")) + return FLOAT64; + else if (typeString.equals("Enum")) + return ENUMERATED; + else if (typeString.equals("Dbpos")) + return CODEDENUM; + else if (typeString.equals("Check")) + return CHECK; + else if (typeString.equals("Tcmd")) + return CODEDENUM; + else if (typeString.equals("Octet64")) + return OCTET_STRING_64; + else if (typeString.equals("Quality")) + return QUALITY; + else if (typeString.equals("Timestamp")) + return TIMESTAMP; + else if (typeString.equals("VisString32")) + return VISIBLE_STRING_32; + else if (typeString.equals("VisString64")) + return VISIBLE_STRING_64; + else if (typeString.equals("VisString65")) + return VISIBLE_STRING_65; + else if (typeString.equals("VisString129")) + return VISIBLE_STRING_129; + else if (typeString.equals("ObjRef")) + return VISIBLE_STRING_129; + else if (typeString.equals("VisString255")) + return VISIBLE_STRING_255; + else if (typeString.equals("Unicode255")) + return UNICODE_STRING_255; + else if (typeString.equals("OptFlds")) + return GENERIC_BITSTRING; + else if (typeString.equals("TrgOps")) + return GENERIC_BITSTRING; + else if (typeString.equals("EntryID")) + return OCTET_STRING_8; + else if (typeString.equals("EntryTime")) + return ENTRY_TIME; + else if (typeString.equals("PhyComAddr")) + return PHYCOMADDR; + else if (typeString.equals("Struct")) + return CONSTRUCTED; + else + throw new SclParserException("unsupported attribute type " + + typeString); + + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/Authentication.java b/tools/model_generator/src/com/libiec61850/scl/model/Authentication.java new file mode 100644 index 0000000..3886034 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/Authentication.java @@ -0,0 +1,34 @@ +package com.libiec61850.scl.model; + +/* + * Authentication.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +public class Authentication { + + public Authentication(Node authenticationNode) { + // TODO Auto-generated constructor stub + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java b/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java new file mode 100644 index 0000000..44193d7 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java @@ -0,0 +1,181 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import com.libiec61850.scl.DataAttributeDefinition; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.DataAttributeType; +import com.libiec61850.scl.types.EnumerationType; +import com.libiec61850.scl.types.SclType; +import com.libiec61850.scl.types.TypeDeclarations; + +public class DataAttribute implements DataModelNode { + + private String name; + private FunctionalConstraint fc; + private AttributeType type; + private boolean isBasicAttribute = true; + private int count; + private DataModelValue value = null; + private String shortAddress = null; + private DataModelNode parent; + + private List subDataAttributes = null; + + private SclType sclType = null; + + private TriggerOptions triggerOptions = null; + + private DataAttributeDefinition definition = null; + + public DataAttribute(DataAttributeDefinition daDefinition, TypeDeclarations typeDeclarations, FunctionalConstraint fc, + DataModelNode parent) throws SclParserException { + this.name = daDefinition.getName(); + this.fc = daDefinition.getFc(); + this.type = daDefinition.getAttributeType(); + this.count = daDefinition.getCount(); + this.parent = parent; + this.definition = daDefinition; + + if (this.fc == null) + this.fc = fc; + + if (fc != null) + this.fc = fc; + + if ((parent != null) && (parent instanceof DataAttribute)) + this.triggerOptions = ((DataAttribute) parent).getTriggerOptions(); + else + this.triggerOptions = daDefinition.getTriggerOptions(); + + if (this.type == AttributeType.CONSTRUCTED) { + isBasicAttribute = false; + createConstructedAttribute(daDefinition, typeDeclarations); + } else if (this.type == AttributeType.ENUMERATED) { + createEnumeratedAttribute(daDefinition, typeDeclarations); + } + } + + private void createEnumeratedAttribute(DataAttributeDefinition daDefinition, TypeDeclarations typeDeclarations) + throws SclParserException { + this.sclType = typeDeclarations.lookupType(daDefinition.getType()); + + if (this.sclType == null) + throw new SclParserException("Missing type definition for enumerated data attribute: " + daDefinition.getbType()); + + if (!(this.sclType instanceof EnumerationType)) + throw new SclParserException("Wrong type definition for enumerated data attribute"); + } + + private void createConstructedAttribute(DataAttributeDefinition daDefinition, TypeDeclarations typeDeclarations) + throws SclParserException { + this.sclType = typeDeclarations.lookupType(daDefinition.getType(), DataAttributeType.class); + + if (this.sclType == null) + throw new SclParserException("Missing type definition for constructed data attribute: " + daDefinition.getbType()); + + if (!(this.sclType instanceof DataAttributeType)) + throw new SclParserException("Wrong type definition for constructed data attribute"); + + DataAttributeType dataAttributeType = (DataAttributeType) this.sclType; + + List daDefinitions = dataAttributeType.getSubDataAttributes(); + + this.subDataAttributes = new LinkedList(); + + for (DataAttributeDefinition daDef : daDefinitions) { + this.subDataAttributes.add(new DataAttribute(daDef, typeDeclarations, this.fc, this)); + } + + } + + public String getName() { + return name; + } + + public FunctionalConstraint getFc() { + return fc; + } + + public AttributeType getType() { + return type; + } + + public List getSubDataAttributes() { + return subDataAttributes; + } + + public boolean isBasicAttribute() { + return isBasicAttribute; + } + + public int getCount() { + return count; + } + + @Override + public DataModelNode getChildByName(String childName) { + for (DataAttribute dataAttribute : subDataAttributes) { + if (dataAttribute.getName().equals(childName)) + return dataAttribute; + } + + return null; + } + + @Override + public SclType getSclType() { + return sclType; + } + + public DataModelValue getValue() { + return value; + } + + public void setValue(DataModelValue value) { + this.value = value; + } + + public String getShortAddress() { + return shortAddress; + } + + public void setShortAddress(String shortAddress) { + this.shortAddress = shortAddress; + } + + public TriggerOptions getTriggerOptions() { + return this.triggerOptions; + } + + public DataAttributeDefinition getDefinition() { + return this.definition; + } + + @Override + public DataModelNode getParent() { + return parent; + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataModelNode.java b/tools/model_generator/src/com/libiec61850/scl/model/DataModelNode.java new file mode 100644 index 0000000..221c4de --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataModelNode.java @@ -0,0 +1,33 @@ +package com.libiec61850.scl.model; + +/* + * DataModelNode.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import com.libiec61850.scl.types.SclType; + +public interface DataModelNode { + public String getName(); + public DataModelNode getChildByName(String childName); + public SclType getSclType(); + public DataModelNode getParent(); +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java b/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java new file mode 100644 index 0000000..7ff6f70 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java @@ -0,0 +1,204 @@ +package com.libiec61850.scl.model; + +/* + * DataModelValue.java + * + * Copyright 2013, 2015 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import com.libiec61850.scl.types.EnumerationType; +import com.libiec61850.scl.types.IllegalValueException; +import com.libiec61850.scl.types.SclType; +import com.libiec61850.scl.types.TypeDeclarations; + +public class DataModelValue { + + private Object value = null; + private String unknownEnumValue = null; + private String enumType = null; + + public DataModelValue(AttributeType type, String enumType, String value) { + this.unknownEnumValue = value; + this.enumType = enumType; + } + + public DataModelValue(AttributeType type, SclType sclType, String value) throws IllegalValueException { + + switch (type) { + case ENUMERATED: + EnumerationType enumType = (EnumerationType) sclType; + + try { + this.value = (Object) (new Integer(enumType.getOrdByEnumString(value))); + } catch (IllegalValueException e) { + try { + + this.value = Integer.parseInt(value); + + if (enumType.isValidOrdValue(Integer.parseInt(value)) == false) { + throw new IllegalValueException(value + + " is not a valid value of type " + sclType.getId()); + } + + System.out.println("WARNING: Initialization of ENUM with ordinal value!"); + } + catch (NumberFormatException nfe) { + throw new IllegalValueException(value + + " is not a valid value of type " + sclType.getId()); + } + } + + break; + case INT8: + case INT16: + case INT32: + case INT8U: + case INT16U: + case INT32U: + case INT24U: + case INT64: + + String trimmedValue = value.trim(); + + if (trimmedValue != value) { + System.out.println("WARNING: value initializer contains leading or trailing whitespace"); + } + + if (trimmedValue.isEmpty()) + this.value = new Long(0); + else + this.value = Long.decode(trimmedValue); + break; + case BOOLEAN: + + trimmedValue = value.trim(); + + if (trimmedValue != value) { + System.out.println("WARNING: value initializer contains leading or trailing whitespace"); + } + + if (trimmedValue.toLowerCase().equals("true")) + this.value = new Boolean(true); + else + this.value = new Boolean(false); + break; + case FLOAT32: + + trimmedValue = value.trim(); + + if (trimmedValue != value) { + System.out.println("WARNING: value initializer contains leading or trailing whitespace"); + } + + if (trimmedValue.isEmpty()) + this.value = new Float(0); + else + this.value = new Float(trimmedValue); + break; + case FLOAT64: + + trimmedValue = value.trim(); + + if (trimmedValue != value) { + System.out.println("WARNING: value initializer contains leading or trailing whitespace"); + } + + if (trimmedValue.isEmpty()) + this.value = new Double(0); + else + this.value = new Double(trimmedValue); + break; + case UNICODE_STRING_255: + this.value = value; + break; + + case VISIBLE_STRING_32: + case VISIBLE_STRING_64: + case VISIBLE_STRING_65: + case VISIBLE_STRING_129: + case VISIBLE_STRING_255: + this.value = (Object) value; + break; + case CHECK: + System.out.println("Warning: Initialization of CHECK is unsupported!"); + case CODEDENUM: + this.value = null; + System.out.println("Warning: Initialization of CODEDENUM is unsupported!"); + break; + case QUALITY: + this.value = null; + System.out.println("Warning: Initialization of QUALITY is unsupported!"); + break; + default: + throw new IllegalValueException("Unsupported type " + type.toString() + " value: " + value); + } + } + + public Object getValue() { + return value; + } + + public String getUnknownEnumValue() { + return unknownEnumValue; + } + + public void updateEnumOrdValue(TypeDeclarations typeDecls) + { + if (enumType != null) { + + SclType sclType = typeDecls.lookupType(enumType); + + if (sclType != null) { + + EnumerationType enumType = (EnumerationType) sclType; + try { + this.value = (Object) (new Integer(enumType.getOrdByEnumString(unknownEnumValue))); + } catch (IllegalValueException e) { + e.printStackTrace(); + } + } + else + System.out.println(" failed!"); + } + } + + public long getLongValue() { + return (Long) value; + } + + public int getIntValue() { + if (value instanceof Long) { + Long longValue = (Long) value; + return ((Long) value).intValue(); + } + if (value instanceof Integer) + return ((Integer) value).intValue(); + + if (value instanceof Boolean) { + if (((Boolean) value) == true) + return 1; + else + return 0; + } + + return 0; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataObject.java b/tools/model_generator/src/com/libiec61850/scl/model/DataObject.java new file mode 100644 index 0000000..7a86176 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataObject.java @@ -0,0 +1,138 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import com.libiec61850.scl.DataAttributeDefinition; +import com.libiec61850.scl.DataObjectDefinition; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.DataAttributeType; +import com.libiec61850.scl.types.DataObjectType; +import com.libiec61850.scl.types.SclType; +import com.libiec61850.scl.types.TypeDeclarations; + +public class DataObject implements DataModelNode { + + private String name; + + private int count; + + private List dataAttributes = null; + private List subDataObjects = null; + private SclType sclType; + private DataModelNode parent; + + public DataObject(DataObjectDefinition doDefinition, TypeDeclarations typeDeclarations, DataModelNode parent) throws SclParserException { + this.name = doDefinition.getName(); + this.count = doDefinition.getCount(); + this.parent = parent; + + this.dataAttributes = new LinkedList(); + this.subDataObjects = new LinkedList(); + + sclType = typeDeclarations.lookupType(doDefinition.getType(), DataObjectType.class); + + if (sclType == null) + throw new SclParserException("type declaration missing for data object."); + + createDataAttributes(typeDeclarations, sclType); + + createSubDataObjects(typeDeclarations, (DataObjectType) sclType); + } + + private void createSubDataObjects(TypeDeclarations typeDeclarations, DataObjectType doType) throws SclParserException { + + List sdoDefinitions = doType.getSubDataObjects(); + + for (DataObjectDefinition sdoDefinition : sdoDefinitions) { + this.subDataObjects.add(new DataObject(sdoDefinition, typeDeclarations, this)); + } + } + + private void createDataAttributes(TypeDeclarations typeDeclarations, SclType sclType) throws SclParserException { + + List daDefinitions = null; + + if (sclType instanceof DataObjectType) + daDefinitions = ((DataObjectType) sclType).getDataAttributes(); + + if (sclType instanceof DataAttributeType) + daDefinitions = ((DataAttributeType) sclType).getSubDataAttributes(); + + for (DataAttributeDefinition daDefinition : daDefinitions) { + + if (daDefinition.getFc() == FunctionalConstraint.SE) { + + System.out.println("Add SG DA for corresponding SE DA: "); + this.dataAttributes.add(new DataAttribute(daDefinition, typeDeclarations, FunctionalConstraint.SG, this)); + } + + this.dataAttributes.add(new DataAttribute(daDefinition, typeDeclarations, null, this)); + + + } + } + + public String getName() { + return name; + } + + public List getDataAttributes() { + return dataAttributes; + } + + public List getSubDataObjects() { + return subDataObjects; + } + + public int getCount() { + return count; + } + + @Override + public DataModelNode getChildByName(String childName) { + for (DataAttribute dataAttribute : dataAttributes) { + if (dataAttribute.getName().equals(childName)) + return dataAttribute; + } + + for (DataObject dataObject : subDataObjects) { + if (dataObject.getName().equals(childName)) + return dataObject; + } + + return null; + } + + @Override + public SclType getSclType() { + return sclType; + } + + @Override + public DataModelNode getParent() { + return parent; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataSet.java b/tools/model_generator/src/com/libiec61850/scl/model/DataSet.java new file mode 100644 index 0000000..9c137c3 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataSet.java @@ -0,0 +1,70 @@ +package com.libiec61850.scl.model; + +/* + * DataSet.java + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class DataSet { + + private String name = null; + private String desc = null; + + List fcda = null; + + public DataSet(Node dataSet) throws SclParserException { + this.name = ParserUtils.parseAttribute(dataSet, "name"); + this.desc = ParserUtils.parseAttribute(dataSet, "desc"); + + if (this.name == null) + throw new SclParserException(dataSet, "Dataset misses required attribute \"name\""); + + fcda = new LinkedList(); + + List fcdaNodes = ParserUtils.getChildNodesWithTag(dataSet, "FCDA"); + for (Node fcdaNode : fcdaNodes) { + fcda.add(new FunctionalConstraintData(fcdaNode)); + } + + + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public List getFcda() { + return fcda; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/FunctionalConstraint.java b/tools/model_generator/src/com/libiec61850/scl/model/FunctionalConstraint.java new file mode 100644 index 0000000..1e8599b --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/FunctionalConstraint.java @@ -0,0 +1,55 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +public enum FunctionalConstraint { + ST(0), /** Status information */ + MX(1), /** Measurands - analogue values */ + SP(2), /** Setpoint */ + SV(3), /** Substitution */ + CF(4), /** Configuration */ + DC(5), /** Description */ + SG(6), /** Setting group */ + SE(7), /** Setting group editable */ + SR(8), /** Service response / Service tracking */ + OR(9), /** Operate received */ + BL(10), /** Blocking */ + EX(11), /** Extended definition */ + CO(12), /** Control */ + ALL(99), /** All FCs */ + NONE(-1) /** not specified */ + ; + + private int intValue; + + FunctionalConstraint(int intValue) { + this.intValue = intValue; + } + + public int getIntValue() { + return this.intValue; + } + + public static FunctionalConstraint createFromString(String fc) { + return FunctionalConstraint.valueOf(fc); + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/FunctionalConstraintData.java b/tools/model_generator/src/com/libiec61850/scl/model/FunctionalConstraintData.java new file mode 100644 index 0000000..b09d4a5 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/FunctionalConstraintData.java @@ -0,0 +1,127 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class FunctionalConstraintData { + + private String ldInstance = null; + private String prefix = null; + private String lnClass = null; + private String lnInstance = null; + private String doName = null; + private String daName = null; + private FunctionalConstraint fc = null; + private Integer ix = null; /* array index */ + + public FunctionalConstraintData(Node fcdaNode) throws SclParserException { + this.ldInstance = ParserUtils.parseAttribute(fcdaNode, "ldInst"); + + prefix = ParserUtils.parseAttribute(fcdaNode, "prefix"); + + this.lnClass = ParserUtils.parseAttribute(fcdaNode, "lnClass"); + + this.lnInstance= ParserUtils.parseAttribute(fcdaNode, "lnInst"); + + this.doName = ParserUtils.parseAttribute(fcdaNode, "doName"); + this.daName = ParserUtils.parseAttribute(fcdaNode, "daName"); + + String fc = ParserUtils.parseAttribute(fcdaNode, "fc"); + + if (fc != null) + this.fc = FunctionalConstraint.createFromString(fc); + + String index = ParserUtils.parseAttribute(fcdaNode, "ix"); + + if (index != null) + this.ix = new Integer(index); + + } + + public String getLdInstance() { + return ldInstance; + } + + public String getLnClass() { + return lnClass; + } + + public String getLnInstance() { + return lnInstance; + } + + public String getDoName() { + return doName; + } + + public String getDaName() { + return daName; + } + + public FunctionalConstraint getFc() { + return fc; + } + + public Integer getIx() { + return ix; + } + + public String getPrefix() { + return prefix; + } + + @Override + public String toString() { + String string = ""; + + if (ldInstance != null) + string = ldInstance + "/"; + + if (lnClass != null) { + + if (prefix != null) + string += prefix; + + string += lnClass; + if (lnInstance == null) + string += "."; + } + + if (lnInstance != null) + string += lnInstance + "."; + + if (doName != null) + string += doName; + + if (daName != null) + string += "." + daName; + + return string; + } + + + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java b/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java new file mode 100644 index 0000000..40ee837 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java @@ -0,0 +1,107 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class GSEControl { + + private String name; + private String desc = null; + private String dataSet; + private int confRev = 1; + private String appID; + private boolean fixedOffs = false; + private int minTime = -1; + private int maxTime = -1; + + public GSEControl(Node gseControlNode) throws SclParserException { + + this.name = ParserUtils.parseAttribute(gseControlNode, "name"); + this.desc = ParserUtils.parseAttribute(gseControlNode, "desc"); + this.dataSet = ParserUtils.parseAttribute(gseControlNode, "datSet"); + + String confRevString = ParserUtils.parseAttribute(gseControlNode, "confRev"); + + if (confRevString != null) + this.confRev = new Integer(confRevString); + + this.appID = ParserUtils.parseAttribute(gseControlNode, "appID"); + + Boolean fixedOffs = ParserUtils.parseBooleanAttribute(gseControlNode, "fixedOffs"); + + if (fixedOffs != null) + this.fixedOffs = fixedOffs; + + String minTimeStr = ParserUtils.parseAttribute(gseControlNode, "minTime"); + String maxTimeStr = ParserUtils.parseAttribute(gseControlNode, "maxTime"); + + if (minTimeStr != null) + minTime = new Integer(minTimeStr); + + if (maxTimeStr != null) + maxTime = new Integer(maxTimeStr); + + String typeString = ParserUtils.parseAttribute(gseControlNode, "type"); + + if (typeString != null) + if (!typeString.equals("GOOSE")) + throw new SclParserException(gseControlNode, "GSEControl of type " + typeString + " not supported!"); + + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public String getDataSet() { + return dataSet; + } + + public int getConfRev() { + return confRev; + } + + public String getAppID() { + return appID; + } + + public boolean isFixedOffs() { + return fixedOffs; + } + + public int getMinTime() { + return minTime; + } + + public int getMaxTime() { + return maxTime; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/IED.java b/tools/model_generator/src/com/libiec61850/scl/model/IED.java new file mode 100644 index 0000000..fb381ae --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/IED.java @@ -0,0 +1,82 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.TypeDeclarations; + +public class IED { + private String name; + private List accessPoints; + private TypeDeclarations typeDeclarations; + + public IED(Node iedNode, TypeDeclarations typeDeclarations) + throws SclParserException { + this.name = ParserUtils.parseAttribute(iedNode, "name"); + + List accessPointNodes = ParserUtils.getChildNodesWithTag(iedNode, "AccessPoint"); + + if (accessPointNodes.size() == 0) + throw new SclParserException(iedNode, "no AccessPoint defined in IED " + name); + + this.accessPoints = new LinkedList(); + + for (Node accessPointNode : accessPointNodes) { + this.accessPoints.add(new AccessPoint(accessPointNode, typeDeclarations)); + } + + this.typeDeclarations = typeDeclarations; + } + + public TypeDeclarations getTypeDeclarations() { + return typeDeclarations; + } + + public String getName() { + return name; + } + + public List getAccessPoints() { + return accessPoints; + } + + public AccessPoint getAccessPointByName(String name) { + + for (AccessPoint ap : accessPoints) { + if (ap.getName().equals(name)) + return ap; + } + + return null; + } + + public AccessPoint getFirstAccessPoint() { + return accessPoints.get(0); + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/Log.java b/tools/model_generator/src/com/libiec61850/scl/model/Log.java new file mode 100644 index 0000000..3b39343 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/Log.java @@ -0,0 +1,44 @@ +package com.libiec61850.scl.model; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +/* + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +public class Log { + + private String name; + + public Log(Node logNode) throws SclParserException { + name = ParserUtils.parseAttribute(logNode, "name"); + + if (name == null) + throw new SclParserException(logNode, "Log is missing required attribute name!"); + } + + public String getName() { + return name; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/LogControl.java b/tools/model_generator/src/com/libiec61850/scl/model/LogControl.java new file mode 100644 index 0000000..b781aca --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/LogControl.java @@ -0,0 +1,132 @@ +package com.libiec61850.scl.model; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +/* + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +public class LogControl { + + private String name; + private String desc; + private String dataSet; + private String ldInst = null; + private String prefix = ""; + private String lnClass = "LLN0"; + private String logName; + private boolean logEna = true; + private boolean reasonCode = true; + private int intgPd = 0; // integrity period in ms + private TriggerOptions triggerOptions; + + public LogControl(Node logControlNode) throws SclParserException { + name = ParserUtils.parseAttribute(logControlNode, "name"); + + if (name == null) + throw new SclParserException(logControlNode, "LogControl is missing required attribute \"name\""); + + desc = ParserUtils.parseAttribute(logControlNode, "desc"); + dataSet = ParserUtils.parseAttribute(logControlNode, "datSet"); + + ldInst = ParserUtils.parseAttribute(logControlNode, "ldInst"); + prefix = ParserUtils.parseAttribute(logControlNode, "prefix"); + + String lnClassString = ParserUtils.parseAttribute(logControlNode, "lnClass"); + + if (lnClassString != null) + lnClass = lnClassString; + + logName = ParserUtils.parseAttribute(logControlNode, "logName"); + + if (logName == null) + throw new SclParserException(logControlNode, "LogControl is missing required attribute \"logName\""); + + String intgPdString = ParserUtils.parseAttribute(logControlNode, "intgPd"); + + if (intgPdString != null) + intgPd = Integer.decode(intgPdString); + + Boolean logEnaBoolean = ParserUtils.parseBooleanAttribute(logControlNode, "logEna"); + if (logEnaBoolean != null) + logEna = logEnaBoolean; + + Boolean reasonCodeBoolean = ParserUtils.parseBooleanAttribute(logControlNode, "reasonCode"); + if (reasonCodeBoolean != null) + reasonCode = reasonCodeBoolean; + + Node trgOpsNode = ParserUtils.getChildNodeWithTag(logControlNode, "TrgOps"); + + if (trgOpsNode != null) + this.triggerOptions = new TriggerOptions(trgOpsNode); + else + this.triggerOptions = new TriggerOptions(); // use default values if no node present + + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public String getDataSet() { + return dataSet; + } + + public String getLdInst() { + return ldInst; + } + + public String getPrefix() { + return prefix; + } + + public String getLnClass() { + return lnClass; + } + + public String getLogName() { + return logName; + } + + public boolean isLogEna() { + return logEna; + } + + public boolean isReasonCode() { + return reasonCode; + } + + public int getIntgPd() { + return intgPd; + } + + public TriggerOptions getTriggerOptions() { + return triggerOptions; + } + + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/LogicalDevice.java b/tools/model_generator/src/com/libiec61850/scl/model/LogicalDevice.java new file mode 100644 index 0000000..0649f03 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/LogicalDevice.java @@ -0,0 +1,81 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.TypeDeclarations; + +public class LogicalDevice { + + private String inst; + + private String ldName; + + private List logicalNodes; + + public LogicalDevice(Node ldNode, TypeDeclarations typeDeclarations) throws SclParserException { + this.inst = ParserUtils.parseAttribute(ldNode, "inst"); + + if (this.inst == null) + throw new SclParserException(ldNode, "Logical devices misses inst attribute."); + + this.ldName = ParserUtils.parseAttribute(ldNode, "ldName"); + + parseLogicalNodes(ldNode, typeDeclarations); + } + + private void parseLogicalNodes(Node ldNode, TypeDeclarations typeDeclarations) throws SclParserException { + Node ln0Node = ParserUtils.getChildNodeWithTag(ldNode, "LN0"); + + if (ln0Node == null) + throw new SclParserException(ldNode, "Logical device misses LN0."); + + logicalNodes = new LinkedList(); + + logicalNodes.add(new LogicalNode(ln0Node, typeDeclarations, this)); + + List lnNodes = ParserUtils.getChildNodesWithTag(ldNode, "LN"); + + for (Node lnNode : lnNodes) { + logicalNodes.add(new LogicalNode(lnNode, typeDeclarations, this)); + } + } + + public String getInst() { + return inst; + } + + public String getLdName() { + return ldName; + } + + public List getLogicalNodes() { + return logicalNodes; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java new file mode 100644 index 0000000..8fa7c58 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java @@ -0,0 +1,293 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.DataObjectDefinition; +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.IllegalValueException; +import com.libiec61850.scl.types.LogicalNodeType; +import com.libiec61850.scl.types.SclType; +import com.libiec61850.scl.types.TypeDeclarations; + +public class LogicalNode implements DataModelNode { + + private String lnClass; + private String lnType; + private String inst; + private String desc; + private String prefix; + private SclType sclType; + + private List dataObjects; + private List dataSets; + private List reportControlBlocks; + private List gseControlBlocks; + private List logControlBlocks; + private List logs; + private List settingGroupControlBlocks; + + private LogicalDevice parentLogicalDevice; + + + public LogicalNode(Node lnNode, TypeDeclarations typeDeclarations, LogicalDevice parent) throws SclParserException { + this.lnClass = ParserUtils.parseAttribute(lnNode, "lnClass"); + this.lnType = ParserUtils.parseAttribute(lnNode, "lnType"); + this.inst = ParserUtils.parseAttribute(lnNode, "inst"); + this.desc = ParserUtils.parseAttribute(lnNode, "desc"); + this.prefix = ParserUtils.parseAttribute(lnNode, "prefix"); + this.parentLogicalDevice = parent; + + if (this.lnClass == null) + throw new SclParserException(lnNode, "required attribute \"lnClass\" is missing in logical node."); + + if (this.lnType == null) + throw new SclParserException(lnNode, "required attribute \"lnType\" is missing in logical node."); + + if (this.inst == null) + throw new SclParserException(lnNode, "required attribute \"inst\" is missing in logical node."); + + // instantiate DataObjects + this.sclType = typeDeclarations.lookupType(this.lnType); + + if (sclType == null) + throw new SclParserException(lnNode, "missing type declaration " + this.lnType); + + if (sclType instanceof LogicalNodeType) { + dataObjects = new LinkedList(); + + LogicalNodeType type = (LogicalNodeType) sclType; + + List doDefinitions = type.getDataObjectDefinitions(); + + for (DataObjectDefinition doDefinition : doDefinitions) { + dataObjects.add(new DataObject(doDefinition, typeDeclarations, this)); + } + + } else + throw new SclParserException(lnNode, "wrong type " + this.lnType + " for logical node"); + + /* Parse data set definitions */ + dataSets = new LinkedList(); + + List dataSetNodes = ParserUtils.getChildNodesWithTag(lnNode, "DataSet"); + for (Node dataSet : dataSetNodes) + dataSets.add(new DataSet(dataSet)); + + /* Parse report control block definitions */ + reportControlBlocks = new LinkedList(); + + List reportControlNodes = ParserUtils.getChildNodesWithTag(lnNode, "ReportControl"); + + for (Node reportControlNode : reportControlNodes) + reportControlBlocks.add(new ReportControlBlock(reportControlNode)); + + /* Parse GSE control block definitions */ + gseControlBlocks = new LinkedList(); + + List gseControlNodes = ParserUtils.getChildNodesWithTag(lnNode, "GSEControl"); + for (Node gseControlNode : gseControlNodes) + gseControlBlocks.add(new GSEControl(gseControlNode)); + + /* Parse log control block definitions */ + logControlBlocks = new LinkedList(); + + List logControlNodes = ParserUtils.getChildNodesWithTag(lnNode, "LogControl"); + for (Node logControlNode : logControlNodes) + logControlBlocks.add(new LogControl(logControlNode)); + + /* Parse logs */ + logs = new LinkedList(); + + List logNodes = ParserUtils.getChildNodesWithTag(lnNode, "Log"); + for (Node logNode : logNodes) + logs.add(new Log(logNode)); + + + /* Parse setting group control block definitions */ + settingGroupControlBlocks = new LinkedList(); + + List sgNodes = ParserUtils.getChildNodesWithTag(lnNode, "SettingControl"); + + if ((this.lnClass.equals("LLN0") == false) && (sgNodes.size() > 0)) + throw new SclParserException(lnNode, "LN other than LN0 is not allowed to contain SettingControl"); + + if (sgNodes.size() > 1) + throw new SclParserException(lnNode, "LN contains more then one SettingControl"); + + for (Node sgNode : sgNodes) + settingGroupControlBlocks.add(new SettingControl(sgNode)); + + /* Parse data object instances */ + List doiNodes = ParserUtils.getChildNodesWithTag(lnNode, "DOI"); + + for (Node doiNode : doiNodes) { + String doiName = ParserUtils.parseAttribute(doiNode, "name"); + + DataObject dataObject = (DataObject) getChildByName(doiName); + + if (dataObject == null) + throw new SclParserException(doiNode, "Missing data object with name \"" + doiName + "\""); + + parseDataAttributeNodes(doiNode, dataObject); + + parseSubDataInstances(doiNode, dataObject); + } + } + + private void parseDataAttributeNodes(Node doiNode, DataModelNode dataObject) + throws SclParserException { + List daiNodes = ParserUtils.getChildNodesWithTag(doiNode, "DAI"); + + for (Node daiNode : daiNodes) { + String daiName = ParserUtils.parseAttribute(daiNode, "name"); + + DataAttribute dataAttribute = (DataAttribute) dataObject.getChildByName(daiName); + + if (dataAttribute == null) + throw new SclParserException(daiNode, "Missing data attribute with name \"" + daiName + "\""); + + Node valNode = ParserUtils.getChildNodeWithTag(daiNode, "Val"); + + if (valNode != null) { + String value = valNode.getTextContent(); + + try { + dataAttribute.setValue(new DataModelValue(dataAttribute.getType(), dataAttribute.getSclType(), value)); + } catch (IllegalValueException e) { + throw new SclParserException(valNode, e.getMessage()); + } + } + + String shortAddress = ParserUtils.parseAttribute(daiNode, "sAddr"); + + if (shortAddress != null) { + + if (!shortAddress.equals("")) + dataAttribute.setShortAddress(shortAddress); + } + + } + } + + private void parseSubDataInstances(Node doiNode, DataModelNode dataObject) + throws SclParserException { + List sdiNodes = ParserUtils.getChildNodesWithTag(doiNode, "SDI"); + + for (Node sdiNode : sdiNodes) { + String sdiName = ParserUtils.parseAttribute(sdiNode, "name"); + + DataModelNode subDataAttribute = dataObject.getChildByName(sdiName); + + if (subDataAttribute == null) + System.out.println("subelement with name " + sdiName + " not found!"); + + parseDataAttributeNodes(sdiNode, subDataAttribute); + + parseSubDataInstances(sdiNode, subDataAttribute); + } + } + + public String getLnClass() { + return lnClass; + } + + public String getLnType() { + return lnType; + } + + public String getInst() { + return inst; + } + + public String getDesc() { + return desc; + } + + public String getPrefix() { + return prefix; + } + + public String getName() { + String name = ""; + + if (prefix != null) + name += prefix; + + name += lnClass; + + name += inst; + + return name; + } + + public List getDataObjects() { + return dataObjects; + } + + public List getDataSets() { + return dataSets; + } + + public List getReportControlBlocks() { + return reportControlBlocks; + } + + public List getGSEControlBlocks() { + return gseControlBlocks; + } + + public List getSettingGroupControlBlocks() { + return settingGroupControlBlocks; + } + + @Override + public DataModelNode getChildByName(String childName) { + for (DataObject dataObject : dataObjects) { + if (dataObject.getName().equals(childName)) + return dataObject; + } + + return null; + } + + + public LogicalDevice getParentLogicalDevice() { + return parentLogicalDevice; + } + + @Override + public SclType getSclType() { + return sclType; + } + + @Override + public DataModelNode getParent() { + return null; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java b/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java new file mode 100644 index 0000000..a55e662 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java @@ -0,0 +1,134 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class OptionFields { + + /* + * #define RPT_OPT_SEQ_NUM 1 #define RPT_OPT_TIME_STAMP 2 #define + * RPT_OPT_REASON_FOR_INCLUSION 4 #define RPT_OPT_DATA_SET 8 #define + * RPT_OPT_DATA_REFERENCE 16 #define RPT_OPT_BUFFER_OVERFLOW 32 #define + * RPT_OPT_ENTRY_ID 64 #define RPT_OPT_CONF_REV 128 + */ + private boolean seqNum = false; + private boolean timeStamp = false; + private boolean dataSet = false; + private boolean reasonCode = false; + private boolean dataRef = false; + private boolean entryID = false; + private boolean configRef = false; + private boolean bufOvfl = true; + + /** + * Get integer value for report options + * + * @return + */ + public int getIntValue() { + int intValue = 0; + + if (seqNum) intValue += 1; + if (timeStamp) intValue += 2; + if (reasonCode) intValue += 4; + if (dataSet) intValue += 8; + if (dataRef) intValue += 16; + if (bufOvfl) intValue += 32; + if (entryID) intValue += 64; + if (configRef) intValue += 128; + + return intValue; + } + + public OptionFields(Node optFieldsNode) throws SclParserException { + Boolean boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "seqNum"); + if (boolVal != null) + this.seqNum = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "timeStamp"); + if (boolVal != null) + this.timeStamp = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "dataSet"); + if (boolVal != null) + this.dataSet = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "reasonCode"); + if (boolVal != null) + this.reasonCode = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "dataRef"); + if (boolVal != null) + this.dataRef = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "entryID"); + if (boolVal != null) + this.entryID = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "bufOvfl"); + if (boolVal != null) + this.configRef = boolVal; + + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "reasonCode"); + if (boolVal != null) + this.bufOvfl = boolVal; + } + + public boolean isSeqNum() { + return seqNum; + } + + public boolean isTimeStamp() { + return timeStamp; + } + + public boolean isDataSet() { + return dataSet; + } + + public boolean isReasonCode() { + return reasonCode; + } + + public boolean isDataRef() { + return dataRef; + } + + public boolean isEntryID() { + return entryID; + } + + public boolean isConfigRef() { + return configRef; + } + + public boolean isBufOvfl() { + return bufOvfl; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/ReportControlBlock.java b/tools/model_generator/src/com/libiec61850/scl/model/ReportControlBlock.java new file mode 100644 index 0000000..7a2d9c5 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/ReportControlBlock.java @@ -0,0 +1,156 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class ReportControlBlock { + + private String name; + private String desc; + private String dataSet; + private Long integrityPeriod = null; + private String rptID; + private Long confRef = null; + private boolean buffered = false; + private long bufferTime = 0; + private TriggerOptions triggerOptions = null; + private OptionFields optionFields = null; + private boolean indexed = true; + private RptEnabled rptEna = null; + + public ReportControlBlock(Node reportControlNode) throws SclParserException { + + this.name = ParserUtils.parseAttribute(reportControlNode, "name"); + this.desc = ParserUtils.parseAttribute(reportControlNode, "desc"); + this.dataSet = ParserUtils.parseAttribute(reportControlNode, "datSet"); + String intgPdString = ParserUtils.parseAttribute(reportControlNode, "intgPd"); + + if (intgPdString != null) + this.integrityPeriod = new Long(intgPdString); + + this.rptID = ParserUtils.parseAttribute(reportControlNode, "rptID"); + + if (this.rptID != null) { + if (this.rptID.equals("")) + this.rptID = null; + } + + String confRefStr = ParserUtils.parseAttribute(reportControlNode, "confRev"); + + if (confRefStr != null) + this.confRef = new Long(confRefStr); + else + throw new SclParserException("Missing required attribute \"confRef\""); + + Boolean bufferedVal = ParserUtils.parseBooleanAttribute(reportControlNode, "buffered"); + + if (bufferedVal != null) + this.buffered = bufferedVal; + + String bufferTimeStr = ParserUtils.parseAttribute(reportControlNode, "bufTime"); + + if (bufferTimeStr != null) + this.bufferTime = new Long(bufferTimeStr); + + Node trgOpsNode = ParserUtils.getChildNodeWithTag(reportControlNode, "TrgOps"); + + if (trgOpsNode != null) + this.triggerOptions = new TriggerOptions(trgOpsNode); + else + this.triggerOptions = new TriggerOptions(); // use default values if no node present + + Node optFieldsNode = ParserUtils.getChildNodeWithTag(reportControlNode, "OptFields"); + + this.optionFields = new OptionFields(optFieldsNode); + + Boolean indexed = ParserUtils.parseBooleanAttribute(reportControlNode, "indexed"); + + if (indexed != null) + this.indexed = indexed.booleanValue(); + + Node rptEnabledNode = ParserUtils.getChildNodeWithTag(reportControlNode, "RptEnabled"); + + if (rptEnabledNode != null) { + RptEnabled rptEna = new RptEnabled(rptEnabledNode); + + if (this.indexed == false) { + if (rptEna.getMaxInstances() != 1) + throw new SclParserException("RptEnabled.max != 1 is not allowed when indexed=\"false\""); + } + + this.rptEna = rptEna; + } + + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public String getDataSet() { + return dataSet; + } + + public Long getIntegrityPeriod() { + return integrityPeriod; + } + + public String getRptID() { + return rptID; + } + + public Long getConfRef() { + return confRef; + } + + public boolean isBuffered() { + return buffered; + } + + public long getBufferTime() { + return bufferTime; + } + + public TriggerOptions getTriggerOptions() { + return triggerOptions; + } + + public OptionFields getOptionFields() { + return optionFields; + } + + public boolean isIndexed() { + return indexed; + } + + public RptEnabled getRptEna() { + return rptEna; + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java b/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java new file mode 100644 index 0000000..6fb90d3 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java @@ -0,0 +1,28 @@ +package com.libiec61850.scl.model; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; + +public class RptEnabled { + + private int maxInstances = 1; + private String desc = null; + + public RptEnabled(Node rptEnabledNode) { + this.desc = ParserUtils.parseAttribute(rptEnabledNode, "desc"); + String maxString = ParserUtils.parseAttribute(rptEnabledNode, "max"); + + if (maxString != null) { + maxInstances = new Integer(maxString); + } + } + + public int getMaxInstances() { + return maxInstances; + } + + public String getDesc() { + return desc; + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/Server.java b/tools/model_generator/src/com/libiec61850/scl/model/Server.java new file mode 100644 index 0000000..cbecd28 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/Server.java @@ -0,0 +1,65 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.types.TypeDeclarations; + +public class Server { + + private Authentication authentication = null; + private List logicalDevices; + + public Server(Node serverNode, TypeDeclarations typeDeclarations) throws SclParserException { + Node authenticationNode = ParserUtils.getChildNodeWithTag(serverNode, "Authentication"); + + if (authenticationNode != null) + this.authentication = new Authentication(authenticationNode); + + List ldNodes = ParserUtils.getChildNodesWithTag(serverNode, "LDevice"); + + if (ldNodes.size() == 0) + throw new SclParserException(serverNode, "No logical devices defined for AccessPoint"); + + logicalDevices = new LinkedList(); + + for (Node ldNode : ldNodes) { + logicalDevices.add(new LogicalDevice(ldNode, typeDeclarations)); + } + + } + + public Authentication getAuthentication() { + return authentication; + } + + public List getLogicalDevices() { + return logicalDevices; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/SettingControl.java b/tools/model_generator/src/com/libiec61850/scl/model/SettingControl.java new file mode 100644 index 0000000..ce320bd --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/SettingControl.java @@ -0,0 +1,61 @@ +package com.libiec61850.scl.model; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +/* + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +public class SettingControl { + + private String desc; + private int numOfSGs = 1; + private int actSG = 1; + + public SettingControl(Node settingControlNode) throws SclParserException { + desc = ParserUtils.parseAttribute(settingControlNode, "desc"); + + String numOfSGsString = ParserUtils.parseAttribute(settingControlNode, "numOfSGs"); + + if (numOfSGsString != null) + numOfSGs = Integer.decode(numOfSGsString); + + String actSGString = ParserUtils.parseAttribute(settingControlNode, "actSG"); + + if (actSGString != null) + actSG = Integer.decode(actSGString); + } + + public String getDesc() { + return desc; + } + + public int getNumOfSGs() { + return numOfSGs; + } + + public int getActSG() { + return actSG; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/TriggerOptions.java b/tools/model_generator/src/com/libiec61850/scl/model/TriggerOptions.java new file mode 100644 index 0000000..1f4b104 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/TriggerOptions.java @@ -0,0 +1,105 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class TriggerOptions { + + private boolean dchg = false; /* 1 */ + private boolean qchg = false; /* 2 */ + private boolean dupd = false; /* 4 */ + private boolean period = false; /* 8 */ + private boolean gi = true; /* 16 */ + + public TriggerOptions(Node trgOpsNode) throws SclParserException { + + Boolean dchgVal = ParserUtils.parseBooleanAttribute(trgOpsNode, "dchg"); + if (dchgVal != null) + this.dchg = dchgVal; + + Boolean qchgVal = ParserUtils.parseBooleanAttribute(trgOpsNode, "qchg"); + if (qchgVal != null) + this.qchg = qchgVal; + + Boolean dupdVal = ParserUtils.parseBooleanAttribute(trgOpsNode, "dupd"); + if (dupdVal != null) + this.dupd = dupdVal; + + Boolean periodVal = ParserUtils.parseBooleanAttribute(trgOpsNode, "period"); + if (periodVal != null) + this.period = periodVal; + + Boolean giVal = ParserUtils.parseBooleanAttribute(trgOpsNode, "gi"); + if (giVal != null) + this.gi = giVal; + } + + /** Constructor for default values when trigger options are not present */ + public TriggerOptions() { + // nothing to do + } + + public TriggerOptions(boolean dchg, boolean qchg, boolean dupd, boolean period, boolean gi) { + this.dchg = dchg; + this.qchg = qchg; + this.dupd = dupd; + this.period = period; + this.gi = gi; + } + + public int getIntValue() { + int intValue = 0; + + if (dchg) intValue += 1; + if (qchg) intValue += 2; + if (dupd) intValue += 4; + if (period) intValue += 8; + if (gi) intValue += 16; + + return intValue; + } + + public boolean isDchg() { + return dchg; + } + + public boolean isQchg() { + return qchg; + } + + public boolean isDupd() { + return dupd; + } + + public boolean isPeriod() { + return period; + } + + public boolean isGi() { + return gi; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java b/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java new file mode 100644 index 0000000..928547c --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java @@ -0,0 +1,78 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.libiec61850.scl.DataAttributeDefinition; +import com.libiec61850.scl.SclParserException; + +public class DataAttributeType extends SclType { + + private List subDataAttributes = null; + + private DataAttributeDefinition getDataAttributeByName(String name) { + for (DataAttributeDefinition dad : subDataAttributes) { + if (dad.getName().equals(name)) + return dad; + } + + return null; + } + + public DataAttributeType(Node xmlNode) throws SclParserException { + super(xmlNode); + + NodeList elementNodes = xmlNode.getChildNodes(); + + if (elementNodes != null) { + this.subDataAttributes = new LinkedList(); + + for (int i = 0; i < elementNodes.getLength(); i++) { + Node elementNode = elementNodes.item(i); + + if (elementNode.getNodeName().equals("BDA")) { + DataAttributeDefinition dad = new DataAttributeDefinition(elementNode); + + if (getDataAttributeByName(dad.getName()) != null) { + throw new SclParserException(xmlNode, + "DA type definition contains multiple elements of name \"" + + dad.getName() + "\""); + } + + + subDataAttributes.add(dad); + } + + } + } + } + + public List getSubDataAttributes() { + return subDataAttributes; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java b/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java new file mode 100644 index 0000000..3e0f345 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java @@ -0,0 +1,126 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.libiec61850.scl.DataAttributeDefinition; +import com.libiec61850.scl.DataObjectDefinition; +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class DataObjectType extends SclType { + + private String cdc = null; + + private List dataAttributes = null; + private List subDataObjects = null; + + private DataAttributeDefinition getDataAttributeByName(String name) { + for (DataAttributeDefinition dad : dataAttributes) { + if (dad.getName().equals(name)) + return dad; + } + + return null; + } + + private DataObjectDefinition getDataObjectByName(String name) { + for (DataObjectDefinition dod : subDataObjects) { + if (dod.getName().equals(name)) + return dod; + } + + return null; + } + + public DataObjectType(Node xmlNode) throws SclParserException { + super(xmlNode); + + this.cdc = ParserUtils.parseAttribute(xmlNode, "cdc"); + + if (this.cdc == null) + throw new SclParserException(xmlNode, "cdc is missing!"); + + NodeList elementNodes = xmlNode.getChildNodes(); + + if (elementNodes != null) { + this.dataAttributes = new LinkedList(); + this.subDataObjects = new LinkedList(); + + for (int i = 0; i < elementNodes.getLength(); i++) { + Node elementNode = elementNodes.item(i); + + if (elementNode.getNodeName().equals("DA")) { + DataAttributeDefinition dad = new DataAttributeDefinition(elementNode); + + DataAttributeDefinition otherDefinition = getDataAttributeByName(dad.getName()); + + if (otherDefinition != null) { + + if (otherDefinition.getFc() == dad.getFc()) + throw new SclParserException(xmlNode, + "DO type definition contains multiple elements of name \"" + + dad.getName() + "\""); + } + + if (getDataObjectByName(dad.getName()) != null) { + throw new SclParserException(xmlNode, + "DO type definition contains multiple elements of name \"" + + dad.getName() + "\""); + } + + + dataAttributes.add(dad); + } + else if (elementNode.getNodeName().equals("SDO")) { + DataObjectDefinition dod = new DataObjectDefinition(elementNode); + + if ((getDataAttributeByName(dod.getName()) != null) || + (getDataObjectByName(dod.getName()) != null)) + throw new SclParserException(xmlNode, + "DO type definition contains multiple elements of name \"" + + dod.getName() + "\""); + + this.subDataObjects.add(dod); + } + + } + } + } + + public String getCdc() { + return cdc; + } + + public List getDataAttributes() { + return dataAttributes; + } + + public List getSubDataObjects() { + return subDataObjects; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/EnumerationType.java b/tools/model_generator/src/com/libiec61850/scl/types/EnumerationType.java new file mode 100644 index 0000000..8c494bd --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/EnumerationType.java @@ -0,0 +1,92 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.libiec61850.scl.SclParserException; + +public class EnumerationType extends SclType { + + private List enumValues; + + public EnumerationType(Node xmlNode) throws SclParserException { + super(xmlNode); + parseEnumerationValueNodes(xmlNode); + } + + public EnumerationType(String name) { + super(name, null); + this.enumValues = new LinkedList(); + } + + static List getDefaultEnumTypes() { + LinkedList defaultTypes = new LinkedList(); + + return defaultTypes; + } + + private void addEnumValue(EnumerationValue enumValue) { + this.enumValues.add(enumValue); + } + + private void parseEnumerationValueNodes(Node enumTypeNode) throws SclParserException { + NodeList elements = enumTypeNode.getChildNodes(); + + if (elements != null) { + this.enumValues = new LinkedList(); + + Node enumValueNode; + + for (int i = 0; i < elements.getLength(); i++) { + enumValueNode = elements.item(i); + + if (enumValueNode.getNodeName().equals("EnumVal")) + this.enumValues.add(new EnumerationValue(enumValueNode)); + + } + } + } + + public int getOrdByEnumString(String enumString) throws IllegalValueException { + for (EnumerationValue value : enumValues) { + if (value.getSymbolicName().equals(enumString)) + return value.getOrd(); + } + + throw new IllegalValueException("Enum has no value " + enumString); + } + + + public boolean isValidOrdValue(int ordValue) { + for (EnumerationValue enumValue : enumValues) { + if (enumValue.getOrd() == ordValue) + return true; + } + + return false; + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/EnumerationValue.java b/tools/model_generator/src/com/libiec61850/scl/types/EnumerationValue.java new file mode 100644 index 0000000..e1236df --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/EnumerationValue.java @@ -0,0 +1,59 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class EnumerationValue { + private String symbolicName; + private int ord; + + public EnumerationValue(String symbolicName, int ord) { + this.symbolicName = symbolicName; + this.ord = ord; + } + + public EnumerationValue(Node xmlNode) throws SclParserException { + String ordString = ParserUtils.parseAttribute(xmlNode, "ord"); + + if (ordString == null) + throw new SclParserException(xmlNode, "ord attribute missing"); + + this.ord = new Integer(ordString); + + this.symbolicName = xmlNode.getTextContent(); + } + + public String getSymbolicName() { + return symbolicName; + } + + public int getOrd() { + return ord; + } + + + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/IllegalValueException.java b/tools/model_generator/src/com/libiec61850/scl/types/IllegalValueException.java new file mode 100644 index 0000000..3161d70 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/IllegalValueException.java @@ -0,0 +1,29 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +public class IllegalValueException extends Exception { + public IllegalValueException(String message) { + super(message); + } + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/LogicalNodeType.java b/tools/model_generator/src/com/libiec61850/scl/types/LogicalNodeType.java new file mode 100644 index 0000000..1ddbfe8 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/LogicalNodeType.java @@ -0,0 +1,81 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.LinkedList; +import java.util.List; +import org.w3c.dom.Node; + +import com.libiec61850.scl.DataObjectDefinition; +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class LogicalNodeType extends SclType { + + private String lnClass = null; + private List dataObjects = null; + + public LogicalNodeType(Node lnNode) throws SclParserException { + super(lnNode); + + parseAttributes(lnNode); + + parseDataObjectNodes(lnNode); + } + + private DataObjectDefinition getObjectDefinitionByName(String name) { + for (DataObjectDefinition dod : dataObjects) { + if (dod.getName().equals(name)) + return dod; + } + + return null; + } + + private void parseDataObjectNodes(Node lnNode) throws SclParserException { + dataObjects = new LinkedList(); + + List doNodeList = ParserUtils.getChildNodesWithTag(lnNode, "DO"); + + for (Node doNode : doNodeList) { + DataObjectDefinition dod = new DataObjectDefinition(doNode); + + if (getObjectDefinitionByName(dod.getName()) != null) + throw new SclParserException(lnNode, "Logical node contains multiple data objects with name \"" + dod.getName() + "\""); + + this.dataObjects.add(dod); + } + } + + private void parseAttributes(Node lnNode) throws SclParserException { + this.lnClass = ParserUtils.parseAttribute(lnNode, "lnClass"); + + if (this.lnClass == null) + throw new SclParserException(lnNode, "no lnClass attribute"); + } + + public List getDataObjectDefinitions() { + return dataObjects; + } + + +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/SclType.java b/tools/model_generator/src/com/libiec61850/scl/types/SclType.java new file mode 100644 index 0000000..04c9e45 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/SclType.java @@ -0,0 +1,54 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class SclType { + + private String id = null; + private String description; + + public SclType(Node xmlNode) throws SclParserException { + this.id = ParserUtils.parseAttribute(xmlNode, "id"); + this.description = ParserUtils.parseAttribute(xmlNode, "desc"); + + if (this.id == null) + throw new SclParserException(xmlNode, "id is missing!"); + } + + public SclType(String id, String description) { + this.id = id; + this.description = description; + } + + public String getId() { + return id; + } + + public String getDesc() { + return description; + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/types/TypeDeclarations.java b/tools/model_generator/src/com/libiec61850/scl/types/TypeDeclarations.java new file mode 100644 index 0000000..4d9999a --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/types/TypeDeclarations.java @@ -0,0 +1,72 @@ +package com.libiec61850.scl.types; + +/* + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + + +public class TypeDeclarations { + + private List typeDeclarations; + + public TypeDeclarations() { + this.typeDeclarations = new LinkedList(); + + List defaultEnumTypes = EnumerationType.getDefaultEnumTypes(); + + for (EnumerationType enumType : defaultEnumTypes) { + this.typeDeclarations.add(enumType); + } + } + + public void addType(SclType sclType) { + this.typeDeclarations.add(sclType); + } + + public SclType lookupType(String typeId) { + for (SclType typeDeclaration : typeDeclarations) { + if (typeDeclaration.getId().equals(typeId)) + return typeDeclaration; + } + + System.out.println("Cannot find type " + typeId); + + return null; + } + + public SclType lookupType(String typeId, Class type) { + for (SclType typeDeclaration: typeDeclarations) { + if (typeDeclaration.getClass() == type) { + if (typeDeclaration.getId().equals(typeId)) + return typeDeclaration; + } + } + + System.out.println("Cannot find type " + typeId); + + return null; + } + +} diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java new file mode 100644 index 0000000..ac47251 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java @@ -0,0 +1,421 @@ +package com.libiec61850.tools; + +/* + * DynamicModelGenerator.java + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.List; + +import com.libiec61850.scl.DataAttributeDefinition; +import com.libiec61850.scl.SclParser; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.communication.ConnectedAP; +import com.libiec61850.scl.communication.GSEAddress; +import com.libiec61850.scl.model.AccessPoint; +import com.libiec61850.scl.model.DataAttribute; +import com.libiec61850.scl.model.DataModelValue; +import com.libiec61850.scl.model.DataObject; +import com.libiec61850.scl.model.DataSet; +import com.libiec61850.scl.model.FunctionalConstraintData; +import com.libiec61850.scl.model.GSEControl; +import com.libiec61850.scl.model.IED; +import com.libiec61850.scl.model.LogicalDevice; +import com.libiec61850.scl.model.LogicalNode; +import com.libiec61850.scl.model.ReportControlBlock; +import com.libiec61850.scl.model.SettingControl; + +public class DynamicModelGenerator { + + private ConnectedAP connectedAP; + private IED ied = null; + + public DynamicModelGenerator(InputStream stream, String icdFile, PrintStream output, String iedName, String accessPointName) + throws SclParserException { + + SclParser sclParser = new SclParser(stream); + + if (iedName == null) + ied = sclParser.getFirstIed(); + else + ied = sclParser.getIedByteName(iedName); + + if (ied == null) + throw new SclParserException("No data model present in SCL file! Exit."); + + AccessPoint accessPoint = null; + + if (accessPointName != null) + accessPoint = ied.getAccessPointByName(accessPointName); + else + accessPoint = ied.getFirstAccessPoint(); + + if (accessPoint == null) + throw new SclParserException("No valid access point found!"); + + this.connectedAP = sclParser.getConnectedAP(ied, accessPoint.getName()); + + List logicalDevices = accessPoint.getServer().getLogicalDevices(); + + output.println("MODEL(" + ied.getName() + "){"); + for (LogicalDevice logicalDevice : logicalDevices) { + output.print("LD("); + output.print(logicalDevice.getInst() + "){\n"); + + exportLogicalNodes(output, logicalDevice); + + output.println("}"); + } + output.println("}"); + } + + private void exportLogicalNodes(PrintStream output, LogicalDevice logicalDevice) { + for (LogicalNode logicalNode : logicalDevice.getLogicalNodes()) { + output.print("LN(" + logicalNode.getName() + "){\n"); + + exportLogicalNode(output, logicalNode); + + output.println("}"); + } + } + + private static String toMmsString(String iecString) { + return iecString.replace('.', '$'); + } + + private void exportLogicalNode(PrintStream output, LogicalNode logicalNode) { + + for (SettingControl sgcb : logicalNode.getSettingGroupControlBlocks()) { + output.print("SG(" + sgcb.getActSG() + " " + sgcb.getNumOfSGs() + ")\n"); + } + + for (DataObject dataObject : logicalNode.getDataObjects()) { + output.print("DO(" + dataObject.getName() + " " + dataObject.getCount() + "){\n"); + + exportDataObject(output, dataObject); + + output.println("}"); + } + + for (DataSet dataSet : logicalNode.getDataSets()) + exportDataSet(output, dataSet, logicalNode); + + for (ReportControlBlock rcb : logicalNode.getReportControlBlocks()) { + + if (rcb.isIndexed()) { + + int maxInstances = 1; + + if (rcb.getRptEna() != null) + maxInstances = rcb.getRptEna().getMaxInstances(); + + for (int i = 0; i < maxInstances; i++) { + String index = String.format("%02d", (i + 1)); + printRCBInstance(output, rcb, index); + } + } + else + printRCBInstance(output, rcb, ""); + } + + for (GSEControl gcb : logicalNode.getGSEControlBlocks()) { + LogicalDevice ld = logicalNode.getParentLogicalDevice(); + + GSEAddress gseAddress = null; + + if (connectedAP != null) + gseAddress = connectedAP.lookupGSEAddress(ld.getInst(), gcb.getName()); + else + System.out.println("WARNING: IED \"" + ied.getName() + "\" has no connected access point!"); + + output.print("GC("); + output.print(gcb.getName() + " "); + output.print(gcb.getAppID() + " "); + output.print(gcb.getDataSet() + " "); + output.print(gcb.getConfRev() + " "); + if (gcb.isFixedOffs()) + output.print('1'); + else + output.print('0'); + output.print(' '); + output.print(gcb.getMinTime()); + output.print(' '); + output.print(gcb.getMaxTime()); + output.print(' '); + + if (gseAddress == null) { + output.println(");"); + } + else { + output.println("){"); + + output.print("PA("); + output.print(gseAddress.getVlanPriority() + " "); + output.print(gseAddress.getVlanId() + " "); + output.print(gseAddress.getAppId() + " "); + + for (int i = 0; i < 6; i++) + output.printf("%02x", gseAddress.getMacAddress()[i]); + + output.println(");"); + + output.println("}"); + } + } + } + + private void printRCBInstance(PrintStream output, ReportControlBlock rcb, String index) { + output.print("RC("); + output.print(rcb.getName() + index + " "); + + if (rcb.getRptID() != null) + output.print(rcb.getRptID() + " "); + else + output.print("- "); + + if (rcb.isBuffered()) + output.print("1 "); + else + output.print("0 "); + + if (rcb.getDataSet() != null) + output.print(rcb.getDataSet() + " "); + else + output.print("- "); + + output.print(rcb.getConfRef() + " "); + output.print(rcb.getTriggerOptions().getIntValue() + " "); + + output.print(rcb.getOptionFields().getIntValue() + " "); + + output.print(rcb.getBufferTime() + " "); + + if (rcb.getIntegrityPeriod() != null) + output.print(rcb.getIntegrityPeriod()); + else + output.print("0"); + + output.println(");"); + } + + private void exportDataSet(PrintStream output, DataSet dataSet, LogicalNode logicalNode) { + output.print("DS(" + dataSet.getName() + "){\n"); + for (FunctionalConstraintData fcda : dataSet.getFcda()) { + String mmsVariableName = ""; + + if (fcda.getPrefix() != null) + mmsVariableName += fcda.getPrefix(); + + mmsVariableName += fcda.getLnClass(); + + if (fcda.getLnInstance() != null) + mmsVariableName += fcda.getLnInstance(); + + mmsVariableName += "$" + fcda.getFc().toString(); + + mmsVariableName += "$" + toMmsString(fcda.getDoName()); + + if (fcda.getDaName() != null) + mmsVariableName += "$" + toMmsString(fcda.getDaName()); + + String logicalDeviceName = null; + + if (fcda.getLdInstance() != null) { + + if (!fcda.getLdInstance().equals(logicalNode.getParentLogicalDevice().getInst())) { + logicalDeviceName = fcda.getLdInstance(); + } + } + + + if (logicalDeviceName != null) + output.print("DE(" + logicalDeviceName + "/" + mmsVariableName + ");\n"); + else + output.print("DE(" + mmsVariableName + ");\n"); + + } + output.println("}"); + } + + private void exportDataObject(PrintStream output, DataObject dataObject) { + for (DataObject subDataObject : dataObject.getSubDataObjects()) { + output.print("DO(" + subDataObject.getName() + " " + subDataObject.getCount() + "){\n"); + + exportDataObject(output, subDataObject); + + output.println("}"); + } + + for (DataAttribute dataAttribute : dataObject.getDataAttributes()) { + exportDataAttribute(output, dataAttribute); + } + } + + private void exportDataAttribute(PrintStream output, DataAttribute dataAttribute) { + + output.print("DA(" + dataAttribute.getName() + " "); + output.print(dataAttribute.getCount() + " "); + output.print(dataAttribute.getType().getIntValue() + " "); + output.print(dataAttribute.getFc().getIntValue() + " "); + output.print(dataAttribute.getTriggerOptions().getIntValue() + " "); + + Long sAddr = null; + + try { + if (dataAttribute.getShortAddress() != null) + sAddr = new Long(dataAttribute.getShortAddress()); + } catch (NumberFormatException e) { + System.out.println("WARNING: short address \"" + dataAttribute.getShortAddress() + "\" is not valid for libIEC61850!\n"); + } + + if (sAddr != null) + output.print(sAddr.longValue()); + else + output.print("0"); + + output.print(")"); + + if (dataAttribute.isBasicAttribute()) { + DataModelValue value = dataAttribute.getValue(); + + /* if no value is given use default value for type if present */ + if (value == null) { + value = dataAttribute.getDefinition().getValue(); + + if (value != null) + if (value.getValue() == null) + value.updateEnumOrdValue(ied.getTypeDeclarations()); + } + + if (value != null) { + + switch (dataAttribute.getType()) { + case ENUMERATED: + case INT8: + case INT16: + case INT32: + case INT64: + output.print("=" + value.getIntValue()); + break; + case INT8U: + case INT16U: + case INT24U: + case INT32U: + output.print("=" + value.getLongValue()); + break; + case BOOLEAN: + { + Boolean boolVal = (Boolean) value.getValue(); + + if (boolVal.booleanValue()) + output.print("=1"); + } + break; + case UNICODE_STRING_255: + output.print("=\"" + value.getValue()+ "\""); + break; + case VISIBLE_STRING_32: + case VISIBLE_STRING_64: + case VISIBLE_STRING_129: + case VISIBLE_STRING_255: + case VISIBLE_STRING_65: + output.print("=\"" + value.getValue()+ "\""); + break; + case FLOAT32: + case FLOAT64: + output.print("=" + value.getValue()); + break; + default: + System.out.println("Unknown default value for " + dataAttribute.getName() + " type: " + dataAttribute.getType()); + break; + } + + } + + output.println(";"); + } + else { + output.println("{"); + + for (DataAttribute subDataAttribute : dataAttribute.getSubDataAttributes()) { + exportDataAttribute(output, subDataAttribute); + } + + output.println("}"); + } + + } + + public static void main(String[] args) throws FileNotFoundException { + System.out.println("Dynamic model generator"); + + if (args.length < 1) { + System.out.println("Usage: genconfig [-ied ] [-ap ] []"); + System.exit(1); + } + + String icdFile = args[0]; + + PrintStream outputStream = System.out; + + String accessPointName = null; + String iedName = null; + + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + if (args[i].equals("-ap")) { + accessPointName = args[i+1]; + + System.out.println("Select access point " + accessPointName); + + i++; + } + else if (args[i].equals("-ied")) { + iedName = args[i+1]; + + System.out.println("Select IED " + iedName); + + i++; + + } + else { + outputStream = new PrintStream(new FileOutputStream(new File(args[i]))); + } + } + + } + + InputStream stream = new FileInputStream(icdFile); + + try { + new DynamicModelGenerator(stream, icdFile, outputStream, iedName, accessPointName); + } catch (SclParserException e) { + System.err.println("ERROR: " + e.getMessage()); + } + } + +} diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java new file mode 100644 index 0000000..c35b839 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java @@ -0,0 +1,1103 @@ +package com.libiec61850.tools; + +/* + * StaticModelGenerator.java + * + * Copyright 2013, 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; + +import com.libiec61850.scl.SclParser; +import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.communication.Communication; +import com.libiec61850.scl.communication.ConnectedAP; +import com.libiec61850.scl.communication.GSE; +import com.libiec61850.scl.communication.GSEAddress; +import com.libiec61850.scl.communication.SubNetwork; +import com.libiec61850.scl.model.AccessPoint; +import com.libiec61850.scl.model.DataAttribute; +import com.libiec61850.scl.model.DataModelValue; +import com.libiec61850.scl.model.DataObject; +import com.libiec61850.scl.model.DataSet; +import com.libiec61850.scl.model.FunctionalConstraint; +import com.libiec61850.scl.model.FunctionalConstraintData; +import com.libiec61850.scl.model.GSEControl; +import com.libiec61850.scl.model.IED; +import com.libiec61850.scl.model.LogicalDevice; +import com.libiec61850.scl.model.LogicalNode; +import com.libiec61850.scl.model.ReportControlBlock; +import com.libiec61850.scl.model.Server; +import com.libiec61850.scl.model.SettingControl; +import com.libiec61850.scl.model.TriggerOptions; + +public class StaticModelGenerator { + + private List variablesList; + private PrintStream cOut; + private PrintStream hOut; + + private StringBuffer initializerBuffer; + + private StringBuffer reportControlBlocks; + private List rcbVariableNames; + private int currentRcbVariableNumber = 0; + + private StringBuffer gseControlBlocks; + private List gseVariableNames; + private int currentGseVariableNumber = 0; + + private StringBuffer settingGroupControlBlocks; + private List sgcbVariableNames; + private int currentSGCBVariableNumber = 0; + + private List dataSetNames; + + private Communication communication; + + private ConnectedAP connectedAP; + + private IED ied; + private AccessPoint accessPoint; + + private String outputFileName; + private String hDefineName; + private String modelPrefix; + private boolean initializeOnce; + + public StaticModelGenerator(InputStream stream, String icdFile, PrintStream cOut, PrintStream hOut, + String outputFileName, String iedName, String accessPointName, String modelPrefix, + boolean initializeOnce) throws SclParserException + { + this.cOut = cOut; + this.hOut = hOut; + this.initializerBuffer = new StringBuffer(); + this.reportControlBlocks = new StringBuffer(); + this.rcbVariableNames = new LinkedList(); + this.gseControlBlocks = new StringBuffer(); + this.gseVariableNames = new LinkedList(); + + this.settingGroupControlBlocks = new StringBuffer(); + this.sgcbVariableNames = new LinkedList(); + + SclParser sclParser = new SclParser(stream); + + this.outputFileName = outputFileName; + this.hDefineName = outputFileName.toUpperCase().replace( '.', '_' ).replace( '-', '_' ) + "_H_"; + this.modelPrefix = modelPrefix; + this.initializeOnce = initializeOnce; + + if( hDefineName.lastIndexOf( '/' ) >= 0 ) + { + hDefineName = hDefineName.substring( hDefineName.lastIndexOf( '/' ) + 1 ); + } + + ied = null; + + if (iedName == null) + ied = sclParser.getFirstIed(); + else + ied = sclParser.getIedByteName(iedName); + + if (ied == null) + System.out.println("IED model not found in SCL file! Exit."); + + accessPoint = null; + + if (accessPointName == null) + accessPoint = ied.getFirstAccessPoint(); + else + accessPoint = ied.getAccessPointByName(accessPointName); + + connectedAP = sclParser.getConnectedAP(ied, accessPoint.getName()); + + printCFileHeader(icdFile); + + printHeaderFileHeader(icdFile); + + variablesList = new LinkedList(); + + Server server = accessPoint.getServer(); + + printForwardDeclarations(server); + + printDeviceModelDefinitions(); + + printInitializerFunction(); + + printVariablePointerDefines(); + + printHeaderFileFooter(); + } + + private void printInitializerFunction() { + cOut.println("\nstatic void\ninitializeValues()"); + cOut.println("{"); + cOut.print(this.initializerBuffer); + cOut.println("}"); + } + + public static void main(String[] args) throws FileNotFoundException { + if (args.length < 1) { + System.out.println("Usage: genmodel [-ied ] [-ap ] [-out ] [-modelprefix ]"); + System.exit(1); + } + + String icdFile = args[0]; + + String outputFileName = "static_model"; + + String accessPointName = null; + String iedName = null; + String modelPrefix = "iedModel"; + boolean initializeOnce = false; + + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + if (args[i].equals("-ap")) { + accessPointName = args[i+1]; + + System.out.println("Select access point " + accessPointName); + + i++; + } + else if (args[i].equals("-ied")) { + iedName = args[i+1]; + + System.out.println("Select IED " + iedName); + + i++; + + } + else if (args[i].equals("-out")) { + outputFileName = args[i+1]; + + System.out.println("Select Output File " + outputFileName); + + i++; + + } + else if (args[i].equals("-modelprefix")) { + modelPrefix = args[i+1]; + + System.out.println("Select Model Prefix " + modelPrefix); + + i++; + + } + else if (args[i].equals("-initializeonce")) { + initializeOnce = true; + + System.out.println("Select Initialize Once"); + + } + else { + System.out.println("Unknown option: \"" + args[i] + "\""); + } + } + + } + + PrintStream cOutStream = new PrintStream(new FileOutputStream(new File(outputFileName + ".c"))); + PrintStream hOutStream = new PrintStream(new FileOutputStream(new File(outputFileName + ".h"))); + + System.out.println("Select ICD File " + icdFile); + InputStream stream = new FileInputStream(icdFile); + + try { + new StaticModelGenerator(stream, icdFile, cOutStream, hOutStream, outputFileName, iedName, accessPointName, modelPrefix, initializeOnce); + } catch (SclParserException e) { + System.err.println("ERROR: " + e.getMessage()); + } + } + + private void printVariablePointerDefines() { + hOut.println("\n\n"); + + for (String variableName : variablesList) { + String name = modelPrefix.toUpperCase() + variableName.substring( modelPrefix.length() ); + hOut.println("#define " + name + " (&" + variableName + ")"); + } + } + +// private String getLogicalDeviceName(LogicalDevice logicalDevice) { +// String logicalDeviceName = logicalDevice.getLdName(); +// +// if (logicalDeviceName == null) +// logicalDeviceName = ied.getName() + logicalDevice.getInst(); +// +// return logicalDeviceName; +// } + + private String getLogicalDeviceInst(LogicalDevice logicalDevice) { + return logicalDevice.getInst(); + } + + private void printDeviceModelDefinitions() { + + printDataSets(); + + List logicalDevices = accessPoint.getServer().getLogicalDevices(); + + createReportVariableList(logicalDevices); + + createGooseVariableList(logicalDevices); + + createSettingControlsVariableList(logicalDevices); + + for (int i = 0; i < logicalDevices.size(); i++) { + + LogicalDevice logicalDevice = logicalDevices.get(i); + + String ldName = modelPrefix + "_" + logicalDevice.getInst(); + + variablesList.add(ldName); + + String logicalDeviceName = getLogicalDeviceInst(logicalDevice); + + cOut.println("\nLogicalDevice " + ldName + " = {"); + + cOut.println(" LogicalDeviceModelType,"); + + cOut.println(" \"" + logicalDeviceName + "\","); + + cOut.println(" (ModelNode*) &" + modelPrefix + ","); + + if (i < (logicalDevices.size() - 1)) + cOut.println(" (ModelNode*) &" + modelPrefix + "_" + logicalDevices.get(i + 1).getInst() + ","); + else + cOut.println(" NULL,"); + + String firstChildName = ldName + "_" + logicalDevice.getLogicalNodes().get(0).getName(); + + cOut.println(" (ModelNode*) &" + firstChildName); + cOut.println("};\n"); + + printLogicalNodeDefinitions(ldName, logicalDevice.getLogicalNodes()); + } + + + for (String rcb : rcbVariableNames) + cOut.println("extern ReportControlBlock " + rcb + ";"); + + cOut.println(); + + cOut.println(reportControlBlocks); + + for (String gcb : gseVariableNames) + cOut.println("extern GSEControlBlock " + gcb + ";"); + + cOut.println(gseControlBlocks); + + for (String sgcb : sgcbVariableNames) + cOut.println("extern SettingGroupControlBlock " + sgcb + ";"); + + cOut.println(settingGroupControlBlocks); + + String firstLogicalDeviceName = logicalDevices.get(0).getInst(); + cOut.println("\nIedModel " + modelPrefix + " = {"); + cOut.println(" \"" + ied.getName() + "\","); + cOut.println(" &" + modelPrefix + "_" + firstLogicalDeviceName + ","); + + if (dataSetNames.size() > 0) + cOut.println(" &" + dataSetNames.get(0) + ","); + else + cOut.println(" NULL,"); + + if (rcbVariableNames.size() > 0) + cOut.println(" &" + rcbVariableNames.get(0) + ","); + else + cOut.println(" NULL,"); + + if (gseVariableNames.size() > 0) + cOut.println(" &" + gseVariableNames.get(0) + ","); + else + cOut.println(" NULL,"); + + if (sgcbVariableNames.size() > 0) + cOut.println(" &" + sgcbVariableNames.get(0) + ","); + else + cOut.println(" NULL,"); + + cOut.println(" initializeValues\n};"); + } + + private void createGooseVariableList(List logicalDevices) { + for (LogicalDevice ld : logicalDevices) { + List lnodes = ld.getLogicalNodes(); + + String ldName = ld.getInst(); + + for (LogicalNode ln : lnodes) { + List goCBs = ln.getGSEControlBlocks(); + + int gseCount = 0; + + for (GSEControl gse : goCBs) { + String gcbVariableName = modelPrefix + "_" + ldName + "_" + ln.getName() + "_gse" + gseCount; + gseVariableNames.add(gcbVariableName); + gseCount++; + } + } + } + } + + private void createReportVariableList(List logicalDevices) { + + for (LogicalDevice ld : logicalDevices) { + List lnodes = ld.getLogicalNodes(); + + String ldName = ld.getInst(); + + for (LogicalNode ln : lnodes) { + List rcbs = ln.getReportControlBlocks(); + + int rcbCount = 0; + + for (ReportControlBlock rcb : rcbs) { + + int maxInstances = 1; + + if (rcb.getRptEna() != null) + maxInstances = rcb.getRptEna().getMaxInstances(); + + for (int i = 0; i < maxInstances; i++) { + String rcbVariableName = modelPrefix + "_" + ldName + "_" + ln.getName() + "_report" + rcbCount; + rcbVariableNames.add(rcbVariableName); + rcbCount++; + } + + } + } + } + } + + private void createSettingControlsVariableList(List logicalDevices) { + for (LogicalDevice ld : logicalDevices) { + List lnodes = ld.getLogicalNodes(); + + String ldName = ld.getInst(); + + for (LogicalNode ln : lnodes) { + List sgcbs = ln.getSettingGroupControlBlocks(); + + for (SettingControl sgcb : sgcbs) { + + String sgcbVariableName = modelPrefix + "_" + ldName + "_" + ln.getName() + "_sgcb"; + + sgcbVariableNames.add(sgcbVariableName); + + } + } + } + } + + private void printLogicalNodeDefinitions(String ldName, List logicalNodes) { + for (int i = 0; i < logicalNodes.size(); i++) { + LogicalNode logicalNode = logicalNodes.get(i); + + String lnName = ldName + "_" + logicalNode.getName(); + + variablesList.add(lnName); + + cOut.println("LogicalNode " + lnName + " = {"); + cOut.println(" LogicalNodeModelType,"); + cOut.println(" \"" + logicalNode.getName() + "\","); + cOut.println(" (ModelNode*) &" + ldName + ","); + if (i < (logicalNodes.size() - 1)) + cOut.println(" (ModelNode*) &" + ldName + "_" + logicalNodes.get(i + 1).getName() + ","); + else + cOut.println(" NULL,"); + + String firstChildName = lnName + "_" + logicalNode.getDataObjects().get(0).getName(); + + cOut.println(" (ModelNode*) &" + firstChildName + ","); + + cOut.println("};\n"); + + printDataObjectDefinitions(lnName, logicalNode.getDataObjects(), null); + + printReportControlBlocks(lnName, logicalNode); + + printGSEControlBlocks(ldName, lnName, logicalNode); + + printSettingControlBlock(lnName, logicalNode); + } + } + + private void printDataObjectDefinitions(String lnName, List dataObjects, String dataAttributeSibling) { + for (int i = 0; i < dataObjects.size(); i++) { + DataObject dataObject = dataObjects.get(i); + + String doName = lnName + "_" + dataObject.getName(); + + variablesList.add(doName); + + cOut.println("DataObject " + doName + " = {"); + cOut.println(" DataObjectModelType,"); + cOut.println(" \"" + dataObject.getName() + "\","); + cOut.println(" (ModelNode*) &" + lnName + ","); + + if (i < (dataObjects.size() - 1)) + cOut.println(" (ModelNode*) &" + lnName + "_" + dataObjects.get(i + 1).getName() + ","); + else if (dataAttributeSibling != null) + cOut.println(" (ModelNode*) &" + dataAttributeSibling + ","); + else + cOut.println(" NULL,"); + + String firstSubDataObjectName = null; + String firstDataAttributeName = null; + + if ((dataObject.getSubDataObjects() != null) && (dataObject.getSubDataObjects().size() > 0)) + firstSubDataObjectName = doName + "_" + dataObject.getSubDataObjects().get(0).getName(); + + if ((dataObject.getDataAttributes() != null) && (dataObject.getDataAttributes().size() > 0)) + firstDataAttributeName = doName + "_" + dataObject.getDataAttributes().get(0).getName(); + + if (firstSubDataObjectName != null) { + cOut.println(" (ModelNode*) &" + firstSubDataObjectName + ","); + } else if (firstDataAttributeName != null) { + cOut.println(" (ModelNode*) &" + firstDataAttributeName + ","); + } else { + cOut.println(" NULL,"); + } + + cOut.println(" " + dataObject.getCount()); + + cOut.println("};\n"); + + if (dataObject.getSubDataObjects() != null) + printDataObjectDefinitions(doName, dataObject.getSubDataObjects(), firstDataAttributeName); + + if (dataObject.getDataAttributes() != null) + printDataAttributeDefinitions(doName, dataObject.getDataAttributes()); + + } + } + + private void printDataAttributeDefinitions(String doName, List dataAttributes) { + for (int i = 0; i < dataAttributes.size(); i++) { + DataAttribute dataAttribute = dataAttributes.get(i); + + String daName = doName + "_" + dataAttribute.getName(); + + if (dataAttribute.getFc() == FunctionalConstraint.SE) { + + if (daName.startsWith(modelPrefix + "_SE_") == false) + daName = daName.substring(0, 9) + "SE_" + daName.substring(9); + + } + + variablesList.add(daName); + + cOut.println("DataAttribute " + daName + " = {"); + cOut.println(" DataAttributeModelType,"); + cOut.println(" \"" + dataAttribute.getName() + "\","); + cOut.println(" (ModelNode*) &" + doName + ","); + if (i < (dataAttributes.size() - 1)) { + DataAttribute sibling = dataAttributes.get(i + 1); + + String siblingDoName = doName; + + if (sibling.getFc() == FunctionalConstraint.SE) { + if (siblingDoName.startsWith(modelPrefix + "_SE_") == false) + siblingDoName = siblingDoName.substring(0, 9) + "SE_" + siblingDoName.substring(9); + } + + cOut.println(" (ModelNode*) &" + siblingDoName + "_" + dataAttributes.get(i + 1).getName() + ","); + } + else + cOut.println(" NULL,"); + if ((dataAttribute.getSubDataAttributes() != null) && (dataAttribute.getSubDataAttributes().size() > 0)) + cOut.println(" (ModelNode*) &" + daName + "_" + dataAttribute.getSubDataAttributes().get(0).getName() + ","); + else + cOut.println(" NULL,"); + + cOut.println(" " + dataAttribute.getCount() + ","); + cOut.println(" IEC61850_FC_" + dataAttribute.getFc().toString() + ","); + cOut.println(" " + dataAttribute.getType() + ","); + + /* print trigger options */ + cOut.print(" 0"); + + TriggerOptions trgOps = dataAttribute.getTriggerOptions(); + + if (trgOps.isDchg()) + cOut.print(" + TRG_OPT_DATA_CHANGED"); + + if (trgOps.isDupd()) + cOut.print(" + TRG_OPT_DATA_UPDATE"); + + if (trgOps.isQchg()) + cOut.print(" + TRG_OPT_QUALITY_CHANGED"); + + cOut.println(","); + + cOut.println(" NULL,"); + + Long sAddr = null; + + try { + if (dataAttribute.getShortAddress() != null) + sAddr = new Long(dataAttribute.getShortAddress()); + } catch (NumberFormatException e) { + System.out.println("WARNING: short address \"" + dataAttribute.getShortAddress() + "\" is not valid for libIEC61850!\n"); + } + + if (sAddr != null) + cOut.print(" " + sAddr.longValue()); + else + cOut.print(" 0"); + + cOut.println("};\n"); + + if (dataAttribute.getSubDataAttributes() != null) + + + printDataAttributeDefinitions(daName, dataAttribute.getSubDataAttributes()); + + DataModelValue value = dataAttribute.getValue(); + + /* if no value is given use default value for type if present */ + if (value == null) { + value = dataAttribute.getDefinition().getValue(); + + if (value != null) + if (value.getValue() == null) + value.updateEnumOrdValue(ied.getTypeDeclarations()); + } + + if (value != null) { + printValue(daName, dataAttribute, value); + } + + } + + } + + private void printValue(String daName, DataAttribute dataAttribute, DataModelValue value) { + + StringBuffer buffer = this.initializerBuffer; + + buffer.append("\n"); + if( initializeOnce ) + { + buffer.append("if (!"); + buffer.append(daName); + buffer.append(".mmsValue)\n"); + } + buffer.append(daName); + buffer.append(".mmsValue = "); + + switch (dataAttribute.getType()) { + case ENUMERATED: + case INT8: + case INT16: + case INT32: + case INT64: + buffer.append("MmsValue_newIntegerFromInt32(" + value.getIntValue() + ");"); + break; + case INT8U: + case INT16U: + case INT24U: + case INT32U: + buffer.append("MmsValue_newUnsignedFromUint32(" + value.getLongValue() + ");"); + break; + case BOOLEAN: + buffer.append("MmsValue_newBoolean(" + value.getValue() + ");"); + break; + case UNICODE_STRING_255: + buffer.append("MmsValue_newMmsString(\"" + value.getValue() + "\");"); + break; + case VISIBLE_STRING_32: + case VISIBLE_STRING_64: + case VISIBLE_STRING_129: + case VISIBLE_STRING_255: + case VISIBLE_STRING_65: + buffer.append("MmsValue_newVisibleString(\"" + value.getValue() + "\");"); + break; + case FLOAT32: + buffer.append("MmsValue_newFloat(" + value.getValue() + ");"); + break; + case FLOAT64: + buffer.append("MmsValue_newDouble(" + value.getValue() + ");"); + break; + default: + System.out.println("Unknown default value for " + daName + " type: " + dataAttribute.getType()); + buffer.append("NULL;"); + break; + } + + buffer.append("\n"); + + } + + private void printForwardDeclarations(Server server) { + + cOut.println("static void initializeValues();"); + hOut.println("extern IedModel " + modelPrefix + ";"); + + for (LogicalDevice logicalDevice : server.getLogicalDevices()) { + String ldName = modelPrefix + "_" + logicalDevice.getInst(); + + hOut.println("extern LogicalDevice " + ldName + ";"); + + for (LogicalNode logicalNode : logicalDevice.getLogicalNodes()) { + String lnName = ldName + "_" + logicalNode.getName(); + + hOut.println("extern LogicalNode " + lnName + ";"); + + printDataObjectForwardDeclarations(lnName, logicalNode.getDataObjects()); + } + + } + } + + private void printDataObjectForwardDeclarations(String prefix, List dataObjects) { + for (DataObject dataObject : dataObjects) { + String doName = prefix + "_" + dataObject.getName(); + + hOut.println("extern DataObject " + doName + ";"); + + if (dataObject.getSubDataObjects() != null) { + printDataObjectForwardDeclarations(doName, dataObject.getSubDataObjects()); + } + + printDataAttributeForwardDeclarations(doName, dataObject.getDataAttributes()); + } + } + + private void printDataAttributeForwardDeclarations(String doName, List dataAttributes) { + for (DataAttribute dataAttribute : dataAttributes) { + String daName = doName + "_" + dataAttribute.getName(); + + if (dataAttribute.getFc() == FunctionalConstraint.SE) { + + if (daName.startsWith(modelPrefix + "_SE_") == false) + daName = daName.substring(0, 9) + "SE_" + daName.substring(9); + } + + hOut.println("extern DataAttribute " + daName + ";"); + + if (dataAttribute.getSubDataAttributes() != null) + printDataAttributeForwardDeclarations(daName, dataAttribute.getSubDataAttributes()); + } + } + + private void printCFileHeader(String filename) { + + String include = outputFileName + ".h\""; + if( include.lastIndexOf( '/' ) >= 0 ) { + include = include.substring( include.lastIndexOf( '/' ) + 1 ); + } + + cOut.println("/*"); + cOut.println(" * " + outputFileName + ".c"); + cOut.println(" *"); + cOut.println(" * automatically generated from " + filename); + cOut.println(" */"); + cOut.println("#include \"" + include); + cOut.println(); + } + + private void printHeaderFileHeader(String filename) { + hOut.println("/*"); + hOut.println(" * " + outputFileName + ".h"); + hOut.println(" *"); + hOut.println(" * automatically generated from " + filename); + hOut.println(" */\n"); + hOut.println("#ifndef " + hDefineName); + hOut.println("#define " + hDefineName + "\n"); + hOut.println("#include "); + hOut.println("#include \"iec61850_model.h\""); + hOut.println(); + } + + private void printHeaderFileFooter() { + hOut.println(); + hOut.println("#endif /* " + hDefineName + " */\n"); + } + + private void printGSEControlBlocks(String ldName, String lnPrefix, LogicalNode logicalNode) { + List gseControlBlocks = logicalNode.getGSEControlBlocks(); + + String[] ldNameComponents = ldName.split("_"); + + String logicalDeviceName = ldNameComponents[1]; + + int gseControlNumber = 0; + + for (GSEControl gseControlBlock : gseControlBlocks) { + + GSEAddress gseAddress = connectedAP.lookupGSEAddress(logicalDeviceName, gseControlBlock.getName()); + + String gseString = ""; + + String phyComAddrName = ""; + + if (gseAddress != null) { + phyComAddrName = lnPrefix + "_gse" + gseControlNumber + "_address"; + + gseString += "\nstatic PhyComAddress " + phyComAddrName + " = {\n"; + gseString += " " + gseAddress.getVlanPriority() + ",\n"; + gseString += " " + gseAddress.getVlanId() + ",\n"; + gseString += " " + gseAddress.getAppId() + ",\n"; + gseString += " {"; + + for (int i = 0; i < 6; i++) { + gseString += "0x" + Integer.toHexString(gseAddress.getMacAddress()[i]); + if (i == 5) + gseString += "}\n"; + else + gseString += ", "; + } + + gseString += "};\n\n"; + } + + String gseVariableName = lnPrefix + "_gse" + gseControlNumber; + + gseString += "GSEControlBlock " + gseVariableName + " = {"; + gseString += "&" + lnPrefix + ", "; + + gseString += "\"" + gseControlBlock.getName() + "\", "; + + if (gseControlBlock.getAppID() == null) + gseString += "NULL, "; + else + gseString += "\"" + gseControlBlock.getAppID() + "\", "; + + if (gseControlBlock.getDataSet() != null) + gseString += "\"" + gseControlBlock.getDataSet() + "\", "; + else + gseString += "NULL, "; + + gseString += gseControlBlock.getConfRev() + ", "; + + if (gseControlBlock.isFixedOffs()) + gseString += "true, "; + else + gseString += "false, "; + + if (gseAddress != null) + gseString += "&" + phyComAddrName + ", "; + else + gseString += "NULL, "; + + gseString += gseControlBlock.getMinTime() + ", "; + gseString += gseControlBlock.getMaxTime() + ", "; + + currentGseVariableNumber++; + + if (currentGseVariableNumber < gseVariableNames.size()) + gseString += "&" + gseVariableNames.get(currentGseVariableNumber); + else + gseString += "NULL"; + + gseString += "};\n"; + + this.gseControlBlocks.append(gseString); + + gseControlNumber++; + } + } + + private void printReportControlBlocks(String lnPrefix, LogicalNode logicalNode) { + List reportControlBlocks = logicalNode.getReportControlBlocks(); + + int reportsCount = reportControlBlocks.size(); + + int reportNumber = 0; + + for (ReportControlBlock rcb : reportControlBlocks) { + + if (rcb.isIndexed()) { + + int maxInstances = 1; + + if (rcb.getRptEna() != null) + maxInstances = rcb.getRptEna().getMaxInstances(); + + for (int i = 0; i < maxInstances; i++) { + String index = String.format("%02d", (i + 1)); + + System.out.println("print report instance " + index); + + printReportControlBlockInstance(lnPrefix, rcb, index, reportNumber, reportsCount); + reportNumber++; + } + } else { + printReportControlBlockInstance(lnPrefix, rcb, "", reportNumber, reportsCount); + reportNumber++; + } + } + } + + private void printSettingControlBlock(String lnPrefix, LogicalNode logicalNode) + { + List settingControls = logicalNode.getSettingGroupControlBlocks(); + + if (settingControls.size() > 0) { + System.out.println("print SGCB for " + lnPrefix); + + SettingControl sgcb = settingControls.get(0); + + String sgcbVariableName = lnPrefix + "_sgcb"; + + String sgcbString = "\nSettingGroupControlBlock " + sgcbVariableName + " = {"; + + sgcbString += "&" + lnPrefix + ", "; + + sgcbString += sgcb.getActSG() + ", " + sgcb.getNumOfSGs() + ", 0, false, 0, 0, "; + + if (currentSGCBVariableNumber < (sgcbVariableNames.size() - 1)) + sgcbString += "&" + sgcbVariableNames.get(currentSGCBVariableNumber + 1); + else + sgcbString += "NULL"; + + sgcbString += "};\n"; + + this.settingGroupControlBlocks.append(sgcbString); + + currentSGCBVariableNumber++; + } + } + + private void printReportControlBlockInstance(String lnPrefix, ReportControlBlock rcb, String index, int reportNumber, int reportsCount) { + String rcbVariableName = lnPrefix + "_report" + reportNumber; + + String rcbString = "ReportControlBlock " + rcbVariableName + " = {"; + + rcbString += "&" + lnPrefix + ", "; + + rcbString += "\"" + rcb.getName() + index + "\", "; + + if (rcb.getRptID() == null) + rcbString += "NULL, "; + else + rcbString += "\"" + rcb.getRptID() + "\", "; + + if (rcb.isBuffered()) + rcbString += "true, "; + else + rcbString += "false, "; + + if (rcb.getDataSet() != null) + rcbString += "\"" + rcb.getDataSet() + "\", "; + else + rcbString += "NULL, "; + + if (rcb.getConfRef() != null) + rcbString += rcb.getConfRef().toString() + ", "; + else + rcbString += "0, "; + + int triggerOps = 16; + + if (rcb.getTriggerOptions() != null) + triggerOps = rcb.getTriggerOptions().getIntValue(); + + rcbString += triggerOps + ", "; + + int options = 0; + + if (rcb.getOptionFields() != null) { + if (rcb.getOptionFields().isSeqNum()) + options += 1; + if (rcb.getOptionFields().isTimeStamp()) + options += 2; + if (rcb.getOptionFields().isReasonCode()) + options += 4; + if (rcb.getOptionFields().isDataSet()) + options += 8; + if (rcb.getOptionFields().isDataRef()) + options += 16; + if (rcb.getOptionFields().isBufOvfl()) + options += 32; + if (rcb.getOptionFields().isEntryID()) + options += 64; + if (rcb.getOptionFields().isConfigRef()) + options += 128; + } else + options = 32; + + rcbString += options + ", "; + + rcbString += rcb.getBufferTime() + ", "; + + if (rcb.getIntegrityPeriod() != null) + rcbString += rcb.getIntegrityPeriod().toString() + ", "; + else + rcbString += "0, "; + + currentRcbVariableNumber++; + + if (currentRcbVariableNumber < rcbVariableNames.size()) + rcbString += "&" + rcbVariableNames.get(currentRcbVariableNumber); + else + rcbString += "NULL"; + + rcbString += "};\n"; + + this.reportControlBlocks.append(rcbString); + } + + private static String toMmsString(String iecString) { + return iecString.replace('.', '$'); + } + + private void printDataSets() { + + List logicalDevices = accessPoint.getServer().getLogicalDevices(); + + /* create list of data set names */ + dataSetNames = new LinkedList(); + + for (LogicalDevice logicalDevice : logicalDevices) { + + for (LogicalNode logicalNode : logicalDevice.getLogicalNodes()) { + + List dataSets = logicalNode.getDataSets(); + + for (DataSet dataSet : dataSets) { + + String dataSetVariableName = modelPrefix + "ds_" + logicalDevice.getInst() + "_" + logicalNode.getName() + "_" + dataSet.getName(); + + dataSetNames.add(dataSetVariableName); + } + } + } + + + /* print data set forward declarations */ + cOut.println(); + for (String dataSetName : dataSetNames) { + cOut.println("extern DataSet " + dataSetName + ";"); + } + cOut.println(); + + /* print data sets */ + int dataSetNameListIndex = 0; + + for (LogicalDevice logicalDevice : logicalDevices) { + + for (LogicalNode logicalNode : logicalDevice.getLogicalNodes()) { + + List dataSets = logicalNode.getDataSets(); + + for (DataSet dataSet : dataSets) { + + String dataSetVariableName = dataSetNames.get(dataSetNameListIndex++); + + int fcdaCount = 0; + + int numberOfFcdas = dataSet.getFcda().size(); + + String dataSetElements = ""; + + cOut.println(); + for (FunctionalConstraintData fcda : dataSet.getFcda()) { + String dataSetEntryName = dataSetVariableName + "_fcda" + fcdaCount; + + cOut.println("extern DataSetEntry " + dataSetEntryName + ";"); + + fcdaCount++; + } + cOut.println(); + + fcdaCount = 0; + + for (FunctionalConstraintData fcda : dataSet.getFcda()) { + String dataSetEntryName = dataSetVariableName + "_fcda" + fcdaCount; + + cOut.println("DataSetEntry " + dataSetEntryName + " = {"); + cOut.println(" \"" + fcda.getLdInstance() + "\","); + + String mmsVariableName = ""; + + if (fcda.getPrefix() != null) + mmsVariableName += fcda.getPrefix(); + + mmsVariableName += fcda.getLnClass(); + + if (fcda.getLnInstance() != null) + mmsVariableName += fcda.getLnInstance(); + + mmsVariableName += "$" + fcda.getFc().toString(); + + mmsVariableName += "$" + toMmsString(fcda.getDoName()); + + if (fcda.getDaName() != null) + mmsVariableName += "$" + toMmsString(fcda.getDaName()); + + // TODO implement index processing! + cOut.println(" false,"); + cOut.println(" \"" + mmsVariableName + "\","); + cOut.println(" -1,"); + cOut.println(" NULL,"); + cOut.println(" NULL,"); + + if (fcdaCount + 1 < numberOfFcdas) + cOut.println(" &" + dataSetVariableName + "_fcda" + (fcdaCount + 1)); + else + cOut.println(" NULL"); + + cOut.println("};\n"); + + fcdaCount++; + + if (fcdaCount != dataSet.getFcda().size()) + dataSetElements += " &" + dataSetEntryName + ",\n"; + else + dataSetElements += " &" + dataSetEntryName; + } + + cOut.println("DataSet " + dataSetVariableName + " = {"); + + String lnVariableName = modelPrefix + "_" + logicalDevice.getInst() + "_" + logicalNode.getName(); + + cOut.println(" \"" + logicalDevice.getInst() + "\","); + cOut.println(" \"" + logicalNode.getName() + "$" + dataSet.getName() + "\","); + cOut.println(" " + dataSet.getFcda().size() + ","); + cOut.println(" &" + dataSetVariableName + "_fcda0,"); + + if (dataSetNameListIndex < dataSetNames.size()) { + String nextDataSetVariableName = dataSetNames.get(dataSetNameListIndex); + cOut.println(" &" + nextDataSetVariableName); + } + else + cOut.println(" NULL"); + + cOut.println("};"); + + } + } + } + + } + +}