Skip to content

Commit 2805261

Browse files
author
Dennis Labordus
authored
Merge pull request openscd#812 from openscd/104-handle-check
feat(104/Address): Added logic to handle Check Addresses.
2 parents 0ec10b5 + 53a3ccd commit 2805261

File tree

11 files changed

+216
-161
lines changed

11 files changed

+216
-161
lines changed

src/editors/protocol104/foundation/cdc.ts

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ export const supportedCdcTypes =
1212
export type SupportedCdcType = typeof supportedCdcTypes[number];
1313

1414
export type CreateFunction = (daiElement: Element, selectedTi: string, inverted: boolean) => Create[];
15+
export type CreateCheckFunction = (daiElement: Element, selectedTi: string) => Create[];
1516
export interface TiInformation {
1617
filter: string;
1718
create: CreateFunction;
19+
checkFilter?: string;
20+
checkCreate?: CreateCheckFunction;
1821
inverted?: boolean;
1922
}
2023

@@ -62,7 +65,9 @@ export const cdcProcessings: Record<
6265
control: {
6366
'63': {
6467
filter: ':scope > SDI[name="Oper"] > SDI[name="ctlVal"] > DAI[name="f"]',
65-
create: createAddressAction
68+
create: createAddressAction,
69+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
70+
checkCreate: createCheckAddressAction,
6671
},
6772
}
6873
},
@@ -85,7 +90,9 @@ export const cdcProcessings: Record<
8590
control: {
8691
'60': {
8792
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
88-
create: createAddressAction
93+
create: createAddressAction,
94+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
95+
checkCreate: createCheckAddressAction,
8996
},
9097
}
9198
},
@@ -109,7 +116,9 @@ export const cdcProcessings: Record<
109116
control: {
110117
'60': {
111118
filter: ':scope > SDI[name="Oper"] > DAI[name=“ctlVal”]',
112-
create: createAddressAction
119+
create: createAddressAction,
120+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
121+
checkCreate: createCheckAddressAction,
113122
},
114123
}
115124
},
@@ -132,13 +141,15 @@ export const cdcProcessings: Record<
132141
monitor: {
133142
'31': {
134143
filter: ':scope > DAI[name="stVal"]',
135-
create: createAddressAction
144+
create: createAddressAction,
136145
},
137146
},
138147
control: {
139148
'59': {
140149
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
141-
create: createAddressAction
150+
create: createAddressAction,
151+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
152+
checkCreate: createCheckAddressAction,
142153
},
143154
}
144155
},
@@ -161,7 +172,9 @@ export const cdcProcessings: Record<
161172
control: {
162173
'62': {
163174
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
164-
create: createAddressAction
175+
create: createAddressAction,
176+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
177+
checkCreate: createCheckAddressAction,
165178
},
166179
}
167180
},
@@ -202,7 +215,9 @@ export const cdcProcessings: Record<
202215
control: {
203216
'62': {
204217
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
205-
create: createAddressAction
218+
create: createAddressAction,
219+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
220+
checkCreate: createCheckAddressAction,
206221
},
207222
}
208223
},
@@ -239,7 +254,9 @@ export const cdcProcessings: Record<
239254
control: {
240255
'58': {
241256
filter: ':scope > SDI[name="Oper"] > DAI[name="ctlVal"]',
242-
create: createAddressAction
257+
create: createAddressAction,
258+
checkFilter: ':scope > SDI[name="Oper"] > DAI[name="Check"]',
259+
checkCreate: createCheckAddressAction,
243260
},
244261
}
245262
},
@@ -283,3 +300,23 @@ function createAddressAction(daiElement: Element, ti: string, inverted: boolean)
283300
}
284301
return [{new: {parent: daiElement, element: privateElement}}];
285302
}
303+
304+
305+
/**
306+
* Create a new SCL Private element and add 104 Address element(s) below this.
307+
* Set the attribute value of 'ti' to the passed ti value.
308+
*
309+
* @param daiElement - The DAI Element to use to set namespace on the root element and create new elements.
310+
* @param ti - The value to be set on the attribute 'ti'.
311+
*/
312+
function createCheckAddressAction(daiElement: Element, ti: string): Create[] {
313+
addPrefixAndNamespaceToDocument(daiElement);
314+
315+
const privateElement = createPrivateElement(daiElement);
316+
let addressElement = createPrivateAddress(daiElement, privateElement, ti);
317+
addressElement.setAttribute('check', 'interlocking');
318+
addressElement = createPrivateAddress(daiElement, privateElement, ti);
319+
addressElement.setAttribute('check', 'synchrocheck');
320+
321+
return [{new: {parent: daiElement, element: privateElement}}];
322+
}

src/editors/protocol104/foundation/foundation.ts

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
newWizardEvent
66
} from "../../../foundation.js";
77
import { editAddressWizard } from "../wizards/address.js";
8-
import {CreateFunction, TiInformation} from "./cdc.js";
8+
import { TiInformation } from "./cdc.js";
99

1010
export const PRIVATE_TYPE_104 = "IEC_60870_5_104";
1111

@@ -101,20 +101,6 @@ export function get104DetailsLine(address: Element): string {
101101
.join(', ');
102102
}
103103

104-
/**
105-
* Indicates if the combination cdc/ti should handle/process the attribute "expected" of the Address Element.
106-
*
107-
* @param cdc - The Common Data Class.
108-
* @param ti - The TI Value.
109-
* @returns true, if the combination should handle/process the attribute "expected".
110-
*/
111-
export function hasExpectedValueField(cdc: string, ti: string): boolean {
112-
return (cdc === 'ENC' && ['30', '45', '58'].includes(ti))
113-
|| (cdc === 'ENG' && ['45', '58'].includes(ti))
114-
|| (cdc === 'ENS' && ti === '30')
115-
|| (cdc === 'INS' && ti === '30');
116-
}
117-
118104
/**
119105
* Indicates if the combination cdc/ti should handle/process the attribute "unitMultiplier" of the Address Element.
120106
*
@@ -195,9 +181,9 @@ export function createActions(
195181
tiInformation: TiInformation
196182
): Create[] {
197183
const actions: Create[] = [];
198-
const daiMonitorElements = doiElement.querySelectorAll(tiInformation.filter);
199-
if (daiMonitorElements.length > 0) {
200-
daiMonitorElements.forEach(daiElement => {
184+
const daiElements = doiElement.querySelectorAll(tiInformation.filter);
185+
if (daiElements.length > 0) {
186+
daiElements.forEach(daiElement => {
201187
const createActions = tiInformation.create(daiElement, ti,
202188
(tiInformation.inverted ? inverted : false) // If the TI Allows it and the Engineer selected it, true will be passed.
203189
);
@@ -207,14 +193,54 @@ export function createActions(
207193
const privateElement = <Element>createAction.new.element;
208194
Array.from(privateElement.querySelectorAll('Address'))
209195
.forEach(addressElement => {
210-
wizard.dispatchEvent(newWizardEvent(editAddressWizard(daiElement, addressElement)));
196+
wizard.dispatchEvent(newWizardEvent(() => editAddressWizard(daiElement, addressElement)));
211197
});
212198
});
213199
});
214200
}
215201
return actions;
216202
}
217203

204+
/**
205+
* Create a list of Create Actions using the parameters passed. First search for the DAI Elements [name="Check"].
206+
* Next create the action and add it to this list, also start the Edit Address Element wizard for all Address Elements
207+
* created.
208+
*
209+
* @param doiElement - The DOI Element.
210+
* @param wizard - The Wizard to dispatch the Open Wizard event on.
211+
* @param ti - The TI Value set on the new Address Elements.
212+
* @param tiInformation - Information about how to create the Address Elements for the passed TI.
213+
* @returns A list of Create Action that will be added to the complex action.
214+
*/
215+
export function createCheckActions(
216+
doiElement: Element,
217+
wizard: Element,
218+
ti: string,
219+
tiInformation: TiInformation
220+
): Create[] {
221+
const actions: Create[] = [];
222+
if (tiInformation.checkFilter) {
223+
const daiElements = doiElement.querySelectorAll(tiInformation.checkFilter);
224+
if (daiElements.length > 0) {
225+
daiElements.forEach(daiElement => {
226+
if (tiInformation.checkCreate) {
227+
const createActions = tiInformation.checkCreate(daiElement, ti);
228+
actions.push(...createActions);
229+
230+
createActions.forEach(createAction => {
231+
const privateElement = <Element>createAction.new.element;
232+
Array.from(privateElement.querySelectorAll('Address'))
233+
.forEach(addressElement => {
234+
wizard.dispatchEvent(newWizardEvent(() => editAddressWizard(daiElement, addressElement)));
235+
});
236+
});
237+
}
238+
});
239+
}
240+
}
241+
return actions;
242+
}
243+
218244
/**
219245
* Enumeration stating the active view of the 104 plugin.
220246
*/

src/editors/protocol104/wizards/address.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import '../../../wizard-select.js';
2222
import {
2323
getCdcValue,
2424
getFullPath,
25-
hasExpectedValueField,
2625
hasScaleFields,
2726
hasUnitMultiplierField
2827
} from "../foundation/foundation.js";
@@ -39,10 +38,6 @@ export function updateValue(
3938

4039
const casdu = getValue(inputs.find(i => i.label === 'casdu')!)!;
4140
const ioa = getValue(inputs.find(i => i.label === 'ioa')!);
42-
const expectedValue =
43-
( hasExpectedValueField(cdc, ti)
44-
? getValue(inputs.find(i => i.label === 'expectedValue')!)
45-
: null);
4641
const unitMultiplier =
4742
( hasUnitMultiplierField(cdc, ti)
4843
? getValue(inputs.find(i => i.label === 'unitMultiplier')!)
@@ -59,7 +54,6 @@ export function updateValue(
5954
if (
6055
casdu === addressElement.getAttribute('casdu') &&
6156
ioa === addressElement.getAttribute('ioa') &&
62-
expectedValue === addressElement.getAttribute('expectedValue') &&
6357
unitMultiplier === addressElement.getAttribute('unitMultiplier') &&
6458
scaleMultiplier === addressElement.getAttribute('scaleMultiplier') &&
6559
scaleOffset === addressElement.getAttribute('scaleOffset')
@@ -71,7 +65,6 @@ export function updateValue(
7165
{
7266
casdu,
7367
ioa,
74-
expectedValue,
7568
unitMultiplier,
7669
scaleMultiplier,
7770
scaleOffset,
@@ -141,17 +134,6 @@ export function renderDAIWizard(
141134
</wizard-textfield>`,
142135
];
143136

144-
if (hasExpectedValueField(cdc, ti)) {
145-
fields.push(html `
146-
<wizard-textfield
147-
label="expectedValue"
148-
.maybeValue="${addressElement.getAttribute('expectedValue')}"
149-
helper="${translate('protocol104.wizard.expectedValueHelper')}"
150-
pattern="${patterns.integer}"
151-
nullable>
152-
</wizard-textfield>`);
153-
}
154-
155137
if (hasUnitMultiplierField(cdc, ti)) {
156138
const allowedMultipliers = ["m", "k", "M", "mu", "y", "z", "a",
157139
"f", "p", "n", "c", "d", "da", "h", "G", "T", "P", "E", "Z", "Y"];
@@ -192,6 +174,16 @@ export function renderDAIWizard(
192174
</wizard-textfield>`);
193175
}
194176

177+
if (addressElement.hasAttribute('expectedValue')) {
178+
fields.push(html `
179+
<wizard-textfield
180+
label="expectedValue"
181+
.maybeValue="${addressElement.getAttribute('expectedValue')}"
182+
disabled
183+
readonly>
184+
</wizard-textfield>`);
185+
}
186+
195187
if (addressElement.hasAttribute('inverted')) {
196188
fields.push(html `
197189
<wizard-textfield

0 commit comments

Comments
 (0)