Compare commits

..

No commits in common. 'v1.5' and 'v1.2.2' have entirely different histories.
v1.5 ... v1.2.2

@ -1,26 +0,0 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'libiec61850'
dry-run: false
language: c
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'libiec61850'
fuzz-seconds: 300
dry-run: false
language: c
- name: Upload Crash
uses: actions/upload-artifact@v3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

@ -1,71 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ v1.5 ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ v1.5 ]
schedule:
- cron: '38 23 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

@ -1,12 +0,0 @@
name: Greetings
on: [pull_request, issues]
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: 'Push requests and other code contributions can only be accepted from authorized persons that have signed our contributor license agreement(CLA). When in doubt please write to info@libiec61850.com.'

2
.gitignore vendored

@ -1,2 +0,0 @@
build/
/Debug/

@ -1,350 +1,3 @@
Changes to version 1.5.3
------------------------
New features and improvements:
- config file parser dynamically allocates linebuffer to allow multithreaded applications (#484)
- parse time values in model configuration file (LIB61850-426)
- config file generator: added missing code for GSEControl (LIB61850-418)
- Config file generator: support multiple access points for GOOSE and SMV control blocks (LIB61850-418)
- config file generator: added code to add SMVCBs to config files (LIB61850-67)
- IED server: added code to create SMVCBs with the dynamic model API (LIB61850-67)
- MMS server: added support for write access with component alternate access (LIB61850-414)
- MMS client: added function MmsConnection_writeVariableComponent to write to variables with alternate component access (LIB61850-414)
- make write access to RCB elements configurable according to ReportSettings (LIB61850-404)
- Added function IedConnection_setLocalAddress to define local IP address and optionally local port of a client connection (LIB61850-378)
- IED server: added ControlAction_getSynchroCheck and ControlAction_getInterlockCheck functions
Fixed bugs and vulnerabilities:
- fixed - IEC 61580 server: dataset is not released when RCB.Datset is set to empty string by client (LIB61850-425)
- PAL: fixed wrong order of function arguments for fread and fwrite functions
- MMS client: parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469)
- fixed - potential memory leaks in goose publisher code (#464)
- fixed - server sends dchg report when only dupd is enabled in RCB (LIB61850-411)
- GOOSE subscriber: fixed - possible heap corruption in parseAllData due to missing validity check in bit-string handling (LIB61850-402)
- IED server: fixed problem with implicit ResvTms setting when reserved with RptEna (LIB61850-400)
- IED server: fixed - segmentation fault when compiled with CONFIG_MMS_THREADLESS_STACK (LIB61850-398)
- fixed - MMS server: messages can be corrupted when TCP buffer is full (LIB61850-385)
- fixed - .NET: IedConenction.WriteDataSetValues throws a NullReferenceException (LIB61850-384)
- fixed - server send invalid response- when client uses wrong ctlModel (LIB61850-383) (#435)
- fixed - IedConnection_setRCBValuesAsync crashes when RCB is already reserved by other client (LIB61850-382)
- fixed - outstanding call not released in IedConnection_getDataSetDirectoryAsync (LIB61850-379)
Changes to version 1.5.2 (Dec 19, 2022)
---------------------------------------
New features and improvements:
- renamed TLSConfiguration_EventLevel to TLSEventLevel
- updated required mbedtls version to 2.28.x
- Added check for changed CRL on socket read/write. Added reset of renegotiation ssl cache on CRL add
- Fixing Security events messages to match IEC62351-100-3
- .NET API: Added support for TLS event handler (LIB61850-373)
- IED Server: added function to set time quality for internally updated times (LIB61850-372)
- added TLSConnection object to provide more context in TLS event callback (LIB61850-366)
- TLS: added TLS alert callbacks; support for session resumption with session IDs (LIB61850-339)
- MMS client: added function MmsConnection_sendRawData for test purposes
- changed StringUtils_createStringInBuffer function to consider max buffer size (LIB61850-333)
- replaced most str(n)cpy/str(n)cat calls (LIB61850-333)
- encode boolean true value as 0x01 instead of 0xff to avoid interoperability problems
- added IedServerConfig_setSyncIntegrityReportTimes/IedServerConfig_setSyncIntegrityReportTimes wrapper to .NET API (LIB61850-323)
- added feature: synchronization of integrity report times (LIB61850-323)
- server: added RCBEventHandler event types REPORT_CREATED and OVERFLOW
- added function ReportControlBlock_getResv
- mms_utility: added option to read data set directory
- .NET API: added IedServer.GetFunctionalConstrainedData method (LIB61850-317)
- RCBEventHandler: replaced GI event by purgeBuf event when client disables RCB instance (LIB61850-316)
- enabled TLS 1.2 support in mbedtls configuration
- improved MmsValue handling; fixed MmsValue(OCTET-STRIG) maximum size problem (LIB61850-150)
- IED server: improved control state machine performance (LIB61850-312)
Fixed bugs and vulnerabilities:
- fixed - dynamic model helper functions: Check added to Cancel object for CDC APC
- fixed wrong number in TLS event code define (LIB61850_366)
- fixed - servers sends object-access-unsupported on GetAllData when ReadAccessHandler is installed (LIB61850-370)
- fixed - endless loop sending reports when MMS PDU size is too small (LIB61850-365)
- fixed path traversal vulnerability in MMS file services (LIB61850-357)
- IED server: added missing call to getNextRoundedStartTime (LIB61850-323)
- fixed - server crashs when SyncIntegrityReportTimes is active and IntgPd=0 (LIB61850-355)
- fixed - missing API export declarations for functions IedServerConfig_setSyncIntegrityReportTimes and IedServerConfig_getSyncIntegrityReportTimes (LIB61850-353)
- IED server: fixed - possible deadlock when IedServer_lockDataModel is used from multiple threads (LIB61850-352)
- MMS server: fixed - possible deadlock in obtainFile-service/file upload task (LIB61850-351)
- MMS server: fixed potential null pointer dereference when confirmeServiceResponse for fileOpen is received with invoke-id 0 (LIB61850-348)
- MMS_SERVER: fixed bug in getNameList request handling when domain ID is too long (LIB61850-346)
- GOOSE subscriber: fixed vulnerabilities related to malformed bit-string, integer, and unsigned values (LIB61850-342)
- MMS server: fixed bug in handling of continueAfter parameter of getNameList request (LIB61850-341)
- fixed sscanf format string in config_file_parser.c
- fixed locking mechanism in logging.c (LIB61850-327)
- fixed problem: negative presentation layer and ACSE results are ignored by client
- fixed wrong buffer size in client side report handling
- fixed memory leak in server read request handling (LIB61850-325)
- fixed memory leak in reuse of client connection (related to socket extension buffer)
- fixed - TLS: CRL is ignored
- fixed wrong MMS protocol version check (#379)
- fixed - SV publisher encoding problem when svID or datset length > 127 bytes (LIB61850-315)(#382)
- IedServerConfig: added missing variable initialization
- fixed - server doesn't respond SBOw when waiting for select callback (LIB61850-313)
Changes to version 1.5.1 (Mar 11, 2022)
---------------------------------------
New features and improvements:
- added server side ReportControlBlock events and value access functions
- added functions Timestamp_fromMmsValue and Quality_toMmsValue
- made server report reservation compatible with Ed. 2.1 (LIB61850-293)
- new functions MmsValue_getOctetStringOctet and MmsValue_setOctetStringOctet
- IedConnection: added function IedConnection_getDataSetDirectoryAsync
- IedConnection: added function IedConnection_createDataSetAsync
- IedConnection: added new function IedConnection_deleteDataSetAsync
- IedServer instance can be restarted
- new function IedConnection_setTimeQuality - Added support to set time quality for client generated time stamps (LIB61850-280)
- .NET API: added wrapper for IedConnection_setFile and IedConnection_setFilestoreBasepath (LIB61850-258)
- IED server: improved accuracy of integrity report intervals
- .NET API: GooseSubscriber - added GetGoId, GetGoCbRef, GetFataSet methods
- IED server: add support for SMV control blocks ("SMVC") in config file parser
- .NET API: added support for server integrated GOOSE publisher
- MacOS thread layer: replaced semaphore by mutex
Fixed bugs and vulnerabilities:
- fixed vulnerability of GOOSE subscriber to malformed messages (LIB61850-304)
- fixed - Bug in presentation layer parser can cause infinite loop (LIB61850-302)
- .NET API: fix problem with garbage collected delegates for async client functions (LIB61850-301)
- fixed compilation problem with option CONFIG_MMS_THREADLESS_STACK
- fixed - TPKT error when connection is interrupted during message reception (LIB61850-299)
- handle presentation layer data messages with transfer-syntax-name
- fixed - UBRB: library can't work at the same time with URCB with preconfigured client and URCB without preconfigured client (LIB61850-292)(#355)
- fix - server crashes when presentation message has no user data (LIB61850-291)(#368)
- MMS server: query log service returns services error instead of reject message when log does not exist (LIB61850-290)
- fixed - IED server: crash during invalid control access - FC=CO on invalid layer (LIB61850-282)
- fixed - Server: ctlNum and origin(status) are not updated automatically by the server when APC command is received (LIB61850-277)
- MMS server: fixed problem with continue-after in some get-name-list handling cases
- fixed - IedConnection: outstanding call on IEC layer is not release under some circumstances (LIB61850-270, LIB61850-251)
- fixed bug in IsoServer that caused memory violation when the server was restarted while a client was connected
- IED client: send RptEna as first element when RCB is to be disabled
- fixed problem with double free of TLS configuration structure (LIB61850-254)
- .NET API: Fixed problem with AccessViolationException in GooseControlBlock.GetDstAddress
- MMS server: fixed data race bug in transmitBuffer handling (#338)
- IED server: fixed crash when IEDName+LDInst is too long
- .NET API: fixed bug - server write access handler causes "CallbackOnCollectedDelegate" exception (LIB61850-236)
- MMS server: fixed potential crash when client connection closed during file upload (LIB61850-2)
- MMS client: fixed problem - doesn't close file when the setFile (obtainFile) service is interrupted e.g. due to connection loss (LIB61850-230)
- Ethernet Socket (Windows): fixed bug and added workaround for problem on Windows (most GOOSE/SV messages are not received when waiting with WaitForMultipleObjects - observed with winpcap 4.1.3 and Windows 10
- fixed problem in BER integer decoder (problem with GOOSE fixed length message decoding)
- .NET API: Fixed memory release problem in method ModelNode.GetObjectReference
- IED server: fixed bug in GoCBEventHandler
- fixed problem in BSD ethernet layer (#328)
- fixed bug in cmake file for BSD
- fixed compilation problem when compiling without GOOSE support (#325)
- IED server: control handling - fixed problem in test flag handling
- IED server: For SBOes check test flag match when accepting operate (sSBOes8)
- IED server: Reject Cancel/SBOw in WaitForChange state - fixed problem with test case sCtl26
Changes to version 1.5.0
------------------------
- added support for time with ns resolution
- IEC 61850 server: control models - allow delaying select response with check handler (new handler return value CONTROL_WAITING_FOR_SELECT)
- IEC 61850 server: added support to listen on multiple IP addresses and ports (new function IedServer_addAccessPoint)
- added support for service tracking
- added tool support for transient data objects
- .NET API: added more functions to create and access server data model
- IED server - control model - send AddCause with operate- for DOes, SBOes control models
- IED server: integrated GOOSE publisher - lock data model during GOOSE retransmission to avoid corrupted GOOSE data
- added server example for dead band handling
- IED server: make presence of RCB.Owner configurable at runtime with function IedServerConfig_enableOwnerForRCB (B1502/S1634)
- IED server: make presence of BRCB.ResvTms configurable at runtime with function IedServerConfig_enableResvTmsForBRCB (F1558)
- restrict maximum recursion depth in BerDecoder_decodeLength when indefinite length encoding is used to avoid stack overflow when receiving malformed messages
- fixed oss-fuzz issues 31399, 31340, 31341, 31344, 31346
- IED server: fixed bug in log service - old-entry and old-entry-time not updated
- IED server: added new function IedServer_handleWriteAccessForComplexAttribute. Changed WriteAccessHandler behavior when ACCESS_POLICY_ALLOW.
- MMS server: add compile time configuration options to enable/disable fileDelete and fileRename services (fileRename is now disabled by default)
- MMS server: better data model lock handling for performance improvements
- Linux - Ethernet: replace IFF_PROMISC by IFF_ALLMULTI
- improvements in Python wrapper code
- IED server: control models - fixed bug that only one control is unselected when connection closes
- IED server: fixed bug - logs (journals) are added to all logical devices instead of just the parents
- IED Server: prevent integrated GOOSE publisher to crash when ethernet socket cannot be created
- IED server: make compatible with tissue 1178
- IED server: reporting - implemented behavior according to tissue 1432
- IED server: WriteAccessHandler can tell the stack not to update the value when returning DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE
- IED server: fixed problem that BL FC is not writable (#287)
- IEC 61850 client: fixed dead lock in IedConnection_getFileAsync when fileRead times out (#285)
- IED server: added ControlSelectStateChangedHandler callback for control mode
- Client: fixed - IedConnection_getRCBValues doesn't check type of server response (#283)
- GOOSE subscriber: changed maximum GoID size according to tissue 770 (129 bytes)
- IED server: send AddCause for invalid origin also in case of direct control models
- IED server: support for configuration of EditSG service and online visibility of SGCB.ResvTms at runtime
- IED server: changed types TrkOps and OptFlds to variable length bit strings
- MMS: changed handling of variable sized bit strings (now also accepts bit strings of larger size, ignoring the bits that exceed the specified size)
- IED server: add support for correct CBB handling (required for test case sAss4) and initiate error PDU
- IED server: add support for tissue 807 (owner attribute in RCB is only present when ReportSettings@owner attribute is true)
- IED server: implemented tissue 1453 also for writing to "RptId" (purgeBuf only executed when value changes)
- GOOSE subscriber: always copy GoID and DatSet from GOOSE message; always create new MmsValue instance for GOOSE data set when subscriber is observer
- IED server: added configuration file support for data set entries with array elements or array element components
- fixed problems in handling array elements and array element components
- fixed bug in MmsConnection_readMultipleVariables: send invaid messsage and memory access errors when too many items are passed to the function exhausting MMS payload size
- IEC 61850 server: fixed problem with test case sRp4 - RCB RptID attribute is not empty after writing empty string
- fixed program crash when normal mode parameers are missing in presentation layer (#252)
- IED Server/GOOSE: Don't send GOOSE message with new event while data model is locked
- GOOSE: added GOOSE observer feature (GooseSubscriber listening to all GOOSE messages) and GOOSE observer example
- COTP: fixed possible heap buffer overflow when handling message with invalid (zero) value in length field (#250)
- IEC 61850 server: fixed - cancel command for time activated control returns object-access-denied even in case of success
- IEC 61850 client: fixed bug - IedConnection_setRCBValuesAsync always return 0 instead of invoke-ID
- MMS: fixed problem in handling of indefinite length encoded BER elements
- IEC 61850 client: reporting - support data set entries with multiple reasons for inclusion
- Java tools: moved minTime, maxTime from GSEControl to GSE; updated GOOSE server example CID file
- IEC 61850 server: Added ControlAction_setError function - with this function the user application can control the error code used in LastApplError and CommandTermination messages
- IEC 61850 server: fixed problem with logging when log data set contains FCDO (#225)
Changes to version 1.4.2.1
--------------------------
- IEC 61850 server: RCB - fixed problem that other client can "steal" reservation
- MMS client: fixed bug in log entry parsing (#224)
- IEC 61850 server: fixed potential null pointer dereference in multi-thread mode when server is stopped
- IEC 61850 server: fixed bug in single threaded mode (windows)
- IEC 61850 server: fixed compilation error in single thread mode (was new in release 1.4.2)
Changes to version 1.4.2
-------------------------
- IEC 61850 server: wait for background thread termination before data model is released
- MMS server: fixed potential crash when get-named-variable-list-attributes response doesn't fit in MMS PDU. Server returns service error in this case
- IEC 61850 server: unbuffered reporting - send first integrity report after integrity timeout (before it was sent when the RCB was enabled)
- IEC 61850 server: allow server to start without logical devices in data model (#218)
- IEC 61850 client: fixed bug in ClientReportControlBlock - some allowed structures for RCB were rejected
- IEC 61850 server: control - unselect when operate with wrong origin parameters, check if check parameter matches for SBO
- IEC 61850 server: fixed missing report timestamp update for unbuffered reporting
- IEC 618580 server: Added function IedServer_setServerIdentity to set values for MMS identity service
- CDC helpers: added functions to create ISC and BAC CDCs
- CDC helpers: added stSeld and attributes from ControlTestingCDC to control CDCs
- CDC helper functions: added stSeld and attributes from ControlTestingCDC to control CDCs
- updated cmake files
- .NET API: fixed memory management issue in MmsValue.SetElement (see #213)
- IEC 61850 server: unselect control when oper is not accepted
- IEC 61850 server: send select-failed for control when origin parameter is not valid
- IEC 61850 server: fixed control handling to comply with test case sCtl25
- IEC 61850 server: fixed control handling to comply with test case sCtl11
- IEC 61850 server: pass origin, ctlNum, ctlVal to select handler (perform check handler) for SBOw
- removed internal header files from install target (#214)
- .NET API: additional function mappings
- TLS: fixed memory leak when TLS authentication fails
- fixed bug in windows socket layer
Changes to version 1.4.1
------------------------
- MMS server: refactored connection handling; more efficient use of HandleSet
- linux/bsd socket layer: replaced select by poll
- removed header dependencies from API headers
- IEC 61850 server: added support for transient data objects
- .NET API: added MmsValue methods BitStringToUInt32BigEndian and BitStringFromUInt32BigEndian
- fixed compilation problem when CONFIG_MMS_THREADLESS_STACK is defined
- MMS get name list service: fixed wrong return value in case of unknown argument for continueAfter (problem with test case sSrvN1)
- fixed memory leak in windows socket layer (socket connect)
- improved robustness in MMS message parsing
- SV publisher: fixed memory leaks (#191)
- .NET API: added ControlAction.GetControlTime methods
- .NET API: fixed problem in ReportControlBlock.SetRCBValues (see #184)
- MMS server: fixed possible crash when client disconnects during file upload
- MMS server: fixed file upload error with multi-threaded server, added some NULL checks to file-handling.
- IEC 61850 server: added function ConfigFileParser_createModelFromConfigFileEx with filename as argument to avoid dependency on FileSystem_... functions
- IEC 61850 server: Add check call before starting a timeactivated operate, so operates can be denied before the waiting state
- IEC 61850 client: improved error handling and fixed potential memory leak in IedConnection_getDeviceModelFromServer
- replaced timegm implementation on windows. Fixes bug with MMS file times
Changes to version 1.4.0
------------------------
- IEC 61850 client: added asynchronous client API (can handle multiple outstanding requests in a single thread)
- IEC 61850 client: added support for non-thread mode (for use with asynchronous API)
- IEC 61850 client: added IedConnection_StateChangedHandler callback that is called for each connection state change
- .NET API: Added support for IedConnection.GetState and StateChangedHandler
- modelviewer: show full hierarchy including sub data objects
- IEC 61850 server: added IedServer_updateCtlModel function to change control model at runtime
- IEC 61850 client: added functions IedConnection_getLogicalDeviceVariables, IedConnection_getLogicalDeviceDataSets, and IedConnection_getLogicalDeviceDataSetsAsync to address #89
- .NET API: extended MmsValue.ToString method to print arrays and data access errors
- common: MmsVariableSpecification_getChildValue now also accepts "." as separator
- .NET API: ReportControlBlock.GetOwner returns null when no owner available (#79)
- IEC 61850 client: IedConnection - added CONNECTING AND CLOSING states - removed IDLE state (CLOSED, CONNECTING, CONNECTED, CLOSING)
- now using mbedtls 2.16
- TLS renegotiation disabled by default
- fixed bug in BerInteger_setUint16
- IEC 61850 client: Added functions IedConnection_setRequestTimeout and IedConnection_getRequestTimeout to C API and IedConnection.RequestTimeout property to .NET API
- MMS client: fixed problem with obtain file timeout with large files
- IEC 61850 server: Control model callback signature changed. Added ControlAction object to access control related parameters in control callbacks
- SV subscriber: improved error handling when Ethernet access doesn't work; fixed potential memory leak
- GOOSE publisher: integrated error handling when Ethernet interface is not available
- GOOSE receiver: add support for operation without Ethernet HAL implementation
- MMS server: fixed memory access problem when client unexpectedly closed connection during file upload (set-file)
- static model generator: Initialize Dbpos value from Val element in ICD/CID file (see github #163)
Changes to version 1.3.3
------------------------
- IEC 61850 server: reporting - fixed problem with removing old GI reports when latest report is also GI
- IEC 61850 client: fixed problems in ClientReportControlBlock_create (see github #134)
- IEC 61850 client: handle reason code correctly when report contains data with different reason code (see github #133)
- IEC 61850 server: optimized report buffer handling for buffered reporting (save memory and encoding time)
- IEC 61850 client: fixed problem - IedConnection cannot be reused after IedConnection_close (github #124)
- IEC 61850 server: added support for pre configured client with ClientLN
- IEC 61850 client: added function ClientReportControlBlock_hasResvTms
- IEC 61850 server: don't clear owner when client disables BRCB (RptEna = false)
- IED Server: added ResvTms handling for BRCB
- SV publisher: fixed length calculation
- IEC 61850 server: added support for segmented reporting
- fixed bug in windows socket abstraction
- fixed client TCP keep alive problem (see github #115)
- MMS server: read service - return data access error for component access to simple variable
- GOOSE receiver: fixed potential deadlock when GooseReceiver_stop is called directly after GooseReceiver_start
Changes to version 1.3.2
------------------------
- MMS client/server: added support for component alternate access for generic variable read requests
- MMS client: improved handling/stability when receiving malformed messages from the server
- IEC 61850 server: fixed problem with wrong purge buffer invocation when using dynamic data set in buffered report control block
- .NET API: add GetFileDirectoryEx function
- modelviewer: show full hierarchy including sub data objects
- .NET API: DataSet implements IDisposable interface, Report/DataSet GetValues methods return now clones of the original native values to prevent GC issues
- .NET API: MmsValue - added Clone method and implemented IDisposable interface
Changes to version 1.3.1
------------------------
- GOOSE publisher: fixed problem in payload length calculation
- .NET API: Added method MmsConnection.ReadMultipleVariables
- IEC 61850 client: implemented tissue 1178 client side (select-response+ is
non-NULL)
- SV publisher: fixed RefrTm and SmpSynch handling
- IEC 61850 client: improved support for handling segmented reports
- .NET API: Added some additional access function to ReportControlBlock
- Java SCL parser: added support for timestamp values in "Val" elements
- fixed bug in cmake file (winpcap support)
- added C# example code for client side setting group handling
- .NET API: added some additional wrapper code for MmsVariableSpecification functions
Changes to version 1.3.0
------------------------
- IEC 61850 server: more features configurable at runtime
- IEC 61850 server: control objects - fixed bug in select response for SBO control model
- IEC 61850 client: add support for single array element access (with component specification)
- MMS server: add support for array element (index) access with nested component
- IEC 61850 server: made IEC 61850 edition configurable at runtime
- IEC 61850 server: added ReadAccessHandler to control read access
- HAL: unified platform abstraction layer (to simplify using the library together with lib60870)
- IEC 61850 server: fixed bug when calling write access handler (wrong pointer for ClientConnection object)
- updated IEC 61850-9-2 LE example to be more realistic
- added server side example for the substitution service
- MMS server: fixed wrong preprocessor defines that can cause problems in some configurations (unlimited number of client connections/ multi-threaded server)
- IEC 61850 client: added new function ControlObjectClient_getCtlValType to simplify control handling
- IEC 61850 server: reporting - don't delete pending events when buffered report is enabled and dataset didn't change
- fixed bug in MmsValue_update
- MMS server: fixed bug in delete variable list service - scope of delete was not considered optional
- some more small bug fixes and optimizations
Changes to version 1.2.2
------------------------
@ -355,7 +8,6 @@ Changes to version 1.2.2
- TLS client: fixed problem with high CPU load
- ISO connection: fixed race condition that can cause corrupted messages
- .NET API: added project files for .NET core 2.0
- .NET API: added server side support for TLS
Changes to version 1.2.1
------------------------

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5.1)
cmake_minimum_required(VERSION 2.8)
# automagically detect if we should cross-compile
if(DEFINED ENV{TOOLCHAIN})
@ -11,8 +11,8 @@ project(libiec61850)
ENABLE_TESTING()
set(LIB_VERSION_MAJOR "1")
set(LIB_VERSION_MINOR "5")
set(LIB_VERSION_PATCH "3")
set(LIB_VERSION_MINOR "2")
set(LIB_VERSION_PATCH "2")
set(LIB_VERSION "${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/")
@ -33,28 +33,16 @@ option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)
option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" ON)
option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF)
set(CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS 5 CACHE STRING "Configure the maximum number of get file tasks")
set(CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 100 CACHE STRING "Configure the maximum number of dataSet members")
option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON)
option(CONFIG_INCLUDE_GOOSE_SUPPORT "Build with GOOSE support" ON)
option(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB "Build with pre-compiled mbedtls dynamic library" OFF)
set(CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/library" CACHE STRING "Path to search for the mbedtls dynamic libraries" )
set(CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include" CACHE STRING "Path to search for the mbedtls include files" )
# choose the library features which shall be included
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_LOG_SERVICE "Build with support for IEC 61850 logging services" ON)
option(CONFIG_IEC61850_SERVICE_TRACKING "Build with support for IEC 61850 service tracking" ON)
option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON)
option(CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL "Allow user provided callback to control read access" ON)
option(CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT "allow only configured clients (when pre-configured by ClientLN)" OFF)
set(CONFIG_IEC61850_SG_RESVTMS 300 CACHE STRING "Configure the maximum number of SG RESVTMS")
set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "65536" CACHE STRING "Default buffer size for buffered reports in byte" )
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)
@ -72,6 +60,22 @@ option(DEBUG_SV_SUBSCRIBER "Enable Sampled Values subscriber debugging" ${DEBUG}
option(DEBUG_SV_PUBLISHER "Enable Sampled Values publisher debugging" ${DEBUG})
option(DEBUG_HAL_ETHERNET "Enable Ethernet HAL printf debugging" ${DEBUG})
#mark_as_advanced(
# DEBUG_SOCKET
# DEBUG_COTP
# DEBUG_ISO_SERVER
# DEBUG_ISO_CLIENT
# DEBUG_IED_SERVER
# DEBUG_IED_CLIENT
# DEBUG_MMS_SERVER
# DEBUG_MMS_CLIENT
# DEBUG_GOOSE_SUBSCRIBER
# DEBUG_GOOSE_PUBLISHER
# DEBUG_SV_SUBSCRIBER
# DEBUG_SV_PUBLISHER
# DEBUG_HAL_ETHERNET
#)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}/config
${CMAKE_CURRENT_LIST_DIR}/src/common/inc
@ -84,18 +88,21 @@ include_directories(
${CMAKE_CURRENT_LIST_DIR}/src/mms/inc_private
${CMAKE_CURRENT_LIST_DIR}/src/mms/iso_mms/asn1c
${CMAKE_CURRENT_LIST_DIR}/src/logging
${CMAKE_CURRENT_LIST_DIR}/src/tls
)
set(API_HEADERS
hal/inc/hal_base.h
hal/inc/hal_time.h
hal/inc/hal_thread.h
hal/inc/hal_filesystem.h
hal/inc/hal_ethernet.h
hal/inc/hal_socket.h
hal/inc/tls_config.h
src/hal/inc/hal_time.h
src/hal/inc/hal_thread.h
src/hal/inc/hal_filesystem.h
src/hal/inc/hal_ethernet.h
src/hal/inc/platform_endian.h
src/common/inc/libiec61850_common_api.h
src/common/inc/libiec61850_platform_includes.h
src/common/inc/linked_list.h
src/common/inc/byte_buffer.h
src/common/inc/lib_memory.h
src/common/inc/string_utilities.h
src/iec61850/inc/iec61850_client.h
src/iec61850/inc/iec61850_common.h
src/iec61850/inc/iec61850_server.h
@ -106,64 +113,54 @@ set(API_HEADERS
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/mms_server.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
src/goose/goose_publisher.h
src/sampled_values/sv_subscriber.h
src/sampled_values/sv_publisher.h
src/logging/logging_api.h
src/tls/tls_api.h
${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h
)
if(MSVC AND MSVC_VERSION LESS 1800)
if(MSVC)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/src/vs
)
endif(MSVC AND MSVC_VERSION LESS 1800)
if(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
set(WITH_MBEDTLS 1)
set(USE_PREBUILD_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR ${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH})
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
endif(MSVC)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0)
set(WITH_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include")
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0)
if(WITH_MBEDTLS)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/src/tls/mbedtls
${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0/include
)
file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0/library/*.c)
add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1)
add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h")
endif(WITH_MBEDTLS)
include(CheckCCompilerFlag)
check_c_compiler_flag("-Wredundant-decls" SUPPORT_REDUNDANT_DECLS)
if (SUPPORT_REDUNDANT_DECLS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wredundant-decls")
endif(SUPPORT_REDUNDANT_DECLS)
# write the detected stuff to this file
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/stack_config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h
)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/hal/inc
)
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/hal")
if(DEBUG)
set(CMAKE_BUILD_TYPE Debug)
endif(DEBUG)
if(BUILD_EXAMPLES)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/examples)
endif(BUILD_EXAMPLES)
@ -194,5 +191,3 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
include(CPack)
endif(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")

@ -31,42 +31,30 @@ 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 += hal/socket/win32
LIB_SOURCE_DIRS += hal/thread/win32
LIB_SOURCE_DIRS += hal/ethernet/win32
LIB_SOURCE_DIRS += hal/filesystem/win32
LIB_SOURCE_DIRS += hal/time/win32
LIB_SOURCE_DIRS += hal/serial/win32
LIB_SOURCE_DIRS += hal/memory
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 += hal/socket/linux
LIB_SOURCE_DIRS += hal/thread/linux
LIB_SOURCE_DIRS += hal/ethernet/linux
LIB_SOURCE_DIRS += hal/filesystem/linux
LIB_SOURCE_DIRS += hal/time/unix
LIB_SOURCE_DIRS += hal/serial/linux
LIB_SOURCE_DIRS += hal/memory
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 += hal/socket/bsd
LIB_SOURCE_DIRS += hal/thread/bsd
LIB_SOURCE_DIRS += hal/ethernet/bsd
LIB_SOURCE_DIRS += hal/filesystem/linux
LIB_SOURCE_DIRS += hal/time/unix
LIB_SOURCE_DIRS += hal/memory
else ifeq ($(HAL_IMPL), MACOS)
LIB_SOURCE_DIRS += hal/socket/bsd
LIB_SOURCE_DIRS += hal/thread/macos
LIB_SOURCE_DIRS += hal/ethernet/bsd
LIB_SOURCE_DIRS += hal/filesystem/linux
LIB_SOURCE_DIRS += hal/time/unix
LIB_SOURCE_DIRS += hal/memory
LIB_SOURCE_DIRS += src/hal/socket/bsd
LIB_SOURCE_DIRS += src/hal/thread/bsd
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 += hal/inc
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/sampled_values
LIB_INCLUDE_DIRS += src/iec61850/inc
@ -78,10 +66,10 @@ LIB_INCLUDE_DIRS += third_party/winpcap/Include
endif
ifdef WITH_MBEDTLS
LIB_SOURCE_DIRS += third_party/mbedtls/mbedtls-2.28/library
LIB_SOURCE_DIRS += hal/tls/mbedtls
LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.28/include
LIB_INCLUDE_DIRS += hal/tls/mbedtls
LIB_SOURCE_DIRS += third_party/mbedtls/mbedtls-2.6.0/library
LIB_SOURCE_DIRS += src/tls/mbedtls
LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.6.0/include
LIB_INCLUDE_DIRS += src/tls/mbedtls
CFLAGS += -D'MBEDTLS_CONFIG_FILE="mbedtls_config.h"'
CFLAGS += -D'CONFIG_MMS_SUPPORT_TLS=1'
endif
@ -92,14 +80,13 @@ ifndef INSTALL_PREFIX
INSTALL_PREFIX = ./.install
endif
LIB_API_HEADER_FILES = hal/inc/hal_time.h
LIB_API_HEADER_FILES += hal/inc/hal_thread.h
LIB_API_HEADER_FILES += hal/inc/hal_filesystem.h
LIB_API_HEADER_FILES += hal/inc/tls_config.h
LIB_API_HEADER_FILES += hal/inc/lib_memory.h
LIB_API_HEADER_FILES += hal/inc/hal_base.h
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
@ -110,16 +97,22 @@ 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/mms_server.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
LIB_API_HEADER_FILES += src/goose/goose_publisher.h
LIB_API_HEADER_FILES += src/sampled_values/sv_subscriber.h
LIB_API_HEADER_FILES += src/sampled_values/sv_publisher.h
LIB_API_HEADER_FILES += src/logging/logging_api.h
LIB_API_HEADER_FILES += src/tls/tls_api.h
get_sources_from_directory = $(wildcard $1/*.c)
get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir)))
@ -130,7 +123,7 @@ LIB_SOURCES = $(call get_sources,$(LIB_SOURCE_DIRS))
LIB_OBJS = $(call src_to,.o,$(LIB_SOURCES))
CFLAGS += -std=gnu99
CFLAGS += -Wno-error=format
#CFLAGS += -Wno-error=format
CFLAGS += -Wstrict-prototypes
ifneq ($(HAL_IMPL), WIN32)
@ -143,9 +136,6 @@ CFLAGS += -Wnested-externs
CFLAGS += -Wmissing-declarations
CFLAGS += -Wshadow
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-format
#CFLAGS += -Wconditional-uninitialized
#CFLAGS += -Werror
all: lib

@ -2,19 +2,12 @@
[![Build Status](https://travis-ci.org/mz-automation/libiec61850.svg?branch=master)](https://travis-ci.org/mz-automation/libiec61850)
This file is part of the documentation of **libIEC61850**. More documentation can be found online at http://libiec61850.com.
The API documentation can be found here:
* C API: https://support.mz-automation.de/doc/libiec61850/c/latest/
* .NET API: https://support.mz-automation.de/doc/libiec61850/net/latest/
Also consider to review the examples to understand how to use the library.
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. Also consider to review the examples to understand how to use the library
Content:
* [Overview](#overview)
* [Features](#features)
* [Examples](#examples)
* [Building and running the examples](#building-and-running-the-examples-with-the-provided-makefiles)
* [Building the library with TLS support](#building-the-library-with-tls-support)
* [Installing the library and the API headers](#installing-the-library-and-the-api-headers)
@ -25,9 +18,12 @@ Content:
* [Experimental Python bindings](#experimental-python-bindings)
* [Licensing](#commercial-licenses-and-support)
* [Contributing](#contributing)
* [Third-party contributions](#third-party-contributions)
## Overview
libiec61850 is an open-source (GPLv3) implementation of an IEC 61850 client and server library implementing the protocols MMS, GOOSE and SV. 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, Windows, and MacOS. 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. The library has been successfully used in many commercial software products and devices.
For commercial projects licenses and support is provided by MZ Automation GmbH. Please contact info@mz-automation.de for more details on licensing options.
@ -51,18 +47,11 @@ The library support the following IEC 61850 protocol features:
* MMS file services (browse, get file, set file, delete/rename file)
** required to download COMTRADE files
* Setting group handling
* Support for service tracking
* GOOSE and SV control block handling
* TLS support
* C and C#/.NET API
## Examples
The examples are built automatically when CMake is used to build the library.
NOTE: Most examples are intended to show a specific function of the library. They are designed to show this function as simple as possible and may miss error handling that has to be present in real applications!
## Building and running the examples with the provided makefiles
In the project root directory type
@ -86,9 +75,7 @@ You can test the server examples by using a generic client or the provided clien
## Building the library with TLS support
Download, unpack, and copy mbedtls-2.28 into the third_party/mbedtls folder.
NOTE: The current version support mbedtls version 2.28. When you download the source archive from https://tls.mbed.org/ you have to rename the extracted folder to "mbedtls-2.28".
Download, unpack, and copy mbedtls-2.6.0 into the third_party/mbedtls folder.
In the main libiec61850 folder run
@ -96,8 +83,6 @@ In the main libiec61850 folder run
make WITH_MBEDTLS=1
```
When using CMake the library is built automatically with TLS support when the folder third_party/mbedtls/mbedtls-2.28 is present.
## 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.
@ -144,16 +129,6 @@ Depending on the system you don't have to provide a generator to the cmake comma
To select some configuration options you can use ccmake or cmake-gui.
For newer version of Visual Studio you can use one of the following commands (for 64 bit builds):
For Visual Studio 2017:
cmake -G "Visual Studio 15 2017 Win64" ..
For Visual Studio 2019 (new way to specify the x64 platform):
cmake -G "Visual Studio 16 2019" .. -A x64
## Using the log service with sqlite
@ -176,8 +151,6 @@ The experimental Python binding can be created using SWIG with cmake.
To enable the bindings you have to select the phyton configuration option with ccmake of cmake-gui.
We don't provide any support for the Python bindings!
## Commercial licenses and support
Support and commercial license options are provided by MZ Automation GmbH. Please contact info@mz-automation.de for more details.
@ -186,4 +159,10 @@ Support and commercial license options are provided by MZ Automation GmbH. Pleas
If you want to contribute to the improvement and development of the library please send me comments, feature requests, bug reports, or patches. For more than trivial contributions I require you to sign a Contributor License Agreement. Please contact info@libiec61850.com.
Please don't send pull requests before signing the Contributor License Agreement! Such pull requests may be silently ignored.
## 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

@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report security issues to `info@libiec61850.com`

@ -51,7 +51,7 @@
#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 100
#define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5
/* activate TCP keep alive mechanism. 1 -> activate */
#define CONFIG_ACTIVATE_TCP_KEEPALIVE 1
@ -68,10 +68,13 @@
/* 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. */
//#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 */
#define CONFIG_INCLUDE_GOOSE_SUPPORT 1
@ -144,10 +147,7 @@
#define CONFIG_IEC61850_REPORT_SERVICE 1
/* support buffered report control blocks with ResvTms field */
#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 1
/* allow only configured clients (when pre-configured by ClientLN) - note behavior in PIXIT Rp13 */
#define CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT 0
#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 0
/* The default buffer size of buffered RCBs in bytes */
#define CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE 65536
@ -161,22 +161,13 @@
/* include support for IEC 61850 log services */
#define CONFIG_IEC61850_LOG_SERVICE 1
/* include support for IEC 61850 service tracking */
#define CONFIG_IEC61850_SERVICE_TRACKING 1
/* allow user to control read access by callback */
#define CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL 1
/* allow application to set server identity (for MMS identity service) at runtime */
#define CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY 1
/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1
/* overwrite 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 "1.0.0" */
//#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
//#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
//#define CONFIG_DEFAULT_MMS_REVISION "1.0.0"
/* MMS virtual file store base path - where MMS file services are looking for files */
#define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/"
@ -215,14 +206,15 @@
#define MMS_IDENTIFY_SERVICE 1
#define MMS_FILE_SERVICE 1
#define MMS_OBTAIN_FILE_SERVICE 1 /* requires MMS_FILE_SERVICE */
#define MMS_DELETE_FILE_SERVICE 1 /* requires MMS_FILE_SERVICE */
#define MMS_RENAME_FILE_SERVICE 0 /* requires MMS_FILE_SERVICE */
#endif /* MMS_DEFAULT_PROFILE */
/* 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
@ -240,27 +232,10 @@
*/
#define CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME 1
/* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1
/* Define the default number of the maximum outstanding calls allowed by the caller (client) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
/************************************************************************************
* Check configuration for consistency - DO NOT MODIFY THIS PART!
************************************************************************************/
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!"
#endif
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!"
#endif
#if (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -63,10 +63,13 @@
/* 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. */
//#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
@ -134,10 +137,7 @@
#cmakedefine01 CONFIG_IEC61850_REPORT_SERVICE
/* support buffered report control blocks with ResvTms field */
#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 1
/* allow only configured clients (when pre-configured by ClientLN) - note behavior in PIXIT Rp13 */
#cmakedefine01 CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT
#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 0
/* The default buffer size of buffered RCBs in bytes */
#cmakedefine CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE @CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE@
@ -146,20 +146,11 @@
#cmakedefine01 CONFIG_IEC61850_SETTING_GROUPS
/* default reservation time of a setting group control block in s */
#cmakedefine CONFIG_IEC61850_SG_RESVTMS @CONFIG_IEC61850_SG_RESVTMS@
#define CONFIG_IEC61850_SG_RESVTMS 100
/* include support for IEC 61850 log services */
#cmakedefine01 CONFIG_IEC61850_LOG_SERVICE
/* include support for IEC 61850 service tracking */
#cmakedefine01 CONFIG_IEC61850_SERVICE_TRACKING
/* allow user to control read access by callback */
#cmakedefine01 CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL
/* allow application to set server identity (for MMS identity service) at runtime */
#define CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY 1
/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1
@ -187,10 +178,7 @@
#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10
/* Maximum number of the members in a data set (named variable list) */
#cmakedefine CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS @CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS@
/* Maximum number of get file tasks */
#cmakedefine CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS @CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS@
#define CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 50
/* Definition of supported services */
#define MMS_DEFAULT_PROFILE 1
@ -208,8 +196,6 @@
#define MMS_IDENTIFY_SERVICE 1
#define MMS_FILE_SERVICE 1
#define MMS_OBTAIN_FILE_SERVICE 1
#define MMS_DELETE_FILE_SERVICE 1
#define MMS_RENAME_FILE_SERVICE 0
#endif /* MMS_DEFAULT_PROFILE */
/* Sort getNameList response according to the MMS specified collation order - this is required by the standard
@ -229,27 +215,10 @@
*/
#define CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME 1
/* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1
/* Define the default number of the maximum outstanding calls allowed by the caller (client) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
/************************************************************************************
* Check configuration for consistency - DO NOT MODIFY THIS PART!
************************************************************************************/
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!"
#endif
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!"
#endif
#if (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -54,7 +54,7 @@ connectionIndicationHandler(IedServer server, ClientConnection connection, bool
}
static CheckHandlerResult
performCheckHandler(ControlAction action, void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, ClientConnection connection)
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");
@ -101,7 +101,7 @@ updateLED3stVal(bool newLedState, uint64_t timeStamp) {
}
static ControlHandlerResult
controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* value, bool test)
controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test)
{
if (test)
return CONTROL_RESULT_OK;
@ -151,7 +151,7 @@ static int ledOffTimeMs = 1000;
static int32_t opCnt = 0;
static ControlHandlerResult
controlHandlerForInt32Controls(ControlAction action, void* parameter, MmsValue* value, bool test)
controlHandlerForInt32Controls(void* parameter, MmsValue* value, bool test)
{
if (test)
return CONTROL_RESULT_OK;

@ -270,7 +270,7 @@
</DOType>
<DOType cdc="SPG" id="SPG_0">
<DA name="setVal" bType="BOOLEAN" fc="SP" dchg="true" />
<DA name="setVal" bType="BOOLEAN" fc="SG" dchg="true" />
</DOType>
<DOType cdc="TSG" id="TSG_0">

@ -7570,11 +7570,11 @@ 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, 88, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report1};
ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCB02", "Events1", false, "Events", 1, 88, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2};
ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsRCB03", "Events1", false, "Events", 1, 88, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3};
ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsRCB04", "Events1", false, "Events", 1, 88, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report4};
ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "EventsRCB05", "Events1", false, "Events", 1, 88, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
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};

@ -28,7 +28,10 @@ using IEC61850.Common;
namespace IEC61850
{
// IEC 61850 common API parts (used by client and server API)
/// <summary>
/// IEC 61850 common API parts (used by client and server API)
/// </summary>
namespace Common {
/// <summary>
@ -73,8 +76,8 @@ namespace IEC61850
}
}
namespace Client
{
namespace Client {
[StructLayout(LayoutKind.Sequential)]
internal struct LastApplErrorInternal
{
@ -98,13 +101,6 @@ namespace IEC61850
}
}
public enum ControlActionType
{
SELECT = 0,
OPERATE = 1,
CANCEL = 2
}
/// <summary>
/// Control object.
/// </summary>
@ -122,40 +118,10 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern int ControlObjectClient_getControlModel(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern int ControlObjectClient_getCtlValType(IntPtr self);
[DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern int ControlObjectClient_getLastError (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime);
/// <summary>
/// Handler for asynchronous control actions (select, operate, cancel)
/// </summary>
public delegate void ControlActionHandler (UInt32 invokeId, Object parameter, IedClientError error, ControlActionType type, bool success);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ControlObjectClient_ControlActionHandler (UInt32 invokeId, IntPtr parameter, int err, int type, [MarshalAs(UnmanagedType.I1)] bool success);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern UInt32 ControlObjectClient_operateAsync(IntPtr self, out int err, IntPtr ctlVal, UInt64 operTime,
ControlObjectClient_ControlActionHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern UInt32 ControlObjectClient_selectAsync(IntPtr self, out int err,
ControlObjectClient_ControlActionHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern UInt32 ControlObjectClient_selectWithValueAsync(IntPtr self, out int err, IntPtr ctlVal,
ControlObjectClient_ControlActionHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern UInt32 ControlObjectClient_cancelAsync(IntPtr self, out int err,
ControlObjectClient_ControlActionHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool ControlObjectClient_select(IntPtr self);
@ -190,7 +156,7 @@ namespace IEC61850
public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject);
private IedConnection iedConnection;
private IntPtr self;
private IntPtr controlObject;
private CommandTerminationHandler commandTerminationHandler = null;
private Object commandTerminationHandlerParameter = null;
@ -207,14 +173,14 @@ namespace IEC61850
{
this.iedConnection = iedConnection;
this.self = ControlObjectClient_create(objectReference, connection);
this.controlObject = ControlObjectClient_create(objectReference, connection);
if (this.self == System.IntPtr.Zero)
if (this.controlObject == System.IntPtr.Zero)
throw new IedConnectionException("Control object not found", 0);
intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler);
ControlObjectClient_setCommandTerminationHandler(self, intCommandTerminationHandler, self);
ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject);
}
/// <summary>
@ -225,22 +191,11 @@ namespace IEC61850
/// </returns>
public ControlModel GetControlModel ()
{
ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(self);
ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(controlObject);
return controlModel;
}
/// <summary>
/// Get the type of ctlVal.
/// </summary>
/// <returns>MmsType required for the ctlVal value.</returns>
public MmsType GetCtlValType ()
{
MmsType ctlValType = (MmsType) ControlObjectClient_getCtlValType (self);
return ctlValType;
}
/// <summary>
/// Sets the origin parameter used by control commands.
/// </summary>
@ -252,17 +207,7 @@ namespace IEC61850
/// </param>
public void SetOrigin (string originator, OrCat originatorCategory)
{
ControlObjectClient_setOrigin(self, originator, (int) originatorCategory);
}
/// <summary>
/// Gets the error code of the last synchronous control action (operate, select, select-with-value, cancel)
/// </summary>
/// <value>error code.</value>
public IedClientError LastError {
get {
return (IedClientError)ControlObjectClient_getLastError (self);
}
ControlObjectClient_setOrigin(controlObject, originator, (int) originatorCategory);
}
/// <summary>
@ -352,155 +297,7 @@ namespace IEC61850
/// <returns>true when the operation has been successful, false otherwise</returns>
public bool Operate (MmsValue ctlVal, UInt64 operTime)
{
return ControlObjectClient_operate(self, ctlVal.valueReference, operTime);
}
private ControlObjectClient_ControlActionHandler internalOperateHandler = null;
private void nativeOperateHandler (UInt32 invokeId, IntPtr parameter, int err, int type, bool success)
{
GCHandle handle = GCHandle.FromIntPtr(parameter);
Tuple<ControlActionHandler, object> callbackInfo = handle.Target as Tuple<ControlActionHandler, object>;
ControlActionHandler handler = callbackInfo.Item1;
object handlerParameter = callbackInfo.Item2;
handle.Free();
IedClientError clientError = (IedClientError)err;
handler(invokeId, handlerParameter, clientError, (ControlActionType) type, success);
}
/// <summary>
/// Operate the control with the specified control value.
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (bool ctlVal, ControlActionHandler handler, object parameter)
{
return OperateAsync (ctlVal, 0, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value (time activated control).
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name='operTime'>the time when the operation will be executed</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (bool ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter)
{
MmsValue value = new MmsValue(ctlVal);
return OperateAsync (value, operTime, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value.
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (float ctlVal, ControlActionHandler handler, object parameter)
{
return OperateAsync (ctlVal, 0, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value (time activated control).
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name='operTime'>the time when the operation will be executed</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (float ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter)
{
MmsValue value = new MmsValue(ctlVal);
return OperateAsync (value, operTime, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value.
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (int ctlVal, ControlActionHandler handler, object parameter)
{
return OperateAsync (ctlVal, 0, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value (time activated control).
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name='operTime'>the time when the operation will be executed</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (int ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter)
{
return OperateAsync (ctlVal, operTime, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value.
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (MmsValue ctlVal, ControlActionHandler handler, object parameter)
{
return OperateAsync (ctlVal, 0, handler, parameter);
}
/// <summary>
/// Operate the control with the specified control value (time activated control).
/// </summary>
/// <param name='ctlVal'>the new value of the control</param>
/// <param name='operTime'>the time when the operation will be executed</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 OperateAsync (MmsValue ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter)
{
int error;
Tuple<ControlActionHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
if (internalOperateHandler == null)
internalOperateHandler = new ControlObjectClient_ControlActionHandler(nativeOperateHandler);
UInt32 invokeId = ControlObjectClient_operateAsync(self, out error, ctlVal.valueReference, operTime, internalOperateHandler, GCHandle.ToIntPtr(handle));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Operate failed", error);
}
return invokeId;
return ControlObjectClient_operate(controlObject, ctlVal.valueReference, operTime);
}
/// <summary>
@ -509,46 +306,20 @@ namespace IEC61850
/// <returns>true when the selection has been successful, false otherwise</returns>
public bool Select ()
{
return ControlObjectClient_select(self);
}
/// <summary>
/// Select the control object.
/// </summary>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 SelectAsync(ControlActionHandler handler, object parameter)
{
int error;
Tuple<ControlActionHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
if (internalOperateHandler == null)
internalOperateHandler = new ControlObjectClient_ControlActionHandler(nativeOperateHandler);
UInt32 invokeId = ControlObjectClient_selectAsync(self, out error, internalOperateHandler, GCHandle.ToIntPtr(handle));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Select failed", error);
return ControlObjectClient_select(controlObject);
}
return invokeId;
}
/// <summary>
/// Send a select with value command for generic MmsValue instances
/// </summary>
/// <param name='ctlVal'>the value to be checked.</param>
/// <param name='ctlVal'>
/// the value to be checked.
/// </param>
/// <returns>true when the selection has been successful, false otherwise</returns>
public bool SelectWithValue (MmsValue ctlVal)
{
return ControlObjectClient_selectWithValue(self, ctlVal.valueReference);
return ControlObjectClient_selectWithValue(controlObject, ctlVal.valueReference);
}
/// <summary>
@ -587,111 +358,13 @@ namespace IEC61850
return SelectWithValue(new MmsValue(ctlVal));
}
/// <summary>
/// Send a select with value command for boolean controls - asynchronous version
/// </summary>
/// <param name='ctlVal'>the value to be checked.</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 SelectWithValueAsync (bool ctlVal, ControlActionHandler handler, object parameter)
{
return SelectWithValueAsync(new MmsValue(ctlVal), handler, parameter);
}
/// <summary>
/// Send a select with value command for integer controls - asynchronous version
/// </summary>
/// <param name='ctlVal'>the value to be checked.</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 SelectWithValueAsync (int ctlVal, ControlActionHandler handler, object parameter)
{
return SelectWithValueAsync(new MmsValue(ctlVal), handler, parameter);
}
/// <summary>
/// Send a select with value command for float controls - asynchronous version
/// </summary>
/// <param name='ctlVal'>the value to be checked.</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 SelectWithValueAsync (float ctlVal, ControlActionHandler handler, object parameter)
{
return SelectWithValueAsync(new MmsValue(ctlVal), handler, parameter);
}
/// <summary>
/// Send a select with value command for generic MmsValue instances - asynchronous version
/// </summary>
/// <param name='ctlVal'>the value to be checked.</param>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 SelectWithValueAsync (MmsValue ctlVal, ControlActionHandler handler, object parameter)
{
int error;
Tuple<ControlActionHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
if (internalOperateHandler == null)
internalOperateHandler = new ControlObjectClient_ControlActionHandler(nativeOperateHandler);
UInt32 invokeId = ControlObjectClient_selectWithValueAsync(self, out error, ctlVal.valueReference, internalOperateHandler, GCHandle.ToIntPtr(handle));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Select with value failed", error);
}
return invokeId;
}
/// <summary>
/// Cancel a selection or time activated operation
/// </summary>
/// <returns>true when the cancelation has been successful, false otherwise</returns>
/// <param name="handler">Callback function to handle the received response or service timeout</param>
/// <param name="parameter">User provided callback parameter. Will be passed to the callback function</param>
/// <returns>the invoke ID of the sent request</returns>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public bool Cancel ()
{
return ControlObjectClient_cancel(self);
}
/// <summary>
/// Cancel a selection or time activated operation
/// </summary>
public UInt32 CancelAsync(ControlActionHandler handler, object parameter)
{
int error;
Tuple<ControlActionHandler, object> callbackInfo = Tuple.Create(handler, parameter);
GCHandle handle = GCHandle.Alloc(callbackInfo);
if (internalOperateHandler == null)
internalOperateHandler = new ControlObjectClient_ControlActionHandler(nativeOperateHandler);
UInt32 invokeId = ControlObjectClient_cancelAsync(self, out error, internalOperateHandler, GCHandle.ToIntPtr(handle));
if (error != 0)
{
handle.Free();
throw new IedConnectionException("Cancel failed", error);
}
return invokeId;
return ControlObjectClient_cancel(controlObject);
}
/// <summary>
@ -700,7 +373,7 @@ namespace IEC61850
[Obsolete("use SetSynchroCheck instead")]
public void EnableSynchroCheck ()
{
ControlObjectClient_setSynchroCheck (self, true);
ControlObjectClient_setSynchroCheck (controlObject, true);
}
/// <summary>
@ -709,7 +382,7 @@ namespace IEC61850
[Obsolete("use SetInterlockCheck instead")]
public void EnableInterlockCheck ()
{
ControlObjectClient_setInterlockCheck (self, true);
ControlObjectClient_setInterlockCheck (controlObject, true);
}
/// <summary>
@ -717,7 +390,7 @@ namespace IEC61850
/// </summary>
public void SetInterlockCheck (bool value)
{
ControlObjectClient_setInterlockCheck (self, value);
ControlObjectClient_setInterlockCheck (controlObject, value);
}
/// <summary>
@ -725,7 +398,7 @@ namespace IEC61850
/// </summary>
public void SetSynchroCheck (bool value)
{
ControlObjectClient_setSynchroCheck (self, value);
ControlObjectClient_setSynchroCheck (controlObject, value);
}
/// <summary>
@ -733,7 +406,7 @@ namespace IEC61850
/// </summary>
public void SetTestMode (bool value)
{
ControlObjectClient_setTestMode (self, value);
ControlObjectClient_setTestMode (controlObject, value);
}
/// <summary>
@ -744,7 +417,7 @@ namespace IEC61850
/// </returns>
public LastApplError GetLastApplError ()
{
LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(self);
LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(controlObject);
return new LastApplError(lastApplError);
}
@ -765,9 +438,9 @@ namespace IEC61850
}
protected virtual void Dispose(bool disposing) {
if (this.self != System.IntPtr.Zero) {
ControlObjectClient_destroy (self);
this.self = System.IntPtr.Zero;
if (this.controlObject != System.IntPtr.Zero) {
ControlObjectClient_destroy (controlObject);
this.controlObject = System.IntPtr.Zero;
}
}
@ -775,10 +448,7 @@ namespace IEC61850
Dispose (true);
}
~ControlObject()
{
Dispose (false);
}
}
}

@ -1,7 +1,7 @@
/*
* DataSet.cs
*
* Copyright 2014-2018 Michael Zillgith
* Copyright 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -34,30 +34,25 @@ namespace IEC61850
/// This class is used to represent a data set. It is used to store the values
/// of a data set.
/// </summary>
/// <remarks>
/// This class manages native resource. Take care that the finalizer/Dispose is not
/// called while running a method or the object is still in use by another object.
/// If in doubt please use the "using" statement.
/// </remarks>
public class DataSet : IDisposable
public class DataSet
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void ClientDataSet_destroy(IntPtr self);
static extern void ClientDataSet_destroy (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientDataSet_getValues(IntPtr self);
static extern IntPtr ClientDataSet_getValues (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientDataSet_getReference(IntPtr self);
static extern IntPtr ClientDataSet_getReference (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int ClientDataSet_getDataSetSize(IntPtr self);
static extern int ClientDataSet_getDataSetSize (IntPtr self);
private IntPtr nativeObject;
private MmsValue values = null;
private string reference = null;
internal DataSet(IntPtr nativeObject)
internal DataSet (IntPtr nativeObject)
{
this.nativeObject = nativeObject;
}
@ -68,13 +63,12 @@ namespace IEC61850
/// <returns>
/// object reference.
/// </returns>
public string GetReference()
public string GetReference ()
{
if (reference == null)
{
IntPtr nativeString = ClientDataSet_getReference(nativeObject);
if (reference == null) {
IntPtr nativeString = ClientDataSet_getReference (nativeObject);
reference = Marshal.PtrToStringAnsi(nativeString);
reference = Marshal.PtrToStringAnsi (nativeString);
}
return reference;
@ -89,16 +83,15 @@ namespace IEC61850
/// <returns>
/// The locally stored values of the data set (as MmsValue instance of type MMS_ARRAY)
/// </returns>
public MmsValue GetValues()
{
if (values == null)
public MmsValue GetValues ()
{
IntPtr nativeValues = ClientDataSet_getValues(nativeObject);
if (values == null) {
IntPtr nativeValues = ClientDataSet_getValues (nativeObject);
values = new MmsValue(nativeValues, false);
values = new MmsValue (nativeValues, false);
}
return values.Clone();
return values;
}
@ -108,42 +101,17 @@ namespace IEC61850
/// <returns>
/// the number of elementes (data set members)
/// </returns>
public int GetSize()
{
return ClientDataSet_getDataSetSize(nativeObject);
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
lock (this)
{
if (!disposed)
{
if (nativeObject != IntPtr.Zero)
{
ClientDataSet_destroy(nativeObject);
nativeObject = IntPtr.Zero;
}
disposed = true;
}
}
}
public void Dispose()
public int GetSize ()
{
Dispose(true);
GC.SuppressFinalize(this);
return ClientDataSet_getDataSetSize (nativeObject);
}
~DataSet()
~DataSet ()
{
Dispose(false);
ClientDataSet_destroy (nativeObject);
}
internal IntPtr getNativeInstance()
internal IntPtr getNativeInstance ()
{
return nativeObject;
}

@ -31,7 +31,7 @@ namespace IEC61850
namespace Client
{
public class GooseControlBlock : IDisposable {
public class GooseControlBlock {
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientGooseControlBlock_create (string dataAttributeReference);
@ -84,18 +84,6 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern PhyComAddress ClientGooseControlBlock_getDstAddress (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientGooseControlBlock_getDstAddress_addr(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern byte ClientGooseControlBlock_getDstAddress_priority(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt16 ClientGooseControlBlock_getDstAddress_vid(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt16 ClientGooseControlBlock_getDstAddress_appid(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void ClientGooseControlBlock_setDstAddress (IntPtr self, PhyComAddress value);
@ -244,23 +232,7 @@ namespace IEC61850
public PhyComAddress GetDstAddress()
{
PhyComAddress addr = new PhyComAddress();
IntPtr value = ClientGooseControlBlock_getDstAddress_addr(self);
MmsValue mmsValue = new MmsValue(value);
byte[] dstMacAddr = mmsValue.getOctetString();
dstMacAddr.CopyTo(addr.dstAddress, 0);
addr.dstAddress = dstMacAddr;
addr.appId = ClientGooseControlBlock_getDstAddress_appid(self);
addr.vlanId = ClientGooseControlBlock_getDstAddress_vid(self);
addr.vlanPriority = ClientGooseControlBlock_getDstAddress_priority(self);
return addr;
return ClientGooseControlBlock_getDstAddress (self);
}
public void SetDstAddress(PhyComAddress value)

@ -22,7 +22,6 @@
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using IEC61850.Common;
@ -70,8 +69,6 @@ namespace IEC61850
private bool isDisposed = false;
private List<GooseSubscriber> subscribers = new List<GooseSubscriber>();
public GooseReceiver()
{
self = GooseReceiver_create ();
@ -82,29 +79,14 @@ namespace IEC61850
GooseReceiver_setInterfaceId (self, interfaceId);
}
/// <summary>
/// Add the subscriber to be handled by this receiver instance
/// </summary>
/// <remarks>A GooseSubscriber can only be added to one GooseReceiver!</remarks>
/// <param name="subscriber"></param>
public void AddSubscriber(GooseSubscriber subscriber)
{
if (subscriber.attachedToReceiver == false)
{
subscriber.attachedToReceiver = true;
GooseReceiver_addSubscriber(self, subscriber.self);
subscribers.Add(subscriber);
}
GooseReceiver_addSubscriber (self, subscriber.self);
}
public void RemoveSubscriber(GooseSubscriber subscriber)
{
if (subscriber.attachedToReceiver)
{
GooseReceiver_removeSubscriber(self, subscriber.self);
subscribers.Remove(subscriber);
subscriber.attachedToReceiver = false;
}
GooseReceiver_removeSubscriber (self, subscriber.self);
}
public void Start()
@ -193,22 +175,10 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void GooseSubscriber_setListener (IntPtr self, InternalGooseListener listener, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GooseSubscriber_getGoId(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GooseSubscriber_getGoCbRef(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GooseSubscriber_getDataSet(IntPtr self);
internal IntPtr self;
private bool isDisposed = false;
// don't call native destructor when attached to a receiver
internal bool attachedToReceiver = false;
private GooseListener listener = null;
private object listenerParameter = null;
@ -244,6 +214,7 @@ namespace IEC61850
return GooseSubscriber_isValid (self);
}
public void SetListener(GooseListener listener, object parameter)
{
this.listener = listener;
@ -256,21 +227,6 @@ namespace IEC61850
}
}
public string GetGoId()
{
return Marshal.PtrToStringAnsi(GooseSubscriber_getGoId(self));
}
public string GetGoCbRef()
{
return Marshal.PtrToStringAnsi(GooseSubscriber_getGoCbRef(self));
}
public string GetDataSet()
{
return Marshal.PtrToStringAnsi(GooseSubscriber_getDataSet(self));
}
public UInt32 GetStNum()
{
return GooseSubscriber_getStNum (self);
@ -344,19 +300,11 @@ namespace IEC61850
{
if (isDisposed == false) {
isDisposed = true;
if (attachedToReceiver == false)
GooseSubscriber_destroy (self);
self = IntPtr.Zero;
}
}
~GooseSubscriber()
{
Dispose();
}
}
}

@ -28,6 +28,10 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />

File diff suppressed because it is too large Load Diff

@ -29,13 +29,6 @@ namespace IEC61850
namespace Common
{
public enum Iec61850Edition : byte
{
EDITION_1 = 0,
EDITION_2 = 1,
EDITION_2_1 = 2
}
public class LibIEC61850
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
@ -123,9 +116,7 @@ namespace IEC61850
/** periodic transmission of all data set values */
INTEGRITY = 8,
/** general interrogation (on client request) */
GI = 16,
/** Report will be triggered only on rising edge (transient variable) */
TRG_OPT_TRANSIENT = 128
GI = 16
}
/// <summary>
@ -193,9 +184,6 @@ namespace IEC61850
private const UInt16 QUALITY_SOURCE_SUBSTITUTED = 1024;
private const UInt16 QUALITY_TEST = 2048;
private const UInt16 QUALITY_OPERATOR_BLOCKED = 4096;
private const UInt16 QUALITY_DERIVED = 8192;
public ushort Value => value;
public override string ToString ()
{
@ -353,17 +341,6 @@ namespace IEC61850
this.value = (ushort) ((int) this.value & (~QUALITY_OPERATOR_BLOCKED));
}
}
public bool Derived
{
get { return ((this.value & QUALITY_DERIVED) != 0); }
set {
if (value)
this.value |= QUALITY_DERIVED;
else
this.value = (ushort) ((int) this.value & (~QUALITY_DERIVED));
}
}
}
/// <summary>
@ -651,21 +628,6 @@ namespace IEC61850
NONE = -1
}
/// <summary>
/// Definition for LastAppError error type for control models
/// Used in LastApplError and CommandTermination messages.
/// </summary>
public enum ControlLastApplError {
NO_ERROR = 0,
UNKNOWN = 1,
TIMEOUT_TEST = 2,
OPERATOR_TEST = 3
}
/// <summary>
/// AddCause - additional cause information for control model errors
/// Used in LastApplError and CommandTermination messages.
/// </summary>
public enum ControlAddCause {
ADD_CAUSE_UNKNOWN = 0,
ADD_CAUSE_NOT_SUPPORTED = 1,

File diff suppressed because it is too large Load Diff

@ -23,7 +23,6 @@
using System;
using System.Runtime.InteropServices;
using IEC61850.Common;
namespace IEC61850.Server
{
@ -44,98 +43,17 @@ namespace IEC61850.Server
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int IedServerConfig_getReportBufferSize(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setReportBufferSizeForURCBs(IntPtr self, int reportBufferSize);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int IedServerConfig_getReportBufferSizeForURCBs(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setFileServiceBasePath(IntPtr self, string basepath);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedServerConfig_getFileServiceBasePath(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_enableFileService(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[return: MarshalAs(UnmanagedType.I1)]
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern bool IedServerConfig_isFileServiceEnabled(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setEdition(IntPtr self, byte edition);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern byte IedServerConfig_getEdition(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setMaxMmsConnections(IntPtr self, int maxConnections);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int IedServerConfig_getMaxMmsConnections(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool IedServerConfig_isDynamicDataSetServiceEnabled(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_enableDynamicDataSetService(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setMaxAssociationSpecificDataSets(IntPtr self, int maxDataSets);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int IedServerConfig_getMaxAssociationSpecificDataSets(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setMaxDomainSpecificDataSets(IntPtr self, int maxDataSets);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int IedServerConfig_getMaxDomainSpecificDataSets(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setMaxDataSetEntries(IntPtr self, int maxDataSetEntries);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int IedServerConfig_getMaxDatasSetEntries(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_enableLogService(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool IedServerConfig_isLogServiceEnabled(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_enableResvTmsForBRCB(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool IedServerConfig_isResvTmsForBRCBEnabled(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_enableOwnerForRCB(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool IedServerConfig_isOwnerForRCBEnabled(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_useIntegratedGoosePublisher(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool IedServerConfig_getSyncIntegrityReportTimes(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setSyncIntegrityReportTimes(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
internal IntPtr self;
public IedServerConfig()
public IedServerConfig ()
{
self = IedServerConfig_create();
self = IedServerConfig_create ();
}
/// <summary>
@ -144,29 +62,11 @@ namespace IEC61850.Server
/// <value>The size of the report buffer.</value>
public int ReportBufferSize
{
get
{
return IedServerConfig_getReportBufferSize(self);
}
set
{
IedServerConfig_setReportBufferSize(self, value);
}
}
/// <summary>
/// Gets or sets the size of the report buffer for unbuffered report control blocks
/// </summary>
/// <value>The size of the report buffer.</value>
public int ReportBufferSizeForURCBs
{
get
{
return IedServerConfig_getReportBufferSizeForURCBs(self);
get {
return IedServerConfig_getReportBufferSize (self);
}
set
{
IedServerConfig_setReportBufferSizeForURCBs(self, value);
set {
IedServerConfig_setReportBufferSize (self, value);
}
}
@ -176,206 +76,11 @@ namespace IEC61850.Server
/// <value>The file service base path.</value>
public string FileServiceBasePath
{
get
{
return Marshal.PtrToStringAnsi(IedServerConfig_getFileServiceBasePath(self));
}
set
{
IedServerConfig_setFileServiceBasePath(self, value);
}
}
/// <summary>
/// Enable/Disable file service for MMS
/// </summary>
/// <value><c>true</c> if file service is enabled; otherwise, <c>false</c>.</value>
public bool FileServiceEnabled
{
get
{
return IedServerConfig_isFileServiceEnabled(self);
}
set
{
IedServerConfig_enableFileService(self, value);
}
}
/// <summary>
/// Gets or sets the edition of the IEC 61850 standard to use
/// </summary>
/// <value>The IEC 61850 edition to use.</value>
public Iec61850Edition Edition
{
get
{
return (Iec61850Edition)IedServerConfig_getEdition(self);
}
set
{
IedServerConfig_setEdition(self, (byte)value);
}
}
/// <summary>
/// Gets or sets maximum number of MMS clients
/// </summary>
/// <value>The max number of MMS client connections.</value>
public int MaxMmsConnections
{
get
{
return IedServerConfig_getMaxMmsConnections(self);
}
set
{
IedServerConfig_setMaxMmsConnections(self, value);
}
}
/// <summary>
/// Enable/Disable dynamic data set service for MMS
/// </summary>
/// <value><c>true</c> if dynamic data set service enabled; otherwise, <c>false</c>.</value>
public bool DynamicDataSetServiceEnabled
{
get
{
return IedServerConfig_isDynamicDataSetServiceEnabled(self);
}
set
{
IedServerConfig_enableDynamicDataSetService(self, value);
}
}
/// <summary>
/// Gets or sets the maximum number of data set entries for dynamic data sets
/// </summary>
/// <value>The max. number data set entries.</value>
public int MaxDataSetEntries
{
get
{
return IedServerConfig_getMaxDatasSetEntries(self);
}
set
{
IedServerConfig_setMaxDataSetEntries(self, value);
}
}
/// <summary>
/// Gets or sets the maximum number of association specific (non-permanent) data sets.
/// </summary>
/// <value>The max. number of association specific data sets.</value>
public int MaxAssociationSpecificDataSets
{
get
{
return IedServerConfig_getMaxAssociationSpecificDataSets(self);
}
set
{
IedServerConfig_setMaxAssociationSpecificDataSets(self, value);
}
}
/// <summary>
/// Gets or sets the maximum number of domain specific (permanent) data sets.
/// </summary>
/// <value>The max. numebr of domain specific data sets.</value>
public int MaxDomainSpecificDataSets
{
get
{
return IedServerConfig_getMaxDomainSpecificDataSets(self);
}
set
{
IedServerConfig_setMaxDomainSpecificDataSets(self, value);
}
}
/// <summary>
/// Enable/Disable log service for MMS
/// </summary>
/// <value><c>true</c> if log service is enabled; otherwise, <c>false</c>.</value>
public bool LogServiceEnabled
{
get
{
return IedServerConfig_isLogServiceEnabled(self);
}
set
{
IedServerConfig_enableLogService(self, value);
}
}
/// <summary>
/// Enable/Disable the presence of ResvTms attribute in BRCBs (buffered report control blocks)
/// </summary>
/// <value><c>true</c> if BRCB has ResvTms; otherwise, <c>false</c>. Defaults to true</value>
public bool BRCBHasResvTms
{
get
{
return IedServerConfig_isResvTmsForBRCBEnabled(self);
get {
return Marshal.PtrToStringAnsi (IedServerConfig_getFileServiceBasePath (self));
}
set
{
IedServerConfig_enableResvTmsForBRCB(self, value);
}
}
/// <summary>
/// Enable/Disable the presence of Owner attribute in RCBs (report control blocks)
/// </summary>
/// <value><c>true</c> if RCB has Owner; otherwise, <c>false</c>. Defaults to false</value>
public bool RCBHasOwner
{
get
{
return IedServerConfig_isOwnerForRCBEnabled(self);
}
set
{
IedServerConfig_enableOwnerForRCB(self, value);
}
}
/// <summary>
/// Enable/disable using the integrated GOOSE publisher for configured GoCBs
/// </summary>
/// <value><c>true</c> when integrated GOOSE publisher is used; otherwise, <c>false</c>. Defaults to true</value>
public bool UseIntegratedGoosePublisher
{
set
{
IedServerConfig_useIntegratedGoosePublisher(self, value);
}
}
/// <summary>
/// Enable/Disable synchoronized integrity report times (disabled by default)
/// </summary>
/// <remarks>
/// When this flag is enabled the integrity report generation times are
/// aligned with the UTC epoch. Then the unix time stamps are straight multiples of the
/// integrity interval.
/// </remarks>
/// <value><c>true</c> if sync integrity report times; otherwise, <c>false</c>.</value>
public bool SyncIntegrityReportTimes
{
get
{
return IedServerConfig_getSyncIntegrityReportTimes(self);
}
set
{
IedServerConfig_setSyncIntegrityReportTimes(self, value);
set {
IedServerConfig_setFileServiceBasePath (self, value);
}
}
@ -389,11 +94,9 @@ namespace IEC61850.Server
/// <see cref="IEC61850.Server.IedServerConfig"/> was occupying.</remarks>
public void Dispose()
{
lock (this)
{
if (self != IntPtr.Zero)
{
IedServerConfig_destroy(self);
lock (this) {
if (self != IntPtr.Zero) {
IedServerConfig_destroy (self);
self = IntPtr.Zero;
}
}
@ -401,7 +104,7 @@ namespace IEC61850.Server
~IedServerConfig()
{
Dispose();
Dispose ();
}
}
}

@ -59,14 +59,6 @@ namespace IEC61850
[MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] public byte[] value;
}
[StructLayout(LayoutKind.Sequential)]
private struct NativePSelector
{
public byte size;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] value;
}
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void IsoConnectionParameters_destroy(IntPtr self);
@ -74,13 +66,13 @@ namespace IEC61850
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, NativePSelector pSelector, NativeSSelector sSelector, NativeTSelector tSelector);
private static extern void IsoConnectionParameters_setRemoteAddresses(IntPtr self, UInt32 pSelector, NativeSSelector 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, NativePSelector pSelector, NativeSSelector sSelector, NativeTSelector tSelector);
private static extern void IsoConnectionParameters_setLocalAddresses(IntPtr self, UInt32 pSelector, NativeSSelector sSelector, NativeTSelector tSelector);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void IsoConnectionParameters_setAcseAuthenticationParameter(IntPtr self, IntPtr acseAuthParameter);
@ -138,7 +130,7 @@ namespace IEC61850
/// <param name='tSelector'>
/// ISO COTP transport layer address
/// </param>
public void SetRemoteAddresses (byte[] pSelector, byte[] sSelector, byte[] tSelector)
public void SetRemoteAddresses (UInt32 pSelector, byte[] sSelector, byte[] tSelector)
{
if (tSelector.Length > 4)
throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded");
@ -150,9 +142,6 @@ namespace IEC61850
for (int i = 0; i < tSelector.Length; i++)
nativeTSelector.value[i] = tSelector[i];
if (sSelector.Length > 16)
throw new ArgumentOutOfRangeException("sSelector", "maximum size (16) exceeded");
NativeSSelector nativeSSelector;
nativeSSelector.size = (byte) sSelector.Length;
nativeSSelector.value = new byte[16];
@ -160,17 +149,7 @@ namespace IEC61850
for (int i = 0; i < sSelector.Length; i++)
nativeSSelector.value [i] = sSelector [i];
if (pSelector.Length > 16)
throw new ArgumentOutOfRangeException("pSelector", "maximum size (16) exceeded");
NativePSelector nativePSelector;
nativePSelector.size = (byte)pSelector.Length;
nativePSelector.value = new byte[16];
for (int i = 0; i < pSelector.Length; i++)
nativePSelector.value[i] = pSelector[i];
IsoConnectionParameters_setRemoteAddresses(self, nativePSelector, nativeSSelector, nativeTSelector);
IsoConnectionParameters_setRemoteAddresses(self, pSelector, nativeSSelector, nativeTSelector);
}
/// <summary>
@ -199,7 +178,7 @@ namespace IEC61850
/// <param name='tSelector'>
/// ISO COTP transport layer address
/// </param>
public void SetLocalAddresses (byte[] pSelector, byte[] sSelector, byte[] tSelector)
public void SetLocalAddresses (UInt32 pSelector, byte[] sSelector, byte[] tSelector)
{
if (tSelector.Length > 4)
throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded");
@ -211,9 +190,6 @@ namespace IEC61850
for (int i = 0; i < tSelector.Length; i++)
nativeTSelector.value[i] = tSelector[i];
if (sSelector.Length > 16)
throw new ArgumentOutOfRangeException("sSelector", "maximum size (16) exceeded");
NativeSSelector nativeSSelector;
nativeSSelector.size = (byte) sSelector.Length;
nativeSSelector.value = new byte[16];
@ -221,17 +197,7 @@ namespace IEC61850
for (int i = 0; i < sSelector.Length; i++)
nativeSSelector.value [i] = sSelector [i];
if (pSelector.Length > 16)
throw new ArgumentOutOfRangeException("pSelector", "maximum size (16) exceeded");
NativePSelector nativePSelector;
nativePSelector.size = (byte)pSelector.Length;
nativePSelector.value = new byte[16];
for (int i = 0; i < pSelector.Length; i++)
nativePSelector.value[i] = pSelector[i];
IsoConnectionParameters_setLocalAddresses(self, nativePSelector, nativeSSelector, nativeTSelector);
IsoConnectionParameters_setLocalAddresses(self, pSelector, nativeSSelector, nativeTSelector);
}
/// <summary>

@ -32,10 +32,11 @@ namespace IEC61850
{
namespace Common
{
/// <summary>
/// This class is used to hold MMS data values of different types.
/// </summary>
public class MmsValue : IEnumerable, IDisposable
public class MmsValue : IEnumerable
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_toString (IntPtr self);
@ -56,21 +57,12 @@ namespace IEC61850
[return: MarshalAs(UnmanagedType.I1)]
static extern bool MmsValue_getBoolean (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsValue_setBoolean(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[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 UInt32 MmsValue_getBitStringAsIntegerBigEndian(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsValue_setBitStringFromIntegerBigEndian(IntPtr self, UInt32 intValue);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int MmsValue_getBitStringSize(IntPtr self);
@ -84,9 +76,6 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern Int32 MmsValue_toInt32 (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsValue_setInt32(IntPtr self, int value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern Int64 MmsValue_toInt64 (IntPtr self);
@ -147,21 +136,6 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_newVisibleString(string value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_newVisibleStringWithSize(int size);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsValue_setVisibleString(IntPtr self, string value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_createArray(IntPtr elementType, int size);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_createEmptyArray(int size);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_createEmptyStructure(int size);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_newOctetString(int size, int maxSize);
@ -174,12 +148,6 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt16 MmsValue_getOctetStringMaxSize(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern byte MmsValue_getOctetStringOctet(IntPtr self, int pos);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsValue_setOctetStringOctet(IntPtr self, int pos, byte value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_getOctetStringBuffer(IntPtr self);
@ -196,26 +164,15 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern ulong MmsValue_getBinaryTimeAsUtcMs (IntPtr self);
[DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_newUtcTimeByMsTime (UInt64 timestamp);
[DllImport("iec61850", CallingConvention=CallingConvention.Cdecl)]
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern int MmsValue_getDataAccessError(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsValue_setElement(IntPtr complexValue, int index, IntPtr elementValue);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsVariableSpecification_getChildValue(IntPtr self, IntPtr value, string childId);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_clone(IntPtr self);
internal IntPtr valueReference; /* reference to native MmsValue instance */
private bool responsableForDeletion = false; /* if .NET wrapper is responsable for the deletion of the native MmsValue instance */
private bool responsableForDeletion; /* if .NET wrapper is responsable for the deletion of the native MmsValue instance */
internal MmsValue (IntPtr value)
// TODO make internal
public MmsValue (IntPtr value)
{
valueReference = value;
this.responsableForDeletion = false;
@ -257,31 +214,15 @@ namespace IEC61850
valueReference = MmsValue_newIntegerFromInt64 (value);
}
/// <summary>
/// Create a new <see cref="IEC61850.Common.MmsValue"/> instance of type MMS_VISIBLE_STRING.
/// </summary>
/// <param name="value">Value.</param>
public MmsValue (string value)
{
valueReference = MmsValue_newVisibleString(value);
}
public void Dispose()
~MmsValue ()
{
lock (this) {
if (valueReference != IntPtr.Zero) {
if (responsableForDeletion)
MmsValue_delete (valueReference);
valueReference = IntPtr.Zero;
}
}
}
~MmsValue ()
{
Dispose();
}
/// <summary>
@ -329,53 +270,6 @@ namespace IEC61850
this.setOctetString (octetString);
}
/// <summary>
/// Create a new MmsValue instance of type MMS_ARRAY. Array elements have the fiven type
/// </summary>
/// <returns>the newly created array</returns>
/// <param name="elementType">array element type</param>
/// <param name="size">number of array elements</param>
public static MmsValue NewArray(MmsVariableSpecification elementType, int size)
{
if (size < 1)
throw new MmsValueException ("array requires at least one element");
IntPtr newValue = MmsValue_createArray (elementType.self, size);
return new MmsValue (newValue, true);
}
/// <summary>
/// Create a new MmsValue instance of type MMS_ARRAY. Array elements are not initialized!
/// </summary>
/// <returns>the newly created array</returns>
/// <param name="size">number of array elements</param>
public static MmsValue NewEmptyArray(int size)
{
if (size < 1)
throw new MmsValueException ("array requires at least one element");
IntPtr newValue = MmsValue_createEmptyArray (size);
return new MmsValue (newValue, true);
}
/// <summary>
/// Create a new MmsValue instance of type MMS_STRUCTURE. Structure elements are not initialized!
/// </summary>
/// <returns>the newly created array</returns>
/// <param name="size">number of structure elements</param>
public static MmsValue NewEmptyStructure(int size)
{
if (size < 1)
throw new MmsValueException ("structure requires at least one element");
IntPtr newValue = MmsValue_createEmptyStructure (size);
return new MmsValue (newValue, true);
}
/// <summary>
/// Create a new MmsValue instance of type MMS_BINARY_TIME
/// </summary>
@ -415,39 +309,6 @@ namespace IEC61850
throw new MmsValueException ("Value is not a time type");
}
/// <summary>
/// Create a new MmsValue instance of type MMS_UTC_TIME
/// </summary>
/// <returns>the new MmsValue instance.</returns>
/// <param name="timestamp">the time value as milliseconds since epoch (1.1.1970 UTC).</param>
public static MmsValue NewUtcTime (UInt64 timestamp)
{
IntPtr newValue = MmsValue_newUtcTimeByMsTime (timestamp);
return new MmsValue (newValue, true);
}
/// <summary>
/// Create a new MmsValue instance of type MMS_VISIBLE_STRING - empty string with given maximum size
/// </summary>
/// <param name="size">The maximum size </param>
/// <returns></returns>
public static MmsValue NewVisibleString(int size, bool responsibleForDeletion = false)
{
IntPtr newValue = MmsValue_newVisibleStringWithSize(size);
return new MmsValue(newValue, responsibleForDeletion);
}
/// <summary>
/// Set the value of an MmsValue instance of type MMS_VISIBLE_STRING
/// </summary>
/// <param name="value">the new string value</param>
public void SetVisibleString(string value)
{
MmsValue_setVisibleString(valueReference, value);
}
/// <summary>
/// Gets the type of the value
/// </summary>
@ -524,11 +385,6 @@ namespace IEC61850
throw new MmsValueException ("Operation not supported for this type");
}
/// <summary>
/// Sets the value of an octet string by a byte array
/// </summary>
/// <param name="octetString">Byte array containing the bytes of the octet string.</param>
/// <exception cref="MmsValueException">This exception is thrown if the value has the wrong type or the byte array is too large.</exception>
public void setOctetString (byte[] octetString)
{
if (GetType () == MmsType.MMS_OCTET_STRING) {
@ -542,26 +398,6 @@ namespace IEC61850
throw new MmsValueException ("Operation not supported for this type");
}
/// <summary>
/// Gets the octet string octet.
/// </summary>
/// <returns>The octet string octet.</returns>
/// <param name="pos">Position of the octet in the octet string.</param>
public byte GetOctetStringOctet(int pos)
{
return MmsValue_getOctetStringOctet(valueReference, pos);
}
/// <summary>
/// Sets the octet string octet.
/// </summary>
/// <param name="pos">Position of the octet in the octet string.</param>
/// <param name="value">The octet string octet.</param>
public void SetOctetStringOctet(int pos, byte value)
{
MmsValue_setOctetStringOctet(valueReference, pos, value);
}
/// <summary>
/// Get an element of an array or structure
/// </summary>
@ -591,59 +427,16 @@ namespace IEC61850
throw new MmsValueException ("Value is of wrong type");
}
/// <summary>
/// Sets the element of an array or structure
/// </summary>
/// <remarks>
/// After calling this function the native memory of the element will be managed by the array or structure.
/// Therefore an element can only be used in a single array or structure.
/// When the value is required in multiple arrays or structures
/// a clone has to be created before using this function!
/// To be save, always use a clone for setting the element.
/// </remarks>
/// <param name="index">index of the element starting with 0</param>
/// <param name="elementValue">MmsValue instance that will be used as element value</param>
/// <exception cref="MmsValueException">This exception is thrown if the value has the wrong type.</exception>
/// <exception cref="MmsValueException">This exception is thrown if the index is out of range.</exception>
public void SetElement(int index, MmsValue elementValue)
{
MmsType elementType = GetType();
if ((elementType == MmsType.MMS_ARRAY) || (elementType == MmsType.MMS_STRUCTURE))
{
if ((index >= 0) && (index < Size()))
{
if (elementValue != null)
{
MmsValue_setElement(valueReference, index, elementValue.valueReference);
/* will be deleted by structure */
elementValue.responsableForDeletion = false;
}
else
MmsValue_setElement(valueReference, index, IntPtr.Zero);
}
else
throw new MmsValueException("Index out of bounds");
}
else
throw new MmsValueException("Value is of wrong type");
}
public MmsDataAccessError GetDataAccessError()
{
if (GetType() == MmsType.MMS_DATA_ACCESS_ERROR)
public MmsDataAccessError GetDataAccessError ()
{
int errorCode = MmsValue_getDataAccessError(valueReference);
if (GetType () == MmsType.MMS_DATA_ACCESS_ERROR) {
int errorCode = MmsValue_getDataAccessError (valueReference);
return (MmsDataAccessError)errorCode;
}
else
throw new MmsValueException("Value is of wrong type");
throw new MmsValueException ("Value is of wrong type");
}
/// <summary>
@ -820,21 +613,6 @@ namespace IEC61850
return MmsValue_toInt32 (valueReference);
}
/// <summary>
/// Sets the 32 bit signed integer.
/// </summary>
/// <param name='value'>
/// the new value to set
/// </param>
/// <exception cref="MmsValueException">This exception is thrown if the value has the wrong type.</exception>
public void SetInt32(int value)
{
if (GetType() != MmsType.MMS_INTEGER)
throw new MmsValueException("Value type is not integer");
MmsValue_setInt32(valueReference, value);
}
/// <summary>
/// Return the value as 64 bit signed integer.
/// </summary>
@ -889,22 +667,6 @@ namespace IEC61850
MmsValue_setBitStringFromInteger(valueReference, intValue);
}
public UInt32 BitStringToUInt32BigEndian()
{
if (GetType() != MmsType.MMS_BIT_STRING)
throw new MmsValueException("Value type is not bit string");
return MmsValue_getBitStringAsIntegerBigEndian(valueReference);
}
public void BitStringFromUInt32BigEndian(UInt32 intValue)
{
if (GetType() != MmsType.MMS_BIT_STRING)
throw new MmsValueException("Value type is not bit string");
MmsValue_setBitStringFromIntegerBigEndian(valueReference, intValue);
}
public void SetBit (int bitPos, bool bitValue)
{
if (GetType () != MmsType.MMS_BIT_STRING)
@ -956,21 +718,6 @@ namespace IEC61850
throw new MmsValueException ("Value type is not boolean");
}
/// <summary>
/// Sets the boolean value of an MMS_BOOLEAN instance
/// </summary>
/// <param name='value'>
/// the new value to set
/// </param>
/// <exception cref="MmsValueException">This exception is thrown if the value has the wrong type.</exception>
public void SetBoolean(bool value)
{
if (GetType() != MmsType.MMS_BOOLEAN)
throw new MmsValueException("Value type is not boolean");
MmsValue_setBoolean(valueReference, value);
}
/// <summary>
/// Gets the float value of an MMS_FLOAT instance
/// </summary>
@ -1031,41 +778,6 @@ namespace IEC61850
throw new MmsValueException ("Value type is not float");
}
/// <summary>
/// Gets the child value with the given name
/// </summary>
/// <returns>the child value or null if no matching child has been found.</returns>
/// <param name="childPath">path specifying the child using '.' or '$' as path element separator.</param>
/// <param name="specification">the variable specification to use.</param>
public MmsValue GetChildValue(string childPath, MmsVariableSpecification specification)
{
StringBuilder childPathStr = new StringBuilder(childPath);
childPathStr.Replace('.', '$');
IntPtr childPtr = MmsVariableSpecification_getChildValue(specification.self, valueReference, childPathStr.ToString());
if (childPtr == IntPtr.Zero)
return null;
else
{
return new MmsValue(childPtr);
}
}
/// <summary>
/// Get an identical copy of this instance
/// </summary>
public MmsValue Clone()
{
IntPtr clonePtr = MmsValue_clone(valueReference);
if (clonePtr == IntPtr.Zero)
return null;
return new MmsValue(clonePtr, true);
}
public override bool Equals (object obj)
{
MmsValue otherValue = (MmsValue) obj;
@ -1116,31 +828,9 @@ namespace IEC61850
return retString;
}
case MmsType.MMS_ARRAY:
{
string retString = "[";
bool first = true;
foreach (MmsValue element in this) {
if (first) {
retString += element.ToString ();
first = false;
} else {
retString += ", " + element.ToString ();
}
}
retString += "]";
return retString;
}
case MmsType.MMS_DATA_ACCESS_ERROR:
return "error: " + GetDataAccessError().ToString();
default:
return "unknown (type:" + GetType().ToString() + ")";
return "unknown";
}
}

@ -26,7 +26,6 @@ using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace IEC61850
{
@ -40,6 +39,9 @@ namespace IEC61850
[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);
@ -61,20 +63,13 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int MmsVariableSpecification_getExponentWidth(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern bool MmsVariableSpecification_isValueOfType(IntPtr self, IntPtr value);
internal IntPtr self;
private IntPtr self;
private bool responsableForDeletion;
/* only to prevent garbage collector to destroy parent element */
internal MmsVariableSpecification parent = null;
internal MmsVariableSpecification (IntPtr self, MmsVariableSpecification parent)
internal MmsVariableSpecification (IntPtr self)
{
this.self = self;
this.responsableForDeletion = false;
this.parent = parent;
}
internal MmsVariableSpecification (IntPtr self, bool responsableForDeletion)
@ -83,27 +78,6 @@ namespace IEC61850
this.responsableForDeletion = responsableForDeletion;
}
/// <summary>
/// Get a child variable specification by its name
/// </summary>
/// <returns>the varibable specification of the child, or null if no such child is existing.</returns>
/// <param name="name">The child name (can also be a path separating the elements with '.' or '$')</param>
public MmsVariableSpecification GetChildByName(string name)
{
StringBuilder nameId = new StringBuilder(name);
nameId.Replace('.', '$');
IntPtr varSpecPtr = MmsVariableSpecification_getNamedVariableRecursive(self, nameId.ToString());
if (varSpecPtr != IntPtr.Zero)
{
return new MmsVariableSpecification(varSpecPtr, this);
}
else
return null;
}
~MmsVariableSpecification ()
{
if (responsableForDeletion)
@ -132,7 +106,7 @@ namespace IEC61850
{
if (GetType() == MmsType.MMS_ARRAY) {
IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self);
return new MmsVariableSpecification(varSpecPtr, this);
return new MmsVariableSpecification(varSpecPtr);
}
else
throw new MmsValueException ("specification is of wrong type");
@ -153,7 +127,7 @@ namespace IEC61850
if ((index >= 0) && (index < Size ())) {
IntPtr varSpecPtr = MmsVariableSpecification_getChildSpecificationByIndex(self, index);
return new MmsVariableSpecification(varSpecPtr, this);
return new MmsVariableSpecification(varSpecPtr);
}
else
throw new MmsValueException ("Index out of bounds");
@ -183,16 +157,6 @@ namespace IEC61850
return MmsVariableSpecification_getSize(self);
}
/// <summary>
/// Determines whether the given value object matches this type
/// </summary>
/// <returns><c>true</c> if the value matches this type; otherwise, <c>false</c>.</returns>
/// <param name="value">the value to test.</param>
public bool IsValueOfType(MmsValue value)
{
return MmsVariableSpecification_isValueOfType(self, value.valueReference);
}
IEnumerator IEnumerable.GetEnumerator ()
{
return new MmsVariableSpecificationEnumerator (this);

@ -34,8 +34,6 @@ namespace IEC61850
/// <summary>
/// Report handler.
/// </summary>
/// <param name="report">represents the received report. DON'T use this object
/// outside the scope of the report handler!</param>
public delegate void ReportHandler (Report report, object parameter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@ -132,11 +130,7 @@ namespace IEC61850
static extern void ClientReportControlBlock_setPurgeBuf (IntPtr self, [MarshalAs(UnmanagedType.I1)] bool purgeBuf);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ClientReportControlBlock_hasResvTms(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern Int16 ClientReportControlBlock_getResvTms (IntPtr self);
static extern Int32 ClientReportControlBlock_getResvTms (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void ClientReportControlBlock_setResvTms (IntPtr self, Int16 resvTms);
@ -153,8 +147,7 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReportControlBlock_getOwner (IntPtr self);
internal IntPtr self;
private IntPtr self;
private IedConnection iedConnection = null;
private string objectReference;
private bool flagRptId = false;
@ -307,18 +300,6 @@ namespace IEC61850
throw new IedConnectionException ("getRCBValues service failed", error);
}
/// <summary>
/// Read all RCB values from the server - asynchronous version
/// </summary>
/// <returns>the invoke ID of the request</returns>
/// <param name="handler">user provided callback function</param>
/// <param name="parameter">user provided callback parameter</param>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public UInt32 GetRCBValuesAsync(GetRCBValuesHandler handler, object parameter)
{
return iedConnection.GetRCBValuesAsync(GetObjectReference(), this, handler, parameter);
}
/// <summary>
/// Write changed RCB values to the server.
/// </summary>
@ -332,7 +313,17 @@ namespace IEC61850
SetRCBValues (true);
}
private UInt32 CreateParametersMask()
/// <summary>
/// Write changed RCB values to the server.
/// </summary>
/// <description>
/// This function will only write the RCB values that were set by one of the setter methods.
/// </description>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
/// <param name='singleRequest'>
/// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests.
/// </param>
public void SetRCBValues (bool singleRequest)
{
UInt32 parametersMask = 0;
@ -378,37 +369,6 @@ namespace IEC61850
if (flagResvTms)
parametersMask += 16384;
return parametersMask;
}
public UInt32 SetRCBValuesAsync(SetRCBValuesHandler handler, object parameter)
{
return SetRCBValuesAsync(true, handler, parameter);
}
public UInt32 SetRCBValuesAsync(bool singleRequest, SetRCBValuesHandler handler, object parameter)
{
UInt32 parametersMask = CreateParametersMask();
return iedConnection.SetRCBValuesAsync(this, parametersMask, singleRequest, handler, parameter);
}
/// <summary>
/// Write changed RCB values to the server.
/// </summary>
/// <description>
/// This function will only write the RCB values that were set by one of the setter methods.
/// </description>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
/// <param name='singleRequest'>
/// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests.
/// </param>
public void SetRCBValues (bool singleRequest)
{
UInt32 parametersMask = CreateParametersMask();
bool flagRptId = this.flagRptId;
int error;
iedConnection.SetRCBValues (out error, self, parametersMask, singleRequest);
@ -751,60 +711,6 @@ namespace IEC61850
flagOptFlds = true;
}
/// <summary>
/// Check if the report control block has the "ResvTms" attribute.
/// </summary>
/// <returns><c>true</c>, if ResvTms is available, <c>false</c> otherwise.</returns>
public bool HasResvTms()
{
return ClientReportControlBlock_hasResvTms(self);
}
/// <summary>
/// Gets the ResvTms (reservation time) value
/// </summary>
/// <remarks>
/// Only for BRCB.
/// Value of -1 indicate the BRCB is exclusively reserved for a set of client based upon configuration.
/// Value of 0 means that the BRCB is not reserved.
/// Positive value indicates that the BRCB is reserved dynamically and the value is the number of
/// seconds for reservation after association loss.
/// </remarks>
/// <returns>The reservation time</returns>
public Int16 GetResvTms()
{
return ClientReportControlBlock_getResvTms(self);
}
/// <summary>
/// Sets the ResvTms (reservation time) value
/// </summary>
/// <param name="resvTms">the reservation time value</param>
public void SetResvTms(Int16 resvTms)
{
ClientReportControlBlock_setResvTms(self, resvTms);
flagResvTms = true;
}
/// <summary>
/// Gets the current owner of the RCB
/// </summary>
/// <returns>The owner information, or null when no owner information is available.</returns>
public byte[] GetOwner()
{
IntPtr mmsValuePtr = ClientReportControlBlock_getOwner(self);
if (mmsValuePtr != IntPtr.Zero)
{
MmsValue octetStringVal = new MmsValue(mmsValuePtr);
return octetStringVal.getOctetString();
}
else
return null;
}
}
}

@ -1,7 +1,7 @@
/*
* Reporting.cs
*
* Copyright 2014-2018 Michael Zillgith
* Copyright 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -35,29 +35,26 @@ namespace IEC61850
private List<ReportControlBlock> activeRCBs = null;
public ReportControlBlock GetReportControlBlock(string rcbObjectReference)
public ReportControlBlock GetReportControlBlock (string rcbObjectReference)
{
var newRCB = new ReportControlBlock(rcbObjectReference, this, connection);
var newRCB = new ReportControlBlock (rcbObjectReference, this, connection);
if (activeRCBs == null)
activeRCBs = new List<ReportControlBlock>();
activeRCBs = new List<ReportControlBlock> ();
activeRCBs.Add(newRCB);
activeRCBs.Add (newRCB);
return newRCB;
}
internal void RemoveRCB(ReportControlBlock rcb)
{
if (activeRCBs != null)
{
activeRCBs.Remove(rcb);
internal void RemoveRCB(ReportControlBlock rcb) {
if (activeRCBs != null) {
activeRCBs.Remove (rcb);
}
}
}
[Flags]
public enum ReasonForInclusion
{
/** the element is not included in the received report */
@ -70,16 +67,16 @@ namespace IEC61850
REASON_QUALITY_CHANGE = 2,
/** the element is included due to an update of the data value */
REASON_DATA_UPDATE = 4,
REASON_DATA_UPDATE = 3,
/** the element is included due to a periodic integrity report task */
REASON_INTEGRITY = 8,
REASON_INTEGRITY = 4,
/** the element is included due to a general interrogation by the client */
REASON_GI = 16,
REASON_GI = 5,
/** the reason for inclusion is unknown */
REASON_UNKNOWN = 32
REASON_UNKNOWN = 6
}
/// <summary>
@ -90,10 +87,10 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ClientReport_hasTimestamp(IntPtr self);
static extern bool ClientReport_hasTimestamp (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt64 ClientReport_getTimestamp(IntPtr self);
static extern UInt64 ClientReport_getTimestamp (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReport_getDataSetValues(IntPtr self);
@ -150,22 +147,13 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReport_getDataReference(IntPtr self, int elementIndex);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern bool ClientReport_hasSubSeqNum(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt16 ClientReport_getSubSeqNum(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern bool ClientReport_getMoreSeqmentsFollow(IntPtr self);
private IntPtr self;
private IntPtr dataSetValues = IntPtr.Zero;
private MmsValue values = null;
internal Report(IntPtr self)
internal Report (IntPtr self)
{
this.self = self;
}
@ -176,9 +164,9 @@ namespace IEC61850
/// <returns>
/// <c>true</c> if this report has a timestamp; otherwise, <c>false</c>.
/// </returns>
public bool HasTimestamp()
public bool HasTimestamp ()
{
return ClientReport_hasTimestamp(self);
return ClientReport_hasTimestamp (self);
}
/// <summary>
@ -187,94 +175,55 @@ namespace IEC61850
/// <returns>
/// The timestamp as milliseconds since 1.1.1970 UTC 00:00 or 0 if no timestamp is present.
/// </returns>
public UInt64 GetTimestamp()
public UInt64 GetTimestamp ()
{
if (HasTimestamp())
return ClientReport_getTimestamp(self);
if (HasTimestamp ())
return ClientReport_getTimestamp (self);
else
return 0;
}
public bool HasDataSetName()
public bool HasDataSetName ()
{
return ClientReport_hasDataSetName(self);
}
public bool HasDataReference()
public bool HasDataReference ()
{
return ClientReport_hasDataReference(self);
}
public bool HasConfRev()
public bool HasConfRev ()
{
return ClientReport_hasConfRev(self);
}
public UInt32 GetConfRev()
public UInt32 GetConfRev ()
{
return ClientReport_getConfRev(self);
}
public bool HasBufOvfl()
public bool HasBufOvfl ()
{
return ClientReport_hasBufOvfl(self);
}
public bool GetBufOvfl()
public bool GetBufOvfl ()
{
return ClientReport_getBufOvfl(self);
}
/// <summary>
/// Indicates if the report contains a sequence number (SeqNum) field
/// </summary>
/// <returns><c>true</c> if this instance has SeqNum; otherwise, <c>false</c>.</returns>
public bool HasSeqNum()
public bool HasSeqNum ()
{
return ClientReport_hasSeqNum(self);
}
/// <summary>
/// Gets the value of the SeqNum field
/// </summary>
/// <returns>The report sequence number</returns>
public UInt16 GetSeqNum()
public UInt16 GetSeqNum ()
{
return ClientReport_getSeqNum(self);
}
/// <summary>
/// Indicates if the report contains a sub sequence number (SubSeqNum) and more segments follow (MoreSegmentsFollow) field
/// </summary>
/// <returns><c>true</c> if this instance has SubSeqNum and MoreSegmentsFollow; otherwise, <c>false</c>.</returns>
public bool HasSubSeqNum()
{
return ClientReport_hasSubSeqNum(self);
}
/// <summary>
/// Gets the sub sequence number (SubSeqNum) value of a segmented report
/// </summary>
/// <returns>The sub sequence number.</returns>
public UInt16 GetSubSeqNum()
{
return ClientReport_getSubSeqNum(self);
}
/// <summary>
/// Gets the more segments follow (MoreSegmentsFollow) flag
/// </summary>
/// <returns><c>true</c>, if more report segments follow, <c>false</c> otherwise.</returns>
public bool GetMoreSegmentsFollow()
{
return ClientReport_getMoreSeqmentsFollow(self);
}
/// <summary>
/// Determines whether this report contains reason for inclusion information
/// </summary>
/// <returns><c>true</c> if this report contains reason for inclusion information; otherwise, <c>false</c>.</returns>
public bool HasReasonForInclusion()
public bool HasReasonForInclusion ()
{
return ClientReport_hasReasonForInclusion(self);
}
@ -285,10 +234,9 @@ namespace IEC61850
/// <returns>
/// The data set values.
/// </returns>
public MmsValue GetDataSetValues()
{
if (dataSetValues == IntPtr.Zero)
public MmsValue GetDataSetValues ()
{
if (dataSetValues == IntPtr.Zero) {
dataSetValues = ClientReport_getDataSetValues(self);
if (dataSetValues == IntPtr.Zero)
@ -297,7 +245,7 @@ namespace IEC61850
values = new MmsValue(dataSetValues);
}
return values.Clone();
return values;
}
/// <summary>
@ -309,11 +257,10 @@ namespace IEC61850
/// <param name='index'>
/// index of the data set member in the data set
/// </param>
public ReasonForInclusion GetReasonForInclusion(int index)
public ReasonForInclusion GetReasonForInclusion (int index)
{
if (values == null)
{
GetDataSetValues();
if (values == null) {
GetDataSetValues ();
if (values == null)
throw new IedConnectionException("No ReasonForInclusion available yet");
@ -324,21 +271,21 @@ namespace IEC61850
if (index >= dataSetSize)
throw new IedConnectionException("data set index out of range (count = " + dataSetSize + ")");
return (ReasonForInclusion)ClientReport_getReasonForInclusion(self, index);
return (ReasonForInclusion) ClientReport_getReasonForInclusion(self, index);
}
public string GetRcbReference()
public string GetRcbReference ()
{
IntPtr rcbRef = ClientReport_getRcbReference(self);
return Marshal.PtrToStringAnsi(rcbRef);
return Marshal.PtrToStringAnsi (rcbRef);
}
public string GetDataSetName()
public string GetDataSetName ()
{
IntPtr dataSetName = ClientReport_getDataSetName(self);
IntPtr dataSetName = ClientReport_getDataSetName (self);
return Marshal.PtrToStringAnsi(dataSetName);
return Marshal.PtrToStringAnsi (dataSetName);
}
/// <summary>
@ -350,7 +297,7 @@ namespace IEC61850
/// <param name='index'>
/// index of the data set element starting with 0
/// </param>
public string GetDataReference(int index)
public string GetDataReference (int index)
{
IntPtr dataRef = ClientReport_getDataReference(self, index);
@ -360,31 +307,30 @@ namespace IEC61850
return null;
}
public string GetRptId()
public string GetRptId ()
{
IntPtr rptId = ClientReport_getRptId(self);
if (rptId == IntPtr.Zero)
return GetRcbReference();
else
return Marshal.PtrToStringAnsi(rptId);
return Marshal.PtrToStringAnsi (rptId);
}
/// <summary>
/// Gets the EntryID of this report.
/// </summary>
/// <returns>The entryID as a byte array representing an MMS octet string.</returns>
public byte[] GetEntryId()
public byte[] GetEntryId ()
{
IntPtr entryIdRef = ClientReport_getEntryId(self);
IntPtr entryIdRef = ClientReport_getEntryId (self);
if (entryIdRef == IntPtr.Zero)
return null;
else
{
MmsValue entryId = new MmsValue(entryIdRef);
else {
MmsValue entryId = new MmsValue (entryIdRef);
return entryId.getOctetString();
return entryId.getOctetString ();
}
}

@ -1,7 +1,7 @@
/*
* TLS.cs
*
* Copyright 2017-2022 Michael Zillgith
* Copyright 2017 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -37,173 +37,6 @@ namespace IEC61850
{
namespace TLS
{
public enum TLSConfigVersion
{
NOT_SELECTED = 0,
SSL_3_0 = 3,
TLS_1_0 = 4,
TLS_1_1 = 5,
TLS_1_2 = 6,
TLS_1_3 = 7
}
public enum TLSEventLevel
{
INFO = 0,
WARNING = 1,
INCIDENT = 2
}
public enum TLSEventCode
{
ALM_ALGO_NOT_SUPPORTED = 1,
ALM_UNSECURE_COMMUNICATION = 2,
ALM_CERT_UNAVAILABLE = 3,
ALM_BAD_CERT = 4,
ALM_CERT_SIZE_EXCEEDED = 5,
ALM_CERT_VALIDATION_FAILED = 6,
ALM_CERT_REQUIRED = 7,
ALM_HANDSHAKE_FAILED_UNKNOWN_REASON = 8,
WRN_INSECURE_TLS_VERSION = 9,
INF_SESSION_RENEGOTIATION = 10,
ALM_CERT_EXPIRED = 11,
ALM_CERT_REVOKED = 12,
ALM_CERT_NOT_CONFIGURED = 13,
ALM_CERT_NOT_TRUSTED = 14
}
public class TLSConnection
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int TLSConnection_getTLSVersion(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr TLSConnection_getPeerAddress(IntPtr self, IntPtr peerAddrBuf);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr TLSConnection_getPeerCertificate(IntPtr self, out int certSize);
private IntPtr self;
private bool isValid;
internal TLSConnection(IntPtr self)
{
this.self = self;
isValid = true;
}
// To be called by event callback caller after callback execution
internal void InValidate()
{
lock (this)
{
isValid = false;
}
}
/// <summary>
/// TLS version used by the connection
/// </summary>
public TLSConfigVersion TLSVersion
{
get
{
lock (this)
{
if (isValid)
{
return (TLSConfigVersion)TLSConnection_getTLSVersion((IntPtr)self);
}
else
{
throw new InvalidOperationException("Object cannot be used outside of TLS event callback");
}
}
}
}
/// <summary>
/// Peer IP address and TCP port of the TLS connection
/// </summary>
public string PeerAddress
{
get
{
lock (this)
{
if (isValid)
{
IntPtr peerAddrBuf = Marshal.AllocHGlobal(130);
IntPtr peerAddrStr = TLSConnection_getPeerAddress(this.self, peerAddrBuf);
string peerAddr = null;
if (peerAddrStr != IntPtr.Zero)
{
peerAddr = Marshal.PtrToStringAnsi(peerAddrStr);
}
Marshal.FreeHGlobal(peerAddrBuf);
return peerAddr;
}
else
{
throw new InvalidOperationException("Object cannot be used outside of TLS event callback");
}
}
}
}
/// <summary>
/// TLS certificate used by the peer
/// </summary>
public byte[] PeerCertificate
{
get
{
lock (this)
{
if (isValid)
{
int certSize;
IntPtr certBuffer = TLSConnection_getPeerCertificate(self, out certSize);
if (certBuffer != IntPtr.Zero)
{
if (certSize > 0)
{
byte[] cert = new byte[certSize];
Marshal.Copy(certBuffer, cert, 0, certSize);
return cert;
}
}
return null;
}
else
{
throw new InvalidOperationException("Object cannot be used outside of TLS event callback");
}
}
}
}
}
/// <summary>
/// TLS security event handler
/// </summary>
/// <param name="parameter">user provided context paramter to be passed to the handler</param>
/// <param name="eventLevel">severity level of the event</param>
/// <param name="eventCode">code to identify the event type</param>
/// <param name="message">text message describing the event</param>
/// <param name="connection">TLS connection that caused the event</param>
public delegate void TLSEventHandler(object parameter, TLSEventLevel eventLevel, TLSEventCode eventCode, string message, TLSConnection connection);
/// <summary>
/// A container for TLS configuration and certificates.
/// </summary>
@ -224,7 +57,7 @@ namespace IEC61850
static extern void TLSConfiguration_setAllowOnlyKnownCertificates(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setChainValidation(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
static extern void TLSConfiguration_setChainValidation (IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setClientMode(IntPtr self);
@ -243,7 +76,7 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnKeyFromFile(IntPtr self, string filename, string keyPassword);
static extern bool TLSConfiguration_setOwnKeyFromFile (IntPtr self, string filename, string keyPassword);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
@ -261,52 +94,13 @@ namespace IEC61850
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addCACertificateFromFile(IntPtr self, string filename);
private TLSEventHandler eventHandler = null;
private object eventHandlerParameter = null;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void InternalTLSEventHandler(IntPtr parameter, int eventLevel, int eventCode, IntPtr message, IntPtr tlsCon);
private InternalTLSEventHandler internalTLSEventHandlerRef = null;
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setEventHandler(IntPtr self, InternalTLSEventHandler handler, IntPtr parameter);
void InternalTLSEventHandlerImpl(IntPtr parameter, int eventLevel, int eventCode, IntPtr message, IntPtr tlsCon)
{
if (eventHandler != null)
{
TLSConnection connection = new TLSConnection(tlsCon);
string msg = Marshal.PtrToStringAnsi(message);
eventHandler(eventHandlerParameter, (TLSEventLevel)eventLevel, (TLSEventCode)eventCode, msg, connection);
connection.InValidate();
}
}
public void SetEventHandler(TLSEventHandler handler, object parameter)
{
this.eventHandler = handler;
this.eventHandlerParameter = parameter;
if (internalTLSEventHandlerRef == null)
{
internalTLSEventHandlerRef = new InternalTLSEventHandler(InternalTLSEventHandlerImpl);
TLSConfiguration_setEventHandler(self, internalTLSEventHandlerRef, IntPtr.Zero);
}
}
public TLSConfiguration()
{
self = TLSConfiguration_create();
public TLSConfiguration() {
self = TLSConfiguration_create ();
}
~TLSConfiguration()
{
Dispose();
Dispose ();
}
internal IntPtr GetNativeInstance()
@ -316,114 +110,101 @@ namespace IEC61850
public bool AllowOnlyKnownCertificates
{
set
{
TLSConfiguration_setAllowOnlyKnownCertificates(self, value);
set {
TLSConfiguration_setAllowOnlyKnownCertificates (self, value);
allowOnlyKnownCerts = value;
}
get
{
get {
return allowOnlyKnownCerts;
}
}
public bool ChainValidation
{
set
{
TLSConfiguration_setChainValidation(self, value);
set {
TLSConfiguration_setChainValidation (self, value);
chainValidation = value;
}
get
{
get {
return chainValidation;
}
}
public void SetClientMode()
{
TLSConfiguration_setClientMode(self);
TLSConfiguration_setClientMode (self);
}
public void SetOwnCertificate(string filename)
{
if (TLSConfiguration_setOwnCertificateFromFile(self, filename) == false)
{
throw new CryptographicException("Failed to read certificate from file");
if (TLSConfiguration_setOwnCertificateFromFile (self, filename) == false) {
throw new CryptographicException ("Failed to read certificate from file");
}
}
public void SetOwnCertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData();
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_setOwnCertificate(self, certBytes, certBytes.Length) == false)
{
throw new CryptographicException("Failed to set certificate");
if (TLSConfiguration_setOwnCertificate (self, certBytes, certBytes.Length) == false) {
throw new CryptographicException ("Failed to set certificate");
}
}
public void AddAllowedCertificate(string filename)
{
if (TLSConfiguration_addAllowedCertificateFromFile(self, filename) == false)
{
throw new CryptographicException("Failed to read allowed certificate from file");
if (TLSConfiguration_addAllowedCertificateFromFile (self, filename) == false) {
throw new CryptographicException ("Failed to read allowed certificate from file");
}
}
public void AddAllowedCertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData();
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_addAllowedCertificate(self, certBytes, certBytes.Length) == false)
{
throw new CryptographicException("Failed to add allowed certificate");
if (TLSConfiguration_addAllowedCertificate (self, certBytes, certBytes.Length) == false) {
throw new CryptographicException ("Failed to add allowed certificate");
}
}
public void AddCACertificate(string filename)
{
if (TLSConfiguration_addCACertificateFromFile(self, filename) == false)
{
throw new CryptographicException("Failed to read CA certificate from file");
if (TLSConfiguration_addCACertificateFromFile (self, filename) == false) {
throw new CryptographicException ("Failed to read CA certificate from file");
}
}
public void AddCACertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData();
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_addCACertificate(self, certBytes, certBytes.Length) == false)
{
throw new CryptographicException("Failed to add CA certificate");
if (TLSConfiguration_addCACertificate (self, certBytes, certBytes.Length) == false) {
throw new CryptographicException ("Failed to add CA certificate");
}
}
public void SetOwnKey(string filename, string password)
{
if (TLSConfiguration_setOwnKeyFromFile(self, filename, password) == false)
public void SetOwnKey (string filename, string password)
{
throw new CryptographicException("Failed to read own key from file");
if (TLSConfiguration_setOwnKeyFromFile (self, filename, password) == false) {
throw new CryptographicException ("Failed to read own key from file");
}
}
public void SetOwnKey(X509Certificate2 key, string password)
public void SetOwnKey (X509Certificate2 key, string password)
{
byte[] certBytes = key.Export(X509ContentType.Pkcs12);
byte[] certBytes = key.Export (X509ContentType.Pkcs12);
if (TLSConfiguration_setOwnKey(self, certBytes, certBytes.Length, password) == false)
{
throw new CryptographicException("Failed to set own key");
if (TLSConfiguration_setOwnKey (self, certBytes, certBytes.Length, password) == false) {
throw new CryptographicException ("Failed to set own key");
}
}
public void Dispose()
{
lock (this)
{
if (self != IntPtr.Zero)
{
TLSConfiguration_destroy(self);
lock (this) {
if (self != IntPtr.Zero) {
TLSConfiguration_destroy (self);
self = IntPtr.Zero;
}
}

@ -1,187 +0,0 @@
using System;
using IEC61850.Client;
using IEC61850.Common;
using System.Threading;
using System.Collections.Generic;
namespace client_example_async
{
class MainClass
{
public static void Main (string[] args)
{
IedConnection con = new IedConnection ();
string hostname;
if (args.Length > 0)
hostname = args[0];
else
hostname = "127.0.0.1";
int port = 102;
if (args.Length > 1)
port = Int32.Parse(args [1]);
Console.WriteLine("Connect to " + hostname);
try
{
con.MaxPduSize = 1000;
con.StateChanged = delegate(IedConnection connection, IedConnectionState newState) {
Console.WriteLine("state change: " + newState.ToString());
};
con.Connect(hostname, port);
AutoResetEvent waitForCallback = new AutoResetEvent(false);
List<string> ldList = null;
con.GetServerDirectoryAsync(ldList, null, delegate(uint invokeId, object parameter, IedClientError err, System.Collections.Generic.List<string> nameList, bool moreFollows) {
if (nameList != null) {
ldList = nameList;
}
else
{
Console.WriteLine("Get server directory error: " + err.ToString());
}
waitForCallback.Set();
}, null);
waitForCallback.WaitOne();
if (ldList != null) {
string firstLdName = null;
Console.WriteLine("Server directory:");
foreach (string ldName in ldList) {
Console.WriteLine(" LD: " + ldName);
if (firstLdName == null)
firstLdName = ldName;
}
bool moreVariabesFollows = true;
string lastVariableName = null;
List<string> variablesList = new List<string>();
while (moreVariabesFollows) {
waitForCallback.Reset();
con.GetLogicalDeviceVariablesAsync(variablesList, firstLdName, lastVariableName, delegate(uint invokeId, object parameter, IedClientError err, List<string> nameList, bool moreFollows) {
if (nameList != null) {
if (moreFollows)
Console.WriteLine("More variables available...");
lastVariableName = nameList[nameList.Count - 1];
}
else
{
Console.WriteLine("Get logical device variables error: " + err.ToString());
}
moreVariabesFollows = moreFollows;
waitForCallback.Set();
}, null);
waitForCallback.WaitOne();
}
Console.WriteLine("Variables in logical device {0}:", firstLdName);
foreach (string variableName in variablesList) {
Console.WriteLine(" {0}", variableName);
}
}
Console.WriteLine("Now read variables...");
/* read FCDO */
con.ReadValueAsync("simpleIOGenericIO/GGIO1.AnIn1", FunctionalConstraint.MX, delegate(uint invokeId, object parameter, IedClientError err, MmsValue value) {
if (err == IedClientError.IED_ERROR_OK)
{
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());
}
}
}
}
else {
Console.WriteLine("Read error: " + err.ToString());
}
}, null);
con.ReadValueAsync("simpleIOGenericIO/GGIO1.AnIn1", FunctionalConstraint.MX, delegate(uint invokeId, object parameter, IedClientError err, MmsValue value) {
if (err == IedClientError.IED_ERROR_OK)
{
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());
}
}
}
}
else {
Console.WriteLine("Read error: " + err.ToString());
}
}, null);
Thread.Sleep(5000);
con.Abort();
Console.WriteLine("Aborted");
}
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 ();
}
static void HandleReadObjectHandler (uint invokeId, object parameter, IedClientError err, MmsValue value)
{
}
}
}

@ -1,27 +0,0 @@
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("client_example_async")]
[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("")]

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{71902641-776A-47D8-9C0E-9ACBBEAC1370}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>client_example_async</RootNamespace>
<AssemblyName>client_example_async</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850.NET.csproj">
<Project>{C35D624E-5506-4560-8074-1728F1FA1A4D}</Project>
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,78 +0,0 @@
using System;
using IEC61850.Client;
using IEC61850.Common;
namespace client_examples_setting_groups
{
/// <summary>
/// This class is intended to show how to use setting groups from the client side.
/// It works with server_example_setting_groups.
/// </summary>
class SettingGroupsClientExample
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
IedConnection con = new IedConnection ();
string hostname;
if (args.Length > 0)
hostname = args[0];
else
hostname = "127.0.0.1";
int port = 102;
if (args.Length > 1)
port = Int32.Parse(args [1]);
Console.WriteLine("Connect to " + hostname);
try
{
con.Connect(hostname, port);
/* Get variable specification of the SGCB (optional) */
MmsVariableSpecification sgcbVarSpec = con.GetVariableSpecification("DEMOPROT/LLN0.SGCB", FunctionalConstraint.SP);
/* Read SGCB */
MmsValue sgcbVal = con.ReadValue("DEMOPROT/LLN0.SGCB", FunctionalConstraint.SP);
Console.WriteLine("NumOfSG: {0}", sgcbVal.GetChildValue("NumOfSG", sgcbVarSpec).ToString());
Console.WriteLine("ActSG: {0}", sgcbVal.GetChildValue("ActSG", sgcbVarSpec).ToString());
Console.WriteLine("EditSG: {0}", sgcbVal.GetChildValue("EditSG", sgcbVarSpec).ToString());
Console.WriteLine("CnfEdit: {0}", sgcbVal.GetChildValue("CnfEdit", sgcbVarSpec).ToString());
/* Set active setting group */
con.WriteValue("DEMOPROT/LLN0.SGCB.ActSG", FunctionalConstraint.SP, new MmsValue((uint) 2));
/* Set edit setting group */
con.WriteValue("DEMOPROT/LLN0.SGCB.EditSG", FunctionalConstraint.SP, new MmsValue((uint) 1));
/* Change a setting group value */
con.WriteValue("DEMOPROT/PTOC1.StrVal.setMag.f", FunctionalConstraint.SE, new MmsValue(1.0f));
/* Confirm new setting group values */
con.WriteValue("DEMOPROT/LLN0.SGCB.CnfEdit", FunctionalConstraint.SP, new MmsValue(true));
/* Read SGCB again */
sgcbVal = con.ReadValue("DEMOPROT/LLN0.SGCB", FunctionalConstraint.SP);
Console.WriteLine("ActSG: {0}",sgcbVal.GetChildValue("ActSG", sgcbVarSpec).ToString());
con.Abort();
}
catch (IedConnectionException e)
{
Console.WriteLine(e.Message);
}
// release all resources - do NOT use the object after this call!!
con.Dispose ();
}
}
}

@ -1,27 +0,0 @@
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("client-example-setting-group")]
[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("")]

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0DA95476-B149-450B-AC36-01CEECFC1A43}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>clientexamplesettinggroup</RootNamespace>
<AssemblyName>client-example-setting-group</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850.NET.csproj">
<Project>{C35D624E-5506-4560-8074-1728F1FA1A4D}</Project>
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
</Project>

@ -40,7 +40,6 @@ namespace control
ControlModel controlModel = control.GetControlModel();
Console.WriteLine(objectReference + " has control model " + controlModel.ToString());
Console.WriteLine(" type of ctlVal: " + control.GetCtlValType().ToString());
switch (controlModel) {

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.779
# Visual Studio 2012
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
EndProject
@ -44,108 +44,86 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sv_subscriber", "sv_subscri
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_server_example", "tls_server_example\tls_server_example.csproj", "{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_setting_groups", "client_example_setting_groups\client_example_setting_groups.csproj", "{0DA95476-B149-450B-AC36-01CEECFC1A43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_async", "client_example_async\client_example_async.csproj", "{71902641-776A-47D8-9C0E-9ACBBEAC1370}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server_goose_publisher", "server_goose_publisher\server_goose_publisher.csproj", "{C14BB883-86B8-401C-B3D6-B655F55F3298}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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
{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
{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
{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
{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
{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
{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
{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
{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
{1285372C-2E62-494A-A661-8D5D3873318C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Release|Any CPU.Build.0 = Release|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.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
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.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
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.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
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.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
{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}.Release|Any CPU.Build.0 = Release|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Release|Any CPU.Build.0 = Release|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1285372C-2E62-494A-A661-8D5D3873318C}.Release|Any CPU.Build.0 = Release|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44651D2D-3252-4FD5-8B8B-5552DBE1B499}.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
{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Release|Any CPU.Build.0 = Release|Any CPU
{0DA95476-B149-450B-AC36-01CEECFC1A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DA95476-B149-450B-AC36-01CEECFC1A43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DA95476-B149-450B-AC36-01CEECFC1A43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DA95476-B149-450B-AC36-01CEECFC1A43}.Release|Any CPU.Build.0 = Release|Any CPU
{71902641-776A-47D8-9C0E-9ACBBEAC1370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71902641-776A-47D8-9C0E-9ACBBEAC1370}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71902641-776A-47D8-9C0E-9ACBBEAC1370}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71902641-776A-47D8-9C0E-9ACBBEAC1370}.Release|Any CPU.Build.0 = Release|Any CPU
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
{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
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F590B86-C80C-4658-83BC-855A87751CEF}
GlobalSection(NestedProjects) = preSolution
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
@ -159,4 +137,7 @@ Global
$2.inheritsScope = text/plain
StartupItem = IEC61850forCSharp\IEC61850forCSharp.csproj
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

@ -69,17 +69,6 @@ namespace example1
Console.WriteLine("Read data set " + dataSet.GetReference());
/* read multiple variables (WARNING: this is not IEC 61850 standard compliant but might
* be supported by most servers).
*/
MmsConnection mmsConnection = con.GetMmsConnection();
MmsValue result = mmsConnection.ReadMultipleVariables("simpleIOGenericIO", new List<string>() {
"GGIO1$ST$Ind1", "GGIO1$ST$Ind1", "GGIO1$ST$Ind1","GGIO1$ST$Ind1"
});
Console.WriteLine(result.ToString());
con.Abort();
}
catch (IedConnectionException e)

@ -24,11 +24,11 @@ namespace example3
{
IsoConnectionParameters parameters = con.GetConnectionParameters();
parameters.SetRemoteAddresses(new byte[] { 0x00, 0x01 }, new byte[] {0x00, 0x01}, new byte[] {0x00, 0x01, 0x02, 0x03});
parameters.SetRemoteAddresses(1, new byte[] {0x00, 0x01}, new byte[] {0x00, 0x01, 0x02, 0x03});
con.ConnectTimeout = 10000;
con.MaxPduSize = 1200;
con.GetMmsConnection().SetLocalDetail(1200);
con.Connect(hostname, 102);

@ -4,58 +4,48 @@ using System.Collections.Generic;
using IEC61850.Client;
using IEC61850.Common;
using System.IO;
using System.Threading;
namespace files
{
/// <summary>
/// This example connects to an IEC 61850 device, list the available files, and then
/// tries to read the file "IEDSERVER.BIN" from the server.
/// </summary>
class MainClass
{
public static void printFiles(IedConnection con, string prefix, string parent)
public static void printFiles (IedConnection con, string prefix, string parent)
{
bool moreFollows = false;
List<FileDirectoryEntry> files = con.GetFileDirectory (parent);
List<FileDirectoryEntry> files = con.GetFileDirectoryEx(parent, null, out moreFollows);
foreach (FileDirectoryEntry file in files)
{
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());
if (file.GetFileName().EndsWith("/")) {
printFiles (con, prefix + " ", parent + file.GetFileName());
}
}
if (moreFollows)
Console.WriteLine("-- MORE FILES AVAILABLE --");
}
static bool getFileHandler(object parameter, byte[] data)
static bool getFileHandler (object parameter, byte[] data)
{
Console.WriteLine("received " + data.Length + " bytes");
BinaryWriter binWriter = (BinaryWriter)parameter;
BinaryWriter binWriter = (BinaryWriter) parameter;
binWriter.Write(data);
return true;
}
public static void Main(string[] args)
public static void Main (string[] args)
{
IedConnection con = new IedConnection();
IedConnection con = new IedConnection ();
string hostname;
if (args.Length > 0)
hostname = args[0];
else
hostname = "127.0.0.1";
hostname = "10.0.2.2";
Console.WriteLine("Connect to " + hostname);
@ -63,17 +53,16 @@ namespace files
{
con.Connect(hostname, 102);
Console.WriteLine("Files in server root directory:");
Console.WriteLine ("Files in server root directory:");
List<string> serverDirectory = con.GetServerDirectory(true);
foreach (string entry in serverDirectory)
{
foreach (string entry in serverDirectory) {
Console.WriteLine(entry);
}
Console.WriteLine();
Console.WriteLine("File directory tree at server:");
Console.WriteLine ("File directory tree at server:");
printFiles(con, "", "");
Console.WriteLine();
@ -85,38 +74,7 @@ namespace files
FileStream fs = new FileStream(filename, FileMode.Create);
BinaryWriter w = new BinaryWriter(fs);
bool fileDownloadFinished = false;
//con.GetFile (filename, new IedConnection.GetFileHandler (getFileHandler), w);
/// COMMENT SECTION WHEN USING SYNC VERSION -->
con.GetFileAsync(filename, delegate (UInt32 invokeId, object parameter, IedClientError err, UInt32 originalInvokeId, byte[] buffer, bool moreFollows)
{
if (err == IedClientError.IED_ERROR_OK)
{
Console.WriteLine("Received new file segment with " + buffer.Length.ToString() + " bytes, more-follows: " + moreFollows.ToString());
w.Write(buffer);
if (moreFollows == false)
fileDownloadFinished = true;
}
else
{
Console.WriteLine("File download error: " + err.ToString());
fileDownloadFinished = true;
}
return true;
}, w);
while (fileDownloadFinished == false)
{
Thread.Sleep(500);
}
/// <-- COMMENT SECTION WHEN USING SYNC VERSION
con.GetFile(filename, new IedConnection.GetFileHandler(getFileHandler), w);
fs.Close();
@ -128,7 +86,7 @@ namespace files
}
// release all resources - do NOT use the object after this call!!
con.Dispose();
con.Dispose ();
}
}
}

@ -4,9 +4,6 @@ using IEC61850.GOOSE.Subscriber;
using System.Threading;
using IEC61850.Common;
/// <summary>
/// This example is intended to be
/// </summary>
namespace goose_subscriber
{
class MainClass
@ -14,10 +11,9 @@ namespace goose_subscriber
private static void gooseListener (GooseSubscriber subscriber, object parameter)
{
Console.WriteLine ("Received GOOSE message:\n-------------------------");
Console.WriteLine (" GoID: " + subscriber.GetGoId());
Console.WriteLine (" GoCbRef: " + subscriber.GetGoCbRef());
Console.WriteLine (" DatSet: " + subscriber.GetDataSet());
Console.WriteLine (" stNum: " + subscriber.GetStNum ());
Console.WriteLine (" sqNum: " + subscriber.GetSqNum ());
@ -37,27 +33,17 @@ namespace goose_subscriber
GooseReceiver receiver = new GooseReceiver ();
receiver.SetInterfaceId ("eth0");
//receiver.SetInterfaceId("0"); // on windows use the interface index starting with 0
GooseSubscriber subscriber = new GooseSubscriber ("simpleIOGenericIO/LLN0$GO$gcbAnalogValues");
// APP-ID has to match the APP-ID of the publisher
subscriber.SetAppId(4096);
subscriber.SetAppId(1000);
subscriber.SetListener (gooseListener, null);
receiver.AddSubscriber (subscriber);
GooseSubscriber subscriber2 = new GooseSubscriber("simpleIOGenericIO/LLN0$GO$gcbEvents");
subscriber2.SetAppId(4096);
subscriber2.SetListener(gooseListener, null);
receiver.AddSubscriber(subscriber2);
receiver.Start ();
subscriber = null;
if (receiver.IsRunning ()) {
bool running = true;

@ -7,7 +7,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>log_client</RootNamespace>
<AssemblyName>log_client</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

@ -104,16 +104,12 @@ namespace reporting
rcb2.SetRCBValues();
rcb2.GetRCBValues();
Console.WriteLine("RCB: " + rcbReference2 + " Owner: " + BitConverter.ToString(rcb2.GetOwner()));
rcb3.GetRCBValues();
if (rcb3.IsBuffered())
Console.WriteLine ("RCB: " + rcbReference3 + " is buffered");
rcb3.InstallReportHandler(reportHandler, rcb3);
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);

@ -7,126 +7,64 @@ namespace server1
{
class MainClass
{
public static void Main(string[] args)
public static void Main (string[] args)
{
bool running = true;
/* run until Ctrl-C is pressed */
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
running = false;
};
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("model.cfg");
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile ("model.cfg");
if (iedModel == null)
{
Console.WriteLine("No valid data model found!");
if (iedModel == null) {
Console.WriteLine ("No valid data model found!");
return;
}
iedModel.SetIedName("TestIED");
DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO1");
DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference ("GenericIO/GGIO1.SPCSO1");
IedServerConfig config = new IedServerConfig();
IedServerConfig config = new IedServerConfig ();
config.ReportBufferSize = 100000;
IedServer iedServer = new IedServer(iedModel, config);
iedServer.SetCheckHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck)
{
Console.WriteLine("Received binary control command:");
Console.WriteLine(" ctlNum: " + action.GetCtlNum());
Console.WriteLine(" execution-time: " + action.GetControlTimeAsDataTimeOffset().ToString());
return CheckHandlerResult.ACCEPTED;
}, null);
IedServer iedServer = new IedServer (iedModel, config);
iedServer.SetControlHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue ctlVal, bool test)
{
iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) {
bool val = ctlVal.GetBoolean();
if (val)
Console.WriteLine("execute binary control command: on");
Console.WriteLine("received binary control command: on");
else
Console.WriteLine("execute binary control command: off");
Console.WriteLine("received binary control command: off");
return ControlHandlerResult.OK;
}, null);
DataObject spcso2 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO2");
iedServer.SetSelectStateChangedHandler(spcso2, delegate (ControlAction action, object parameter, bool isSelected, SelectStateChangedReason reason)
{
DataObject cObj = action.GetControlObject();
Console.WriteLine("Control object " + cObj.GetObjectReference() + (isSelected ? " selected" : " unselected") + " reason: " + reason.ToString());
}, null);
iedServer.SetRCBEventHandler(delegate (object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError)
{
Console.WriteLine("RCB: " + rcb.Parent.GetObjectReference() + "." + rcb.Name + " event: " + eventType.ToString());
if (con != null)
{
Console.WriteLine(" caused by client " + con.GetPeerAddress());
}
else
{
Console.WriteLine(" client = null");
}
if (eventType == RCBEventType.ENABLED)
{
Console.WriteLine(" RptID: " + rcb.RptID);
Console.WriteLine(" DatSet: " + rcb.DataSet);
Console.WriteLine(" TrgOps: " + rcb.TrgOps.ToString());
}
if ((eventType == RCBEventType.SET_PARAMETER) || (eventType == RCBEventType.GET_PARAMETER))
{
Console.WriteLine(" param: " + parameterName);
Console.WriteLine(" result: " + serviceError.ToString());
}
}, null);
iedServer.Start(102);
iedServer.Start (102);
Console.WriteLine ("Server started");
if (iedServer.IsRunning())
{
Console.WriteLine("Server started");
GC.Collect ();
GC.Collect();
DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference ("GenericIO/GGIO1.AnIn1");
DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1");
DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild("mag.f");
DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild("t");
DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild ("mag.f");
DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild ("t");
float floatVal = 1.0f;
while (running)
{
while (running) {
floatVal += 1f;
iedServer.UpdateTimestampAttributeValue(ggio1AnIn1T, new Timestamp(DateTime.Now));
iedServer.UpdateFloatAttributeValue(ggio1AnIn1magF, floatVal);
Thread.Sleep(100);
iedServer.UpdateTimestampAttributeValue (ggio1AnIn1T, new Timestamp (DateTime.Now));
iedServer.UpdateFloatAttributeValue (ggio1AnIn1magF, floatVal);
Thread.Sleep (100);
}
iedServer.Stop();
Console.WriteLine("Server stopped");
}
else
{
Console.WriteLine("Failed to start server");
}
iedServer.Stop ();
Console.WriteLine ("Server stopped");
iedServer.Destroy();
iedServer.Destroy ();
}
}
}

@ -2,12 +2,13 @@ MODEL(simpleIO){
LD(GenericIO){
LN(LLN0){
DO(Mod 0){
DA(stVal 0 12 0 1 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(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
@ -23,22 +24,30 @@ DA(d 0 20 5 0 0);
DA(configRev 0 20 5 0 0);
DA(ldNs 0 20 11 0 0);
}
DS(ControlEvents){
DS(Events){
DE(GGIO1$ST$SPCSO1$stVal);
DE(GGIO1$ST$SPCSO2$stVal);
DE(GGIO1$ST$SPCSO3$stVal);
DE(GGIO1$ST$SPCSO4$stVal);
DE(GGIO1$ST$SPCSO5$stVal);
DE(GGIO1$ST$SPCSO6$stVal);
DE(GGIO1$ST$SPCSO7$stVal);
DE(GGIO1$ST$SPCSO8$stVal);
DE(GGIO1$ST$SPCSO9$stVal);
DE(GGIO1$ST$SPCSO2$stSeld);
DE(GGIO1$OR$SPCSO2$opRcvd);
DE(GGIO1$OR$SPCSO2$opOk);
}
RC(ControlEventsRCB01 ControlEvents 0 ControlEvents 1 17 239 0 1000);
RC(ControlEventsRCB02 ControlEvents 0 ControlEvents 1 17 239 0 1000);
}
DS(AnalogValues){
DE(GGIO1$MX$AnIn1);
DE(GGIO1$MX$AnIn2);
DE(GGIO1$MX$AnIn3);
DE(GGIO1$MX$AnIn4);
}
RC(EventsRCB01 Events 0 Events 1 24 111 50 1000);
RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 111 50 1000);
LC(EventLog Events GenericIO/LLN0$EventLog 19 0 0 1);
LC(GeneralLog - - 19 0 0 1);
LOG(GeneralLog);
LOG(EventLog);
GC(gcbEvents events Events 2 0 -1 -1 ){
PA(4 273 4096 010ccd010001);
}
GC(gcbAnalogValues analog AnalogValues 2 0 -1 -1 ){
PA(4 273 4096 010ccd010001);
}
}
LN(LPHD1){
DO(PhyNam 0){
@ -57,12 +66,13 @@ DA(t 0 22 0 0 0);
}
LN(GGIO1){
DO(Mod 0){
DA(stVal 0 12 0 1 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(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
@ -84,11 +94,11 @@ DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
DO(AnIn2 0){
DA(mag 0 27 1 1 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 0);
DA(t 0 22 1 0 102);
}
DO(AnIn3 0){
DA(mag 0 27 1 1 0){
@ -105,24 +115,8 @@ DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
DO(SPCSO1 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=1;
}
DO(SPCSO2 0){
DA(SBO 0 17 12 0 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
@ -134,28 +128,12 @@ DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(Cancel 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(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(t 0 22 0 0 0);
DA(stSeld 0 0 0 1 0);
DA(opRcvd 0 0 9 1 0);
DA(opOk 0 0 9 1 0);
DA(tOpOk 0 22 9 0 0);
DA(ctlModel 0 12 4 0 0)=2;
DA(sboTimeout 0 9 4 1 0)=2000;
DA(sboClass 0 12 4 0 0);
}
DO(SPCSO3 0){
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
@ -167,33 +145,12 @@ DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(Cancel 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(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(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=3;
}
DO(SPCSO4 0){
DA(SBOw 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(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
@ -205,54 +162,14 @@ DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(Cancel 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(ctlModel 0 12 4 0 0)=1;
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=4;
}
DO(SPCSO5 0){
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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);
}
DO(SPCSO4 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=1;
DA(Cancel 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);
}
}
DO(SPCSO6 0){
DA(SBO 0 17 12 0 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 12 0 0);
DA(origin 0 27 12 0 0){
DA(orCat 0 12 12 0 0);
DA(orIdent 0 13 12 0 0);
@ -262,144 +179,59 @@ DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(Cancel 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(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);
DA(ctlModel 0 12 4 0 0)=2;
}
DO(SPCSO7 0){
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Cancel 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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);
}
DO(Ind2 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=3;
}
DO(SPCSO8 0){
DA(SBOw 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Cancel 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(origin 0 27 0 0 0){
DA(orCat 0 12 0 0 0);
DA(orIdent 0 13 0 0 0);
}
DA(ctlNum 0 6 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);
DA(ctlModel 0 12 4 0 0)=4;
}
DO(SPCSO9 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(Cancel 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);
}
DO(Ind4 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=3;
}
DO(Ind1 0){
DA(stVal 0 0 0 1 0);
}
LN(PDUP1){
DO(Beh 0){
DA(stVal 0 12 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);
DO(Mod 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=0;
}
DO(Ind3 0){
DA(stVal 0 0 0 1 0);
DO(Str 0){
DA(general 0 0 0 1 0);
DA(dirGeneral 0 12 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);
DO(Op 0){
DA(general 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(OpDlTmms 0){
DA(setVal 0 3 2 1 0);
}
DO(RsDlTmms 0){
DA(setVal 0 3 2 1 0);
}
}
}
}

@ -7,8 +7,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>server1</RootNamespace>
<AssemblyName>server1</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -19,7 +18,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("server_goose_publisher")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("server_goose_publisher")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c14bb883-86b8-401c-b3d6-b655f55f3298")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -1,129 +0,0 @@
using System;
using IEC61850.Server;
using IEC61850.Common;
using System.Threading;
namespace server_goose_publisher
{
/// <summary>
/// This example shows how to use the server integrated GOOSE publisher from .NET
/// </summary>
/// <remarks>
/// This example requires that the native library (libiec61850) is compiled with GOOSE support.
/// </remarks>
class ServerExampleWithGoosePublisher
{
public static void Main(string[] args)
{
bool running = true;
/* run until Ctrl-C is pressed */
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
running = false;
};
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("simpleIO_direct_control_goose.cfg");
if (iedModel == null)
{
Console.WriteLine("No valid data model found!");
return;
}
iedModel.SetIedName("TestIED");
DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO1");
IedServerConfig config = new IedServerConfig();
config.ReportBufferSize = 100000;
IedServer iedServer = new IedServer(iedModel, config);
// Set GOOSE interface (e.g. "eth0" for Linux or "0" for Windows (first interface)
iedServer.SetGooseInterfaceId("0");
// The GoCBEventHandler can be used to track GoCB events
iedServer.SetGoCBHandler(delegate (MmsGooseControlBlock goCB, int cbEvent, object parameter)
{
if (cbEvent == 1)
{
Console.WriteLine("GCB " + goCB.LN.GetObjectReference() + ":" + goCB.Name + " enabled");
}
else
{
Console.WriteLine("GCB " + goCB.LN.GetObjectReference() + ":" + goCB.Name + " disabled");
}
}, null);
iedServer.SetCheckHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck)
{
Console.WriteLine("Received binary control command:");
Console.WriteLine(" ctlNum: " + action.GetCtlNum());
Console.WriteLine(" execution-time: " + action.GetControlTimeAsDataTimeOffset().ToString());
return CheckHandlerResult.ACCEPTED;
}, null);
iedServer.SetControlHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue ctlVal, bool test)
{
bool val = ctlVal.GetBoolean();
if (val)
Console.WriteLine("execute binary control command: on");
else
Console.WriteLine("execute binary control command: off");
return ControlHandlerResult.OK;
}, null);
DataObject spcso2 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO2");
iedServer.SetSelectStateChangedHandler(spcso2, delegate (ControlAction action, object parameter, bool isSelected, SelectStateChangedReason reason)
{
DataObject cObj = action.GetControlObject();
Console.WriteLine("Control object " + cObj.GetObjectReference() + (isSelected ? " selected" : " unselected") + " reason: " + reason.ToString());
}, null);
iedServer.Start(102);
// Enable GOOSE publishing for all GOOSE control blocks
iedServer.EnableGoosePublishing();
if (iedServer.IsRunning())
{
Console.WriteLine("Server started");
GC.Collect();
DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1");
DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild("mag.f");
DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild("t");
float floatVal = 1.0f;
while (running)
{
floatVal += 1f;
iedServer.UpdateTimestampAttributeValue(ggio1AnIn1T, new Timestamp(DateTime.Now));
iedServer.UpdateFloatAttributeValue(ggio1AnIn1magF, floatVal);
Thread.Sleep(100);
}
iedServer.Stop();
Console.WriteLine("Server stopped");
}
else
{
Console.WriteLine("Failed to start server");
}
iedServer.Destroy();
}
}
}

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C14BB883-86B8-401C-B3D6-B655F55F3298}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>server_goose_publisher</RootNamespace>
<AssemblyName>server_goose_publisher</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ServerExampleWithGoosePublisher.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="simpleIO_direct_control_goose.cfg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850.NET.csproj">
<Project>{c35d624e-5506-4560-8074-1728f1fa1a4d}</Project>
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -1,217 +0,0 @@
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(Events2){
DE(GGIO1$ST$SPCSO1);
DE(GGIO1$ST$SPCSO2);
DE(GGIO1$ST$SPCSO3);
DE(GGIO1$ST$SPCSO4);
}
DS(Events3){
DE(GGIO1$ST$SPCSO1$stVal);
DE(GGIO1$ST$SPCSO1$q);
DE(GGIO1$ST$SPCSO2$stVal);
DE(GGIO1$ST$SPCSO2$q);
DE(GGIO1$ST$SPCSO3$stVal);
DE(GGIO1$ST$SPCSO3$q);
DE(GGIO1$ST$SPCSO4$stVal);
DE(GGIO1$ST$SPCSO4$q);
}
DS(AnalogValues){
DE(GGIO1$MX$AnIn1);
DE(GGIO1$MX$AnIn2);
DE(GGIO1$MX$AnIn3);
DE(GGIO1$MX$AnIn4);
}
RC(EventsRCB01 Events 0 Events 1 24 175 50 1000);
RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 175 50 1000);
GC(gcbEvents events Events3 2 0 1000 3000 ){
PA(4 1 4096 010ccd010001);
}
GC(gcbAnalogValues analog AnalogValues 2 0 -1 -1 ){
PA(4 1 4096 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 0){
DA(f 0 10 1 1 0);
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
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);
}
}
}
}

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -7,8 +7,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>sv_subscriber</RootNamespace>
<AssemblyName>sv_subscriber</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

@ -49,15 +49,6 @@ namespace tests
Assert.AreEqual(7, val.BitStringToUInt32());
}
[Test ()]
public void MmsValueUtcTime ()
{
var val = MmsValue.NewUtcTime (100000);
val.GetUtcTimeInMs ();
Assert.AreEqual (val.GetUtcTimeInMs (), 100000);
}
[Test()]
public void MmsValueOctetString ()
{
@ -114,57 +105,6 @@ namespace tests
Assert.AreEqual (val.ToFloat (), (float)0.1234);
}
[Test()]
public void MmsValueArray()
{
MmsValue val = MmsValue.NewEmptyArray (3);
val.SetElement (0, new MmsValue (1));
val.SetElement (1, new MmsValue (2));
val.SetElement (2, new MmsValue (3));
Assert.AreEqual (val.GetType (), MmsType.MMS_ARRAY);
Assert.AreEqual (val.Size (), 3);
MmsValue elem0 = val.GetElement (0);
Assert.AreEqual (elem0.GetType (), MmsType.MMS_INTEGER);
Assert.AreEqual (elem0.ToInt32 (), 1);
MmsValue elem2 = val.GetElement (2);
Assert.AreEqual (elem2.GetType (), MmsType.MMS_INTEGER);
Assert.AreEqual (elem2.ToInt32 (), 3);
val.SetElement (0, null);
val.SetElement (1, null);
val.SetElement (2, null);
}
[Test()]
public void MmsValueStructure()
{
MmsValue val = MmsValue.NewEmptyStructure (2);
val.SetElement (0, new MmsValue(true));
val.SetElement (1, MmsValue.NewBitString (10));
Assert.AreEqual (val.GetType (), MmsType.MMS_STRUCTURE);
Assert.AreEqual (val.Size (), 2);
MmsValue elem0 = val.GetElement (0);
Assert.AreEqual (elem0.GetType (), MmsType.MMS_BOOLEAN);
Assert.AreEqual (elem0.GetBoolean(), true);
MmsValue elem1 = val.GetElement (1);
Assert.AreEqual (elem1.GetType (), MmsType.MMS_BIT_STRING);
val.SetElement (0, null);
val.SetElement (1, null);
}
[Test ()]
public void Timestamps()
{
@ -244,8 +184,6 @@ namespace tests
Assert.AreEqual (list.ToArray () [0], "simpleIOGenericIO");
Assert.IsTrue(iedServer.IsRunning());
iedServer.Stop ();
iedServer.Destroy ();
@ -291,38 +229,10 @@ namespace tests
Assert.IsNotNull (modelNode);
}
[Test()]
public void AccessDataModelServerSideNavigateModelNode()
{
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("../../model.cfg");
ModelNode modelNode = iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1");
Assert.IsNotNull(modelNode);
Assert.IsTrue(modelNode.GetType().Equals(typeof(DataObject)));
var children = modelNode.GetChildren();
Assert.AreEqual(3, children.Count);
ModelNode mag = children.First.Value;
Assert.AreEqual("mag", mag.GetName());
ModelNode t = children.Last.Value;
Assert.AreEqual("t", t.GetName());
//modelNode = iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1.mag.f");
//Assert.IsTrue(modelNode.GetType().Equals(typeof(IEC61850.Server.DataAttribute)));
}
[Test ()]
public void AccessDataModelClientServer()
{
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("../../model.cfg");
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile ("../../model.cfg");
ModelNode ind1 = iedModel.GetModelNodeByShortObjectReference ("GenericIO/GGIO1.Ind1.stVal");
@ -412,62 +322,10 @@ namespace tests
iedServer.Destroy ();
}
[Test()]
public void ControlWriteAccessComplexDAToServer()
{
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("../../model2.cfg");
IEC61850.Server.DataAttribute setAnVal_setMag = (IEC61850.Server.DataAttribute)iedModel.GetModelNodeByShortObjectReference("GenericIO/LLN0.SetAnVal.setMag");
IedServer iedServer = new IedServer(iedModel);
int handlerCalled = 0;
MmsValue receivedValue = null;
iedServer.SetWriteAccessPolicy(FunctionalConstraint.SP, AccessPolicy.ACCESS_POLICY_DENY);
iedServer.HandleWriteAccessForComplexAttribute(setAnVal_setMag, delegate (IEC61850.Server.DataAttribute dataAttr, MmsValue value, ClientConnection con, object parameter) {
receivedValue = value;
handlerCalled++;
return MmsDataAccessError.SUCCESS;
}, null);
iedServer.Start(10002);
IedConnection connection = new IedConnection();
connection.Connect("localhost", 10002);
MmsValue complexValue = MmsValue.NewEmptyStructure(1);
complexValue.SetElement(0, new MmsValue((float)1.0));
connection.WriteValue("simpleIOGenericIO/LLN0.SetAnVal.setMag", FunctionalConstraint.SP, complexValue);
Assert.NotNull(receivedValue);
Assert.AreEqual(MmsType.MMS_STRUCTURE, receivedValue.GetType());
Assert.AreEqual(1.0, receivedValue.GetElement(0).ToFloat());
receivedValue.Dispose();
receivedValue = null;
connection.WriteValue("simpleIOGenericIO/LLN0.SetAnVal.setMag.f", FunctionalConstraint.SP, new MmsValue((float)2.0));
Assert.NotNull(receivedValue);
Assert.AreEqual(MmsType.MMS_FLOAT, receivedValue.GetType());
Assert.AreEqual(2.0, receivedValue.ToFloat());
connection.Abort();
iedServer.Stop();
iedServer.Dispose();
}
[Test()]
public void WriteAccessPolicy()
{
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile ("../../model.cfg");
IEC61850.Server.DataAttribute opDlTmms = (IEC61850.Server.DataAttribute) iedModel.GetModelNodeByShortObjectReference("GenericIO/PDUP1.OpDlTmms.setVal");
@ -486,8 +344,6 @@ namespace tests
connection.Connect ("localhost", 10002);
iedServer.SetWriteAccessPolicy(FunctionalConstraint.SP, AccessPolicy.ACCESS_POLICY_ALLOW);
connection.WriteValue ("simpleIOGenericIO/PDUP1.RsDlTmms.setVal", FunctionalConstraint.SP, new MmsValue ((int)1234));
iedServer.SetWriteAccessPolicy (FunctionalConstraint.SP, AccessPolicy.ACCESS_POLICY_DENY);
@ -509,7 +365,7 @@ namespace tests
iedServer.Stop ();
iedServer.Dispose();
iedServer.Destroy ();
}
[Test()]
@ -525,17 +381,7 @@ namespace tests
IedServer iedServer = new IedServer (iedModel);
iedServer.SetControlHandler (spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test) {
byte [] orIdent = action.GetOrIdent ();
string orIdentStr = System.Text.Encoding.UTF8.GetString (orIdent, 0, orIdent.Length);
Assert.AreEqual ("TEST1234", orIdentStr);
Assert.AreEqual (OrCat.MAINTENANCE, action.GetOrCat ());
Assert.AreSame (spcso1, action.GetControlObject ());
iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) {
handlerCalled++;
return ControlHandlerResult.OK;
}, null);
@ -547,7 +393,6 @@ namespace tests
connection.Connect ("localhost", 10002);
ControlObject controlClient = connection.CreateControlObject ("simpleIOGenericIO/GGIO1.SPCSO1");
controlClient.SetOrigin ("TEST1234", OrCat.MAINTENANCE);
Assert.IsNotNull (controlClient);
@ -559,7 +404,7 @@ namespace tests
iedServer.Stop ();
iedServer.Dispose();
iedServer.Destroy ();
}
@ -608,8 +453,6 @@ namespace tests
Assert.AreEqual ("127.0.0.1:", ipAddress.Substring (0, 10));
iedServer.Stop ();
iedServer.Dispose();
}
[Test()]
@ -638,45 +481,6 @@ namespace tests
Assert.AreEqual (Validity.QUESTIONABLE, q.Validity);
}
[Test()]
public void MmsValueCreateStructureAndAddElement()
{
MmsValue structure1 = MmsValue.NewEmptyStructure(1);
MmsValue structure2 = MmsValue.NewEmptyStructure(1);
MmsValue element = MmsValue.NewEmptyStructure(1);
structure1.SetElement(0, element);
/* Clone is required when adding the value to another structure or element */
MmsValue elementClone = element.Clone();
structure2.SetElement(0, elementClone);
element.Dispose();
structure1.Dispose();
structure2.Dispose();
Assert.AreEqual(true, true);
}
[Test()]
public void MmsValueClone()
{
MmsValue boolValue = new MmsValue(true);
MmsValue boolClone = boolValue.Clone();
boolValue.Dispose();
boolClone.Dispose();
MmsValue structure = MmsValue.NewEmptyStructure(1);
MmsValue structureClone = structure.Clone();
structure.Dispose();
structureClone.Dispose();
}
}
}

@ -1,446 +0,0 @@
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);
}
DO(SetInt1 0){
DA(setVal 0 3 2 1 0);
}
DO(SetInt2 0){
DA(setVal 0 3 2 1 0);
}
DO(SetInt3 0){
DA(setVal 0 3 2 1 0);
}
DO(SetInt4 0){
DA(setVal 0 3 2 1 0);
}
DO(SetBool1 0){
DA(setVal 0 0 2 1 0);
}
DO(SetBool2 0){
DA(setVal 0 0 2 1 0);
}
DO(SetBool3 0){
DA(setVal 0 0 2 1 0);
}
DO(SetBool4 0){
DA(setVal 0 0 2 1 0);
}
DO(Int64 0){
DA(stVal 0 4 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(SetAnVal 0){
DA(setMag 0 27 2 1 0){
DA(f 0 10 2 1 0);
}
}
DS(Events){
DE(GGIO1$ST$SPCSO1$stVal);
DE(GGIO1$ST$SPCSO2$stVal);
DE(GGIO1$ST$SPCSO3$stVal);
DE(GGIO1$ST$SPCSO4$stVal);
}
DS(EventsFCDO){
DE(GGIO1$ST$SPCSO1);
DE(GGIO1$ST$SPCSO2);
DE(GGIO1$ST$SPCSO3);
DE(GGIO1$ST$SPCSO4);
}
DS(Booleans){
DE(LLN0$SP$SetBool1$setVal);
DE(LLN0$SP$SetBool2$setVal);
DE(LLN0$SP$SetBool3$setVal);
DE(LLN0$SP$SetBool4$setVal);
}
DS(Integers){
DE(LLN01$SP$SetInt1$setVal);
DE(LLN01$SP$SetInt2$setVal);
DE(LLN01$SP$SetInt3$setVal);
DE(LLN01$SP$SetInt4$setVal);
}
RC(EventsRCB01 Events1 0 Events 1 24 239 50 1000);
RC(EventsRCB02 Events1 0 Events 1 24 239 50 1000);
RC(BufferedRCB01 Events1 1 Events 1 24 239 50 1000);
RC(BufferedRCB02 Events1 1 Events 1 24 239 50 1000);
GC(gcbEvents events Events 1 0 1000 3000 ){
PA(4 1 4096 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);
DA(dU 0 21 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 0){
DA(f 0 10 1 1 0);
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
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(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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=1;
}
DO(SPCSO2 0){
DA(SBO 0 17 12 0 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(Cancel 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=2;
DA(sboClass 0 12 4 0 0);
}
DO(SPCSO3 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(Cancel 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=3;
}
DO(SPCSO4 0){
DA(SBOw 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(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(Cancel 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=4;
}
DO(SPCSO5 0){
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=1;
DA(Cancel 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);
}
}
DO(SPCSO6 0){
DA(SBO 0 17 12 0 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Cancel 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=2;
}
DO(SPCSO7 0){
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Cancel 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=3;
}
DO(SPCSO8 0){
DA(SBOw 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(Cancel 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(operTm 0 22 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(origin 0 27 0 0 0){
DA(orCat 0 12 0 0 0);
DA(orIdent 0 13 0 0 0);
}
DA(ctlNum 0 6 0 0 0);
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=4;
}
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);
}
DO(SchdAbsTm 0){
DA(val 24 10 2 1 0);
}
}
LN(MHAI1){
DO(HA 0){
DO(phsAHar 16){
DA(cVal 0 27 1 5 0){
DA(mag 0 27 1 5 0){
DA(f 0 10 1 5 0);
}
DA(ang 0 27 1 5 0){
DA(f 0 10 1 5 0);
}
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
DA(numHar 0 7 4 1 0)=16;
DA(numCyc 0 7 4 1 0);
DA(evalTm 0 7 4 1 0);
DA(frequency 0 10 4 1 0);
}
}
}
}

@ -46,7 +46,7 @@ namespace tls_server_example
IedServer iedServer = new IedServer (iedModel, tlsConfig);
iedServer.SetControlHandler (spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test) {
iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) {
bool val = ctlVal.GetBoolean();
if (val)

@ -11,25 +11,18 @@ add_subdirectory(server_example_61400_25)
add_subdirectory(server_example_setting_groups)
add_subdirectory(server_example_logging)
add_subdirectory(server_example_files)
add_subdirectory(server_example_substitution)
add_subdirectory(server_example_service_tracking)
add_subdirectory(server_example_deadband)
add_subdirectory(iec61850_client_example1)
add_subdirectory(iec61850_client_example2)
add_subdirectory(iec61850_client_example_control)
add_subdirectory(iec61850_client_example3)
add_subdirectory(iec61850_client_example4)
add_subdirectory(iec61850_client_example5)
add_subdirectory(iec61850_client_example_reporting)
add_subdirectory(iec61850_client_example_log)
add_subdirectory(iec61850_client_example_array)
add_subdirectory(iec61850_client_example_files)
add_subdirectory(iec61850_client_example_async)
add_subdirectory(iec61850_client_file_async)
if (NOT WIN32)
add_subdirectory(mms_utility)
endif(NOT WIN32)
if(NOT WIN32)
add_subdirectory(iec61850_client_example_files)
endif()
if(WIN32)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib")
@ -47,7 +40,6 @@ endif(WITH_MBEDTLS)
if(${BUILD_SV_GOOSE_EXAMPLES})
add_subdirectory(server_example_goose)
add_subdirectory(goose_observer)
add_subdirectory(goose_subscriber)
add_subdirectory(goose_publisher)
add_subdirectory(sv_subscriber)

@ -1,11 +1,11 @@
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 += iec61850_client_example_array
EXAMPLE_DIRS += iec61850_client_example_control
EXAMPLE_DIRS += iec61850_client_example_log
EXAMPLE_DIRS += server_example_simple
EXAMPLE_DIRS += server_example_basic_io
EXAMPLE_DIRS += server_example_password_auth
@ -18,9 +18,8 @@ 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 += server_example_logging
EXAMPLE_DIRS += server_example_files
EXAMPLE_DIRS += server_example_substitution
EXAMPLE_DIRS += server_example_deadband
EXAMPLE_DIRS += goose_subscriber
EXAMPLE_DIRS += goose_publisher
EXAMPLE_DIRS += sv_subscriber

@ -1,21 +0,0 @@
set(goose_observer_SRCS
goose_observer.c
)
IF(MSVC)
set_source_files_properties(${goose_observer_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(goose_observer
${goose_observer_SRCS}
)
target_link_libraries(goose_observer
iec61850
)

@ -1,101 +0,0 @@
/*
* goose_observer.c
*
* This is an example for generic GOOSE observer
*
* Has to be started as root in Linux.
*/
#include "goose_receiver.h"
#include "goose_subscriber.h"
#include "hal_thread.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static int running = 1;
void sigint_handler(int signalId)
{
running = 0;
}
void
gooseListener(GooseSubscriber subscriber, void* parameter)
{
printf("GOOSE event:\n");
printf(" vlanTag: %s\n", GooseSubscriber_isVlanSet(subscriber) ? "found" : "NOT found");
if (GooseSubscriber_isVlanSet(subscriber))
{
printf(" vlanId: %u\n", GooseSubscriber_getVlanId(subscriber));
printf(" vlanPrio: %u\n", GooseSubscriber_getVlanPrio(subscriber));
}
printf(" appId: %d\n", GooseSubscriber_getAppId(subscriber));
uint8_t macBuf[6];
GooseSubscriber_getSrcMac(subscriber,macBuf);
printf(" srcMac: %02X:%02X:%02X:%02X:%02X:%02X\n", macBuf[0],macBuf[1],macBuf[2],macBuf[3],macBuf[4],macBuf[5]);
GooseSubscriber_getDstMac(subscriber,macBuf);
printf(" dstMac: %02X:%02X:%02X:%02X:%02X:%02X\n", macBuf[0],macBuf[1],macBuf[2],macBuf[3],macBuf[4],macBuf[5]);
printf(" goId: %s\n", GooseSubscriber_getGoId(subscriber));
printf(" goCbRef: %s\n", GooseSubscriber_getGoCbRef(subscriber));
printf(" dataSet: %s\n", GooseSubscriber_getDataSet(subscriber));
printf(" confRev: %u\n", GooseSubscriber_getConfRev(subscriber));
printf(" ndsCom: %s\n", GooseSubscriber_needsCommission(subscriber) ? "true" : "false");
printf(" simul: %s\n", GooseSubscriber_isTest(subscriber) ? "true" : "false");
printf(" stNum: %u sqNum: %u\n", GooseSubscriber_getStNum(subscriber),
GooseSubscriber_getSqNum(subscriber));
printf(" timeToLive: %u\n", GooseSubscriber_getTimeAllowedToLive(subscriber));
uint64_t timestamp = GooseSubscriber_getTimestamp(subscriber);
printf(" timestamp: %u.%u\n", (uint32_t) (timestamp / 1000), (uint32_t) (timestamp % 1000));
printf(" message is %s\n", GooseSubscriber_isValid(subscriber) ? "valid" : "INVALID");
MmsValue* values = GooseSubscriber_getDataSetValues(subscriber);
char buffer[1024];
MmsValue_printToBuffer(values, buffer, 1024);
printf(" AllData: %s\n", buffer);
}
int
main(int argc, char** argv)
{
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("", NULL);
GooseSubscriber_setObserver(subscriber);
GooseSubscriber_setListener(subscriber, gooseListener, NULL);
GooseReceiver_addSubscriber(receiver, subscriber);
GooseReceiver_start(receiver);
if (GooseReceiver_isRunning(receiver)) {
signal(SIGINT, sigint_handler);
while (running) {
Thread_sleep(100);
}
}
else {
printf("Failed to start GOOSE subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n");
}
GooseReceiver_stop(receiver);
GooseReceiver_destroy(receiver);
return 0;
}

@ -3,11 +3,19 @@ set(goose_publisher_example_SRCS
goose_publisher_example.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${goose_publisher_example_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(goose_publisher_example
${goose_publisher_example_SRCS}
)
target_link_libraries(goose_publisher_example
iec61850
)
ELSE(WIN32)
add_executable(goose_publisher_example
${goose_publisher_example_SRCS}
@ -17,4 +25,6 @@ target_link_libraries(goose_publisher_example
iec61850
)
ENDIF(WIN32)

@ -12,11 +12,11 @@
#include "goose_publisher.h"
#include "hal_thread.h"
/* has to be executed as root! */
// has to be executed as root!
int
main(int argc, char **argv)
main(int argc, char** argv)
{
char *interface;
char* interface;
if (argc > 1)
interface = argv[1];
@ -51,38 +51,21 @@ main(int argc, char **argv)
*/
GoosePublisher publisher = GoosePublisher_create(&gooseCommParameters, interface);
if (publisher) {
GoosePublisher_setGoCbRef(publisher, "simpleIOGenericIO/LLN0$GO$gcbAnalogValues");
GoosePublisher_setConfRev(publisher, 1);
GoosePublisher_setDataSetRef(publisher, "simpleIOGenericIO/LLN0$AnalogValues");
GoosePublisher_setTimeAllowedToLive(publisher, 500);
int i = 0;
for (i = 0; i < 4; i++) {
for (i = 0; i < 3; i++) {
Thread_sleep(1000);
if (i == 3) {
/* now change dataset to send an invalid GOOSE message */
LinkedList_add(dataSetValues, MmsValue_newBoolean(true));
GoosePublisher_publish(publisher, dataSetValues);
}
else {
if (GoosePublisher_publish(publisher, dataSetValues) == -1) {
printf("Error sending message!\n");
}
}
}
GoosePublisher_destroy(publisher);
}
else {
printf("Failed to create GOOSE publisher. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n");
}
LinkedList_destroyDeep(dataSetValues, (LinkedListValueDeleteFunction) MmsValue_delete);
return 0;
}

@ -3,11 +3,19 @@ set(goose_subscriber_example_SRCS
goose_subscriber_example.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${goose_subscriber_example_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(goose_subscriber_example
${goose_subscriber_example_SRCS}
)
target_link_libraries(goose_subscriber_example
iec61850
)
ELSE(WIN32)
add_executable(goose_subscriber_example
${goose_subscriber_example_SRCS}
@ -17,4 +25,6 @@ target_link_libraries(goose_subscriber_example
iec61850
)
ENDIF(WIN32)

@ -9,7 +9,6 @@
#include "goose_receiver.h"
#include "goose_subscriber.h"
#include "hal_thread.h"
#include "linked_list.h"
#include <stdlib.h>
#include <stdio.h>
@ -17,13 +16,12 @@
static int running = 1;
static void
sigint_handler(int signalId)
void sigint_handler(int signalId)
{
running = 0;
}
static void
void
gooseListener(GooseSubscriber subscriber, void* parameter)
{
printf("GOOSE event:\n");
@ -34,7 +32,6 @@ gooseListener(GooseSubscriber subscriber, void* parameter)
uint64_t timestamp = GooseSubscriber_getTimestamp(subscriber);
printf(" timestamp: %u.%u\n", (uint32_t) (timestamp / 1000), (uint32_t) (timestamp % 1000));
printf(" message is %s\n", GooseSubscriber_isValid(subscriber) ? "valid" : "INVALID");
MmsValue* values = GooseSubscriber_getDataSetValues(subscriber);
@ -42,7 +39,7 @@ gooseListener(GooseSubscriber subscriber, void* parameter)
MmsValue_printToBuffer(values, buffer, 1024);
printf(" allData: %s\n", buffer);
printf("%s\n", buffer);
}
int
@ -61,8 +58,6 @@ main(int argc, char** argv)
GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL);
uint8_t dstMac[6] = {0x01,0x0c,0xcd,0x01,0x00,0x01};
GooseSubscriber_setDstMac(subscriber, dstMac);
GooseSubscriber_setAppId(subscriber, 1000);
GooseSubscriber_setListener(subscriber, gooseListener, NULL);
@ -71,20 +66,13 @@ main(int argc, char** argv)
GooseReceiver_start(receiver);
if (GooseReceiver_isRunning(receiver)) {
signal(SIGINT, sigint_handler);
while (running) {
Thread_sleep(100);
}
}
else {
printf("Failed to start GOOSE subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n");
}
GooseReceiver_stop(receiver);
GooseReceiver_destroy(receiver);
return 0;
}

@ -7,10 +7,10 @@ set(sv_9_2_LE_example_SRCS
static_model.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${sv_9_2_LE_example_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
ENDIF(WIN32)
add_executable(sv_9_2_LE_example
${sv_9_2_LE_example_SRCS}

@ -9,8 +9,6 @@ PROJECT_ICD_FILE = sv.icd
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
LDFLAGS += -lm
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk

@ -28,12 +28,13 @@
#include <stdlib.h>
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
/* 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;
static int svcbEnabled = 1;
@ -47,21 +48,11 @@ static int amp2;
static int amp3;
static int amp4;
static int amp1q;
static int amp2q;
static int amp3q;
static int amp4q;
static int vol1;
static int vol2;
static int vol3;
static int vol4;
static int vol1q;
static int vol2q;
static int vol3q;
static int vol4q;
static SVPublisher svPublisher;
static SVPublisher_ASDU asdu;
@ -70,33 +61,19 @@ setupSVPublisher(const char* svInterface)
{
svPublisher = SVPublisher_create(NULL, svInterface);
if (svPublisher) {
asdu = SVPublisher_addASDU(svPublisher, "xxxxMUnn01", NULL, 1);
amp1 = SVPublisher_ASDU_addINT32(asdu);
amp1q = SVPublisher_ASDU_addQuality(asdu);
amp2 = SVPublisher_ASDU_addINT32(asdu);
amp2q = SVPublisher_ASDU_addQuality(asdu);
amp3 = SVPublisher_ASDU_addINT32(asdu);
amp3q = SVPublisher_ASDU_addQuality(asdu);
amp4 = SVPublisher_ASDU_addINT32(asdu);
amp4q = SVPublisher_ASDU_addQuality(asdu);
vol1 = SVPublisher_ASDU_addINT32(asdu);
vol1q = SVPublisher_ASDU_addQuality(asdu);
vol2 = SVPublisher_ASDU_addINT32(asdu);
vol2q = SVPublisher_ASDU_addQuality(asdu);
vol3 = SVPublisher_ASDU_addINT32(asdu);
vol3q = SVPublisher_ASDU_addQuality(asdu);
vol4 = SVPublisher_ASDU_addINT32(asdu);
vol4q = SVPublisher_ASDU_addQuality(asdu);
SVPublisher_ASDU_setSmpCntWrap(asdu, 4000);
SVPublisher_ASDU_setRefrTm(asdu, 0);
SVPublisher_setupComplete(svPublisher);
}
}
static void sVCBEventHandler (SVControlBlock* svcb, int event, void* parameter)
@ -134,7 +111,8 @@ main(int argc, char** argv)
setupSVPublisher(svInterface);
if (svPublisher) {
int voltage = 1;
int current = 1;
SVControlBlock* svcb = IedModel_getSVControlBlock(&iedModel, IEDMODEL_MUnn_LLN0, "MSVCB01");
@ -145,110 +123,45 @@ main(int argc, char** argv)
IedServer_setSVCBHandler(iedServer, svcb, sVCBEventHandler, NULL);
Quality q = QUALITY_VALIDITY_GOOD;
int vol = (int) (6350.f * sqrt(2));
int amp = 0;
float phaseAngle = 0.f;
int voltageA;
int voltageB;
int voltageC;
int voltageN;
int currentA;
int currentB;
int currentC;
int currentN;
int sampleCount = 0;
uint64_t nextCycleStart = Hal_getTimeInMs() + 1000;
while (running) {
/* update measurement values */
int samplePoint = sampleCount % 80;
double angleA = (2 * M_PI / 80) * samplePoint;
double angleB = (2 * M_PI / 80) * samplePoint - ( 2 * M_PI / 3);
double angleC = (2 * M_PI / 80) * samplePoint - ( 4 * M_PI / 3);
voltageA = (vol * sin(angleA)) * 100;
voltageB = (vol * sin(angleB)) * 100;
voltageC = (vol * sin(angleC)) * 100;
voltageN = voltageA + voltageB + voltageC;
currentA = (amp * sin(angleA - phaseAngle)) * 1000;
currentB = (amp * sin(angleB - phaseAngle)) * 1000;
currentC = (amp * sin(angleC - phaseAngle)) * 1000;
currentN = currentA + currentB + currentC;
uint64_t timeval = Hal_getTimeInMs();
IedServer_lockDataModel(iedServer);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR1_Amp_instMag_i, currentA);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR1_Amp_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR2_Amp_instMag_i, currentB);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR2_Amp_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR3_Amp_instMag_i, currentC);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR3_Amp_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR4_Amp_instMag_i, currentN);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR4_Amp_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR1_Vol_instMag_i, voltageA);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR1_Vol_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR2_Vol_instMag_i, voltageB);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR2_Vol_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR3_Vol_instMag_i, voltageC);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR3_Vol_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR4_Vol_instMag_i, voltageN);
IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR4_Vol_q, q);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR1_Amp_instMag_i, current);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR2_Amp_instMag_i, current);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR3_Amp_instMag_i, current);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR3_Amp_instMag_i, current);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR1_Vol_instMag_i, voltage);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR2_Vol_instMag_i, voltage);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR3_Vol_instMag_i, voltage);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR4_Vol_instMag_i, voltage);
IedServer_unlockDataModel(iedServer);
if (svcbEnabled) {
SVPublisher_ASDU_setINT32(asdu, amp1, currentA);
SVPublisher_ASDU_setQuality(asdu, amp1q, q);
SVPublisher_ASDU_setINT32(asdu, amp2, currentB);
SVPublisher_ASDU_setQuality(asdu, amp2q, q);
SVPublisher_ASDU_setINT32(asdu, amp3, currentC);
SVPublisher_ASDU_setQuality(asdu, amp3q, q);
SVPublisher_ASDU_setINT32(asdu, amp4, currentN);
SVPublisher_ASDU_setQuality(asdu, amp4q, q);
SVPublisher_ASDU_setINT32(asdu, amp1, current);
SVPublisher_ASDU_setINT32(asdu, amp2, current);
SVPublisher_ASDU_setINT32(asdu, amp3, current);
SVPublisher_ASDU_setINT32(asdu, amp4, current);
SVPublisher_ASDU_setINT32(asdu, vol1, voltageA);
SVPublisher_ASDU_setQuality(asdu, vol1q, q);
SVPublisher_ASDU_setINT32(asdu, vol2, voltageB);
SVPublisher_ASDU_setQuality(asdu, vol2q, q);
SVPublisher_ASDU_setINT32(asdu, vol3, voltageC);
SVPublisher_ASDU_setQuality(asdu, vol3q, q);
SVPublisher_ASDU_setINT32(asdu, vol4, voltageN);
SVPublisher_ASDU_setQuality(asdu, vol4q, q);
SVPublisher_ASDU_setINT32(asdu, vol1, voltage);
SVPublisher_ASDU_setINT32(asdu, vol2, voltage);
SVPublisher_ASDU_setINT32(asdu, vol3, voltage);
SVPublisher_ASDU_setINT32(asdu, vol4, voltage);
SVPublisher_ASDU_setRefrTmNs(asdu, Hal_getTimeInNs());
SVPublisher_ASDU_setSmpCnt(asdu, (uint16_t) sampleCount);
SVPublisher_ASDU_increaseSmpCnt(asdu);
SVPublisher_publish(svPublisher);
}
sampleCount = ((sampleCount + 1) % 4000);
if ((sampleCount % 400) == 0) {
uint64_t timeval = Hal_getTimeInMs();
while (timeval < nextCycleStart + 100) {
Thread_sleep(1);
timeval = Hal_getTimeInMs();
}
voltage++;
current++;
nextCycleStart = nextCycleStart + 100;
}
}
}
else {
printf("Cannot start SV publisher!\n");
Thread_sleep(500);
}
/* stop MMS server - close TCP server socket and all client sockets */

@ -22,7 +22,7 @@ extern DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda7;
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda0 = {
"MUnn",
false,
"TCTR1$MX$Amp",
"TCTR1$MX$Amp$instMag$i",
-1,
NULL,
NULL,
@ -32,7 +32,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda0 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda1 = {
"MUnn",
false,
"TCTR2$MX$Amp",
"TCTR2$MX$Amp$instMag$i",
-1,
NULL,
NULL,
@ -42,7 +42,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda1 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda2 = {
"MUnn",
false,
"TCTR3$MX$Amp",
"TCTR3$MX$Amp$instMag$i",
-1,
NULL,
NULL,
@ -52,7 +52,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda2 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda3 = {
"MUnn",
false,
"TCTR4$MX$Amp",
"TCTR4$MX$Amp$instMag$i",
-1,
NULL,
NULL,
@ -62,7 +62,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda3 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda4 = {
"MUnn",
false,
"TVTR1$MX$Vol",
"TVTR1$MX$Vol$instMag$i",
-1,
NULL,
NULL,
@ -72,7 +72,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda4 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda5 = {
"MUnn",
false,
"TVTR2$MX$Vol",
"TVTR2$MX$Vol$instMag$i",
-1,
NULL,
NULL,
@ -82,7 +82,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda5 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda6 = {
"MUnn",
false,
"TVTR3$MX$Vol",
"TVTR3$MX$Vol$instMag$i",
-1,
NULL,
NULL,
@ -92,7 +92,7 @@ DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda6 = {
DataSetEntry iedModelds_MUnn_LLN0_PhsMeas1_fcda7 = {
"MUnn",
false,
"TVTR4$MX$Vol",
"TVTR4$MX$Vol$instMag$i",
-1,
NULL,
NULL,

@ -74,26 +74,26 @@ SCL.xsd">
<DataSet name="PhsMeas1">
<FCDA ldInst="MUnn" lnClass="TCTR" lnInst="1" fc="MX"
doName="Amp" />
doName="Amp" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TCTR" lnInst="2" fc="MX"
doName="Amp" />
doName="Amp" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TCTR" lnInst="3" fc="MX"
doName="Amp" />
doName="Amp" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TCTR" lnInst="4" fc="MX"
doName="Amp" />
doName="Amp" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TVTR" lnInst="1" fc="MX"
doName="Vol" />
doName="Vol" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TVTR" lnInst="2" fc="MX"
doName="Vol" />
doName="Vol" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TVTR" lnInst="3" fc="MX"
doName="Vol" />
doName="Vol" daName="instMag.i"/>
<FCDA ldInst="MUnn" lnClass="TVTR" lnInst="4" fc="MX"
doName="Vol" />
doName="Vol" daName="instMag.i"/>
</DataSet>
<SampledValueControl name="MSVCB01" datSet="PhsMeas1"
smvID="xxxxMUnn01" smpRate="80" nofASDU="1" confRev="1" smpMod="SmpPerPeriod">
smvID="xxxxMUnn01" smpRate="80" nofASDU="1" confRev="1">
<SmvOpts refreshTime="false" sampleSynchronized="true"
security="false" dataRef="false" />

@ -3,10 +3,10 @@ set(iec61850_client_example1_SRCS
client_example1.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${iec61850_client_example1_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
ENDIF(WIN32)
add_executable(iec61850_client_example1
${iec61850_client_example1_SRCS}

@ -33,9 +33,6 @@ int main(int argc, char** argv) {
char* hostname;
int tcpPort = 102;
const char* localIp = NULL;
int localTcpPort = -1;
if (argc > 1)
hostname = argv[1];
@ -45,42 +42,20 @@ int main(int argc, char** argv) {
if (argc > 2)
tcpPort = atoi(argv[2]);
if (argc > 3)
localIp = argv[3];
if (argc > 4)
localTcpPort = atoi(argv[4]);
IedClientError error;
IedConnection con = IedConnection_create();
/* Optional bind to local IP address/interface */
if (localIp) {
IedConnection_setLocalAddress(con, localIp, localTcpPort);
printf("Bound to Local Address: %s:%i\n", localIp, localTcpPort);
}
IedConnection_connect(con, &error, hostname, tcpPort);
printf("Connecting to %s:%i\n", hostname, tcpPort);
if (error == IED_ERROR_OK)
{
printf("Connected\n");
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)
{
if (MmsValue_getType(value) == MMS_FLOAT) {
if (value != NULL) {
float fval = MmsValue_toFloat(value);
printf("read float value: %f\n", fval);
}
else if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) {
printf("Failed to read value (error code: %i)\n", MmsValue_getDataAccessError(value));
}
MmsValue_delete(value);
}
@ -89,23 +64,22 @@ int main(int argc, char** argv) {
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! (error code: %i)\n", error);
printf("failed to write simpleIOGenericIO/GGIO1.NamPlt.vendor!\n");
MmsValue_delete(value);
/* read data set */
ClientDataSet clientDataSet = IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.Events", NULL);
if (clientDataSet == NULL) {
if (clientDataSet == NULL)
printf("failed to read dataset\n");
goto close_connection;
}
/* Read RCB values */
ClientReportControlBlock rcb =
IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL);
if (rcb) {
bool rptEna = ClientReportControlBlock_getRptEna(rcb);
printf("RptEna = %i\n", rptEna);
@ -144,9 +118,8 @@ int main(int argc, char** argv) {
ClientDataSet_destroy(clientDataSet);
ClientReportControlBlock_destroy(rcb);
}
close_connection:
close_connection:
IedConnection_close(con);
}
@ -155,6 +128,6 @@ close_connection:
}
IedConnection_destroy(con);
return 0;
}

@ -3,10 +3,10 @@ set(iec61850_client_example2_SRCS
client_example2.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${iec61850_client_example2_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
ENDIF(WIN32)
add_executable(iec61850_client_example2
${iec61850_client_example2_SRCS}

@ -38,7 +38,7 @@ printDataDirectory(char* doRef, IedConnection con, int spaces)
dataAttribute = LinkedList_getNext(dataAttribute);
char daRef[130];
char daRef[129];
sprintf(daRef, "%s.%s", doRef, daName);
printDataDirectory(daRef, con, spaces + 2);
}
@ -124,7 +124,7 @@ main(int argc, char** argv)
while (dataSet != NULL) {
char* dataSetName = (char*) dataSet->data;
bool isDeletable;
char dataSetRef[130];
char dataSetRef[129];
sprintf(dataSetRef, "%s.%s", lnRef, dataSetName);
LinkedList dataSetMembers = IedConnection_getDataSetDirectory(con, &error, dataSetRef,
@ -201,6 +201,5 @@ main(int argc, char** argv)
cleanup_and_exit:
IedConnection_destroy(con);
return 0;
}

@ -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
)

@ -1,7 +1,7 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = goose_observer
PROJECT_SOURCES = goose_observer.c
PROJECT_BINARY_NAME = client_example3
PROJECT_SOURCES = client_example3.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk

@ -0,0 +1,219 @@
/*
* 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 <stdlib.h>
#include <stdio.h>
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);
ControlObjectClient_setOrigin(control, NULL, 3);
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);
}

@ -67,28 +67,18 @@ int main(int argc, char** argv) {
LinkedList_destroyStatic(newDataSetEntries);
printf("error: %i\n", error);
if (error == IED_ERROR_OK ) {
/* read new data set */
/* read data set */
ClientDataSet clientDataSet;
clientDataSet = IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.AnalogueValues", NULL);
if (error == IED_ERROR_OK) {
printDataSetValues(ClientDataSet_getValues(clientDataSet));
ClientDataSet_destroy(clientDataSet);
}
else {
printf("Failed to read data set (error code: %d)\n", error);
}
Thread_sleep(1000);
IedConnection_deleteDataSet(con, &error, "simpleIOGenericIO/LLN0.AnalogueValues");
}
else {
printf("Failed to create data set (error code: %d)\n", error);
}
IedConnection_close(con);
}
@ -97,7 +87,6 @@ int main(int argc, char** argv) {
}
IedConnection_destroy(con);
return 0;
}

@ -3,10 +3,10 @@ set(iec61850_client_example5_SRCS
client_example5.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${iec61850_client_example5_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
ENDIF(WIN32)
add_executable(iec61850_client_example5
${iec61850_client_example5_SRCS}

@ -50,15 +50,12 @@ main(int argc, char** argv)
TSelector localTSelector = { 3, { 0x00, 0x01, 0x02 } };
TSelector remoteTSelector = { 2, { 0x00, 0x01 } };
SSelector remoteSSelector = { 2, { 0, 1 } };
SSelector localSSelector = { 5, { 0, 1, 2, 3, 4 } };
PSelector localPSelector = {4, { 0x12, 0x34, 0x56, 0x78 } };
PSelector remotePSelector = {4, { 0x87, 0x65, 0x43, 0x21 } };
SSelector sSelector1 = { 2, { 0, 1 } };
SSelector sSelector2 = { 5, { 0, 1, 2, 3, 4 } };
/* change parameters for presentation, session and transport layers */
IsoConnectionParameters_setRemoteAddresses(parameters, remotePSelector, remoteSSelector, localTSelector);
IsoConnectionParameters_setLocalAddresses(parameters, localPSelector, localSSelector, remoteTSelector);
IsoConnectionParameters_setRemoteAddresses(parameters, 0x12345678, sSelector1, localTSelector);
IsoConnectionParameters_setLocalAddresses(parameters, 0x87654321, sSelector2, remoteTSelector);
char* password = "top secret";
@ -87,7 +84,6 @@ main(int argc, char** argv)
IedConnection_destroy(con);
AcseAuthenticationParameter_destroy(auth);
return 0;
}

@ -1,17 +0,0 @@
set(iec61850_client_example_array_SRCS
client_example_array.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_array_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_array
${iec61850_client_example_array_SRCS}
)
target_link_libraries(iec61850_client_example_array
iec61850
)

@ -1,17 +0,0 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_array
PROJECT_SOURCES = client_example_array.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)

@ -1,100 +0,0 @@
/*
* client_example_array.c
*
* SHows how to handle array access from client side
*
* This example is intended to be used with server_example_complex_array
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#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();
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
/* read complete array */
MmsValue* array = IedConnection_readObject(con, &error, "testComplexArray/MHAI1.HA.phsAHar", IEC61850_FC_MX);
if (array != NULL) {
MmsValue_delete(array);
}
else
printf("Failed to read array!\n");
/* read array element at different component levels */
char* arrayElementRef = "testComplexArray/MHAI1.HA.phsAHar(2).cVal.mag.f";
MmsValue* element = IedConnection_readObject(con, &error, arrayElementRef, IEC61850_FC_MX);
if (element != NULL) {
MmsValue_delete(element);
}
else
printf("Failed to read array element %s!\n", arrayElementRef);
arrayElementRef = "testComplexArray/MHAI1.HA.phsAHar(2).cVal.mag";
element = IedConnection_readObject(con, &error, arrayElementRef, IEC61850_FC_MX);
if (element != NULL) {
MmsValue_delete(element);
}
else
printf("Failed to read array element %s!\n", arrayElementRef);
arrayElementRef = "testComplexArray/MHAI1.HA.phsAHar(2).cVal";
element = IedConnection_readObject(con, &error, arrayElementRef, IEC61850_FC_MX);
if (element != NULL) {
MmsValue_delete(element);
}
else
printf("Failed to read array element %s!\n", arrayElementRef);
arrayElementRef = "testComplexArray/MHAI1.HA.phsAHar(2)";
element = IedConnection_readObject(con, &error, arrayElementRef, IEC61850_FC_MX);
if (element != NULL) {
MmsValue_delete(element);
}
else
printf("Failed to read array element %s!\n", arrayElementRef);
close_connection:
IedConnection_close(con);
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -1,17 +0,0 @@
set(iec61850_client_async_SRCS
client_example_async.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_async_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_async
${iec61850_client_async_SRCS}
)
target_link_libraries(iec61850_client_async
iec61850
)

@ -1,17 +0,0 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_async
PROJECT_SOURCES = client_example_async.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)

@ -1,322 +0,0 @@
/*
* client_example_async.c
*
* Shows how to use the asynchronous client API
*
* This example is intended to be used with server_example_basic_io.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static ClientDataSet clientDataSet = NULL;
static void
printValue(char* name, MmsValue* value)
{
char buf[1000];
MmsValue_printToBuffer(value, buf, 1000);
printf("%s: %s\n", name, buf);
}
static void
readObjectHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value)
{
if (err == IED_ERROR_OK) {
printValue((char*) parameter, value);
MmsValue_delete(value);
}
else {
printf("Failed to read object %s (err=%i)\n", (char*) parameter, err);
}
}
static void
readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet)
{
if (err == IED_ERROR_OK) {
clientDataSet = dataSet;
printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet));
MmsValue* values = ClientDataSet_getValues(dataSet);
if (MmsValue_getType(values) == MMS_ARRAY) {
int i;
for (i = 0; i < MmsValue_getArraySize(values); i++) {
printf(" [%i]", i);
printValue("", MmsValue_getElement(values, i));
}
}
}
else {
printf("Failed to read data set (err=%i)\n", err);
}
}
static void
writeDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList /* <MmsValue*> */accessResults)
{
if (err == IED_ERROR_OK) {
if (accessResults) {
int i = 0;
LinkedList element = LinkedList_getNext(accessResults);
while (element) {
MmsValue* accessResultValue = (MmsValue*) LinkedList_getData(element);
printf(" access-result[%i]", i);
printValue("", accessResultValue);
element = LinkedList_getNext(element);
i++;
}
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete);
}
}
else {
printf("Failed to write data set (err=%i)\n", err);
}
}
static 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 != IEC61850_REASON_NOT_INCLUDED) {
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
}
}
}
static void
getVarSpecHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsVariableSpecification* spec)
{
if (err == IED_ERROR_OK) {
printf("variable: %s has type %d\n", (char*) parameter, MmsVariableSpecification_getType(spec));
MmsVariableSpecification_destroy(spec);
}
else {
printf("Failed to get variable specification for object %s (err=%i)\n", (char*) parameter, err);
}
}
static void
getNameListHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList nameList, bool moreFollows)
{
if (err != IED_ERROR_OK) {
printf("Get name list error: %d\n", err);
}
else {
char* ldName = (char*) parameter;
LinkedList element = LinkedList_getNext(nameList);
while (element) {
char* variableName = (char*) LinkedList_getData(element);
printf(" %s/%s\n", ldName, variableName);
element = LinkedList_getNext(element);
}
LinkedList_destroy(nameList);
free(ldName);
}
}
static void
getServerDirectoryHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList nameList, bool moreFollows)
{
IedConnection con = (IedConnection) parameter;
if (err != IED_ERROR_OK) {
printf("Get server directory error: %d\n", err);
}
else {
LinkedList element = LinkedList_getNext(nameList);
/* Call logical device variables for each logical node */
while (element) {
char* ldName = (char*) LinkedList_getData(element);
IedClientError cerr;
printf("LD: %s variables:\n", ldName);
IedConnection_getLogicalDeviceVariablesAsync(con, &cerr, ldName, NULL, NULL, getNameListHandler, strdup(ldName));
printf("LD: %s data sets:\n", ldName);
IedConnection_getLogicalDeviceDataSetsAsync(con, &err, ldName, NULL, NULL, getNameListHandler, strdup(ldName));
element = LinkedList_getNext(element);
}
LinkedList_destroy(nameList);
}
}
static void
controlActionHandler(uint32_t invokeId, void* parameter, IedClientError err, ControlActionType type, bool success)
{
printf("control: ID: %d type: %i err: %d success: %i\n", invokeId, type, err, success);
}
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_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED) {
if (IedConnection_getState(con) == IED_STATE_CLOSED) {
success = false;
break;
}
Thread_sleep(10);
}
if (success) {
IedConnection_getServerDirectoryAsync(con, &error, NULL, NULL, getServerDirectoryHandler, con);
if (error != IED_ERROR_OK) {
printf("read server directory error %i\n", error);
}
Thread_sleep(1000);
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn1.mag.f");
if (error != IED_ERROR_OK) {
printf("read object error %i\n", error);
}
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn2.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn2.mag.f");
if (error != IED_ERROR_OK) {
printf("read object error %i\n", error);
}
IedConnection_getVariableSpecificationAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1", IEC61850_FC_MX, getVarSpecHandler, "simpleIOGenericIO/GGIO1.AnIn1");
if (error != IED_ERROR_OK) {
printf("get variable specification error %i\n", error);
}
IedConnection_readDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", NULL, readDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("read data set error %i\n", error);
}
LinkedList values = LinkedList_create();
LinkedList_add(values, MmsValue_newBoolean(true));
LinkedList_add(values, MmsValue_newBoolean(false));
LinkedList_add(values, MmsValue_newBoolean(true));
LinkedList_add(values, MmsValue_newBoolean(false));
IedConnection_writeDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", values, writeDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("write data set error %i\n", error);
}
LinkedList_destroyDeep(values, (LinkedListValueDeleteFunction) MmsValue_delete);
Thread_sleep(1000);
ControlObjectClient controlClient = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO1", con);
if (controlClient != NULL) {
ControlObjectClient_setOrigin(controlClient, "test1", CONTROL_ORCAT_AUTOMATIC_REMOTE);
MmsValue* ctlVal = MmsValue_newBoolean(true);
ControlObjectClient_operateAsync(controlClient, &error, ctlVal, 0, controlActionHandler, NULL);
if (error != IED_ERROR_OK) {
printf("Failed to send operate %i\n", error);
}
}
else {
printf("Failed to connect to control object\n");
}
}
Thread_sleep(1000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK) {
printf("Release returned error: %d\n", error);
}
else {
while (IedConnection_getState(con) != IED_STATE_CLOSED) {
Thread_sleep(10);
}
}
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
if (clientDataSet)
ClientDataSet_destroy(clientDataSet);
IedConnection_destroy(con);
return 0;
}

@ -1,17 +0,0 @@
set(iec61850_client_example_control_SRCS
client_example_control.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_control_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(client_example_control
${iec61850_client_example_control_SRCS}
)
target_link_libraries(client_example_control
iec61850
)

@ -1,17 +0,0 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_control
PROJECT_SOURCES = client_example_control.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)

@ -1,249 +0,0 @@
/*
* client_example_control.c
*
* How to control a device ... intended to be used with server_example_control
*/
#include "iec61850_client.h"
#include "hal_thread.h"
#include <stdlib.h>
#include <stdio.h>
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)
{
MmsValue* ctlVal = NULL;
MmsValue* stVal = NULL;
/************************
* Direct control
***********************/
ControlObjectClient control
= ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO1", con);
if (control)
{
ctlVal = MmsValue_newBoolean(true);
ControlObjectClient_setOrigin(control, NULL, 3);
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 */
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");
}
}
else {
printf("Control object simpleIOGenericIO/GGIO1.SPCSO1 not found in server\n");
}
/************************
* Select before operate
***********************/
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO2", con);
if (control)
{
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);
}
else {
printf("Control object simpleIOGenericIO/GGIO1.SPCSO2 not found in server\n");
}
/****************************************
* Direct control with enhanced security
****************************************/
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO3", con);
if (control)
{
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");
}
}
else {
printf("Control object simpleIOGenericIO/GGIO1.SPCSO3 not found in server\n");
}
/***********************************************
* Select before operate with enhanced security
***********************************************/
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO4", con);
if (control)
{
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);
}
else {
printf("Control object simpleIOGenericIO/GGIO1.SPCSO4 not found in server\n");
}
/*********************************************************************
* Direct control with enhanced security (expect CommandTermination-)
*********************************************************************/
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO9", con);
if (control)
{
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);
}
else {
printf("Control object simpleIOGenericIO/GGIO1.SPCSO9 not found in server\n");
}
IedConnection_close(con);
}
else {
printf("Connection failed!\n");
}
IedConnection_destroy(con);
return 0;
}

@ -8,78 +8,19 @@
*
* Note: intended to be used with server_example3 or server_example_files
*
* Note: DOES NOT WORK WITH VISUAL STUDIO because of libgen.h
*
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <libgen.h>
#endif
#ifdef _WIN32
static char _dirname[1000];
static char*
dirname(char* path)
{
char* lastSep = NULL;
int len = strlen(path);
int i = 0;
while (i < len) {
if (path[i] == '/' || path[i] == ':' || path[i] == '\\')
lastSep = path + i;
i++;
}
if (lastSep) {
strcpy(_dirname, path);
_dirname[lastSep - path] = 0;
}
else
strcpy(_dirname, "");
return _dirname;
}
static char _basename[1000];
static char*
basename(char* path)
{
char* lastSep = NULL;
int len = strlen(path);
int i = 0;
while (i < len) {
if (path[i] == '/' || path[i] == ':' || path[i] == '\\')
lastSep = path + i;
i++;
}
if (lastSep)
strcpy(_basename, lastSep + 1);
else
strcpy(_basename, path);
return _basename;
}
#endif
static char* hostname = "localhost";
static int tcpPort = 102;
static char* filename = NULL;
static bool singleRequest = false;
typedef enum {
FileOperationType_None = 0,
@ -101,14 +42,13 @@ downloadHandler(void* parameter, uint8_t* buffer, uint32_t bytesRead)
printf("received %i bytes\n", bytesRead);
if (bytesRead > 0) {
if (fwrite(buffer, bytesRead, 1, fp) != 1) {
if (fwrite(buffer, bytesRead, 1, fp) == 1)
return true;
else {
printf("Failed to write local file!\n");
return false;
}
}
return true;
}
static void
@ -118,10 +58,8 @@ printHelp()
printf(" Options:\n");
printf(" -h <hostname/IP>\n");
printf(" -p portnumber\n");
printf(" -s single request for show (sub) directory (ignore morefollows");
printf(" Operations\n");
printf(" dir - show directory\n");
printf(" subdir <dirname> - show sub directory\n");
printf(" info <filename> - show file info\n");
printf(" del <filename> - delete file\n");
printf(" get <filename> - get file\n");
@ -143,9 +81,6 @@ parseOptions(int argc, char** argv)
else if (strcmp(argv[currentArgc], "-p") == 0) {
tcpPort = atoi(argv[++currentArgc]);
}
else if (strcmp(argv[currentArgc], "-s") == 0) {
singleRequest = true;
}
else if (strcmp(argv[currentArgc], "del") == 0) {
operation = FileOperationType_Del;
filename = argv[++currentArgc];
@ -153,10 +88,6 @@ parseOptions(int argc, char** argv)
else if (strcmp(argv[currentArgc], "dir") == 0) {
operation = FileOperationType_Dir;
}
else if (strcmp(argv[currentArgc], "subdir") == 0) {
operation = FileOperationType_Dir;
filename = argv[++currentArgc];
}
else if (strcmp(argv[currentArgc], "info") == 0) {
operation = FileOperationType_Info;
filename = argv[++currentArgc];
@ -185,15 +116,9 @@ showDirectory(IedConnection con)
{
IedClientError error;
bool moreFollows = false;
/* Get the root directory */
LinkedList rootDirectory;
if (singleRequest)
rootDirectory = IedConnection_getFileDirectoryEx(con, &error, filename, NULL, &moreFollows);
else
rootDirectory = IedConnection_getFileDirectory(con, &error, filename);
LinkedList rootDirectory =
IedConnection_getFileDirectory(con, &error, NULL);
if (error != IED_ERROR_OK) {
printf("Error retrieving file directory\n");
@ -212,9 +137,6 @@ showDirectory(IedConnection con)
LinkedList_destroyDeep(rootDirectory, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy);
}
if (moreFollows)
printf("\n- MORE FILES AVAILABLE -\n");
}
void
@ -226,7 +148,7 @@ getFile(IedConnection con)
char* localFilename = basename(bname);
FILE* fp = fopen(localFilename, "wb");
FILE* fp = fopen(localFilename, "w");
if (fp != NULL) {
@ -338,7 +260,6 @@ main(int argc, char** argv)
}
IedConnection_destroy(con);
return 0;
}

@ -72,9 +72,7 @@ int main(int argc, char** argv) {
LinkedList logs = IedConnection_getLogicalNodeDirectory(con, &error, "simpleIOGenericIO/LLN0", ACSI_CLASS_LOG);
if (error == IED_ERROR_OK) {
if (LinkedList_size(logs) > 0) {
printf("Found logs in LN simpleIOGenericIO/LLN0:\n");
printf("Found log in LN simpleIOGenericIO/LLN0:\n");
LinkedList log = LinkedList_getNext(logs);
@ -85,10 +83,6 @@ int main(int argc, char** argv) {
log = LinkedList_getNext(log);
}
}
else {
printf("No logs found\n");
}
LinkedList_destroy(logs);
}
@ -96,7 +90,7 @@ int main(int argc, char** argv) {
/* read log control block (using the generic read function) */
MmsValue* lcbValue = IedConnection_readObject(con, &error, "simpleIOGenericIO/LLN0.EventLog", IEC61850_FC_LG);
if ((error == IED_ERROR_OK) && (MmsValue_getType(lcbValue) != MMS_DATA_ACCESS_ERROR)) {
if (error == IED_ERROR_OK) {
char printBuf[1024];
@ -140,7 +134,6 @@ int main(int argc, char** argv) {
}
IedConnection_destroy(con);
return 0;
}

@ -1,17 +0,0 @@
set(iec61850_client_no_thread_SRCS
client_example_no_thread.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_no_thread_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_no_thread
${iec61850_client_no_thread_SRCS}
)
target_link_libraries(iec61850_client_no_thread
iec61850
)

@ -1,17 +0,0 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_no_thread
PROJECT_SOURCES = client_example_no_thread.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)

@ -1,461 +0,0 @@
/*
* client_example_no_thread.c
*
* Shows how to use IedConnection in non-thread mode together with the asynchronous client API
*
* NOTE:
* - in non-thread mode only asynchronous service functions can be used!
* - the IedConnection_tick function has to be called periodically
* - the asynchronous API returns service results by callback functions
*
* This example is intended to be used with server_example_basic_io.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static ClientDataSet clientDataSet = NULL;
static void
printValue(char* name, MmsValue* value)
{
char buf[1000];
MmsValue_printToBuffer(value, buf, 1000);
printf("%s: %s\n", name, buf);
}
/* callback function for IedConnection_readObjectAsync */
static void
readObjectHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value)
{
if (err == IED_ERROR_OK) {
printValue((char*) parameter, value);
MmsValue_delete(value);
}
else {
printf("Failed to read object %s (err=%i)\n", (char*) parameter, err);
}
}
/* callback function for IedConnection_readDataSetValuesAsync */
static void
readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet)
{
if (err == IED_ERROR_OK) {
clientDataSet = dataSet;
printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet));
MmsValue* values = ClientDataSet_getValues(dataSet);
if (MmsValue_getType(values) == MMS_ARRAY) {
int i;
for (i = 0; i < MmsValue_getArraySize(values); i++) {
printf(" [%i]", i);
printValue("", MmsValue_getElement(values, i));
}
}
}
else {
printf("Failed to read data set (err=%i)\n", err);
}
}
static void
writeDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList /* <MmsValue*> */accessResults)
{
if (err == IED_ERROR_OK) {
if (accessResults) {
int i = 0;
LinkedList element = LinkedList_getNext(accessResults);
while (element) {
MmsValue* accessResultValue = LinkedList_getData(element);
printf(" access-result[%i]", i);
printValue("", accessResultValue);
element = LinkedList_getNext(element);
i++;
}
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete);
}
}
else {
printf("Failed to write data set (err=%i)\n", err);
}
}
static 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 != IEC61850_REASON_NOT_INCLUDED) {
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
}
}
}
static void
getControlVariableVarSpecHandler(uint32_t invokeId, void* parameter, IedClientError err, MmsVariableSpecification* spec)
{
if (err == IED_ERROR_OK) {
MmsVariableSpecification** ctlVarSpec = (MmsVariableSpecification**)parameter;
*ctlVarSpec = spec;
}
else {
printf("Failed to get variable specification for object %s (err=%i)\n", (char*) parameter, err);
}
}
static void
getVarSpecHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsVariableSpecification* spec)
{
if (err == IED_ERROR_OK) {
printf("variable: %s has type %d\n", (char*) parameter, MmsVariableSpecification_getType(spec));
MmsVariableSpecification_destroy(spec);
}
else {
printf("Failed to get variable specification for object %s (err=%i)\n", (char*) parameter, err);
}
}
/* callback function for service functions IedConnection_getLogicalDeviceVariablesAsync, IedConnection_getLogicalDeviceDataSetsAsync */
static void
getNameListHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList nameList, bool moreFollows)
{
if (err != IED_ERROR_OK) {
printf("Get name list error: %d\n", err);
}
else {
char* ldName = (char*) parameter;
LinkedList element = LinkedList_getNext(nameList);
while (element) {
char* variableName = (char*) LinkedList_getData(element);
printf(" %s/%s\n", ldName, variableName);
element = LinkedList_getNext(element);
}
LinkedList_destroy(nameList);
free(ldName);
}
}
/* callback function for IedConnection_getServerDirectoryAsync */
static void
getServerDirectoryHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList nameList, bool moreFollows)
{
IedConnection con = (IedConnection) parameter;
if (err != IED_ERROR_OK) {
printf("Get server directory error: %d\n", err);
}
else {
LinkedList element = LinkedList_getNext(nameList);
/* Call logical device variables for each logical node */
while (element) {
char* ldName = (char*) LinkedList_getData(element);
printf("LD: %s variables:\n", ldName);
IedConnection_getLogicalDeviceVariablesAsync(con, &err, ldName, NULL, NULL, getNameListHandler, strdup(ldName));
printf("LD: %s data sets:\n", ldName);
IedConnection_getLogicalDeviceDataSetsAsync(con, &err, ldName, NULL, NULL, getNameListHandler, strdup(ldName));
element = LinkedList_getNext(element);
}
LinkedList_destroy(nameList);
}
}
static void
controlActionHandler(uint32_t invokeId, void* parameter, IedClientError err, ControlActionType type, bool success)
{
printf("control: ID: %d type: %i err: %d success: %i\n", invokeId, type, err, success);
}
static void
stateChangedHandler(void* parameter, IedConnection connection, IedConnectionState newState)
{
printf("Connection state changed: ");
switch (newState) {
case IED_STATE_CLOSED:
printf("CLOSED\n");
break;
case IED_STATE_CLOSING:
printf("CLOSING\n");
break;
case IED_STATE_CONNECTING:
printf("CONNECTING\n");
break;
case IED_STATE_CONNECTED:
printf("CONNECTED\n");
break;
}
}
static void
getRCBValuesHandler (uint32_t invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb)
{
if (parameter) {
printf("get rcb values handler: %s (error:%i)\n", (char*)parameter, err);
}
}
static void
genericServiceHandler (uint32_t invokeId, void* parameter, IedClientError err)
{
if (parameter) {
printf("generic service handler: %s (error:%i)\n", (char*)parameter, err);
}
}
static void waitWithTick(IedConnection con, int waitMs)
{
uint64_t startTime = Hal_getTimeInMs();
while (Hal_getTimeInMs() < (startTime + (uint64_t) waitMs))
{
if (IedConnection_tick(con) == true)
Thread_sleep(10);
}
}
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;
ClientReportControlBlock rcb = NULL;
/* create new IedConnection with non-thread mode */
IedConnection con = IedConnection_createEx(NULL, false);
/* track connection state change */
IedConnection_installStateChangedHandler(con, stateChangedHandler, NULL);
/* invoke association with server */
IedConnection_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
bool success = true;
/* Call IedConnection_tick until state is CONNECTED or CLOSED */
while (IedConnection_getState(con) != IED_STATE_CONNECTED) {
if (IedConnection_getState(con) == IED_STATE_CLOSED) {
success = false;
break;
}
if (IedConnection_tick(con) == true)
Thread_sleep(10);
}
if (success) {
IedConnection_getServerDirectoryAsync(con, &error, NULL, NULL, getServerDirectoryHandler, con);
if (error != IED_ERROR_OK) {
printf("read server directory error %i\n", error);
}
waitWithTick(con, 1000);
rcb = ClientReportControlBlock_create("simpleIOGenericIO/LLN0.RP.EventsRCB01");
/* Read RCB values */
IedConnection_getRCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", rcb, getRCBValuesHandler, NULL);
if (error != IED_ERROR_OK) {
printf("getRCBValues service error!\n");
}
else {
waitWithTick(con, 1000);
/* prepare the parameters of the RCP */
ClientReportControlBlock_setResv(rcb, true);
ClientReportControlBlock_setDataSetReference(rcb, "simpleIOGenericIO/LLN0$Events"); /* NOTE the "$" instead of "." ! */
ClientReportControlBlock_setRptEna(rcb, true);
ClientReportControlBlock_setGI(rcb, true);
/* Configure the report receiver */
IedConnection_installReportHandler(con, "simpleIOGenericIO/LLN0.RP.EventsRCB", ClientReportControlBlock_getRptId(rcb), reportCallbackFunction,
NULL);
/* Write RCB parameters and enable report */
IedConnection_setRCBValuesAsync(con, &error, rcb, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_GI, true, genericServiceHandler, NULL);
waitWithTick(con, 1000);
}
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn1.mag.f");
if (error != IED_ERROR_OK) {
printf("read object error %i\n", error);
}
waitWithTick(con, 1000);
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn2.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn2.mag.f");
if (error != IED_ERROR_OK) {
printf("read object error %i\n", error);
}
waitWithTick(con, 1000);
IedConnection_getVariableSpecificationAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1", IEC61850_FC_MX, getVarSpecHandler, "simpleIOGenericIO/GGIO1.AnIn1");
if (error != IED_ERROR_OK) {
printf("get variable specification error %i\n", error);
}
waitWithTick(con, 1000);
IedConnection_readDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", NULL, readDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("read data set error %i\n", error);
}
waitWithTick(con, 1000);
LinkedList values = LinkedList_create();
LinkedList_add(values, MmsValue_newBoolean(true));
LinkedList_add(values, MmsValue_newBoolean(false));
LinkedList_add(values, MmsValue_newBoolean(true));
LinkedList_add(values, MmsValue_newBoolean(false));
IedConnection_writeDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", values, writeDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("write data set error %i\n", error);
}
waitWithTick(con, 1000);
LinkedList_destroyDeep(values, (LinkedListValueDeleteFunction) MmsValue_delete);
waitWithTick(con, 1000);
/* Get the variable specification for the controllable data object by online service */
MmsVariableSpecification* ctlVarSpec = NULL;
IedConnection_getVariableSpecificationAsync(con, &error, "simpleIOGenericIO/GGIO1.SPCSO1", IEC61850_FC_CO,
getControlVariableVarSpecHandler, &ctlVarSpec);
waitWithTick(con, 1000);
if (ctlVarSpec != NULL) {
/* ControlObjectClient_create function cannot be used in non-thread mode - use ControlObjectClient_createEx instead */
ControlObjectClient controlClient = ControlObjectClient_createEx("simpleIOGenericIO/GGIO1.SPCSO1", con,
CONTROL_MODEL_DIRECT_NORMAL, ctlVarSpec);
if (controlClient != NULL) {
ControlObjectClient_setOrigin(controlClient, "test1", CONTROL_ORCAT_AUTOMATIC_REMOTE);
MmsValue* ctlVal = MmsValue_newBoolean(true);
ControlObjectClient_operateAsync(controlClient, &error, ctlVal, 0, controlActionHandler, NULL);
waitWithTick(con, 1000);
MmsValue_delete(ctlVal);
if (error != IED_ERROR_OK) {
printf("Failed to send operate %i\n", error);
}
ControlObjectClient_destroy(controlClient);
}
else {
printf("Failed to connect to control object\n");
}
MmsVariableSpecification_destroy(ctlVarSpec);
}
}
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK) {
printf("Release returned error: %d\n", error);
}
else {
/* Call IedConnection_tick until state is CLOSED */
while (IedConnection_getState(con) != IED_STATE_CLOSED) {
if (IedConnection_tick(con) == true)
Thread_sleep(10);
}
}
if (rcb != NULL)
ClientReportControlBlock_destroy(rcb);
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
if (clientDataSet)
ClientDataSet_destroy(clientDataSet);
IedConnection_destroy(con);
return 0;
}

@ -1,7 +1,7 @@
/*
* client_example_reporting.c
*
* This example is intended to be used with server_example_basic_io or server_example_goose.
* This example is intended to be used with server_example3 or server_example_goose.
*/
#include "iec61850_client.h"
@ -40,41 +40,27 @@ reportCallbackFunction(void* parameter, ClientReport report)
ctime_r(&unixTime, timeBuf);
#endif
printf(" report contains timestamp (%u): %s", (unsigned int) unixTime, timeBuf);
printf(" report contains timestamp (%u):", (unsigned int) unixTime);
printf("%s \n", timeBuf);
}
if (dataSetDirectory) {
int i;
for (i = 0; i < LinkedList_size(dataSetDirectory); i++) {
ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
if (reason != IEC61850_REASON_NOT_INCLUDED) {
char valBuffer[500];
sprintf(valBuffer, "no value");
if (dataSetValues) {
MmsValue* value = MmsValue_getElement(dataSetValues, i);
if (value) {
MmsValue_printToBuffer(value, valBuffer, 500);
}
}
LinkedList entry = LinkedList_get(dataSetDirectory, i);
char* entryName = (char*) entry->data;
printf(" %s (included for reason %i): %s\n", entryName, reason, valBuffer);
printf(" %s (included for reason %i)\n", entryName, reason);
}
}
}
}
int
main(int argc, char** argv)
{
int main(int argc, char** argv) {
char* hostname;
int tcpPort = 102;
@ -98,28 +84,28 @@ main(int argc, char** argv)
if (error == IED_ERROR_OK) {
ClientReportControlBlock rcb = NULL;
ClientDataSet clientDataSet = NULL;
LinkedList dataSetDirectory = NULL;
/* read data set directory */
dataSetDirectory = IedConnection_getDataSetDirectory(con, &error, "simpleIOGenericIO/LLN0.Events", NULL);
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;
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;
goto exit_error;
}
/* Read RCB values */
rcb = IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL);
ClientReportControlBlock rcb =
IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL);
if (error != IED_ERROR_OK) {
printf("getRCBValues service error!\n");
@ -128,7 +114,6 @@ main(int argc, char** argv)
/* prepare the parameters of the RCP */
ClientReportControlBlock_setResv(rcb, true);
ClientReportControlBlock_setTrgOps(rcb, TRG_OPT_DATA_CHANGED | TRG_OPT_QUALITY_CHANGED | TRG_OPT_GI);
ClientReportControlBlock_setDataSetReference(rcb, "simpleIOGenericIO/LLN0$Events"); /* NOTE the "$" instead of "." ! */
ClientReportControlBlock_setRptEna(rcb, true);
ClientReportControlBlock_setGI(rcb, true);
@ -138,7 +123,7 @@ main(int argc, char** argv)
(void*) dataSetDirectory);
/* Write RCB parameters and enable report */
IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_TRG_OPS | RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_GI, true);
IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_GI, true);
if (error != IED_ERROR_OK) {
printf("setRCBValues service error!\n");
@ -166,29 +151,21 @@ main(int argc, char** argv)
}
}
exit_error:
/* disable reporting */
ClientReportControlBlock_setRptEna(rcb, false);
IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA, true);
exit_error:
IedConnection_close(con);
if (clientDataSet)
ClientDataSet_destroy(clientDataSet);
if (rcb)
ClientReportControlBlock_destroy(rcb);
if (dataSetDirectory)
LinkedList_destroy(dataSetDirectory);
IedConnection_close(con);
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -1,17 +0,0 @@
set(iec61850_client_file_async_SRCS
client_example_async.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_file_async_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_file_async
${iec61850_client_file_async_SRCS}
)
target_link_libraries(iec61850_client_file_async
iec61850
)

@ -1,106 +0,0 @@
/*
* client_example_async.c
*
* Shows how to use the asynchronous client API
*
* This example is intended to be used with server_example_basic_io.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static bool fileTransferComplete = false;
static bool
getFileAsyncHandler (uint32_t invokeId, void* parameter, IedClientError err, uint32_t originalInvokeId,
uint8_t* buffer, uint32_t bytesRead, bool moreFollows)
{
if ((err != IED_ERROR_OK) || (moreFollows == false)) {
if (err == IED_ERROR_OK) {
printf("Received %d bytes\n", bytesRead);
}
printf("File transfer complete (err:%d)\n", err);
fileTransferComplete = true;
}
else {
printf("Received %d bytes\n", bytesRead);
}
return true;
}
int main(int argc, char** argv) {
char* hostname;
char* filename = NULL;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
filename = argv[2];
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connectAsync(con, &error, hostname, 102);
if (error == IED_ERROR_OK) {
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED) {
if (IedConnection_getState(con) == IED_STATE_CLOSED) {
success = false;
break;
}
Thread_sleep(10);
}
if (success) {
if (filename) {
IedConnection_getFileAsync(con, &error, filename, getFileAsyncHandler, NULL);
printf("Started file download\n");
while (fileTransferComplete == false)
Thread_sleep(10);
}
}
Thread_sleep(1000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK) {
printf("Release returned error: %d\n", error);
}
else {
while (IedConnection_getState(con) != IED_STATE_CLOSED) {
Thread_sleep(10);
}
}
}
else {
printf("Failed to connect to %s\n", hostname);
}
IedConnection_destroy(con);
return 0;
}

@ -3,10 +3,10 @@ set(iec61850_sv_client_example_SRCS
sv_client_example.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${iec61850_sv_client_example_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
ENDIF(WIN32)
add_executable(iec61850_sv_client_example
${iec61850_sv_client_example_SRCS}

@ -114,7 +114,6 @@ int main(int argc, char** argv) {
}
IedConnection_destroy(con);
return 0;
}

@ -3,10 +3,10 @@ set(mms_utility_SRCS
mms_utility.c
)
IF(MSVC)
IF(WIN32)
set_source_files_properties(${mms_utility_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
ENDIF(WIN32)
add_executable(mms_utility
${mms_utility_SRCS}

@ -1,15 +1,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "string_utilities.h"
#include "iec61850_common.h"
#include "mms_client_connection.h"
#include "conversions.h"
static void
print_help()
{
printf("MMS utility (libiec61850 %s) options:\n", LibIEC61850_getVersionString());
printf("MMS utility (libiec61850 " LIBIEC61850_VERSION ") options:\n");
printf("-h <hostname> specify hostname\n");
printf("-p <port> specify port\n");
printf("-l <max_pdu_size> specify maximum PDU size\n");
@ -17,30 +18,27 @@ print_help()
printf("-i show server identity\n");
printf("-t <domain_name> show domain directory\n");
printf("-r <variable_name> read domain variable\n");
printf("-c <component_name> specify component name for variable read\n");
printf("-a <domain_name> specify domain for read or write command\n");
printf("-f show file list\n");
printf("-g <filename> get file attributes\n");
printf("-x <filename> delete file\n");
printf("-j <domainName/journalName> read journal\n");
printf("-v <variable list_name> read domain variable list\n");
printf("-z <variable list_name> get domain variable list directory\n");
printf("-y <index> array index for read access\n");
printf("-m print raw MMS messages\n");
}
static void
mmsFileDirectoryHandler(void* parameter, char* filename, uint32_t size, uint64_t lastModified)
mmsFileDirectoryHandler (void* parameter, char* filename, uint32_t size, uint64_t lastModified)
{
char* lastName = (char*) parameter;
strcpy(lastName, filename);
strcpy (lastName, filename);
printf("%s\n", filename);
}
static void
mmsGetFileAttributeHandler(void* parameter, char* filename, uint32_t size, uint64_t lastModified)
mmsGetFileAttributeHandler (void* parameter, char* filename, uint32_t size, uint64_t lastModified)
{
char gtString[30];
Conversions_msTimeToGeneralizedTime(lastModified, (uint8_t*) gtString);
@ -99,18 +97,14 @@ printRawMmsMessage(void* parameter, uint8_t* message, int messageLength, bool re
printf("\n");
}
int main(int argc, char** argv)
{
int returnCode = 0;
int main(int argc, char** argv) {
char* hostname = StringUtils_copyString("localhost");
int tcpPort = 102;
int maxPduSize = 65000;
int arrayIndex = -1;
char* domainName = NULL;
char* variableName = NULL;
char* componentName = NULL;
char* filename = NULL;
char* journalName = NULL;
@ -125,18 +119,16 @@ int main(int argc, char** argv)
int printRawMmsMessages = 0;
int deleteFile = 0;
int readVariableList = 0;
int readDataSetDirectory = 0;
int c;
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1) {
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:")) != -1)
switch (c) {
case 'm':
printRawMmsMessages = 1;
break;
case 'h':
free(hostname);
hostname = StringUtils_copyString(optarg);
break;
case 'p':
@ -163,18 +155,10 @@ int main(int argc, char** argv)
readVariable = 1;
variableName = StringUtils_copyString(optarg);
break;
case 'c':
componentName = StringUtils_copyString(optarg);
break;
case 'v':
readVariableList = 1;
variableName = StringUtils_copyString(optarg);
break;
case 'z':
readDataSetDirectory = 1;
variableName = StringUtils_copyString(optarg);
break;
case 'f':
showFileList = 1;
break;
@ -192,21 +176,16 @@ int main(int argc, char** argv)
journalName = StringUtils_copyString(optarg);
break;
case 'y':
arrayIndex = atoi(optarg);
break;
default:
print_help();
return 0;
}
}
MmsConnection con = MmsConnection_create();
MmsError error;
/* Set maximum MMS PDU size (local detail) */
/* Set maximum MMS PDU size (local detail) to 2000 byte */
MmsConnection_setLocalDetail(con, maxPduSize);
if (printRawMmsMessages)
@ -214,10 +193,6 @@ int main(int argc, char** argv)
if (!MmsConnection_connect(con, &error, hostname, tcpPort)) {
printf("MMS connect failed!\n");
if (error != MMS_ERROR_NONE)
returnCode = error;
goto exit;
}
else
@ -227,9 +202,6 @@ int main(int argc, char** argv)
MmsServerIdentity* identity =
MmsConnection_identify(con, &error);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (identity != NULL) {
printf("\nServer identity:\n----------------\n");
printf(" vendor:\t%s\n", identity->vendorName);
@ -243,24 +215,14 @@ int main(int argc, char** argv)
if (readDeviceList) {
printf("\nDomains present on server:\n--------------------------\n");
LinkedList nameList = MmsConnection_getDomainNames(con, &error);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (nameList) {
LinkedList_printStringList(nameList);
LinkedList_destroy(nameList);
}
}
if (getDeviceDirectory) {
LinkedList variableList = MmsConnection_getDomainVariableNames(con, &error,
domainName);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList) {
LinkedList element = LinkedList_getNext(variableList);
printf("\nMMS domain variables for domain %s\n", domainName);
@ -274,19 +236,12 @@ int main(int argc, char** argv)
}
LinkedList_destroy(variableList);
}
else {
printf("\nFailed to read domain directory (error=%d)\n", error);
}
variableList = MmsConnection_getDomainJournals(con, &error, domainName);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList != NULL) {
if (variableList) {
LinkedList element = variableList;
element = variableList;
printf("\nMMS journals for domain %s\n", domainName);
@ -298,10 +253,6 @@ int main(int argc, char** argv)
LinkedList_destroy(variableList);
}
else {
printf("\nFailed to read domain journals (error=%d)\n", error);
}
}
if (readJournal) {
@ -329,9 +280,6 @@ int main(int argc, char** argv)
LinkedList journalEntries = MmsConnection_readJournalTimeRange(con, &error, logDomain, logName, startTime, endTime,
&moreFollows);
if (error != MMS_ERROR_NONE)
returnCode = error;
MmsValue_delete(startTime);
MmsValue_delete(endTime);
@ -366,8 +314,7 @@ int main(int argc, char** argv)
readNext = true;
}
}
while ((moreFollows == true) || (readNext == true));
} while ((moreFollows == true) || (readNext == true));
}
}
else
@ -376,42 +323,21 @@ int main(int argc, char** argv)
if (readVariable) {
if (readWriteHasDomain) {
MmsValue* result;
if (componentName == NULL) {
if (arrayIndex == -1) {
result = MmsConnection_readVariable(con, &error, domainName, variableName);
}
else {
result = MmsConnection_readSingleArrayElementWithComponent(con, &error, domainName, variableName, arrayIndex, NULL);
}
}
else {
if (arrayIndex == -1) {
result = MmsConnection_readVariableComponent(con, &error, domainName, variableName, componentName);
}
else {
result = MmsConnection_readSingleArrayElementWithComponent(con, &error, domainName, variableName, arrayIndex, componentName);
}
}
MmsValue* result = MmsConnection_readVariable(con, &error, domainName, variableName);
if (error != MMS_ERROR_NONE) {
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
printf("Read SUCCESS\n");
if (result != NULL) {
char outbuf[1024];
MmsValue_printToBuffer(result, outbuf, 1024);
printf("%s\n", outbuf);
MmsValue_delete(result);
}
else
printf("result: NULL\n");
@ -428,8 +354,6 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE) {
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
printf("Read SUCCESS\n");
@ -439,43 +363,6 @@ int main(int argc, char** argv)
printf("Reading VMD scope variable list not yet supported!\n");
}
if (readDataSetDirectory) {
if (readWriteHasDomain) {
bool deletable = false;
LinkedList varListDir = MmsConnection_readNamedVariableListDirectory(con, &error, domainName, variableName, &deletable);
if (error != MMS_ERROR_NONE) {
printf("Reading variable list directory failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
LinkedList varListElem = LinkedList_getNext(varListDir);
int listIdx = 0;
while (varListElem) {
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(varListElem);
if (varAccessSpec->arrayIndex)
printf("[%i] %s/%s(%i)%s\n", listIdx, varAccessSpec->domainId, varAccessSpec->itemId, varAccessSpec->arrayIndex, varAccessSpec->componentName == NULL ? "" : varAccessSpec->componentName);
else
printf("[%i] %s/%s\n", listIdx, varAccessSpec->domainId, varAccessSpec->itemId);
listIdx++;
varListElem = LinkedList_getNext(varListElem);
}
printf("Read SUCCESS\n");
}
}
else
printf("Reading VMD scope variable list not yet supported!\n");
}
if (showFileList) {
char lastName[300];
lastName[0] = 0;
@ -483,19 +370,12 @@ int main(int argc, char** argv)
char* continueAfter = NULL;
while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName)) {
if (error != MMS_ERROR_NONE)
returnCode = error;
continueAfter = lastName;
}
}
if (getFileAttributes) {
MmsConnection_getFileDirectory(con, &error, filename, NULL, mmsGetFileAttributeHandler, NULL);
if (error != MMS_ERROR_NONE)
returnCode = error;
}
if (deleteFile) {
@ -503,7 +383,6 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE) {
printf("Delete file failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
printf("File deleted\n");
@ -512,13 +391,6 @@ int main(int argc, char** argv)
exit:
free(hostname);
free(domainName);
free(variableName);
free(journalName);
free(componentName);
MmsConnection_destroy(con);
return returnCode;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save