Skip to content

Commit 984652a

Browse files
feat(wizard/connectedap): auto create GSE and SMV elements (openscd#1019)
* feat(foundation): add MAC-Address and APPID generator * feat(wizards/connectedap): create GSE and SMV
1 parent 02ec714 commit 984652a

File tree

8 files changed

+1725
-186
lines changed

8 files changed

+1725
-186
lines changed

src/foundation/generators.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
const maxGseMacAddress = 0x010ccd0101ff;
2+
const minGseMacAddress = 0x010ccd010000;
3+
4+
const maxSmvMacAddress = 0x010ccd0401ff;
5+
const minSmvMacAddress = 0x010ccd040000;
6+
7+
function convertToMac(mac: number): string {
8+
const str = 0 + mac.toString(16).toUpperCase();
9+
const arr = str.match(/.{1,2}/g)!;
10+
return arr?.join('-');
11+
}
12+
13+
const gseMacRange = Array(maxGseMacAddress - minGseMacAddress)
14+
.fill(1)
15+
.map((_, i) => convertToMac(minGseMacAddress + i));
16+
17+
const smvMacRange = Array(maxSmvMacAddress - minSmvMacAddress)
18+
.fill(1)
19+
.map((_, i) => convertToMac(minSmvMacAddress + i));
20+
21+
/**
22+
* @param doc - project xml document
23+
* @param serviceType - SampledValueControl (SMV) or GSEControl (GSE)
24+
* @returns a function generating increasing unused `MAC-Address` within `doc` on subsequent invocations
25+
*/
26+
export function mACAddressGenerator(
27+
doc: XMLDocument,
28+
serviceType: 'SMV' | 'GSE'
29+
): () => string {
30+
const macs = new Set(
31+
Array.from(
32+
doc.querySelectorAll(`${serviceType} > Address > P[type="MAC-Address"]`)
33+
).map(macs => macs.textContent!)
34+
);
35+
36+
const range = serviceType === 'SMV' ? smvMacRange : gseMacRange;
37+
38+
return () => {
39+
const uniqueMAC = range.find(mac => !macs.has(mac));
40+
if (uniqueMAC) macs.add(uniqueMAC);
41+
return uniqueMAC ?? '';
42+
};
43+
}
44+
45+
const maxGseAppId = 0x3fff;
46+
const minGseAppId = 0x0000;
47+
48+
// APPID range for Type1A(Trip) GOOSE acc. IEC 61850-8-1
49+
const maxGseTripAppId = 0xbfff;
50+
const minGseTripAppId = 0x8000;
51+
52+
const maxSmvAppId = 0x7fff;
53+
const minSmvAppId = 0x4000;
54+
55+
const gseAppIdRange = Array(maxGseAppId - minGseAppId)
56+
.fill(1)
57+
.map((_, i) => (minGseAppId + i).toString(16).toUpperCase().padStart(4, '0'));
58+
59+
const gseTripAppIdRange = Array(maxGseTripAppId - minGseTripAppId)
60+
.fill(1)
61+
.map((_, i) =>
62+
(minGseTripAppId + i).toString(16).toUpperCase().padStart(4, '0')
63+
);
64+
65+
const smvAppIdRange = Array(maxSmvAppId - minSmvAppId)
66+
.fill(1)
67+
.map((_, i) => (minSmvAppId + i).toString(16).toUpperCase().padStart(4, '0'));
68+
69+
/**
70+
* @param doc - project xml document
71+
* @param serviceType - SampledValueControl (SMV) or GSEControl (GSE)
72+
* @param type1A - whether the GOOSE is a Trip GOOSE resulting in different APPID range - default false
73+
* @returns a function generating increasing unused `APPID` within `doc` on subsequent invocations
74+
*/
75+
export function appIdGenerator(
76+
doc: XMLDocument,
77+
serviceType: 'SMV' | 'GSE',
78+
type1A = false
79+
): () => string {
80+
const appIds = new Set(
81+
Array.from(
82+
doc.querySelectorAll(`${serviceType} > Address > P[type="APPID"]`)
83+
).map(appId => appId.textContent!)
84+
);
85+
86+
const range =
87+
serviceType === 'SMV'
88+
? smvAppIdRange
89+
: type1A
90+
? gseTripAppIdRange
91+
: gseAppIdRange;
92+
93+
return () => {
94+
const uniqueAppId = range.find(appId => !appIds.has(appId));
95+
if (uniqueAppId) appIds.add(uniqueAppId);
96+
return uniqueAppId ?? '';
97+
};
98+
}

0 commit comments

Comments
 (0)