├── .dockerignore ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── DOCKER-HUB.md ├── Dockerfile ├── README.md ├── docker-entrypoint ├── include ├── goose_publisher.h ├── goose_receiver.h ├── goose_subscriber.h ├── hal_base.h ├── hal_filesystem.h ├── hal_thread.h ├── hal_time.h ├── iec61850_cdc.h ├── iec61850_client.h ├── iec61850_common.h ├── iec61850_config_file_parser.h ├── iec61850_dynamic_model.h ├── iec61850_model.h ├── iec61850_server.h ├── iso_connection_parameters.h ├── lib_memory.h ├── libiec61850_common_api.h ├── linked_list.h ├── logging_api.h ├── mms_client_connection.h ├── mms_common.h ├── mms_server.h ├── mms_type_spec.h ├── mms_types.h ├── mms_value.h ├── sv_publisher.h ├── sv_subscriber.h └── tls_config.h ├── lib └── libiec61850.a ├── misc └── Schneider Electric IED - PM8000.zip ├── res ├── ION.config.xml ├── ION.icd └── PM.icd ├── src └── 61850-sim.c └── tools └── model-generator ├── genmodel.jar └── manifest.mf /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 61850-sim 3 | src/static_model.* -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | name: Build and push docker images 13 | 14 | env: 15 | VERSION: "dev" 16 | 17 | steps: 18 | 19 | - name: Informing 20 | run: echo "Trigger '${{ github.event_name }}', branch '${{ github.ref }}', named '${{ github.ref_name }}'" 21 | 22 | - name: Checking out repository 23 | uses: actions/checkout@v2 24 | 25 | - name: Build docker image 26 | run: | 27 | docker build --pull --build-arg VERSION=$VERSION --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg BUILD_NUMBER=$GITHUB_RUN_NUMBER --tag 61850-sim:$GITHUB_RUN_NUMBER . 28 | 29 | - name: Tag docker images 30 | run: | 31 | docker tag 61850-sim:$GITHUB_RUN_NUMBER stinging/61850-sim:$VERSION 32 | docker tag 61850-sim:$GITHUB_RUN_NUMBER harbor.sting.dev/library/61850-sim:$VERSION 33 | 34 | - name: Login to DockerHub 35 | uses: docker/login-action@v1 36 | with: 37 | username: ${{ secrets.DOCKERHUB_USERNAME }} 38 | password: ${{ secrets.DOCKERHUB_TOKEN }} 39 | 40 | - name: Push docker images to DockerHub 41 | run: | 42 | docker push stinging/61850-sim:$VERSION 43 | 44 | - name: Login to StingHarbor 45 | uses: docker/login-action@v1 46 | with: 47 | registry: harbor.sting.dev 48 | username: ${{ secrets.STINGHARBOR_USERNAME }} 49 | password: ${{ secrets.STINGHARBOR_PASSWORD }} 50 | 51 | - name: Push docker images to StingHarbor 52 | run: | 53 | docker push harbor.sting.dev/library/61850-sim:$VERSION 54 | 55 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | name: Build and push docker images 14 | 15 | env: 16 | VERSION: "0.0" 17 | 18 | steps: 19 | 20 | - name: Informing 21 | run: echo "Trigger '${{ github.event_name }}', branch '${{ github.ref }}', named '${{ github.ref_name }}'" 22 | 23 | - name: Set version 24 | run: | 25 | echo "VERSION=${{ github.ref_name }}" >> $GITHUB_ENV 26 | 27 | - name: Checking out repository 28 | uses: actions/checkout@v2 29 | 30 | - name: Get version 31 | run: | 32 | echo $VERSION 33 | 34 | - name: Build docker image 35 | run: | 36 | docker build --pull --build-arg VERSION=$VERSION --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg BUILD_NUMBER=$GITHUB_RUN_NUMBER --tag 61850-sim:$GITHUB_RUN_NUMBER . 37 | 38 | - name: Tag docker images 39 | run: | 40 | docker tag 61850-sim:$GITHUB_RUN_NUMBER stinging/61850-sim 41 | docker tag 61850-sim:$GITHUB_RUN_NUMBER stinging/61850-sim:$VERSION 42 | docker tag 61850-sim:$GITHUB_RUN_NUMBER harbor.sting.dev/library/61850-sim 43 | docker tag 61850-sim:$GITHUB_RUN_NUMBER harbor.sting.dev/library/61850-sim:$VERSION 44 | 45 | - name: Login to DockerHub 46 | uses: docker/login-action@v1 47 | with: 48 | username: ${{ secrets.DOCKERHUB_USERNAME }} 49 | password: ${{ secrets.DOCKERHUB_TOKEN }} 50 | 51 | - name: Push docker images to DockerHub 52 | run: | 53 | docker push stinging/61850-sim 54 | docker push stinging/61850-sim:$VERSION 55 | 56 | - name: Login to StingHarbor 57 | uses: docker/login-action@v1 58 | with: 59 | registry: harbor.sting.dev 60 | username: ${{ secrets.STINGHARBOR_USERNAME }} 61 | password: ${{ secrets.STINGHARBOR_PASSWORD }} 62 | 63 | - name: Push docker images to StingHarbor 64 | run: | 65 | docker push harbor.sting.dev/library/61850-sim 66 | docker push harbor.sting.dev/library/61850-sim:$VERSION 67 | 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 61850-sim 3 | src/static_model.* 4 | 5 | misc/Hitachi* 6 | res/MSM.scd 7 | res/TEC.scd -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [1.2] - 2022-08-21 5 | 6 | ### Added 7 | - Authentication with password 8 | - CHANGELOG 9 | ### Changed 10 | - mirror docker image repository 11 | ### Fixed 12 | - internal settings not beeing able to be customized 13 | 14 | ## [1.1] - 2014-07-10 15 | ### Added 16 | - configuration of the coefficients 17 | 18 | ## [1.0] - 2014-05-31 19 | ### Added 20 | - initial version 21 | 22 | [1.2]: https://github.com/st-ing/61850-sim/compare/1.1...1.2 23 | [1.1]: https://github.com/st-ing/61850-sim/compare/1.0...1.1 24 | [1.0]: https://github.com/st-ing/61850-sim/releases/tag/1.0 25 | 26 | -------------------------------------------------------------------------------- /DOCKER-HUB.md: -------------------------------------------------------------------------------- 1 | # Quick reference 2 | 3 | **Maintained by**: Dusan Stojkovic 4 | 5 | **Source code:** https://github.com/st-ing/61850-sim 6 | 7 | # Supported tags and respective `Dockerfile` links 8 | 9 | - [`1.2`, `latest`](https://github.com/st-ing/61850-sim/blob/1.2/Dockerfile) 10 | - [`1.1`](https://github.com/st-ing/61850-sim/blob/1.1/Dockerfile) 11 | - [`1.0`](https://github.com/st-ing/61850-sim/blob/1.0/Dockerfile) 12 | 13 | # What is Fuzzy IEC61850 Simulator? 14 | 15 | This simulator is a helpful tool that can be used for testing of various [IED](https://en.wikipedia.org/wiki/Intelligent_electronic_device) integration scenarios. 16 | It supports [IEC61850](https://en.wikipedia.org/wiki/IEC_61850) based communication and acts as a [MMS](https://en.wikipedia.org/wiki/Manufacturing_Message_Specification#MMS_stack_over_TCP/IP) server. 17 | 18 | Simulation is meant to be run as a (docker) container, as it makes it underlying system agnostic (i.e. laptop, bare-metal, cloud, ...) and brings flexibility when scaling is required (i.e. simulating 200 IEDs). 19 | 20 | As an input, the simulation takes a model file that is in any of the [formats](https://en.wikipedia.org/wiki/Substation_Configuration_Language#Types_of_SCL_-) supported by [Substation Configuration Language (SCL)](https://en.wikipedia.org/wiki/Substation_Configuration_Language): ICD (*IED Capability Description*), CID (*Configured IED Description*) or IID (*Instantiated IED Description*). 21 | Based on this model, a runtime is generated dynamically, and simulation is commenced. 22 | 23 | More information can be found at https://github.com/st-ing/61850-sim#readme 24 | 25 | # How to use this image 26 | 27 | ## Running 28 | In order to run the simulation use the following or similiar command: 29 | 30 | ``` 31 | docker run \ 32 | -p 102:102 \ 33 | -v :/model.cid \ 34 | stinging/61850-sim 35 | ``` 36 | 37 | where *``* is path to IED model in any of [ICD, CID, or IID formats](https://en.wikipedia.org/wiki/Substation_Configuration_Language#Types_of_SCL_files). 38 | 39 | 40 | 41 | This is the minimal use-case. For more complex use-cases check the *configuring* and *examples*. 42 | 43 | ## Configuring 44 | The behaviour of the simulator can be configured using environmental variables. The overview is given in the following table: 45 | 46 | |Environment Variable|Description|Default value 47 | |--|--|-- 48 | | `IED_NAME` | Name of the IED device | _IED_ | 49 | | `MMS_PORT` | IEC61850 MMS server listening port | _102_ | 50 | |_internal_|| 51 | | `IEC_61850_EDITION` | Edition of IEC61850 (1.0, 2.0, 2.1) /respectivly 0, 1, 2/| _1_ | 52 | | `MAX_MMS_CONNECTIONS` | Maximum number of MMS client connections | _10_ | 53 | | `MAX_DATA_POINTS` | Modeling logging enabled | _10000_ | 54 | |_security_|| 55 | | `AUTH_PASSWORD` | Authentication password | | 56 | |_logging_|| 57 | | `LOG_MODELING` | Modeling logging enabled | _false_ | 58 | | `LOG_SIMULATION` | Simulation logging enabled | _false_ | 59 | | `LOG_DIAGNOSTICS_INTERVAL` | Diagnostics logging interval [**min**] | _5_ | 60 | |_simulation_|| 61 | | `SIMULATION_FREQUENCY` | Frequency of signal change (overall) [**Hz**]| _1_ | 62 | ||| 63 | 64 | The simulation for each individual data point can be additionally configure in **coefficients configuration** file: 65 | 66 | ``` 67 | 68 | 69 | ... 70 | 71 | ... 72 | 73 | ... 74 | 75 | ... 76 | 77 | ``` 78 | 79 | where *``* is the unique identifier for the datapoint, *``* is name/path of the data point and *``* is type; 80 | *``* is a coefficient , *``* is randomness factor (i.e. `0.1` (10%)) and *``* is the value of the coefficient. 81 | 82 | The **coefficients configuration** file is (re)generated on every run and can be exposed by mapping - see examples bellow. 83 | 84 | ## Examples 85 | 86 | **ABB CoreTec 4** 87 | 88 | *(port 102, frequency 10Hz / 0.1s, modeling logging, simulation logging)* 89 | 90 | ``` 91 | docker run -it --rm \ 92 | -p 102:102 \ 93 | -e SIMULATION_FREQUENCY=10 \ 94 | -e LOG_MODELING=true \ 95 | -e LOG_SIMULATION=true \ 96 | -v $(pwd)/res/TEC.scd:/model.cid \ 97 | stinging/61850-sim 98 | ``` 99 | 100 | **Hitachi Energy MSM (Modular Switchgear Monitoring)** 101 | 102 | *(port 55555 (on host), specific IED name 'MSM_Test_1', frequency 100Hz / 10ms, coefficient configuration)* 103 | 104 | ``` 105 | docker run -it --rm \ 106 | --network=host \ 107 | -e IED_NAME=MSM_Test_1 \ 108 | -e MMS_PORT=55555 \ 109 | -e SIMULATION_FREQUENCY=100 \ 110 | -v $(pwd)/res/MSM.scd:/model.cid \ 111 | -v $(pwd)/res/MSM.config.xml:/config.xml \ 112 | stinging/61850-sim 113 | ``` 114 | 115 | **Schneider Electric PowerLogic ION7550** 116 | 117 | *(port 1000, frequency 1kHz / 1ms, authentication with password 'abcd123', coefficient configuration)* 118 | 119 | ``` 120 | docker run -it --rm \ 121 | -p 1000:102 \ 122 | -e SIMULATION_FREQUENCY=1000 \ 123 | -e LOG_MODELING=true \ 124 | -e AUTH_PASSWORD=abc123 \ 125 | -v $(pwd)/res/ION.icd:/model.cid \ 126 | -v $(pwd)/res/ION.config.xml:/config.xml:ro \ 127 | stinging/61850-sim 128 | ``` 129 | 130 | **Schneider Electric PowerLogic PM8000** 131 | 132 | *(frequency 1Hz / 1s, simulation logging)* 133 | 134 | ``` 135 | docker run -it --rm \ 136 | -e SIMULATION_FREQUENCY=1 \ 137 | -e LOG_SIMULATION=true \ 138 | -v $(pwd)/res/PM.icd:/model.cid \ 139 | stinging/61850-sim 140 | ``` 141 | 142 | ### As a part of docker compose: 143 | 144 | *(specific IED name 'DEV03', frequency 5Hz / 200ms, modeling logging, simulation logging, internal network and specific IP 10.10.0.201)* 145 | 146 | ``` 147 | iec61850-sim-node-03: 148 | image: stinging/61850-sim 149 | container_name: iec61850-sim-node-03 150 | tty: true 151 | restart: unless-stopped 152 | volumes: 153 | - /opt/61850-sim/DEV.scd:/model.cid 154 | environment: 155 | IED_NAME: DEV03 156 | LOG_MODELING: "true" 157 | LOG_SIMULATION: "true" 158 | SIMULATION_FREQUENCY: 5 159 | networks: 160 | iec61850-sim-net: 161 | ipv4_address: 10.10.0.201 162 | ``` 163 | 164 | # Misc 165 | This code base uses **libIEC61850** library. More documentation can be found online at http://libiec61850.com. 166 | 167 | The supporting source code is published and available at https://github.com/st-ing/61850-sim. 168 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ARG VERSION 4 | ARG BUILD_NUMBER 5 | ARG BUILD_DATE 6 | 7 | LABEL maintainer="Dusan Stojkovic " 8 | 9 | LABEL org.opencontainers.image.title="Fuzzy IEC61850 Simulator" 10 | LABEL org.opencontainers.image.version=$VERSION 11 | LABEL org.opencontainers.image.revision=$BUILD_NUMBER 12 | LABEL org.opencontainers.image.created=$BUILD_DATE 13 | LABEL org.opencontainers.image.vendor="sting GmbH" 14 | LABEL org.opencontainers.image.base.name="stinging/61850-sim" 15 | 16 | RUN apk add linux-headers build-base openjdk8 libxml2-dev libxml2 17 | 18 | # simulation related 19 | COPY include ./opt/include 20 | COPY lib ./opt/lib 21 | COPY src ./opt/src 22 | 23 | # model related 24 | COPY tools ./opt/tools 25 | 26 | WORKDIR /opt 27 | 28 | COPY docker-entrypoint /usr/bin/ 29 | RUN chmod +x /usr/bin/docker-entrypoint 30 | 31 | # TBD - non-root, healthcheck 32 | 33 | ENTRYPOINT ["/usr/bin/docker-entrypoint"] 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fuzzy IEC61850 Simulator 2 | 3 | [![Fuzzy IEC61850 Simulator](https://github.com/st-ing/61850-sim/actions/workflows/ci.yml/badge.svg)](https://github.com/st-ing/61850-sim/actions/workflows/ci.yml) 4 | 5 | 6 | This simulator is a helpful tool that can be used for testing of various [IED](https://en.wikipedia.org/wiki/Intelligent_electronic_device) integration scenarios. 7 | It supports [IEC61850](https://en.wikipedia.org/wiki/IEC_61850) based communication and acts as a [MMS](https://en.wikipedia.org/wiki/Manufacturing_Message_Specification#MMS_stack_over_TCP/IP) server. 8 | 9 | Simulation is meant to be run as a (docker) container, as it makes it underlying system agnostic (i.e. laptop, bare-metal, cloud, ...) and brings flexibility when scaling is required (i.e. simulating 200 IEDs). 10 | 11 | As an input, the simulation takes a model file that is in any of the [formats](https://en.wikipedia.org/wiki/Substation_Configuration_Language#Types_of_SCL_files) supported by [Substation Configuration Language (SCL)](https://en.wikipedia.org/wiki/Substation_Configuration_Language): ICD (*IED Capability Description*), CID (*Configured IED Description*) or IID (*Instantiated IED Description*). 12 | Based on this model, a runtime is generated dynamically, and simulation is commenced. 13 | 14 | ## Features 15 | 16 | Some of the features that are currently implemented (and some that are 'work in progress'): 17 | 18 | * takes ICD, CID, and IID type of model files as input 19 | * applies simulation logic 20 | * configurable simulation frequency 21 | * exposes MMS server endpoint 22 | * configurable MMS port 23 | * configurable logging granularity 24 | * fuzzification/defuzzification 🚧 25 | * TLS support 🚧 26 | * authentication (password) 27 | * authorization 🚧 28 | 29 | ## Simulation 30 | 31 | The simulation value is calculated based on the combination of the functions ![$f_i = A_i + B_i sin(C_i t + D_i)$](https://latex.codecogs.com/gif.latex?f_i%20%3D%20A_i%20+%20B_i%20sin%28C_i%20t%20+%20D_i%29), where ![$i \in (1..n)$](https://latex.codecogs.com/gif.latex?i%20%5Cin%20%281..n%29) 32 | but with a salt of 'randomization' for each of the coefficients (![$A_i$](https://latex.codecogs.com/gif.latex?A_i), ![$B_i$](https://latex.codecogs.com/gif.latex?B_i), ![$C_i$](https://latex.codecogs.com/gif.latex?C_i) and ![$D_i$](https://latex.codecogs.com/gif.latex?D_i)) at the time of the simulation initialization, 33 | and in every simulation iteration for the time horizon parameter (![$t$](https://latex.codecogs.com/gif.latex?t)). 34 | 35 | After each time quant (determined by _simulation frequency_ parameter) new simulation values are calculated, and following fuzzification/defuzzification steps, a random data point (from the model) is assigned a new simulation value. 36 | 37 | ## Pull it 38 | 39 | The simulation (docker) image is automaticaly build and published to (docker) repository and available under 40 | `stinging/61850-sim` and you get it simply by: 41 | ``` 42 | docker pull stinging/61850-sim 43 | ``` 44 | 45 | Backup/mirror repository is available under `harbor.sting.dev/library/61850-sim` and you get it simply by: 46 | ``` 47 | docker pull harbor.sting.dev/library/61850-sim 48 | ``` 49 | 50 | ## ... or build it 51 | 52 | It is also possible to do a manual build. In order to build the simulator docker image, use the following or similiar commad: 53 | ``` 54 | docker build -t 61850-sim . 55 | ``` 56 | 57 | ## Configure it 58 | The behaviour of the simulator can be configured using environmental variables. The overview is given in the following table: 59 | 60 | |Environment Variable|Description|Default value 61 | |--|--|-- 62 | | `IED_NAME` | Name of the IED device | _IED_ | 63 | | `MMS_PORT` | IEC61850 MMS server listening port | _102_ | 64 | |_internal_|| 65 | | `IEC_61850_EDITION` | Edition of IEC61850 (1.0, 2.0, 2.1) /respectivly 0, 1, 2/| _1_ | 66 | | `MAX_MMS_CONNECTIONS` | Maximum number of MMS client connections | _10_ | 67 | | `MAX_DATA_POINTS` | Modeling logging enabled | _10000_ | 68 | |_security_|| 69 | | `AUTH_PASSWORD` | Authentication password | | 70 | |_logging_|| 71 | | `LOG_MODELING` | Modeling logging enabled | _false_ | 72 | | `LOG_SIMULATION` | Simulation logging enabled | _false_ | 73 | | `LOG_DIAGNOSTICS_INTERVAL` | Diagnostics logging interval [**min**] | _5_ | 74 | |_simulation_|| 75 | | `SIMULATION_FREQUENCY` | Frequency of signal change (overall) [**Hz**]| _1_ | 76 | ||| 77 | 78 | The simulation for each individual data point can be additionally configure in **coefficients configuration** file: 79 | 80 | ``` 81 | 82 | 83 | ... 84 | 85 | ... 86 | 87 | ... 88 | 89 | ... 90 | 91 | ``` 92 | 93 | where *``* is the unique identifier for the datapoint, *``* is name/path of the data point and *``* is type; 94 | *``* is a coefficient , *``* is randomness factor (i.e. `0.1` (10%)) and *``* is the value of the coefficient. 95 | 96 | The **coefficients configuration** file is (re)generated on every run and can be exposed by mapping - see examples bellow. 97 | 98 | ## Run it 99 | In order to run the simulation use the following or similiar command: 100 | ``` 101 | docker run \ 102 | -p 102:102 \ 103 | -v :/model.cid \ 104 | stinging/61850-sim 105 | ``` 106 | 107 | where *``* is path to IED model in any of [ICD, CID, or IID formats](https://en.wikipedia.org/wiki/Substation_Configuration_Language#Types_of_SCL_files). 108 | 109 | ## Examples 110 | 111 | **ABB CoreTec 4** 112 | 113 | *(port 102, frequency 10Hz / 0.1s, modeling logging, simulation logging)* 114 | 115 | ``` 116 | docker run -it --rm \ 117 | -p 102:102 \ 118 | -e SIMULATION_FREQUENCY=10 \ 119 | -e LOG_MODELING=true \ 120 | -e LOG_SIMULATION=true \ 121 | -v $(pwd)/res/TEC.scd:/model.cid \ 122 | stinging/61850-sim 123 | ``` 124 | 125 | **Hitachi Energy MSM (Modular Switchgear Monitoring)** 126 | 127 | *(port 55555 (on host), specific IED name 'MSM_Test_1', frequency 100Hz / 10ms, coefficient configuration)* 128 | 129 | ``` 130 | docker run -it --rm \ 131 | --network=host \ 132 | -e IED_NAME=MSM_Test_1 \ 133 | -e MMS_PORT=55555 \ 134 | -e SIMULATION_FREQUENCY=100 \ 135 | -v $(pwd)/res/MSM.scd:/model.cid \ 136 | -v $(pwd)/res/MSM.config.xml:/config.xml \ 137 | stinging/61850-sim 138 | ``` 139 | 140 | **Schneider Electric PowerLogic ION7550** 141 | 142 | *(port 1000, frequency 1kHz / 1ms, authentication with password 'abcd123', coefficient configuration)* 143 | 144 | ``` 145 | docker run -it --rm \ 146 | -p 1000:102 \ 147 | -e SIMULATION_FREQUENCY=1000 \ 148 | -e LOG_MODELING=true \ 149 | -e AUTH_PASSWORD=abc123 \ 150 | -v $(pwd)/res/ION.icd:/model.cid \ 151 | -v $(pwd)/res/ION.config.xml:/config.xml:ro \ 152 | stinging/61850-sim 153 | ``` 154 | 155 | **Schneider Electric PowerLogic PM8000** 156 | 157 | *(frequency 1Hz / 1s, simulation logging)* 158 | 159 | ``` 160 | docker run -it --rm \ 161 | -e SIMULATION_FREQUENCY=1 \ 162 | -e LOG_SIMULATION=true \ 163 | -v $(pwd)/res/PM.icd:/model.cid \ 164 | stinging/61850-sim 165 | ``` 166 | 167 | ### As a part of docker compose: 168 | 169 | *(specific IED name 'DEV03', frequency 5Hz / 200ms, modeling logging, simulation logging, internal network and specific IP 10.10.0.201)* 170 | 171 | ``` 172 | iec61850-sim-node-03: 173 | image: stinging/61850-sim 174 | container_name: iec61850-sim-node-03 175 | tty: true 176 | restart: unless-stopped 177 | volumes: 178 | - /opt/61850-sim/DEV.scd:/model.cid 179 | environment: 180 | IED_NAME: DEV03 181 | LOG_MODELING: "true" 182 | LOG_SIMULATION: "true" 183 | SIMULATION_FREQUENCY: 5 184 | networks: 185 | iec61850-sim-net: 186 | ipv4_address: 10.10.0.201 187 | ``` 188 | 189 | ## Demo servers 190 | 191 | - Schneider Electric PowerLogic PM8000 192 | 193 | **server** fuzzy-61850-sim.sting.dev 194 | 195 | **port** 1001 196 | 197 | (*docker run -d --name=61850-sim-1001 --restart=unless-stopped -p 1001:102 -e LOG_SIMULATION=true -e SIMULATION_FREQUENCY=1 -v ~/61850-sim-res/PM.icd:/model.cid:ro stinging/61850-sim:1.0*) 198 | 199 | - Schneider Electric PowerLogic ION7550 200 | 201 | **server** fuzzy-61850-sim.sting.dev 202 | 203 | **port** 1002 204 | 205 | **password** Kr0j@c 206 | 207 | (*docker run -d --name=61850-sim-1002 --restart=unless-stopped -p 1002:102 -e AUTH_PASSWORD=Kr0j@c -e SIMULATION_FREQUENCY=5 -v ~/61850-sim-res/ION.icd:/model.cid:ro stinging/61850-sim:1.0*) 208 | 209 | ## Third-party components 210 | This code base uses **libIEC61850** library. More documentation can be found online at http://libiec61850.com. 211 | 212 | ## Future ideas 213 | - introduction of FML (https://en.wikipedia.org/wiki/Fuzzy_markup_language) based simulation definition 214 | - support for Data Sets, Reporting, ... (https://www.beanit.com/iec-61850/tutorial/) -------------------------------------------------------------------------------- /docker-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | LOCAL_IP=$(hostname -i |grep -E -oh '((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])'|head -n 1) 4 | 5 | if [ -z "$IED_NAME" ]; then 6 | export IED_NAME="IED" 7 | fi 8 | 9 | if [ -z "$MMS_PORT" ]; then 10 | export MMS_PORT=102 11 | fi 12 | 13 | if [ -z "$IEC_61850_EDITION" ]; then 14 | export IEC_61850_EDITION=1 15 | fi 16 | 17 | if [ -z "$MAX_MMS_CONNECTIONS" ]; then 18 | export MAX_MMS_CONNECTIONS=10 19 | fi 20 | 21 | if [ -z "$MAX_DATA_POINTS" ]; then 22 | export MAX_DATA_POINTS=10000 23 | fi 24 | 25 | cd /opt 26 | 27 | echo "Compiling IED model..." 28 | java -jar tools/model-generator/genmodel.jar ../model.cid -out src/static_model 29 | 30 | echo "Compiling simulation..." 31 | cc -pthread -I./include -I/usr/include/libxml2/ -L./lib -L/usr/lib -DIEC_61850_EDITION=$IEC_61850_EDITION -DMAX_MMS_CONNECTIONS=$MAX_MMS_CONNECTIONS -DMAX_DATA_POINTS=$MAX_DATA_POINTS -o 61850-sim ./src/61850-sim.c ./src/static_model.c -liec61850 -lxml2 -lm 32 | 33 | echo "Preparing simulation..." 34 | chmod +x /opt/61850-sim 35 | #file /opt/61850-sim 36 | 37 | echo "Running simulation..." 38 | exec /opt/61850-sim -------------------------------------------------------------------------------- /include/goose_publisher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * goose_publisher.h 3 | * 4 | * Copyright 2013-2020 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef GOOSE_PUBLISHER_H_ 25 | #define GOOSE_PUBLISHER_H_ 26 | 27 | #include "iec61850_common.h" 28 | #include "linked_list.h" 29 | #include "mms_value.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #ifndef GOOSE_SV_COMM_PARAMETERS 36 | #define GOOSE_SV_COMM_PARAMETERS 37 | 38 | typedef struct sCommParameters { 39 | uint8_t vlanPriority; 40 | uint16_t vlanId; 41 | uint16_t appId; 42 | uint8_t dstAddress[6]; 43 | } CommParameters; 44 | 45 | #endif 46 | 47 | typedef struct sGoosePublisher* GoosePublisher; 48 | 49 | /** 50 | * \brief Create a new GoosePublisher instance 51 | * 52 | * NOTE: The created GoosePublisher instance uses VLAN tags 53 | * 54 | * \param parameters GOOSE communication parameters 55 | * \param interfaceId name of the Ethernet interface to use (e.g. "eth0") 56 | */ 57 | LIB61850_API GoosePublisher 58 | GoosePublisher_create(CommParameters* parameters, const char* interfaceID); 59 | 60 | /** 61 | * \brief Create a new GoosePublisher instance 62 | * 63 | * \param parameters GOOSE communication parameters 64 | * \param interfaceId name of the Ethernet interface to use (e.g. "eth0") 65 | * \param useVlanTag enable or disable the usage of VLAN tags in GOOSE messages 66 | */ 67 | LIB61850_API GoosePublisher 68 | GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, bool useVlanTag); 69 | 70 | /** 71 | * \brief Release all resources of the GoosePublisher instance 72 | * 73 | * \param self GoosePublisher instance 74 | */ 75 | LIB61850_API void 76 | GoosePublisher_destroy(GoosePublisher self); 77 | 78 | /** 79 | * \brief Publish a GOOSE message 80 | * 81 | * NOTE: This function also increased the sequence number of the GOOSE publisher 82 | * 83 | * \param self GoosePublisher instance 84 | * \param dataSet the GOOSE data set to send 85 | */ 86 | LIB61850_API int 87 | GoosePublisher_publish(GoosePublisher self, LinkedList dataSet); 88 | 89 | /** 90 | * \brief Publish a GOOSE message and store the sent message in the provided buffer 91 | * 92 | * \param self GoosePublisher instance 93 | * \param dataSet the GOOSE data set to send 94 | * \param msgBuf to store the sent message 95 | * \param[out] msgLen the length of the sent message 96 | * \param bufSize the size of the buffer to store the sent message 97 | */ 98 | LIB61850_API int 99 | GoosePublisher_publishAndDump(GoosePublisher self, LinkedList dataSet, char* msgBuf, int32_t* msgLen, int32_t bufSize); 100 | 101 | /** 102 | * \brief Sets the GoID used by the GoosePublisher instance 103 | * 104 | * \param self GoosePublisher instance 105 | * \param goID the GoId string 106 | */ 107 | LIB61850_API void 108 | GoosePublisher_setGoID(GoosePublisher self, char* goID); 109 | 110 | /** 111 | * \brief Sets the GoCB reference used by the GoosePublisher instance 112 | * 113 | * \param self GoosePublisher instance 114 | * \param goCbRef the GoCB reference string 115 | */ 116 | LIB61850_API void 117 | GoosePublisher_setGoCbRef(GoosePublisher self, char* goCbRef); 118 | 119 | /** 120 | * \brief Sets the time allowed to live value of the GOOSE messages 121 | * 122 | * \param self GoosePublisher instance 123 | * \param timeAllowedToLive the time allowed to live value in milliseconds 124 | */ 125 | LIB61850_API void 126 | GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToLive); 127 | 128 | /** 129 | * \brief Sets the data set reference used by the GoosePublisher instance 130 | * 131 | * \param self GoosePublisher instance 132 | * \param dataSetRef the data set reference string 133 | */ 134 | LIB61850_API void 135 | GoosePublisher_setDataSetRef(GoosePublisher self, char* dataSetRef); 136 | 137 | /** 138 | * \brief Sets the configuration revision used by the GoosePublisher instance 139 | * 140 | * \param self GoosePublisher instance 141 | * \param confRev the configuration revision value 142 | */ 143 | LIB61850_API void 144 | GoosePublisher_setConfRev(GoosePublisher self, uint32_t confRev); 145 | 146 | /** 147 | * \brief Sets simulation flag in sent GOOSE messages 148 | * 149 | * \param self GoosePublisher instance 150 | * \param simulation the value of the simulation flag 151 | */ 152 | LIB61850_API void 153 | GoosePublisher_setSimulation(GoosePublisher self, bool simulation); 154 | 155 | /** 156 | * \brief Manually sets the state number (stNum) of the GoosePublisher instance 157 | * 158 | * NOTE: Only for testing! Use \ref GoosePublisher_increaseStNum instead whenever 159 | * a data set member changes. 160 | * 161 | * \param self GoosePublisher instance 162 | * \param stNum the state number of the next GOOSE message to send 163 | */ 164 | LIB61850_API void 165 | GoosePublisher_setStNum(GoosePublisher self, uint32_t stNum); 166 | 167 | /** 168 | * \brief Manually sets the sequence number (sqNum) of the GoosePublisher instance 169 | * 170 | * NOTE: Only for testing! The sequence number is increase manually whenever \ref GoosePublisher_publish is called. 171 | * 172 | * \param self GoosePublisher instance 173 | * \param stNum the state number of the next GOOSE message to send 174 | */ 175 | LIB61850_API void 176 | GoosePublisher_setSqNum(GoosePublisher self, uint32_t sqNum); 177 | 178 | /** 179 | * \brief Sets the needs commission flag in sent GOOSE messages 180 | * 181 | * \param self GoosePublisher instance 182 | * \param ndsCom the value of the needs commission flag 183 | */ 184 | LIB61850_API void 185 | GoosePublisher_setNeedsCommission(GoosePublisher self, bool ndsCom); 186 | 187 | /** 188 | * \brief Increase the state number (stNum) of the GoosePublisher instance 189 | * 190 | * The state number should be increased whenever a member of the GOOSE data set changed 191 | * 192 | * NOTE: This function also resets the sequence number (sqNum) 193 | * 194 | * \param self GoosePublisher instance 195 | */ 196 | LIB61850_API uint64_t 197 | GoosePublisher_increaseStNum(GoosePublisher self); 198 | 199 | /** 200 | * \brief Reset state and sequence number of the GoosePublisher instance 201 | * 202 | * This function will set the state number (stNum) to 1 and the sequence number (sqNum) to 0. 203 | * 204 | * \param self GoosePublisher instance 205 | */ 206 | LIB61850_API void 207 | GoosePublisher_reset(GoosePublisher self); 208 | 209 | #ifdef __cplusplus 210 | } 211 | #endif 212 | 213 | #endif /* GOOSE_PUBLISHER_H_ */ 214 | -------------------------------------------------------------------------------- /include/goose_receiver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * goose_receiver.h 3 | * 4 | * Copyright 2014-2019 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef GOOSE_RECEIVER_H_ 25 | #define GOOSE_RECEIVER_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | 33 | #include "hal_ethernet.h" 34 | #include "goose_subscriber.h" 35 | 36 | /** 37 | * \addtogroup goose_api_group 38 | */ 39 | /**@{*/ 40 | 41 | typedef struct sGooseReceiver* GooseReceiver; 42 | 43 | /** 44 | * \brief Create a new receiver instance 45 | * 46 | * A GooseReceiver instance is used to handle all GOOSE messages received on a specific 47 | * network interface. 48 | * 49 | * \return the new GooseReceiver instance 50 | */ 51 | LIB61850_API GooseReceiver 52 | GooseReceiver_create(void); 53 | 54 | /** 55 | * \brief Create a new receiver instance using the provided buffer instead of allocating an own buffer 56 | * 57 | * A GooseReceiver instance is used to handle all GOOSE messages received on a specific 58 | * network interface. 59 | * 60 | * \param buffer buffer to store Ethernet messages or NULL when using \ref GooseReceiver_handleMessage 61 | * 62 | * \return the new GooseReceiver instance 63 | */ 64 | LIB61850_API GooseReceiver 65 | GooseReceiver_createEx(uint8_t* buffer); 66 | 67 | /** 68 | * \brief sets the interface for the GOOSE receiver 69 | * 70 | * \param self the GooseReceiver instance 71 | * \param interfaceId 72 | */ 73 | LIB61850_API void 74 | GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId); 75 | 76 | /** 77 | * \brief return the interface ID used by the GOOSE receiver 78 | * 79 | * \param self the GosseReceiver instance 80 | * 81 | * \return the Ethernet interface ID string 82 | */ 83 | LIB61850_API const char* 84 | GooseReceiver_getInterfaceId(GooseReceiver self); 85 | 86 | /** 87 | * \brief Add a subscriber to this receiver instance 88 | * 89 | * NOTE: Do not call this function while the receiver is running (after GooseReceiver_start 90 | * has been called)! 91 | * 92 | * \param self the GooseReceiver instance 93 | * \param subscriber the GooseSubscriber instance to add 94 | */ 95 | LIB61850_API void 96 | GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber); 97 | 98 | /** 99 | * \brief Remove a subscriber from this receiver instance 100 | * 101 | * NOTE: Do not call this function while the receiver is running (after GooseReceiver_start 102 | * has been called)! 103 | * 104 | * \param self the GooseReceiver instance 105 | * \param subscriber the GooseSubscriber instance to remove 106 | */ 107 | LIB61850_API void 108 | GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber); 109 | 110 | /** 111 | * \brief start the GOOSE receiver in a separate thread 112 | * 113 | * \param self the GooseReceiver instance 114 | */ 115 | LIB61850_API void 116 | GooseReceiver_start(GooseReceiver self); 117 | 118 | /** 119 | * \brief stop the GOOSE receiver running in a separate thread 120 | * 121 | * This function is used to stop the receiver thread started with GooseReceiver_start 122 | * 123 | * \param self the GooseReceiver instance 124 | */ 125 | LIB61850_API void 126 | GooseReceiver_stop(GooseReceiver self); 127 | 128 | /** 129 | * \brief Check if GOOSE receiver is running 130 | * 131 | * Can be used to check if \ref GooseReceiver_start has been successful. 132 | * 133 | * \param self the GooseReceiver instance 134 | * 135 | * \return true if GOOSE receiver is running, false otherwise 136 | */ 137 | LIB61850_API bool 138 | GooseReceiver_isRunning(GooseReceiver self); 139 | 140 | /** 141 | * \brief Free all resource of the GooseReceiver and all installed GooseSubscribers 142 | * 143 | * \param self the GooseReceiver instance 144 | */ 145 | LIB61850_API void 146 | GooseReceiver_destroy(GooseReceiver self); 147 | 148 | /*************************************** 149 | * Functions for non-threaded operation 150 | ***************************************/ 151 | LIB61850_API EthernetSocket 152 | GooseReceiver_startThreadless(GooseReceiver self); 153 | 154 | LIB61850_API void 155 | GooseReceiver_stopThreadless(GooseReceiver self); 156 | 157 | /** 158 | * \brief Parse GOOSE messages if they are available 159 | * 160 | * Call after reception of an Ethernet frame or periodically 161 | * 162 | * \param self the receiver object 163 | * 164 | * \return true if a message was available and has been parsed, false otherwise 165 | */ 166 | LIB61850_API bool 167 | GooseReceiver_tick(GooseReceiver self); 168 | 169 | /** 170 | * \brief Parse a GOOSE message 171 | * 172 | * Call after reception of an Ethernet frame (can be used as an alternative to \ref GooseReceiver_tick 173 | * to avoid implementing the Ethernet HAL) 174 | * 175 | * \param self the receiver object 176 | * \param buffer a buffer containing the complete Ethernet message 177 | * \param size size of the Ethernet message 178 | */ 179 | LIB61850_API void 180 | GooseReceiver_handleMessage(GooseReceiver self, uint8_t* buffer, int size); 181 | 182 | /**@}*/ 183 | 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | 188 | 189 | #endif /* GOOSE_RECEIVER_H_ */ 190 | -------------------------------------------------------------------------------- /include/goose_subscriber.h: -------------------------------------------------------------------------------- 1 | /* 2 | * goose_subscriber.h 3 | * 4 | * Copyright 2013-2018 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef GOOSE_SUBSCRIBER_H_ 25 | #define GOOSE_SUBSCRIBER_H_ 26 | 27 | #include "libiec61850_common_api.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /** 34 | * \defgroup goose_api_group IEC 61850 GOOSE subscriber API 35 | */ 36 | /**@{*/ 37 | 38 | #include "mms_value.h" 39 | 40 | typedef enum 41 | { 42 | GOOSE_PARSE_ERROR_NO_ERROR = 0, 43 | GOOSE_PARSE_ERROR_UNKNOWN_TAG, 44 | GOOSE_PARSE_ERROR_TAGDECODE, 45 | GOOSE_PARSE_ERROR_SUBLEVEL, 46 | GOOSE_PARSE_ERROR_OVERFLOW, 47 | GOOSE_PARSE_ERROR_UNDERFLOW, 48 | GOOSE_PARSE_ERROR_TYPE_MISMATCH, 49 | GOOSE_PARSE_ERROR_LENGTH_MISMATCH, 50 | } GooseParseError; 51 | 52 | typedef struct sGooseSubscriber* GooseSubscriber; 53 | 54 | /** 55 | * \brief user provided callback function that will be invoked when a GOOSE message is received. 56 | * 57 | * \param subscriber the subscriber object that invoked the callback function, 58 | * \param parameter a user provided parameter that will be passed to the callback function 59 | */ 60 | typedef void (*GooseListener)(GooseSubscriber subscriber, void* parameter); 61 | 62 | /** 63 | * \brief create a new GOOSE subscriber instance. 64 | * 65 | * A new GOOSE subscriber will be created and connected to a specific GOOSE control block reference. 66 | * 67 | * The parameter goCbRef has to be given in MMS like notation (as it also will appear in the GOOSE message 68 | * sent by the publisher). An example could be "simpleIOGenericIO/LLN0$GO$gcbEvents". 69 | * 70 | * The data set values contained in a GOOSE message will be written to the optionally provided MmsValue instance. 71 | * The MmsValue object has to be of type MMS_ARRAY. The array elements need to be of the same type as 72 | * the data set elements. It is intended that the provided MmsValue instance has been created by the 73 | * IedConnection_getDataSet() method before. 74 | * 75 | * If NULL is given as dataSetValues it will be created the first time when a appropriate GOOSE message 76 | * is received. 77 | * 78 | * \param goCbRef a string containing the object reference of the GOOSE Control Block (GoCB) in MMS notation the 79 | * GOOSE publisher uses. 80 | * \param dataSetValues the MmsValue object where the data set values will be written or NULL. 81 | */ 82 | LIB61850_API GooseSubscriber 83 | GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues); 84 | 85 | LIB61850_API char* 86 | GooseSubscriber_getGoId(GooseSubscriber self); 87 | 88 | LIB61850_API char* 89 | GooseSubscriber_getGoCbRef(GooseSubscriber self); 90 | 91 | LIB61850_API char* 92 | GooseSubscriber_getDataSet(GooseSubscriber self); 93 | 94 | /** 95 | * \brief set the destination mac address used by the subscriber to filter relevant messages. 96 | * 97 | * If dstMac is set the subscriber will ignore all messages with other dstMac values. 98 | * 99 | * \param self GooseSubscriber instance to operate on. 100 | * \param dstMac the destination mac address 101 | */ 102 | LIB61850_API void 103 | GooseSubscriber_setDstMac(GooseSubscriber self, uint8_t dstMac[6]); 104 | 105 | /** 106 | * \brief set the APPID used by the subscriber to filter relevant messages. 107 | * 108 | * If APPID is set the subscriber will ignore all messages with other APPID values. 109 | * 110 | * \param self GooseSubscriber instance to operate on. 111 | * \param appId the APPID value the subscriber should use to filter messages 112 | */ 113 | LIB61850_API void 114 | GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId); 115 | 116 | /** 117 | * \brief Check if subscriber state is valid 118 | * 119 | * A GOOSE subscriber is valid if TimeAllowedToLive timeout is not elapsed and GOOSE 120 | * message were received with correct state and sequence ID. 121 | * 122 | */ 123 | LIB61850_API bool 124 | GooseSubscriber_isValid(GooseSubscriber self); 125 | 126 | /** 127 | * \brief Get parse error in case of invalid subscriber state 128 | * 129 | * \param self GooseSubscriber instance to operate on. 130 | * 131 | * \return the error code representing a message parse problem of the last received message 132 | */ 133 | LIB61850_API GooseParseError 134 | GooseSubscriber_getParseError(GooseSubscriber self); 135 | 136 | LIB61850_API void 137 | GooseSubscriber_destroy(GooseSubscriber self); 138 | 139 | /** 140 | * \brief set a callback function that will be invoked when a GOOSE message has been received. 141 | * 142 | * \param self GooseSubscriber instance to operate on. 143 | * \param listener user provided callback function 144 | * \param parameter a user provided parameter that will be passed to the callback function 145 | */ 146 | LIB61850_API void 147 | GooseSubscriber_setListener(GooseSubscriber self, GooseListener listener, void* parameter); 148 | 149 | LIB61850_API int32_t 150 | GooseSubscriber_getAppId(GooseSubscriber self); 151 | 152 | LIB61850_API void 153 | GooseSubscriber_getSrcMac(GooseSubscriber self, uint8_t *buffer); 154 | 155 | LIB61850_API void 156 | GooseSubscriber_getDstMac(GooseSubscriber self, uint8_t *buffer); 157 | /** 158 | * \brief return the state number (stNum) of the last received GOOSE message. 159 | * 160 | * The state number is increased if any of the values in the GOOSE data set changed due to a valid trigger condition 161 | * 162 | * \param self GooseSubscriber instance to operate on. 163 | * 164 | * \return the state number of the last received GOOSE message 165 | */ 166 | LIB61850_API uint32_t 167 | GooseSubscriber_getStNum(GooseSubscriber self); 168 | 169 | /** 170 | * \brief return the sequence number (sqNum) of the last received GOOSE message. 171 | * 172 | * The sequence number is increased for every consecutive GOOSE message without state change. When a state change occurs (stNum is increased) 173 | * then the sequence number (sqNum) will be reset. 174 | * 175 | * \param self GooseSubscriber instance to operate on. 176 | * 177 | * \return the sequence number of the last received GOOSE message 178 | */ 179 | LIB61850_API uint32_t 180 | GooseSubscriber_getSqNum(GooseSubscriber self); 181 | 182 | /** 183 | * \brief returns the test flag of the last received GOOSE message 184 | * 185 | * IMPORTANT: Goose messages with test=TRUE have to be ignored to be standard compliant! 186 | * 187 | * \param self GooseSubscriber instance to operate on. 188 | * 189 | * \return the state of the test flag of the last received GOOSE message. 190 | */ 191 | LIB61850_API bool 192 | GooseSubscriber_isTest(GooseSubscriber self); 193 | 194 | /** 195 | * \brief returns the confRev value of the last received GOOSE message 196 | * 197 | * \param self GooseSubscriber instance to operate on. 198 | * 199 | * \return the confRev value of the last received GOOSE message. If the message does not contain such 200 | * a value the result is always 0 201 | */ 202 | LIB61850_API uint32_t 203 | GooseSubscriber_getConfRev(GooseSubscriber self); 204 | 205 | /** 206 | * \brief returns the value of the ndsCom (needs commission) flag of the last received GOOSE message. 207 | * 208 | * IMPORTANT: Goose messages with ndsCom=TRUE have to be ignored to be standard compliant! 209 | * 210 | * \param self GooseSubscriber instance to operate on. 211 | * 212 | * \return the state of the ndsCom flag of the last received GOOSE message. 213 | * 214 | */ 215 | LIB61850_API bool 216 | GooseSubscriber_needsCommission(GooseSubscriber self); 217 | 218 | /** 219 | * \brief Get the TimeAllowedToLive value of the last received message. 220 | * 221 | * \param self GooseSubscriber instance to operate on. 222 | * 223 | * \return the TimeAllowedToLive value of the last received GOOSE message in milliseconds. 224 | */ 225 | LIB61850_API uint32_t 226 | GooseSubscriber_getTimeAllowedToLive(GooseSubscriber self); 227 | 228 | /** 229 | * \brief Get the timestamp of the last received message. 230 | * 231 | * \param self GooseSubscriber instance to operate on. 232 | * 233 | * \return the timestamp value of the last received GOOSE message in milliseconds since epoch (1.1.1970 UTC). 234 | */ 235 | LIB61850_API uint64_t 236 | GooseSubscriber_getTimestamp(GooseSubscriber self); 237 | 238 | /** 239 | * \brief get the data set values received with the last report 240 | * 241 | * Note: To prevent data corruption. The MmsValue instance received should 242 | * only be used inside of the callback function, when the GOOSE receiver is 243 | * running in a separate thread. 244 | * 245 | * \param self GooseSubscriber instance to operate on. 246 | * 247 | * \return MmsValue instance of the report data set 248 | */ 249 | LIB61850_API MmsValue* 250 | GooseSubscriber_getDataSetValues(GooseSubscriber self); 251 | 252 | LIB61850_API bool 253 | GooseSubscriber_isVlanSet(GooseSubscriber self); 254 | 255 | LIB61850_API uint16_t 256 | GooseSubscriber_getVlanId(GooseSubscriber self); 257 | 258 | LIB61850_API uint8_t 259 | GooseSubscriber_getVlanPrio(GooseSubscriber self); 260 | 261 | /** 262 | * \brief Configure the Subscriber to listen to any received GOOSE message 263 | * 264 | * NOTE: When the observer flag is set the subscriber also has access to the 265 | * goCbRef, goId, and datSet values of the received GOOSE message 266 | */ 267 | LIB61850_API void 268 | GooseSubscriber_setObserver(GooseSubscriber self); 269 | #ifdef __cplusplus 270 | } 271 | #endif 272 | 273 | 274 | /**@}*/ 275 | 276 | #endif /* GOOSE_SUBSCRIBER_H_ */ 277 | -------------------------------------------------------------------------------- /include/hal_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hal_base.h 3 | * 4 | * Copyright 2018 MZ Automation GmbH 5 | * 6 | * This file is part of Platform Abstraction Layer (libpal) 7 | * for libiec61850 and lib60870. 8 | * 9 | * libpal is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * libpal is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with libpal. If not, see . 21 | * 22 | * See COPYING file for the complete license text. 23 | */ 24 | 25 | #ifndef HAL_INC_HAL_BASE_H_ 26 | #define HAL_INC_HAL_BASE_H_ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifdef __GNUC__ 35 | #define ATTRIBUTE_PACKED __attribute__ ((__packed__)) 36 | #else 37 | #define ATTRIBUTE_PACKED 38 | #endif 39 | 40 | #ifndef DEPRECATED 41 | #if defined(__GNUC__) || defined(__clang__) 42 | #define DEPRECATED __attribute__((deprecated)) 43 | #else 44 | #define DEPRECATED 45 | #endif 46 | #endif 47 | 48 | #if defined _WIN32 || defined __CYGWIN__ 49 | #ifdef EXPORT_FUNCTIONS_FOR_DLL 50 | #define PAL_API __declspec(dllexport) 51 | #else 52 | #define PAL_API 53 | #endif 54 | 55 | #define PAL_INTERNAL 56 | #else 57 | #if __GNUC__ >= 4 58 | #define PAL_API __attribute__ ((visibility ("default"))) 59 | #define PAL_INTERNAL __attribute__ ((visibility ("hidden"))) 60 | #else 61 | #define PAL_API 62 | #define PAL_INTERNAL 63 | #endif 64 | #endif 65 | 66 | #endif /* HAL_INC_HAL_BASE_H_ */ 67 | -------------------------------------------------------------------------------- /include/hal_filesystem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * filesystem_hal.h 3 | * 4 | * Copyright 2014 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef FILESYSTEM_HAL_H_ 25 | #define FILESYSTEM_HAL_H_ 26 | 27 | #include "hal_base.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /*! \addtogroup hal 34 | * 35 | * @{ 36 | */ 37 | 38 | /** 39 | * @defgroup HAL_FILESYSTEM Interface to the native file system (optional) 40 | * 41 | * @{ 42 | */ 43 | 44 | typedef void* FileHandle; 45 | typedef struct sDirectoryHandle* DirectoryHandle; 46 | 47 | #ifndef CONFIG_SYSTEM_FILE_SEPARATOR 48 | #define CONFIG_SYSTEM_FILE_SEPARATOR '/' 49 | #endif 50 | 51 | /** 52 | * \brief open a file 53 | * 54 | * \param pathName full name (path + filename) of the file 55 | * \param readWrite true opens the file with read and write access - false opens for read access only 56 | * 57 | * \return a handle for the file. Has to be used by subsequent calls to file functions to identify the file or 58 | * NULL if opening fails 59 | */ 60 | PAL_API FileHandle 61 | FileSystem_openFile(char* pathName, bool readWrite); 62 | 63 | /** 64 | * \brief read from an open file 65 | * 66 | * This function will read the next block of the file. The maximum number of bytes to read 67 | * is given. A call to this function will move the file position by the number of bytes read. 68 | * If the file position reaches the end of file then subsequent calls of this function shall 69 | * return 0. 70 | * 71 | * \param handle the file handle to identify the file 72 | * \param buffer the buffer to write the read data 73 | * \param maxSize maximum number of bytes to read 74 | * 75 | * \return the number of bytes actually read 76 | */ 77 | PAL_API int 78 | FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize); 79 | 80 | /** 81 | * \brief write to an open file 82 | * 83 | * \param handle the file handle to identify the file 84 | * \param buffer the buffer with the data to write 85 | * \param size the number of bytes to write 86 | * 87 | * \return the number of bytes actually written 88 | */ 89 | PAL_API int 90 | FileSystem_writeFile(FileHandle handle, uint8_t* buffer, int size); 91 | 92 | /** 93 | * \brief close an open file 94 | * 95 | * \param handle the file handle to identify the file 96 | */ 97 | PAL_API void 98 | FileSystem_closeFile(FileHandle handle); 99 | 100 | /** 101 | * \brief return attributes of the given file 102 | * 103 | * This function is used by the MMS layer to determine basic file attributes. 104 | * The size of the file has to be returned in bytes. The timestamp of the last modification has 105 | * to be returned as milliseconds since Unix epoch - or 0 if this function is not supported. 106 | * 107 | * \param pathName full name (path + filename) of the file 108 | * \param fileSize a pointer where to store the file size 109 | * \param lastModificationTimestamp is used to store the timestamp of last modification of the file 110 | * 111 | * \return true if file exists, false if not 112 | */ 113 | PAL_API bool 114 | FileSystem_getFileInfo(char* filename, uint32_t* fileSize, uint64_t* lastModificationTimestamp); 115 | 116 | /** 117 | * \brief delete a file 118 | * 119 | * \param pathName full name (path + filename) of the file 120 | * 121 | * \return true on success, false on error 122 | */ 123 | PAL_API bool 124 | FileSystem_deleteFile(char* filename); 125 | 126 | /** 127 | * \brief rename a file 128 | * 129 | * \param oldFileName current full name (path + filename) of the file 130 | * \param newFileName new full name (path + filename) of the file 131 | * 132 | * \return true on success, false on error 133 | */ 134 | PAL_API bool 135 | FileSystem_renameFile(char* oldFilename, char* newFilename); 136 | 137 | /** 138 | * \brief open the directoy with the specified name 139 | * 140 | * \param directoryName 141 | * 142 | * \return a handle for the opened directory to be used in subsequent calls to identify the directory 143 | */ 144 | PAL_API DirectoryHandle 145 | FileSystem_openDirectory(char* directoryName); 146 | 147 | /** 148 | * \brief read the next directory entry 149 | * 150 | * This function returns the next directory entry. The entry is only a valid pointer as long as the 151 | * FileSystem_closeDirectory or another FileSystem_readDirectory function is not called for the given 152 | * DirectoryHandle. 153 | * 154 | * \param directory the handle to identify the directory 155 | * \param isDirectory return value that indicates if the directory entry is itself a directory (true) 156 | * 157 | * \return the name of the directory entry 158 | */ 159 | PAL_API char* 160 | FileSystem_readDirectory(DirectoryHandle directory, bool* isDirectory); 161 | 162 | 163 | /** 164 | * \brief close a directory 165 | * 166 | * \param directory the handle to identify the directory 167 | */ 168 | PAL_API void 169 | FileSystem_closeDirectory(DirectoryHandle directory); 170 | 171 | 172 | /*! @} */ 173 | 174 | /*! @} */ 175 | 176 | #ifdef __cplusplus 177 | } 178 | #endif 179 | 180 | #endif /* FILESYSTEM_HAL_H_ */ 181 | -------------------------------------------------------------------------------- /include/hal_thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * thread_hal.h 3 | * 4 | * Multi-threading abstraction layer 5 | * 6 | * Copyright 2013-2018 Michael Zillgith 7 | * 8 | * This file is part of libIEC61850. 9 | * 10 | * libIEC61850 is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * libIEC61850 is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with libIEC61850. If not, see . 22 | * 23 | * See COPYING file for the complete license text. 24 | */ 25 | 26 | #ifndef THREAD_HAL_H_ 27 | #define THREAD_HAL_H_ 28 | 29 | #include "hal_base.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /** 36 | * \file hal_thread.h 37 | * \brief Abstraction layer for threading and synchronization 38 | */ 39 | 40 | /*! \addtogroup hal 41 | * 42 | * @{ 43 | */ 44 | 45 | /** 46 | * @defgroup HAL_THREAD Threading and synchronization API 47 | * 48 | * @{ 49 | */ 50 | 51 | /** Opaque reference of a Thread instance */ 52 | typedef struct sThread* Thread; 53 | 54 | /** Qpaque reference of a Semaphore instance */ 55 | typedef void* Semaphore; 56 | 57 | /** Reference to a function that is called when starting the thread */ 58 | typedef void* (*ThreadExecutionFunction) (void*); 59 | 60 | /** 61 | * \brief Create a new Thread instance 62 | * 63 | * \param function the entry point of the thread 64 | * \param parameter a parameter that is passed to the threads start function 65 | * \param autodestroy the thread is automatically destroyed if the ThreadExecutionFunction has finished. 66 | * 67 | * \return the newly created Thread instance 68 | */ 69 | PAL_API Thread 70 | Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy); 71 | 72 | /** 73 | * \brief Start a Thread. 74 | * 75 | * This function invokes the start function of the thread. The thread terminates when 76 | * the start function returns. 77 | * 78 | * \param thread the Thread instance to start 79 | */ 80 | PAL_API void 81 | Thread_start(Thread thread); 82 | 83 | /** 84 | * \brief Destroy a Thread and free all related resources. 85 | * 86 | * \param thread the Thread instance to destroy 87 | */ 88 | PAL_API void 89 | Thread_destroy(Thread thread); 90 | 91 | /** 92 | * \brief Suspend execution of the Thread for the specified number of milliseconds 93 | */ 94 | PAL_API void 95 | Thread_sleep(int millies); 96 | 97 | PAL_API Semaphore 98 | Semaphore_create(int initialValue); 99 | 100 | /* Wait until semaphore value is greater than zero. Then decrease the semaphore value. */ 101 | PAL_API void 102 | Semaphore_wait(Semaphore self); 103 | 104 | PAL_API void 105 | Semaphore_post(Semaphore self); 106 | 107 | PAL_API void 108 | Semaphore_destroy(Semaphore self); 109 | 110 | /*! @} */ 111 | 112 | /*! @} */ 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | 118 | 119 | #endif /* THREAD_HAL_H_ */ 120 | -------------------------------------------------------------------------------- /include/hal_time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * time.c 3 | * 4 | * Copyright 2013-2020 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef HAL_C_ 25 | #define HAL_C_ 26 | 27 | #include "hal_base.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /** 34 | * \file hal_time.h 35 | * \brief Abstraction layer for system time access 36 | */ 37 | 38 | /*! \addtogroup hal 39 | * 40 | * @{ 41 | */ 42 | 43 | /** 44 | * @defgroup HAL_TIME Time related functions 45 | * 46 | * @{ 47 | */ 48 | 49 | typedef uint64_t nsSinceEpoch; 50 | typedef uint64_t msSinceEpoch; 51 | 52 | /** 53 | * Get the system time in milliseconds. 54 | * 55 | * The time value returned as 64-bit unsigned integer should represent the milliseconds 56 | * since the UNIX epoch (1970/01/01 00:00 UTC). 57 | * 58 | * \return the system time with millisecond resolution. 59 | */ 60 | PAL_API msSinceEpoch 61 | Hal_getTimeInMs(void); 62 | 63 | /** 64 | * Get the system time in nanoseconds. 65 | * 66 | * The time value returned as 64-bit unsigned integer should represent the nanoseconds 67 | * since the UNIX epoch (1970/01/01 00:00 UTC). 68 | * 69 | * \return the system time with nanosecond resolution. 70 | */ 71 | PAL_API nsSinceEpoch 72 | Hal_getTimeInNs(void); 73 | 74 | /** 75 | * Set the system time from ns time 76 | * 77 | * The time value returned as 64-bit unsigned integer should represent the nanoseconds 78 | * since the UNIX epoch (1970/01/01 00:00 UTC). 79 | * 80 | * \return true on success, otherwise false 81 | */ 82 | PAL_API bool 83 | Hal_setTimeInNs(nsSinceEpoch nsTime); 84 | 85 | /*! @} */ 86 | 87 | /*! @} */ 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | 93 | 94 | #endif /* HAL_C_ */ 95 | -------------------------------------------------------------------------------- /include/iec61850_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iec61850_common.h 3 | * 4 | * Copyright 2013-2019 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef IEC61850_COMMON_H_ 25 | #define IEC61850_COMMON_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | 32 | #include "libiec61850_common_api.h" 33 | #include "logging_api.h" 34 | #include "linked_list.h" 35 | 36 | /** 37 | * @defgroup iec61850_common_api_group IEC 61850 API common parts 38 | */ 39 | /**@{*/ 40 | 41 | /** IEC 61850 edition 1 */ 42 | #define IEC_61850_EDITION_1 0 43 | 44 | /** IEC 61850 edition 2 */ 45 | #define IEC_61850_EDITION_2 1 46 | 47 | /** IEC 61850 edition 2.1 */ 48 | #define IEC_61850_EDITION_2_1 2 49 | 50 | /** PhyComAddress type contains Ethernet address and VLAN attributes */ 51 | typedef struct { 52 | uint8_t vlanPriority; 53 | uint16_t vlanId; 54 | uint16_t appId; 55 | uint8_t dstAddress[6]; 56 | } PhyComAddress; 57 | 58 | /** 59 | * \brief Control model (represented by "ctlModel" attribute) 60 | */ 61 | typedef enum { 62 | /** 63 | * No support for control functions. Control object only support status information. 64 | */ 65 | CONTROL_MODEL_STATUS_ONLY = 0, 66 | 67 | /** 68 | * Direct control with normal security: Supports Operate, TimeActivatedOperate (optional), 69 | * and Cancel (optional). 70 | */ 71 | CONTROL_MODEL_DIRECT_NORMAL = 1, 72 | 73 | /** 74 | * Select before operate (SBO) with normal security: Supports Select, Operate, TimeActivatedOperate (optional), 75 | * and Cancel (optional). 76 | */ 77 | CONTROL_MODEL_SBO_NORMAL = 2, 78 | 79 | /** 80 | * Direct control with enhanced security (enhanced security includes the CommandTermination service) 81 | */ 82 | CONTROL_MODEL_DIRECT_ENHANCED = 3, 83 | 84 | /** 85 | * Select before operate (SBO) with enhanced security (enhanced security includes the CommandTermination service) 86 | */ 87 | CONTROL_MODEL_SBO_ENHANCED = 4 88 | } ControlModel; 89 | 90 | /** 91 | * @defgroup TRIGGER_OPTIONS Trigger options (bit values combinable) 92 | * 93 | * @{ 94 | */ 95 | 96 | /** Report will be triggered when data changes */ 97 | #define TRG_OPT_DATA_CHANGED 1 98 | 99 | /** Report will be triggered when quality changes */ 100 | #define TRG_OPT_QUALITY_CHANGED 2 101 | 102 | /** Report will be triggered when data is updated */ 103 | #define TRG_OPT_DATA_UPDATE 4 104 | 105 | /** Report will be triggered periodically */ 106 | #define TRG_OPT_INTEGRITY 8 107 | 108 | /** Report will be triggered by GI (general interrogation) request */ 109 | #define TRG_OPT_GI 16 110 | 111 | /** Report will be triggered only on rising edge (transient variable */ 112 | #define TRG_OPT_TRANSIENT 128 113 | /** @} */ 114 | 115 | 116 | 117 | /** 118 | * @defgroup REPORT_OPTIONS Report options (bit values combinable) 119 | * 120 | * @{ 121 | */ 122 | 123 | /** Report contains sequence number */ 124 | #define RPT_OPT_SEQ_NUM 1 125 | 126 | /** Report contains a report timestamp */ 127 | #define RPT_OPT_TIME_STAMP 2 128 | 129 | /** Report contains reason for inclusion value for each included data set member */ 130 | #define RPT_OPT_REASON_FOR_INCLUSION 4 131 | 132 | /** Report contains data set object reference */ 133 | #define RPT_OPT_DATA_SET 8 134 | 135 | /** Report contains data reference for each included data set member */ 136 | #define RPT_OPT_DATA_REFERENCE 16 137 | 138 | /** Report contains buffer overflow flag */ 139 | #define RPT_OPT_BUFFER_OVERFLOW 32 140 | 141 | /** Report contains entry id */ 142 | #define RPT_OPT_ENTRY_ID 64 143 | 144 | /** Report contains configuration revision */ 145 | #define RPT_OPT_CONF_REV 128 146 | /** @} */ 147 | 148 | /** 149 | * @defgroup ORIGINATOR_CATEGORIES Originator categories (orCat) 150 | * 151 | * @{ 152 | */ 153 | 154 | /** Not supported - should not be used */ 155 | #define CONTROL_ORCAT_NOT_SUPPORTED 0 156 | 157 | /** Control operation issued from an operator using a client located at bay level */ 158 | #define CONTROL_ORCAT_BAY_CONTROL 1 159 | 160 | /** Control operation issued from an operator using a client located at station level */ 161 | #define CONTROL_ORCAT_STATION_CONTROL 2 162 | 163 | /** Control operation from a remote operator outside the substation (for example network control center) */ 164 | #define CONTROL_ORCAT_REMOTE_CONTROL 3 165 | 166 | /** Control operation issued from an automatic function at bay level */ 167 | #define CONTROL_ORCAT_AUTOMATIC_BAY 4 168 | 169 | /** Control operation issued from an automatic function at station level */ 170 | #define CONTROL_ORCAT_AUTOMATIC_STATION 5 171 | 172 | /** Control operation issued from a automatic function outside of the substation */ 173 | #define CONTROL_ORCAT_AUTOMATIC_REMOTE 6 174 | 175 | /** Control operation issued from a maintenance/service tool */ 176 | #define CONTROL_ORCAT_MAINTENANCE 7 177 | 178 | /** Status change occurred without control action (for example external trip of a circuit breaker or failure inside the breaker) */ 179 | #define CONTROL_ORCAT_PROCESS 8 180 | 181 | /** @} */ 182 | 183 | /** 184 | * @defgroup CONTROL_ADD_CAUSE Definition for addCause type - used in control models 185 | * 186 | * @{ 187 | */ 188 | 189 | /** AddCause - additional cause information for control model errors */ 190 | typedef enum { 191 | ADD_CAUSE_UNKNOWN = 0, 192 | ADD_CAUSE_NOT_SUPPORTED = 1, 193 | ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2, 194 | ADD_CAUSE_SELECT_FAILED = 3, 195 | ADD_CAUSE_INVALID_POSITION = 4, 196 | ADD_CAUSE_POSITION_REACHED = 5, 197 | ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6, 198 | ADD_CAUSE_STEP_LIMIT = 7, 199 | ADD_CAUSE_BLOCKED_BY_MODE = 8, 200 | ADD_CAUSE_BLOCKED_BY_PROCESS = 9, 201 | ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10, 202 | ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11, 203 | ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12, 204 | ADD_CAUSE_BLOCKED_BY_HEALTH = 13, 205 | ADD_CAUSE_1_OF_N_CONTROL = 14, 206 | ADD_CAUSE_ABORTION_BY_CANCEL = 15, 207 | ADD_CAUSE_TIME_LIMIT_OVER = 16, 208 | ADD_CAUSE_ABORTION_BY_TRIP = 17, 209 | ADD_CAUSE_OBJECT_NOT_SELECTED = 18, 210 | ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19, 211 | ADD_CAUSE_NO_ACCESS_AUTHORITY = 20, 212 | ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21, 213 | ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22, 214 | ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23, 215 | ADD_CAUSE_ABORTION_BY_COMMAND = 24, 216 | ADD_CAUSE_NONE = 25, 217 | ADD_CAUSE_INCONSISTENT_PARAMETERS = 26, 218 | ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27 219 | } ControlAddCause; 220 | 221 | /** @} */ 222 | 223 | /** 224 | * @defgroup CONTROL_LAST_APPL_ERROR Definition for LastAppError error type - used in control models 225 | * 226 | * @{ 227 | */ 228 | 229 | typedef enum { 230 | CONTROL_ERROR_NO_ERROR = 0, 231 | CONTROL_ERROR_UNKNOWN = 1, 232 | CONTROL_ERROR_TIMEOUT_TEST = 2, 233 | CONTROL_ERROR_OPERATOR_TEST = 3 234 | } ControlLastApplError; 235 | 236 | /** @} */ 237 | 238 | /** 239 | * @defgroup FUNCTIONAL_CONSTRAINTS Definitions and functions related to functional constraints (FCs) 240 | * 241 | * @{ 242 | */ 243 | 244 | #if (CONFIG_PROVIDE_OLD_FC_DEFINES == 1) 245 | #define ST IEC61850_FC_ST 246 | #define MX IEC61850_FC_MX 247 | #define SP IEC61850_FC_SP 248 | #define SV IEC61850_FC_SV 249 | #define CF IEC61850_FC_CF 250 | #define DC IEC61850_FC_DC 251 | #define SG IEC61850_FC_SG 252 | #define SE IEC61850_FC_SE 253 | #define SR IEC61850_FC_SR 254 | #define OR IEC61850_FC_OR 255 | #define BL IEC61850_FC_BL 256 | #define EX IEC61850_FC_EX 257 | #define CO IEC61850_FC_CO 258 | #define ALL IEC61850_FC_ALL 259 | #define NONE IEC61850_FC_NONE 260 | #endif /* (CONFIG_PROVIDE_OLD_FC_DEFINES == 1) */ 261 | 262 | 263 | /** FCs (Functional constraints) according to IEC 61850-7-2 */ 264 | typedef enum eFunctionalConstraint { 265 | /** Status information */ 266 | IEC61850_FC_ST = 0, 267 | /** Measurands - analog values */ 268 | IEC61850_FC_MX = 1, 269 | /** Setpoint */ 270 | IEC61850_FC_SP = 2, 271 | /** Substitution */ 272 | IEC61850_FC_SV = 3, 273 | /** Configuration */ 274 | IEC61850_FC_CF = 4, 275 | /** Description */ 276 | IEC61850_FC_DC = 5, 277 | /** Setting group */ 278 | IEC61850_FC_SG = 6, 279 | /** Setting group editable */ 280 | IEC61850_FC_SE = 7, 281 | /** Service response / Service tracking */ 282 | IEC61850_FC_SR = 8, 283 | /** Operate received */ 284 | IEC61850_FC_OR = 9, 285 | /** Blocking */ 286 | IEC61850_FC_BL = 10, 287 | /** Extended definition */ 288 | IEC61850_FC_EX = 11, 289 | /** Control */ 290 | IEC61850_FC_CO = 12, 291 | /** Unicast SV */ 292 | IEC61850_FC_US = 13, 293 | /** Multicast SV */ 294 | IEC61850_FC_MS = 14, 295 | /** Unbuffered report */ 296 | IEC61850_FC_RP = 15, 297 | /** Buffered report */ 298 | IEC61850_FC_BR = 16, 299 | /** Log control blocks */ 300 | IEC61850_FC_LG = 17, 301 | /** Goose control blocks */ 302 | IEC61850_FC_GO = 18, 303 | 304 | /** All FCs - wildcard value */ 305 | IEC61850_FC_ALL = 99, 306 | IEC61850_FC_NONE = -1 307 | } FunctionalConstraint; 308 | 309 | /**extern "C" { 310 | * \brief convert a function constraint to a static string 311 | */ 312 | LIB61850_API char* 313 | FunctionalConstraint_toString(FunctionalConstraint fc); 314 | 315 | /** 316 | * \brief parse a string treated as a functional constraint representation 317 | */ 318 | LIB61850_API FunctionalConstraint 319 | FunctionalConstraint_fromString(const char* fcString); 320 | 321 | /** @} */ 322 | 323 | /** 324 | * @defgroup QUALITY Definitions and functions related to data attribute quality 325 | * 326 | * @{ 327 | */ 328 | 329 | 330 | typedef uint16_t Quality; 331 | typedef uint16_t Validity; 332 | 333 | #define QUALITY_VALIDITY_GOOD 0 334 | #define QUALITY_VALIDITY_INVALID 2 335 | #define QUALITY_VALIDITY_RESERVED 1 336 | #define QUALITY_VALIDITY_QUESTIONABLE 3 337 | 338 | #define QUALITY_DETAIL_OVERFLOW 4 339 | #define QUALITY_DETAIL_OUT_OF_RANGE 8 340 | #define QUALITY_DETAIL_BAD_REFERENCE 16 341 | #define QUALITY_DETAIL_OSCILLATORY 32 342 | #define QUALITY_DETAIL_FAILURE 64 343 | #define QUALITY_DETAIL_OLD_DATA 128 344 | #define QUALITY_DETAIL_INCONSISTENT 256 345 | #define QUALITY_DETAIL_INACCURATE 512 346 | 347 | #define QUALITY_SOURCE_SUBSTITUTED 1024 348 | 349 | #define QUALITY_TEST 2048 350 | 351 | #define QUALITY_OPERATOR_BLOCKED 4096 352 | 353 | #define QUALITY_DERIVED 8192 354 | 355 | LIB61850_API Validity 356 | Quality_getValidity(Quality* self); 357 | 358 | LIB61850_API void 359 | Quality_setValidity(Quality* self, Validity validity); 360 | 361 | LIB61850_API void 362 | Quality_setFlag(Quality* self, int flag); 363 | 364 | LIB61850_API void 365 | Quality_unsetFlag(Quality* self, int flag); 366 | 367 | LIB61850_API bool 368 | Quality_isFlagSet(Quality* self, int flag); 369 | 370 | LIB61850_API Quality 371 | Quality_fromMmsValue(const MmsValue* mmsValue); 372 | 373 | /** @} */ 374 | 375 | /** 376 | * @defgroup DBPOS Definitions and functions related to IEC 61850 Dbpos (a CODED ENUM) data type 377 | * 378 | * @{ 379 | */ 380 | 381 | typedef enum { 382 | DBPOS_INTERMEDIATE_STATE = 0, 383 | DBPOS_OFF = 1, 384 | DBPOS_ON = 2, 385 | DBPOS_BAD_STATE = 3 386 | } Dbpos; 387 | 388 | 389 | /** 390 | * \brief convert MMS bit string to Dbpos enumeration type 391 | * 392 | * \param mmsValue the MmsValue instance representing the Dbpos value 393 | * 394 | * \return the corresponding Dbpos value 395 | */ 396 | LIB61850_API Dbpos 397 | Dbpos_fromMmsValue(const MmsValue* mmsValue); 398 | 399 | /** 400 | * \brief conver Dbpos to MMS bit string 401 | * 402 | * \param mmsValue the MmsValue instance representing a Dbpos value or NULL to create a new MmsValue instance 403 | * \param a Dbpos value 404 | * 405 | * \return the corresponding MmsValue instance 406 | */ 407 | LIB61850_API MmsValue* 408 | Dbpos_toMmsValue(MmsValue* mmsValue, Dbpos dbpos); 409 | 410 | /** @} */ 411 | 412 | /** 413 | * @defgroup TIMESTAMP Definitions and functions related to IEC 61850 Timestamp (UTC Time) data type 414 | * 415 | * @{ 416 | */ 417 | 418 | typedef union { 419 | uint8_t val[8]; 420 | } Timestamp; 421 | 422 | LIB61850_API Timestamp* 423 | Timestamp_create(void); 424 | 425 | LIB61850_API Timestamp* 426 | Timestamp_createFromByteArray(uint8_t* byteArray); 427 | 428 | LIB61850_API void 429 | Timestamp_destroy(Timestamp* self); 430 | 431 | LIB61850_API void 432 | Timestamp_clearFlags(Timestamp* self); 433 | 434 | LIB61850_API uint32_t 435 | Timestamp_getTimeInSeconds(Timestamp* self); 436 | 437 | LIB61850_API msSinceEpoch 438 | Timestamp_getTimeInMs(Timestamp* self); 439 | 440 | LIB61850_API nsSinceEpoch 441 | Timestamp_getTimeInNs(Timestamp* self); 442 | 443 | LIB61850_API bool 444 | Timestamp_isLeapSecondKnown(Timestamp* self); 445 | 446 | LIB61850_API void 447 | Timestamp_setLeapSecondKnown(Timestamp* self, bool value); 448 | 449 | LIB61850_API bool 450 | Timestamp_hasClockFailure(Timestamp* self); 451 | 452 | LIB61850_API void 453 | Timestamp_setClockFailure(Timestamp* self, bool value); 454 | 455 | LIB61850_API bool 456 | Timestamp_isClockNotSynchronized(Timestamp* self); 457 | 458 | LIB61850_API void 459 | Timestamp_setClockNotSynchronized(Timestamp* self, bool value); 460 | 461 | LIB61850_API int 462 | Timestamp_getSubsecondPrecision(Timestamp* self); 463 | 464 | /** 465 | * \brief Set the subsecond precision value of the time stamp 466 | * 467 | * \param subsecondPrecision the number of significant bits of the fractionOfSecond part of the time stamp 468 | */ 469 | LIB61850_API void 470 | Timestamp_setSubsecondPrecision(Timestamp* self, int subsecondPrecision); 471 | 472 | /** 473 | * \brief Set the time in seconds 474 | * 475 | * NOTE: the fractionOfSecond part is set to zero 476 | * NOTE: the subSecondPrecision is not touched 477 | * 478 | * \param self the Timestamp instance 479 | * \param secondsSinceEpoch the seconds since unix epoch (unix timestamp) 480 | */ 481 | LIB61850_API void 482 | Timestamp_setTimeInSeconds(Timestamp* self, uint32_t secondsSinceEpoch); 483 | 484 | /** 485 | * \brief Set the time in milliseconds 486 | * 487 | * NOTE: the subSecondPrecision is not touched 488 | * 489 | * \param self the Timestamp instance 490 | * \param msTime the milliseconds since unix epoch 491 | */ 492 | LIB61850_API void 493 | Timestamp_setTimeInMilliseconds(Timestamp* self, msSinceEpoch msTime); 494 | 495 | /** 496 | * \brief Set the time in nanoseconds 497 | * 498 | * NOTE: the subSecondPrecision is not touched 499 | * 500 | * \param self the Timestamp instance 501 | * \param msTime the nanoseconds since unix epoch 502 | */ 503 | LIB61850_API void 504 | Timestamp_setTimeInNanoseconds(Timestamp* self, nsSinceEpoch nsTime); 505 | 506 | LIB61850_API void 507 | Timestamp_setByMmsUtcTime(Timestamp* self, MmsValue* mmsValue); 508 | 509 | /** 510 | * \brief Set an MmsValue instance of type UTCTime to the timestamp value 511 | * 512 | * \param self the Timestamp instance 513 | * \param mmsValue the mmsValue instance, if NULL a new instance will be created 514 | */ 515 | LIB61850_API MmsValue* 516 | Timestamp_toMmsValue(Timestamp* self, MmsValue* mmsValue); 517 | 518 | /** 519 | * \brief Get the version of the library as string 520 | * 521 | * \return the version of the library (e.g. "1.2.2") 522 | */ 523 | LIB61850_API char* 524 | LibIEC61850_getVersionString(void); 525 | 526 | /** @} */ 527 | 528 | /**@}*/ 529 | 530 | #ifdef __cplusplus 531 | } 532 | #endif 533 | 534 | #endif /* IEC61850_COMMON_H_ */ 535 | -------------------------------------------------------------------------------- /include/iec61850_config_file_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config_file_parser.h 3 | * 4 | * Copyright 2014 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef CONFIG_FILE_PARSER_H_ 25 | #define CONFIG_FILE_PARSER_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include "hal_filesystem.h" 32 | 33 | /** \addtogroup server_api_group 34 | * @{ 35 | */ 36 | 37 | /** 38 | * @defgroup CONFIG_FILE_PARSER Create data models by configuration files 39 | * 40 | * @{ 41 | */ 42 | 43 | /** 44 | * \brief Create a data model from simple text configuration file 45 | * 46 | * \param filename name or path of the configuraton file 47 | * 48 | * \return the data model to be used by \ref IedServer 49 | */ 50 | LIB61850_API IedModel* 51 | ConfigFileParser_createModelFromConfigFileEx(const char* filename); 52 | 53 | LIB61850_API IedModel* 54 | ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle); 55 | 56 | /**@}*/ 57 | 58 | /**@}*/ 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | 64 | #endif /* CONFIG_FILE_PARSER_H_ */ 65 | -------------------------------------------------------------------------------- /include/iec61850_dynamic_model.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dynamic_model.h 3 | * 4 | * Copyright 2014 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef DYNAMIC_MODEL_H_ 25 | #define DYNAMIC_MODEL_H_ 26 | 27 | #include "iec61850_model.h" 28 | #include "iec61850_cdc.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | 35 | /** \addtogroup server_api_group 36 | * @{ 37 | */ 38 | 39 | /** 40 | * @defgroup DYNAMIC_MODEL General dynamic model creation functions 41 | * 42 | * @{ 43 | */ 44 | 45 | 46 | /** 47 | * \brief create a new IedModel instance 48 | * 49 | * The IedModel object is the root node of an IEC 61850 service data model. 50 | * 51 | * \param name the name of the IedModel or NULL (optional - NOT YET USED) 52 | * 53 | * \return 54 | */ 55 | LIB61850_API IedModel* 56 | IedModel_create(const char* name/*, MemoryAllocator allocator*/); 57 | 58 | /** 59 | * \brief Set the name of the IED (use only for dynamic model!) 60 | * 61 | * This will change the default name (usually "TEMPLATE") to a user configured values. 62 | * NOTE: This function has to be called before IedServer_create ! 63 | * NOTE: For dynamic model (and configuration file date model) this function has to be 64 | * used instead of IedModel_setIedName. 65 | * 66 | * \param model the IedModel instance 67 | * \param the name of the configured IED 68 | */ 69 | LIB61850_API void 70 | IedModel_setIedNameForDynamicModel(IedModel* self, const char* name); 71 | 72 | /** 73 | * \brief destroy a dynamically created data model 74 | * 75 | * This function will free all the memory allocated for the data model. 76 | * 77 | * NOTE: Do not use this function when using a static data model (static_model.c create by static model generator). 78 | * 79 | * \param model the model instance to destroy 80 | */ 81 | LIB61850_API void 82 | IedModel_destroy(IedModel* model); 83 | 84 | /** 85 | * \brief Create a new logical device model and add it to the IED model 86 | * 87 | * \param name the name of the new logical device 88 | * \param parent the parent IED model 89 | * 90 | * \return the newly created LogicalDevice instance 91 | */ 92 | LIB61850_API LogicalDevice* 93 | LogicalDevice_create(const char* name, IedModel* parent); 94 | 95 | 96 | /** 97 | * \brief Create a new logical mode and add it to a logical device 98 | * 99 | * \param name the name of the new logical node 100 | * \param parent the parent logical device 101 | * 102 | * \return the newly created LogicalNode instance 103 | */ 104 | LIB61850_API LogicalNode* 105 | LogicalNode_create(const char* name, LogicalDevice* parent); 106 | 107 | /** 108 | * \brief create a new data object and add it to a parent model node 109 | * 110 | * The parent model node has to be of type DataObject or LogicalNode. 111 | * 112 | * \param name the name of the data object (e.h. "Mod", "Health" ...) 113 | * \param parent the parent model node 114 | * \param arrayElements the number of array elements if the data object is an array or 0 115 | * 116 | * \return the newly create DataObject instance 117 | */ 118 | LIB61850_API DataObject* 119 | DataObject_create(const char* name, ModelNode* parent, int arrayElements); 120 | 121 | /** 122 | * \brief create a new data attribute and add it to a parent model node 123 | * 124 | * The parent model node has to be of type DataObject or DataAttribute 125 | * 126 | * \param name the name of the data attribute (e.g. "stVal") 127 | * \param parent the parent model node 128 | * \param type the type of the data attribute (CONSTRUCTED if the type contains sub data attributes) 129 | * \param fc the functional constraint (FC) of the data attribute 130 | * \param triggerOptions the trigger options (dupd, dchg, qchg) that cause an event notification 131 | * \param arrayElements the number of array elements if the data attribute is an array or 0 132 | * \param sAddr an optional short address 133 | * 134 | * \return the newly create DataAttribute instance 135 | */ 136 | LIB61850_API DataAttribute* 137 | DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type, FunctionalConstraint fc, 138 | uint8_t triggerOptions, int arrayElements, uint32_t sAddr); 139 | 140 | /** 141 | * \brief Get the data type of the data attribute 142 | * 143 | * \param self the data attribute instance 144 | * 145 | * \return the data attribute type 146 | */ 147 | LIB61850_API DataAttributeType 148 | DataAttribute_getType(DataAttribute* self); 149 | 150 | /** 151 | * \brief Get the functional constraint (FC) of the data attribute 152 | * 153 | * \param self the data attribute instance 154 | * 155 | * \return the functional constraint (FC) of the data attribute 156 | */ 157 | LIB61850_API FunctionalConstraint 158 | DataAttribute_getFC(DataAttribute* self); 159 | 160 | /** 161 | * \brief Get the trigger options of the data attribute 162 | * 163 | * \param self the data attribute instance 164 | * 165 | * \return the trigger options (dupd, dchg, qchg) that cause an event notification 166 | */ 167 | LIB61850_API uint8_t 168 | DataAttribute_getTrgOps(DataAttribute* self); 169 | 170 | /** 171 | * \brief Set the value of the data attribute (can be used to set default values before server is created) 172 | * 173 | * \param self the data attribute instance 174 | * \param value the new default value 175 | */ 176 | LIB61850_API void 177 | DataAttribute_setValue(DataAttribute* self, MmsValue* value); 178 | 179 | /** 180 | * \brief create a new report control block (RCB) 181 | * 182 | * Create a new report control block (RCB) and add it to the given logical node (LN). 183 | * 184 | * \param name name of the RCB relative to the parent LN 185 | * \param parent the parent LN. 186 | * \param rptId of the report. If NULL the default report ID (object reference) is used. 187 | * \param isBuffered true for a buffered RCB - false for unbuffered RCB 188 | * \param dataSetName name (object reference) of the default data set or NULL if no data set 189 | * is set by default 190 | * \param confRef the configuration revision 191 | * \param trgOps the trigger options supported by this RCB (bit set) 192 | * \param options the inclusion options. Specifies what elements are included in a report (bit set) 193 | * \param bufTm the buffering time of the RCB in milliseconds (time between the first event and the preparation of the report). 194 | * \param intgPd integrity period in milliseconds 195 | * 196 | * \return the new RCB instance. 197 | */ 198 | LIB61850_API ReportControlBlock* 199 | ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bool isBuffered, char* 200 | dataSetName, uint32_t confRef, uint8_t trgOps, uint8_t options, uint32_t bufTm, uint32_t intgPd); 201 | 202 | /** 203 | * \brief Set a pre-configured client for the RCB 204 | * 205 | * If set only the pre configured client should use this RCB instance 206 | * 207 | * \param self the RCB instance 208 | * \param clientType the type of the client (0 = no client, 4 = IPv4 client, 6 = IPv6 client) 209 | * \param clientAddress buffer containing the client address (4 byte in case of an IPv4 address, 16 byte in case of an IPv6 address, NULL for no client) 210 | */ 211 | LIB61850_API void 212 | ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clientType, uint8_t* clientAddress); 213 | 214 | /** 215 | * \brief create a new log control block (LCB) 216 | * 217 | * Create a new log control block (LCB) and add it to the given logical node (LN). 218 | * 219 | * \param name name of the LCB relative to the parent LN 220 | * \param parent the parent LN. 221 | * \param dataSetName name (object reference) of the default data set or NULL if no data set 222 | * is set by default 223 | * \param logRef name (object reference) of the default log or NULL if no log is set by default. THe LDname doesn't contain the IED name! 224 | * \param trgOps the trigger options supported by this LCB (bit set) 225 | * \param intgPd integrity period in milliseconds 226 | * \param logEna if true the log will be enabled by default, false otherwise 227 | * \param reasonCode if true the reasonCode will be included in the log (this is always true in MMS mapping) 228 | * 229 | * \return the new LCB instance 230 | */ 231 | LIB61850_API LogControlBlock* 232 | LogControlBlock_create(const char* name, LogicalNode* parent, char* dataSetName, char* logRef, uint8_t trgOps, 233 | uint32_t intgPd, bool logEna, bool reasonCode); 234 | 235 | /** 236 | * \brief create a log (used by the IEC 61850 log service) 237 | * 238 | * \param name name of the LOG relative to the parent LN 239 | * \param parent the parent LN 240 | * 241 | * \return the new LOG instance 242 | */ 243 | LIB61850_API Log* 244 | Log_create(const char* name, LogicalNode* parent); 245 | 246 | /** 247 | * \brief create a setting group control block (SGCB) 248 | * 249 | * Create a new setting group control block (SGCB) and add it to the given logical node (LN). 250 | * 251 | * \param parent the parent LN. 252 | * \param the active setting group on server startup (1..N) 253 | * \param the number of setting groups (N) 254 | * 255 | * \return the new SGCB instance 256 | */ 257 | LIB61850_API SettingGroupControlBlock* 258 | SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numOfSGs); 259 | 260 | /** 261 | * \brief create a new GSE/GOOSE control block (GoCB) 262 | * 263 | * Create a new GOOSE control block (GoCB) and add it to the given logical node (LN) 264 | * 265 | * \param name name of the GoCB relative to the parent LN 266 | * \param parent the parent LN 267 | * \param appId the application ID of the GoCB 268 | * \param dataSet the data set reference to be used by the GoCB 269 | * \param confRev the configuration revision 270 | * \param fixedOffs indicates if GOOSE publisher shall use fixed offsets (NOT YET SUPPORTED) 271 | * \param minTime minimum GOOSE retransmission time (-1 if not specified - uses stack default then) 272 | * \param maxTime GOOSE retransmission time in stable state (-1 if not specified - uses stack default then) 273 | * 274 | * \return the new GoCB instance 275 | */ 276 | LIB61850_API GSEControlBlock* 277 | GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char* dataSet, uint32_t confRev, 278 | bool fixedOffs, int minTime, int maxTime); 279 | 280 | /** 281 | * \brief create a new Multicast/Unicast Sampled Value (SV) control block (SvCB) 282 | * 283 | * Create a new Sampled Value control block (SvCB) and add it to the given logical node (LN) 284 | * 285 | * \param name name of the SvCB relative to the parent LN 286 | * \param parent the parent LN 287 | * \param svID the application ID of the SvCB 288 | * \param dataSet the data set reference to be used by the SVCB 289 | * \param confRev the configuration revision 290 | * \param smpMod the sampling mode used 291 | * \param smpRate the sampling rate used 292 | * \param optFlds the optional element configuration 293 | * 294 | * \return the new SvCB instance 295 | */ 296 | LIB61850_API SVControlBlock* 297 | SVControlBlock_create(const char* name, LogicalNode* parent, char* svID, char* dataSet, uint32_t confRev, uint8_t smpMod, 298 | uint16_t smpRate, uint8_t optFlds, bool isUnicast); 299 | 300 | LIB61850_API void 301 | SVControlBlock_addPhyComAddress(SVControlBlock* self, PhyComAddress* phyComAddress); 302 | 303 | LIB61850_API void 304 | GSEControlBlock_addPhyComAddress(GSEControlBlock* self, PhyComAddress* phyComAddress); 305 | 306 | /** 307 | * \brief create a PhyComAddress object 308 | * 309 | * A PhyComAddress object contains all required addressing information for a GOOSE publisher. 310 | * 311 | * \param vlanPriority the priority field of the VLAN tag 312 | * \param vlanId the ID field of the VLAN tag 313 | * \param appId the application identifier 314 | * \param dstAddress the 6 byte multicast MAC address to specify the destination 315 | * 316 | * \return the new PhyComAddress object 317 | */ 318 | LIB61850_API PhyComAddress* 319 | PhyComAddress_create(uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[]); 320 | 321 | /** 322 | * \brief create a new data set 323 | * 324 | * \param name the name of the data set 325 | * \param parent the logical node that hosts the data set (typically a LLN0) 326 | * 327 | * \return the new data set instance 328 | */ 329 | LIB61850_API DataSet* 330 | DataSet_create(const char* name, LogicalNode* parent); 331 | 332 | /** 333 | * \brief returns the number of elements (entries) of the data set 334 | * 335 | * \param self the instance of the data set 336 | * 337 | * \returns the number of data set elements 338 | */ 339 | LIB61850_API int 340 | DataSet_getSize(DataSet* self); 341 | 342 | LIB61850_API DataSetEntry* 343 | DataSet_getFirstEntry(DataSet* self); 344 | 345 | LIB61850_API DataSetEntry* 346 | DataSetEntry_getNext(DataSetEntry* self); 347 | 348 | /** 349 | * \brief create a new data set entry (FCDA) 350 | * 351 | * Create a new FCDA reference and add it to the given data set as a new data set member. 352 | * 353 | * Note: Be aware that data set entries are not IEC 61850 object reference but MMS variable names 354 | * that have to contain the LN name, the FC and subsequent path elements separated by "$" instead of ".". 355 | * This is due to efficiency reasons to avoid the creation of additional strings. 356 | * 357 | * If the variable parameter does not contain a logical device name (separated from the remaining variable 358 | * name by the "/" character) the logical device where the data set resides is used automatically. 359 | * 360 | * \param dataSet the data set to which the new entry will be added 361 | * \param variable the name of the variable as MMS variable name including FC ("$" used as separator!) 362 | * \param index the index if the FCDA is an array element, otherwise -1 363 | * \param component the name of the component of the variable if the FCDA is a sub element of an array 364 | * element. If this is not the case then NULL should be given here. 365 | * 366 | * \return the new data set entry instance 367 | */ 368 | LIB61850_API DataSetEntry* 369 | DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const char* component); 370 | 371 | /**@}*/ 372 | 373 | /**@}*/ 374 | 375 | #ifdef __cplusplus 376 | } 377 | #endif 378 | 379 | #endif /* DYNAMIC_MODEL_H_ */ 380 | -------------------------------------------------------------------------------- /include/iec61850_model.h: -------------------------------------------------------------------------------- 1 | /* 2 | * model.h 3 | * 4 | * Copyright 2013-2016 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef MODEL_H_ 25 | #define MODEL_H_ 26 | 27 | #include "iec61850_common.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /** \addtogroup server_api_group 34 | * @{ 35 | */ 36 | 37 | /** 38 | * @defgroup DATA_MODEL General data model definitions, access and iteration functions 39 | * 40 | * @{ 41 | */ 42 | 43 | /** 44 | * \brief abstract base type for IEC 61850 data model nodes 45 | */ 46 | typedef struct sModelNode ModelNode; 47 | 48 | /** 49 | * \brief IEC 61850 data model element of type data attribute 50 | */ 51 | typedef struct sDataAttribute DataAttribute; 52 | 53 | /** 54 | * \brief IEC 61850 data model element of type data object 55 | */ 56 | typedef struct sDataObject DataObject; 57 | 58 | /** 59 | * \brief IEC 61850 data model element of type logical node 60 | */ 61 | typedef struct sLogicalNode LogicalNode; 62 | 63 | /** 64 | * \brief IEC 61850 data model element of type logical device 65 | */ 66 | typedef struct sLogicalDevice LogicalDevice; 67 | 68 | /** 69 | * \brief Root node of the IEC 61850 data model. This is usually created by the model generator tool (genmodel.jar) 70 | */ 71 | typedef struct sIedModel IedModel; 72 | 73 | typedef struct sDataSet DataSet; 74 | typedef struct sReportControlBlock ReportControlBlock; 75 | 76 | /** 77 | * \brief IEC 61850 data model of setting group control block (SGCB) 78 | */ 79 | typedef struct sSettingGroupControlBlock SettingGroupControlBlock; 80 | 81 | typedef struct sGSEControlBlock GSEControlBlock; 82 | 83 | typedef struct sSVControlBlock SVControlBlock; 84 | 85 | typedef struct sLogControlBlock LogControlBlock; 86 | 87 | typedef struct sLog Log; 88 | 89 | typedef enum { 90 | IEC61850_UNKNOWN_TYPE = -1, 91 | IEC61850_BOOLEAN = 0,/* int */ 92 | IEC61850_INT8 = 1, /* int8_t */ 93 | IEC61850_INT16 = 2, /* int16_t */ 94 | IEC61850_INT32 = 3, /* int32_t */ 95 | IEC61850_INT64 = 4, /* int64_t */ 96 | IEC61850_INT128 = 5, /* no native mapping! */ 97 | IEC61850_INT8U = 6, /* uint8_t */ 98 | IEC61850_INT16U = 7, /* uint16_t */ 99 | IEC61850_INT24U = 8, /* uint32_t */ 100 | IEC61850_INT32U = 9, /* uint32_t */ 101 | IEC61850_FLOAT32 = 10, /* float */ 102 | IEC61850_FLOAT64 = 11, /* double */ 103 | IEC61850_ENUMERATED = 12, 104 | IEC61850_OCTET_STRING_64 = 13, 105 | IEC61850_OCTET_STRING_6 = 14, 106 | IEC61850_OCTET_STRING_8 = 15, 107 | IEC61850_VISIBLE_STRING_32 = 16, 108 | IEC61850_VISIBLE_STRING_64 = 17, 109 | IEC61850_VISIBLE_STRING_65 = 18, 110 | IEC61850_VISIBLE_STRING_129 = 19, 111 | IEC61850_VISIBLE_STRING_255 = 20, 112 | IEC61850_UNICODE_STRING_255 = 21, 113 | IEC61850_TIMESTAMP = 22, 114 | IEC61850_QUALITY = 23, 115 | IEC61850_CHECK = 24, 116 | IEC61850_CODEDENUM = 25, 117 | IEC61850_GENERIC_BITSTRING = 26, 118 | IEC61850_CONSTRUCTED = 27, 119 | IEC61850_ENTRY_TIME = 28, 120 | IEC61850_PHYCOMADDR = 29, 121 | IEC61850_CURRENCY = 30, 122 | IEC61850_OPTFLDS = 31, /* bit-string(10) */ 123 | IEC61850_TRGOPS = 32 /* bit-string(6) */ 124 | 125 | 126 | #if (CONFIG_IEC61850_USE_COMPAT_TYPE_DECLARATIONS == 1) 127 | , 128 | BOOLEAN = 0,/* int */ 129 | INT8 = 1, /* int8_t */ 130 | INT16 = 2, /* int16_t */ 131 | INT32 = 3, /* int32_t */ 132 | INT64 = 4, /* int64_t */ 133 | INT128 = 5, /* no native mapping! */ 134 | INT8U = 6, /* uint8_t */ 135 | INT16U = 7, /* uint16_t */ 136 | INT24U = 8, /* uint32_t */ 137 | INT32U = 9, /* uint32_t */ 138 | FLOAT32 = 10, /* float */ 139 | FLOAT64 = 11, /* double */ 140 | ENUMERATED = 12, 141 | OCTET_STRING_64 = 13, 142 | OCTET_STRING_6 = 14, 143 | OCTET_STRING_8 = 15, 144 | VISIBLE_STRING_32 = 16, 145 | VISIBLE_STRING_64 = 17, 146 | VISIBLE_STRING_65 = 18, 147 | VISIBLE_STRING_129 = 19, 148 | VISIBLE_STRING_255 = 20, 149 | UNICODE_STRING_255 = 21, 150 | TIMESTAMP = 22, 151 | QUALITY = 23, 152 | CHECK = 24, 153 | CODEDENUM = 25, 154 | GENERIC_BITSTRING = 26, 155 | CONSTRUCTED = 27, 156 | ENTRY_TIME = 28, 157 | PHYCOMADDR = 29, 158 | CURRENCY = 30 159 | OPTFLDS = 31, 160 | TRGOPS = 32 161 | #endif 162 | } DataAttributeType; 163 | 164 | typedef enum { 165 | LogicalDeviceModelType, 166 | LogicalNodeModelType, 167 | DataObjectModelType, 168 | DataAttributeModelType 169 | } ModelNodeType; 170 | 171 | struct sIedModel { 172 | char* name; 173 | LogicalDevice* firstChild; 174 | DataSet* dataSets; 175 | ReportControlBlock* rcbs; 176 | GSEControlBlock* gseCBs; 177 | SVControlBlock* svCBs; 178 | SettingGroupControlBlock* sgcbs; 179 | LogControlBlock* lcbs; 180 | Log* logs; 181 | void (*initializer) (void); 182 | }; 183 | 184 | struct sLogicalDevice { 185 | ModelNodeType modelType; 186 | char* name; 187 | ModelNode* parent; 188 | ModelNode* sibling; 189 | ModelNode* firstChild; 190 | }; 191 | 192 | struct sModelNode { 193 | ModelNodeType modelType; 194 | char* name; 195 | ModelNode* parent; 196 | ModelNode* sibling; 197 | ModelNode* firstChild; 198 | }; 199 | 200 | struct sLogicalNode { 201 | ModelNodeType modelType; 202 | char* name; 203 | ModelNode* parent; 204 | ModelNode* sibling; 205 | ModelNode* firstChild; 206 | }; 207 | 208 | struct sDataObject { 209 | ModelNodeType modelType; 210 | char* name; 211 | ModelNode* parent; 212 | ModelNode* sibling; 213 | ModelNode* firstChild; 214 | 215 | int elementCount; /* > 0 if this is an array */ 216 | }; 217 | 218 | struct sDataAttribute { 219 | ModelNodeType modelType; 220 | char* name; 221 | ModelNode* parent; 222 | ModelNode* sibling; 223 | ModelNode* firstChild; 224 | 225 | int elementCount; /* > 0 if this is an array */ 226 | 227 | FunctionalConstraint fc; 228 | DataAttributeType type; 229 | 230 | uint8_t triggerOptions; /* TRG_OPT_DATA_CHANGED | TRG_OPT_QUALITY_CHANGED | TRG_OPT_DATA_UPDATE */ 231 | 232 | MmsValue* mmsValue; 233 | 234 | uint32_t sAddr; 235 | }; 236 | 237 | typedef struct sDataSetEntry { 238 | char* logicalDeviceName; 239 | bool isLDNameDynamicallyAllocated; 240 | char* variableName; 241 | int index; 242 | char* componentName; 243 | MmsValue* value; 244 | struct sDataSetEntry* sibling; 245 | } DataSetEntry; 246 | 247 | struct sDataSet { 248 | char* logicalDeviceName; 249 | char* name; /* eg. MMXU1$dataset1 */ 250 | int elementCount; 251 | DataSetEntry* fcdas; 252 | DataSet* sibling; 253 | }; 254 | 255 | struct sReportControlBlock { 256 | LogicalNode* parent; 257 | char* name; 258 | char* rptId; 259 | bool buffered; 260 | char* dataSetName; /* pre loaded with relative name in logical node */ 261 | 262 | uint32_t confRef; /* ConfRef - configuration revision */ 263 | uint8_t trgOps; /* TrgOps - trigger conditions */ 264 | uint8_t options; /* OptFlds */ 265 | uint32_t bufferTime; /* BufTm - time to buffer events until a report is generated */ 266 | uint32_t intPeriod; /* IntgPd - integrity period */ 267 | 268 | /* type (first byte) and address of the pre-configured client 269 | type can be one of (0 - no reservation, 4 - IPv4 client, 6 - IPv6 client) */ 270 | uint8_t clientReservation[17]; 271 | 272 | ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ 273 | }; 274 | 275 | struct sLogControlBlock { 276 | LogicalNode* parent; 277 | 278 | char* name; 279 | 280 | char* dataSetName; 281 | char* logRef; /* object reference to the journal */ 282 | 283 | uint8_t trgOps; /* TrgOps - trigger conditions */ 284 | uint32_t intPeriod; /* IntgPd - integrity period */ 285 | 286 | bool logEna; /* enable log by default */ 287 | bool reasonCode; /* include reason code in log */ 288 | 289 | LogControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ 290 | }; 291 | 292 | struct sLog { 293 | LogicalNode* parent; 294 | 295 | char* name; 296 | 297 | Log* sibling; /* next log instance in list or NULL if this is the last entry */ 298 | }; 299 | 300 | struct sSettingGroupControlBlock { 301 | LogicalNode* parent; 302 | 303 | uint8_t actSG; /* value from SCL file */ 304 | uint8_t numOfSGs; /* value from SCL file */ 305 | 306 | uint8_t editSG; /* 0 at power-up */ 307 | bool cnfEdit; /* false at power-up */ 308 | uint64_t timestamp; 309 | uint16_t resvTms; 310 | 311 | SettingGroupControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ 312 | }; 313 | 314 | struct sGSEControlBlock { 315 | LogicalNode* parent; 316 | char* name; 317 | char* appId; 318 | char* dataSetName; /* pre loaded with relative name in logical node */ 319 | uint32_t confRev; /* ConfRev - configuration revision */ 320 | bool fixedOffs; /* fixed offsets */ 321 | PhyComAddress* address; /* GSE communication parameters */ 322 | int minTime; /* optional minTime parameter --> -1 if not present */ 323 | int maxTime; /* optional maxTime parameter --> -1 if not present */ 324 | GSEControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ 325 | }; 326 | 327 | struct sSVControlBlock { 328 | LogicalNode* parent; 329 | char* name; 330 | 331 | char* svId; /* MsvUD/UsvID */ 332 | char* dataSetName; /* pre loaded with relative name in logical node */ 333 | 334 | uint8_t optFlds; 335 | 336 | uint8_t smpMod; 337 | uint16_t smpRate; 338 | 339 | uint32_t confRev; /* ConfRev - configuration revision */ 340 | 341 | PhyComAddress* dstAddress; /* SV communication parameters */ 342 | 343 | bool isUnicast; 344 | 345 | int noASDU; 346 | 347 | SVControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ 348 | }; 349 | 350 | /** 351 | * \brief get the number of direct children of a model node 352 | * 353 | * \param self the model node instance 354 | * 355 | * \return the number of children of the model node 356 | * ¸ 357 | */ 358 | LIB61850_API int 359 | ModelNode_getChildCount(ModelNode* self); 360 | 361 | /** 362 | * \brief return a child model node 363 | * 364 | * \param self the model node instance 365 | * \param name the name of the child model node 366 | * 367 | * \return the model node instance or NULL if model node does not exist. 368 | */ 369 | LIB61850_API ModelNode* 370 | ModelNode_getChild(ModelNode* self, const char* name); 371 | 372 | /** 373 | * \brief return a child model node with a given functional constraint 374 | * 375 | * Sometimes the name is not enough to identify a model node. This is the case when 376 | * editable setting groups are used. In this case the setting group members have two different 377 | * model nodes associated that differ in their FC (SG and SE). 378 | * 379 | * \param self the model node instance 380 | * \param name the name of the child model node 381 | * \param fc the functional constraint of the model node 382 | * 383 | * \return the model node instance or NULL if model node does not exist. 384 | */ 385 | LIB61850_API ModelNode* 386 | ModelNode_getChildWithFc(ModelNode* self, const char* name, FunctionalConstraint fc); 387 | 388 | /** 389 | * \brief Return the IEC 61850 object reference of a model node 390 | * 391 | * \param self the model node instance 392 | * \param objectReference pointer to a buffer where to write the object reference string. If NULL 393 | * is given the buffer is allocated by the function. 394 | * 395 | * \return the object reference string 396 | */ 397 | LIB61850_API char* 398 | ModelNode_getObjectReference(ModelNode* self, char* objectReference); 399 | 400 | /** 401 | * \brief Return the IEC 61850 object reference of a model node 402 | * 403 | * \param self the model node instance 404 | * \param objectReference pointer to a buffer where to write the object reference string. If NULL 405 | * is given the buffer is allocated by the function. 406 | * \param withoutIedName create object reference without IED name part 407 | * 408 | * \return the object reference string 409 | */ 410 | LIB61850_API char* 411 | ModelNode_getObjectReferenceEx(ModelNode* node, char* objectReference, bool withoutIedName); 412 | 413 | /** 414 | * \brief Get the type of the ModelNode 415 | * 416 | * \param self the ModelNode instance 417 | * 418 | * \return the type of the ModelNode (one of LD, LN, DO, DA) 419 | */ 420 | LIB61850_API ModelNodeType 421 | ModelNode_getType(ModelNode* self); 422 | 423 | /** 424 | * \brief Get the name of the ModelNode 425 | * 426 | * \param self the ModelNode instance 427 | * 428 | * \return the name of the ModelNode 429 | */ 430 | LIB61850_API const char* 431 | ModelNode_getName(ModelNode* self); 432 | 433 | /** 434 | * \brief Get the parent ModelNode of this ModelNode instance 435 | * 436 | * \param self the ModelNode instance 437 | * 438 | * \return the parent instance, or NULL when the ModelNode has no parent 439 | */ 440 | LIB61850_API ModelNode* 441 | ModelNode_getParent(ModelNode* self); 442 | 443 | /** 444 | * \brief Get the list of direct child nodes 445 | * 446 | * \param self the ModelNode instance 447 | * 448 | * \return the list of private child nodes, or NULL when the node has no children 449 | */ 450 | LIB61850_API LinkedList 451 | ModelNode_getChildren(ModelNode* self); 452 | 453 | /** 454 | * \brief Set the name of the IED 455 | * 456 | * This will change the default name (usualy "TEMPLATE") to a user configured values. 457 | * NOTE: This function has to be called before IedServer_create ! 458 | * 459 | * \param model the IedModel instance 460 | * \param the name of the configured IED 461 | */ 462 | LIB61850_API void 463 | IedModel_setIedName(IedModel* self, const char* iedName); 464 | 465 | /** 466 | * \brief Lookup a model node by its object reference 467 | * 468 | * This function uses the full logical device name as part of the object reference 469 | * as it happens to appear on the wire. E.g. if IED name in SCL file would be "IED1" 470 | * and the logical device "WD1" the resulting LD name would be "IED1WD". 471 | * 472 | * \param self the IedModel instance that holds the model node 473 | * \param objectReference the IEC 61850 object reference 474 | * 475 | * \return the model node instance or NULL if model node does not exist. 476 | */ 477 | LIB61850_API ModelNode* 478 | IedModel_getModelNodeByObjectReference(IedModel* self, const char* objectReference); 479 | 480 | LIB61850_API SVControlBlock* 481 | IedModel_getSVControlBlock(IedModel* self, LogicalNode* parentLN, const char* svcbName); 482 | 483 | /** 484 | * \brief Lookup a model node by its short (normalized) reference 485 | * 486 | * This version uses the object reference that does not contain the 487 | * IED name as part of the logical device name. This function is useful for 488 | * devices where the IED name can be configured. 489 | * 490 | * \param self the IedModel instance that holds the model node 491 | * \param objectReference the IEC 61850 object reference 492 | * 493 | * \return the model node instance or NULL if model node does not exist. 494 | */ 495 | LIB61850_API ModelNode* 496 | IedModel_getModelNodeByShortObjectReference(IedModel* self, const char* objectReference); 497 | 498 | /** 499 | * \brief Lookup a model node by its short address 500 | * 501 | * Short address is a 32 bit unsigned integer as specified in the "sAddr" attribute of 502 | * the ICD file or in the configuration file. 503 | * 504 | * \param self the IedModel instance that holds the model node 505 | * \param shortAddress 506 | * 507 | * \return the model node instance or NULL if model node does not exist. 508 | */ 509 | LIB61850_API ModelNode* 510 | IedModel_getModelNodeByShortAddress(IedModel* self, uint32_t shortAddress); 511 | 512 | /** 513 | * \brief Lookup logical device (LD) by device instance name (SCL attribute "inst") 514 | * 515 | * \param self IedModel instance 516 | * \param ldInst the logical device instance name (SCL attribute "inst") 517 | * 518 | * \return The matching LogicalDevice instance 519 | */ 520 | LIB61850_API LogicalDevice* 521 | IedModel_getDeviceByInst(IedModel* self, const char* ldInst); 522 | 523 | /** 524 | * \brief Lookup logical device (LD) instance by index 525 | * 526 | * \param self IedModel instance 527 | * \param index the index of the LD in the range (0 .. number of LDs - 1) 528 | * 529 | * \return the corresponding LogicalDevice* object or NULL if the index is out of range 530 | */ 531 | LIB61850_API LogicalDevice* 532 | IedModel_getDeviceByIndex(IedModel* self, int index); 533 | 534 | 535 | /** 536 | * \brief Lookup a logical node by name that is part of the given logical device 537 | * 538 | * \param device the logical device instance 539 | * \param lnName the logical node name 540 | * 541 | * \return the logical device instance or NULL if it does not exist 542 | */ 543 | LIB61850_API LogicalNode* 544 | LogicalDevice_getLogicalNode(LogicalDevice* self, const char* lnName); 545 | 546 | /** 547 | * \brief Get the setting group control block (SGCB) of the logical device 548 | * 549 | * \param device the logical device instance 550 | * 551 | * \return the SGCB instance or NULL if no SGCB is available 552 | */ 553 | LIB61850_API SettingGroupControlBlock* 554 | LogicalDevice_getSettingGroupControlBlock(LogicalDevice* self); 555 | 556 | /**@}*/ 557 | 558 | /**@}*/ 559 | 560 | 561 | /** 562 | * \brief unset all MmsValue references in the data model 563 | * 564 | * \param self the IedModel instance that holds the model node 565 | */ 566 | LIB61850_API void 567 | IedModel_setAttributeValuesToNull(IedModel* self); 568 | 569 | /** 570 | * \brief Lookup logical device (LD) by device name 571 | * 572 | * \param self IedModel instance 573 | * \param ldInst the logical device name (as it is seen from the protocol side - MMS domain name) 574 | * 575 | * \return The matching LogicalDevice instance 576 | */ 577 | LIB61850_API LogicalDevice* 578 | IedModel_getDevice(IedModel* self, const char* ldName); 579 | 580 | /** 581 | * \brief Lookup a data set in the IED model 582 | * 583 | * \param self IedModel instance 584 | * \param dataSetReference MMS mapping object reference! e.g. ied1Inverter/LLN0$dataset1 585 | * 586 | * \return The matching DataSet instance 587 | */ 588 | LIB61850_API DataSet* 589 | IedModel_lookupDataSet(IedModel* self, const char* dataSetReference); 590 | 591 | /** 592 | * \brief Lookup a DataAttribute instance with the corresponding MmsValue instance 593 | * 594 | * \param self IedModel instance 595 | * \param value the MmsValue instance (from the MMS value cache) 596 | * 597 | * \return the matching DataAttribute instance 598 | */ 599 | LIB61850_API DataAttribute* 600 | IedModel_lookupDataAttributeByMmsValue(IedModel* self, MmsValue* value); 601 | 602 | 603 | /** 604 | * \brief Get the number of logical devices 605 | * 606 | * \param self IedModel instance 607 | * 608 | * \return the number of logical devices 609 | */ 610 | LIB61850_API int 611 | IedModel_getLogicalDeviceCount(IedModel* self); 612 | 613 | LIB61850_API int 614 | LogicalDevice_getLogicalNodeCount(LogicalDevice* self); 615 | 616 | LIB61850_API ModelNode* 617 | LogicalDevice_getChildByMmsVariableName(LogicalDevice* self, const char* mmsVariableName); 618 | 619 | LIB61850_API bool 620 | LogicalNode_hasFCData(LogicalNode* self, FunctionalConstraint fc); 621 | 622 | LIB61850_API bool 623 | LogicalNode_hasBufferedReports(LogicalNode* self); 624 | 625 | LIB61850_API bool 626 | LogicalNode_hasUnbufferedReports(LogicalNode* self); 627 | 628 | /** 629 | * \brief get a data set instance 630 | * 631 | * \param self the logical node instance of the data set 632 | * \param dataSetName the name of the data set 633 | * 634 | * \return the data set instance or NULL if the data set does not exist 635 | */ 636 | LIB61850_API DataSet* 637 | LogicalNode_getDataSet(LogicalNode* self, const char* dataSetName); 638 | 639 | LIB61850_API bool 640 | DataObject_hasFCData(DataObject* self, FunctionalConstraint fc); 641 | 642 | 643 | #ifdef __cplusplus 644 | } 645 | #endif 646 | 647 | 648 | #endif /* MODEL_H_ */ 649 | -------------------------------------------------------------------------------- /include/iso_connection_parameters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iso_connection_parameters.h 3 | * 4 | * Copyright 2013-2018 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef ISO_CONNECTION_PARAMETERS_H_ 25 | #define ISO_CONNECTION_PARAMETERS_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include "tls_config.h" 32 | 33 | /** 34 | * \addtogroup mms_client_api_group 35 | */ 36 | /**@{*/ 37 | 38 | 39 | /** 40 | * \brief authentication mechanism used by AcseAuthenticator 41 | */ 42 | typedef enum 43 | { 44 | /** Neither ACSE nor TLS authentication used */ 45 | ACSE_AUTH_NONE = 0, 46 | 47 | /** Use ACSE password for client authentication */ 48 | ACSE_AUTH_PASSWORD = 1, 49 | 50 | /** Use ACSE certificate for client authentication */ 51 | ACSE_AUTH_CERTIFICATE = 2, 52 | 53 | /** Use TLS certificate for client authentication */ 54 | ACSE_AUTH_TLS = 3 55 | } AcseAuthenticationMechanism; 56 | 57 | 58 | typedef struct sAcseAuthenticationParameter* AcseAuthenticationParameter; 59 | 60 | struct sAcseAuthenticationParameter 61 | { 62 | AcseAuthenticationMechanism mechanism; 63 | 64 | union 65 | { 66 | struct 67 | { 68 | uint8_t* octetString; 69 | int passwordLength; 70 | } password; /* for mechanism = ACSE_AUTH_PASSWORD */ 71 | 72 | struct 73 | { 74 | uint8_t* buf; 75 | int length; 76 | } certificate; /* for mechanism = ACSE_AUTH_CERTIFICATE or ACSE_AUTH_TLS */ 77 | 78 | } value; 79 | }; 80 | 81 | LIB61850_API AcseAuthenticationParameter 82 | AcseAuthenticationParameter_create(void); 83 | 84 | LIB61850_API void 85 | AcseAuthenticationParameter_destroy(AcseAuthenticationParameter self); 86 | 87 | LIB61850_API void 88 | AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, AcseAuthenticationMechanism mechanism); 89 | 90 | LIB61850_API void 91 | AcseAuthenticationParameter_setPassword(AcseAuthenticationParameter self, char* password); 92 | 93 | 94 | /** 95 | * \brief Callback function to authenticate a client 96 | * 97 | * \param parameter user provided parameter - set when user registers the authenticator 98 | * \param authParameter the authentication parameters provided by the client 99 | * \param securityToken pointer where to store an application specific security token - can be ignored if not used. 100 | * \param appReference ISO application reference (ap-title + ae-qualifier) 101 | * 102 | * \return true if client connection is accepted, false otherwise 103 | */ 104 | typedef bool 105 | (*AcseAuthenticator)(void* parameter, AcseAuthenticationParameter authParameter, void** securityToken, IsoApplicationReference* appReference); 106 | 107 | /** 108 | * \brief COTP T selector 109 | * 110 | * To not use T SEL set size to 0. 111 | */ 112 | typedef struct { 113 | uint8_t size; /** 0 .. 4 - 0 means T-selector is not present */ 114 | uint8_t value[4]; /** T-selector value */ 115 | } TSelector; 116 | 117 | /** 118 | * \brief OSI session selector 119 | * 120 | * To not use S SEL set size to 0 121 | */ 122 | typedef struct { 123 | uint8_t size; /** 0 .. 16 - 0 means S-selector is not present */ 124 | uint8_t value[16]; /** S-selector value */ 125 | } SSelector; 126 | 127 | /** 128 | * \brief OSI presentation (P) selector 129 | * 130 | * To not use P SEL set size to 0 131 | */ 132 | typedef struct { 133 | uint8_t size; /** 0 .. 16 - 0 means P-selector is not present */ 134 | uint8_t value[16]; /** P-selector value */ 135 | } PSelector; 136 | 137 | struct sIsoConnectionParameters 138 | { 139 | AcseAuthenticationParameter acseAuthParameter; 140 | 141 | #if (CONFIG_MMS_SUPPORT_TLS == 1) 142 | TLSConfiguration tlsConfiguration; 143 | #endif 144 | 145 | const char* hostname; 146 | int tcpPort; 147 | 148 | uint8_t remoteApTitle[10]; 149 | int remoteApTitleLen; 150 | int remoteAEQualifier; 151 | PSelector remotePSelector; 152 | SSelector remoteSSelector; 153 | TSelector remoteTSelector; 154 | 155 | 156 | uint8_t localApTitle[10]; 157 | int localApTitleLen; 158 | int localAEQualifier; 159 | PSelector localPSelector; 160 | SSelector localSSelector; 161 | TSelector localTSelector; 162 | 163 | }; 164 | 165 | typedef struct sIsoConnectionParameters* IsoConnectionParameters; 166 | 167 | /** 168 | * \brief create a new IsoConnectionParameters instance (FOR LIBRARY INTERNAL USE) 169 | * 170 | * NOTE: This function used internally by the MMS client library. When using the MMS or IEC 61850 API 171 | * there should be no reason for the user to call this function. 172 | * 173 | * \return new IsoConnectionParameters instance 174 | */ 175 | LIB61850_API IsoConnectionParameters 176 | IsoConnectionParameters_create(void); 177 | 178 | /** 179 | * \brief Destroy an IsoConnectionParameters instance (FOR LIBRARY INTERNAL USE) 180 | * 181 | * NOTE: This function used internally by the MMS client library. When using the MMS or IEC 61850 API 182 | * there should be no reason for the user to call this function. 183 | * 184 | * \param self the IsoConnectionParameters instance 185 | */ 186 | LIB61850_API void 187 | IsoConnectionParameters_destroy(IsoConnectionParameters self); 188 | 189 | 190 | LIB61850_API void 191 | IsoConnectionParameters_setTlsConfiguration(IsoConnectionParameters self, TLSConfiguration tlsConfig); 192 | 193 | /** 194 | * \brief set the authentication parameter 195 | * 196 | * This will set the authentication parameter and activates authentication. 197 | * 198 | * \param self the IsoConnectionParameters instance 199 | * \param acseAuthParameter 200 | */ 201 | LIB61850_API void 202 | IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters self, 203 | AcseAuthenticationParameter acseAuthParameter); 204 | 205 | /** 206 | * \brief Set TCP parameters (FOR LIBRARY INTERNAL USE) 207 | * 208 | * NOTE: This function used internally by the MMS client library. When using the MMS or IEC 61850 API 209 | * there should be no reason for the user to call this function 210 | * 211 | * \param self the IsoConnectionParameters instance 212 | * \param hostname the hostname of IP address if the server 213 | * \param tcpPort the TCP port number of the server 214 | */ 215 | LIB61850_API void 216 | IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const char* hostname, int tcpPort); 217 | 218 | /** 219 | * \brief set the remote AP-Title and AE-Qualifier 220 | * 221 | * Calling this function is optional and not recommended. If not called the default 222 | * parameters are used. 223 | * If apTitle is NULL the parameter the AP-Title and AE-Qualifier will not be transmitted. 224 | * This seems to be required by some server devices. 225 | * 226 | * \param self the IsoConnectionParameters instance 227 | * \param apTitle the AP-Title OID as string. 228 | * \param aeQualifier the AP-qualifier 229 | */ 230 | LIB61850_API void 231 | IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier); 232 | 233 | /** 234 | * \brief set remote addresses for the lower layers 235 | * 236 | * This function can be used to set the addresses for the lower layer protocols (presentation, session, and transport 237 | * layer). Calling this function is optional and not recommended. If not called the default 238 | * parameters are used. 239 | * 240 | * \param self the IsoConnectionParameters instance 241 | * \param pSelector the P-Selector (presentation layer address) 242 | * \param sSelector the S-Selector (session layer address) 243 | * \param tSelector the T-Selector (ISO transport layer address) 244 | */ 245 | LIB61850_API void 246 | IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, PSelector pSelector, SSelector sSelector, TSelector tSelector); 247 | 248 | /** 249 | * \brief set the local AP-Title and AE-Qualifier 250 | * 251 | * Calling this function is optional and not recommended. If not called the default 252 | * parameters are used. 253 | * If apTitle is NULL the parameter the AP-Title and AE-Qualifier will not be transmitted. 254 | * This seems to be required by some server devices. 255 | * 256 | * \param self the IsoConnectionParameters instance 257 | * \param apTitle the AP-Title OID as string. 258 | * \param aeQualifier the AP-qualifier 259 | */ 260 | LIB61850_API void 261 | IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier); 262 | 263 | /** 264 | * \brief set local addresses for the lower layers 265 | * 266 | * This function can be used to set the addresses for the lower layer protocols (presentation, session, and transport 267 | * layer). Calling this function is optional and not recommended. If not called the default 268 | * parameters are used. 269 | * 270 | * \param self the IsoConnectionParameters instance 271 | * \param pSelector the P-Selector (presentation layer address) 272 | * \param sSelector the S-Selector (session layer address) 273 | * \param tSelector the T-Selector (ISO transport layer address) 274 | */ 275 | LIB61850_API void 276 | IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, PSelector pSelector, SSelector sSelector, TSelector tSelector); 277 | 278 | /**@}*/ 279 | 280 | #ifdef __cplusplus 281 | } 282 | #endif 283 | 284 | #endif /* ISO_CONNECTION_PARAMETERS_H_ */ 285 | -------------------------------------------------------------------------------- /include/lib_memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * lib_memory.h 3 | * 4 | * Copyright 2014 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef MEMORY_H_ 25 | #define MEMORY_H_ 26 | 27 | #include "hal_base.h" 28 | 29 | #define CALLOC(nmemb, size) Memory_calloc(nmemb, size) 30 | #define MALLOC(size) Memory_malloc(size) 31 | #define REALLOC(oldptr, size) Memory_realloc(oldptr, size) 32 | #define FREEMEM(ptr) Memory_free(ptr) 33 | 34 | #define GLOBAL_CALLOC(nmemb, size) Memory_calloc(nmemb, size) 35 | #define GLOBAL_MALLOC(size) Memory_malloc(size) 36 | #define GLOBAL_REALLOC(oldptr, size) Memory_realloc(oldptr, size) 37 | #define GLOBAL_FREEMEM(ptr) Memory_free(ptr) 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | typedef void 44 | (*MemoryExceptionHandler) (void* parameter); 45 | 46 | PAL_API void 47 | Memory_installExceptionHandler(MemoryExceptionHandler handler, void* parameter); 48 | 49 | PAL_API void* 50 | Memory_malloc(size_t size); 51 | 52 | PAL_API void* 53 | Memory_calloc(size_t nmemb, size_t size); 54 | 55 | PAL_API void * 56 | Memory_realloc(void *ptr, size_t size); 57 | 58 | PAL_API void 59 | Memory_free(void* memb); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif /* MEMORY_H_ */ 66 | -------------------------------------------------------------------------------- /include/libiec61850_common_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libiec61850_common_api.h 3 | */ 4 | 5 | #ifndef LIBIEC61850_COMMON_API_INCLUDES_H_ 6 | #define LIBIEC61850_COMMON_API_INCLUDES_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef __GNUC__ 15 | #define ATTRIBUTE_PACKED __attribute__ ((__packed__)) 16 | #else 17 | #define ATTRIBUTE_PACKED 18 | #endif 19 | 20 | #ifndef DEPRECATED 21 | #if defined(__GNUC__) || defined(__clang__) 22 | #define DEPRECATED __attribute__((deprecated)) 23 | #else 24 | #define DEPRECATED 25 | #endif 26 | #endif 27 | 28 | #if defined _WIN32 || defined __CYGWIN__ 29 | #ifdef EXPORT_FUNCTIONS_FOR_DLL 30 | #define LIB61850_API __declspec(dllexport) 31 | #else 32 | #define LIB61850_API 33 | #endif 34 | 35 | #define LIB61850_INTERNAL 36 | #else 37 | #if __GNUC__ >= 4 38 | #define LIB61850_API __attribute__ ((visibility ("default"))) 39 | #define LIB61850_INTERNAL __attribute__ ((visibility ("hidden"))) 40 | #else 41 | #define LIB61850_API 42 | #define LIB61850_INTERNAL 43 | #endif 44 | #endif 45 | 46 | #include "hal_time.h" 47 | #include "mms_value.h" 48 | 49 | #endif /* LIBIEC61850_COMMON_API_INCLUDES_H_ */ 50 | -------------------------------------------------------------------------------- /include/linked_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * linked_list.h 3 | * 4 | * Copyright 2013-2021 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef LINKED_LIST_H_ 25 | #define LINKED_LIST_H_ 26 | 27 | #include "libiec61850_common_api.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /** 34 | * \addtogroup common_api_group 35 | */ 36 | /**@{*/ 37 | 38 | /** 39 | * \defgroup LINKED_LIST LinkedList data type definition and handling functions 40 | */ 41 | /**@{*/ 42 | 43 | 44 | struct sLinkedList { 45 | void* data; 46 | struct sLinkedList* next; 47 | }; 48 | 49 | /** 50 | * \brief Reference to a linked list or to a linked list element. 51 | */ 52 | typedef struct sLinkedList* LinkedList; 53 | 54 | /** 55 | * \brief Create a new LinkedList object 56 | * 57 | * \return the newly created LinkedList instance 58 | */ 59 | LIB61850_API LinkedList 60 | LinkedList_create(void); 61 | 62 | /** 63 | * \brief Delete a LinkedList object 64 | * 65 | * This function destroy the LinkedList object. It will free all data structures used by the LinkedList 66 | * instance. It will call free for all elements of the linked list. This function should only be used if 67 | * simple objects (like dynamically allocated strings) are stored in the linked list. 68 | * 69 | * \param self the LinkedList instance 70 | */ 71 | LIB61850_API void 72 | LinkedList_destroy(LinkedList self); 73 | 74 | 75 | typedef void (*LinkedListValueDeleteFunction) (void*); 76 | 77 | /** 78 | * \brief Delete a LinkedList object 79 | * 80 | * This function destroy the LinkedList object. It will free all data structures used by the LinkedList 81 | * instance. It will call a user provided function for each data element. This user provided function is 82 | * responsible to properly free the data element. 83 | * 84 | * \param self the LinkedList instance 85 | * \param valueDeleteFunction a function that is called for each data element of the LinkedList with the pointer 86 | * to the linked list data element. 87 | */ 88 | LIB61850_API void 89 | LinkedList_destroyDeep(LinkedList self, LinkedListValueDeleteFunction valueDeleteFunction); 90 | 91 | /** 92 | * \brief Delete a LinkedList object without freeing the element data 93 | * 94 | * This function should be used statically allocated data objects are stored in the LinkedList instance. 95 | * Other use cases would be if the data elements in the list should not be deleted. 96 | * 97 | * \param self the LinkedList instance 98 | */ 99 | LIB61850_API void 100 | LinkedList_destroyStatic(LinkedList self); 101 | 102 | /** 103 | * \brief Add a new element to the list 104 | * 105 | * This function will add a new data element to the list. The new element will the last element in the 106 | * list. 107 | * 108 | * \param self the LinkedList instance 109 | * \param data data to append to the LinkedList instance 110 | */ 111 | LIB61850_API void 112 | LinkedList_add(LinkedList self, void* data); 113 | 114 | /** 115 | * \brief Check if the specified data is contained in the list 116 | * 117 | * \param self the LinkedList instance 118 | * \param data data to remove from the LinkedList instance 119 | * 120 | * \return true if data is part of the list, false otherwise 121 | */ 122 | LIB61850_API bool 123 | LinkedList_contains(LinkedList self, void* data); 124 | 125 | /** 126 | * \brief Removed the specified element from the list 127 | * 128 | * \param self the LinkedList instance 129 | * \param data data to remove from the LinkedList instance 130 | * 131 | * \return true if data has been removed from the list, false otherwise 132 | */ 133 | LIB61850_API bool 134 | LinkedList_remove(LinkedList self, void* data); 135 | 136 | /** 137 | * \brief Get the list element specified by index (starting with 0). 138 | * 139 | * \param self the LinkedList instance 140 | * \param index index of the requested element. 141 | */ 142 | LIB61850_API LinkedList 143 | LinkedList_get(LinkedList self, int index); 144 | 145 | /** 146 | * \brief Get the next element in the list (iterator). 147 | * 148 | * \param self the LinkedList instance 149 | */ 150 | LIB61850_API LinkedList 151 | LinkedList_getNext(LinkedList self); 152 | 153 | /** 154 | * \brief Get the last element in the list. 155 | * 156 | * \param self the LinkedList instance 157 | */ 158 | LIB61850_API LinkedList 159 | LinkedList_getLastElement(LinkedList self); 160 | 161 | /** 162 | * \brief Insert a new element int the list 163 | * 164 | * \param listElement the LinkedList instance 165 | */ 166 | LIB61850_API LinkedList 167 | LinkedList_insertAfter(LinkedList listElement, void* data); 168 | 169 | /** 170 | * \brief Get the size of the list 171 | * 172 | * \param self the LinkedList instance 173 | * 174 | * \return number of data elements stored in the list 175 | */ 176 | LIB61850_API int 177 | LinkedList_size(LinkedList self); 178 | 179 | LIB61850_API void* 180 | LinkedList_getData(LinkedList self); 181 | 182 | LIB61850_API void 183 | LinkedList_printStringList(LinkedList self); 184 | 185 | /**@}*/ 186 | 187 | /**@}*/ 188 | 189 | #ifdef __cplusplus 190 | } 191 | #endif 192 | 193 | #endif /* LINKED_LIST_H_ */ 194 | -------------------------------------------------------------------------------- /include/logging_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * logging_api.h 3 | * 4 | * Copyright 2016 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ 25 | #define LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include "libiec61850_common_api.h" 32 | 33 | 34 | /** \addtogroup server_api_group 35 | * @{ 36 | */ 37 | 38 | /** 39 | * @defgroup LOGGING_SPI Service provider interface (SPI) for log storage implementations 40 | * 41 | * This interface has to be implemented by the log storage provider. The Log storage provider 42 | * has to provide a specific constructor that creates an instance of LogStorage by allocating 43 | * the required memory for the struct sLogStorage data structure and populate the function 44 | * pointers with provider specific implementation functions. 45 | * 46 | * @{ 47 | */ 48 | 49 | /** The LogStorage object handle */ 50 | typedef struct sLogStorage* LogStorage; 51 | 52 | /** 53 | * \brief Will be called for each new LogEntry by the getEntries and getEntriesAfter functions 54 | * 55 | * \param parameter - a user provided parameter that is passed to the callback handler 56 | * \param timestamp - the entry timestamp of the LogEntry 57 | * \param entryID - the entryID of the LogEntry 58 | * \param moreFollow - more data will follow - if false, the data is not valid and no more data will follow 59 | * 60 | * \return true ready to receive new data, false abort operation 61 | */ 62 | typedef bool (*LogEntryCallback) (void* parameter, uint64_t timestamp, uint64_t entryID, bool moreFollow); 63 | 64 | /** 65 | * \brief Will be called for each new LogEntryData by the getEntries and getEntriesAfter functions 66 | * 67 | * \param parameter - a user provided parameter that is passed to the callback handler 68 | * \param dataRef - the data reference of the LogEntryData 69 | * \param data - the data content as an unstructured binary data block 70 | * \param dataSize - the size of the binary data block 71 | * \param reasonCode - the reasonCode of the LogEntryData 72 | * \param moreFollow - more data will follow - if false, the data is not valid and no more data will follow 73 | * 74 | * \return true ready to receive new data, false abort operation 75 | */ 76 | typedef bool (*LogEntryDataCallback) (void* parameter, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow); 77 | 78 | struct sLogStorage { 79 | 80 | void* instanceData; 81 | 82 | int maxLogEntries; 83 | 84 | uint64_t (*addEntry) (LogStorage self, uint64_t timestamp); 85 | 86 | bool (*addEntryData) (LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode); 87 | 88 | bool (*getEntries) (LogStorage self, uint64_t startingTime, uint64_t endingTime, 89 | LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); 90 | 91 | bool (*getEntriesAfter) (LogStorage self, uint64_t startingTime, uint64_t entryID, 92 | LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); 93 | 94 | bool (*getOldestAndNewestEntries) (LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime, 95 | uint64_t* oldEntry, uint64_t* oldEntryTime); 96 | 97 | void (*destroy) (LogStorage self); 98 | }; 99 | 100 | 101 | /** 102 | * \brief Set the maximum number of log entries for this log 103 | * 104 | * \param self the pointer of the LogStorage instance 105 | * \param maxEntries the maximum number of log entries 106 | */ 107 | LIB61850_API void 108 | LogStorage_setMaxLogEntries(LogStorage self, int maxEntries); 109 | 110 | /** 111 | * \brief Get the maximum allowed number of log entries for this log 112 | * 113 | * \param self the pointer of the LogStorage instance 114 | * 115 | * \return the maximum number of log entries 116 | */ 117 | LIB61850_API int 118 | LogStorage_getMaxLogEntries(LogStorage self); 119 | 120 | /** 121 | * \brief Add an entry to the log 122 | * 123 | * \param self the pointer of the LogStorage instance 124 | * \param timestamp the entry time of the new entry 125 | * 126 | * \return the entryID of the new entry 127 | */ 128 | LIB61850_API uint64_t 129 | LogStorage_addEntry(LogStorage self, uint64_t timestamp); 130 | 131 | /** 132 | * \brief Add new entry data to an existing log entry 133 | * 134 | * \param self the pointer of the LogStorage instance 135 | * \param entryID the ID of the log entry where the data will be added 136 | * \param dataRef the data reference of the log entry data 137 | * \param data the data content as an unstructured binary data block 138 | * \param dataSize - the size of the binary data block 139 | * \param reasonCode - the reasonCode of the LogEntryData 140 | * 141 | * \return true if the entry data was successfully added, false otherwise 142 | */ 143 | LIB61850_API bool 144 | LogStorage_addEntryData(LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode); 145 | 146 | /** 147 | * \brief Get log entries specified by a time range 148 | * 149 | * \param self the pointer of the LogStorage instance 150 | * \param startingTime start time of the time range 151 | * \param endingTime end time of the time range 152 | * \param entryCallback callback function to be called for each new log entry 153 | * \param entryDataCallback callback function to be called for each new log entry data 154 | * \param parameter - a user provided parameter that is passed to the callback handler 155 | * 156 | * \return true if the request has been successful, false otherwise 157 | */ 158 | LIB61850_API bool 159 | LogStorage_getEntries(LogStorage self, uint64_t startingTime, uint64_t endingTime, 160 | LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); 161 | 162 | /** 163 | * \brief Get log entries specified by a start log entry 164 | * 165 | * The request will return all log entries that where entered into the log after the 166 | * log entry specified by startingTime and entryID. 167 | * 168 | * \param self the pointer of the LogStorage instance 169 | * \param startingTime timestamp of the start log entry 170 | * \param entryID entryID of the start log entry 171 | * \param entryCallback callback function to be called for each new log entry 172 | * \param entryDataCallback callback function to be called for each new log entry data 173 | * \param parameter - a user provided parameter that is passed to the callback handler 174 | * 175 | * \return true if the request has been successful, false otherwise 176 | */ 177 | LIB61850_API bool 178 | LogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_t entryID, 179 | LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter); 180 | 181 | /** 182 | * \brief Get the entry time and entryID of the oldest and the newest log entries 183 | * 184 | * This function is used to update the log status information in the LCB 185 | * 186 | * \param self the pointer of the LogStorage instance 187 | * \param newEntry pointer to store the entryID of the newest entry 188 | * \param newEntryTime pointer to store the entry time of the newest entry 189 | * \param oldEntry pointer to store the entryID of the oldest entry 190 | * \param oldEntryTime pointer to store the entry time of the oldest entry 191 | * 192 | */ 193 | LIB61850_API bool 194 | LogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime, 195 | uint64_t* oldEntry, uint64_t* oldEntryTime); 196 | 197 | /** 198 | * \brief Destroy the LogStorage instance and free all related resources 199 | * 200 | * \param self the pointer of the LogStorage instance 201 | */ 202 | LIB61850_API void 203 | LogStorage_destroy(LogStorage self); 204 | 205 | /**@}*/ 206 | 207 | /**@}*/ 208 | 209 | #ifdef __cplusplus 210 | } 211 | #endif 212 | 213 | #endif /* LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ */ 214 | -------------------------------------------------------------------------------- /include/mms_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mms_common.h 3 | * 4 | * Copyright 2013-2018 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #include "libiec61850_common_api.h" 25 | 26 | #ifndef MMS_COMMON_H_ 27 | #define MMS_COMMON_H_ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /** 34 | * \addtogroup common_api_group 35 | */ 36 | /**@{*/ 37 | 38 | typedef enum 39 | { 40 | /* generic error codes */ 41 | MMS_ERROR_NONE = 0, 42 | MMS_ERROR_CONNECTION_REJECTED = 1, 43 | MMS_ERROR_CONNECTION_LOST = 2, 44 | MMS_ERROR_SERVICE_TIMEOUT = 3, 45 | MMS_ERROR_PARSING_RESPONSE = 4, 46 | MMS_ERROR_HARDWARE_FAULT = 5, 47 | MMS_ERROR_CONCLUDE_REJECTED = 6, 48 | MMS_ERROR_INVALID_ARGUMENTS = 7, 49 | MMS_ERROR_OUTSTANDING_CALL_LIMIT = 8, 50 | 51 | MMS_ERROR_OTHER = 9, 52 | 53 | /* confirmed error PDU codes */ 54 | MMS_ERROR_VMDSTATE_OTHER = 10, 55 | 56 | MMS_ERROR_APPLICATION_REFERENCE_OTHER = 20, 57 | 58 | MMS_ERROR_DEFINITION_OTHER = 30, 59 | MMS_ERROR_DEFINITION_INVALID_ADDRESS = 31, 60 | MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED = 32, 61 | MMS_ERROR_DEFINITION_TYPE_INCONSISTENT = 33, 62 | MMS_ERROR_DEFINITION_OBJECT_UNDEFINED = 34, 63 | MMS_ERROR_DEFINITION_OBJECT_EXISTS = 35, 64 | MMS_ERROR_DEFINITION_OBJECT_ATTRIBUTE_INCONSISTENT = 36, 65 | 66 | MMS_ERROR_RESOURCE_OTHER = 40, 67 | MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE = 41, 68 | 69 | MMS_ERROR_SERVICE_OTHER = 50, 70 | MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT = 55, 71 | 72 | MMS_ERROR_SERVICE_PREEMPT_OTHER = 60, 73 | 74 | MMS_ERROR_TIME_RESOLUTION_OTHER = 70, 75 | 76 | MMS_ERROR_ACCESS_OTHER = 80, 77 | MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT = 81, 78 | MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED = 82, 79 | MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED = 83, 80 | MMS_ERROR_ACCESS_OBJECT_INVALIDATED = 84, 81 | MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID = 85, /* for DataAccessError 11 */ 82 | MMS_ERROR_ACCESS_TEMPORARILY_UNAVAILABLE = 86, /* for DataAccessError 2 */ 83 | 84 | MMS_ERROR_FILE_OTHER = 90, 85 | MMS_ERROR_FILE_FILENAME_AMBIGUOUS = 91, 86 | MMS_ERROR_FILE_FILE_BUSY = 92, 87 | MMS_ERROR_FILE_FILENAME_SYNTAX_ERROR = 93, 88 | MMS_ERROR_FILE_CONTENT_TYPE_INVALID = 94, 89 | MMS_ERROR_FILE_POSITION_INVALID = 95, 90 | MMS_ERROR_FILE_FILE_ACCESS_DENIED = 96, 91 | MMS_ERROR_FILE_FILE_NON_EXISTENT = 97, 92 | MMS_ERROR_FILE_DUPLICATE_FILENAME = 98, 93 | MMS_ERROR_FILE_INSUFFICIENT_SPACE_IN_FILESTORE = 99, 94 | 95 | /* reject codes */ 96 | MMS_ERROR_REJECT_OTHER = 100, 97 | MMS_ERROR_REJECT_UNKNOWN_PDU_TYPE = 101, 98 | MMS_ERROR_REJECT_INVALID_PDU = 102, 99 | MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE = 103, 100 | MMS_ERROR_REJECT_UNRECOGNIZED_MODIFIER = 104, 101 | MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT = 105 102 | 103 | } MmsError; 104 | 105 | typedef enum 106 | { 107 | /*! this represents all MMS array types (arrays contain uniform elements) */ 108 | MMS_ARRAY = 0, 109 | /*! this represents all complex MMS types (structures) */ 110 | MMS_STRUCTURE = 1, 111 | /*! boolean value */ 112 | MMS_BOOLEAN = 2, 113 | /*! bit string */ 114 | MMS_BIT_STRING = 3, 115 | /*! represents all signed integer types */ 116 | MMS_INTEGER = 4, 117 | /*! represents all unsigned integer types */ 118 | MMS_UNSIGNED = 5, 119 | /*! represents all float type (32 and 64 bit) */ 120 | MMS_FLOAT = 6, 121 | /*! octet string (unstructured bytes) */ 122 | MMS_OCTET_STRING = 7, 123 | /*! MMS visible string */ 124 | MMS_VISIBLE_STRING = 8, 125 | MMS_GENERALIZED_TIME = 9, 126 | MMS_BINARY_TIME = 10, 127 | MMS_BCD = 11, 128 | MMS_OBJ_ID = 12, 129 | /*! MMS unicode string */ 130 | MMS_STRING = 13, 131 | /*! MMS UTC time type */ 132 | MMS_UTC_TIME = 14, 133 | /*! This represents an error code as returned by MMS read services */ 134 | MMS_DATA_ACCESS_ERROR = 15 135 | } MmsType; 136 | 137 | typedef struct sMmsDomain MmsDomain; 138 | 139 | typedef struct sMmsAccessSpecifier 140 | { 141 | MmsDomain* domain; 142 | char* variableName; 143 | int arrayIndex; /* -1 --> no index present / ignore index */ 144 | char* componentName; 145 | } MmsAccessSpecifier; 146 | 147 | typedef struct 148 | { 149 | char* domainId; 150 | char* itemId; 151 | int32_t arrayIndex; /* -1 --> no index present / ignore index */ 152 | char* componentName; 153 | } MmsVariableAccessSpecification; 154 | 155 | typedef struct sMmsNamedVariableList* MmsNamedVariableList; 156 | typedef struct sMmsAccessSpecifier* MmsNamedVariableListEntry; 157 | 158 | /** 159 | * \brief ITU (International Telecommunication Union) object identifier (OID) 160 | */ 161 | typedef struct { 162 | uint16_t arc[10]; 163 | int arcCount; 164 | } ItuObjectIdentifier; 165 | 166 | /** 167 | * \brief ISO application reference (specifies an ISO application endpoint) 168 | */ 169 | typedef struct { 170 | ItuObjectIdentifier apTitle; 171 | int aeQualifier; 172 | } IsoApplicationReference; 173 | 174 | /**@}*/ 175 | 176 | 177 | #ifdef __cplusplus 178 | } 179 | #endif 180 | 181 | #endif /* MMS_COMMON_H_ */ 182 | -------------------------------------------------------------------------------- /include/mms_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mms_server.h 3 | * 4 | * Copyright 2013-2018 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef MMS_SERVER_H_ 25 | #define MMS_SERVER_H_ 26 | 27 | /** \addtogroup mms_server_api_group 28 | * @{ 29 | */ 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include "mms_value.h" 36 | #include "iso_connection_parameters.h" 37 | 38 | typedef enum { 39 | MMS_SERVER_NEW_CONNECTION, 40 | MMS_SERVER_CONNECTION_CLOSED, 41 | MMS_SERVER_CONNECTION_TICK 42 | } MmsServerEvent; 43 | 44 | typedef struct sMmsServer* MmsServer; 45 | 46 | typedef struct sMmsServerConnection* MmsServerConnection; 47 | 48 | typedef enum { 49 | MMS_DOMAIN_SPECIFIC, 50 | MMS_ASSOCIATION_SPECIFIC, 51 | MMS_VMD_SPECIFIC 52 | } MmsVariableListType; 53 | 54 | LIB61850_INTERNAL void 55 | MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress); 56 | 57 | LIB61850_INTERNAL bool 58 | MmsServer_isRunning(MmsServer self); 59 | 60 | /** 61 | * \brief callback handler that is called whenever a named variable list changes 62 | * 63 | * \param parameter a user provided parameter 64 | * \param create if true the the request if a request to create a new variable list, false is a delete request 65 | * \param listType the type (scope) of the named variable list (either domain, association or VMD specific) 66 | * \param domain the MMS domain the list is belonging to (is NULL for association or VMD specific lists!) 67 | * \param listName the name 68 | * \param connection client connection that requests the creation of deletion of the variable list 69 | * 70 | * \return MMS_ERROR_NONE if the request is accepted, otherwise the MmsError value that has to be sent back to the client 71 | */ 72 | typedef MmsError (*MmsNamedVariableListChangedHandler)(void* parameter, bool create, MmsVariableListType listType, MmsDomain* domain, 73 | char* listName, MmsServerConnection connection); 74 | 75 | /** 76 | * \brief Install callback handler that is called when a named variable list changes (is created or deleted) 77 | * 78 | * \param self the MmsServer instance to operate on 79 | * \param handler the callback handler function 80 | * \param parameter user provided parameter that is passed to the callback handler 81 | */ 82 | LIB61850_INTERNAL void 83 | MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableListChangedHandler handler, void* parameter); 84 | 85 | /** 86 | * \brief ObtainFile service callback handler 87 | * 88 | * This is invoked when the obtainFile service is requested by the client. It can be used to accept or deny the 89 | * write access to the file system based on the client connection. 90 | * 91 | * \param parameter user provided parameter that is passed to the callback handler 92 | * \param connection the connection that requested the service 93 | * \param sourceFilename the source file name on the client side system 94 | * \param destinationFilename the target file name on the server side system 95 | */ 96 | typedef bool (*MmsObtainFileHandler)(void* parameter, MmsServerConnection connection, const char* sourceFilename, const char* destinationFilename); 97 | 98 | /** 99 | * \brief Install callback handler that is invoked when the file upload (obtainFile service) is invoked by the client 100 | * 101 | * This handler can be used to apply access restrictions on the file upload (obtainFile) service 102 | * 103 | * \param self the MmsServer instance to operate on 104 | * \param handler the callback handler function 105 | * \param parameter user provided parameter that is passed to the callback handler 106 | */ 107 | LIB61850_INTERNAL void 108 | MmsServer_installObtainFileHandler(MmsServer self, MmsObtainFileHandler handler, void* parameter); 109 | 110 | /** 111 | * \brief Get file complete (obtainFile service terminated) callback handler 112 | * 113 | * This handler can be used to invoke some actions after a file upload is complete. 114 | * 115 | * \param parameter user provided parameter that is passed to the callback handler 116 | * \param connection the connection that requested the service 117 | * \param destinationFilename the target file name on the server side system 118 | */ 119 | typedef void (*MmsGetFileCompleteHandler)(void* parameter, MmsServerConnection connection, const char* destinationFilename); 120 | 121 | /** 122 | * \brief Install callback handler that is invoked when the file upload (obtainFile service) is completed and the 123 | * file has been uploaded. 124 | * 125 | * \param self the MmsServer instance 126 | * \param handler the callback handler function 127 | * \param parameter user provided parameter that is passed to the callback handler 128 | */ 129 | LIB61850_INTERNAL void 130 | MmsServer_installGetFileCompleteHandler(MmsServer self, MmsGetFileCompleteHandler handler, void* parameter); 131 | 132 | 133 | typedef enum { 134 | MMS_FILE_ACCESS_TYPE_READ_DIRECTORY, 135 | MMS_FILE_ACCESS_TYPE_OPEN, 136 | MMS_FILE_ACCESS_TYPE_OBTAIN, 137 | MMS_FILE_ACCESS_TYPE_DELETE, 138 | MMS_FILE_ACCESS_TYPE_RENAME 139 | } MmsFileServiceType; 140 | 141 | /** 142 | * \brief MmsFileAccessHandler callback function. Use to monitor and control file access 143 | * 144 | * \param parameter user provided parameter that is passed to the callback handler 145 | * \param connection the connection that requested the service 146 | * \param service the requested file service 147 | * \param localFilename the requested file or directory name at the server 148 | * \param otherFilename a second file name parameter (e.g. source file of the ObtainFile or new file of rename file) 149 | * 150 | * \return MMS_ERROR_NONE when the request is accepted, otherwise use the appropriate error code (e.g. MMS_ERROR_FILE_FILE_ACCESS_DENIED) 151 | */ 152 | typedef MmsError (*MmsFileAccessHandler) (void* parameter, MmsServerConnection connection, MmsFileServiceType service, 153 | const char* localFilename, const char* otherFilename); 154 | 155 | 156 | /** 157 | * \brief Install a callback handler this is invoked when the client requests a file server. This function can be 158 | * used to monitor and control file access 159 | * 160 | * \param self the MmsServer instance 161 | * \param handler the callback handler function 162 | * \param parameter user provided parameter that is passed to the callback handler 163 | */ 164 | LIB61850_API void 165 | MmsServer_installFileAccessHandler(MmsServer self, MmsFileAccessHandler handler, void* parameter); 166 | 167 | /** 168 | * \brief Set the virtual filestore basepath for the MMS file services 169 | * 170 | * All external file service accesses will be mapped to paths relative to the base directory. 171 | * NOTE: This function is only available when the CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME 172 | * option in stack_config.h is set. 173 | * 174 | * \param self the MmsServer instance 175 | * \param basepath the new virtual filestore basepath 176 | */ 177 | LIB61850_INTERNAL void 178 | MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath); 179 | 180 | /** 181 | * \brief Set the maximum number of TCP client connections 182 | * 183 | * \param[in] maxConnections the maximum number of TCP client connections to accept 184 | */ 185 | LIB61850_INTERNAL void 186 | MmsServer_setMaxConnections(MmsServer self, int maxConnections); 187 | 188 | /** 189 | * \brief Enable/disable MMS file services at runtime 190 | * 191 | * NOTE: requires CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME = 1 in stack configuration 192 | * 193 | * \param[in] self the MmsServer instance 194 | * \param[in] enable true to enable file services, false to disable 195 | */ 196 | LIB61850_INTERNAL void 197 | MmsServer_enableFileService(MmsServer self, bool enable); 198 | 199 | /** 200 | * \brief Enable/disable dynamic named variable list (data set) service 201 | * 202 | * NOTE: requires CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME = 1 in stack configuration 203 | * 204 | * \param[in] self the MmsServer instance 205 | * \param[in] enable true to enable named variable list services, false to disable 206 | */ 207 | LIB61850_INTERNAL void 208 | MmsServer_enableDynamicNamedVariableListService(MmsServer self, bool enable); 209 | 210 | /** 211 | * \brief Set the maximum number of association specific data sets (per connection) 212 | * 213 | * \param[in] self the MmsServer instance 214 | * \param[in] maxDataSets maximum number association specific data sets 215 | */ 216 | LIB61850_INTERNAL void 217 | MmsServer_setMaxAssociationSpecificDataSets(MmsServer self, int maxDataSets); 218 | 219 | /** 220 | * \brief Set the maximum number of domain specific data sets 221 | * 222 | * \param[in] self the MmsServer instance 223 | * \param[in] maxDataSets maximum number domain specific data sets 224 | */ 225 | LIB61850_INTERNAL void 226 | MmsServer_setMaxDomainSpecificDataSets(MmsServer self, int maxDataSets); 227 | 228 | /** 229 | * \brief Set the maximum number of data set entries (for dynamic data sets) 230 | * 231 | * \param[in] self the MmsServer instance 232 | * \param[in] maxDataSetEntries maximum number of dynamic data set entries 233 | */ 234 | LIB61850_INTERNAL void 235 | MmsServer_setMaxDataSetEntries(MmsServer self, int maxDataSetEntries); 236 | 237 | /** 238 | * \brief Enable/disable journal service 239 | * 240 | * NOTE: requires CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME = 1 in stack configuration 241 | * 242 | * \param[in] self the MmsServer instance 243 | * \param[in] enable true to enable journal service, false to disable 244 | */ 245 | LIB61850_INTERNAL void 246 | MmsServer_enableJournalService(MmsServer self, bool enable); 247 | 248 | 249 | 250 | 251 | 252 | /*************************************************** 253 | * Functions for MMS identify service 254 | ***************************************************/ 255 | 256 | /** 257 | * \brief set the values that the server will give as response for an MMS identify request 258 | * 259 | * With this function the VMD identity attributes can be set programmatically. If not set by this 260 | * function the default values form stack_config.h are used. 261 | * 262 | * \param self the MmsServer instance to operate on 263 | * \param vendorName the vendor name attribute of the VMD 264 | * \param modelName the model name attribute of the VMD 265 | * \param revision the revision attribute of the VMD 266 | */ 267 | LIB61850_INTERNAL void 268 | MmsServer_setServerIdentity(MmsServer self, char* vendorName, char* modelName, char* revision); 269 | 270 | /** 271 | * \brief get the vendor name attribute of the VMD identity 272 | * 273 | * \param self the MmsServer instance to operate on 274 | * \return the vendor name attribute of the VMD as C string 275 | */ 276 | LIB61850_INTERNAL char* 277 | MmsServer_getVendorName(MmsServer self); 278 | 279 | /** 280 | * \brief get the model name attribute of the VMD identity 281 | * 282 | * \param self the MmsServer instance to operate on 283 | * \return the model name attribute of the VMD as C string 284 | */ 285 | LIB61850_INTERNAL char* 286 | MmsServer_getModelName(MmsServer self); 287 | 288 | /** 289 | * \brief get the revision attribute of the VMD identity 290 | * 291 | * \param self the MmsServer instance to operate on 292 | * \return the revision attribute of the VMD as C string 293 | */ 294 | LIB61850_INTERNAL char* 295 | MmsServer_getRevision(MmsServer self); 296 | 297 | /*************************************************** 298 | * Functions for MMS status service 299 | ***************************************************/ 300 | 301 | #define MMS_LOGICAL_STATE_STATE_CHANGES_ALLOWED 0 302 | #define MMS_LOGICAL_STATE_NO_STATE_CHANGES_ALLOWED 1 303 | #define MMS_LOGICAL_STATE_LIMITED_SERVICES_PERMITTED 2 304 | #define MMS_LOGICAL_STATE_SUPPORT_SERVICES_ALLOWED 3 305 | 306 | #define MMS_PHYSICAL_STATE_OPERATIONAL 0 307 | #define MMS_PHYSICAL_STATE_PARTIALLY_OPERATIONAL 1 308 | #define MMS_PHYSICAL_STATE_INOPERATIONAL 2 309 | #define MMS_PHYSICAL_STATE_NEEDS_COMMISSIONING 3 310 | 311 | /** 312 | * \brief User provided handler that is invoked on a MMS status request 313 | * 314 | * The extendedDerivation parameter indicates that the client requests the server to perform 315 | * self diagnosis tests before answering the request. 316 | * 317 | * \param parameter is a user provided parameter 318 | * \param mmsServer is the MmsServer instance 319 | * \param connection is the MmsServerConnection instance that received the MMS status request 320 | * \param extendedDerivation indicates if the request contains the extendedDerivation parameter 321 | */ 322 | typedef void (*MmsStatusRequestListener)(void* parameter, MmsServer mmsServer, MmsServerConnection connection, bool extendedDerivation); 323 | 324 | /** 325 | * \brief set the VMD state values for the VMD status service 326 | * 327 | * \param self the MmsServer instance to operate on 328 | * \param vmdLogicalStatus the logical status attribute of the VMD 329 | * \param vmdPhysicalStatus the physical status attribute of the VMD 330 | */ 331 | LIB61850_INTERNAL void 332 | MmsServer_setVMDStatus(MmsServer self, int vmdLogicalStatus, int vmdPhysicalStatus); 333 | 334 | /** 335 | * \brief get the logical status attribute of the VMD 336 | * 337 | * \param self the MmsServer instance to operate on 338 | */ 339 | LIB61850_INTERNAL int 340 | MmsServer_getVMDLogicalStatus(MmsServer self); 341 | 342 | /** 343 | * \brief get the physical status attribute of the VMD 344 | * 345 | * \param self the MmsServer instance to operate on 346 | */ 347 | LIB61850_INTERNAL int 348 | MmsServer_getVMDPhysicalStatus(MmsServer self); 349 | 350 | /** 351 | * \brief set the MmsStatusRequestListener for this MmsServer 352 | * 353 | * With this function the API user can register a listener that is invoked whenever a 354 | * MMS status request is received from a client. Inside of the handler the user can 355 | * provide new status values with the MmsServer_setVMDStatus function. 356 | * 357 | * \param self the MmsServer instance to operate on 358 | * \param listener the listener that is called when a MMS status request is received 359 | * \param parameter a user provided parameter that is handed over to the listener 360 | */ 361 | LIB61850_INTERNAL void 362 | MmsServer_setStatusRequestListener(MmsServer self, MmsStatusRequestListener listener, void* parameter); 363 | 364 | LIB61850_INTERNAL char* 365 | MmsServerConnection_getClientAddress(MmsServerConnection self); 366 | 367 | LIB61850_INTERNAL char* 368 | MmsServerConnection_getLocalAddress(MmsServerConnection self); 369 | 370 | LIB61850_INTERNAL void* 371 | MmsServerConnection_getSecurityToken(MmsServerConnection self); 372 | 373 | /**@}*/ 374 | 375 | #ifdef __cplusplus 376 | } 377 | #endif 378 | 379 | #endif /* MMS_SERVER_H_ */ 380 | -------------------------------------------------------------------------------- /include/mms_type_spec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mms_type_spec.h 3 | * 4 | * MmsTypeSpecfication objects are used to describe simple and complex MMS types. 5 | * Complex types are arrays or structures of simple and complex types. 6 | * They also represent MMS NamedVariables. 7 | * 8 | * Copyright 2013-2019 Michael Zillgith 9 | * 10 | * This file is part of libIEC61850. 11 | * 12 | * libIEC61850 is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation, either version 3 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * libIEC61850 is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License 23 | * along with libIEC61850. If not, see . 24 | * 25 | * See COPYING file for the complete license text. 26 | */ 27 | 28 | #ifndef MMS_TYPE_SPEC_H_ 29 | #define MMS_TYPE_SPEC_H_ 30 | 31 | #include "libiec61850_common_api.h" 32 | #include "mms_common.h" 33 | #include "mms_types.h" 34 | #include "linked_list.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** 41 | * \addtogroup common_api_group 42 | */ 43 | /**@{*/ 44 | 45 | /** 46 | * \defgroup MMS_VAR_SPEC MmsVariableSpecification data type specifications 47 | */ 48 | /**@{*/ 49 | 50 | /** 51 | * \brief Delete MmsTypeSpecification object (recursive). 52 | * 53 | * \param self the MmsVariableSpecification instance 54 | */ 55 | LIB61850_API void 56 | MmsVariableSpecification_destroy(MmsVariableSpecification* self); 57 | 58 | /** 59 | * \brief Get the corresponding child of value according to childId. 60 | * 61 | * This function assumes that value is the corresponding value of the MMS variable self. 62 | * Given the relative name of a child of self this function returns the corresponding child 63 | * of the value object. Note: the child name has to be provided in MMS mapping syntax (with 64 | * "$" sign as separator between path name elements! 65 | * 66 | * \param self the MmsVariableSpecification instance 67 | * \param value the MmsValue instance 68 | * \param childId the relative MMS name to the child MMS variable (with "$" separators!) 69 | * 70 | */ 71 | LIB61850_API MmsValue* 72 | MmsVariableSpecification_getChildValue(MmsVariableSpecification* self, MmsValue* value, const char* childId); 73 | 74 | /** 75 | * \brief Get the child of self specified by its relative name 76 | * 77 | * \param self the MmsVariableSpecification instance 78 | * \param nameId the relative MMS name to the child MMS variable (with "$" separators!) 79 | * 80 | * \return the variable specification of the child or NULL if not existing. 81 | */ 82 | LIB61850_API MmsVariableSpecification* 83 | MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* self, const char* nameId); 84 | 85 | /** 86 | * \brief get the MMS type of the variable 87 | * 88 | * \param self the MmsVariableSpecification instance 89 | * 90 | * \return the MMS type of the variable 91 | */ 92 | LIB61850_API MmsType 93 | MmsVariableSpecification_getType(MmsVariableSpecification* self); 94 | 95 | /** 96 | * \brief Check if the value has exactly the same type as this variable specfication 97 | * 98 | * \param self the MmsVariableSpecification instance 99 | * \param value the value to check 100 | * 101 | * \return true if type is matching, false otherwise 102 | */ 103 | LIB61850_API bool 104 | MmsVariableSpecification_isValueOfType(MmsVariableSpecification* self, MmsValue* value); 105 | 106 | /** 107 | * \brief get the name of the variable 108 | * 109 | * Note: the return string is only valid as long as the MmsVariableSpecification 110 | * instance exists! 111 | * 112 | * \param self the MmsVariableSpecification instance 113 | * 114 | * \return the name of the variable 115 | */ 116 | LIB61850_API const char* 117 | MmsVariableSpecification_getName(MmsVariableSpecification* self); 118 | 119 | LIB61850_API LinkedList /* */ 120 | MmsVariableSpecification_getStructureElements(MmsVariableSpecification* self); 121 | 122 | /** 123 | * \brief returns the number of elements if the type is a complex type (structure, array) or the 124 | * bit size of integers, unsigned integers, floats, bit strings, visible and MMS strings and octet strings. 125 | * 126 | * 127 | * 128 | * \param self the MmsVariableSpecification object 129 | * 130 | * \return the number of elements or -1 if not applicable 131 | */ 132 | LIB61850_API int 133 | MmsVariableSpecification_getSize(MmsVariableSpecification* self); 134 | 135 | LIB61850_API MmsVariableSpecification* 136 | MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification* self, int index); 137 | 138 | /** 139 | * \brief return the MmsVariableSpecification of a structure element with the given name 140 | * 141 | * \param self the MmsVariableSpecification object 142 | * \param name the name of the component (structure element) 143 | * \param index (OUT) if not NULL the index of the structure element will be stored there 144 | * 145 | * \return the type specification of the component or NULL if the component was not found 146 | */ 147 | LIB61850_API MmsVariableSpecification* 148 | MmsVariableSpecification_getChildSpecificationByName(MmsVariableSpecification* self, const char* name, int* index); 149 | 150 | LIB61850_API MmsVariableSpecification* 151 | MmsVariableSpecification_getArrayElementSpecification(MmsVariableSpecification* self); 152 | 153 | LIB61850_API int 154 | MmsVariableSpecification_getExponentWidth(MmsVariableSpecification* self); 155 | 156 | /**@}*/ 157 | 158 | /**@}*/ 159 | 160 | #ifdef __cplusplus 161 | } 162 | #endif 163 | 164 | #endif /* MMS_TYPE_SPEC_H_ */ 165 | -------------------------------------------------------------------------------- /include/mms_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mms_types.h 3 | * 4 | * Copyright 2013, 2014 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef MMS_TYPES_H_ 25 | #define MMS_TYPES_H_ 26 | 27 | #include "libiec61850_common_api.h" 28 | 29 | typedef enum { 30 | MMS_VALUE_NO_RESPONSE, 31 | MMS_VALUE_OK, 32 | MMS_VALUE_ACCESS_DENIED, 33 | MMS_VALUE_VALUE_INVALID, 34 | MMS_VALUE_TEMPORARILY_UNAVAILABLE, 35 | MMS_VALUE_OBJECT_ACCESS_UNSUPPORTED 36 | } MmsValueIndication; 37 | 38 | /** 39 | * \addtogroup MMS_VAR_SPEC 40 | */ 41 | /**@{*/ 42 | 43 | /** 44 | * Type definition for MMS Named Variables 45 | */ 46 | typedef struct sMmsVariableSpecification MmsVariableSpecification; 47 | 48 | /**@}*/ 49 | 50 | struct ATTRIBUTE_PACKED sMmsVariableSpecification { 51 | MmsType type; 52 | char* name; 53 | union uMmsTypeSpecification 54 | { 55 | struct sMmsArray { 56 | int elementCount; /* number of array elements */ 57 | MmsVariableSpecification* elementTypeSpec; 58 | } array; 59 | struct sMmsStructure { 60 | int elementCount; 61 | MmsVariableSpecification** elements; 62 | } structure; 63 | int boolean; /* dummy - not required */ 64 | int integer; /* size of integer in bits */ 65 | int unsignedInteger; /* size of integer in bits */ 66 | struct sMmsFloat 67 | { 68 | uint8_t exponentWidth; 69 | uint8_t formatWidth; 70 | } floatingpoint; 71 | int bitString; /* Number of bits in bitstring */ 72 | int octetString; /* Number of octets in octet string */ 73 | int visibleString; /* Maximum size of string */ 74 | int mmsString; 75 | int utctime; /* dummy - not required */ 76 | int binaryTime; /* size: either 4 or 6 */ 77 | } typeSpec; 78 | }; 79 | 80 | 81 | #endif /* MMS_TYPES_H_ */ 82 | -------------------------------------------------------------------------------- /include/sv_publisher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sv_publisher.h 3 | * 4 | * Copyright 2016-2018 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | 25 | #ifndef LIBIEC61850_SRC_SAMPLED_VALUES_SV_PUBLISHER_H_ 26 | #define LIBIEC61850_SRC_SAMPLED_VALUES_SV_PUBLISHER_H_ 27 | 28 | #include "iec61850_common.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #ifndef GOOSE_SV_COMM_PARAMETERS 35 | #define GOOSE_SV_COMM_PARAMETERS 36 | 37 | typedef struct sCommParameters { 38 | uint8_t vlanPriority; 39 | uint16_t vlanId; 40 | uint16_t appId; 41 | uint8_t dstAddress[6]; 42 | } CommParameters; 43 | 44 | #endif 45 | 46 | /** 47 | * \defgroup sv_publisher_api_group IEC 61850 Sampled Values (SV) publisher API 48 | */ 49 | /**@{*/ 50 | 51 | #define IEC61850_SV_SMPSYNC_NOT_SYNCHRONIZED 0 52 | #define IEC61850_SV_SMPSYNC_SYNCED_UNSPEC_LOCAL_CLOCK 1 53 | #define IEC61850_SV_SMPSYNC_SYNCED_GLOBAL_CLOCK 2 54 | 55 | #define IEC61850_SV_SMPMOD_PER_NOMINAL_PERIOD 0 56 | #define IEC61850_SV_SMPMOD_SAMPLES_PER_SECOND 1 57 | #define IEC61850_SV_SMPMOD_SECONDS_PER_SAMPLE 2 58 | 59 | /** 60 | * \brief An opaque type representing an IEC 61850-9-2 Sampled Values publisher. 61 | */ 62 | typedef struct sSVPublisher* SVPublisher; 63 | 64 | /** 65 | * \brief An opaque type representing an IEC 61850-9-2 Sampled Values Application Service Data Unit (ASDU). 66 | */ 67 | typedef struct sSVPublisher_ASDU* SVPublisher_ASDU; 68 | 69 | /** 70 | * \brief Create a new IEC61850-9-2 Sampled Values publisher. 71 | * 72 | * NOTE: VLAN tagging is enabled when calling this constructor. To disable VLAN tagging 73 | * use \ref SVPublisher_createEx instead. 74 | * 75 | * \param[in] interfaceId the name of the interface over which the SV publisher should send SV packets. 76 | * \param[in] parameters optional parameters for setting VLAN options and destination MAC address. Use NULL for default values. 77 | * \return the new SV publisher instance. 78 | */ 79 | LIB61850_API SVPublisher 80 | SVPublisher_create(CommParameters* parameters, const char* interfaceId); 81 | 82 | /** 83 | * \brief Create a new IEC61850-9-2 Sampled Values publisher. 84 | * 85 | * \param[in] interfaceId the name of the interface over which the SV publisher should send SV packets. 86 | * \param[in] parameters optional parameters for setting VLAN options and destination MAC address. Use NULL for default values. 87 | * \param[in] useVlanTags enable(true)/disable(false) VLAN tagging 88 | * \return the new SV publisher instance. 89 | */ 90 | LIB61850_API SVPublisher 91 | SVPublisher_createEx(CommParameters* parameters, const char* interfaceId, bool useVlanTag); 92 | 93 | /** 94 | * \brief Create an Application Service Data Unit (ASDU) and add it to an existing Sampled Values publisher. 95 | * 96 | * \param[in] svID 97 | * \param[in] datset 98 | * \param[in] confRev Configuration revision number. Should be incremented each time that the configuration of the logical device changes. 99 | * \return the new ASDU instance. 100 | */ 101 | LIB61850_API SVPublisher_ASDU 102 | SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev); 103 | 104 | /** 105 | * \brief Prepare the publisher for publishing. 106 | * 107 | * This method must be called before SVPublisher_publish(). 108 | * 109 | * \param[in] self the Sampled Values publisher instance. 110 | */ 111 | LIB61850_API void 112 | SVPublisher_setupComplete(SVPublisher self); 113 | 114 | /** 115 | * \brief Publish all registered ASDUs 116 | * 117 | * \param[in] self the Sampled Values publisher instance. 118 | */ 119 | LIB61850_API void 120 | SVPublisher_publish(SVPublisher self); 121 | 122 | /** 123 | * \brief Destroy an IEC61850-9-2 Sampled Values instance. 124 | * 125 | * \param[in] self the Sampled Values publisher instance. 126 | */ 127 | LIB61850_API void 128 | SVPublisher_destroy(SVPublisher self); 129 | 130 | /** 131 | * \addtogroup sv_publisher_asdu_group Values Application Service Data Unit (ASDU) 132 | * @{ 133 | */ 134 | 135 | /** 136 | * \brief Reset the internal data buffer of an ASDU. 137 | * 138 | * All data elements added by SVPublisher_ASDU_add*() functions are removed. 139 | * SVPublisher_setupComplete() must be called afterwards. 140 | * 141 | * \param[in] self the Sampled Values ASDU instance. 142 | */ 143 | LIB61850_API void 144 | SVPublisher_ASDU_resetBuffer(SVPublisher_ASDU self); 145 | 146 | /** 147 | * \brief Reserve memory for a signed 8-bit integer in the ASDU. 148 | * 149 | * \param[in] self the Sampled Values ASDU instance. 150 | * \return the offset in bytes within the ASDU data block. 151 | */ 152 | LIB61850_API int 153 | SVPublisher_ASDU_addINT8(SVPublisher_ASDU self); 154 | 155 | /** 156 | * \brief Set the value of a 8-bit integer in the ASDU. 157 | * 158 | * \param[in] self the Sampled Values ASDU instance. 159 | * \param[in] index The offset within the data block of the ASDU in bytes. 160 | * \param[in] value The value which should be set. 161 | */ 162 | LIB61850_API void 163 | SVPublisher_ASDU_setINT8(SVPublisher_ASDU self, int index, int8_t value); 164 | 165 | /** 166 | * \brief Reserve memory for a signed 32-bit integer in the ASDU. 167 | * 168 | * \param[in] self the Sampled Values ASDU instance. 169 | * \return the offset in bytes within the ASDU data block. 170 | */ 171 | LIB61850_API int 172 | SVPublisher_ASDU_addINT32(SVPublisher_ASDU self); 173 | 174 | /** 175 | * \brief Set the value of a 32-bit integer in the ASDU. 176 | * 177 | * \param[in] self the Sampled Values ASDU instance. 178 | * \param[in] index The offset within the data block of the ASDU in bytes. 179 | * \param[in] value The value which should be set. 180 | */ 181 | LIB61850_API void 182 | SVPublisher_ASDU_setINT32(SVPublisher_ASDU self, int index, int32_t value); 183 | 184 | /** 185 | * \brief Reserve memory for a signed 64-bit integer in the ASDU. 186 | * 187 | * \param[in] self the Sampled Values ASDU instance. 188 | * \return the offset in bytes of the new element within the ASDU data block. 189 | */ 190 | LIB61850_API int 191 | SVPublisher_ASDU_addINT64(SVPublisher_ASDU self); 192 | 193 | /** 194 | * \brief Set the value of a 64-bit integer in the ASDU. 195 | * 196 | * \param[in] self the Sampled Values ASDU instance. 197 | * \param[in] index The offset within the data block of the ASDU in bytes. 198 | * \param[in] value The value which should be set. 199 | */ 200 | LIB61850_API void 201 | SVPublisher_ASDU_setINT64(SVPublisher_ASDU self, int index, int64_t value); 202 | 203 | /** 204 | * \brief Reserve memory for a single precision floating point number in the ASDU. 205 | * 206 | * \param[in] self the Sampled Values ASDU instance. 207 | * \return the offset in bytes of the new element within the ASDU data block. 208 | */ 209 | LIB61850_API int 210 | SVPublisher_ASDU_addFLOAT(SVPublisher_ASDU self); 211 | 212 | /** 213 | * \brief Set the value of a single precision floating point number in the ASDU. 214 | * 215 | * \param[in] self the Sampled Values ASDU instance. 216 | * \param[in] index The offset within the data block of the ASDU in bytes. 217 | * \param[in] value The value which should be set. 218 | */ 219 | LIB61850_API void 220 | SVPublisher_ASDU_setFLOAT(SVPublisher_ASDU self, int index, float value); 221 | 222 | /** 223 | * \brief Reserve memory for a double precision floating point number in the ASDU. 224 | * 225 | * \param[in] self the Sampled Values ASDU instance. 226 | * \return the offset in bytes of the new element within the ASDU data block. 227 | */ 228 | LIB61850_API int 229 | SVPublisher_ASDU_addFLOAT64(SVPublisher_ASDU self); 230 | 231 | /** 232 | * \brief Set the value of a double precision floating pointer number in the ASDU. 233 | * 234 | * \param[in] self the Sampled Values ASDU instance. 235 | * \param[in] index The offset within the data block of the ASDU in bytes. 236 | * \param[in] value The value which should be set. 237 | */ 238 | LIB61850_API void 239 | SVPublisher_ASDU_setFLOAT64(SVPublisher_ASDU self, int index, double value); 240 | 241 | /** 242 | * \brief Reserve memory for a 64 bit time stamp in the ASDU 243 | * 244 | * \param[in] self the Sampled Values ASDU instance. 245 | * \return the offset in bytes of the new element within the ASDU data block. 246 | */ 247 | LIB61850_API int 248 | SVPublisher_ASDU_addTimestamp(SVPublisher_ASDU self); 249 | 250 | /** 251 | * \brief Set the value of a 64 bit time stamp in the ASDU. 252 | * 253 | * \param[in] self the Sampled Values ASDU instance. 254 | * \param[in] index The offset within the data block of the ASDU in bytes. 255 | * \param[in] value The value which should be set. 256 | */ 257 | LIB61850_API void 258 | SVPublisher_ASDU_setTimestamp(SVPublisher_ASDU self, int index, Timestamp value); 259 | 260 | /** 261 | * \brief Reserve memory for a quality value in the ASDU 262 | * 263 | * NOTE: Quality is encoded as BITSTRING (4 byte) 264 | * 265 | * \param[in] self the Sampled Values ASDU instance. 266 | * \return the offset in bytes of the new element within the ASDU data block. 267 | */ 268 | LIB61850_API int 269 | SVPublisher_ASDU_addQuality(SVPublisher_ASDU self); 270 | 271 | /** 272 | * \brief Set the value of a quality attribute in the ASDU. 273 | * 274 | * \param[in] self the Sampled Values ASDU instance. 275 | * \param[in] index The offset within the data block of the ASDU in bytes. 276 | * \param[in] value The value which should be set. 277 | */ 278 | LIB61850_API void 279 | SVPublisher_ASDU_setQuality(SVPublisher_ASDU self, int index, Quality value); 280 | 281 | /** 282 | * \brief Set the sample count attribute of the ASDU. 283 | * 284 | * \param[in] self the Sampled Values ASDU instance. 285 | * \param[in] value the new value of the attribute. 286 | */ 287 | LIB61850_API void 288 | SVPublisher_ASDU_setSmpCnt(SVPublisher_ASDU self, uint16_t value); 289 | 290 | /** 291 | * \brief Get the sample count attribute of the ASDU. 292 | * 293 | * \param[in] self the Sampled Values ASDU instance. 294 | */ 295 | LIB61850_API uint16_t 296 | SVPublisher_ASDU_getSmpCnt(SVPublisher_ASDU self); 297 | 298 | /** 299 | * \brief Increment the sample count attribute of the ASDU. 300 | * 301 | * The parameter SmpCnt shall contain the values of a counter, which is incremented each time a new sample of the analogue value is taken. 302 | * The sample values shall be kept in the right order. 303 | * If the counter is used to indicate time consistency of various sampled values, the counter shall be reset by an external synchronization event. 304 | * 305 | * \param[in] self the Sampled Values ASDU instance. 306 | */ 307 | LIB61850_API void 308 | SVPublisher_ASDU_increaseSmpCnt(SVPublisher_ASDU self); 309 | 310 | /** 311 | * \brief Set the roll-over (wrap) limit for the sample counter. When reaching the limit the 312 | * sample counter will be reset to 0 (default is no limit) 313 | * 314 | * \param[in] self the Sampled Values ASDU instance. 315 | * \param[in] value the new sample counter limit 316 | */ 317 | LIB61850_API void 318 | SVPublisher_ASDU_setSmpCntWrap(SVPublisher_ASDU self, uint16_t value); 319 | 320 | /** 321 | * \brief Enables the transmission of refresh time attribute of the ASDU 322 | * 323 | * The refresh time is the time when the data in put into the sampled values buffer 324 | * 325 | * \param[in] self the Sampled Values ASDU instance. 326 | */ 327 | LIB61850_API void 328 | SVPublisher_ASDU_enableRefrTm(SVPublisher_ASDU self); 329 | 330 | /** 331 | * \brief Set the refresh time attribute of the ASDU with nanosecond resolution 332 | * 333 | * \param[in] self the Sampled Values ASDU instance. 334 | * \param[in] refrTmNs the refresh time value with nanoseconds resolution. 335 | */ 336 | LIB61850_API void 337 | SVPublisher_ASDU_setRefrTmNs(SVPublisher_ASDU self, nsSinceEpoch refrTmNs); 338 | 339 | /** 340 | * \brief Set the refresh time attribute of the ASDU with millisecond resolution 341 | * 342 | * \param[in] self the Sampled Values ASDU instance. 343 | * \param[in] refrTmNs the refresh time value with with milliseconds resolution. 344 | */ 345 | LIB61850_API void 346 | SVPublisher_ASDU_setRefrTm(SVPublisher_ASDU self, msSinceEpoch refrTm); 347 | 348 | /** 349 | * \brief Set the refresh time attribute of the ASDU 350 | * 351 | * NOTE: Using this function you can control the time quality flags and the 352 | * sub second precision (number of valid bits) of the RefrTm value. 353 | * 354 | * \param[in] self the Sampled Values ASDU instance. 355 | * \param[in] refrTm the refresh time value 356 | */ 357 | LIB61850_API void 358 | SVPublisher_ASDU_setRefrTmByTimestamp(SVPublisher_ASDU self, Timestamp* refrTm); 359 | 360 | /** 361 | * \brief Set the sample mode attribute of the ASDU. 362 | * 363 | * The attribute SmpMod shall specify if the sample rate is defined in units of samples per nominal period, samples per second or seconds per sample. 364 | * If it is missing, the default value is samples per period. 365 | * 366 | * NOTE: Function has to be called before calling \ref SVPublisher_setupComplete 367 | * 368 | * \param[in] self the Sampled Values ASDU instance. 369 | * \param[in] smpMod one of IEC61850_SV_SMPMOD_PER_NOMINAL_PERIOD, IEC61850_SV_SMPMOD_SAMPLES_PER_SECOND or IEC61850_SV_SMPMOD_SECONDS_PER_SAMPLE 370 | */ 371 | LIB61850_API void 372 | SVPublisher_ASDU_setSmpMod(SVPublisher_ASDU self, uint8_t smpMod); 373 | 374 | /** 375 | * \brief Set the sample rate attribute of the ASDU. 376 | * 377 | * The attribute SmpRate shall specify the sample rate. 378 | * The value shall be interpreted depending on the value of the SmpMod attribute. 379 | * 380 | * NOTE: Function has to be called before calling \ref SVPublisher_setupComplete 381 | * 382 | * \param[in] self the Sampled Values ASDU instance. 383 | * \param[in] smpRate Amount of samples (default per nominal period, see SmpMod). 384 | */ 385 | LIB61850_API void 386 | SVPublisher_ASDU_setSmpRate(SVPublisher_ASDU self, uint16_t smpRate); 387 | 388 | /** 389 | * \brief Set the clock synchronization information 390 | * 391 | * Default value is not synchronized (0). 392 | * Possible values are: 393 | * 0 = SV are not synchronized by an external clock signal. 394 | * 1 = SV are synchronized by a clock signal from an unspecified local area clock. 395 | * 2 = SV are synchronized by a global area clock signal (time traceable). 396 | * 5 to 254 = SV are synchronized by a clock signal from a local area clock identified by this value. 397 | * 3;4;255 = Reserved values – Do not use. 398 | * 399 | * \param[in] self the Sampled Values ASDU instance. 400 | * \param[in] smpSynch the clock synchronization state 401 | */ 402 | LIB61850_API void 403 | SVPublisher_ASDU_setSmpSynch(SVPublisher_ASDU self, uint16_t smpSynch); 404 | 405 | /**@} @}*/ 406 | 407 | #ifndef DEPRECATED 408 | #if defined(__GNUC__) || defined(__clang__) 409 | #define DEPRECATED __attribute__((deprecated)) 410 | #else 411 | #define DEPRECATED 412 | #endif 413 | #endif 414 | 415 | /** 416 | * \addtogroup sv_publisher_deprecated_api_group Deprecated API 417 | * \ingroup sv_publisher_api_group IEC 61850 Sampled Values (SV) publisher API 418 | * \deprecated 419 | * @{ 420 | */ 421 | 422 | typedef struct sSVPublisher* SampledValuesPublisher; 423 | 424 | typedef struct sSV_ASDU* SV_ASDU; 425 | 426 | LIB61850_API DEPRECATED SVPublisher 427 | SampledValuesPublisher_create(CommParameters* parameters, const char* interfaceId); 428 | 429 | LIB61850_API DEPRECATED SVPublisher_ASDU 430 | SampledValuesPublisher_addASDU(SVPublisher self, char* svID, char* datset, uint32_t confRev); 431 | 432 | LIB61850_API DEPRECATED void 433 | SampledValuesPublisher_setupComplete(SVPublisher self); 434 | 435 | LIB61850_API DEPRECATED void 436 | SampledValuesPublisher_publish(SVPublisher self); 437 | 438 | LIB61850_API DEPRECATED void 439 | SampledValuesPublisher_destroy(SVPublisher self); 440 | 441 | LIB61850_API DEPRECATED void 442 | SV_ASDU_resetBuffer(SVPublisher_ASDU self); 443 | 444 | LIB61850_API DEPRECATED int 445 | SV_ASDU_addINT8(SVPublisher_ASDU self); 446 | 447 | LIB61850_API DEPRECATED void 448 | SV_ASDU_setINT8(SVPublisher_ASDU self, int index, int8_t value); 449 | 450 | LIB61850_API DEPRECATED int 451 | SV_ASDU_addINT32(SVPublisher_ASDU self); 452 | 453 | LIB61850_API DEPRECATED void 454 | SV_ASDU_setINT32(SVPublisher_ASDU self, int index, int32_t value); 455 | 456 | LIB61850_API DEPRECATED int 457 | SV_ASDU_addINT64(SVPublisher_ASDU self); 458 | 459 | LIB61850_API DEPRECATED void 460 | SV_ASDU_setINT64(SVPublisher_ASDU self, int index, int64_t value); 461 | 462 | LIB61850_API DEPRECATED int 463 | SV_ASDU_addFLOAT(SVPublisher_ASDU self); 464 | 465 | LIB61850_API DEPRECATED void 466 | SV_ASDU_setFLOAT(SVPublisher_ASDU self, int index, float value); 467 | 468 | LIB61850_API DEPRECATED int 469 | SV_ASDU_addFLOAT64(SVPublisher_ASDU self); 470 | 471 | LIB61850_API DEPRECATED void 472 | SV_ASDU_setFLOAT64(SVPublisher_ASDU self, int index, double value); 473 | 474 | LIB61850_API DEPRECATED void 475 | SV_ASDU_setSmpCnt(SVPublisher_ASDU self, uint16_t value); 476 | 477 | LIB61850_API DEPRECATED uint16_t 478 | SV_ASDU_getSmpCnt(SVPublisher_ASDU self); 479 | 480 | LIB61850_API DEPRECATED void 481 | SV_ASDU_increaseSmpCnt(SVPublisher_ASDU self); 482 | 483 | LIB61850_API DEPRECATED void 484 | SV_ASDU_setRefrTm(SVPublisher_ASDU self, uint64_t refrTm); 485 | 486 | LIB61850_API DEPRECATED void 487 | SV_ASDU_setSmpMod(SVPublisher_ASDU self, uint8_t smpMod); 488 | 489 | LIB61850_API DEPRECATED void 490 | SV_ASDU_setSmpRate(SVPublisher_ASDU self, uint16_t smpRate); 491 | 492 | /**@}*/ 493 | 494 | #ifdef __cplusplus 495 | } 496 | #endif 497 | 498 | #endif /* LIBIEC61850_SRC_SAMPLED_VALUES_SV_PUBLISHER_H_ */ 499 | -------------------------------------------------------------------------------- /include/sv_subscriber.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sv_subscriber.h 3 | * 4 | * Copyright 2015-2018 Michael Zillgith 5 | * 6 | * This file is part of libIEC61850. 7 | * 8 | * libIEC61850 is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * libIEC61850 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with libIEC61850. If not, see . 20 | * 21 | * See COPYING file for the complete license text. 22 | */ 23 | 24 | #ifndef SAMPLED_VALUES_SV_SUBSCRIBER_H_ 25 | #define SAMPLED_VALUES_SV_SUBSCRIBER_H_ 26 | 27 | #include "libiec61850_common_api.h" 28 | #include "iec61850_common.h" 29 | #include "hal_ethernet.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /** 36 | * \defgroup sv_subscriber_api_group IEC 61850 Sampled Values (SV) subscriber API 37 | * 38 | * The sampled values (SV) subscriber API consists of three different objects. 39 | * The \ref SVReceiver object is responsible for handling all SV Ethernet messages 40 | * for a specific Ethernet interface. If you want to receive SV messages on multiple 41 | * Ethernet interfaces you have to use several \ref SVReceiver instances. 42 | * An \ref SVSubscriber object is associated to a SV data stream that is identified by its appID 43 | * and destination Ethernet address. The \reg SVSubscriber object is used to install a callback 44 | * handler \ref SVUpdateListener that is invoked for each ASDU (application service data unit) received for the 45 | * associated stream. An \ref SVSubscriber_ASDU is an object that represents a single ASDU. Each ASDU contains 46 | * some meta information that can be obtained by specific access functions like e.g. 47 | * \ref SVSubscriber_ASDU_getSmpCnt to access the "SmpCnt" (sample count) attribute of the ASDU. The actual 48 | * measurement data contained in the ASDU does not consist of structured ASN.1 data but stored as raw binary 49 | * data. Without a priori knowledge of the dataset associated with the ASDU data stream it is not 50 | * possible to interpret the received data correctly. Therefore you have to provide the data access functions 51 | * with an index value to indicate the data type and the start of the data in the data block of the ASDU. 52 | * E.g. reading a data set consisting of two FLOAT32 values you can use two subsequent calls of 53 | * \ref SVSubscriber_ASDU_getFLOAT32 one with index = 0 and the second one with index = 4. 54 | * 55 | * | IEC 61850 type | required bytes | 56 | * | -------------- | -------------- | 57 | * | BOOLEAN | 1 byte | 58 | * | INT8 | 1 byte | 59 | * | INT16 | 2 byte | 60 | * | INT32 | 4 byte | 61 | * | INT64 | 8 byte | 62 | * | INT8U | 1 byte | 63 | * | INT16U | 2 byte | 64 | * | INT24U | 3 byte | 65 | * | INT32U | 4 byte | 66 | * | INT64U | 8 byte | 67 | * | FLOAT32 | 4 byte | 68 | * | FLOAT64 | 8 byte | 69 | * | ENUMERATED | 4 byte | 70 | * | CODED ENUM | 4 byte | 71 | * | OCTET STRING | 20 byte | 72 | * | VISIBLE STRING | 35 byte | 73 | * | TimeStamp | 8 byte | 74 | * | EntryTime | 6 byte | 75 | * | BITSTRING | 4 byte | 76 | * | Quality | 4 byte | 77 | * 78 | * The SV subscriber API can be used independent of the IEC 61850 client API. In order to access the SVCB via MMS you 79 | * have to use the IEC 61850 client API. Please see \ref ClientSVControlBlock object in section \ref IEC61850_CLIENT_SV. 80 | * 81 | */ 82 | /**@{*/ 83 | 84 | 85 | /** 86 | * \brief opaque handle to a SV ASDU (Application service data unit) instance. 87 | * 88 | * Sampled Values (SV) ASDUs (application service data units) are the basic units for 89 | * sampled value data. Each ASDU represents a single sample consisting of multiple measurement 90 | * values with a single dedicated timestamp. 91 | * 92 | * NOTE: SVSubscriber_ASDU are statically allocated and are only valid inside of the SVUpdateListener 93 | * function when called by the library. If you need the data contained in the ASDU elsewhere 94 | * you have to copy and store the data by yourself! 95 | */ 96 | typedef struct sSVSubscriber_ASDU* SVSubscriber_ASDU; 97 | 98 | /** 99 | * \brief opaque handle to a SV subscriber instance 100 | * 101 | * A subscriber is an instance associated with a single stream of measurement data. It is identified 102 | * by the Ethernet destination address, the appID value (both are on SV message level) and the svID value 103 | * that is part of each ASDU (SVSubscriber_ASDU object). 104 | */ 105 | typedef struct sSVSubscriber* SVSubscriber; 106 | 107 | /** 108 | * \brief Callback function for received SV messages 109 | * 110 | * Will be called for each ASDU contained in a SV message! 111 | * 112 | * \param subscriber the subscriber that was associated with the received SV message 113 | * \param parameter a user provided parameter that is simply passed to the callback 114 | * \param asdu SV ASDU data structure. This structure is only valid inside of the callback function 115 | */ 116 | typedef void (*SVUpdateListener)(SVSubscriber subscriber, void* parameter, SVSubscriber_ASDU asdu); 117 | 118 | /** 119 | * \brief opaque handle to a SV receiver instance 120 | */ 121 | typedef struct sSVReceiver* SVReceiver; 122 | 123 | /** 124 | * \brief Create a new SV receiver instance. 125 | * 126 | * A receiver is responsible for processing all SV message for a single Ethernet interface. 127 | * In order to process messages from multiple Ethernet interfaces you have to create multiple 128 | * instances. 129 | * 130 | * \return the newly created receiver instance 131 | */ 132 | LIB61850_API SVReceiver 133 | SVReceiver_create(void); 134 | 135 | /** 136 | * \brief Disable check for destination address of the received SV messages 137 | * 138 | * \param self the receiver instance reference 139 | */ 140 | LIB61850_API void 141 | SVReceiver_disableDestAddrCheck(SVReceiver self); 142 | 143 | /** 144 | * \brief Enable check for destination address of the received SV messages 145 | * 146 | * Per default only the appID is checked to identify relevant SV messages and the 147 | * destination address is ignored for performance reasons. This only works when the 148 | * appIDs are unique in the local system. Otherwise the destination address check 149 | * has to be enabled. 150 | * 151 | * \param self the receiver instance reference 152 | */ 153 | LIB61850_API void 154 | SVReceiver_enableDestAddrCheck(SVReceiver self); 155 | 156 | /** 157 | * \brief Set the Ethernet interface ID for the receiver instance 158 | * 159 | * Use this function if you want to use a different interface than 160 | * the default interface set by CONFIG_ETHERNET_INTERFACE_ID (stack_config.h) 161 | * NOTE: This function has to be called before calling SVReceiver_start. 162 | * 163 | * \param self the receiver instance reference 164 | * \param interfaceId the Ethernet interface id (platform specific e.g. eth0 for linux). 165 | */ 166 | LIB61850_API void 167 | SVReceiver_setInterfaceId(SVReceiver self, const char* interfaceId); 168 | 169 | /** 170 | * \brief Add a subscriber instance to the receiver 171 | * 172 | * The given subscriber will be connected to the receiver instance. 173 | * 174 | * \param self the receiver instance reference 175 | * \param subscriber the subscriber instance to connect 176 | */ 177 | LIB61850_API void 178 | SVReceiver_addSubscriber(SVReceiver self, SVSubscriber subscriber); 179 | 180 | /** 181 | * \brief Disconnect subscriber and receiver 182 | * 183 | * \param self the receiver instance reference 184 | * \param subscriber the subscriber instance to disconnect 185 | */ 186 | LIB61850_API void 187 | SVReceiver_removeSubscriber(SVReceiver self, SVSubscriber subscriber); 188 | 189 | /** 190 | * \brief Receiver starts listening for SV messages. 191 | * 192 | * NOTE: This call will start a new background thread. 193 | * 194 | * \param self the receiver instance reference 195 | */ 196 | LIB61850_API void 197 | SVReceiver_start(SVReceiver self); 198 | 199 | /** 200 | * \brief Receiver stops listening for SV messages 201 | * 202 | * \param self the receiver instance reference 203 | */ 204 | LIB61850_API void 205 | SVReceiver_stop(SVReceiver self); 206 | 207 | /** 208 | * \brief Check if SV receiver is running 209 | * 210 | * Can be used to check if \ref SVReceiver_start has been successful. 211 | * 212 | * \param self the receiver instance reference 213 | * 214 | * \return true if SV receiver is running, false otherwise 215 | */ 216 | LIB61850_API bool 217 | SVReceiver_isRunning(SVReceiver self); 218 | 219 | /** 220 | * \brief Destroy receiver instance (cleanup resources) 221 | * 222 | * \param self the receiver instance reference 223 | */ 224 | LIB61850_API void 225 | SVReceiver_destroy(SVReceiver self); 226 | 227 | /*************************************** 228 | * Functions for non-threaded operation 229 | ***************************************/ 230 | 231 | LIB61850_API EthernetSocket 232 | SVReceiver_startThreadless(SVReceiver self); 233 | 234 | LIB61850_API void 235 | SVReceiver_stopThreadless(SVReceiver self); 236 | 237 | /** 238 | * \brief Parse SV messages if they are available. 239 | * 240 | * Call after reception of ethernet frame and periodically to to house keeping tasks 241 | * 242 | * \param self the receiver object 243 | * 244 | * \return true if a message was available and has been parsed, false otherwise 245 | */ 246 | LIB61850_API bool 247 | SVReceiver_tick(SVReceiver self); 248 | 249 | /* 250 | * \brief Create a new SV subscriber instance 251 | * 252 | * \param ethAddr optional destination address (NULL to not specify the destination address) 253 | * \param appID the APP-ID to identify matching SV messages 254 | * 255 | * \return the new subscriber instance 256 | */ 257 | 258 | LIB61850_API SVSubscriber 259 | SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID); 260 | 261 | /** 262 | * \brief Set a callback handler to process received SV messages 263 | * 264 | * If the received SV message contains multiple ASDUs (application service data units) the callback 265 | * function will be called for each ASDU separately. If a callback function has already been installed 266 | * for this SVSubscriber object the old callback will be replaced. 267 | * 268 | * \param self The subscriber object 269 | * \param listener the callback function to install 270 | * \param a user provided parameter that is provided to the callback function 271 | */ 272 | LIB61850_API void 273 | SVSubscriber_setListener(SVSubscriber self, SVUpdateListener listener, void* parameter); 274 | 275 | LIB61850_API void 276 | SVSubscriber_destroy(SVSubscriber self); 277 | 278 | /************************************************************************* 279 | * SVSubscriber_ASDU object methods 280 | **************************************************************************/ 281 | 282 | /** 283 | * \addtogroup sv_subscriber_asdu_group Values Application Service Data Unit (ASDU) 284 | * @{ 285 | */ 286 | 287 | /** 288 | * \brief return the SmpCnt value included in the SV ASDU 289 | * 290 | * The SmpCnt (sample counter) is increased for each ASDU to 291 | * identify the sample. 292 | * 293 | * \param self ASDU object instance 294 | */ 295 | LIB61850_API uint16_t 296 | SVSubscriber_ASDU_getSmpCnt(SVSubscriber_ASDU self); 297 | 298 | /** 299 | * \brief return the SvID value included in the SV ASDU 300 | * 301 | * \param self ASDU object instance 302 | */ 303 | LIB61850_API const char* 304 | SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self); 305 | 306 | /** 307 | * \brief return the DatSet value included in the SV ASDU 308 | * 309 | * \param self ASDU object instance 310 | */ 311 | LIB61850_API const char* 312 | SVSubscriber_ASDU_getDatSet(SVSubscriber_ASDU self); 313 | 314 | /** 315 | * \brief return the ConfRev value included in the SV ASDU 316 | * 317 | * \param self ASDU object instance 318 | */ 319 | LIB61850_API uint32_t 320 | SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self); 321 | 322 | /** 323 | * \brief return the SmpMod value included in the SV ASDU 324 | * 325 | * \param self ASDU object instance 326 | */ 327 | LIB61850_API uint8_t 328 | SVSubscriber_ASDU_getSmpMod(SVSubscriber_ASDU self); 329 | 330 | /** 331 | * \brief return the SmpRate value included in the SV ASDU 332 | * 333 | * \param self ASDU object instance 334 | */ 335 | LIB61850_API uint16_t 336 | SVSubscriber_ASDU_getSmpRate(SVSubscriber_ASDU self); 337 | 338 | /** 339 | * \brief Check if DatSet value is included in the SV ASDU 340 | * 341 | * \param self ASDU object instance 342 | * 343 | * \return true if DatSet value is present, false otherwise 344 | */ 345 | LIB61850_API bool 346 | SVSubscriber_ASDU_hasDatSet(SVSubscriber_ASDU self); 347 | 348 | /** 349 | * \brief Check if RefrTm value is included in the SV ASDU 350 | * 351 | * \param self ASDU object instance 352 | * 353 | * \return true if RefrTm value is present, false otherwise 354 | */ 355 | LIB61850_API bool 356 | SVSubscriber_ASDU_hasRefrTm(SVSubscriber_ASDU self); 357 | 358 | /** 359 | * \brief Check if SmpMod value is included in the SV ASDU 360 | * 361 | * \param self ASDU object instance 362 | * 363 | * \return true if SmpMod value is present, false otherwise 364 | */ 365 | LIB61850_API bool 366 | SVSubscriber_ASDU_hasSmpMod(SVSubscriber_ASDU self); 367 | 368 | /** 369 | * \brief Check if SmpRate value is included in the SV ASDU 370 | * 371 | * \param self ASDU object instance 372 | * 373 | * \return true if SmpRate value is present, false otherwise 374 | */ 375 | LIB61850_API bool 376 | SVSubscriber_ASDU_hasSmpRate(SVSubscriber_ASDU self); 377 | 378 | /** 379 | * \brief Get the RefrTim value included in SV ASDU as milliseconds timestamp 380 | * 381 | * \param self ASDU object instance 382 | * 383 | * \return the time value as ms timestamp or 0 if RefrTm is not present in the SV ASDU 384 | */ 385 | LIB61850_API uint64_t 386 | SVSubscriber_ASDU_getRefrTmAsMs(SVSubscriber_ASDU self); 387 | 388 | /** 389 | * \brief Get the RefrTim value included in SV ASDU as nanoseconds timestamp 390 | * 391 | * \param self ASDU object instance 392 | * 393 | * \return the time value as nanoseconds timestamp or 0 if RefrTm is not present in the SV ASDU 394 | */ 395 | LIB61850_API nsSinceEpoch 396 | SVSubscriber_ASDU_getRefrTmAsNs(SVSubscriber_ASDU self); 397 | 398 | /** 399 | * \brief Get an INT8 data value in the data part of the ASDU 400 | * 401 | * \param self ASDU object instance 402 | * \param index the index (byte position of the start) of the data in the data part 403 | * 404 | * \return SV data 405 | */ 406 | LIB61850_API int8_t 407 | SVSubscriber_ASDU_getINT8(SVSubscriber_ASDU self, int index); 408 | 409 | /** 410 | * \brief Get an INT16 data value in the data part of the ASDU 411 | * 412 | * \param self ASDU object instance 413 | * \param index the index (byte position of the start) of the data in the data part 414 | * 415 | * \return SV data 416 | */ 417 | LIB61850_API int16_t 418 | SVSubscriber_ASDU_getINT16(SVSubscriber_ASDU self, int index); 419 | 420 | /** 421 | * \brief Get an INT32 data value in the data part of the ASDU 422 | * 423 | * \param self ASDU object instance 424 | * \param index the index (byte position of the start) of the data in the data part 425 | * 426 | * \return SV data 427 | */ 428 | LIB61850_API int32_t 429 | SVSubscriber_ASDU_getINT32(SVSubscriber_ASDU self, int index); 430 | 431 | /** 432 | * \brief Get an INT64 data value in the data part of the ASDU 433 | * 434 | * \param self ASDU object instance 435 | * \param index the index (byte position of the start) of the data in the data part 436 | * 437 | * \return SV data 438 | */ 439 | LIB61850_API int64_t 440 | SVSubscriber_ASDU_getINT64(SVSubscriber_ASDU self, int index); 441 | 442 | /** 443 | * \brief Get an INT8U data value in the data part of the ASDU 444 | * 445 | * \param self ASDU object instance 446 | * \param index the index (byte position of the start) of the data in the data part 447 | * 448 | * \return SV data 449 | */ 450 | LIB61850_API uint8_t 451 | SVSubscriber_ASDU_getINT8U(SVSubscriber_ASDU self, int index); 452 | 453 | /** 454 | * \brief Get an INT16U data value in the data part of the ASDU 455 | * 456 | * \param self ASDU object instance 457 | * \param index the index (byte position of the start) of the data in the data part 458 | * 459 | * \return SV data 460 | */ 461 | LIB61850_API uint16_t 462 | SVSubscriber_ASDU_getINT16U(SVSubscriber_ASDU self, int index); 463 | 464 | /** 465 | * \brief Get an INT32U data value in the data part of the ASDU 466 | * 467 | * \param self ASDU object instance 468 | * \param index the index (byte position of the start) of the data in the data part 469 | * 470 | * \return SV data 471 | */ 472 | LIB61850_API uint32_t 473 | SVSubscriber_ASDU_getINT32U(SVSubscriber_ASDU self, int index); 474 | 475 | /** 476 | * \brief Get an INT64U data value in the data part of the ASDU 477 | * 478 | * \param self ASDU object instance 479 | * \param index the index (byte position of the start) of the data in the data part 480 | * 481 | * \return SV data 482 | */ 483 | LIB61850_API uint64_t 484 | SVSubscriber_ASDU_getINT64U(SVSubscriber_ASDU self, int index); 485 | 486 | /** 487 | * \brief Get an FLOAT32 data value in the data part of the ASDU 488 | * 489 | * \param self ASDU object instance 490 | * \param index the index (byte position of the start) of the data in the data part 491 | * 492 | * \return SV data 493 | */ 494 | LIB61850_API float 495 | SVSubscriber_ASDU_getFLOAT32(SVSubscriber_ASDU self, int index); 496 | 497 | /** 498 | * \brief Get an FLOAT64 data value in the data part of the ASDU 499 | * 500 | * \param self ASDU object instance 501 | * \param index the index (byte position of the start) of the data in the data part 502 | * 503 | * \return SV data 504 | */ 505 | LIB61850_API double 506 | SVSubscriber_ASDU_getFLOAT64(SVSubscriber_ASDU self, int index); 507 | 508 | /** 509 | * \brief Get a timestamp data value in the data part of the ASDU 510 | * 511 | * \param self ASDU object instance 512 | * \param index the index (byte position of the start) of the data in the data part 513 | * 514 | * \return SV data 515 | */ 516 | LIB61850_API Timestamp 517 | SVSubscriber_ASDU_getTimestamp(SVSubscriber_ASDU self, int index); 518 | 519 | /** 520 | * \brief Get a quality value in the data part of the ASDU 521 | * 522 | * NOTE: Quality is encoded as BITSTRING (4 byte) 523 | * 524 | * \param self ASDU object instance 525 | * \param index the index (byte position of the start) of the data in the data part 526 | * 527 | * \return SV data 528 | */ 529 | LIB61850_API Quality 530 | SVSubscriber_ASDU_getQuality(SVSubscriber_ASDU self, int index); 531 | 532 | /** 533 | * \brief Returns the size of the data part of the ASDU 534 | * 535 | * \param self ASDU object instance 536 | * 537 | * \return size of the ASDU data part in bytes. 538 | */ 539 | LIB61850_API int 540 | SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self); 541 | 542 | #ifndef DEPRECATED 543 | #if defined(__GNUC__) || defined(__clang__) 544 | #define DEPRECATED __attribute__((deprecated)) 545 | #else 546 | #define DEPRECATED 547 | #endif 548 | #endif 549 | 550 | /** 551 | * \addtogroup sv_subscriber_deprecated_api_group Deprecated API 552 | * \ingroup sv_subscriber_api_group IEC 61850 Sampled Values (SV) publisher API 553 | * \deprecated 554 | * @{ 555 | */ 556 | 557 | typedef struct sSVSubscriberASDU* SVClientASDU; 558 | 559 | LIB61850_API DEPRECATED uint16_t 560 | SVClientASDU_getSmpCnt(SVSubscriber_ASDU self); 561 | 562 | LIB61850_API DEPRECATED const char* 563 | SVClientASDU_getSvId(SVSubscriber_ASDU self); 564 | 565 | LIB61850_API DEPRECATED uint32_t 566 | SVClientASDU_getConfRev(SVSubscriber_ASDU self); 567 | 568 | LIB61850_API DEPRECATED bool 569 | SVClientASDU_hasRefrTm(SVSubscriber_ASDU self); 570 | 571 | LIB61850_API DEPRECATED uint64_t 572 | SVClientASDU_getRefrTmAsMs(SVSubscriber_ASDU self); 573 | 574 | LIB61850_API DEPRECATED int8_t 575 | SVClientASDU_getINT8(SVSubscriber_ASDU self, int index); 576 | 577 | LIB61850_API DEPRECATED int16_t 578 | SVClientASDU_getINT16(SVSubscriber_ASDU self, int index); 579 | 580 | LIB61850_API DEPRECATED int32_t 581 | SVClientASDU_getINT32(SVSubscriber_ASDU self, int index); 582 | 583 | LIB61850_API DEPRECATED int64_t 584 | SVClientASDU_getINT64(SVSubscriber_ASDU self, int index); 585 | 586 | LIB61850_API DEPRECATED uint8_t 587 | SVClientASDU_getINT8U(SVSubscriber_ASDU self, int index); 588 | 589 | LIB61850_API DEPRECATED uint16_t 590 | SVClientASDU_getINT16U(SVSubscriber_ASDU self, int index); 591 | 592 | LIB61850_API DEPRECATED uint32_t 593 | SVClientASDU_getINT32U(SVSubscriber_ASDU self, int index); 594 | 595 | LIB61850_API DEPRECATED uint64_t 596 | SVClientASDU_getINT64U(SVSubscriber_ASDU self, int index); 597 | 598 | LIB61850_API DEPRECATED float 599 | SVClientASDU_getFLOAT32(SVSubscriber_ASDU self, int index); 600 | 601 | LIB61850_API DEPRECATED double 602 | SVClientASDU_getFLOAT64(SVSubscriber_ASDU self, int index); 603 | 604 | LIB61850_API DEPRECATED int 605 | SVClientASDU_getDataSize(SVSubscriber_ASDU self); 606 | 607 | /**@} @}*/ 608 | 609 | #ifdef __cplusplus 610 | } 611 | #endif 612 | 613 | #endif /* SAMPLED_VALUES_SV_SUBSCRIBER_ */ 614 | -------------------------------------------------------------------------------- /include/tls_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tls_config.h 3 | * 4 | * TLS Configuration API for protocol stacks using TCP/IP 5 | * 6 | * Copyright 2017-2018 MZ Automation GmbH 7 | * 8 | * Abstraction layer for configuration of different TLS implementations 9 | * 10 | */ 11 | 12 | #ifndef SRC_TLS_CONFIG_H_ 13 | #define SRC_TLS_CONFIG_H_ 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #include "hal_base.h" 20 | 21 | /** 22 | * \file tls_config.h 23 | * \brief TLS API functions 24 | */ 25 | 26 | /*! \addtogroup hal Platform (Hardware/OS) abstraction layer 27 | * 28 | * @{ 29 | */ 30 | 31 | /** 32 | * @defgroup TLS_CONFIG_API TLS configuration 33 | * 34 | * @{ 35 | */ 36 | 37 | typedef struct sTLSConfiguration* TLSConfiguration; 38 | 39 | /** 40 | * \brief Create a new \ref TLSConfiguration object to represent TLS configuration and certificates 41 | * 42 | * \return the new TLS configuration 43 | */ 44 | PAL_API TLSConfiguration 45 | TLSConfiguration_create(void); 46 | 47 | /* will be called by stack automatically when appropriate */ 48 | PAL_API void 49 | TLSConfiguration_setClientMode(TLSConfiguration self); 50 | 51 | /** 52 | * \brief Enables the validation of the certificate trust chain (enabled by default) 53 | * 54 | * \param value true to enable chain validation, false to disable 55 | */ 56 | PAL_API void 57 | TLSConfiguration_setChainValidation(TLSConfiguration self, bool value); 58 | 59 | /** 60 | * \brief Set if only known certificates are accepted. 61 | * 62 | * If set to true only known certificates are accepted. Connections with unknown certificates 63 | * are rejected even if they are signed by a trusted authority. 64 | * 65 | * \param value true to enable setting, false otherwise 66 | */ 67 | PAL_API void 68 | TLSConfiguration_setAllowOnlyKnownCertificates(TLSConfiguration self, bool value); 69 | 70 | /** 71 | * \brief Set own certificate (identity) from a byte buffer 72 | * 73 | * \param certificate the certificate buffer 74 | * \param certLen the lenght of the certificate 75 | * 76 | * \return true, when the certificate was set, false otherwise (e.g. unknown certificate format) 77 | */ 78 | PAL_API bool 79 | TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, int certLen); 80 | 81 | /** 82 | * \brief Set own certificate (identity) from a certificate file 83 | * 84 | * \param filename of the certificate file 85 | * 86 | * \return true, when the certificate was set, false otherwise (e.g. unknown certificate format) 87 | */ 88 | PAL_API bool 89 | TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename); 90 | 91 | PAL_API bool 92 | TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword); 93 | 94 | PAL_API bool 95 | TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword); 96 | 97 | PAL_API bool 98 | TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certifcate, int certLen); 99 | 100 | PAL_API bool 101 | TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename); 102 | 103 | PAL_API bool 104 | TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certifcate, int certLen); 105 | 106 | PAL_API bool 107 | TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename); 108 | 109 | /** 110 | * \brief Set the renegotiation timeout. 111 | * 112 | * After the timeout elapsed a TLS session renegotiation has to occur. 113 | * 114 | * \param timeInMs session renegotiation timeout in milliseconds 115 | */ 116 | PAL_API void 117 | TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs); 118 | 119 | PAL_API void 120 | TLSConfiguration_destroy(TLSConfiguration self); 121 | 122 | /** @} */ 123 | 124 | /** @} */ 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif /* SRC_TLS_CONFIG_H_ */ 131 | -------------------------------------------------------------------------------- /lib/libiec61850.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st-ing/61850-sim/eb3372af8dab5f570ab85cba0274f57b2a558645/lib/libiec61850.a -------------------------------------------------------------------------------- /misc/Schneider Electric IED - PM8000.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st-ing/61850-sim/eb3372af8dab5f570ab85cba0274f57b2a558645/misc/Schneider Electric IED - PM8000.zip -------------------------------------------------------------------------------- /res/ION.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 2 6 | 7 | 8 | 50.0 9 | 100.0 10 | 0.40 11 | 3.79 12 | 13 | 14 | 10000 15 | 5000 16 | 1.485014 17 | 18 | -------------------------------------------------------------------------------- /tools/model-generator/genmodel.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st-ing/61850-sim/eb3372af8dab5f570ab85cba0274f57b2a558645/tools/model-generator/genmodel.jar -------------------------------------------------------------------------------- /tools/model-generator/manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.libiec61850.tools.StaticModelGenerator 3 | --------------------------------------------------------------------------------