Skip to content

Commit 8381d52

Browse files
author
Dennis Labordus
authored
Merge pull request openscd#803 from openscd/104-add-control-address
feat(104/Address): Added "Control" handling of CDC and first part of refactoring after discussion.
2 parents 664eb0b + 1e04176 commit 8381d52

File tree

19 files changed

+1876
-212
lines changed

19 files changed

+1876
-212
lines changed

src/editors/protocol104/foundation/cdc.ts

Lines changed: 126 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ import {addPrefixAndNamespaceToDocument, createPrivateAddress, createPrivateElem
55
/**
66
* List of supported Common Data Classes in the 104 protocol.
77
*/
8-
export const supportedCdcTypes = ['ACT', 'ASG', 'BCR', 'CMV', 'DPS', 'ING', 'INS', 'MV', 'SEC', 'SPG', 'SPS'] as const;
8+
export const supportedCdcTypes =
9+
[ 'ACT', 'APC', 'ASG', 'BAC', 'BCR', 'BSC', 'CMV',
10+
'DPC', 'DPS', 'INC', 'ING', 'INS', 'ISC', 'MV',
11+
'SEC', 'SPC', 'SPG', 'SPS'] as const;
912
export type SupportedCdcType = typeof supportedCdcTypes[number];
1013

11-
type CreateFunction = (daiElement: Element, selectedTi: string) => Create[];
14+
export type CreateFunction = (daiElement: Element, selectedTi: string) => Create[];
1215

1316
/**
1417
* Record with configuration information on how to create Address elements for the 104 protocol.
@@ -35,60 +38,137 @@ export const cdcProcessings: Record<
3538
ACT: {
3639
monitor: {
3740
'30': {
38-
filter: 'DAI[name="general"], DAI[name="phsA"], DAI[name="phsB"], DAI[name="phsC"], DAI[name="neut"]',
41+
filter: ':scope > DAI[name="general"], ' +
42+
':scope > DAI[name="phsA"], ' +
43+
':scope > DAI[name="phsB"], ' +
44+
':scope > DAI[name="phsC"], ' +
45+
':scope > DAI[name="neut"]',
3946
create: createSingleAddressAction
4047
},
4148
'39': {
42-
filter: 'DAI[name="general"]',
49+
filter: ':scope > DAI[name="general"]',
4350
create: createSingleAddressAction
4451
}
4552
},
4653
control: {}
4754
},
55+
APC: {
56+
monitor: {
57+
'36': {
58+
filter: ':scope > SDI[name="mxVal"] > DAI[name="f"]',
59+
create: createSingleAddressAction
60+
},
61+
},
62+
control: {
63+
'63': {
64+
filter: ':scope > SDI[name="Oper"] > SDI[name="ctlVal"] > DAI[name="f"]',
65+
create: createSingleAddressAction
66+
},
67+
}
68+
},
4869
ASG: {
4970
monitor: {
5071
'63': {
51-
filter: 'SDI[name="setMag"] > DAI[name="f"]',
72+
filter: ':scope > SDI[name="setMag"] > DAI[name="f"]',
5273
create: createSingleAddressAction
5374
}
5475
},
5576
control: {}
5677
},
78+
BAC: {
79+
monitor: {
80+
'36': {
81+
filter: ':scope > SDI[name="mxVal"] > DAI[name="f"]',
82+
create: createSingleAddressAction
83+
},
84+
},
85+
control: {
86+
'60': {
87+
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
88+
create: createSingleAddressAction
89+
},
90+
}
91+
},
5792
BCR: {
5893
monitor: {
5994
'37': {
60-
filter: 'DAI[name="actVal"], DAI[name="frVal"]',
95+
filter: ':scope > DAI[name="actVal"], ' +
96+
':scope > DAI[name="frVal"]',
6197
create: createSingleAddressAction
6298
},
6399
},
64100
control: {}
65101
},
102+
BSC: {
103+
monitor: {
104+
'32': {
105+
filter: ':scope > SDI[name="valWTr"] > DAI[name="posVal"]',
106+
create: createSingleAddressAction
107+
},
108+
},
109+
control: {
110+
'60': {
111+
filter: ':scope > SDI[name="Oper"] > DAI[name=“ctlVal”]',
112+
create: createSingleAddressAction
113+
},
114+
}
115+
},
66116
CMV: {
67117
monitor: {
68118
'35': {
69-
filter: 'SDI[name="mag"] > DAI[name="i"], SDI[name="ang"] > DAI[name="i"]',
119+
filter: ':scope > SDI[name="mag"] > DAI[name="i"], ' +
120+
':scope > SDI[name="ang"] > DAI[name="i"]',
70121
create: createSingleAddressAction
71122
},
72123
'36': {
73-
filter: 'SDI[name="mag"] > DAI[name="f"], SDI[name="ang"] > DAI[name="f"]',
124+
filter: ':scope > SDI[name="mag"] > DAI[name="f"], ' +
125+
':scope > SDI[name="ang"] > DAI[name="f"]',
74126
create: createSingleAddressAction
75127
}
76128
},
77129
control: {}
78130
},
131+
DPC: {
132+
monitor: {
133+
'31': {
134+
filter: ':scope > DAI[name="stVal"]',
135+
create: createSingleAddressAction
136+
},
137+
},
138+
control: {
139+
'59': {
140+
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
141+
create: createSingleAddressAction
142+
},
143+
}
144+
},
79145
DPS: {
80146
monitor: {
81147
'31': {
82-
filter: 'DAI[name="stVal"]',
148+
filter: ':scope > DAI[name="stVal"]',
83149
create: createSingleAddressAction
84150
}
85151
},
86152
control: {}
87153
},
154+
INC: {
155+
monitor: {
156+
'35': {
157+
filter: ':scope > DAI[name="stVal"]',
158+
create: createSingleAddressAction
159+
},
160+
},
161+
control: {
162+
'62': {
163+
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
164+
create: createSingleAddressAction
165+
},
166+
}
167+
},
88168
ING: {
89169
monitor: {
90170
'62': {
91-
filter: 'DAI[name="setVal"]',
171+
filter: ':scope > DAI[name="setVal"]',
92172
create: createSingleAddressAction
93173
}
94174
},
@@ -97,28 +177,42 @@ export const cdcProcessings: Record<
97177
INS: {
98178
monitor: {
99179
'30': {
100-
filter: 'DAI[name="stVal"]',
180+
filter: ':scope > DAI[name="stVal"]',
101181
create: createInvertedAddressAction
102182
},
103183
'33': {
104-
filter: 'DAI[name="stVal"]',
184+
filter: ':scope > DAI[name="stVal"]',
105185
create: createSingleAddressAction
106186
},
107187
'35': {
108-
filter: 'DAI[name="stVal"]',
188+
filter: ':scope > DAI[name="stVal"]',
109189
create: createSingleAddressAction
110190
}
111191
},
112192
control: {}
113193
},
194+
ISC: {
195+
monitor: {
196+
'32': {
197+
filter: ':scope > SDI[name="valWTr"] > DAI[name="posVal"]',
198+
create: createSingleAddressAction
199+
},
200+
},
201+
control: {
202+
'62': {
203+
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
204+
create: createSingleAddressAction
205+
},
206+
}
207+
},
114208
MV: {
115209
monitor: {
116210
'35': {
117-
filter: 'SDI[name="mag"] > DAI[name="i"]',
211+
filter: ':scope > SDI[name="mag"] > DAI[name="i"]',
118212
create: createSingleAddressAction
119213
},
120214
'36': {
121-
filter: 'SDI[name="mag"] > DAI[name="f"]',
215+
filter: ':scope > SDI[name="mag"] > DAI[name="f"]',
122216
create: createSingleAddressAction
123217
}
124218
},
@@ -127,16 +221,30 @@ export const cdcProcessings: Record<
127221
SEC: {
128222
monitor: {
129223
'37': {
130-
filter: 'DAI[name="cnt"]',
224+
filter: ':scope > DAI[name="cnt"]',
131225
create: createSingleAddressAction
132226
}
133227
},
134228
control: {}
135229
},
230+
SPC: {
231+
monitor: {
232+
'30': {
233+
filter: ':scope > DAI[name="stVal"]',
234+
create: createSingleAddressAction
235+
},
236+
},
237+
control: {
238+
'58': {
239+
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
240+
create: createSingleAddressAction
241+
},
242+
}
243+
},
136244
SPG: {
137245
monitor: {
138246
'58': {
139-
filter: 'DAI[name="setVal"]',
247+
filter: ':scope > DAI[name="setVal"]',
140248
create: createSingleAddressAction
141249
}
142250
},
@@ -145,7 +253,7 @@ export const cdcProcessings: Record<
145253
SPS: {
146254
monitor: {
147255
'30': {
148-
filter: 'DAI[name="stVal"]',
256+
filter: ':scope > DAI[name="stVal"]',
149257
create: createSingleAddressAction
150258
}
151259
},

src/editors/protocol104/foundation/foundation.ts

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import {
2+
Create,
23
getInstanceAttribute,
3-
getNameAttribute
4+
getNameAttribute,
5+
newWizardEvent
46
} from "../../../foundation.js";
7+
import { editAddressWizard } from "../wizards/address.js";
8+
import { CreateFunction } from "./cdc.js";
59

610
export const PRIVATE_TYPE_104 = "IEC_60870_5_104";
711

@@ -135,6 +139,80 @@ export function hasScaleFields(cdc: string, ti: string): boolean {
135139
return (cdc === 'MV' && ['35', '36'].includes(ti));
136140
}
137141

142+
/**
143+
* Search for a DAI Element below the passed DOI Element.
144+
*
145+
* @param doiElement - The DOI Element to search on.
146+
* @param name - The name of the DAI Element to search for.
147+
* @returns The found DAI Element or null, if not found.
148+
*/
149+
export function getDaiElement(doiElement: Element, name: string): Element | null {
150+
return doiElement.querySelector(`:scope > DAI[name="${name}"]`);
151+
}
152+
153+
/**
154+
* Search for the Value of a DAI Element below the passed DOI Element.
155+
*
156+
* @param doiElement - The DOI Element to search on.
157+
* @param name - The name of the DAI Element to search for.
158+
* @returns The value (Val) of the found DAI Element or null, if not found.
159+
*/
160+
export function getDaiValue(doiElement: Element, name: string): string | null {
161+
const daiElement = getDaiElement(doiElement, name);
162+
if (daiElement) {
163+
return daiElement.querySelector(':scope > Val')?.textContent ?? null;
164+
}
165+
return null;
166+
}
167+
168+
/**
169+
* Search for the DAI Element 'ctlModel', this one indicates if control Addresses need to be created.
170+
*
171+
* @param doiElement - The DOI Element.
172+
* @returns The value of the CtlModel.
173+
*/
174+
export function getCtlModel(doiElement: Element): string | null {
175+
return getDaiValue(doiElement, 'ctlModel');
176+
}
177+
178+
/**
179+
* Create a list of Create Actions using the parameters passed. First search for the DAI Elements
180+
* that can be effected. Next create the action and add it to this list, also start the Edit
181+
* Address Element wizard for all Address Elements created.
182+
*
183+
* @param doiElement - The DOI Element.
184+
* @param wizard - The Wizard to dispatch the Open Wizard event on.
185+
* @param ti - The TI Value set on the new Address Elements.
186+
* @param filter - The Filter used to find the DAI Elements.
187+
* @param createFunction - The Function used to create the new Private/Address Elements.
188+
* @returns A list of Create Action that will be added to the complex action.
189+
*/
190+
export function createActions(
191+
doiElement: Element,
192+
wizard: Element,
193+
ti: string,
194+
filter: string,
195+
createFunction: CreateFunction
196+
): Create[] {
197+
const actions: Create[] = [];
198+
const daiMonitorElements = doiElement.querySelectorAll(filter);
199+
if (daiMonitorElements.length > 0) {
200+
daiMonitorElements.forEach(daiElement => {
201+
const createActions = createFunction(daiElement, ti);
202+
actions.push(...createActions);
203+
204+
createActions.forEach(createAction => {
205+
const privateElement = <Element>createAction.new.element;
206+
Array.from(privateElement.querySelectorAll('Address'))
207+
.forEach(addressElement => {
208+
wizard.dispatchEvent(newWizardEvent(editAddressWizard(daiElement, addressElement)));
209+
});
210+
});
211+
});
212+
}
213+
return actions;
214+
}
215+
138216
/**
139217
* Enumeration stating the active view of the 104 plugin.
140218
*/

src/editors/protocol104/foundation/private.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ export const PROTOCOL_104_PRIVATE = "IEC_60870_5_104";
22
export const PROTOCOL_104_NS = "http://www.iec.ch/61850-80-1/2007/IEC_60870-5-104";
33
export const PROTOCOL_104_PREFIX = "IEC_60870_5_104";
44

5-
65
/**
76
* Will add the namespace of the 104 Protocol to the Root Element of the Document (SCL) as prefix to
87
* be used with all 104 elements (Address).

src/editors/protocol104/wizards/doi.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import '../../../wizard-textfield.js';
1414

1515
import {
1616
getCdcValue,
17+
getCtlModel,
1718
getFullPath,
1819
PRIVATE_TYPE_104
1920
} from "../foundation/foundation.js";
@@ -60,6 +61,16 @@ export function renderDOIWizard(doiElement: Element): TemplateResult[] {
6061
);
6162
}
6263

64+
const ctlModel = getCtlModel(doiElement);
65+
if (ctlModel !== null) {
66+
fields.push(html `<wizard-textfield
67+
label="ctlModel"
68+
.maybeValue=${ctlModel}
69+
disabled
70+
readonly>
71+
</wizard-textfield>`);
72+
}
73+
6374
return fields;
6475
}
6576

0 commit comments

Comments
 (0)