diff --git a/public/js/plugins.js b/public/js/plugins.js index ec13f982c..f7f91ee06 100644 --- a/public/js/plugins.js +++ b/public/js/plugins.js @@ -10,7 +10,7 @@ export const officialPlugins = [ name: 'IED', src: '/src/editors/IED.js', icon: 'edit', - default: true, + default: false, kind: 'editor', }, { diff --git a/src/editors/IED.ts b/src/editors/IED.ts index f6a61fa75..927f66210 100644 --- a/src/editors/IED.ts +++ b/src/editors/IED.ts @@ -8,7 +8,6 @@ import '../zeroline-pane.js'; import './ied/ied-container.js' import { translate } from 'lit-translate'; -import { IEDSelector } from './ied/foundation.js'; import { Select } from '@material/mwc-select'; import { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation'; import { compareNames, getDescriptionAttribute, getNameAttribute } from '../foundation.js'; @@ -21,7 +20,7 @@ export default class IedPlugin extends LitElement { /** Query holding the current selected IEDs. */ @state() - currentSelectedIEDs: string = IEDSelector.IED; + currentSelectedIEDs = ':root > IED'; @query('#iedSelect') iedSelector?: Select; diff --git a/src/editors/ied/access-point-container.ts b/src/editors/ied/access-point-container.ts index 6717886ea..cf4c32382 100644 --- a/src/editors/ied/access-point-container.ts +++ b/src/editors/ied/access-point-container.ts @@ -9,7 +9,6 @@ import { import '../../action-pane.js'; import './server-container.js' -import { IEDSelector } from './foundation.js'; import { nothing } from 'lit-html'; import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js'; @@ -28,7 +27,7 @@ export class AccessPointContainer extends LitElement { render(): TemplateResult { return html`<action-pane .label="${this.header()}"> - ${Array.from(this.element.querySelectorAll(IEDSelector.Server)).map( + ${Array.from(this.element.querySelectorAll(':scope > Server')).map( server => html`<server-container .element=${server} ></server-container>`)} diff --git a/src/editors/ied/do-container.ts b/src/editors/ied/do-container.ts new file mode 100644 index 000000000..ef49c9e42 --- /dev/null +++ b/src/editors/ied/do-container.ts @@ -0,0 +1,76 @@ +import { + css, + customElement, + html, + LitElement, + property, + TemplateResult, +} from 'lit-element'; +import { nothing } from 'lit-html'; + +import '../../action-pane.js'; +import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js'; + +/** [[`IED`]] plugin subeditor for editing `DO` element. */ +@customElement('do-container') +export class DOContainer extends LitElement { + /** + * The DO itself. + */ + @property({ attribute: false }) + element!: Element; + + /** + * The optional DOI of this DO. + */ + @property({ attribute: false }) + instanceElement!: Element; + + private header(): TemplateResult { + const name = getNameAttribute(this.element); + const desc = getDescriptionAttribute(this.element); + + if (this.instanceElement != null) { + return html`<b>${name}${desc ? html` — ${desc}` : nothing}</b>`; + } else { + return html`${name}${desc ? html` — ${desc}` : nothing}`; + } + } + + /** + * Get the nested SDO element(s). + * @returns The nested SDO element(s) of this DO container. + */ + private getDOElements(): Element[] { + const type = this.element.getAttribute('type') ?? undefined; + const doType = this.element.closest('SCL')!.querySelector(`:root > DataTypeTemplates > DOType[id="${type}"]`); + if (doType != null) { + return Array.from(doType!.querySelectorAll(':scope > SDO')) + } + return []; + } + + /** + * Get the instance element (SDI) of a SDO element (if available) + * @param sdo - The SDO object to search with. + * @returns The optional SDI element. + */ + private getInstanceElement(sdo: Element): Element | null { + const sdoName = getNameAttribute(sdo); + if (this.instanceElement) { + return this.instanceElement.querySelector(`:scope > SDI[name="${sdoName}"]`) + } + return null; + } + + render(): TemplateResult { + return html`<action-pane .label="${this.header()}" icon="${this.instanceElement != null ? 'done' : ''}"> + ${this.getDOElements().map(dO => + html`<do-container + .element=${dO} + .instanceElement=${this.getInstanceElement(dO)}> + </do-container>`)} + </action-pane> + `; + } +} \ No newline at end of file diff --git a/src/editors/ied/foundation.ts b/src/editors/ied/foundation.ts deleted file mode 100644 index c9bb6ef49..000000000 --- a/src/editors/ied/foundation.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Containing all available search strings for sections within an IED section. - */ -export enum IEDSelector { - IED = ':root > IED', - AccessPoint = ':root > IED > AccessPoint', - Server = ':root > IED > AccessPoint > Server', - LDevice = ':root > IED > AccessPoint > Server > LDevice', - AnyLN = ':root > IED > AccessPoint > Server > LDevice > LN,LN0' -} \ No newline at end of file diff --git a/src/editors/ied/ied-container.ts b/src/editors/ied/ied-container.ts index 9fb5f24b7..eb2e24f85 100644 --- a/src/editors/ied/ied-container.ts +++ b/src/editors/ied/ied-container.ts @@ -11,7 +11,6 @@ import { nothing } from 'lit-html'; import '../../action-pane.js'; import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js'; import './access-point-container.js'; -import { IEDSelector } from './foundation.js'; /** [[`IED`]] plugin subeditor for editing `IED` element. */ @customElement('ied-container') @@ -29,7 +28,7 @@ export class IedContainer extends LitElement { render(): TemplateResult { return html`<action-pane .label="${this.header()}"> - ${Array.from(this.element.querySelectorAll(IEDSelector.AccessPoint)).map( + ${Array.from(this.element.querySelectorAll(':scope > AccessPoint')).map( ap => html`<access-point-container .element=${ap} ></access-point-container>`)} diff --git a/src/editors/ied/ldevice-container.ts b/src/editors/ied/ldevice-container.ts index a32ab2443..4f537850d 100644 --- a/src/editors/ied/ldevice-container.ts +++ b/src/editors/ied/ldevice-container.ts @@ -9,7 +9,6 @@ import { import '../../action-pane.js'; import './ln-container.js' -import { IEDSelector } from './foundation.js'; import { nothing } from 'lit-html'; import { getDescriptionAttribute, getInstanceAttribute, getNameAttribute } from '../../foundation.js'; @@ -28,8 +27,8 @@ export class LDeviceContainer extends LitElement { render(): TemplateResult { return html`<action-pane .label="${this.header()}"> - <div id="bayContainer"> - ${Array.from(this.element.querySelectorAll(IEDSelector.AnyLN)).map( + <div id="lnContainer"> + ${Array.from(this.element.querySelectorAll(':scope > LN,LN0')).map( server => html`<ln-container .element=${server} ></ln-container>`)} @@ -38,7 +37,7 @@ export class LDeviceContainer extends LitElement { } static styles = css` - #bayContainer { + #lnContainer { display: grid; grid-gap: 12px; box-sizing: border-box; @@ -46,7 +45,7 @@ export class LDeviceContainer extends LitElement { } @media (max-width: 387px) { - #bayContainer { + #lnContainer { grid-template-columns: repeat(auto-fit, minmax(196px, auto)); } }`; diff --git a/src/editors/ied/ln-container.ts b/src/editors/ied/ln-container.ts index 6c38d256f..34854e8fd 100644 --- a/src/editors/ied/ln-container.ts +++ b/src/editors/ied/ln-container.ts @@ -9,7 +9,8 @@ import { import { nothing } from 'lit-html'; import '../../action-pane.js'; -import { getInstanceAttribute } from '../../foundation.js'; +import './do-container.js'; +import { getInstanceAttribute, getNameAttribute } from '../../foundation.js'; /** [[`IED`]] plugin subeditor for editing `LN` and `LN0` element. */ @customElement('ln-container') @@ -27,8 +28,36 @@ export class LNContainer extends LitElement { ${inst ? html` — ${inst}` : nothing}`; } + /** + * Get the DO child elements of this LN(0) section. + * @returns The DO child elements, or an empty array if none are found. + */ + private getDOElements(): Element[] { + const lnType = this.element.getAttribute('lnType') ?? undefined; + const lNodeType = this.element.closest('SCL')!.querySelector(`:root > DataTypeTemplates > LNodeType[id="${lnType}"]`); + if (lNodeType != null) { + return Array.from(lNodeType.querySelectorAll(':scope > DO')); + } + return []; + } + + /** + * Get the instance element (DOI) of a DO element (if available) + * @param dO - The DOI object to use. + * @returns The optional DOI object. + */ + private getInstanceElement(dO: Element): Element | null { + const doName = getNameAttribute(dO); + return this.element.querySelector(`:scope > DOI[name="${doName}"]`) + } + render(): TemplateResult { return html`<action-pane .label="${this.header()}"> + ${this.getDOElements().map(dO => html`<do-container + .element=${dO} + .instanceElement=${this.getInstanceElement(dO)}> + </do-container> + `)} </action-pane>`; } diff --git a/src/editors/ied/server-container.ts b/src/editors/ied/server-container.ts index 7f3af899c..18107c905 100644 --- a/src/editors/ied/server-container.ts +++ b/src/editors/ied/server-container.ts @@ -9,7 +9,6 @@ import { import '../../action-pane.js'; import './ldevice-container.js'; -import { IEDSelector } from './foundation.js'; /** [[`IED`]] plugin subeditor for editing `Server` element. */ @customElement('server-container') @@ -23,7 +22,7 @@ export class ServerContainer extends LitElement { render(): TemplateResult { return html`<action-pane label="${this.header()}"> - ${Array.from(this.element.querySelectorAll(IEDSelector.LDevice)).map( + ${Array.from(this.element.querySelectorAll(':scope > LDevice')).map( server => html`<ldevice-container .element=${server} ></ldevice-container>`)} diff --git a/test/integration/__snapshots__/open-scd.test.snap.js b/test/integration/__snapshots__/open-scd.test.snap.js index eee71d139..d11c1cfef 100644 --- a/test/integration/__snapshots__/open-scd.test.snap.js +++ b/test/integration/__snapshots__/open-scd.test.snap.js @@ -581,7 +581,6 @@ snapshots["open-scd looks like its snapshot"] = hasmeta="" left="" mwc-list-item="" - selected="" tabindex="-1" value="/src/editors/IED.js" > diff --git a/test/integration/editors/ied/__snapshots__/IED.test.snap.js b/test/integration/editors/ied/__snapshots__/IED.test.snap.js index 08c763d99..bf6d78491 100644 --- a/test/integration/editors/ied/__snapshots__/IED.test.snap.js +++ b/test/integration/editors/ied/__snapshots__/IED.test.snap.js @@ -1,17 +1,6 @@ /* @web/test-runner snapshot v1 */ export const snapshots = {}; -snapshots["IED Editor Plugin without a doc loaded looks like the latest snapshot"] = -`<h1> - <span style="color: var(--base1)"> - [iededitor.missing] - </span> -</h1> -<wizard-dialog> -</wizard-dialog> -`; -/* end snapshot IED Editor Plugin without a doc loaded looks like the latest snapshot */ - snapshots["IED Plugin without a doc loaded looks like the latest snapshot"] = `<h1> <span style="color: var(--base1)"> diff --git a/test/integration/editors/triggered/ImportIedsPlugin.test.ts b/test/integration/editors/triggered/ImportIedsPlugin.test.ts index a4c4ad713..60dd3fe87 100644 --- a/test/integration/editors/triggered/ImportIedsPlugin.test.ts +++ b/test/integration/editors/triggered/ImportIedsPlugin.test.ts @@ -63,12 +63,12 @@ describe('ImportIedsPlugin', () => { expect( element.doc?.querySelectorAll(':root > DataTypeTemplates > DOType') .length - ).to.equal(14); + ).to.equal(16); element.prepareImport(importDoc, doc); expect( element.doc?.querySelectorAll(':root > DataTypeTemplates > DOType') .length - ).to.equal(24); + ).to.equal(26); }); it('loads unique datypes to the project', () => { diff --git a/test/testfiles/valid2007B4.scd b/test/testfiles/valid2007B4.scd index eaf570e68..6a956978c 100644 --- a/test/testfiles/valid2007B4.scd +++ b/test/testfiles/valid2007B4.scd @@ -250,6 +250,7 @@ </GSEControl> </LN0> <LN lnClass="LPHD" inst="1" lnType="Dummy.LPHD1"/> + <LN lnClass="THARDE" inst="1" lnType="Dummy.THARDE"/> <LN lnClass="XCBR" inst="1" lnType="Dummy.XCBR1"> <DOI name="Pos"> <DAI name="ctlModel"> @@ -393,6 +394,7 @@ <DataTypeTemplates> <LNodeType lnClass="LLN0" id="Dummy.LLN0"> <DO name="Mod" type="Dummy.LLN0.Mod" /> + <DO name="ExtendedMod" type="Dummy.LLN0.ExtendedMod" /> <DO name="Beh" type="Dummy.LLN0.Beh" /> <DO name="Health" type="Dummy.LLN0.Health" /> <DO name="NamPlt" type="Dummy.LLN0.NamPlt" /> @@ -486,6 +488,27 @@ <DA fc="CO" name="Oper" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> <DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LLN0.Mod.Cancel" /> </DOType> + <DOType cdc="ENC" id="Dummy.LLN0.ExtendedMod"> + <SDO fc="ST" name="someSdo" type="someSdoType"/> + <DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="ST" name="stSeld" bType="BOOLEAN" /> + <DA fc="OR" name="opRcvd" bType="BOOLEAN" /> + <DA fc="OR" name="opOk" bType="BOOLEAN" /> + <DA fc="OR" name="tOpOk" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" /> + <DA fc="CF" name="sboTimeout" bType="INT32U" /> + <DA fc="CF" name="operTimeout" bType="INT32U" /> + <DA fc="CO" name="SBO" bType="ObjRef" /> + <DA fc="CO" name="SBOw" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> + <DA fc="CO" name="Oper" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> + <DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LLN0.Mod.Cancel" /> + </DOType> + <DOType cdc="CMV" id="someSdoType"> + <DA fc="MX" qchg="true" name="q" bType="Quality"/> + <DA fc="MX" name="t" bType="Timestamp"/> + </DOType> <DOType cdc="ENS" id="Dummy.LLN0.Beh"> <DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" /> <DA fc="ST" name="q" bType="Quality" /> diff --git a/test/testfiles/valid2007B4withIEDModifications.scd b/test/testfiles/valid2007B4withIEDModifications.scd new file mode 100644 index 000000000..39e9ce1f5 --- /dev/null +++ b/test/testfiles/valid2007B4withIEDModifications.scd @@ -0,0 +1,681 @@ +<?xml version="1.0" encoding="UTF-8"?> +<SCL version="2007" revision="B" release="4" xmlns:sxy="http://www.iec.ch/61850/2003/SCLcoordinates" xmlns="http://www.iec.ch/61850/2003/SCL" xmlns:txy="http://www.iec.ch/61850/2003/Terminal" xmlns:scl="http://www.iec.ch/61850/2003/SCL" xsi:schemaLocation="http://www.iec.ch/61850/2003/SCL SCL.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:IEC_60870_5_104="http://www.iec.ch/61850-80-1/2007/SCL"> + <Header id="TrainingIEC61850" version="1" revision="143" toolID="IEC 61850 System Configurator, Version: V5.90 " nameStructure="IEDName"> + <Text>TrainingIEC61850</Text> + <History> + <Hitem version="1" revision="143" when="Wednesday, September 25, 2019 9:11:36 AM" who="Licenced User: OMICRON electronics GmbH JakVog00 Machine: JAKVOG00LW01 User: JakVog00" what="Station is upgraded from IEC 61850 System Configurator, Version: V5.80 HF1 to V5.90 ." why="IEC 61850 System Configurator Automatic Startup: Insert Comment" /> + </History> + </Header> + <Substation name="AA1" desc="Substation"> + <VoltageLevel name="E1" desc="Voltage Level" nomFreq="50.0" numPhases="3"> + <Voltage unit="V" multiplier="k">110.0</Voltage> + <Bay name="COUPLING_BAY" desc="Bay"> + <Private type="dummyType"> + <ekaf:LNode xmlns:ekaf="http://www.dummyURL.com/dummyNS" iedName="IED2" ldInst="CBSWr" lnClass="LPHD" lnInst="1"/> + </Private> + <LNode iedName="IED2" ldInst="CBSW" lnClass="LPHD" lnInst="1"/> + <LNode iedName="IED2" ldInst="CBSW" lnClass="XSWI" lnInst="3"/> + <ConductingEquipment type="CBR" name="QA1" desc="coupling field ciscuit breaker"/> + <ConductingEquipment type="DIS" name="QB1" desc="busbar disconnector QB1"> + <LNode iedName="IED2" ldInst="CBSW" lnClass="XSWI" lnInst="2"/> + </ConductingEquipment> + <ConductingEquipment type="DIS" name="QB2" desc="busbar disconnector QB2"/> + <ConductingEquipment type="DIS" name="QC11" desc="busbar earth switch QC11"> + <Terminal name="T1" connectivityNode="AA1/E1/COUPLING_BAY/L2" substationName="AA1" voltageLevelName="E1" bayName="COUPLING_BAY" cNodeName="L2"/> + <Terminal connectivityNode="AA1/E1/COUPLING_BAY/grounded" name="T2" substationName="AA1" voltageLevelName="E1" bayName="COUPLING_BAY" cNodeName="grounded"/> + </ConductingEquipment> + <ConductingEquipment type="DIS" name="QC21" desc="busbar disconnector Q12"> + <Terminal connectivityNode="AA1/E1/COUPLING_BAY/grounded" name="T1" substationName="AA1" voltageLevelName="E1" bayName="COUPLING_BAY" cNodeName="grounded"/> + </ConductingEquipment> + <ConnectivityNode pathName="AA1/E1/COUPLING_BAY/L2" name="L2"/> + </Bay> + <Bay name="Bay2" desc="Bay2"> + </Bay> + </VoltageLevel> + <VoltageLevel name="J1" desc="Voltage Level"> + <Voltage unit="V" multiplier="k">20</Voltage> + <Bay name="Bay1" desc="Bay1"> + </Bay> + </VoltageLevel> + </Substation> + <Communication> + <SubNetwork name="StationBus" desc="desc" type="8-MMS"> + <BitRate unit="b/s">100.0</BitRate> + <ConnectedAP iedName="IED1" apName="P1"> + <Address> + <P type="IP">192.168.210.111</P> + <P type="IP-SUBNET">255.255.255.0</P> + <P type="IP-GATEWAY">192.168.210.1</P> + <P type="OSI-AP-Title">1,3,9999,23</P> + <P type="OSI-AE-Qualifier">23</P> + <P type="OSI-PSEL">00000001</P> + <P type="OSI-SSEL">0001</P> + <P type="OSI-TSEL">0001</P> + </Address> + <GSE ldInst="CircuitBreaker_CB1" cbName="GCB"> + <Address> + <P type="MAC-Address">01-0C-CD-01-00-10</P> + <P type="VLAN-ID">005</P> + <P type="VLAN-PRIORITY">4</P> + <P type="APPID">0010</P> + </Address> + </GSE> + <PhysConn type="RedConn"> + <P type="Plug">RJ45</P> + </PhysConn> + </ConnectedAP> + </SubNetwork> + <SubNetwork name="ProcessBus" type="8-MMS"> + <ConnectedAP iedName="IED2" apName="P1"> + <Address> + <P type="IP">192.168.0.112</P> + <P type="IP-SUBNET">255.255.255.0</P> + <P type="IP-GATEWAY">192.168.210.1</P> + <P type="OSI-AP-Title">1,3,9999,23</P> + <P type="OSI-AE-Qualifier">23</P> + <P type="OSI-PSEL">00000001</P> + <P type="OSI-SSEL">0001</P> + <P type="OSI-TSEL">0001</P> + </Address> + </ConnectedAP> + <ConnectedAP iedName="IED3" apName="P1"> + <Address> + <P type="IP">192.168.0.113</P> + <P type="IP-SUBNET">255.255.255.0</P> + <P type="IP-GATEWAY">192.168.210.1</P> + <P type="OSI-AP-Title">1,3,9999,23</P> + <P type="OSI-AE-Qualifier">23</P> + <P type="OSI-PSEL">00000001</P> + <P type="OSI-SSEL">0001</P> + <P type="OSI-TSEL">0001</P> + </Address> + <SMV ldInst="MU01" cbName="MSVCB01"> + <Address> + <P type="MAC-Address">01-0C-CD-04-00-20</P> + <P type="VLAN-ID">007</P> + <P type="VLAN-PRIORITY">4</P> + <P type="APPID">4002</P> + </Address> + </SMV> + </ConnectedAP> + </SubNetwork> + </Communication> + <IED name="IED1" type="DummyIED" manufacturer="DummyManufactorer" configVersion="1" originalSclVersion="2007" originalSclRevision="B" owner="DummyOwner"> + <Services> + <DynAssociation /> + <GetDirectory /> + <GetDataObjectDefinition /> + <DataObjectDirectory /> + <GetDataSetValue /> + <SetDataSetValue /> + <DataSetDirectory /> + <ConfDataSet modify="false" max="3" /> + <DynDataSet max="42" /> + <ReadWrite /> + <ConfReportControl bufConf="false" max="10"/> + <GetCBValues /> + <ReportSettings rptID="Dyn" optFields="Dyn" bufTime="Dyn" trgOps="Dyn" intgPd="Dyn" resvTms="true" owner="true" /> + <GOOSE max="1" /> + <GSSE max="0" /> + <ConfLNs fixPrefix="true" fixLnInst="true" /> + </Services> + <AccessPoint name="P1"> + <Server> + <Authentication none="true" /> + <LDevice inst="CircuitBreaker_CB1"> + <LN0 lnClass="LLN0" inst="" lnType="Dummy.LLN0"> + <DataSet name="GooseDataSet1"> + <FCDA ldInst="CircuitBreaker_CB1" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="stVal" fc="ST"/> + <FCDA ldInst="CircuitBreaker_CB1" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="q" fc="ST"/> + <FCDA ldInst="CircuitBreaker_CB1" prefix="" lnClass="CSWI" lnInst="1" doName="Pos" daName="stVal" fc="ST"/> + <FCDA ldInst="Disconnectors" prefix="DC" lnClass="XSWI" lnInst="1" doName="Pos" daName="stVal" fc="ST"/> + <FCDA ldInst="Disconnectors" prefix="DC" lnClass="XSWI" lnInst="1" doName="Pos" daName="q" fc="ST"/> + </DataSet> + <GSEControl type="GOOSE" appID="0001" fixedOffs="false" confRev="1" name="GCB" datSet="GooseDataSet1"> + <IEDName apRef="P1" ldInst="CircuitBreaker_CB1" lnClass="CSWI" lnInst="1">IED2</IEDName> + </GSEControl> + <GSEControl type="GOOSE" appID="0003" fixedOffs="false" confRev="1" name="GCB2"/> + </LN0> + <LN lnClass="XCBR" inst="1" lnType="Dummy.XCBR1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="CSWI" inst="1" lnType="Dummy.CSWIwithoutCtlModel"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>sbo-with-enhanced-security</Val> + </DAI> + </DOI> + </LN> + <LN prefix="CB" lnClass="XCBR" inst="2" lnType="Dummy.XCBR1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN prefix="CB" lnClass="CSWI" inst="2" lnType="Dummy.CSWIwithoutCtlModel"> + <DOI name="Pos"> + <SDI name="pulseConfig"> + <DAI name="numPls"> + <Val>1</Val> + </DAI> + </SDI> + <DAI name="ctlModel"> + <Val>sbo-with-enhanced-security</Val> + </DAI> + </DOI> + </LN> + </LDevice> + <LDevice inst="Disconnectors"> + <LN0 lnClass="LLN0" inst="" lnType="Dummy.LLN0"/> + <LN prefix="DC" lnClass="XSWI" inst="1" lnType="Dummy.XSWI1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN prefix="DC" lnClass="CSWI" inst="1" lnType="Dummy.CSWI"> + <Inputs> + <ExtRef iedName="IED2" ldInst="CBSW" lnClass="XSWI" lnInst="2" doName="Pos" daName="stVal" serviceType="GOOSE" srcCBName="GCB" srcLDInst="CBSW" srcLNClass="LLN0" intAddr="intAddr"/> + <ExtRef iedName="IED2" ldInst="CBSW" lnClass="XSWI" lnInst="2" doName="Pos" daName="q"/> + <ExtRef ldInst="CBSW" lnClass="XSWI" lnInst="2" doName="Pos" daName="t" intAddr="stVal-t"/> + </Inputs> + </LN> + <LN prefix="DC" lnClass="CILO" inst="1" lnType="Dummy.CILO"/> + <LN lnClass="XSWI" inst="3" lnType="Dummy.XSWI1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="CSWI" inst="3" lnType="Dummy.CSWI"/> + <LN lnClass="CILO" inst="3" lnType="Dummy.CILO"/> + <LN lnClass="XSWI" inst="2" lnType="Dummy.XSWI1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>direct-with-normal-security</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="CSWI" inst="2" lnType="Dummy.CSWIwithoutCtlModel"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>sbo-with-normal-security</Val> + </DAI> + </DOI> + </LN> + </LDevice> + </Server> + </AccessPoint> + <KDC iedName="IED1" apName="P1"/> + </IED> + <IED name="IED2" type="DummyIED" manufacturer="DummyManufactorer" configVersion="1" originalSclVersion="2007" originalSclRevision="B" owner="DummyOwner"> + <Services> + <DynAssociation /> + <GetDirectory /> + <GetDataObjectDefinition /> + <DataObjectDirectory /> + <GetDataSetValue /> + <SetDataSetValue /> + <DataSetDirectory /> + <ConfDataSet modify="false" max="3" /> + <DynDataSet max="42" /> + <ReadWrite /> + <ConfReportControl max="10" /> + <GetCBValues /> + <ReportSettings rptID="Dyn" optFields="Dyn" bufTime="Dyn" trgOps="Dyn" intgPd="Dyn" resvTms="true" owner="true" /> + <GOOSE max="1" /> + <GSSE max="0" /> + <ConfLNs fixPrefix="true" fixLnInst="true" /> + </Services> + <AccessPoint name="P1"> + <Server> + <Authentication /> + <LDevice inst="CBSW"> + <LN0 lnClass="LLN0" inst="" lnType="Dummy.LLN0"> + <Private type="dummyType"> + <esld:FCDA xmlns:esld="http://www.dummyURL.com/dummyNS" ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="Pos" daName="stVal" fc="ST"/> + </Private> + <DataSet name="GooseDataSet1"> + <FCDA ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="Pos" daName="stVal" fc="ST"/> + <FCDA ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="Pos" daName="q" fc="ST"/> + </DataSet> + <GSEControl type="GOOSE" appID="0002" fixedOffs="false" confRev="1" name="GCB" datSet="GooseDataSet1"> + </GSEControl> + </LN0> + <LN lnClass="LPHD" inst="1" lnType="Dummy.LPHD1"/> + <LN lnClass="THARDE" inst="1" lnType="Dummy.THARDE"/> + <LN lnClass="XCBR" inst="1" lnType="Dummy.XCBR1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="XSWI" inst="1" lnType="Dummy.XSWI1"> + <DataSet name="dataSet"> + <FCDA ldInst="CBSW" lnClass="XSWI" lnInst="1" doName="Pos" daName="stVal" fc="ST"/> + <FCDA ldInst="CBSW" lnClass="XSWI" lnInst="1" doName="Pos" daName="q" fc="ST"/> + </DataSet> + <ReportControl rptID="IED2/CBSW/XSWI/SwitchGearBRCB" confRev="9" buffered="true" bufTime="100" indexed="true" intgPd="0" name="ReportCb" datSet="dataSet"> + <TrgOps dchg="true" qchg="true" dupd="false" period="false" gi="true"/> + <OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" dataRef="false" entryID="false" configRef="true" bufOvfl="false"/> + <RptEnabled max="5"> + <ClientLN apRef="P1" ldInst="CircuitBreaker_CB1" lnClass="XCBR" lnInst="1" iedName="IED1"/> + </RptEnabled> + </ReportControl> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + <Inputs> + <ExtRef iedName="IED1" ldInst="Disconnectors" prefix="DC" lnClass="XSWI" lnInst="1" doName="Pos" daName="stVal"/> + <ExtRef iedName="IED1" ldInst="Disconnectors" prefix="DC" lnClass="XSWI" lnInst="1" doName="Pos" daName="q"/> + </Inputs> + </LN> + <LN lnClass="XSWI" inst="2" lnType="Dummy.XSWI1"> + <DataSet name="dataSet"> + <FCDA ldInst="CBSW" lnClass="XSWI" lnInst="1" doName="Pos" daName="stVal" fc="ST"/> + <FCDA ldInst="CBSW" lnClass="XSWI" lnInst="1" doName="Pos" daName="q" fc="ST"/> + </DataSet> + <ReportControl rptID="IED2/CBSW/XSWI/SwitchGearBRCB" confRev="9" buffered="true" bufTime="100" indexed="true" intgPd="0" name="ReportCb" datSet="dataSet"> + <TrgOps dchg="true" qchg="true" dupd="false" period="false" gi="true"/> + <OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" dataRef="false" entryID="false" configRef="true" bufOvfl="false"/> + <RptEnabled max="5"> + <ClientLN apRef="P1" ldInst="CircuitBreaker_CB1" lnClass="XCBR" lnInst="1" iedName="IED1"/> + </RptEnabled> + </ReportControl> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="XSWI" inst="3" lnType="Dummy.XSWI1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="GGIO" inst="1" lnType="Dummy.GGIO1"/> + </LDevice> + <LDevice inst="CircuitBreaker_CB1"> + <LN0 lnClass="LLN0" inst="" lnType="Dummy.LLN0"/> + <LN lnClass="XCBR" inst="1" lnType="Dummy.XCBR1"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>status-only</Val> + </DAI> + </DOI> + </LN> + <LN lnClass="CSWI" inst="1" lnType="Dummy.CSWIwithoutCtlModel"> + <DOI name="Pos"> + <DAI name="ctlModel"> + <Val>direct-with-enhanced-security</Val> + </DAI> + </DOI> + <Inputs> + <ExtRef iedName="IED1" ldInst="CircuitBreaker_CB1" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="stVal"/> + <ExtRef iedName="IED1" ldInst="CircuitBreaker_CB1" prefix="" lnClass="XCBR" lnInst="1" doName="Pos" daName="q"/> + </Inputs> + </LN> + <LN lnClass="tHarde" lnType="lnTypeWithoutDOs" /> + </LDevice> + </Server> + </AccessPoint> + </IED> + <IED name="IED3" type="DummyIED" manufacturer="DummyManufactorer" configVersion="1" originalSclVersion="2007" originalSclRevision="B" owner="DummyOwner"> + <Services> + <DynAssociation /> + <GetDirectory /> + <GetDataObjectDefinition /> + <DataObjectDirectory /> + <GetDataSetValue /> + <SetDataSetValue /> + <DataSetDirectory /> + <ConfDataSet modify="false" max="3" /> + <DynDataSet max="42" /> + <ReadWrite /> + <ConfReportControl bufConf="false" max="10"/> + <GetCBValues /> + <ReportSettings rptID="Dyn" optFields="Dyn" bufTime="Dyn" trgOps="Dyn" intgPd="Dyn" resvTms="true" owner="true" /> + <GOOSE max="1" /> + <GSSE max="0" /> + <ConfLNs fixPrefix="true" fixLnInst="true" /> + </Services> + <AccessPoint name="P1"> + <Server> + <Authentication none="true" /> + <LDevice inst="MU01"> + <LN0 lnClass="LLN0" inst="" lnType="Dummy.LLN0.two"> + <DataSet name="PhsMeas1"> + <FCDA ldInst="MU01" prefix="I01A" lnClass="TCTR" lnInst="1" doName="Amp" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01A" lnClass="TCTR" lnInst="1" doName="Amp" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01B" lnClass="TCTR" lnInst="2" doName="Amp" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01B" lnClass="TCTR" lnInst="2" doName="Amp" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01C" lnClass="TCTR" lnInst="3" doName="Amp" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01C" lnClass="TCTR" lnInst="3" doName="Amp" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01N" lnClass="TCTR" lnInst="4" doName="Amp" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="I01N" lnClass="TCTR" lnInst="4" doName="Amp" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01A" lnClass="TVTR" lnInst="1" doName="Vol" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01A" lnClass="TVTR" lnInst="1" doName="Vol" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01B" lnClass="TVTR" lnInst="2" doName="Vol" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01B" lnClass="TVTR" lnInst="2" doName="Vol" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01C" lnClass="TVTR" lnInst="3" doName="Vol" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01C" lnClass="TVTR" lnInst="3" doName="Vol" daName="q" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01N" lnClass="TVTR" lnInst="4" doName="Vol" daName="instMag.i" fc="MX"/> + <FCDA ldInst="MU01" prefix="U01N" lnClass="TVTR" lnInst="4" doName="Vol" daName="q" fc="MX"/> + </DataSet> + <SampledValueControl smvID="IED3_SMVID" multicast="true" smpRate="80" nofASDU="1" confRev="1" name="MSVCB01" datSet="PhsMeas1"> + <SmvOpts/> + </SampledValueControl> + </LN0> + <LN prefix="I01A" lnClass="TCTR" inst="1" lnType="DummyTCTR" /> + <LN prefix="I01B" lnClass="TCTR" inst="2" lnType="DummyTCTR" /> + <LN prefix="I01C" lnClass="TCTR" inst="3" lnType="DummyTCTR" /> + <LN prefix="I01N" lnClass="TCTR" inst="4" lnType="DummyTCTR" /> + <LN prefix="U01A" lnClass="TVTR" inst="1" lnType="DummyTVTR" /> + <LN prefix="U01B" lnClass="TVTR" inst="2" lnType="DummyTVTR" /> + <LN prefix="U01C" lnClass="TVTR" inst="3" lnType="DummyTVTR" /> + <LN prefix="U01N" lnClass="TVTR" inst="4" lnType="DummyTVTR" /> + </LDevice> + </Server> + </AccessPoint> + <AccessPoint name="P2"> + </AccessPoint> + </IED> + <DataTypeTemplates> + <LNodeType lnClass="tHardeClass" id="lnTypeWithoutDOs"> + </LNodeType> + <LNodeType lnClass="LLN0" id="Dummy.LLN0"> + <DO name="Mod" type="Dummy.LLN0.Mod" /> + <DO name="SomeMod" type="NonExistingType" /> + <DO name="ExtendedMod" type="Dummy.LLN0.ExtendedMod" /> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="Health" type="Dummy.LLN0.Health" /> + <DO name="NamPlt" type="Dummy.LLN0.NamPlt" /> + </LNodeType> + <LNodeType lnClass="LLN0" id="Dummy.LLN0.two"> + <DO name="Mod" type="Dummy.LLN0.Mod" /> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="Health" type="Dummy.LLN0.Health" /> + <DO name="NamPlt" type="Dummy.LLN0.NamPlt" /> + </LNodeType> + <LNodeType lnClass="LPHD" id="Dummy.LPHD1"> + <DO name="PhyNam" type="Dummy.LPHD1.PhyNam" /> + <DO name="PhyHealth" type="Dummy.LLN0.Health" /> + <DO name="Proxy" type="Dummy.SPS" /> + <DO name="Sim" type="Dummy.LPHD1.Sim" /> + </LNodeType> + <LNodeType lnClass="XCBR" id="Dummy.XCBR1"> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt" /> + <DO name="Loc" type="Dummy.SPS" /> + <DO name="OpCnt" type="Dummy.XCBR1.OpCnt" /> + <DO name="Pos" type="Dummy.XCBR1.Pos" /> + <DO name="BlkOpn" type="Dummy.XCBR1.BlkOpn" /> + <DO name="BlkCls" type="Dummy.XCBR1.BlkOpn" /> + </LNodeType> + <LNodeType lnClass="CSWI" id="Dummy.CSWI"> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt" /> + <DO name="Loc" type="Dummy.SPS" /> + <DO name="OpCnt" type="Dummy.XCBR1.OpCnt" /> + <DO name="Pos" type="Dummy.CSWI.Pos1" /> + </LNodeType> + <LNodeType lnClass="CILO" id="Dummy.CILO"> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt" /> + <DO name="EnaOpn" type="Dummy.SPS"/> + <DO name="EnaCls" type="Dummy.SPS"/> + </LNodeType> + <LNodeType lnClass="CSWI" id="Dummy.CSWIwithoutCtlModel"> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt" /> + <DO name="Loc" type="Dummy.SPS" /> + <DO name="OpCnt" type="Dummy.XCBR1.OpCnt" /> + <DO name="Pos" type="Dummy.CSWI.Pos2" /> + </LNodeType> + <LNodeType lnClass="XSWI" id="Dummy.XSWI1"> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt" /> + <DO name="Loc" type="Dummy.SPS" /> + <DO name="OpCnt" type="Dummy.XCBR1.OpCnt" /> + <DO name="Pos" type="Dummy.XCBR1.Pos" /> + <DO name="BlkOpn" type="Dummy.XCBR1.BlkOpn" /> + <DO name="BlkCls" type="Dummy.XCBR1.BlkOpn" /> + </LNodeType> + <LNodeType lnClass="GGIO" id="Dummy.GGIO1"> + <DO name="Beh" type="Dummy.LLN0.Beh" /> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt" /> + <DO name="Ind1" type="Dummy.SPS" /> + <DO name="SPCSO1" type="Dummy.LPHD1.Sim" /> + </LNodeType> + <LNodeType lnClass="TCTR" id="DummyTCTR"> + <DO name="Mod" type="Dummy.LLN0.Mod"/> + <DO name="Beh" type="Dummy.LLN0.Beh"/> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt"/> + <DO name="Amp" type="DummySAV"/> + </LNodeType> + <LNodeType lnClass="TVTR" id="DummyTVTR"> + <DO name="Mod" type="Dummy.LLN0.Mod"/> + <DO name="Beh" type="Dummy.LLN0.Beh"/> + <DO name="NamPlt" type="Dummy.XCBR1.NamPlt"/> + <DO name="Vol" type="DummySAV"/> + </LNodeType> + <DOType cdc="SAV" id="DummySAV"> + <DA fc="MX" name="instMag" bType="Struct" type="AnalogueValue_i"/> + <DA fc="MX" qchg="true" name="q" bType="Quality"/> + <DA fc="CF" name="sVC" bType="Struct" type="ScaledValueConfig"/> + </DOType> + <DOType cdc="ENC" id="Dummy.LLN0.Mod"> + <DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="ST" name="stSeld" bType="BOOLEAN" /> + <DA fc="OR" name="opRcvd" bType="BOOLEAN" /> + <DA fc="OR" name="opOk" bType="BOOLEAN" /> + <DA fc="OR" name="tOpOk" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" /> + <DA fc="CF" name="sboTimeout" bType="INT32U" /> + <DA fc="CF" name="operTimeout" bType="INT32U" /> + <DA fc="CO" name="SBO" bType="ObjRef" /> + <DA fc="CO" name="SBOw" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> + <DA fc="CO" name="Oper" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> + <DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LLN0.Mod.Cancel" /> + </DOType> + <DOType cdc="ENC" id="Dummy.LLN0.ExtendedMod"> + <SDO fc="ST" name="someSdo" type="someSdoType"/> + <SDO fc="ST" name="someOtherSdo" type="someSdoType"/> + <DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="ST" name="stSeld" bType="BOOLEAN" /> + <DA fc="OR" name="opRcvd" bType="BOOLEAN" /> + <DA fc="OR" name="opOk" bType="BOOLEAN" /> + <DA fc="OR" name="tOpOk" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" /> + <DA fc="CF" name="sboTimeout" bType="INT32U" /> + <DA fc="CF" name="operTimeout" bType="INT32U" /> + <DA fc="CO" name="SBO" bType="ObjRef" /> + <DA fc="CO" name="SBOw" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> + <DA fc="CO" name="Oper" bType="Struct" type="Dummy.LLN0.Mod.SBOw" /> + <DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LLN0.Mod.Cancel" /> + </DOType> + <DOType cdc="CMV" id="someSdoType"> + <SDO fc="ST" name="anotherSdo" type="justASDOType"/> + <DA fc="MX" qchg="true" name="q" bType="Quality"/> + <DA fc="MX" name="t" bType="Timestamp"/> + </DOType> + <DOType cdc="CMV" id="justASDOType"> + <DA fc="MX" qchg="true" name="q" bType="Quality"/> + <DA fc="MX" name="t" bType="Timestamp"/> + </DOType> + <DOType cdc="ENS" id="Dummy.LLN0.Beh"> + <DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + </DOType> + <DOType cdc="ENS" id="Dummy.LLN0.Health"> + <DA fc="ST" name="stVal" bType="Enum" type="Dummy_Health" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + </DOType> + <DOType cdc="LPL" id="Dummy.LLN0.NamPlt"> + <DA fc="DC" name="vendor" bType="VisString255" /> + <DA fc="DC" name="swRev" bType="VisString255" /> + <DA fc="DC" name="d" bType="VisString255" /> + <DA fc="DC" name="configRev" bType="VisString255" /> + <DA fc="EX" name="ldNs" bType="VisString255" /> + </DOType> + <DOType cdc="DPL" id="Dummy.LPHD1.PhyNam"> + <DA fc="DC" name="vendor" bType="VisString255" /> + <DA fc="DC" name="hwRev" bType="VisString255" /> + <DA fc="DC" name="swRev" bType="VisString255" /> + <DA fc="DC" name="serNum" bType="VisString255" /> + <DA fc="DC" name="model" bType="VisString255" /> + </DOType> + <DOType cdc="SPC" id="Dummy.LPHD1.Sim"> + <DA fc="ST" name="stVal" bType="BOOLEAN" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="ST" name="stSeld" bType="BOOLEAN" /> + <DA fc="OR" name="opRcvd" bType="BOOLEAN" /> + <DA fc="OR" name="opOk" bType="BOOLEAN" /> + <DA fc="OR" name="tOpOk" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" /> + <DA fc="CF" name="sboTimeout" bType="INT32U" /> + <DA fc="CF" name="operTimeout" bType="INT32U" /> + <DA fc="DC" name="d" bType="VisString255" /> + <DA fc="CO" name="SBO" bType="ObjRef" /> + <DA fc="CO" name="SBOw" bType="Struct" type="Dummy.LPHD1.Sim.SBOw" /> + <DA fc="CO" name="Oper" bType="Struct" type="Dummy.LPHD1.Sim.SBOw" /> + <DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LPHD1.Sim.Cancel" /> + </DOType> + <DOType cdc="DPC" id="Dummy.XCBR1.Pos"> + <DA fc="ST" name="stVal" bType="Dbpos" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" /> + <DA fc="DC" name="d" bType="VisString255" /> + </DOType> + <DOType cdc="DPC" id="Dummy.CSWI.Pos1"> + <DA fc="ST" name="stVal" bType="Dbpos" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel"> + <Val>sbo-with-enhanced-security</Val> + </DA> + <DA fc="DC" name="d" bType="VisString255" /> + </DOType> + <DOType cdc="DPC" id="Dummy.CSWI.Pos2"> + <DA fc="ST" name="stVal" bType="Dbpos" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel"/> + <DA fc="DC" name="d" bType="VisString255" /> + </DOType> + <DOType cdc="INS" id="Dummy.XCBR1.OpCnt"> + <DA fc="ST" name="stVal" bType="INT32" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + </DOType> + <DOType cdc="LPL" id="Dummy.XCBR1.NamPlt"> + <DA fc="DC" name="vendor" bType="VisString255" /> + <DA fc="DC" name="swRev" bType="VisString255" /> + <DA fc="DC" name="d" bType="VisString255" /> + </DOType> + <DOType cdc="SPC" id="Dummy.XCBR1.BlkOpn"> + <DA fc="ST" name="stVal" bType="BOOLEAN" /> + <DA fc="ST" name="q" bType="Quality" /> + <DA fc="ST" name="t" bType="Timestamp" /> + <DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" /> + <DA fc="DC" name="d" bType="VisString255" /> + </DOType> + <DOType cdc="SPS" id="Dummy.SPS"> + <DA fc="ST" dchg="true" name="stVal" bType="BOOLEAN"/> + <DA fc="ST" qchg="true" name="q" bType="Quality"/> + <DA fc="ST" name="t" bType="Timestamp"/> + </DOType> + <DAType id="AnalogueValue_i"> + <BDA name="i" bType="INT32"/> + </DAType> + <DAType id="ScaledValueConfig"> + <BDA name="scaleFactor" bType="FLOAT32"/> + <BDA name="offset" bType="FLOAT32"/> + </DAType> + <DAType id="Dummy_origin"> + <BDA name="orCat" bType="Enum" type="Dummy_orCategory" /> + <BDA name="orIdent" bType="Octet64" /> + </DAType> + <DAType id="Dummy.LLN0.Mod.SBOw"> + <BDA name="ctlVal" bType="Enum" type="Dummy_Beh" /> + <BDA name="origin" bType="Struct" type="Dummy_origin" /> + <BDA name="ctlNum" bType="INT8U" /> + <BDA name="T" bType="Timestamp" /> + <BDA name="Test" bType="BOOLEAN" /> + <BDA name="Check" bType="Check" /> + <ProtNs>IEC 61850-8-1:2003</ProtNs> + </DAType> + <DAType id="Dummy.LLN0.Mod.Cancel"> + <BDA name="ctlVal" bType="Enum" type="Dummy_Beh" /> + <BDA name="origin" bType="Struct" type="Dummy_origin" /> + <BDA name="ctlNum" bType="INT8U" /> + <BDA name="T" bType="Timestamp" /> + <BDA name="Test" bType="BOOLEAN" /> + </DAType> + <DAType id="Dummy.LPHD1.Sim.SBOw"> + <BDA name="ctlVal" bType="BOOLEAN" /> + <BDA name="origin" bType="Struct" type="Dummy_origin" /> + <BDA name="ctlNum" bType="INT8U" /> + <BDA name="T" bType="Timestamp" /> + <BDA name="Test" bType="BOOLEAN" /> + <BDA name="Check" bType="Check" /> + </DAType> + <DAType id="Dummy.LPHD1.Sim.Cancel"> + <BDA name="ctlVal" bType="BOOLEAN" /> + <BDA name="origin" bType="Struct" type="Dummy_origin" /> + <BDA name="ctlNum" bType="INT8U" /> + <BDA name="T" bType="Timestamp" /> + <BDA name="Test" bType="BOOLEAN" /> + </DAType> + <EnumType id="Dummy_ctlModel"> + <EnumVal ord="0">status-only</EnumVal> + <EnumVal ord="1">direct-with-normal-security</EnumVal> + <EnumVal ord="2">sbo-with-normal-security</EnumVal> + <EnumVal ord="3">direct-with-enhanced-security</EnumVal> + <EnumVal ord="4">sbo-with-enhanced-security</EnumVal> + </EnumType> + <EnumType id="Dummy_Beh"> + <EnumVal ord="1">on</EnumVal> + <EnumVal ord="2">blocked</EnumVal> + <EnumVal ord="3">test</EnumVal> + <EnumVal ord="4">test/blocked</EnumVal> + <EnumVal ord="5">off</EnumVal> + </EnumType> + <EnumType id="Dummy_Health"> + <EnumVal ord="1">Ok</EnumVal> + <EnumVal ord="2">Warning</EnumVal> + <EnumVal ord="3">Alarm</EnumVal> + </EnumType> + <EnumType id="Dummy_orCategory"> + <EnumVal ord="0">not-supported</EnumVal> + <EnumVal ord="1">bay-control</EnumVal> + <EnumVal ord="2">station-control</EnumVal> + <EnumVal ord="3">remote-control</EnumVal> + <EnumVal ord="4">automatic-bay</EnumVal> + <EnumVal ord="5">automatic-station</EnumVal> + <EnumVal ord="6">automatic-remote</EnumVal> + <EnumVal ord="7">maintenance</EnumVal> + <EnumVal ord="8">process</EnumVal> + </EnumType> + </DataTypeTemplates> +</SCL> \ No newline at end of file diff --git a/test/unit/Plugging.test.ts b/test/unit/Plugging.test.ts index f95ff03fb..f864126e0 100644 --- a/test/unit/Plugging.test.ts +++ b/test/unit/Plugging.test.ts @@ -22,7 +22,7 @@ describe('PluggingElement', () => { }); it('stores default plugins on load', () => - expect(element).property('editors').to.have.lengthOf(4)); + expect(element).property('editors').to.have.lengthOf(3)); describe('plugin manager dialog', () => { let firstEditorPlugin: HTMLElement; @@ -49,7 +49,7 @@ describe('PluggingElement', () => { it('disables deselected plugins', async () => { firstEditorPlugin.click(); await element.updateComplete; - expect(element).property('editors').to.have.lengthOf(3); + expect(element).property('editors').to.have.lengthOf(2); }); it('enables selected plugins', async () => { @@ -57,7 +57,7 @@ describe('PluggingElement', () => { await element.updateComplete; (<HTMLElement>element.pluginList.firstElementChild).click(); await element.updateComplete; - expect(element).property('editors').to.have.lengthOf(4); + expect(element).property('editors').to.have.lengthOf(3); }); it('resets plugins to default on reset button click', async () => { @@ -65,7 +65,7 @@ describe('PluggingElement', () => { await element.updateComplete; resetAction.click(); await element.updateComplete; - expect(element).property('editors').to.have.lengthOf(4); + expect(element).property('editors').to.have.lengthOf(3); }); it('opens the custom plugin dialog on add button click', async () => { @@ -139,7 +139,7 @@ describe('PluggingElement', () => { await name.updateComplete; primaryAction.click(); await element.updateComplete; - expect(element.editors).to.have.lengthOf(5); + expect(element.editors).to.have.lengthOf(4); }); it('adds a new menu kind plugin on add button click', async () => { const lengthMenuKindPlugins = element.menuEntries.length; diff --git a/test/unit/editors/ied/__snapshots__/do-container.test.snap.js b/test/unit/editors/ied/__snapshots__/do-container.test.snap.js new file mode 100644 index 000000000..54435eba5 --- /dev/null +++ b/test/unit/editors/ied/__snapshots__/do-container.test.snap.js @@ -0,0 +1,23 @@ +/* @web/test-runner snapshot v1 */ +export const snapshots = {}; + +snapshots["do-container looks like the latest snapshot with a SDO element."] = +`<action-pane + icon="" + tabindex="0" +> + <do-container> + </do-container> +</action-pane> +`; +/* end snapshot do-container looks like the latest snapshot with a SDO element. */ + +snapshots["do-container looks like the latest snapshot with a DO element."] = +`<action-pane + icon="" + tabindex="0" +> +</action-pane> +`; +/* end snapshot do-container looks like the latest snapshot with a DO element. */ + diff --git a/test/unit/editors/ied/__snapshots__/ldevice-container.test.snap.js b/test/unit/editors/ied/__snapshots__/ldevice-container.test.snap.js index 2589a3de7..e807fb7fe 100644 --- a/test/unit/editors/ied/__snapshots__/ldevice-container.test.snap.js +++ b/test/unit/editors/ied/__snapshots__/ldevice-container.test.snap.js @@ -3,7 +3,7 @@ export const snapshots = {}; snapshots["ldevice-container looks like the latest snapshot"] = `<action-pane tabindex="0"> - <div id="bayContainer"> + <div id="lnContainer"> <ln-container> </ln-container> <ln-container> diff --git a/test/unit/editors/ied/__snapshots__/ln-container.test.snap.js b/test/unit/editors/ied/__snapshots__/ln-container.test.snap.js index 1a249e169..9aa4546e4 100644 --- a/test/unit/editors/ied/__snapshots__/ln-container.test.snap.js +++ b/test/unit/editors/ied/__snapshots__/ln-container.test.snap.js @@ -3,12 +3,38 @@ export const snapshots = {}; snapshots["ln-container looks like the latest snapshot with a LN0 element."] = `<action-pane tabindex="0"> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> </action-pane> `; /* end snapshot ln-container looks like the latest snapshot with a LN0 element. */ snapshots["ln-container looks like the latest snapshot with a LN element."] = `<action-pane tabindex="0"> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> + <do-container> + </do-container> </action-pane> `; /* end snapshot ln-container looks like the latest snapshot with a LN element. */ diff --git a/test/unit/editors/ied/do-container.test.ts b/test/unit/editors/ied/do-container.test.ts new file mode 100644 index 000000000..e477aa514 --- /dev/null +++ b/test/unit/editors/ied/do-container.test.ts @@ -0,0 +1,67 @@ +import { html, fixture, expect } from '@open-wc/testing'; + +import '../../../../src/editors/ied/do-container.js'; +import { DOContainer } from '../../../../src/editors/ied/do-container.js'; + +describe('do-container', () => { + let element: DOContainer; + let validSCL: XMLDocument; + + beforeEach(async () => { + validSCL = await fetch('/test/testfiles/valid2007B4withIEDModifications.scd') + .then(response => response.text()) + .then(str => new DOMParser().parseFromString(str, 'application/xml')); + }); + + it('looks like the latest snapshot with a DO element.', async () => { + element = await fixture(html`<do-container + .element=${validSCL.querySelector( + 'DataTypeTemplates > LNodeType[id="Dummy.LLN0"] > DO[name="Mod"]')} + ></do-container>`); + expect(element).shadowDom.to.equalSnapshot(); + }); + + it('looks like the latest snapshot with a SDO element.', async () => { + element = await fixture(html`<do-container + .element=${validSCL.querySelector( + 'DataTypeTemplates > DOType[id="Dummy.LLN0.ExtendedMod"] > SDO[name="someSdo"]')} + ></do-container>`); + expect(element).shadowDom.to.equalSnapshot(); + }); + + describe('has a getDOElements function ', () => { + it('which return the (S)DO containers underneath a given DO.', async () => { + element = await fixture(html`<do-container + .element=${validSCL.querySelector( + 'DataTypeTemplates > LNodeType[id="Dummy.LLN0"] > DO[name="ExtendedMod"]')} + ></do-container>`); + + const nestedDOs = element['getDOElements'](); + expect(nestedDOs).to.not.be.empty; + expect(nestedDOs!.length).to.eql(2); + expect(nestedDOs![1].getAttribute('name')).to.eql('someOtherSdo'); + }); + + it('which return the (S)DO containers underneath a given SDO.', async () => { + element = await fixture(html`<do-container + .element=${validSCL.querySelector( + 'DataTypeTemplates > DOType[id="Dummy.LLN0.ExtendedMod"] > SDO[name="someOtherSdo"]')} + ></do-container>`); + + const nestedDOs = element['getDOElements'](); + expect(nestedDOs).to.not.be.empty; + expect(nestedDOs!.length).to.eql(1); + expect(nestedDOs![0].getAttribute('name')).to.eql('anotherSdo'); + }); + + it('which return an empty array if a DO doesn\t have child (S)DO\'s.', async () => { + element = await fixture(html`<do-container + .element=${validSCL.querySelector( + 'DataTypeTemplates > DOType[id="someSdoType"] > SDO[name="anotherSdo"]')} + ></do-container>`); + + const nestedDOs = element['getDOElements'](); + expect(nestedDOs).to.be.empty; + }); + }); +}); diff --git a/test/unit/editors/ied/ln-container.test.ts b/test/unit/editors/ied/ln-container.test.ts index e7336253d..2068840fe 100644 --- a/test/unit/editors/ied/ln-container.test.ts +++ b/test/unit/editors/ied/ln-container.test.ts @@ -8,7 +8,7 @@ describe('ln-container', () => { let validSCL: XMLDocument; beforeEach(async () => { - validSCL = await fetch('/test/testfiles/valid2007B4.scd') + validSCL = await fetch('/test/testfiles/valid2007B4withIEDModifications.scd') .then(response => response.text()) .then(str => new DOMParser().parseFromString(str, 'application/xml')); }); @@ -18,7 +18,7 @@ describe('ln-container', () => { .element=${validSCL.querySelector( 'IED[name="IED1"] > AccessPoint[name="P1"] > Server > LDevice[inst="CircuitBreaker_CB1"] > LN0[lnClass="LLN0"]')} ></ln-container>`); - await expect(element).shadowDom.to.equalSnapshot(); + expect(element).shadowDom.to.equalSnapshot(); }); it('looks like the latest snapshot with a LN element.', async () => { @@ -26,6 +26,66 @@ describe('ln-container', () => { .element=${validSCL.querySelector( 'IED[name="IED1"] > AccessPoint[name="P1"] > Server > LDevice[inst="CircuitBreaker_CB1"] > LN[lnClass="XCBR"]')} ></ln-container>`); - await expect(element).shadowDom.to.equalSnapshot(); + expect(element).shadowDom.to.equalSnapshot(); + }); + + describe('has a getDOElements function ', () => { + it('which return the DO containers underneath a given LN.', async () => { + element = await fixture(html`<ln-container + .element=${validSCL.querySelector( + 'IED[name="IED1"] > AccessPoint[name="P1"] > Server > LDevice[inst="Disconnectors"] > LN[lnClass="CILO"]')} + ></ln-container>`); + + const nestedDOs = element['getDOElements'](); + expect(nestedDOs).to.not.be.empty; + expect(nestedDOs!.length).to.eql(4); + expect(nestedDOs![1].getAttribute('name')).to.eql('NamPlt'); + }); + + it('which return the DO containers underneath a given LN0.', async () => { + element = await fixture(html`<ln-container + .element=${validSCL.querySelector( + 'IED[name="IED2"] > AccessPoint[name="P1"] > Server > LDevice[inst="CircuitBreaker_CB1"] > LN0[lnClass="LLN0"]')} + ></ln-container>`); + + const nestedDOs = element['getDOElements'](); + expect(nestedDOs).to.not.be.empty; + expect(nestedDOs!.length).to.eql(6); + expect(nestedDOs![4].getAttribute('name')).to.eql('Health'); + }); + + it('which return an empty array if a LN doesn\t have child DO\'s.', async () => { + element = await fixture(html`<ln-container + .element=${validSCL.querySelector( + 'IED[name="IED2"] > AccessPoint[name="P1"] > Server > LDevice[inst="CircuitBreaker_CB1"] > LN[lnClass="tHarde"]')} + ></ln-container>`); + + const nestedDOs = element['getDOElements'](); + expect(nestedDOs).to.be.empty; + }); + }); + + describe('has a getInstanceElement function ', () => { + beforeEach(async () => { + element = await fixture(html`<ln-container + .element=${validSCL.querySelector( + 'IED[name="IED2"] > AccessPoint[name="P1"] > Server > LDevice[inst="CBSW"] > LN[lnClass="XCBR"]')} + ></ln-container>`); + }); + + it('which returns a DOI for a LN if it\'s available.', async () => { + const dO = validSCL.querySelector( + 'DataTypeTemplates > LNodeType[id="Dummy.XCBR1"] > DO[name="Pos"]') + const instance = element['getInstanceElement'](dO!)!; + expect(instance).to.not.be.null; + expect(instance.tagName).to.eql('DOI'); + expect(instance.getAttribute('name')).to.eql('Pos'); + }); + + it('which returns null if no DOI is available.', async () => { + const dO = validSCL.querySelector( + 'DataTypeTemplates > LNodeType[id="Dummy.XCBR1"] > DO[name="Loc"]') + expect(element['getInstanceElement'](dO!)!).to.be.null; + }); }); });