nodalis-compiler 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -0
- package/package.json +59 -0
- package/src/compilers/CPPCompiler.js +272 -0
- package/src/compilers/Compiler.js +108 -0
- package/src/compilers/JSCompiler.js +293 -0
- package/src/compilers/iec-parser/parser.js +4254 -0
- package/src/compilers/st-parser/expressionConverter.js +155 -0
- package/src/compilers/st-parser/gcctranspiler.js +237 -0
- package/src/compilers/st-parser/jstranspiler.js +254 -0
- package/src/compilers/st-parser/parser.js +367 -0
- package/src/compilers/st-parser/tokenizer.js +78 -0
- package/src/compilers/support/generic/json.hpp +25526 -0
- package/src/compilers/support/generic/modbus.cpp +378 -0
- package/src/compilers/support/generic/modbus.h +124 -0
- package/src/compilers/support/generic/nodalis.cpp +421 -0
- package/src/compilers/support/generic/nodalis.h +798 -0
- package/src/compilers/support/generic/opcua.cpp +267 -0
- package/src/compilers/support/generic/opcua.h +50 -0
- package/src/compilers/support/generic/open62541.c +151897 -0
- package/src/compilers/support/generic/open62541.h +50357 -0
- package/src/compilers/support/jint/nodalis/Nodalis.sln +28 -0
- package/src/compilers/support/jint/nodalis/NodalisEngine/ModbusClient.cs +200 -0
- package/src/compilers/support/jint/nodalis/NodalisEngine/NodalisEngine.cs +817 -0
- package/src/compilers/support/jint/nodalis/NodalisEngine/NodalisEngine.csproj +16 -0
- package/src/compilers/support/jint/nodalis/NodalisEngine/OPCClient.cs +172 -0
- package/src/compilers/support/jint/nodalis/NodalisEngine/OPCServer.cs +275 -0
- package/src/compilers/support/jint/nodalis/NodalisPLC/NodalisPLC.csproj +19 -0
- package/src/compilers/support/jint/nodalis/NodalisPLC/Program.cs +197 -0
- package/src/compilers/support/jint/nodalis/NodalisPLC/bootstrap.bat +5 -0
- package/src/compilers/support/jint/nodalis/NodalisPLC/bootstrap.sh +5 -0
- package/src/compilers/support/jint/nodalis/build.bat +25 -0
- package/src/compilers/support/jint/nodalis/build.sh +31 -0
- package/src/compilers/support/nodejs/IOClient.js +110 -0
- package/src/compilers/support/nodejs/modbus.js +115 -0
- package/src/compilers/support/nodejs/nodalis.js +662 -0
- package/src/compilers/support/nodejs/opcua.js +194 -0
- package/src/nodalis.js +174 -0
|
@@ -0,0 +1,4254 @@
|
|
|
1
|
+
/* eslint-disable curly */
|
|
2
|
+
/* eslint-disable eqeqeq */
|
|
3
|
+
// Copyright [2025] Nathan Skipper
|
|
4
|
+
//
|
|
5
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
// you may not use this file except in compliance with the License.
|
|
7
|
+
// You may obtain a copy of the License at
|
|
8
|
+
//
|
|
9
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
//
|
|
11
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
// See the License for the specific language governing permissions and
|
|
15
|
+
// limitations under the License.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @description IEC Project Parser
|
|
20
|
+
* @author Nathan Skipper, MTI
|
|
21
|
+
* @version 1.0.2
|
|
22
|
+
* @copyright Apache 2.0
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {DOMParser} from "xmldom";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Tests whether an object value is null or undefined.
|
|
29
|
+
* @param {Object} obj
|
|
30
|
+
* @returns Returns True of the object is valid, or false if it is null or undefined.
|
|
31
|
+
*/
|
|
32
|
+
function isValid(obj){
|
|
33
|
+
return obj !== null && typeof obj !== "undefined";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Determines whether the value is a primitive type.
|
|
38
|
+
* @param {*} val The value to evaluate.
|
|
39
|
+
* @returns {boolean} Returns true if the value is a primitive type.
|
|
40
|
+
*/
|
|
41
|
+
function isPrimitive(val) {
|
|
42
|
+
return (
|
|
43
|
+
val === null ||
|
|
44
|
+
typeof val === 'string' ||
|
|
45
|
+
typeof val === 'number' ||
|
|
46
|
+
typeof val === 'boolean' ||
|
|
47
|
+
typeof val === 'undefined'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Determines whether the value is an array.
|
|
53
|
+
* @param {*} val The value to evaluate.
|
|
54
|
+
* @returns {boolean} returns true if the value is an array.
|
|
55
|
+
*/
|
|
56
|
+
function isArray(val) {
|
|
57
|
+
return Array.isArray(val);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function forEachElem(array, action){
|
|
61
|
+
for(var x = 0; x < array.length; x++){
|
|
62
|
+
action(array[x]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Evaluates whether a value is an object.
|
|
68
|
+
* @param {*} val The value to evaluate.
|
|
69
|
+
* @returns {boolean} returns true if the value is an object.
|
|
70
|
+
*/
|
|
71
|
+
function isObject(val) {
|
|
72
|
+
return typeof val === 'object' && val !== null && !isArray(val);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Creates a new SVG element based on the SVG provided.
|
|
76
|
+
* @param {string} htmlString The svg code to use in generating a new element. Note: the svg code must be wrapped in a containing element, such as a "g".
|
|
77
|
+
* @param {boolean} includeSVG Indicates whether to include a containing SVG around the created element.
|
|
78
|
+
* @returns {SVGElement} Returns a new SVG element.
|
|
79
|
+
*/
|
|
80
|
+
function createElementFromSVG(htmlString, includeSVG = false) {
|
|
81
|
+
const doc = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
82
|
+
doc.innerHTML = htmlString.trim();
|
|
83
|
+
|
|
84
|
+
return includeSVG ? doc.cloneNode(true) : doc.firstChild.cloneNode(true);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Provides a new GUID.
|
|
89
|
+
* @returns {string} Returns a GUID string.
|
|
90
|
+
*/
|
|
91
|
+
function generateGUID() {
|
|
92
|
+
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
93
|
+
const r = Math.random() * 16 | 0;
|
|
94
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8); // y is 8, 9, A, or B
|
|
95
|
+
return v.toString(16);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Creates a timestamp string of the current date and time.
|
|
101
|
+
* @returns {string} Returns a string of the current date and time in yyyyMMddHHmmss format.
|
|
102
|
+
*/
|
|
103
|
+
function formatTimestamp() {
|
|
104
|
+
const now = new Date(Date.now());
|
|
105
|
+
|
|
106
|
+
const yyyy = now.getFullYear();
|
|
107
|
+
const MM = String(now.getMonth() + 1).padStart(2, '0'); // Months are zero-based
|
|
108
|
+
const dd = String(now.getDate()).padStart(2, '0');
|
|
109
|
+
const HH = String(now.getHours()).padStart(2, '0');
|
|
110
|
+
const mm = String(now.getMinutes()).padStart(2, '0');
|
|
111
|
+
const ss = String(now.getSeconds()).padStart(2, '0');
|
|
112
|
+
|
|
113
|
+
return `${yyyy}${MM}${dd}${HH}${mm}${ss}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* An abstract class which will provide definition for serializing any inheriting class
|
|
119
|
+
* into json or from json. The inheriting class must extend the "TypeMap" property defined
|
|
120
|
+
* by this class to provide types for the properties of the class. Primitive types must be
|
|
121
|
+
* assigned default values instead of the class name of the type. For example, a property
|
|
122
|
+
* that has is a number should be "IntProperty": 0.
|
|
123
|
+
*/
|
|
124
|
+
export class Serializable{
|
|
125
|
+
constructor(){
|
|
126
|
+
this.TypeMap = {};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Converts this object to a json string based on the defined TypeMap.
|
|
131
|
+
* @returns {string} returns the json string representing this object.
|
|
132
|
+
*/
|
|
133
|
+
toJSON() {
|
|
134
|
+
const obj = {};
|
|
135
|
+
for (const key in this.TypeMap) {
|
|
136
|
+
if(this.hasOwnProperty(key)){
|
|
137
|
+
var value = this[key];
|
|
138
|
+
if (isPrimitive(value)) {
|
|
139
|
+
obj[key] = value;
|
|
140
|
+
} else if (isArray(value)) {
|
|
141
|
+
obj[key] = value.map(item =>
|
|
142
|
+
isPrimitive(item) ? item : item?.toJSON?.() ?? item
|
|
143
|
+
);
|
|
144
|
+
} else if (isObject(value)) {
|
|
145
|
+
obj[key] = value?.toJSON?.() ?? value;
|
|
146
|
+
} else {
|
|
147
|
+
obj[key] = value; // fallback
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
}
|
|
152
|
+
return JSON.stringify(obj);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Populates the object with the values of the json string, based on the TypeMap definition.
|
|
157
|
+
* @param {string} json The json string from which to populate the properties of the object.
|
|
158
|
+
* @param {Object?} parent The parent to add to this object, if it has a Parent property.
|
|
159
|
+
* @returns {Object} Returns the object after populating its properties.
|
|
160
|
+
*/
|
|
161
|
+
fromJSON(json, parent){
|
|
162
|
+
var jsonObj = JSON.parse(json);
|
|
163
|
+
for (const [key, value] of Object.entries(jsonObj)) {
|
|
164
|
+
const Type = this.TypeMap[key];
|
|
165
|
+
|
|
166
|
+
if (isValid(value)) {
|
|
167
|
+
if (Array.isArray(value)) {
|
|
168
|
+
this[key] = value.map(item => {
|
|
169
|
+
if (isPrimitive(item)) {
|
|
170
|
+
return item;
|
|
171
|
+
} else if (Type && typeof Type === 'function') {
|
|
172
|
+
const instance = new Type();
|
|
173
|
+
return instance.fromJSON(item, this);
|
|
174
|
+
} else {
|
|
175
|
+
return item;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
} else if (isPrimitive(value)) {
|
|
179
|
+
this[key] = value;
|
|
180
|
+
} else if (Type && typeof Type === 'function') {
|
|
181
|
+
const instance = new Type();
|
|
182
|
+
this[key] = instance.fromJSON(value, this);
|
|
183
|
+
} else {
|
|
184
|
+
this[key] = value;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if(this.hasOwnProperty("Parent")){
|
|
189
|
+
this.Parent = parent;
|
|
190
|
+
}
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The Project class represents the XML data for a Project element in the IEC file.
|
|
197
|
+
*/
|
|
198
|
+
export class Project extends Serializable {
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Constructs a new Project object based on the child elements.
|
|
202
|
+
* @param {FileHeader?} fileHeader Can be undefined, but if provided, sets the FileHeader property to what is provided.
|
|
203
|
+
* @param {ContentHeader?} contentHeader Can be undefined, but if provided, sets the ContentHeader property to what is provided.
|
|
204
|
+
* @param {Types?} types Can be undefined, but if provided, sets the Types property.
|
|
205
|
+
* @param {Instances?} instances Not used currently.
|
|
206
|
+
*/
|
|
207
|
+
constructor(fileHeader, contentHeader, types, instances, mappingTable) {
|
|
208
|
+
super();
|
|
209
|
+
this.TypeMap = {
|
|
210
|
+
"FileHeader": FileHeader,
|
|
211
|
+
"ContentHeader": ContentHeader,
|
|
212
|
+
"Types": Types,
|
|
213
|
+
"Instances": Instances,
|
|
214
|
+
"MappingTable": MappingTable
|
|
215
|
+
};
|
|
216
|
+
/**@type {FileHeader} */
|
|
217
|
+
this.FileHeader = new FileHeader();
|
|
218
|
+
/**@type {ContentHeader} */
|
|
219
|
+
this.ContentHeader = new ContentHeader();
|
|
220
|
+
/**@type {Types} */
|
|
221
|
+
this.Types = new Types();
|
|
222
|
+
/**@type {Instances} */
|
|
223
|
+
this.Instances = new Instances();
|
|
224
|
+
this.MappingTable = new MappingTable();
|
|
225
|
+
if(isValid(fileHeader)) {this.FileHeader = fileHeader;}
|
|
226
|
+
if(isValid(contentHeader)) {this.ContentHeader = contentHeader;}
|
|
227
|
+
if(isValid(types)) {this.Types = types;}
|
|
228
|
+
|
|
229
|
+
if(isValid(instances)) this.Instances = instances;
|
|
230
|
+
if(isValid(mappingTable)) this.MappingTable = mappingTable;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Parses a string of xml representing the complete project file and sets the properties of a new Project object based on it.
|
|
235
|
+
* @param {String} xml A string containing the xml to parse.
|
|
236
|
+
* @returns A new Project object.
|
|
237
|
+
*/
|
|
238
|
+
static fromXML(xml) {
|
|
239
|
+
const parser = new DOMParser();
|
|
240
|
+
const xmlDoc = parser.parseFromString(xml, "text/xml");
|
|
241
|
+
|
|
242
|
+
const proj = new Project(
|
|
243
|
+
FileHeader.fromXML(xmlDoc.getElementsByTagName("FileHeader")[0]),
|
|
244
|
+
ContentHeader.fromXML(xmlDoc.getElementsByTagName("ContentHeader")[0]),
|
|
245
|
+
null,
|
|
246
|
+
null
|
|
247
|
+
);
|
|
248
|
+
proj.Types = Types.fromXML(xmlDoc.getElementsByTagName("Types")[0], proj);
|
|
249
|
+
proj.Instances = Instances.fromXML(xmlDoc.getElementsByTagName("Instances")[0], proj);
|
|
250
|
+
proj.MappingTable = MappingTable.fromXML(xmlDoc.getElementsByTagName("MappingTable")[0], proj);
|
|
251
|
+
if(!isValid(proj.Types)) proj.Types = new Types(null, proj);
|
|
252
|
+
if(!isValid(proj.Instances)) proj.Instances = new Instances(null, proj);
|
|
253
|
+
if(!isValid(proj.MappingTable)) proj.MappingTable = new MappingTable();
|
|
254
|
+
return proj;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Formats the object as an XML string.
|
|
259
|
+
* @returns A string representation of the Project object.
|
|
260
|
+
*/
|
|
261
|
+
toXML() {
|
|
262
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
263
|
+
<Project xmlns="www.iec.ch/public/TC65SC65BWG7TF10"
|
|
264
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
265
|
+
xsi:schemaLocation="www.iec.ch/public/TC65SC65BWG7TF10 IEC61131_10_Ed1_0.xsd"
|
|
266
|
+
schemaVersion="1.0">
|
|
267
|
+
${this.FileHeader.toXML()}
|
|
268
|
+
${this.ContentHeader.toXML()}
|
|
269
|
+
${this.Types.toXML()}
|
|
270
|
+
${this.Instances.toXML()}
|
|
271
|
+
${this.MappingTable.toXML()}
|
|
272
|
+
</Project>`;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
getAllPrograms(){
|
|
276
|
+
var programs = [];
|
|
277
|
+
try{
|
|
278
|
+
forEachElem(this.Types.GlobalNamespace.NamespaceDecl.Programs,
|
|
279
|
+
(p) => {
|
|
280
|
+
programs.push(p);
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
catch(e){
|
|
285
|
+
console.error(e);
|
|
286
|
+
}
|
|
287
|
+
return programs;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
getAllFunctionBlocks(){
|
|
291
|
+
var fbs = [];
|
|
292
|
+
try{
|
|
293
|
+
forEachElem(this.Types.GlobalNamespace.NamespaceDecl.FunctionBlocks,
|
|
294
|
+
(p) => {
|
|
295
|
+
fbs.push(p);
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
catch(e){
|
|
300
|
+
console.error(e);
|
|
301
|
+
}
|
|
302
|
+
return fbs;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Finds the containing Project for the child.
|
|
307
|
+
* @param {FbdObject|LdObject|Rung|Network|BodyContent|MainBody|Program|FunctionBlock|NamespaceDecl|GlobalNamespace|Types} child The child object from which to find the containing Project.
|
|
308
|
+
* @returns Returns the Project for the child, or null if not found.
|
|
309
|
+
*/
|
|
310
|
+
static getProject(child){
|
|
311
|
+
return Project.getParentOfType(child, Project);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Finds the containing parent for the child that matches the specified type.
|
|
316
|
+
* @param {FbdObject|LdObject|Rung|Network|BodyContent|MainBody|Program|FunctionBlock|NamespaceDecl|GlobalNamespace|Types} child The child object from which to find the containing Project.
|
|
317
|
+
* @param {class} type The class type to search for.
|
|
318
|
+
* @returns Returns the parent object of the specified type for the child, or null if not found.
|
|
319
|
+
*/
|
|
320
|
+
static getParentOfType(child, type){
|
|
321
|
+
var ret = null;
|
|
322
|
+
try{
|
|
323
|
+
ret = child;
|
|
324
|
+
while(isValid(ret.Parent) && !(ret instanceof type)){
|
|
325
|
+
ret = ret.Parent;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
}
|
|
329
|
+
catch(e){
|
|
330
|
+
console.error(e);
|
|
331
|
+
}
|
|
332
|
+
return ret;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Represents the FileHeader element of an IEC file.
|
|
338
|
+
*/
|
|
339
|
+
export class FileHeader extends Serializable {
|
|
340
|
+
/**
|
|
341
|
+
* Instantiates a new FileHeader object based on provided information.
|
|
342
|
+
* @param {string?} companyName Can be undefined, but if provided, sets the companyName property.
|
|
343
|
+
* @param {string?} companyURL Can be undefined, but if provided, sets the companyURL property.
|
|
344
|
+
* @param {string?} productName Can be undefined, but if provided, sets the productName property.
|
|
345
|
+
* @param {string?} productVersion Can be undefined, but if provided, sets the productVersion property.
|
|
346
|
+
* @param {strin?} productRelease Can be undefined, but if provided, sets the productRelease property.
|
|
347
|
+
*/
|
|
348
|
+
constructor(companyName, companyURL, productName, productVersion, productRelease) {
|
|
349
|
+
super();
|
|
350
|
+
this.TypeMap = {
|
|
351
|
+
"companyName": "",
|
|
352
|
+
"companyURL": "",
|
|
353
|
+
"productName": "",
|
|
354
|
+
"productVersion": "",
|
|
355
|
+
"productRelease": ""
|
|
356
|
+
};
|
|
357
|
+
this.companyName = "";
|
|
358
|
+
this.companyURL = "";
|
|
359
|
+
this.productName = "";
|
|
360
|
+
this.productVersion = "";
|
|
361
|
+
this.productRelease = "";
|
|
362
|
+
if(isValid(companyName)) {this.companyName = companyName;}
|
|
363
|
+
if(isValid(companyURL)) {this.companyURL = companyURL;}
|
|
364
|
+
if(isValid(productName)) {this.productName = productName;}
|
|
365
|
+
if(isValid(productVersion)) {this.productVersion = productVersion;}
|
|
366
|
+
if(isValid(productRelease)) {this.productRelease = productRelease;}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Creates a new FileHeader object based on an Element object representing the XML.
|
|
371
|
+
* @param {Element} xml The xml element to parse.
|
|
372
|
+
* @returns Returns a new FileHeader object.
|
|
373
|
+
*/
|
|
374
|
+
static fromXML(xml) {
|
|
375
|
+
if(!isValid(xml)) {return null;}
|
|
376
|
+
return new FileHeader(
|
|
377
|
+
xml.getAttribute("companyName"),
|
|
378
|
+
xml.getAttribute("companyURL"),
|
|
379
|
+
xml.getAttribute("productName"),
|
|
380
|
+
xml.getAttribute("productVersion"),
|
|
381
|
+
xml.getAttribute("productRelease")
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
*
|
|
387
|
+
* @returns Returns a string of XML representing the object.
|
|
388
|
+
*/
|
|
389
|
+
toXML() {
|
|
390
|
+
return `<FileHeader companyName="${this.companyName}" companyURL="${this.companyURL}"
|
|
391
|
+
productName="${this.productName}" productVersion="${this.productVersion}"
|
|
392
|
+
productRelease="${this.productRelease}"/>`;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Represents the ContentHeader element in an IEC project file.
|
|
398
|
+
*/
|
|
399
|
+
export class ContentHeader extends Serializable {
|
|
400
|
+
/**
|
|
401
|
+
* Instantiates a new ContentHeader based on properties provided.
|
|
402
|
+
* @param {string?} name Can be null or undefined.
|
|
403
|
+
* @param {string?} version Can be null or undefined.
|
|
404
|
+
* @param {string?} creationDateTime Can be null or undefined.
|
|
405
|
+
* @param {string?} modificationDateTime Can be null or undefined.
|
|
406
|
+
* @param {string?} organization Can be null or undefined.
|
|
407
|
+
* @param {string?} author Can be null or undefined.
|
|
408
|
+
* @param {string?} language Can be null or undefined.
|
|
409
|
+
*/
|
|
410
|
+
constructor(name, version, creationDateTime, modificationDateTime, organization, author, language) {
|
|
411
|
+
super();
|
|
412
|
+
this.TypeMap = {
|
|
413
|
+
"name": "",
|
|
414
|
+
"version": "",
|
|
415
|
+
"creationDateTime": "",
|
|
416
|
+
"modificationDateTime": "",
|
|
417
|
+
"organization": "",
|
|
418
|
+
"author": "",
|
|
419
|
+
"language": ""
|
|
420
|
+
};
|
|
421
|
+
this.Name = "New";
|
|
422
|
+
this.version = "1.0";
|
|
423
|
+
this.creationDateTime = Date.now().toString();
|
|
424
|
+
this.modificationDateTime = Date.now().toString();
|
|
425
|
+
this.organization = "";
|
|
426
|
+
this.author = "";
|
|
427
|
+
this.language = "En";
|
|
428
|
+
|
|
429
|
+
if(isValid(name)) {this.Name = name;}
|
|
430
|
+
if(isValid(version)) {this.version = version;}
|
|
431
|
+
if(isValid(creationDateTime)) {this.creationDateTime = creationDateTime;}
|
|
432
|
+
if(isValid(modificationDateTime)) {this.modificationDateTime = modificationDateTime;}
|
|
433
|
+
if(isValid(organization)) {this.organization = organization;}
|
|
434
|
+
if(isValid(author)) {this.author = author;}
|
|
435
|
+
if(isValid(language)) {this.language = language;}
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Creates a new ContentHeader object based on an XML element object.
|
|
439
|
+
* @param {Element} xml An Element object representing the XML.
|
|
440
|
+
* @returns A new ContentHeader object.
|
|
441
|
+
*/
|
|
442
|
+
static fromXML(xml) {
|
|
443
|
+
if(!isValid(xml)) {return null;}
|
|
444
|
+
return new ContentHeader(
|
|
445
|
+
xml.getAttribute("name"),
|
|
446
|
+
xml.getAttribute("version"),
|
|
447
|
+
xml.getAttribute("creationDateTime"),
|
|
448
|
+
xml.getAttribute("modificationDateTime"),
|
|
449
|
+
xml.getAttribute("organization"),
|
|
450
|
+
xml.getAttribute("author"),
|
|
451
|
+
xml.getAttribute("language"));
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
*
|
|
455
|
+
* @returns Returns an string of xml representing the object.
|
|
456
|
+
*/
|
|
457
|
+
toXML() {
|
|
458
|
+
return `<ContentHeader name="${this.Name}" version="${this.version}" creationDateTime="${this.creationDateTime}"
|
|
459
|
+
modificationDateTime="${this.modificationDateTime}" organization="${this.organization}" author="${this.author}" language="${this.language}">
|
|
460
|
+
</ContentHeader>`;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Defines the coordinate info for the IEC file. This provides scaling for the diagram types.
|
|
466
|
+
*/
|
|
467
|
+
export class CoordinateInfo extends Serializable{
|
|
468
|
+
/**
|
|
469
|
+
*
|
|
470
|
+
* @param {Scaling?} FbdScaling
|
|
471
|
+
* @param {Scaling?} LdScaling
|
|
472
|
+
* @param {Scaling?} SfcScaling
|
|
473
|
+
*/
|
|
474
|
+
constructor(FbdScaling, LdScaling, SfcScaling) {
|
|
475
|
+
super();
|
|
476
|
+
this.TypeMap = {
|
|
477
|
+
"FbdScaling": Scaling,
|
|
478
|
+
"LdScaling": Scaling,
|
|
479
|
+
"SfcScaling": Scaling
|
|
480
|
+
};
|
|
481
|
+
this.FbdScaling = new Scaling(1, 1);
|
|
482
|
+
this.LdScaling = new Scaling(1, 1);
|
|
483
|
+
this.SfcScaling = new Scaling(1, 1);
|
|
484
|
+
if(isValid(FbdScaling)) this.FbdScaling = FbdScaling;
|
|
485
|
+
if(isValid(LdScaling)) this.LdScaling = LdScaling;
|
|
486
|
+
if(isValid(SfcScaling)) this.SfcScaling = SfcScaling;
|
|
487
|
+
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Creates a new CoordinateInfo object based on an XML element.
|
|
492
|
+
* @param {Element} xml The XML element from which to get the object's properties.
|
|
493
|
+
* @returns {CoordinateInfo} Returns a new object based on the XML.
|
|
494
|
+
*/
|
|
495
|
+
static fromXML(xml) {
|
|
496
|
+
if(!isValid(xml)) {return null;}
|
|
497
|
+
return new CoordinateInfo(
|
|
498
|
+
Scaling.fromXML(xml.getElementsByTagName("FbdScaling")[0]),
|
|
499
|
+
Scaling.fromXML(xml.getElementsByTagName("LdScaling")[0]),
|
|
500
|
+
Scaling.fromXML(xml.getElementsByTagName("SfcScaling")[0])
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Creates an xml string representing the object.
|
|
506
|
+
* @returns {string} Returns the XML string representing the object.
|
|
507
|
+
*/
|
|
508
|
+
toXML() {
|
|
509
|
+
return `<CoordinateInfo>
|
|
510
|
+
${this.FbdScaling.toXML()}
|
|
511
|
+
${this.LdScaling.toXML()}
|
|
512
|
+
${this.SfcScaling.toXML()}
|
|
513
|
+
</CoordinateInfo>`;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Implements the scaling for an IEC file.
|
|
519
|
+
*/
|
|
520
|
+
export class Scaling extends Serializable{
|
|
521
|
+
/**
|
|
522
|
+
* Constructs a new Scaling object.
|
|
523
|
+
* @param {string?} x The x scale factor
|
|
524
|
+
* @param {string?} y The y scale factor.
|
|
525
|
+
*/
|
|
526
|
+
constructor(x, y) {
|
|
527
|
+
super();
|
|
528
|
+
this.TypeMap = {
|
|
529
|
+
"x": "",
|
|
530
|
+
"y": ""
|
|
531
|
+
};
|
|
532
|
+
this.x = "1";
|
|
533
|
+
this.y = "1";
|
|
534
|
+
if(isValid(x)) this.x = x;
|
|
535
|
+
if(isValid(y)) this.y = y;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Creates a new scaling object based on the xml element.
|
|
540
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
541
|
+
* @returns {Scaling} A new scaling object.
|
|
542
|
+
*/
|
|
543
|
+
static fromXML(xml) {
|
|
544
|
+
if(!isValid(xml)) {return null;}
|
|
545
|
+
return new Scaling(
|
|
546
|
+
xml.getAttribute("x"),
|
|
547
|
+
xml.getAttribute("y")
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Creates an xml string representing the object.
|
|
553
|
+
* @returns {string} An xml string representing the object.
|
|
554
|
+
*/
|
|
555
|
+
toXML() {
|
|
556
|
+
return `<Scaling x="${this.x}" y="${this.y}"/>`;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Represents the Types element in an IEC project file.
|
|
562
|
+
*/
|
|
563
|
+
export class Types extends Serializable{
|
|
564
|
+
/**
|
|
565
|
+
* Instantiates a new Types object.
|
|
566
|
+
* @param {GlobalNamespace?} globalNamespace Can be null or undefined.
|
|
567
|
+
* @param {Project?} parent The containing project.
|
|
568
|
+
*/
|
|
569
|
+
constructor(globalNamespace, parent) {
|
|
570
|
+
super();
|
|
571
|
+
this.TypeMap = {
|
|
572
|
+
"GlobalNameSpace": GlobalNamespace
|
|
573
|
+
};
|
|
574
|
+
this.GlobalNamespace = new GlobalNamespace();
|
|
575
|
+
this.Parent = null;
|
|
576
|
+
if(isValid(globalNamespace)) {this.GlobalNamespace = globalNamespace;}
|
|
577
|
+
if(isValid(parent)) this.Parent = parent;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Creates a new Types object based on an XML element.
|
|
581
|
+
* @param {Element} xml An element object representing the XML for the types.
|
|
582
|
+
* @param {Project} parent The containing project.
|
|
583
|
+
* @returns Returns a new Types object.
|
|
584
|
+
*/
|
|
585
|
+
static fromXML(xml, parent) {
|
|
586
|
+
if(!isValid(xml)) {return null;}
|
|
587
|
+
const type = new Types(null, parent);
|
|
588
|
+
const gns = GlobalNamespace.fromXML(xml.getElementsByTagName("GlobalNamespace")[0], type);
|
|
589
|
+
type.GlobalNamespace = gns;
|
|
590
|
+
return type;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
*
|
|
594
|
+
* @returns Returns a string representing the xml of this object.
|
|
595
|
+
*/
|
|
596
|
+
toXML() {
|
|
597
|
+
return `<Types>
|
|
598
|
+
${this.GlobalNamespace.toXML()}
|
|
599
|
+
</Types>`;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
toST(){
|
|
603
|
+
return this.GlobalNamespace.toST();
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Represents the GlobalNamespace element of the IEC project file.
|
|
609
|
+
*/
|
|
610
|
+
export class GlobalNamespace extends Serializable {
|
|
611
|
+
/**
|
|
612
|
+
* Constructs a new GlobalNamespace object.
|
|
613
|
+
* @param {NamespaceDecl?} namespaceDecl Can be null or undefined.
|
|
614
|
+
* @param {Types?} parent The containing object.
|
|
615
|
+
*/
|
|
616
|
+
constructor(namespaceDecl, parent) {
|
|
617
|
+
super();
|
|
618
|
+
this.TypeMap = {
|
|
619
|
+
"NamespaceDecl": NamespaceDecl
|
|
620
|
+
};
|
|
621
|
+
/**@type {NamespaceDecl} */
|
|
622
|
+
this.NamespaceDecl = new NamespaceDecl();
|
|
623
|
+
this.Parent = null;
|
|
624
|
+
if(isValid(namespaceDecl)) {this.NamespaceDecl = namespaceDecl;}
|
|
625
|
+
if(isValid(parent)) this.Parent = parent;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Creates a new GlobalNamespace object based on an XML element.
|
|
629
|
+
* @param {Element} xml An xml Element object from which to create the GlobalNamespace.
|
|
630
|
+
* @returns Returns a new GlobalNamespace object.
|
|
631
|
+
*/
|
|
632
|
+
static fromXML(xml, parent) {
|
|
633
|
+
if(!isValid(xml)) {return null;}
|
|
634
|
+
const gns = new GlobalNamespace(null , parent);
|
|
635
|
+
gns.NamespaceDecl = NamespaceDecl.fromXML(xml.getElementsByTagName("NamespaceDecl")[0], gns);
|
|
636
|
+
return gns;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
*
|
|
641
|
+
* @returns Returns a string of xml representing the object.
|
|
642
|
+
*/
|
|
643
|
+
toXML() {
|
|
644
|
+
return `<GlobalNamespace>
|
|
645
|
+
${this.NamespaceDecl.toXML()}
|
|
646
|
+
</GlobalNamespace>`;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
toST(){
|
|
650
|
+
return this.NamespaceDecl.toST();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Represents the NamespaceDecl element of an IEC project file.
|
|
656
|
+
*/
|
|
657
|
+
export class NamespaceDecl extends Serializable{
|
|
658
|
+
/**
|
|
659
|
+
* Instantiates a new NamespaceDecl object.
|
|
660
|
+
* @param {string?} name Can be null or undefined.
|
|
661
|
+
* @param {GlobalNamespace?} parent The containing object.
|
|
662
|
+
*/
|
|
663
|
+
constructor(name, parent) {
|
|
664
|
+
super();
|
|
665
|
+
this.TypeMap = {
|
|
666
|
+
"name": "",
|
|
667
|
+
"Programs": [],
|
|
668
|
+
"FunctionBlocks": []
|
|
669
|
+
};
|
|
670
|
+
/**
|
|
671
|
+
* @type {string}
|
|
672
|
+
*/
|
|
673
|
+
this.Name = "Default";
|
|
674
|
+
/**
|
|
675
|
+
* @type {Program[]}
|
|
676
|
+
*/
|
|
677
|
+
this.Programs = [];
|
|
678
|
+
/**
|
|
679
|
+
* @type {FunctionBlock[]}
|
|
680
|
+
*/
|
|
681
|
+
this.FunctionBlocks = [];
|
|
682
|
+
/**
|
|
683
|
+
* @type {GlobalNamespace}
|
|
684
|
+
*/
|
|
685
|
+
this.Parent = null;
|
|
686
|
+
if(isValid(name)) {this.Name = name;}
|
|
687
|
+
if(isValid(parent)) this.Parent = parent;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Creates a new NamespaceDecl object from the given xml element.
|
|
692
|
+
* @param {Element} xml The XML element to parse.
|
|
693
|
+
* @param {GlobalNamespace} parent The containing object.
|
|
694
|
+
* @returns instantiated NamespaceDecl object based on xml.
|
|
695
|
+
*/
|
|
696
|
+
static fromXML(xml, parent) {
|
|
697
|
+
if(!isValid(xml)) {return null;}
|
|
698
|
+
var ns = new NamespaceDecl(
|
|
699
|
+
xml.getAttribute("name"), parent
|
|
700
|
+
);
|
|
701
|
+
var xmlprogs = xml.getElementsByTagName("Program");
|
|
702
|
+
var xmlfb = xml.getElementsByTagName("FunctionBlock");
|
|
703
|
+
if(!isValid(ns.Programs)) {ns.Programs = [];}
|
|
704
|
+
if(!isValid(ns.FunctionBlocks)) {ns.FunctionBlocks = [];}
|
|
705
|
+
forEachElem(xmlprogs, (prog) => {
|
|
706
|
+
ns.Programs.push(Program.fromXML(prog, ns));
|
|
707
|
+
});
|
|
708
|
+
forEachElem(xmlfb, (fb) => {
|
|
709
|
+
ns.FunctionBlocks.push(FunctionBlock.fromXML(fb, ns));
|
|
710
|
+
});
|
|
711
|
+
return ns;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
*
|
|
715
|
+
* @returns Returns a string of xml representing the object.
|
|
716
|
+
*/
|
|
717
|
+
toXML() {
|
|
718
|
+
var progs = "";
|
|
719
|
+
var fbs = "";
|
|
720
|
+
forEachElem(this.Programs, (elem) => {
|
|
721
|
+
progs += elem.toXML();
|
|
722
|
+
});
|
|
723
|
+
forEachElem(this.FunctionBlocks, (elem) => {
|
|
724
|
+
fbs += elem.toXML();
|
|
725
|
+
});
|
|
726
|
+
return `<NamespaceDecl name="${this.Name}">
|
|
727
|
+
${progs}
|
|
728
|
+
${fbs}
|
|
729
|
+
</NamespaceDecl>`;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Converts all elements of this namespace to structured text.
|
|
734
|
+
* @returns {string} A string representing the structured text.
|
|
735
|
+
*/
|
|
736
|
+
toST(){
|
|
737
|
+
var blocks = "";
|
|
738
|
+
var programs = "";
|
|
739
|
+
forEachElem(this.FunctionBlocks, (f) => blocks += f.toST() + "\n");
|
|
740
|
+
forEachElem(this.Programs, (p) => programs += p.toST() + "\n");
|
|
741
|
+
return `${blocks}
|
|
742
|
+
${programs}`;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Adds options to a given element for all variable types defined within this namespace, or as a standard function block.
|
|
747
|
+
* @param {HTMLElement} elem The element to add the options to.
|
|
748
|
+
*/
|
|
749
|
+
addVariableTypes(elem){
|
|
750
|
+
try{
|
|
751
|
+
forEachElem(FbdObject.StandardBlocks, sb => {
|
|
752
|
+
var opt = document.createElement("option");
|
|
753
|
+
opt.value = sb.TypeName;
|
|
754
|
+
opt.textContent = sb.TypeName;
|
|
755
|
+
elem.appendChild(opt);
|
|
756
|
+
});
|
|
757
|
+
forEachElem(this.FunctionBlocks, sb => {
|
|
758
|
+
var opt = document.createElement("option");
|
|
759
|
+
opt.value = sb.Name;
|
|
760
|
+
opt.textContent = sb.Name;
|
|
761
|
+
elem.appendChild(opt);
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
catch(e){
|
|
765
|
+
console.error(e);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Represents the instances list for the IEC file.
|
|
772
|
+
*/
|
|
773
|
+
export class Instances extends Serializable {
|
|
774
|
+
/**
|
|
775
|
+
* Constructs a new Instances object.
|
|
776
|
+
* @param {Configuration[]?} configurations The configurations for the instances.
|
|
777
|
+
* @param {Project?} parent The parent that owns this object.
|
|
778
|
+
*/
|
|
779
|
+
constructor(configurations, parent) {
|
|
780
|
+
super();
|
|
781
|
+
this.TypeMap = {
|
|
782
|
+
"Configurations": []
|
|
783
|
+
};
|
|
784
|
+
this.Configurations = [];
|
|
785
|
+
this.Parent = null;
|
|
786
|
+
if(isValid(configurations)) this.Configurations = configurations;
|
|
787
|
+
if(isValid(parent)) this.Parent = parent;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Creates an object from an xml element.
|
|
792
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
793
|
+
* @param {Project?} parent The parent that owns this object.
|
|
794
|
+
* @returns {Instances} A new object.
|
|
795
|
+
*/
|
|
796
|
+
static fromXML(xml, parent) {
|
|
797
|
+
if(!isValid(xml)) {return null;}
|
|
798
|
+
var obj = new Instances();
|
|
799
|
+
if(isValid(parent)) obj.Parent = parent;
|
|
800
|
+
var configs = xml.getElementsByTagName("Configuration");
|
|
801
|
+
forEachElem(configs, (c) => {
|
|
802
|
+
obj.Configurations.push(Configuration.fromXML(xml, obj));
|
|
803
|
+
});
|
|
804
|
+
return obj;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Creates an xml string representing the object.
|
|
809
|
+
* @returns {string} An xml string representing the object.
|
|
810
|
+
*/
|
|
811
|
+
toXML() {
|
|
812
|
+
var configs = "";
|
|
813
|
+
forEachElem(this.Configurations, (c) => {
|
|
814
|
+
configs += c.toXML() + "\n";
|
|
815
|
+
});
|
|
816
|
+
return `<Instances>
|
|
817
|
+
${configs}
|
|
818
|
+
</Instances>`;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* A configuration for the IEC file.
|
|
825
|
+
*/
|
|
826
|
+
export class Configuration extends Serializable{
|
|
827
|
+
/**
|
|
828
|
+
* Constructs a new configuration object.
|
|
829
|
+
* @param {string?} name The name of the configuration.
|
|
830
|
+
* @param {Resource[]?} resources An array of resources.
|
|
831
|
+
* @param {Instances?} parent The parent that owns this object.
|
|
832
|
+
*/
|
|
833
|
+
constructor(name, resources, parent) {
|
|
834
|
+
super();
|
|
835
|
+
this.TypeMap = {
|
|
836
|
+
"Name": "",
|
|
837
|
+
"Resources": []
|
|
838
|
+
};
|
|
839
|
+
this.Parent = null;
|
|
840
|
+
this.Resources = [];
|
|
841
|
+
this.Name = "Main";
|
|
842
|
+
if(isValid(parent)) this.Parent = parent;
|
|
843
|
+
if(isValid(name)) this.Name = name;
|
|
844
|
+
if(isValid(resources)) this.Resources = resources;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Creates a new Configuration object based on the XML element.
|
|
849
|
+
* @param {Element} xml The xml element to create the object from.
|
|
850
|
+
* @param {Instances} parent The parent that owns this object.
|
|
851
|
+
* @returns {Configuration} Returns the configuration object.
|
|
852
|
+
*/
|
|
853
|
+
static fromXML(xml, parent) {
|
|
854
|
+
if(!isValid(xml)) {return null;}
|
|
855
|
+
var obj = new Configuration(xml.getAttribute("name"),null, parent);
|
|
856
|
+
forEachElem(xml.getElementsByTagName("Resource"), (r) => {
|
|
857
|
+
obj.Resources.push(Resource.fromXML(r, obj));
|
|
858
|
+
});
|
|
859
|
+
return obj;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Creates an xml string representing the object.
|
|
864
|
+
* @returns {string} An xml string representing the object.
|
|
865
|
+
*/
|
|
866
|
+
toXML() {
|
|
867
|
+
var resources = "";
|
|
868
|
+
forEachElem(this.Resources, (r) => {
|
|
869
|
+
resources += r.toXML() + "\n";
|
|
870
|
+
});
|
|
871
|
+
return `<Configuration name="${this.Name}">
|
|
872
|
+
${resources}
|
|
873
|
+
</Configuration>`;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Represents a Resource element in an IEC file.
|
|
880
|
+
*/
|
|
881
|
+
export class Resource extends Serializable{
|
|
882
|
+
/**
|
|
883
|
+
* Constructs a new resource object.
|
|
884
|
+
* @param {string?} name The name of the resource.
|
|
885
|
+
* @param {string?} resourceTypeName The type of the resource.
|
|
886
|
+
* @param {GlobalVars?} globalVars A GlobalVars objects.
|
|
887
|
+
* @param {Task[]?} tasks An array of tasks.
|
|
888
|
+
* @param {ProgramInstance[]?} programInstances An array of program instances.
|
|
889
|
+
* @param {Configuration?} parent The parent that owns this object.
|
|
890
|
+
*/
|
|
891
|
+
constructor(name, resourceTypeName, globalVars, tasks, programInstances, parent) {
|
|
892
|
+
super();
|
|
893
|
+
this.TypeMap = {
|
|
894
|
+
"Name": "",
|
|
895
|
+
"ResourceTypeName": "",
|
|
896
|
+
"GlobalVars": GlobalVars,
|
|
897
|
+
"Tasks": [],
|
|
898
|
+
"ProgramInstances": []
|
|
899
|
+
};
|
|
900
|
+
this.Name = "Main";
|
|
901
|
+
this.ResourceTypeName = "";
|
|
902
|
+
this.GlobalVars = new GlobalVars(null, this);
|
|
903
|
+
this.Tasks = [];
|
|
904
|
+
this.ProgramInstances = [];
|
|
905
|
+
this.Parent = null;
|
|
906
|
+
if(isValid(name)) this.Name = name;
|
|
907
|
+
if(isValid(resourceTypeName)) this.ResourceTypeName = resourceTypeName;
|
|
908
|
+
if(isValid(globalVars)) this.GlobalVars = globalVars;
|
|
909
|
+
if(isValid(tasks)) this.Tasks = tasks;
|
|
910
|
+
if(isValid(programInstances)) this.ProgramInstances = programInstances;
|
|
911
|
+
if(isValid(parent)) this.Parent = parent;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Creates a new object based on the xml element.
|
|
916
|
+
* @param {Element} xml The xml element to create the object from.
|
|
917
|
+
* @param {Configuration?} parent The parent that will own the object.
|
|
918
|
+
* @returns {Resource} Returns a new resource object based on the Xml.
|
|
919
|
+
*/
|
|
920
|
+
static fromXML(xml, parent) {
|
|
921
|
+
if(!isValid(xml)) {return null;}
|
|
922
|
+
var obj = new Resource(xml.getAttribute("name"), xml.getAttribute("resourceTypeName"), null, null, null, parent);
|
|
923
|
+
obj.GlobalVars = GlobalVars.fromXML(xml.getElementsByTagName("GlobalVars")[0]);
|
|
924
|
+
forEachElem(xml.getElementsByTagName("Task"), (t) => {
|
|
925
|
+
obj.Tasks.push(Task.fromXML(t, obj));
|
|
926
|
+
});
|
|
927
|
+
forEachElem(xml.getElementsByTagName("ProgramInstance"), (p) => {
|
|
928
|
+
obj.ProgramInstances.push(ProgramInstance.fromXML(p, obj));
|
|
929
|
+
});
|
|
930
|
+
return obj;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Creates an xml string representing the object.
|
|
935
|
+
* @returns {string} Returns an xml string of the object.
|
|
936
|
+
*/
|
|
937
|
+
toXML() {
|
|
938
|
+
var tasks = "";
|
|
939
|
+
var progs = "";
|
|
940
|
+
|
|
941
|
+
forEachElem(this.Tasks, (t) => {
|
|
942
|
+
tasks += t.toXML() + "\n";
|
|
943
|
+
});
|
|
944
|
+
forEachElem(this.ProgramInstances, (p) => {
|
|
945
|
+
progs += p.toXML() + "\n";
|
|
946
|
+
});
|
|
947
|
+
return `<Resource name="${this.Name}" resourceTypeName="${this.ResourceTypeName}">
|
|
948
|
+
${this.GlobalVars.toXML()}
|
|
949
|
+
${tasks}
|
|
950
|
+
${progs}
|
|
951
|
+
</Resource>`;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Converts the resource's programming to Structured Text.
|
|
956
|
+
* @returns {string} Returns a string representing the structured text.
|
|
957
|
+
*/
|
|
958
|
+
toST(){
|
|
959
|
+
var tasks = "";
|
|
960
|
+
var progs = "";
|
|
961
|
+
var vars = "";
|
|
962
|
+
var included = "";
|
|
963
|
+
var map = this.Parent.Parent.Parent.MappingTable.toST(this.Name);
|
|
964
|
+
var programs = this.Parent.Parent.Parent.getAllPrograms();
|
|
965
|
+
var fbs = this.Parent.Parent.Parent.getAllFunctionBlocks();
|
|
966
|
+
forEachElem(fbs, fb => included += fb.toST() + "\n");
|
|
967
|
+
forEachElem(this.Tasks, t => tasks += t.toST());
|
|
968
|
+
forEachElem(this.ProgramInstances,
|
|
969
|
+
/**
|
|
970
|
+
*
|
|
971
|
+
* @param {ProgramInstance} p
|
|
972
|
+
*/
|
|
973
|
+
p => {
|
|
974
|
+
progs += p.toST();
|
|
975
|
+
|
|
976
|
+
var incProg = programs.find(pr => pr.Name === p.TypeName);
|
|
977
|
+
if(isValid(incProg)){
|
|
978
|
+
included += incProg.toST() + "\n";
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
forEachElem(this.GlobalVars.Variables,
|
|
982
|
+
/**
|
|
983
|
+
*
|
|
984
|
+
* @param {Variable} v
|
|
985
|
+
*/
|
|
986
|
+
(v) => {
|
|
987
|
+
let addr = null;
|
|
988
|
+
if(isValid(v.Address)){
|
|
989
|
+
addr = "%" + v.Address.Location + v.Address.Size + v.Address.Address;
|
|
990
|
+
}
|
|
991
|
+
vars += `${v.Name} ${isValid(addr) ? " AT " + addr : ""} : ${v.Type.TypeName};${isValid(addr) ? `\n//Global={"Name":"${v.Name}", "Address":"${addr}"}` : ""}\n`;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
);
|
|
995
|
+
var res =
|
|
996
|
+
`
|
|
997
|
+
${map}
|
|
998
|
+
${tasks}
|
|
999
|
+
${progs}
|
|
1000
|
+
VAR_GLOBAL
|
|
1001
|
+
${vars}
|
|
1002
|
+
END_VAR
|
|
1003
|
+
${included}`;
|
|
1004
|
+
return res;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Represents a GlobalVars element in the IEC file.
|
|
1010
|
+
*/
|
|
1011
|
+
export class GlobalVars extends Serializable{
|
|
1012
|
+
/**
|
|
1013
|
+
* Constructs a new GlobalVars object.
|
|
1014
|
+
* @param {Variable[]?} variables An array of variables.
|
|
1015
|
+
* @param {Resource?} parent The parent that owns this object.
|
|
1016
|
+
*/
|
|
1017
|
+
constructor(variables, parent){
|
|
1018
|
+
super();
|
|
1019
|
+
this.TypeMap = {
|
|
1020
|
+
"Variables": []
|
|
1021
|
+
};
|
|
1022
|
+
this.Variables = [];
|
|
1023
|
+
this.Parent = null;
|
|
1024
|
+
if(isValid(variables)) this.Variables = variables;
|
|
1025
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Creates a new object based on the xml element.
|
|
1030
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
1031
|
+
* @param {Resource?} parent The parent that owns the object.
|
|
1032
|
+
* @returns {GlobalVars?} Returns a new GlobalVars object from the xml.
|
|
1033
|
+
*/
|
|
1034
|
+
static fromXML(xml, parent){
|
|
1035
|
+
if(!isValid(xml)) return null;
|
|
1036
|
+
var obj = new GlobalVars(null, parent);
|
|
1037
|
+
forEachElem(xml.getElementsByTagName("Variable"), v => {
|
|
1038
|
+
obj.Variables.push(Variable.fromXML(v));
|
|
1039
|
+
});
|
|
1040
|
+
return obj;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* Creates an xml string representation of the object.
|
|
1045
|
+
* @returns {string} Returns an xml string of the object.
|
|
1046
|
+
*/
|
|
1047
|
+
toXML(){
|
|
1048
|
+
var v = "";
|
|
1049
|
+
forEachElem(this.Variables, va => {
|
|
1050
|
+
v += va.toXML() + "\n";
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
return `<GlobalVars>
|
|
1054
|
+
${v}
|
|
1055
|
+
</GlobalVars>`;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Represents a task in the IEC file.
|
|
1062
|
+
*/
|
|
1063
|
+
export class Task extends Serializable{
|
|
1064
|
+
/**
|
|
1065
|
+
* Constructs a new Task object.
|
|
1066
|
+
* @param {string?} type The type of the task.
|
|
1067
|
+
* @param {string?} name The name of the task.
|
|
1068
|
+
* @param {string?} interval The interval at which the task runs.
|
|
1069
|
+
* @param {string?} priority The priority of the task.
|
|
1070
|
+
* @param {Configuration?} parent The parent that owns the task.
|
|
1071
|
+
*/
|
|
1072
|
+
constructor(type, name, interval, priority, parent){
|
|
1073
|
+
super();
|
|
1074
|
+
this.TypeMap = {
|
|
1075
|
+
"Type": "",
|
|
1076
|
+
"Name": "",
|
|
1077
|
+
"Interval": "",
|
|
1078
|
+
"Priority": ""
|
|
1079
|
+
};
|
|
1080
|
+
this.Type = "";
|
|
1081
|
+
this.Name = "";
|
|
1082
|
+
this.Interval = "1000";
|
|
1083
|
+
this.Priority = "1";
|
|
1084
|
+
this.Parent = null;
|
|
1085
|
+
if(isValid(type)) this.Type = type;
|
|
1086
|
+
if(isValid(name)) this.Name = name;
|
|
1087
|
+
if(isValid(interval)) this.Interval = interval;
|
|
1088
|
+
if(isValid(priority)) this.Priority = priority;
|
|
1089
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Creates a new task object from xml.
|
|
1094
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
1095
|
+
* @param {Configuration?} parent The parent that owns the object.
|
|
1096
|
+
* @returns {Task} Returns a new task object.
|
|
1097
|
+
*/
|
|
1098
|
+
static fromXML(xml, parent){
|
|
1099
|
+
if(!isValid(xml)) return null;
|
|
1100
|
+
return new Task(xml.getAttribute("xsi:type"), xml.getAttribute("name"), xml.getAttribute("interval"), xml.getAttribute("priority"), parent);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* Creates a xml string representation of the object.
|
|
1105
|
+
* @returns {string} Returns an xml string of the object.
|
|
1106
|
+
*/
|
|
1107
|
+
toXML(){
|
|
1108
|
+
return `<Task xsi:type="${this.Type}" name="${this.Name}" interval="${this.Interval}" priority="${this.Priority}"/>`;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Converts the task information to a structured text comment containing JSON that can be consumed by a compiler
|
|
1113
|
+
* for creating platform specific tasks.
|
|
1114
|
+
* @returns {string} A string representing the task as structured text.
|
|
1115
|
+
*/
|
|
1116
|
+
toST(){
|
|
1117
|
+
return `//Task={"Name":"${this.Name}", "Interval":"${this.Interval}", "Priority":"${this.Priority}"}\n`;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Represents a ProgramInstance in the IEC file.
|
|
1123
|
+
*/
|
|
1124
|
+
export class ProgramInstance extends Serializable{
|
|
1125
|
+
/**
|
|
1126
|
+
* Constructs a new ProgramInstance object.
|
|
1127
|
+
* @param {string?} name The name of the instance.
|
|
1128
|
+
* @param {string?} typeName The type name for the instance.
|
|
1129
|
+
* @param {string?} associatedTaskName The task associated with this instance.
|
|
1130
|
+
* @param {Configuration?} parent The parent that owns this object.
|
|
1131
|
+
*/
|
|
1132
|
+
constructor(name, typeName, associatedTaskName, parent){
|
|
1133
|
+
super();
|
|
1134
|
+
this.TypeMap = {
|
|
1135
|
+
"Name": "",
|
|
1136
|
+
"TypeName": "",
|
|
1137
|
+
"AssociatedTaskName": ""
|
|
1138
|
+
};
|
|
1139
|
+
this.TypeName = "";
|
|
1140
|
+
this.Name = "";
|
|
1141
|
+
this.AssociatedTaskName = "";
|
|
1142
|
+
this.Parent = null;
|
|
1143
|
+
if(isValid(typeName)) this.TypeName = typeName;
|
|
1144
|
+
if(isValid(name)) this.Name = name;
|
|
1145
|
+
if(isValid(associatedTaskName)) this.AssociatedTaskName = associatedTaskName;
|
|
1146
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Creates a new ProgramInstance object from the xml element.
|
|
1151
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
1152
|
+
* @param {Configuration?} parent The parent that owns the objec.t
|
|
1153
|
+
* @returns {ProgramInstance?} Returns a new object.
|
|
1154
|
+
*/
|
|
1155
|
+
static fromXML(xml, parent){
|
|
1156
|
+
if(!isValid(xml)) return null;
|
|
1157
|
+
return new ProgramInstance(xml.getAttribute("name"), xml.getAttribute("typeName"), xml.getAttribute("associatedTaskName"), parent);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
*
|
|
1162
|
+
* @returns {string} An xml string representing the object.
|
|
1163
|
+
*/
|
|
1164
|
+
toXML(){
|
|
1165
|
+
return `<ProgramInstance typeName="${this.TypeName}" name="${this.Name}" associatedTaskName="${this.AssociatedTaskName}"/>`;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
/**
|
|
1169
|
+
* Creates a structured text comment containing JSON that represents the properties of the instance, which can be consumed by
|
|
1170
|
+
* compilers to set up platform-specific instances.
|
|
1171
|
+
* @returns {string} Returns a string representing the structured Text.
|
|
1172
|
+
*/
|
|
1173
|
+
toST(){
|
|
1174
|
+
return `//Instance={"TypeName":"${this.TypeName}", "Name":"${this.Name}", "AssociatedTaskName":"${this.AssociatedTaskName}"}\n`;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Represents the Program element of the IEC project file.
|
|
1180
|
+
*/
|
|
1181
|
+
export class Program extends Serializable {
|
|
1182
|
+
/**
|
|
1183
|
+
*
|
|
1184
|
+
* @param {string?} name Can be null or undefined.
|
|
1185
|
+
* @param {ExternalVars?} externalVars can be null or undefined.
|
|
1186
|
+
* @param {Vars?} vars can be null or undefined.
|
|
1187
|
+
* @param {MainBody?} mainBody Can be null or undefined.
|
|
1188
|
+
* @param {NamespaceDecl?} parent The containing namespace.
|
|
1189
|
+
*/
|
|
1190
|
+
constructor(name, externalVars, vars, mainBody, parent) {
|
|
1191
|
+
super();
|
|
1192
|
+
this.TypeMap = {
|
|
1193
|
+
"Name": "",
|
|
1194
|
+
"ExternalVars": ExternalVars,
|
|
1195
|
+
"Vars": Vars,
|
|
1196
|
+
"MainBody": MainBody,
|
|
1197
|
+
};
|
|
1198
|
+
this.Name = "";
|
|
1199
|
+
this.ExternalVars = new ExternalVars();
|
|
1200
|
+
this.Vars = new Vars();
|
|
1201
|
+
this.MainBody = new MainBody();
|
|
1202
|
+
this.Parent = null;
|
|
1203
|
+
if(isValid(name)) this.Name = name;
|
|
1204
|
+
if(isValid(externalVars)) this.ExternalVars = externalVars;
|
|
1205
|
+
if(isValid(vars)) this.Vars = vars;
|
|
1206
|
+
if(isValid(mainBody)) this.MainBody = mainBody;
|
|
1207
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* Creates a new Program object based on an XML element.
|
|
1212
|
+
* @param {Element} xml The XML element to create from.
|
|
1213
|
+
* @param {NamespaceDecl} parent The containing namespace.
|
|
1214
|
+
* @returns A new Program object.
|
|
1215
|
+
*/
|
|
1216
|
+
static fromXML(xml, parent) {
|
|
1217
|
+
if(!isValid(xml)) return null;
|
|
1218
|
+
const prog = new Program(
|
|
1219
|
+
xml.getAttribute("name"),
|
|
1220
|
+
ExternalVars.fromXML(xml.getElementsByTagName("ExternalVars")[0]),
|
|
1221
|
+
Vars.fromXML(xml.getElementsByTagName("Vars")[0]),
|
|
1222
|
+
null, parent
|
|
1223
|
+
);
|
|
1224
|
+
prog.MainBody = MainBody.fromXML(xml.getElementsByTagName("MainBody")[0], prog);
|
|
1225
|
+
return prog;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
*
|
|
1230
|
+
* @returns Returns an xml string representing the object.
|
|
1231
|
+
*/
|
|
1232
|
+
toXML() {
|
|
1233
|
+
return `<Program name="${this.Name}">
|
|
1234
|
+
${this.ExternalVars.toXML()}
|
|
1235
|
+
${this.Vars.toXML()}
|
|
1236
|
+
${this.MainBody.toXML()}
|
|
1237
|
+
</Program>`;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Compiles the program as structured text. NOTE: external variables are ignored and should be
|
|
1242
|
+
* defined in the resource section of the project as global variables.
|
|
1243
|
+
* @returns {string} Returns a string representing the structured text of the program.
|
|
1244
|
+
*/
|
|
1245
|
+
toST(){
|
|
1246
|
+
var st = "";
|
|
1247
|
+
try{
|
|
1248
|
+
var decl = "";
|
|
1249
|
+
forEachElem(this.Vars.Variables,
|
|
1250
|
+
/**
|
|
1251
|
+
*
|
|
1252
|
+
* @param {Variable} v
|
|
1253
|
+
*/
|
|
1254
|
+
(v) => {
|
|
1255
|
+
decl += `${v.Name} ${isValid(v.Address) ? "AT %" + v.Address.Location + v.Address.Size + (v.Address.Address.length > 0 ? "." + v.Address.Address : "") : ""} : ${v.Type.TypeName};\n`;
|
|
1256
|
+
}
|
|
1257
|
+
);
|
|
1258
|
+
st =
|
|
1259
|
+
`PROGRAM ${this.Name}
|
|
1260
|
+
VAR
|
|
1261
|
+
${decl}
|
|
1262
|
+
END_VAR
|
|
1263
|
+
${this.MainBody.toST()}
|
|
1264
|
+
END_PROGRAM`;
|
|
1265
|
+
}
|
|
1266
|
+
catch(e){
|
|
1267
|
+
console.error(e);
|
|
1268
|
+
}
|
|
1269
|
+
return st;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Represents a MainBody element in the IEC project file.
|
|
1275
|
+
*/
|
|
1276
|
+
export class MainBody extends Serializable{
|
|
1277
|
+
/**
|
|
1278
|
+
* Constructs a new MainBody object.
|
|
1279
|
+
* @param {BodyContent?} bodyContent Can be null or undefined.
|
|
1280
|
+
* @param {Program|FunctionBlock?} parent The containing object for this one.
|
|
1281
|
+
*/
|
|
1282
|
+
constructor(bodyContent, parent) {
|
|
1283
|
+
super();
|
|
1284
|
+
this.TypeMap = {
|
|
1285
|
+
"BodyContent": BodyContent
|
|
1286
|
+
};
|
|
1287
|
+
this.BodyContent = new BodyContent();
|
|
1288
|
+
this.Parent = null;
|
|
1289
|
+
if(isValid(bodyContent)) this.BodyContent = bodyContent;
|
|
1290
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Creates a new MainBody object from an xml element.
|
|
1295
|
+
* @param {Element} xml The XML element object from which to create an object.
|
|
1296
|
+
* @param {Program|FunctionBlock?} parent The containing object for this one.
|
|
1297
|
+
* @returns {MainBody} A new MainBody object.
|
|
1298
|
+
*/
|
|
1299
|
+
static fromXML(xml, parent) {
|
|
1300
|
+
if(!isValid(xml)) return null;
|
|
1301
|
+
const body = new MainBody( null , parent);
|
|
1302
|
+
body.BodyContent = BodyContent.fromXML(xml.getElementsByTagName("BodyContent")[0], body);
|
|
1303
|
+
return body;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
*
|
|
1308
|
+
* @returns {string} Returns a string of xml representing htis object.
|
|
1309
|
+
*/
|
|
1310
|
+
toXML() {
|
|
1311
|
+
return `<MainBody>
|
|
1312
|
+
${this.BodyContent.toXML()}
|
|
1313
|
+
</MainBody>`;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Converts the content of this body to structured text.
|
|
1318
|
+
* @returns {string} Returns a string representing the structured text.
|
|
1319
|
+
*/
|
|
1320
|
+
toST(){
|
|
1321
|
+
return this.BodyContent.toST();
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* Represents a BodyContent element in an IEC project file.
|
|
1327
|
+
*/
|
|
1328
|
+
export class BodyContent extends Serializable {
|
|
1329
|
+
/**
|
|
1330
|
+
* Constructs a new BodyContent object
|
|
1331
|
+
* @param {string?} type The type of body content. Default: ST
|
|
1332
|
+
* @param {ST?} st An ST object, can be null or undefined.
|
|
1333
|
+
* @param {Rung[]?} rungs An array of Rung objects. Can be null or undefined.
|
|
1334
|
+
* @param {Network[]?} networks An array of network objects. Can be null or undefined.
|
|
1335
|
+
* @param {MainBody?} parent The Mainbody object that contains this content
|
|
1336
|
+
*/
|
|
1337
|
+
constructor(type, st, rungs, networks, parent) {
|
|
1338
|
+
super();
|
|
1339
|
+
this.TypeMap = {
|
|
1340
|
+
"Type": "",
|
|
1341
|
+
"ST": ST,
|
|
1342
|
+
"Rungs": [],
|
|
1343
|
+
"Networks": []
|
|
1344
|
+
};
|
|
1345
|
+
this.Type = "ST";
|
|
1346
|
+
if(isValid(type)) this.Type = type;
|
|
1347
|
+
this.ST = null;
|
|
1348
|
+
this.Rungs = [];
|
|
1349
|
+
this.Networks = [];
|
|
1350
|
+
this.Parent = null;
|
|
1351
|
+
if(type == "ST"){
|
|
1352
|
+
this.ST = new ST();
|
|
1353
|
+
if(isValid(st)) this.ST = st;
|
|
1354
|
+
}
|
|
1355
|
+
else if(type == "LD"){
|
|
1356
|
+
if(isValid(rungs)) this.Rungs = rungs;
|
|
1357
|
+
}
|
|
1358
|
+
else if(type == "FBD"){
|
|
1359
|
+
if(isValid(networks)) this.Networks = networks;
|
|
1360
|
+
}
|
|
1361
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Creates a new BodyContent object based on an XML element.
|
|
1366
|
+
* @param {Element} xml An XML element object.
|
|
1367
|
+
* @param {MainBody?} parent The parent of this object.
|
|
1368
|
+
* @returns {BodyContent} Returns a new BodyContent object.
|
|
1369
|
+
*/
|
|
1370
|
+
static fromXML(xml, parent) {
|
|
1371
|
+
if(!isValid(xml)) return null;
|
|
1372
|
+
var b = new BodyContent(
|
|
1373
|
+
xml.getAttribute("xsi:type"), null, null, null, parent);
|
|
1374
|
+
var xmlrungs = xml.getElementsByTagName("Rung");
|
|
1375
|
+
var xmlnet = xml.getElementsByTagName("Network");
|
|
1376
|
+
var xmlst = xml.getElementsByTagName("ST")[0];
|
|
1377
|
+
if(b.Type == "ST"){
|
|
1378
|
+
b.ST = ST.fromXML(xmlst);
|
|
1379
|
+
if(!isValid(b.ST)){
|
|
1380
|
+
b.ST = new ST();
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
else if(b.Type == "LD"){
|
|
1384
|
+
forEachElem(xmlrungs, (elem) => {
|
|
1385
|
+
b.Rungs.push(Rung.fromXML(elem, b));
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
else if(b.Type == "FBD"){
|
|
1389
|
+
forEachElem(xmlnet, (elem) => {
|
|
1390
|
+
b.Networks.push(Network.fromXML(elem, b));
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
return b;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
/**
|
|
1398
|
+
*
|
|
1399
|
+
* @returns Returns an xml string representing the object.
|
|
1400
|
+
*/
|
|
1401
|
+
toXML() {
|
|
1402
|
+
var subxml = "";
|
|
1403
|
+
if(this.Type == "ST"){
|
|
1404
|
+
if(isValid(this.ST)){
|
|
1405
|
+
subxml = this.ST.toXML();
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
else if(this.Type == "LD"){
|
|
1409
|
+
if(isValid(this.Rungs)){
|
|
1410
|
+
forEachElem(this.Rungs, (rung) => {
|
|
1411
|
+
subxml += rung.toXML() + "\n";
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
else if(this.Type == "FBD"){
|
|
1416
|
+
if(isValid(this.Networks)){
|
|
1417
|
+
forEachElem(this.Networks, (net) => {
|
|
1418
|
+
subxml += net.toXML() + "\n";
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
return `<BodyContent xsi:type="${this.Type}">
|
|
1423
|
+
${subxml}
|
|
1424
|
+
</BodyContent>`;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Finds an object in the rungs based on the ID value.
|
|
1429
|
+
* @param {string} id The ID value for the object.
|
|
1430
|
+
* @returns {FbdObject|LdObject?} Returns the object matching the ID, or null if no match.
|
|
1431
|
+
*/
|
|
1432
|
+
findObject(id){
|
|
1433
|
+
var ret = null;
|
|
1434
|
+
try{
|
|
1435
|
+
forEachElem(this.Rungs, (r) => {
|
|
1436
|
+
if(isValid(ret)){
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
ret = r.findObject(id);
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
catch(e){
|
|
1443
|
+
console.error(e);
|
|
1444
|
+
}
|
|
1445
|
+
return ret;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* Converts the content to structured text.
|
|
1450
|
+
* @returns {string} Returns a string representing the structured text.
|
|
1451
|
+
*/
|
|
1452
|
+
toST(){
|
|
1453
|
+
var st = "";
|
|
1454
|
+
try{
|
|
1455
|
+
if(this.Type ==="LD"){
|
|
1456
|
+
this.Rungs.sort((r1, r2) => parseInt(r1.EvaluationOrder) - parseInt(r2.EvaluationOrder));
|
|
1457
|
+
forEachElem(this.Rungs, r => {
|
|
1458
|
+
st += r.toST();
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
else if(this.ST !== null){
|
|
1462
|
+
st = this.ST.Content.trim();
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
catch(e){
|
|
1466
|
+
console.error(e);
|
|
1467
|
+
}
|
|
1468
|
+
return st;
|
|
1469
|
+
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* Represents a Structured Text (ST) element in the IEC project file.
|
|
1475
|
+
*/
|
|
1476
|
+
export class ST extends Serializable{
|
|
1477
|
+
/**
|
|
1478
|
+
* Constructs a new ST object with content.
|
|
1479
|
+
* @param {string?} content The content of the code, or null or undefined.
|
|
1480
|
+
*/
|
|
1481
|
+
constructor(content) {
|
|
1482
|
+
super();
|
|
1483
|
+
this.TypeMap = {
|
|
1484
|
+
"Content": ""
|
|
1485
|
+
};
|
|
1486
|
+
this.Content = "";
|
|
1487
|
+
|
|
1488
|
+
if(isValid(content)) this.Content = content;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* Creates an ST object based on an XML element.
|
|
1493
|
+
* @param {Element} xml The element from which to create the object.
|
|
1494
|
+
* @returns {ST} A new ST object.
|
|
1495
|
+
*/
|
|
1496
|
+
static fromXML(xml) {
|
|
1497
|
+
if(!isValid(xml)) return null;
|
|
1498
|
+
return new ST(
|
|
1499
|
+
xml.textContent.trim()
|
|
1500
|
+
);
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
*
|
|
1505
|
+
* @returns {string} An XML string representing the object.
|
|
1506
|
+
*/
|
|
1507
|
+
toXML() {
|
|
1508
|
+
return `<ST><![CDATA[${this.Content}]]></ST>`;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
/**
|
|
1513
|
+
* Represents a FunctionBlack element of the IEC Project File.
|
|
1514
|
+
*/
|
|
1515
|
+
export class FunctionBlock extends Serializable{
|
|
1516
|
+
/**
|
|
1517
|
+
* Constructs a new FunctionBlock object based on the arguments
|
|
1518
|
+
* @param {string} name The name of the function block.
|
|
1519
|
+
* @param {Parameters} parameters The parameters for the function block.
|
|
1520
|
+
* @param {Vars} vars The variables within the function block.
|
|
1521
|
+
* @param {MainBody} mainBody The main body of the block.
|
|
1522
|
+
* @param {NamespaceDecl} parent The parent that owns the block.
|
|
1523
|
+
*/
|
|
1524
|
+
constructor(name, parameters, vars, mainBody, parent) {
|
|
1525
|
+
super();
|
|
1526
|
+
this.TypeMap = {
|
|
1527
|
+
"Name": "",
|
|
1528
|
+
"Parameters": Parameters,
|
|
1529
|
+
"Vars": Vars,
|
|
1530
|
+
"MainBody": MainBody
|
|
1531
|
+
};
|
|
1532
|
+
this.Parent = null;
|
|
1533
|
+
this.Name = "";
|
|
1534
|
+
this.Parameters = new Parameters();
|
|
1535
|
+
this.Vars = new Vars();
|
|
1536
|
+
this.MainBody = new MainBody();
|
|
1537
|
+
if(isValid(name)) this.Name = name;
|
|
1538
|
+
if(isValid(parameters)) this.Parameters = parameters;
|
|
1539
|
+
if(isValid(vars)) this.Vars = vars;
|
|
1540
|
+
if(isValid(mainBody)) this.MainBody = mainBody;
|
|
1541
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Creates a new FunctionBlock object based on an xml element.
|
|
1545
|
+
* @param {Element} xml The XML to create the FunctionBlock from.
|
|
1546
|
+
* @param {NamespaceDecl} parent The parent that owns the object.
|
|
1547
|
+
* @returns {FunctionBlock} Returns a new FunctionBlock object.
|
|
1548
|
+
*/
|
|
1549
|
+
static fromXML(xml, parent) {
|
|
1550
|
+
if(!isValid(xml)) return null;
|
|
1551
|
+
var obj = new FunctionBlock(xml.getAttribute("name"), null, null, null, parent);
|
|
1552
|
+
obj.Parameters = Parameters.fromXML(xml.getElementsByTagName("Parameters")[0]);
|
|
1553
|
+
obj.Vars = Vars.fromXML(xml.getElementsByTagName("Vars")[0]);
|
|
1554
|
+
obj.MainBody = MainBody.fromXML(xml.getElementsByTagName("MainBody")[0], obj);
|
|
1555
|
+
return obj;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
*
|
|
1559
|
+
* @returns {string} Returns an XML string representing the object.
|
|
1560
|
+
*/
|
|
1561
|
+
toXML() {
|
|
1562
|
+
return `<FunctionBlock name="${this.Name}">
|
|
1563
|
+
${this.Parameters.toXML()}
|
|
1564
|
+
${this.Vars.toXML()}
|
|
1565
|
+
${this.MainBody.toXML()}
|
|
1566
|
+
</FunctionBlock>`;
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* Compiles the function block as structured text.
|
|
1571
|
+
* @returns {string} Returns a string representing the structured text.
|
|
1572
|
+
*/
|
|
1573
|
+
toST(){
|
|
1574
|
+
var st = "";
|
|
1575
|
+
try{
|
|
1576
|
+
var decl = "";
|
|
1577
|
+
var inputs = "";
|
|
1578
|
+
var outputs = "";
|
|
1579
|
+
this.Parameters.InputVars.Variables.sort((a, b) => parseInt(a.Order) - parseInt(b.Order));
|
|
1580
|
+
this.Parameters.OutputVars.Variables.sort((a, b) => parseInt(a.Order) - parseInt(b.Order));
|
|
1581
|
+
forEachElem(this.Parameters.InputVars.Variables,
|
|
1582
|
+
/**
|
|
1583
|
+
*
|
|
1584
|
+
* @param {Variable} v
|
|
1585
|
+
*/
|
|
1586
|
+
(v) => {
|
|
1587
|
+
inputs += `${v.Name} : ${v.Type.TypeName};\n`;
|
|
1588
|
+
}
|
|
1589
|
+
);
|
|
1590
|
+
forEachElem(this.Parameters.OutputVars.Variables,
|
|
1591
|
+
/**
|
|
1592
|
+
*
|
|
1593
|
+
* @param {Variable} v
|
|
1594
|
+
*/
|
|
1595
|
+
(v) => {
|
|
1596
|
+
outputs += `${v.Name} : ${v.Type.TypeName};\n`;
|
|
1597
|
+
}
|
|
1598
|
+
);
|
|
1599
|
+
forEachElem(this.Vars.Variables,
|
|
1600
|
+
/**
|
|
1601
|
+
*
|
|
1602
|
+
* @param {Variable} v
|
|
1603
|
+
*/
|
|
1604
|
+
(v) => {
|
|
1605
|
+
decl += `${v.Name} ${isValid(v.Address) ? "%" + v.Address.Location + v.Address.Size + (v.Address.Address.length > 0 ? "." + v.Address.Address : "") : ""} : ${v.Type.TypeName};\n`;
|
|
1606
|
+
}
|
|
1607
|
+
);
|
|
1608
|
+
st =
|
|
1609
|
+
`FUNCTION_BLOCK ${this.Name}
|
|
1610
|
+
VAR_INPUT
|
|
1611
|
+
${inputs}
|
|
1612
|
+
END_VAR
|
|
1613
|
+
VAR_OUTPUT
|
|
1614
|
+
${outputs}
|
|
1615
|
+
END_VAR
|
|
1616
|
+
VAR
|
|
1617
|
+
${decl}
|
|
1618
|
+
END_VAR
|
|
1619
|
+
${this.MainBody.toST()}
|
|
1620
|
+
END_FUNCTION_BLOCK`;
|
|
1621
|
+
}
|
|
1622
|
+
catch(e){
|
|
1623
|
+
console.error(e);
|
|
1624
|
+
}
|
|
1625
|
+
return st;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/**
|
|
1630
|
+
* Represents the Rung element of an IEC project file.
|
|
1631
|
+
*/
|
|
1632
|
+
export class Rung extends Serializable {
|
|
1633
|
+
/**
|
|
1634
|
+
* Constructs a new Rung object.
|
|
1635
|
+
* @param {string?} evaluationOrder The order of eval for this rung.
|
|
1636
|
+
* @param {BodyContent?} parent The containing BodyContent object for this rung.
|
|
1637
|
+
*/
|
|
1638
|
+
constructor(evaluationOrder, parent) {
|
|
1639
|
+
super();
|
|
1640
|
+
this.TypeMap = {
|
|
1641
|
+
"EvaluationOrder": "",
|
|
1642
|
+
"Objects": []
|
|
1643
|
+
};
|
|
1644
|
+
this.EvaluationOrder = "";
|
|
1645
|
+
this.Objects = [];
|
|
1646
|
+
this.Parent = null;
|
|
1647
|
+
if(isValid(evaluationOrder)) this.EvaluationOrder = evaluationOrder;
|
|
1648
|
+
if(isValid(parent)) this.Parent = parent;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
/**
|
|
1652
|
+
* Creates a new Rung object based on an XML element.
|
|
1653
|
+
* @param {Element} xml The XML element from which to create the Rung.
|
|
1654
|
+
* @param {BodyContent?} parent The containing bodycontent for this rung.
|
|
1655
|
+
* @returns {Rung} A new rung object.
|
|
1656
|
+
*/
|
|
1657
|
+
static fromXML(xml, parent) {
|
|
1658
|
+
if(!isValid(xml)) return null;
|
|
1659
|
+
var rung = new Rung(xml.getAttribute("evaluationOrder"), parent);
|
|
1660
|
+
var lnodes = xml.getElementsByTagName("LdObject");
|
|
1661
|
+
var fnodes = xml.getElementsByTagName("FbdObject");
|
|
1662
|
+
forEachElem(lnodes, (elem) => {
|
|
1663
|
+
if(elem.tagName == "LdObject"){
|
|
1664
|
+
rung.Objects.push(LdObject.fromXML(elem, rung));
|
|
1665
|
+
}
|
|
1666
|
+
});
|
|
1667
|
+
forEachElem(fnodes, (elem) => {
|
|
1668
|
+
if(elem.tagName == "FbdObject"){
|
|
1669
|
+
rung.Objects.push(FbdObject.fromXML(elem, rung));
|
|
1670
|
+
}
|
|
1671
|
+
})
|
|
1672
|
+
return rung;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
*
|
|
1677
|
+
* @returns {string} Returns a string of xml representing the object.
|
|
1678
|
+
*/
|
|
1679
|
+
toXML() {
|
|
1680
|
+
var objxml = "";
|
|
1681
|
+
forEachElem(this.Objects, (obj) => {
|
|
1682
|
+
objxml += obj.toXML() + "\n";
|
|
1683
|
+
});
|
|
1684
|
+
return `<Rung evaluationOrder="${this.EvaluationOrder}">
|
|
1685
|
+
${objxml}
|
|
1686
|
+
</Rung>`;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
/**
|
|
1690
|
+
* Creates a new rung and adds the left and right power rails.
|
|
1691
|
+
* @param {string} order The evaluation order for this rung.
|
|
1692
|
+
* @param {BodyContent?} parent The body content containing this rung.
|
|
1693
|
+
* @returns
|
|
1694
|
+
*/
|
|
1695
|
+
static createRung(order, parent){
|
|
1696
|
+
var rung = new Rung(order, parent);
|
|
1697
|
+
rung.addObject(LdObject.createPowerRail("1", true, rung));
|
|
1698
|
+
rung.addObject(LdObject.createPowerRail("256", false, rung));
|
|
1699
|
+
//rung.Objects[1].connectTo("1");
|
|
1700
|
+
return rung;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
/**
|
|
1704
|
+
* Adds an object to the rung.
|
|
1705
|
+
* @param {FbdObject|LdObject|CommonObject} newobj The object to add to the rung.
|
|
1706
|
+
* @param {string} refID The Id of the output point to which this object should be connected.
|
|
1707
|
+
* @param {string} connectionVar The input variable name to which the output should be connected.
|
|
1708
|
+
* @returns {boolean} Returns true if the object was added.
|
|
1709
|
+
*/
|
|
1710
|
+
addObject(newobj, refID="", connectionVar=""){
|
|
1711
|
+
var retval = true;
|
|
1712
|
+
try{
|
|
1713
|
+
if(this.Objects.findIndex((elem) => {newobj === elem;}) == -1){
|
|
1714
|
+
this.Objects.push(newobj);
|
|
1715
|
+
if(refID.length > 0){
|
|
1716
|
+
newobj.connectTo(refID, connectionVar);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
else{
|
|
1720
|
+
retval = false;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
catch(e){
|
|
1724
|
+
retval = false;
|
|
1725
|
+
console.error(e);
|
|
1726
|
+
}
|
|
1727
|
+
return retval;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* Removes an object from the rung.
|
|
1732
|
+
* @param {LdObject|FbdObject|CommonObject} obj The object to remove.
|
|
1733
|
+
* @returns {boolean} True if it successfully removed the object.
|
|
1734
|
+
*/
|
|
1735
|
+
removeObject(obj){
|
|
1736
|
+
var retval = true;
|
|
1737
|
+
try{
|
|
1738
|
+
let i = this.Objects.findIndex((elem) => elem === obj);
|
|
1739
|
+
if(i > -1){
|
|
1740
|
+
if(i > 0 && obj.Type !== "RightPowerRail"){
|
|
1741
|
+
//get all objects connected to this one and reassign their connections to this object's input.
|
|
1742
|
+
var outcons = this.findConnectedOutputs(obj);
|
|
1743
|
+
var incons = this.findConnectedInputs(obj);
|
|
1744
|
+
|
|
1745
|
+
if(outcons.length > 0){
|
|
1746
|
+
if(incons.length >0){
|
|
1747
|
+
forEachElem(outcons, (con) => {
|
|
1748
|
+
con.RefID = incons[0].RefID;
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
this.Objects.splice(i, 1);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
else{
|
|
1757
|
+
retval = false;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
catch(e){
|
|
1761
|
+
console.error(e);
|
|
1762
|
+
retval = false;
|
|
1763
|
+
}
|
|
1764
|
+
return retval;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Finds an object in the rung based on its unique ID value.
|
|
1769
|
+
* @param {string} id The ID value for the object.
|
|
1770
|
+
* @returns {FbdObject|LdObject|CommonObject} Returns the object that matches the ID, or null if no object matches.
|
|
1771
|
+
*/
|
|
1772
|
+
findObject(id){
|
|
1773
|
+
return this.Objects.find((v) => v.ID == id);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
*
|
|
1778
|
+
* @param {LdObject | FbdObject} obj The ladder logic object from which to find connections.
|
|
1779
|
+
* @param {boolean} outputs Determines whether to search for objects that are connected to this object's outputs or inputs.
|
|
1780
|
+
* If true, it searches for output connections. If false, it searches for inputs. Default is true;
|
|
1781
|
+
* @returns {FbdObject[]|LdObject[]|CommonObject[]} Returns an array of objects.
|
|
1782
|
+
*/
|
|
1783
|
+
findConnections(obj, outputs=true){
|
|
1784
|
+
var retval = [];
|
|
1785
|
+
try{
|
|
1786
|
+
if(outputs){
|
|
1787
|
+
forEachElem(obj.Outputs, (point) => {
|
|
1788
|
+
forEachElem(this.Objects, (o) => {
|
|
1789
|
+
if(o.isConnectedTo(point.ID)){
|
|
1790
|
+
if(!retval.includes(o)) retval.push(o);
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
});
|
|
1795
|
+
if(obj instanceof FbdObject){
|
|
1796
|
+
forEachElem(obj.OutputVariables.Variables, (v) => {
|
|
1797
|
+
forEachElem(this.Objects, (o) => {
|
|
1798
|
+
if(o.isConnectedTo(v.OutputPoint.ID)){
|
|
1799
|
+
if(!retval.includes(o)) retval.push(o);
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
else{
|
|
1806
|
+
forEachElem(obj.Inputs, (point) => {
|
|
1807
|
+
if(point.Connections.length > 0){
|
|
1808
|
+
forEachElem(this.Objects, (o) => {
|
|
1809
|
+
forEachElem(point.Connections, (c) => {
|
|
1810
|
+
if(o.hasOutput(c.RefID)){
|
|
1811
|
+
if(!retval.includes(o)) retval.push(o);
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
if(obj instanceof FbdObject){
|
|
1819
|
+
forEachElem(obj.InputVariables.Variables, (v) => {
|
|
1820
|
+
forEachElem(this.Objects, (o) => {
|
|
1821
|
+
if(v.InputPoint.Connections.length > 0){
|
|
1822
|
+
forEachElem(v.InputPoint.Connections, (c) => {
|
|
1823
|
+
if(o.hasOutput(c.RefID)){
|
|
1824
|
+
if(!retval.includes(o)) retval.push(o);
|
|
1825
|
+
}
|
|
1826
|
+
});
|
|
1827
|
+
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
});
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
|
|
1836
|
+
}
|
|
1837
|
+
catch(e){
|
|
1838
|
+
|
|
1839
|
+
}
|
|
1840
|
+
return retval;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
/**
|
|
1844
|
+
* Finds all input points that are connected to the given object's outputs.
|
|
1845
|
+
* @param {FbdObject | LdObject} obj the ladder logic object from which to search for connected outputs.
|
|
1846
|
+
* @returns {Connection[]} An array of Connection objects from the ConnectionPointIns in the objects that are connected to this object's output points.
|
|
1847
|
+
*/
|
|
1848
|
+
findConnectedOutputs(obj){
|
|
1849
|
+
var retval = [];
|
|
1850
|
+
try{
|
|
1851
|
+
forEachElem(obj.Outputs, (point) => {
|
|
1852
|
+
forEachElem(this.Objects, (o) => {
|
|
1853
|
+
forEachElem(o.Inputs, (input) => {
|
|
1854
|
+
if(isValid(input.Connection)){
|
|
1855
|
+
if(input.Connection.RefID == point.ID){
|
|
1856
|
+
retval.push(input.Connection);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
});
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
});
|
|
1863
|
+
if(obj === FbdObject){
|
|
1864
|
+
forEachElem(obj.OutputVariables.Variables, (v) => {
|
|
1865
|
+
forEachElem(this.Objects, (o) => {
|
|
1866
|
+
forEachElem(o.InputVariables.Variables, (invar) => {
|
|
1867
|
+
if(isValid(invar.InputPoint.Connection)){
|
|
1868
|
+
if(invar.InputPoint.Connection.RefID == v.OutputPoint.ID){
|
|
1869
|
+
retval.push(invar.InputPoint.Connection);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
});
|
|
1873
|
+
});
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
catch(e){
|
|
1878
|
+
console.error(e);
|
|
1879
|
+
}
|
|
1880
|
+
return retval;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
/**
|
|
1884
|
+
* Finds all inputs into this object that have connections.
|
|
1885
|
+
* @param {FbdObject | LdObject} obj The ladder logic object from which to search for connected inputs.
|
|
1886
|
+
* @returns {Connection[]} An array of connection objects from the ConnectionPointIns in this object.
|
|
1887
|
+
*/
|
|
1888
|
+
findConnectedInputs(obj){
|
|
1889
|
+
var retval = [];
|
|
1890
|
+
try{
|
|
1891
|
+
forEachElem(obj.Inputs, (point) => {
|
|
1892
|
+
if(isValid(point.Connection)){
|
|
1893
|
+
retval.push(point.Connection);
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
|
|
1897
|
+
if(obj instanceof FbdObject){
|
|
1898
|
+
forEachElem(obj.InputVariables.Variables, (v) => {
|
|
1899
|
+
if(isValid(v.InputPoint.Connection)){
|
|
1900
|
+
retval.push(v.InputPoint.Connection);
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
catch(e){
|
|
1906
|
+
|
|
1907
|
+
}
|
|
1908
|
+
return retval;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/**
|
|
1912
|
+
* Finds the greatest output ID.
|
|
1913
|
+
* @returns {number} The greatest output ID value.
|
|
1914
|
+
*/
|
|
1915
|
+
findLastOutputID(){
|
|
1916
|
+
var ret = 0;
|
|
1917
|
+
try{
|
|
1918
|
+
forEachElem(this.Objects, (o) => {
|
|
1919
|
+
forEachElem(o.Outputs, (c) => {
|
|
1920
|
+
var n = parseInt(c.ID);
|
|
1921
|
+
if(n > ret) ret = n;
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1924
|
+
if(o instanceof FbdObject){
|
|
1925
|
+
forEachElem(o.OutputVariables.Variables, (v) => {
|
|
1926
|
+
var n = parseInt(v.OutputPoint.ID);
|
|
1927
|
+
if(n > ret) ret = n;
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
catch(e){
|
|
1933
|
+
|
|
1934
|
+
}
|
|
1935
|
+
return ret;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
/**
|
|
1939
|
+
* Gets the objects of certain types arranged by their output IDs.
|
|
1940
|
+
* @param {string[]} types An array of "Type" values to look for.
|
|
1941
|
+
*/
|
|
1942
|
+
objectsByOutput(types){
|
|
1943
|
+
var objs = new Array(this.findLastOutputID() + 1);
|
|
1944
|
+
objs = objs.fill(null);
|
|
1945
|
+
forEachElem(this.Objects, (elem) => {
|
|
1946
|
+
var i = 0;
|
|
1947
|
+
for(i = 0; i < elem.Outputs.length; i++){
|
|
1948
|
+
var id = parseInt(elem.Outputs[i].ID);
|
|
1949
|
+
if(!isValid(types)){
|
|
1950
|
+
objs[id] = elem;
|
|
1951
|
+
}
|
|
1952
|
+
else if(types.includes(elem.Type)){
|
|
1953
|
+
objs[id] = elem;
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
if(elem instanceof FbdObject){
|
|
1957
|
+
forEachElem(elem.OutputVariables.Variables, (v) => {
|
|
1958
|
+
var id = parseInt(v.OutputPoint.ID);
|
|
1959
|
+
if(!isValid(types)){
|
|
1960
|
+
objs[id] = elem;
|
|
1961
|
+
}
|
|
1962
|
+
else if(types.includes(elem.Type)){
|
|
1963
|
+
objs[id] = elem;
|
|
1964
|
+
}
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
});
|
|
1968
|
+
return objs;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
/**
|
|
1972
|
+
* Finds the objects based on the inputs.
|
|
1973
|
+
* @param {string[]} types A list of "Type" names to find.
|
|
1974
|
+
* @returns {FbdObject[]|LdObject[]} The objects by input ID.
|
|
1975
|
+
*/
|
|
1976
|
+
objectsWithInputs(types){
|
|
1977
|
+
var objs = [];
|
|
1978
|
+
forEachElem(this.Objects, (elem) => {
|
|
1979
|
+
var i = 0;
|
|
1980
|
+
if(elem.Inputs.length > 0){
|
|
1981
|
+
if(!isValid(types)){
|
|
1982
|
+
objs.push(elem);
|
|
1983
|
+
}
|
|
1984
|
+
else if(types.includes(elem.Type)){
|
|
1985
|
+
objs.push(elem);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
if( elem instanceof FbdObject){
|
|
1989
|
+
forEachElem(elem.InputVariables.Variables, (v) => {
|
|
1990
|
+
if(v.InputPoint != null){
|
|
1991
|
+
if(!isValid(types)){
|
|
1992
|
+
objs.push(elem);
|
|
1993
|
+
}
|
|
1994
|
+
else if(types.includes(elem.Type)){
|
|
1995
|
+
objs.push(elem);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
});
|
|
2001
|
+
return objs;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
#buildExpression(start){
|
|
2005
|
+
var expression = "";
|
|
2006
|
+
forEachElem(this.findConnections(start, false),
|
|
2007
|
+
/**
|
|
2008
|
+
*
|
|
2009
|
+
* @param {LdObject | FbdObject} con
|
|
2010
|
+
*/
|
|
2011
|
+
(con) => {
|
|
2012
|
+
if(expression.length > 0){
|
|
2013
|
+
expression += " OR ";
|
|
2014
|
+
}
|
|
2015
|
+
if(con instanceof FbdObject){
|
|
2016
|
+
var v = con.OutputVariables.Variables.find(iv => start.hasInput(iv.OutputPoint.ID));
|
|
2017
|
+
if(isValid(v)){
|
|
2018
|
+
expression += con.toST(v.ParameterName);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
else if(con.Type !== "LeftPowerRail"){
|
|
2022
|
+
expression += `(${this.#buildExpression(con)})`;
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
);
|
|
2026
|
+
if(start.Type !== "Coil"){
|
|
2027
|
+
expression = `${start.toST()}${expression.length > 0 ? " AND (" + expression + ")" : ""}`;
|
|
2028
|
+
}
|
|
2029
|
+
return expression;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* Builds a string of structured text for the entire rung
|
|
2034
|
+
* @returns {string} Returns a string representing the structured text for this rung.
|
|
2035
|
+
*/
|
|
2036
|
+
toST(){
|
|
2037
|
+
var st = "";
|
|
2038
|
+
try{
|
|
2039
|
+
//1) get the DataSources and Sinks and create their assignments.
|
|
2040
|
+
//1a) Create expressions for setting the Block object inputs.
|
|
2041
|
+
//2) Get all the coils, for each coil, we...
|
|
2042
|
+
//2a) Get all objects for its inputs, if there are multiple inputs, we begin an OR statement with the return of the recursive call to toST on each object.
|
|
2043
|
+
//2b) If there is only one input, we call the toST on that object and AND it with the recursive call to this toST
|
|
2044
|
+
//2c) If we hit Left Rail, we call toST on the coil, passing it the resulting expression from all the inputs.
|
|
2045
|
+
var objs = this.objectsWithInputs(["Block"]);
|
|
2046
|
+
var done = [];
|
|
2047
|
+
forEachElem(objs,
|
|
2048
|
+
/**
|
|
2049
|
+
*
|
|
2050
|
+
* @param {FbdObject} block
|
|
2051
|
+
*/
|
|
2052
|
+
(block) => {
|
|
2053
|
+
if(done.includes(block.ID)) return;
|
|
2054
|
+
done.push(block.ID);
|
|
2055
|
+
forEachElem(block.InputVariables.Variables,
|
|
2056
|
+
/**
|
|
2057
|
+
*
|
|
2058
|
+
* @param {InputVariable} invar
|
|
2059
|
+
*/
|
|
2060
|
+
(invar) => {
|
|
2061
|
+
forEachElem(invar.InputPoint.Connections, (c) => {
|
|
2062
|
+
/**
|
|
2063
|
+
* @type {FbdObject}
|
|
2064
|
+
*/
|
|
2065
|
+
var inobj = this.Objects.find(o => o.hasOutput(c.RefID));
|
|
2066
|
+
if(isValid(inobj)){
|
|
2067
|
+
if(inobj.Type === "DataSource"){
|
|
2068
|
+
st += block.toST(invar.ParameterName, inobj.toST()) + ";\n";
|
|
2069
|
+
}
|
|
2070
|
+
else{
|
|
2071
|
+
st += block.toST(invar.ParameterName, this.#buildExpression(inobj)) + ";\n";
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
);
|
|
2077
|
+
forEachElem(block.OutputVariables.Variables,
|
|
2078
|
+
/**
|
|
2079
|
+
*
|
|
2080
|
+
* @param {OutputVariable} outvar
|
|
2081
|
+
*/
|
|
2082
|
+
(outvar) => {
|
|
2083
|
+
|
|
2084
|
+
|
|
2085
|
+
var inobj = this.Objects.find(o => o.hasInput(outvar.OutputPoint.ID));
|
|
2086
|
+
if(isValid(inobj)){
|
|
2087
|
+
if(inobj.Type === "DataSink"){
|
|
2088
|
+
st += inobj.toST(outvar.ParameterName, block.toST(outvar.ParameterName)) + ";\n";
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
}
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2095
|
+
);
|
|
2096
|
+
|
|
2097
|
+
objs = this.objectsWithInputs(["Coil"]);
|
|
2098
|
+
forEachElem(objs,
|
|
2099
|
+
/**
|
|
2100
|
+
*
|
|
2101
|
+
* @param {LdObject} coil
|
|
2102
|
+
*/
|
|
2103
|
+
(coil) => {
|
|
2104
|
+
st += coil.toST(this.#buildExpression(coil)) + ";\n";
|
|
2105
|
+
|
|
2106
|
+
}
|
|
2107
|
+
);
|
|
2108
|
+
|
|
2109
|
+
|
|
2110
|
+
}
|
|
2111
|
+
catch(e){
|
|
2112
|
+
console.error(e);
|
|
2113
|
+
}
|
|
2114
|
+
return st;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* Represents a Network element in an IEC project file.
|
|
2120
|
+
*/
|
|
2121
|
+
export class Network extends Serializable{
|
|
2122
|
+
/**
|
|
2123
|
+
* Constructs a new Network object.
|
|
2124
|
+
* @param {string} evaluationOrder
|
|
2125
|
+
*/
|
|
2126
|
+
constructor(evaluationOrder, parent) {
|
|
2127
|
+
super();
|
|
2128
|
+
this.TypeMap = {
|
|
2129
|
+
"EvaluationOrder": "",
|
|
2130
|
+
"Objects": []
|
|
2131
|
+
};
|
|
2132
|
+
this.EvaluationOrder = "";
|
|
2133
|
+
this.Parent = null;
|
|
2134
|
+
this.Objects = [];
|
|
2135
|
+
if(isValid(evaluationOrder)) this.EvaluationOrder = evaluationOrder;
|
|
2136
|
+
if(isValid(parent)) this.Parent = parent;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
/**
|
|
2140
|
+
* Creates a new Network object based on the xml element.
|
|
2141
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
2142
|
+
*/
|
|
2143
|
+
static fromXML(xml, parent) {
|
|
2144
|
+
if(!isValid(xml)) return null;
|
|
2145
|
+
var net = new Network(xml.getAttribute("evaluationOrder"), parent);
|
|
2146
|
+
var onodes = xml.getElementsByTagName("CommonObject,FbdObject");
|
|
2147
|
+
forEachElem(onodes, (elem) => {
|
|
2148
|
+
if(elem.tagName == "CommonObject"){
|
|
2149
|
+
net.Objects.push(CommonObject.fromXML(elem, net));
|
|
2150
|
+
}
|
|
2151
|
+
else if(elem.tagName == "FbdObject"){
|
|
2152
|
+
net.Objects.push(FbdObject.fromXML(elem, net));
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
/**
|
|
2158
|
+
*
|
|
2159
|
+
* @returns Returns an xml string representing the object.
|
|
2160
|
+
*/
|
|
2161
|
+
toXML() {
|
|
2162
|
+
var objxml = "";
|
|
2163
|
+
forEachElem(this.Objects, (obj) => {
|
|
2164
|
+
objxml += obj.toXML() + "\n";
|
|
2165
|
+
});
|
|
2166
|
+
return `<Network xsi:type="FbdNetwork" evaluationOrder="${this.EvaluationOrder}" >
|
|
2167
|
+
${objxml}
|
|
2168
|
+
</Network>`;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* Represents a Ladder Logic Object in the IEC Project file.
|
|
2174
|
+
*/
|
|
2175
|
+
export class LdObject extends Serializable{
|
|
2176
|
+
/**
|
|
2177
|
+
* Constructs a new LdObject object.
|
|
2178
|
+
* @param {string?} type The type of object, or null/undefined.
|
|
2179
|
+
* @param {string?} operand The operand for the object., or null/undefined.
|
|
2180
|
+
* @param {string?} operand1 When type is a "CompareContact", this is the first operand of the compare.
|
|
2181
|
+
* @param {string?} operand2 when type is a "CompareContact", this is the second operand of the compare.
|
|
2182
|
+
* @param {string?} negated Should be a string of "true" or "false", determining whether the contact/coil is negated.
|
|
2183
|
+
* @param {string?} latch Specifies the type of latch for the coil. Defaults to "none".
|
|
2184
|
+
* @param {string?} edge Determines the edge of the contact. Defaults to none.
|
|
2185
|
+
* @param {string?} operator Designates the "compareOperator" option for a CompareContact type.
|
|
2186
|
+
* @param {RelPosition?} relPosition The relative position for the LdObject
|
|
2187
|
+
* @param {Rung?} parent The rung that this object is part of.
|
|
2188
|
+
*/
|
|
2189
|
+
constructor(type, operand, operand1, operand2, negated, latch, edge, operator, relPosition, parent) {
|
|
2190
|
+
super();
|
|
2191
|
+
this.TypeMap = {
|
|
2192
|
+
"Type": "",
|
|
2193
|
+
"Operand": "",
|
|
2194
|
+
"Operand1": "",
|
|
2195
|
+
"Operand2": "",
|
|
2196
|
+
"Negated": "",
|
|
2197
|
+
"Latch": "",
|
|
2198
|
+
"Edge": "",
|
|
2199
|
+
"Operator": "",
|
|
2200
|
+
"RelPosition": RelPosition,
|
|
2201
|
+
"Inputs": [],
|
|
2202
|
+
"Outputs": []
|
|
2203
|
+
};
|
|
2204
|
+
this.ID = generateGUID();
|
|
2205
|
+
this.Type = "Contact";
|
|
2206
|
+
this.Operand = "";
|
|
2207
|
+
this.Operand1 = "";
|
|
2208
|
+
this.Operand2 = "";
|
|
2209
|
+
this.Negated = "false";
|
|
2210
|
+
this.Latch = "none";
|
|
2211
|
+
this.Edge = "none";
|
|
2212
|
+
this.Operator = "";
|
|
2213
|
+
this.Parent = null;
|
|
2214
|
+
this.RelPosition = new RelPosition(0, 0);
|
|
2215
|
+
if(isValid(type)) this.Type = type;
|
|
2216
|
+
if(isValid(operand)) this.Operand = operand;
|
|
2217
|
+
if(isValid(operand1)) this.Operand1 = operand1;
|
|
2218
|
+
if(isValid(operand2)) this.Operand2 = operand2;
|
|
2219
|
+
if(isValid(negated)) this.Negated = negated;
|
|
2220
|
+
if(isValid(latch)) this.Latch = latch;
|
|
2221
|
+
if(isValid(edge)) this.Edge = edge;
|
|
2222
|
+
if(isValid(operator)) this.Operator = operator;
|
|
2223
|
+
if(isValid(parent)) this.Parent = parent;
|
|
2224
|
+
if(isValid(relPosition)) this.RelPosition = relPosition;
|
|
2225
|
+
this.Inputs = [];
|
|
2226
|
+
this.Outputs = [];
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
/**
|
|
2230
|
+
* creates a new LdObject object from an xml element.
|
|
2231
|
+
* @param {Element} xml The element representing the XML.
|
|
2232
|
+
* @param {Rung} [parent=null] The rung that this object is part of.
|
|
2233
|
+
* @returns a new LdObject object.
|
|
2234
|
+
*/
|
|
2235
|
+
static fromXML(xml, parent=null) {
|
|
2236
|
+
if(!isValid(xml)) return null;
|
|
2237
|
+
var obj = new LdObject(
|
|
2238
|
+
xml.getAttribute("xsi:type"),
|
|
2239
|
+
xml.getAttribute("operand"),
|
|
2240
|
+
xml.getAttribute("operand1"),
|
|
2241
|
+
xml.getAttribute("operand2"),
|
|
2242
|
+
xml.getAttribute("negated"),
|
|
2243
|
+
xml.getAttribute("latch"),
|
|
2244
|
+
xml.getAttribute("edge"),
|
|
2245
|
+
xml.getAttribute("compareOperator"),
|
|
2246
|
+
RelPosition.fromXML(xml.getElementsByTagName("RelPosition")[0]),
|
|
2247
|
+
parent
|
|
2248
|
+
);
|
|
2249
|
+
var ins = xml.getElementsByTagName("ConnectionPointIn");
|
|
2250
|
+
var outs = xml.getElementsByTagName("ConnectionPointOut");
|
|
2251
|
+
forEachElem(ins, (elem) => {
|
|
2252
|
+
obj.Inputs.push(ConnectionPointIn.fromXML(elem));
|
|
2253
|
+
});
|
|
2254
|
+
forEachElem(outs, (elem) => {
|
|
2255
|
+
obj.Outputs.push(ConnectionPointOut.fromXML(elem));
|
|
2256
|
+
});
|
|
2257
|
+
return obj;
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
/**
|
|
2261
|
+
*
|
|
2262
|
+
* @returns Returns an xml string representing the object.
|
|
2263
|
+
*/
|
|
2264
|
+
toXML() {
|
|
2265
|
+
var conxml = "";
|
|
2266
|
+
forEachElem(this.Inputs, (elem) => {
|
|
2267
|
+
conxml += elem.toXML() + "\n";
|
|
2268
|
+
});
|
|
2269
|
+
forEachElem(this.Outputs, (elem) => {
|
|
2270
|
+
conxml += elem.toXML() + "\n";
|
|
2271
|
+
});
|
|
2272
|
+
var attribs = "";
|
|
2273
|
+
if(this.Operand.length > 0){
|
|
2274
|
+
attribs += ` operand="${this.Operand}"`;
|
|
2275
|
+
}
|
|
2276
|
+
if(this.Operand1.length > 0){
|
|
2277
|
+
attribs += ` operand1="${this.Operand1}"`;
|
|
2278
|
+
}
|
|
2279
|
+
if(this.Operand2.length > 0){
|
|
2280
|
+
attribs += ` operand2="${this.Operand2}"`;
|
|
2281
|
+
}
|
|
2282
|
+
if(this.Edge.length > 0){
|
|
2283
|
+
attribs += ` edge="${this.Edge}"`;
|
|
2284
|
+
}
|
|
2285
|
+
if(this.Negated.length > 0){
|
|
2286
|
+
attribs += ` negated="${this.Negated}"`;
|
|
2287
|
+
}
|
|
2288
|
+
if(this.Latch.length > 0){
|
|
2289
|
+
attribs += ` latch="${this.Latch}"`;
|
|
2290
|
+
}
|
|
2291
|
+
if(this.Operator.length > 0){
|
|
2292
|
+
attribs += ` compareOperator="${this.Operator}"`;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
return `<LdObject xsi:type="${this.Type}" ${attribs}>
|
|
2296
|
+
${this.RelPosition.toXML()}
|
|
2297
|
+
${conxml}
|
|
2298
|
+
</LdObject>`;
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
/**
|
|
2302
|
+
* Helper function to create a power rail object.
|
|
2303
|
+
* @param {string} outID The output ID of the rail, if left rail.
|
|
2304
|
+
* @param {boolean} left Indicates whether to create a left or right rail.
|
|
2305
|
+
* @param {Rung} parent The rung to which the rail should be added.
|
|
2306
|
+
* @returns {LdObject} The rail object.
|
|
2307
|
+
*/
|
|
2308
|
+
static createPowerRail(outID, left=true, parent=null){
|
|
2309
|
+
var rail = null;
|
|
2310
|
+
if(!left){
|
|
2311
|
+
rail = new LdObject("RightPowerRail", "","","","","","","", null, parent);
|
|
2312
|
+
rail.Inputs.push(new ConnectionPointIn());
|
|
2313
|
+
}
|
|
2314
|
+
else{
|
|
2315
|
+
rail = new LdObject("LeftPowerRail", parent.EvaluationOrder,"","","","","","", null, parent);
|
|
2316
|
+
rail.Outputs.push(new ConnectionPointOut(outID));
|
|
2317
|
+
}
|
|
2318
|
+
return rail;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
/**
|
|
2322
|
+
* Helper function to create a contact object.
|
|
2323
|
+
* @param {string} operand The operand for the contact.
|
|
2324
|
+
* @param {string} outID The ID for the output point.
|
|
2325
|
+
* @param {string} negated The negation of the contact.
|
|
2326
|
+
* @param {string} edge The edge of the contact.
|
|
2327
|
+
* @param {Rung} parent The rung that is the parent.
|
|
2328
|
+
* @returns {LdObject} A new contact object.
|
|
2329
|
+
*/
|
|
2330
|
+
static createContact(operand, outID, negated="false", edge="none", parent=null){
|
|
2331
|
+
var contact = new LdObject("Contact", operand, "", "", negated, "", edge, "", null, parent);
|
|
2332
|
+
contact.Inputs.push(new ConnectionPointIn());
|
|
2333
|
+
contact.Outputs.push(new ConnectionPointOut(outID));
|
|
2334
|
+
return contact;
|
|
2335
|
+
}
|
|
2336
|
+
/**
|
|
2337
|
+
* Helper function to create a new compare contact object.
|
|
2338
|
+
* @param {string} operand1 The first operand of the compare.
|
|
2339
|
+
* @param {string} operand2 The second operand of the compare.
|
|
2340
|
+
* @param {string} operator The operator for the compare.
|
|
2341
|
+
* @param {string} outID The output ID of the object.
|
|
2342
|
+
* @param {Rung} parent The rung that will be its parent.
|
|
2343
|
+
* @returns {LdObject} The compare contact object.
|
|
2344
|
+
*/
|
|
2345
|
+
static createCompareContact(operand1, operand2, operator, outID, parent=null){
|
|
2346
|
+
var contact = new LdObject("CompareContact", "", operand1, operand2, "", "", "", operator, null, parent);
|
|
2347
|
+
contact.Inputs.push(new ConnectionPointIn());
|
|
2348
|
+
contact.Outputs.push(new ConnectionPointOut(outID));
|
|
2349
|
+
return contact;
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Helper function to create a new coil object.
|
|
2353
|
+
* @param {string} operand The operand for the coil.
|
|
2354
|
+
* @param {string} outID The output ID for the coil.
|
|
2355
|
+
* @param {string} negated The nagation state.
|
|
2356
|
+
* @param {string} latch The latch state.
|
|
2357
|
+
* @param {string} edge The edge of the coil.
|
|
2358
|
+
* @param {Rung} parent The rung that is the parent.
|
|
2359
|
+
* @returns {LdObject} A new coil object.
|
|
2360
|
+
*/
|
|
2361
|
+
static createCoil(operand, outID, negated="false", latch="none", edge="none", parent=null){
|
|
2362
|
+
var coil = new LdObject("Coil", operand, "", "", negated, latch, edge, "", null, parent);
|
|
2363
|
+
coil.Inputs.push(new ConnectionPointIn());
|
|
2364
|
+
coil.Outputs.push(new ConnectionPointOut(outID));
|
|
2365
|
+
return coil;
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
/**
|
|
2369
|
+
* Checks to see if an output point is connected to this object.
|
|
2370
|
+
* @param {string} refOutID The output ID to look for.
|
|
2371
|
+
* @returns {boolean} Returns true if the object is connected to the given output point ID.
|
|
2372
|
+
*/
|
|
2373
|
+
isConnectedTo(refOutID){
|
|
2374
|
+
var retval = false;
|
|
2375
|
+
try{
|
|
2376
|
+
forEachElem(this.Inputs, (point) => {
|
|
2377
|
+
if(retval) return;
|
|
2378
|
+
if(point.isConnectedTo(refOutID)){
|
|
2379
|
+
retval = true;
|
|
2380
|
+
}
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
catch(e){
|
|
2384
|
+
console.error(e);
|
|
2385
|
+
}
|
|
2386
|
+
return retval;
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
/**
|
|
2390
|
+
* Connects this object to an output point.
|
|
2391
|
+
* @param {string} outID The output point ID to connect to.
|
|
2392
|
+
* @param {string} invar Not used on this class.
|
|
2393
|
+
*/
|
|
2394
|
+
connectTo(outID, invar=""){
|
|
2395
|
+
try{
|
|
2396
|
+
var connected = false;
|
|
2397
|
+
forEachElem(this.Inputs, (point) => {
|
|
2398
|
+
if(connected) return;
|
|
2399
|
+
if(point.isConnectedTo(outID)){
|
|
2400
|
+
connected = true;
|
|
2401
|
+
}
|
|
2402
|
+
else{
|
|
2403
|
+
point.connectTo(outID);
|
|
2404
|
+
connected = true;
|
|
2405
|
+
}
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
catch(e){
|
|
2409
|
+
console.error(e);
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
/**
|
|
2414
|
+
* Disconnects the object from an output point.
|
|
2415
|
+
* @param {string} outID The ID of the output point.
|
|
2416
|
+
*/
|
|
2417
|
+
disconnect(outID){
|
|
2418
|
+
var found = false;
|
|
2419
|
+
forEachElem(this.Inputs, (point) => {
|
|
2420
|
+
if(found) return;
|
|
2421
|
+
if(point.isConnectedTo(outID)){
|
|
2422
|
+
point.disconnect(outID);
|
|
2423
|
+
found = true;
|
|
2424
|
+
}
|
|
2425
|
+
});
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
/**
|
|
2429
|
+
* Gets the output IDs for this object.
|
|
2430
|
+
* @returns {string[]} Returns an array of output IDs on this object.
|
|
2431
|
+
*/
|
|
2432
|
+
getOutputIDs(){
|
|
2433
|
+
var results = [];
|
|
2434
|
+
forEachElem(this.Outputs, (point) => {
|
|
2435
|
+
results.push(point.ID);
|
|
2436
|
+
});
|
|
2437
|
+
// results.sort((a, b) => {
|
|
2438
|
+
// return parseInt(a) - parseInt(b);
|
|
2439
|
+
// });
|
|
2440
|
+
return results;
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
/**
|
|
2444
|
+
* Checks to see if this object has the output.
|
|
2445
|
+
* @param {string} id The output ID to look for.
|
|
2446
|
+
* @returns {boolean} Returns true if the object does have the output.
|
|
2447
|
+
*/
|
|
2448
|
+
hasOutput(id){
|
|
2449
|
+
var ret = false;
|
|
2450
|
+
try{
|
|
2451
|
+
ret = isValid(this.getOutputIDs().find((v) => v == id));
|
|
2452
|
+
}
|
|
2453
|
+
catch(e){
|
|
2454
|
+
console.error(e);
|
|
2455
|
+
}
|
|
2456
|
+
return ret;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
/**
|
|
2460
|
+
* Gets the list of connected inputs, by the output ID they are connected to.
|
|
2461
|
+
* @returns {string[]} An array of output IDs.
|
|
2462
|
+
*/
|
|
2463
|
+
getInputIDs(){
|
|
2464
|
+
var results = [];
|
|
2465
|
+
forEachElem(this.Inputs, (point) => {
|
|
2466
|
+
forEachElem(point.Connections, (c) => {
|
|
2467
|
+
results.push(c.RefID);
|
|
2468
|
+
});
|
|
2469
|
+
});
|
|
2470
|
+
// results.sort((a, b) => {
|
|
2471
|
+
// return parseInt(a) - parseInt(b);
|
|
2472
|
+
// });
|
|
2473
|
+
return results;
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* Checks to see if this object is connected to an output ID on one of its inputs.
|
|
2477
|
+
* @param {string} id
|
|
2478
|
+
* @returns {boolean} Returns true if the object is connected to the output.
|
|
2479
|
+
*/
|
|
2480
|
+
hasInput(id){
|
|
2481
|
+
var ret = false;
|
|
2482
|
+
try{
|
|
2483
|
+
ret = isValid(this.getInputIDs().find((v) => v == id));
|
|
2484
|
+
}
|
|
2485
|
+
catch(e){
|
|
2486
|
+
console.error(e);
|
|
2487
|
+
}
|
|
2488
|
+
return ret;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
/**
|
|
2492
|
+
* Converts the object to its representation in Structured Text.
|
|
2493
|
+
* @param {string|null} expression The expression to assign to an operator, in the event of a coil, or if a contact.
|
|
2494
|
+
* @returns {string} A string representing the structured text code for this object.
|
|
2495
|
+
*/
|
|
2496
|
+
toST(expression){
|
|
2497
|
+
var st = "";
|
|
2498
|
+
try{
|
|
2499
|
+
switch(this.Type){
|
|
2500
|
+
case "Contact":
|
|
2501
|
+
if(this.Negated === "true"){
|
|
2502
|
+
st = "NOT ";
|
|
2503
|
+
}
|
|
2504
|
+
st += this.Operand;
|
|
2505
|
+
break;
|
|
2506
|
+
case "CompareContact":
|
|
2507
|
+
switch(this.Operator){
|
|
2508
|
+
case ">":
|
|
2509
|
+
st = `(${this.Operand1} > ${this.Operand2})`;
|
|
2510
|
+
break;
|
|
2511
|
+
case ">=":
|
|
2512
|
+
st = `(${this.Operand1} >= ${this.Operand2})`;
|
|
2513
|
+
break;
|
|
2514
|
+
case "=":
|
|
2515
|
+
st = `(${this.Operand1} = ${this.Operand2})`;
|
|
2516
|
+
break;
|
|
2517
|
+
case "<=":
|
|
2518
|
+
st = `(${this.Operand1} <= ${this.Operand2})`;
|
|
2519
|
+
break;
|
|
2520
|
+
case "<":
|
|
2521
|
+
st = `(${this.Operand1} < ${this.Operand2})`;
|
|
2522
|
+
break;
|
|
2523
|
+
case "<>":
|
|
2524
|
+
st = `(${this.Operand1} <> ${this.Operand2})`;
|
|
2525
|
+
break;
|
|
2526
|
+
}
|
|
2527
|
+
break;
|
|
2528
|
+
case "Coil":
|
|
2529
|
+
st = this.Operand + ` := `;
|
|
2530
|
+
if(this.Latch === "none"){
|
|
2531
|
+
if(this.Negated === "true"){
|
|
2532
|
+
st += "NOT ";
|
|
2533
|
+
}
|
|
2534
|
+
st += `(${expression})`;
|
|
2535
|
+
}
|
|
2536
|
+
else if(this.Latch === "set"){
|
|
2537
|
+
st = `IF (${expression}) THEN
|
|
2538
|
+
${this.Operand} + " := 1;"
|
|
2539
|
+
END_IF;`;
|
|
2540
|
+
}
|
|
2541
|
+
else if(this.Latch === "reset"){
|
|
2542
|
+
st = `IF (${expression}) THEN
|
|
2543
|
+
${this.Operand} + " := 0;"
|
|
2544
|
+
END_IF;`;
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
|
|
2548
|
+
break;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
catch(e){
|
|
2552
|
+
console.error(e);
|
|
2553
|
+
}
|
|
2554
|
+
return st;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
/**
|
|
2559
|
+
* Represents an input connection point in the IEC project file.
|
|
2560
|
+
*/
|
|
2561
|
+
export class ConnectionPointIn extends Serializable {
|
|
2562
|
+
/**
|
|
2563
|
+
* Creates a new ConnectionPointIn object.
|
|
2564
|
+
* @param {RelPosition?} RelPosition The relative position of the connection point, or null/undefined
|
|
2565
|
+
* @param {Connection[]?} connections An array of connections to the point, or null/undefined.
|
|
2566
|
+
*/
|
|
2567
|
+
constructor(RelPosition, connections) {
|
|
2568
|
+
super();
|
|
2569
|
+
this.TypeMap = {
|
|
2570
|
+
"RelPosition": RelPosition,
|
|
2571
|
+
"Connections": []
|
|
2572
|
+
};
|
|
2573
|
+
this.RelPosition = null;
|
|
2574
|
+
this.Connections = [];
|
|
2575
|
+
if(isValid(RelPosition)) this.RelPosition = RelPosition;
|
|
2576
|
+
if(isValid(connections)) this.Connections = connections;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
/**
|
|
2580
|
+
* Creates a new ConnectionPointIn object based on an xml element.
|
|
2581
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
2582
|
+
* @returns Returns a new ConnectionPointIn object.
|
|
2583
|
+
*/
|
|
2584
|
+
static fromXML(xml) {
|
|
2585
|
+
if(!isValid(xml)) return null;
|
|
2586
|
+
var rel = null;
|
|
2587
|
+
var con = null;
|
|
2588
|
+
if(xml.getElementsByTagName("RelPosition").length > 0){
|
|
2589
|
+
rel = RelPosition.fromXML(xml);
|
|
2590
|
+
}
|
|
2591
|
+
con = xml.getElementsByTagName("Connection");
|
|
2592
|
+
var cons = [];
|
|
2593
|
+
forEachElem(con, (e) => {
|
|
2594
|
+
cons.push(Connection.fromXML(e));
|
|
2595
|
+
});
|
|
2596
|
+
return new ConnectionPointIn(rel, cons);
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
/**
|
|
2600
|
+
*
|
|
2601
|
+
* @returns Returns an xml string representation of the object.
|
|
2602
|
+
*/
|
|
2603
|
+
toXML() {
|
|
2604
|
+
var relxml = "";
|
|
2605
|
+
var conxml = "";
|
|
2606
|
+
if(this.RelPosition != null){
|
|
2607
|
+
relxml = this.RelPosition.toXML();
|
|
2608
|
+
}
|
|
2609
|
+
forEachElem(this.Connections, (c) => {
|
|
2610
|
+
conxml += c.toXML() + "\n";
|
|
2611
|
+
});
|
|
2612
|
+
return `<ConnectionPointIn>
|
|
2613
|
+
${relxml}
|
|
2614
|
+
${conxml}
|
|
2615
|
+
</ConnectionPointIn>`;
|
|
2616
|
+
}
|
|
2617
|
+
/**
|
|
2618
|
+
* Checks to see if this connection point is connected to an output.
|
|
2619
|
+
* @param {string} refID The output ID to check for.
|
|
2620
|
+
* @returns {boolean} Returns true if it is connected.
|
|
2621
|
+
*/
|
|
2622
|
+
isConnectedTo(refID){
|
|
2623
|
+
return this.Connections.findIndex((c) => c.RefID == refID) > -1;
|
|
2624
|
+
}
|
|
2625
|
+
/**
|
|
2626
|
+
* Connects this point to a given output.
|
|
2627
|
+
* @param {string} refID The ID of the output.
|
|
2628
|
+
*/
|
|
2629
|
+
connectTo(refID){
|
|
2630
|
+
if(this.Connections.findIndex((c) => c.RefID == refID) == -1){
|
|
2631
|
+
this.Connections.push( new Connection(refID));
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
/**
|
|
2635
|
+
* Disconnects this point from an output.
|
|
2636
|
+
* @param {string} refID The output ID to disconnect from.
|
|
2637
|
+
*/
|
|
2638
|
+
disconnect(refID){
|
|
2639
|
+
var i = this.Connections.findIndex((c) => c.RefID == refID);
|
|
2640
|
+
if(i > -1){
|
|
2641
|
+
this.Connections.splice(i, 1);
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
/**
|
|
2648
|
+
* Represents an output connection point in the IEC Project file.
|
|
2649
|
+
*/
|
|
2650
|
+
export class ConnectionPointOut extends Serializable {
|
|
2651
|
+
/**
|
|
2652
|
+
* Constructs a new ConnectionPointOut object
|
|
2653
|
+
* @param {string?} id The connectionPointId attribute
|
|
2654
|
+
* @param {RelPosition?} relPosition The relative position.
|
|
2655
|
+
*/
|
|
2656
|
+
constructor(id, relPosition) {
|
|
2657
|
+
super();
|
|
2658
|
+
this.TypeMap = {
|
|
2659
|
+
"ID": "",
|
|
2660
|
+
"RelPosition": RelPosition
|
|
2661
|
+
};
|
|
2662
|
+
this.ID = "";
|
|
2663
|
+
this.RelPosition = null;
|
|
2664
|
+
if(isValid(id)) this.ID = id;
|
|
2665
|
+
if(isValid(relPosition)) this.RelPosition = relPosition;
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
/**
|
|
2669
|
+
* Creates a new ConnectionPointOut object based on the xml element.
|
|
2670
|
+
* @param {Element} xml An element object represneting the XML.
|
|
2671
|
+
* @returns Returns a new ConnectionPointOut object.
|
|
2672
|
+
*/
|
|
2673
|
+
static fromXML(xml) {
|
|
2674
|
+
if(!isValid(xml)) return null;
|
|
2675
|
+
var rel = null;
|
|
2676
|
+
if(xml.getElementsByTagName("RelPosition")[0] != null){
|
|
2677
|
+
rel = RelPosition.fromXML(xml.getElementsByTagName("RelPosition")[0]);
|
|
2678
|
+
}
|
|
2679
|
+
return new ConnectionPointOut(xml.getAttribute("connectionPointOutId"), rel);
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
/**
|
|
2683
|
+
*
|
|
2684
|
+
* @returns Returns an xml string representing the object.
|
|
2685
|
+
*/
|
|
2686
|
+
toXML() {
|
|
2687
|
+
var relxml = "";
|
|
2688
|
+
if(this.RelPosition != null)
|
|
2689
|
+
{
|
|
2690
|
+
relxml = this.RelPosition.toXML();
|
|
2691
|
+
}
|
|
2692
|
+
return `<ConnectionPointOut connectionPointOutId="${this.ID}">
|
|
2693
|
+
${relxml}
|
|
2694
|
+
</ConnectionPointOut>`;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
/**
|
|
2699
|
+
* Represents a size for connections/objects in the IEC project file.
|
|
2700
|
+
*/
|
|
2701
|
+
export class Size extends Serializable{
|
|
2702
|
+
/**
|
|
2703
|
+
* Constructs a new Size object
|
|
2704
|
+
* @param {string?} x The width, or null/undefined
|
|
2705
|
+
* @param {string?} y The height, or null/undefined
|
|
2706
|
+
*/
|
|
2707
|
+
constructor(x, y) {
|
|
2708
|
+
super();
|
|
2709
|
+
this.TypeMap = {
|
|
2710
|
+
"x": "",
|
|
2711
|
+
"y": ""
|
|
2712
|
+
};
|
|
2713
|
+
this.x = "";
|
|
2714
|
+
this.y = "";
|
|
2715
|
+
|
|
2716
|
+
if(isValid(x)) this.x = x;
|
|
2717
|
+
if(isValid(y)) this.y = y;
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
/**
|
|
2721
|
+
* Creates an Size object based on an XML element.
|
|
2722
|
+
* @param {Element} xml The element from which to create the object.
|
|
2723
|
+
* @returns A new Size object.
|
|
2724
|
+
*/
|
|
2725
|
+
static fromXML(xml) {
|
|
2726
|
+
if(!isValid(xml)) return null;
|
|
2727
|
+
return new Size(xml.getAttribute("x"), xml.getAttribute("y"));
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
/**
|
|
2731
|
+
*
|
|
2732
|
+
* @returns An XML string representing the object.
|
|
2733
|
+
*/
|
|
2734
|
+
toXML() {
|
|
2735
|
+
return `<Size x="${this.x}" y="${this.y}"/>`;
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
/**
|
|
2740
|
+
* Represents a relative position for connections/objects in the IEC project file.
|
|
2741
|
+
*/
|
|
2742
|
+
export class RelPosition extends Serializable{
|
|
2743
|
+
/**
|
|
2744
|
+
* Constructs a new RelPosition object
|
|
2745
|
+
* @param {string?} x The x coordinate for the position, or null/undefined
|
|
2746
|
+
* @param {string?} y The y coordinate for the position, or null/undefined
|
|
2747
|
+
*/
|
|
2748
|
+
constructor(x, y) {
|
|
2749
|
+
super();
|
|
2750
|
+
this.TypeMap = {
|
|
2751
|
+
"x": "",
|
|
2752
|
+
"y": ""
|
|
2753
|
+
};
|
|
2754
|
+
this.x = "0";
|
|
2755
|
+
this.y = "0";
|
|
2756
|
+
|
|
2757
|
+
if(isValid(x)) this.x = x;
|
|
2758
|
+
if(isValid(y)) this.y = y;
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
/**
|
|
2762
|
+
* Creates an RelPosition object based on an XML element.
|
|
2763
|
+
* @param {Element} xml The element from which to create the object.
|
|
2764
|
+
* @returns A new RelPosition object.
|
|
2765
|
+
*/
|
|
2766
|
+
static fromXML(xml) {
|
|
2767
|
+
if(!isValid(xml)) return null;
|
|
2768
|
+
return new RelPosition(xml.getAttribute("x"), xml.getAttribute("y"));
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
/**
|
|
2772
|
+
*
|
|
2773
|
+
* @returns An XML string representing the object.
|
|
2774
|
+
*/
|
|
2775
|
+
toXML() {
|
|
2776
|
+
return `<RelPosition x="${this.x}" y="${this.y}"/>`;
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
|
|
2781
|
+
/**
|
|
2782
|
+
* Represents a connection between an input and output in the IEC Project File.
|
|
2783
|
+
*/
|
|
2784
|
+
export class Connection extends Serializable{
|
|
2785
|
+
/**
|
|
2786
|
+
* Constructs a new Connection object
|
|
2787
|
+
* @param {string} refId A reference to the output connection point ID.
|
|
2788
|
+
*/
|
|
2789
|
+
constructor(refId) {
|
|
2790
|
+
super();
|
|
2791
|
+
this.TypeMap = {
|
|
2792
|
+
"RefID": ""
|
|
2793
|
+
};
|
|
2794
|
+
this.RefID = "";
|
|
2795
|
+
|
|
2796
|
+
if(isValid(refId)) this.RefID = refId;
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
/**
|
|
2800
|
+
* Creates an Connection object based on an XML element.
|
|
2801
|
+
* @param {Element} xml The element from which to create the object.
|
|
2802
|
+
* @returns A new Connection object.
|
|
2803
|
+
*/
|
|
2804
|
+
static fromXML(xml) {
|
|
2805
|
+
return new Connection(xml.getAttribute("refConnectionPointOutId"));
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
/**
|
|
2809
|
+
*
|
|
2810
|
+
* @returns An XML string representing the object.
|
|
2811
|
+
*/
|
|
2812
|
+
toXML() {
|
|
2813
|
+
return `<Connection refConnectionPointOutId="${this.RefID}"/>`;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
/**
|
|
2818
|
+
* Represents a function block diagram object in the IEC project file.
|
|
2819
|
+
*/
|
|
2820
|
+
export class FbdObject extends Serializable {
|
|
2821
|
+
|
|
2822
|
+
/**
|
|
2823
|
+
* @type {{TypeName: string, InputVariables: string[], OutputVariables: string[]}[]}
|
|
2824
|
+
*/
|
|
2825
|
+
static StandardBlocks = [
|
|
2826
|
+
{
|
|
2827
|
+
TypeName: "TON",
|
|
2828
|
+
InputVariables: ["IN", "PT"],
|
|
2829
|
+
OutputVariables: ["Q", "ET"]
|
|
2830
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
TypeName: "TOF",
|
|
2833
|
+
InputVariables: ["IN", "PT"],
|
|
2834
|
+
OutputVariables: ["Q", "ET"]
|
|
2835
|
+
},
|
|
2836
|
+
{
|
|
2837
|
+
TypeName: "TP",
|
|
2838
|
+
InputVariables: ["IN", "PT"],
|
|
2839
|
+
OutputVariables: ["Q", "ET"]
|
|
2840
|
+
},
|
|
2841
|
+
{
|
|
2842
|
+
TypeName: "OR",
|
|
2843
|
+
InputVariables: ["IN1", "IN2"],
|
|
2844
|
+
OutputVariables: ["OUT"]
|
|
2845
|
+
},
|
|
2846
|
+
{
|
|
2847
|
+
TypeName: "AND",
|
|
2848
|
+
InputVariables: ["IN1", "IN2"],
|
|
2849
|
+
OutputVariables: ["OUT"]
|
|
2850
|
+
},
|
|
2851
|
+
{
|
|
2852
|
+
TypeName: "ASSIGNMENT",
|
|
2853
|
+
InputVariables: ["IN"],
|
|
2854
|
+
OutputVariables: ["OUT"]
|
|
2855
|
+
},
|
|
2856
|
+
{
|
|
2857
|
+
TypeName: "NOT",
|
|
2858
|
+
InputVariables: ["IN"],
|
|
2859
|
+
OutputVariables: ["OUT"]
|
|
2860
|
+
},
|
|
2861
|
+
{
|
|
2862
|
+
TypeName: "XOR",
|
|
2863
|
+
InputVariables: ["IN1", "IN2"],
|
|
2864
|
+
OutputVariables: ["OUT"]
|
|
2865
|
+
},
|
|
2866
|
+
{
|
|
2867
|
+
TypeName: "NOR",
|
|
2868
|
+
InputVariables: ["IN1", "IN2"],
|
|
2869
|
+
OutputVariables: ["OUT"]
|
|
2870
|
+
},
|
|
2871
|
+
{
|
|
2872
|
+
TypeName: "NAND",
|
|
2873
|
+
InputVariables: ["IN1", "IN2"],
|
|
2874
|
+
OutputVariables: ["OUT"]
|
|
2875
|
+
},
|
|
2876
|
+
{
|
|
2877
|
+
TypeName: "SR",
|
|
2878
|
+
InputVariables: ["S1", "R"],
|
|
2879
|
+
OutputVariables: ["Q1"]
|
|
2880
|
+
},
|
|
2881
|
+
{
|
|
2882
|
+
TypeName: "RS",
|
|
2883
|
+
InputVariables: ["S", "R1"],
|
|
2884
|
+
OutputVariables: ["Q1"]
|
|
2885
|
+
},
|
|
2886
|
+
{
|
|
2887
|
+
TypeName: "R_TRIG",
|
|
2888
|
+
InputVariables: ["CLK"],
|
|
2889
|
+
OutputVariables: ["OUT"]
|
|
2890
|
+
},
|
|
2891
|
+
{
|
|
2892
|
+
TypeName: "F_TRIG",
|
|
2893
|
+
InputVariables: ["CLK"],
|
|
2894
|
+
OutputVariables: ["OUT"]
|
|
2895
|
+
},
|
|
2896
|
+
{
|
|
2897
|
+
TypeName: "CTU",
|
|
2898
|
+
InputVariables: ["CU", "R", "PV"],
|
|
2899
|
+
OutputVariables: ["Q", "CV"]
|
|
2900
|
+
},
|
|
2901
|
+
{
|
|
2902
|
+
TypeName: "CTD",
|
|
2903
|
+
InputVariables: ["CD", "LD", "PV"],
|
|
2904
|
+
OutputVariables: ["Q", "CV"]
|
|
2905
|
+
},
|
|
2906
|
+
{
|
|
2907
|
+
TypeName: "CTUD",
|
|
2908
|
+
InputVariables: ["CU", "CD", "R", "LD", "PV"],
|
|
2909
|
+
OutputVariables: ["QU", "QD", "CV"]
|
|
2910
|
+
},
|
|
2911
|
+
{
|
|
2912
|
+
TypeName: "EQ",
|
|
2913
|
+
InputVariables: ["IN1", "IN2"],
|
|
2914
|
+
OutputVariables: ["OUT"]
|
|
2915
|
+
},
|
|
2916
|
+
{
|
|
2917
|
+
TypeName: "NE",
|
|
2918
|
+
InputVariables: ["IN1, IN2"],
|
|
2919
|
+
OutputVariables: ["OUT"]
|
|
2920
|
+
},
|
|
2921
|
+
{
|
|
2922
|
+
TypeName: "LT",
|
|
2923
|
+
InputVariables: ["IN1", "IN2"],
|
|
2924
|
+
OutputVariables: ["OUT"]
|
|
2925
|
+
},
|
|
2926
|
+
{
|
|
2927
|
+
TypeName: "GT",
|
|
2928
|
+
InputVariables: ["IN1", "IN2"],
|
|
2929
|
+
OutputVariables: ["OUT"]
|
|
2930
|
+
},
|
|
2931
|
+
{
|
|
2932
|
+
TypeName: "GE",
|
|
2933
|
+
InputVariables: ["IN1", "IN2"],
|
|
2934
|
+
OutputVariables: ["OUT"]
|
|
2935
|
+
},
|
|
2936
|
+
{
|
|
2937
|
+
TypeName: "LE",
|
|
2938
|
+
InputVariables: ["IN1", "IN2"],
|
|
2939
|
+
OutputVariables: ["OUT"]
|
|
2940
|
+
},
|
|
2941
|
+
{
|
|
2942
|
+
TypeName: "MOVE",
|
|
2943
|
+
InputVariables: ["IN"],
|
|
2944
|
+
OutputVariables: ["OUT"]
|
|
2945
|
+
},
|
|
2946
|
+
{
|
|
2947
|
+
TypeName: "SEL",
|
|
2948
|
+
InputVariables: ["G", "IN0", "IN1"],
|
|
2949
|
+
OutputVariables: ["OUT"]
|
|
2950
|
+
},
|
|
2951
|
+
{
|
|
2952
|
+
TypeName: "MUX",
|
|
2953
|
+
InputVariables: ["K", "IN0", "IN1"],
|
|
2954
|
+
OutputVariables: ["OUT"]
|
|
2955
|
+
},
|
|
2956
|
+
{
|
|
2957
|
+
TypeName: "MIN",
|
|
2958
|
+
InputVariables: ["IN1", "IN2"],
|
|
2959
|
+
OutputVariables: ["OUT"]
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
TypeName: "MAX",
|
|
2963
|
+
InputVariables: ["IN1", "IN2"],
|
|
2964
|
+
OutputVariables: ["OUT"]
|
|
2965
|
+
},
|
|
2966
|
+
{
|
|
2967
|
+
TypeName: "LIMIT",
|
|
2968
|
+
InputVariables: ["MN", "IN", "MX"],
|
|
2969
|
+
OutputVariables: ["OUT"]
|
|
2970
|
+
},
|
|
2971
|
+
];
|
|
2972
|
+
|
|
2973
|
+
/**
|
|
2974
|
+
* Creates an instantiation of an FbdObject block based on the given properties.
|
|
2975
|
+
* @param {string} typeName The type of the FBD
|
|
2976
|
+
* @param {string} instanceName The instance name for the block.
|
|
2977
|
+
* @param {string[]} inputvars An array of input variable names. The input variables can be negated with the prefix "!"
|
|
2978
|
+
* @param {string[]} outvars An array of output variable names.
|
|
2979
|
+
* @param {Rung|Network} root The root rung or network to which this block is to be added.
|
|
2980
|
+
*/
|
|
2981
|
+
static createStandardBlock(typeName, instanceName, inputvars, outvars, root){
|
|
2982
|
+
|
|
2983
|
+
const height = FbdObject.BLOCK_HEIGHT + ((Math.max(inputvars.length, outvars.length) - 1) * FbdObject.SIZE_INC);
|
|
2984
|
+
const inputVariables = new InputVariables();
|
|
2985
|
+
const outputVariables = new OutputVariables();
|
|
2986
|
+
forEachElem(inputvars, (v) => {
|
|
2987
|
+
let vname = v;
|
|
2988
|
+
let negated = "false";
|
|
2989
|
+
if(v.startsWith("!")){
|
|
2990
|
+
vname = v.substring(1);
|
|
2991
|
+
negated = "true";
|
|
2992
|
+
}
|
|
2993
|
+
inputVariables.Variables.push(new InputVariable(vname, negated, new ConnectionPointIn()));
|
|
2994
|
+
});
|
|
2995
|
+
var startOut = root.findLastOutputID() + 1;
|
|
2996
|
+
forEachElem(outvars, (v) => {
|
|
2997
|
+
outputVariables.Variables.push(new OutputVariable(v, new ConnectionPointOut(startOut)));
|
|
2998
|
+
startOut++;
|
|
2999
|
+
});
|
|
3000
|
+
return new FbdObject("Block", instanceName, typeName, instanceName,
|
|
3001
|
+
new Size(FbdObject.BLOCK_WIDTH, height),
|
|
3002
|
+
new RelPosition(root.findGreatestX() + FbdObject.BLOCK_WIDTH, root.findGreatestY()),
|
|
3003
|
+
inputVariables,
|
|
3004
|
+
outputVariables,
|
|
3005
|
+
null, null, root
|
|
3006
|
+
);
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
/**
|
|
3010
|
+
* Creates a new FbdObject based on the definition provided by a function block.
|
|
3011
|
+
* @param {FunctionBlock} functionBlock The function block from which to create the object.
|
|
3012
|
+
* @param {Rung|Network} root The root/parent of the object.
|
|
3013
|
+
*/
|
|
3014
|
+
static createCustomBlock(functionBlock, root){
|
|
3015
|
+
const inputVariables = new InputVariables();
|
|
3016
|
+
const outputVariables = new OutputVariables();
|
|
3017
|
+
forEachElem(functionBlock.Parameters.InputVars.Variables, (v) => {
|
|
3018
|
+
inputVariables.Variables.push(new InputVariable(v.Name, "false", new ConnectionPointIn()));
|
|
3019
|
+
});
|
|
3020
|
+
var startOut = root.findLastOutputID() + 1;
|
|
3021
|
+
|
|
3022
|
+
forEachElem(functionBlock.Parameters.OutputVars.Variables, (v) => {
|
|
3023
|
+
outputVariables.Variables.push(new OutputVariable(v.Name, new ConnectionPointOut(startOut)));
|
|
3024
|
+
startOut++;
|
|
3025
|
+
});
|
|
3026
|
+
const height = FbdObject.BLOCK_HEIGHT + ((Math.max(inputVariables.Variables.length, outputVariables.Variables.length) - 1) * FbdObject.SIZE_INC);
|
|
3027
|
+
|
|
3028
|
+
return new FbdObject("Block", instanceName, typeName, instanceName,
|
|
3029
|
+
new Size(FbdObject.BLOCK_WIDTH, height),
|
|
3030
|
+
new RelPosition(root.findGreatestX() + FbdObject.BLOCK_WIDTH, root.findGreatestY()),
|
|
3031
|
+
inputVariables,
|
|
3032
|
+
outputVariables,
|
|
3033
|
+
null, null, root
|
|
3034
|
+
);
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
/**
|
|
3038
|
+
* Creates a new FBD object of the datasource type.
|
|
3039
|
+
* @param {string} identifier The identifier of the data source.
|
|
3040
|
+
* @param {LdObject|FbdObject} root The root rung or network to which this datasource belongs.
|
|
3041
|
+
* @returns
|
|
3042
|
+
*/
|
|
3043
|
+
static createDataSource(identifier, root){
|
|
3044
|
+
const BASE_WIDTH = 48, BASE_HEIGHT = 24;
|
|
3045
|
+
return new FbdObject("DataSource", identifier, "", "",
|
|
3046
|
+
new Size(BASE_WIDTH, BASE_HEIGHT),
|
|
3047
|
+
new RelPosition(root.findGreatestX() + (BASE_WIDTH*2), root.findGreatestY()),
|
|
3048
|
+
null, null, null,
|
|
3049
|
+
[
|
|
3050
|
+
new ConnectionPointOut(root.findLastOutputID() + 1)
|
|
3051
|
+
], root);
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
/**
|
|
3055
|
+
* Creates a new FBD object of the datasink type.
|
|
3056
|
+
* @param {string} identifier The identifier of the data sink.
|
|
3057
|
+
* @param {LdObject|FbdObject} root The root rung or network to which this sink belongs.
|
|
3058
|
+
* @returns
|
|
3059
|
+
*/
|
|
3060
|
+
static createDataSink(identifier, root){
|
|
3061
|
+
const BASE_WIDTH = 48, BASE_HEIGHT = 24;
|
|
3062
|
+
return new FbdObject("DataSink", identifier, "", "",
|
|
3063
|
+
new Size(BASE_WIDTH, BASE_HEIGHT),
|
|
3064
|
+
new RelPosition(root.findGreatestX() + (BASE_WIDTH*2), root.findGreatestY()),
|
|
3065
|
+
null, null,
|
|
3066
|
+
[
|
|
3067
|
+
new ConnectionPointIn()
|
|
3068
|
+
],
|
|
3069
|
+
null, root);
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
|
|
3073
|
+
/**
|
|
3074
|
+
* Constructs a new FbdObject
|
|
3075
|
+
* @param {string?} type The type of object, or null/undefined.
|
|
3076
|
+
* @param {string?} identifier The identifier for the object, or null/undefined
|
|
3077
|
+
* @param {Size?} size the size of the object, or null/undefined
|
|
3078
|
+
* @param {RelPosition?} relPosition the relative position of the object, or null/undefined
|
|
3079
|
+
* @param {InputVariables?} invars the input variables of the object, or null/undefined
|
|
3080
|
+
* @param {OutputVariables?} outvars the output variables of the object, or null/undefined
|
|
3081
|
+
* @param {ConnectionPointIn[]?} inputs An array of ConnectionPointIn objects, or null/undefined
|
|
3082
|
+
* @param {ConnectionPointOut[]?} outputs An array of ConnectionPointOut objects, or null/undefined
|
|
3083
|
+
* @param {Rung|Network|null} parent The parent object that contains this object or null/undefined.
|
|
3084
|
+
*/
|
|
3085
|
+
constructor(type, identifier, typeName, instanceName, size, relPosition, invars, outvars, inputs, outputs, parent) {
|
|
3086
|
+
super();
|
|
3087
|
+
this.TypeMap = {
|
|
3088
|
+
"Type": "",
|
|
3089
|
+
"Identifier": "",
|
|
3090
|
+
"TypeName": "",
|
|
3091
|
+
"InstanceName": "",
|
|
3092
|
+
"Inputs": [],
|
|
3093
|
+
"Outputs": [],
|
|
3094
|
+
"InputVariables": InputVariables,
|
|
3095
|
+
"OutputVariables": OutputVariables,
|
|
3096
|
+
"Size": Size,
|
|
3097
|
+
"RelPosition": RelPosition
|
|
3098
|
+
};
|
|
3099
|
+
this.ID = generateGUID();
|
|
3100
|
+
this.Type = "";
|
|
3101
|
+
this.Identifier = "";
|
|
3102
|
+
this.TypeName = "";
|
|
3103
|
+
this.InstanceName = "";
|
|
3104
|
+
this.Inputs = [];
|
|
3105
|
+
this.Outputs = [];
|
|
3106
|
+
this.InputVariables = new InputVariables();
|
|
3107
|
+
this.OutputVariables = new OutputVariables();
|
|
3108
|
+
this.Size = null;
|
|
3109
|
+
this.RelPosition = new RelPosition(0, 0);
|
|
3110
|
+
this.Parent = null;
|
|
3111
|
+
|
|
3112
|
+
if(isValid(type)) this.Type = type;
|
|
3113
|
+
if(isValid(identifier)) this.Identifier = identifier;
|
|
3114
|
+
if(isValid(size)) this.Size = size;
|
|
3115
|
+
if(isValid(relPosition)) this.RelPosition = relPosition;
|
|
3116
|
+
if(isValid(invars)) this.InputVariables = invars;
|
|
3117
|
+
if(isValid(outvars)) this.OutputVariables = outvars;
|
|
3118
|
+
if(isValid(inputs) && type !== "Block") this.Inputs = inputs;
|
|
3119
|
+
if(isValid(outputs) && type !== "Block") this.Outputs = outputs;
|
|
3120
|
+
if(isValid(typeName)) this.TypeName = typeName;
|
|
3121
|
+
if(isValid(instanceName)) this.InstanceName = instanceName;
|
|
3122
|
+
if(isValid(parent)) this.Parent = parent;
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
/**
|
|
3126
|
+
* Creates a new FbdObject from the element.
|
|
3127
|
+
* @param {Element} xml The xml element to create the object from.
|
|
3128
|
+
* @param {Rung|Network} parent The containing object for this object.
|
|
3129
|
+
* @returns Returns null if the xml is invalid, or returns a new FbdObject.
|
|
3130
|
+
*/
|
|
3131
|
+
static fromXML(xml, parent) {
|
|
3132
|
+
if(!isValid(xml)) return null;
|
|
3133
|
+
var inxml = xml.getElementsByTagName("ConnectionPointIn");
|
|
3134
|
+
var outxml = xml.getElementsByTagName("ConnectionPointOut");
|
|
3135
|
+
var conins = [];
|
|
3136
|
+
var conouts = [];
|
|
3137
|
+
forEachElem(inxml, (c) => {
|
|
3138
|
+
conins.push(ConnectionPointIn.fromXML(c));
|
|
3139
|
+
});
|
|
3140
|
+
forEachElem(outxml, (c) => {
|
|
3141
|
+
conouts.push(ConnectionPointOut.fromXML(c));
|
|
3142
|
+
});
|
|
3143
|
+
return new FbdObject(
|
|
3144
|
+
xml.getAttribute("xsi:type"),
|
|
3145
|
+
xml.getAttribute("identifier"),
|
|
3146
|
+
xml.getAttribute("typeName"),
|
|
3147
|
+
xml.getAttribute("instanceName"),
|
|
3148
|
+
Size.fromXML(xml.getElementsByTagName("Size").item(0)),
|
|
3149
|
+
RelPosition.fromXML(xml.getElementsByTagName("RelPosition").item(0)),
|
|
3150
|
+
InputVariables.fromXML(xml.getElementsByTagName("InputVariables").item(0)),
|
|
3151
|
+
OutputVariables.fromXML(xml.getElementsByTagName("OutputVariables").item(0)),
|
|
3152
|
+
conins, conouts,
|
|
3153
|
+
parent
|
|
3154
|
+
);
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
/**
|
|
3158
|
+
*
|
|
3159
|
+
* @returns Returns an xml string representing the object.
|
|
3160
|
+
*/
|
|
3161
|
+
toXML() {
|
|
3162
|
+
|
|
3163
|
+
var inputs = "";
|
|
3164
|
+
var outputs = "";
|
|
3165
|
+
forEachElem(this.Inputs, (elem) => {
|
|
3166
|
+
inputs += elem.toXML() + "\n";
|
|
3167
|
+
});
|
|
3168
|
+
forEachElem(this.Outputs, (elem) => {
|
|
3169
|
+
outputs += elem.toXML() + "\n";
|
|
3170
|
+
});
|
|
3171
|
+
|
|
3172
|
+
return `<FbdObject xsi:type="${this.Type}" identifier="${this.Identifier}" typeName="${this.TypeName}" instanceName="${this.InstanceName}">
|
|
3173
|
+
${this.RelPosition.toXML()}
|
|
3174
|
+
${this.InputVariables?.toXML()}
|
|
3175
|
+
${this.OutputVariables?.toXML()}
|
|
3176
|
+
${inputs}
|
|
3177
|
+
${outputs}
|
|
3178
|
+
</FbdObject>`;
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
/**
|
|
3182
|
+
* Checks to see if an output is connected to this object.
|
|
3183
|
+
* @param {string} refOutID The output ID to check for.
|
|
3184
|
+
* @returns {string} If the output ID is connected on an input variable, the function returns the input variable name.
|
|
3185
|
+
* If it is connected on an input point, it returns the ID. If it is not connected, it returns an empty string.
|
|
3186
|
+
*/
|
|
3187
|
+
isConnectedTo(refOutID){
|
|
3188
|
+
var retval = "";
|
|
3189
|
+
try{
|
|
3190
|
+
if(this.Type === "Block")
|
|
3191
|
+
retval = this.InputVariables.isConnectedTo(refOutID);
|
|
3192
|
+
else{
|
|
3193
|
+
forEachElem(this.Inputs,
|
|
3194
|
+
/**
|
|
3195
|
+
*
|
|
3196
|
+
* @param {ConnectionPointIn} i
|
|
3197
|
+
*/
|
|
3198
|
+
(i) => {
|
|
3199
|
+
forEachElem(i.Connections, (c) => {
|
|
3200
|
+
if(c.RefID === refOutID){
|
|
3201
|
+
retval = c.RefID;
|
|
3202
|
+
}
|
|
3203
|
+
});
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
catch(e){
|
|
3208
|
+
console.error(e);
|
|
3209
|
+
}
|
|
3210
|
+
return retval;
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3213
|
+
/**
|
|
3214
|
+
* Connects this object to an output ID.
|
|
3215
|
+
* @param {string} outID The output ID to connect to.
|
|
3216
|
+
* @param {string} invar The input variable on which to connect. If blank, the function connects the output to an input.
|
|
3217
|
+
*/
|
|
3218
|
+
connectTo(outID, invar=""){
|
|
3219
|
+
try{
|
|
3220
|
+
if(invar.length > 0){
|
|
3221
|
+
|
|
3222
|
+
this.InputVariables.connectTo(outID, invar);
|
|
3223
|
+
}
|
|
3224
|
+
else{
|
|
3225
|
+
var connected = false;
|
|
3226
|
+
forEachElem(this.Inputs, (point) => {
|
|
3227
|
+
if(connected) return;
|
|
3228
|
+
if(point.isConnectedTo(outID)){
|
|
3229
|
+
connected = true;
|
|
3230
|
+
}
|
|
3231
|
+
else{
|
|
3232
|
+
point.connectTo(outID);
|
|
3233
|
+
connected = true;
|
|
3234
|
+
}
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
catch(e){
|
|
3239
|
+
console.error(e);
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
/**
|
|
3244
|
+
* Disconnects the output from the object.
|
|
3245
|
+
* @param {string} outID The output to disconnect.
|
|
3246
|
+
*/
|
|
3247
|
+
disconnect(outID){
|
|
3248
|
+
var found = false;
|
|
3249
|
+
forEachElem(this.Inputs, (point) => {
|
|
3250
|
+
if(found) return;
|
|
3251
|
+
if(point.isConnectedTo(outID)){
|
|
3252
|
+
point.disconnect(outID);
|
|
3253
|
+
found = true;
|
|
3254
|
+
}
|
|
3255
|
+
});
|
|
3256
|
+
if(!found){
|
|
3257
|
+
this.InputVariables.disconnect(outID);
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
|
|
3262
|
+
/**
|
|
3263
|
+
* Creates an array of output IDs for this object.
|
|
3264
|
+
* @returns {string[]} An array of output IDs for this object.
|
|
3265
|
+
*/
|
|
3266
|
+
getOutputIDs(){
|
|
3267
|
+
var results = [];
|
|
3268
|
+
forEachElem(this.Outputs, (point) => {
|
|
3269
|
+
results.push(point.ID);
|
|
3270
|
+
});
|
|
3271
|
+
forEachElem(this.OutputVariables.Variables, (v) => {
|
|
3272
|
+
results.push(v.OutputPoint.ID);
|
|
3273
|
+
});
|
|
3274
|
+
// results.sort((a, b) => {
|
|
3275
|
+
// return parseInt(a) - parseInt(b);
|
|
3276
|
+
// });
|
|
3277
|
+
return results;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
/**
|
|
3281
|
+
* Checks to see if this object has the given output ID.
|
|
3282
|
+
* @param {string} id
|
|
3283
|
+
* @returns {boolean} Returns true if the object has the output.
|
|
3284
|
+
*/
|
|
3285
|
+
hasOutput(id){
|
|
3286
|
+
var ret = false;
|
|
3287
|
+
try{
|
|
3288
|
+
ret = isValid(this.getOutputIDs().find((v) => v == id));
|
|
3289
|
+
}
|
|
3290
|
+
catch(e){
|
|
3291
|
+
console.error(e);
|
|
3292
|
+
}
|
|
3293
|
+
return ret;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
/**
|
|
3297
|
+
* Gets an array of output IDs to which this object's inputs are connected.
|
|
3298
|
+
* @returns {string[]} An array of IDs.
|
|
3299
|
+
*/
|
|
3300
|
+
getInputIDs(){
|
|
3301
|
+
var results = [];
|
|
3302
|
+
forEachElem(this.Inputs, (point) => {
|
|
3303
|
+
forEachElem(point.Connections, (c) => {
|
|
3304
|
+
results.push(c.RefID);
|
|
3305
|
+
});
|
|
3306
|
+
});
|
|
3307
|
+
forEachElem(this.InputVariables.Variables, (v) => {
|
|
3308
|
+
forEachElem(v.InputPoint.Connections, (c) => {
|
|
3309
|
+
|
|
3310
|
+
results.push(c.RefID);
|
|
3311
|
+
});
|
|
3312
|
+
});
|
|
3313
|
+
// results.sort((a, b) => {
|
|
3314
|
+
// return parseInt(a) - parseInt(b);
|
|
3315
|
+
// });
|
|
3316
|
+
return results;
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
/**
|
|
3320
|
+
* Checks to see if this object is connected to an output ID.
|
|
3321
|
+
* @param {string} id The output ID to look for.
|
|
3322
|
+
* @returns {boolean} Returns true if the object has an input for the given output ID.
|
|
3323
|
+
*/
|
|
3324
|
+
hasInput(id){
|
|
3325
|
+
var ret = false;
|
|
3326
|
+
try{
|
|
3327
|
+
ret = isValid(this.getInputIDs().find((v) => v == id));
|
|
3328
|
+
}
|
|
3329
|
+
catch(e){
|
|
3330
|
+
console.error(e);
|
|
3331
|
+
}
|
|
3332
|
+
return ret;
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
/**
|
|
3336
|
+
* Converts the object to structured text code, based on the variable provided.
|
|
3337
|
+
* If the variable is an input variable, or it is empty and this is a datasink, then the function creates an assignment based on the provided expression.
|
|
3338
|
+
* If the variable is an output, or it is empty and this is a datasource, it creates the expression for assignment.
|
|
3339
|
+
* @param {string} variable The variable name to create ST for. If empty and this is a datasource or datasink, then
|
|
3340
|
+
* @param {string} expression The expression to assign to an input variable or datasink.
|
|
3341
|
+
* @returns {string} Returns a string representing the structured text code for the object.
|
|
3342
|
+
*/
|
|
3343
|
+
toST(variable = "", expression=""){
|
|
3344
|
+
var st = "";
|
|
3345
|
+
try{
|
|
3346
|
+
switch(this.Type){
|
|
3347
|
+
case "DataSource":
|
|
3348
|
+
st = this.Identifier;
|
|
3349
|
+
break;
|
|
3350
|
+
case "DataSink":
|
|
3351
|
+
st = `${this.Identifier} := (${expression})`;
|
|
3352
|
+
break;
|
|
3353
|
+
case "Block":
|
|
3354
|
+
var v = this.InputVariables.Variables.find((val) => val.ParameterName === variable);
|
|
3355
|
+
if(isValid(v)){
|
|
3356
|
+
if(v.Negated === "true"){
|
|
3357
|
+
st = "NOT ";
|
|
3358
|
+
}
|
|
3359
|
+
st += `${this.InstanceName}.${variable} := ${expression}`;
|
|
3360
|
+
}
|
|
3361
|
+
else{
|
|
3362
|
+
v = this.OutputVariables.Variables.find((val) => val.ParameterName === variable);
|
|
3363
|
+
if(isValid(v)){
|
|
3364
|
+
st = `${this.InstanceName}.${variable}`;
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
break;
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
catch(e){
|
|
3371
|
+
console.error(e);
|
|
3372
|
+
}
|
|
3373
|
+
return st;
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
/**
|
|
3378
|
+
* Represents a CommonObject element in an IEC project file.
|
|
3379
|
+
*/
|
|
3380
|
+
export class CommonObject extends Serializable{
|
|
3381
|
+
/**
|
|
3382
|
+
* Constructs a new CommonObject object.
|
|
3383
|
+
* @param {string} type The type of the object, or null/undefined
|
|
3384
|
+
* @param {RelPosition} relPosition the relative position of the object, or null/undefined
|
|
3385
|
+
* @param {Content} content The content of the object, or null/undefined
|
|
3386
|
+
*/
|
|
3387
|
+
constructor(type, relPosition, content) {
|
|
3388
|
+
super();
|
|
3389
|
+
this.TypeMap = {
|
|
3390
|
+
"Type": "",
|
|
3391
|
+
"RelPosition": RelPosition,
|
|
3392
|
+
"Content": Content
|
|
3393
|
+
};
|
|
3394
|
+
this.Type = "Comment";
|
|
3395
|
+
this.RelPosition = null;
|
|
3396
|
+
this.Content = null;
|
|
3397
|
+
if(isValid(type)) this.Type = type;
|
|
3398
|
+
if(isValid(this.RelPosition)) this.RelPosition = relPosition;
|
|
3399
|
+
if(isValid(this.Content)) this.Content = content;
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
/**
|
|
3403
|
+
* Creates a new CommonObject object based on the given xml Element.
|
|
3404
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
3405
|
+
* @returns Returns a new CommonObject object, or null if the XML is not valid.
|
|
3406
|
+
*/
|
|
3407
|
+
static fromXML(xml) {
|
|
3408
|
+
if(!isValid(xml)) return null;
|
|
3409
|
+
return new CommonObject(
|
|
3410
|
+
xml.getAttribute("xsi:type"),
|
|
3411
|
+
RelPosition.fromXML(xml.getElementsByTagName("RelPosition")[0]),
|
|
3412
|
+
Content.fromXML(xml.getElementsByTagName("Content")[0])
|
|
3413
|
+
);
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
/**
|
|
3417
|
+
*
|
|
3418
|
+
* @returns Returns a string of xml representing the object.
|
|
3419
|
+
*/
|
|
3420
|
+
toXML() {
|
|
3421
|
+
return `<CommonObject xsi:type="${this.Type}">
|
|
3422
|
+
${this.RelPosition ? this.RelPosition.toXML() : ""}
|
|
3423
|
+
${this.Content ? this.Content.toXML() : ""}
|
|
3424
|
+
</CommonObject>`;
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
/**
|
|
3429
|
+
* Represents a Content element of the IEC project file.
|
|
3430
|
+
*/
|
|
3431
|
+
export class Content extends Serializable{
|
|
3432
|
+
/**
|
|
3433
|
+
* Constructs a new Content object.
|
|
3434
|
+
* @param {string} type The type for the content, or null/undefined
|
|
3435
|
+
* @param {string} content The content of the object, or null/undefined
|
|
3436
|
+
*/
|
|
3437
|
+
constructor(type, content){
|
|
3438
|
+
super();
|
|
3439
|
+
this.TypeMap = {
|
|
3440
|
+
"Type": "",
|
|
3441
|
+
"Content": ""
|
|
3442
|
+
};
|
|
3443
|
+
this.Type = "SimpleText";
|
|
3444
|
+
this.Content = "";
|
|
3445
|
+
if(isValid(type)) this.Type = type;
|
|
3446
|
+
if(isValid(content)) this.Content = content;
|
|
3447
|
+
}
|
|
3448
|
+
/**
|
|
3449
|
+
* Creates a new Content object based on the xml element.
|
|
3450
|
+
* @param {Element} xml The element from which to create the object.
|
|
3451
|
+
* @returns returns a new Content object, or null if the xml is not valid.
|
|
3452
|
+
*/
|
|
3453
|
+
static fromXML(xml){
|
|
3454
|
+
if(!isValid(xml)) return null;
|
|
3455
|
+
return new Content(xml.getAttribute("xsi:type"), xml.textContent);
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3458
|
+
/**
|
|
3459
|
+
*
|
|
3460
|
+
* @returns Returns an xml string representing the content object.
|
|
3461
|
+
*/
|
|
3462
|
+
toXML(){
|
|
3463
|
+
return `<Content xsi:type="${this.Type}>
|
|
3464
|
+
${this.Content}
|
|
3465
|
+
</Content>`;
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/**
|
|
3470
|
+
* Represents a Parameters element in the IEC project file.
|
|
3471
|
+
*/
|
|
3472
|
+
export class Parameters extends Serializable {
|
|
3473
|
+
/**
|
|
3474
|
+
* Constructs a new Parameters object.
|
|
3475
|
+
* @param {OutputVars} outputVars An OutputVars object, or null/undefined.
|
|
3476
|
+
* @param {InputVars} inputVars an InputVars object, or null/undefined;
|
|
3477
|
+
*/
|
|
3478
|
+
constructor(outputVars, inputVars) {
|
|
3479
|
+
super();
|
|
3480
|
+
this.TypeMap = {
|
|
3481
|
+
"InputVars": InputVars,
|
|
3482
|
+
"OutputVars": OutputVars
|
|
3483
|
+
};
|
|
3484
|
+
this.InputVars = new InputVars();
|
|
3485
|
+
this.OutputVars = new OutputVars();
|
|
3486
|
+
|
|
3487
|
+
if(isValid(outputVars)) this.OutputVars = outputVars;
|
|
3488
|
+
if(isValid(inputVars)) this.InputVars = inputVars;
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
/**
|
|
3492
|
+
* Creates a new Parameters object based on an xml element.
|
|
3493
|
+
* @param {Element} xml The XML element to create the object from.
|
|
3494
|
+
* @returns Returns a new Parameters object, or null if the xml is invalid.
|
|
3495
|
+
*/
|
|
3496
|
+
static fromXML(xml) {
|
|
3497
|
+
if(!isValid(xml)) return null;
|
|
3498
|
+
return new Parameters(
|
|
3499
|
+
OutputVars.fromXML(xml.getElementsByTagName("OutputVars")[0]),
|
|
3500
|
+
InputVars.fromXML(xml.getElementsByTagName("InputVars")[0])
|
|
3501
|
+
);
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
/**
|
|
3505
|
+
*
|
|
3506
|
+
* @returns Returns a string of xml representing the object.
|
|
3507
|
+
*/
|
|
3508
|
+
toXML() {
|
|
3509
|
+
return `<Parameters>
|
|
3510
|
+
${this.OutputVars.toXML()}
|
|
3511
|
+
${this.InputVars.toXML()}
|
|
3512
|
+
</Parameters>`;
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
|
|
3516
|
+
/**
|
|
3517
|
+
* Represents an InputVariables element in the IEC project file.
|
|
3518
|
+
*/
|
|
3519
|
+
export class InputVariables extends Serializable {
|
|
3520
|
+
/**
|
|
3521
|
+
* Constructs a new InputVariables object.
|
|
3522
|
+
* @param {InputVariable[]?} variables An array of InputVariable objects, or null/undefined;
|
|
3523
|
+
*/
|
|
3524
|
+
constructor(variables) {
|
|
3525
|
+
super();
|
|
3526
|
+
this.TypeMap = {
|
|
3527
|
+
"Variables": []
|
|
3528
|
+
};
|
|
3529
|
+
this.Variables = [];
|
|
3530
|
+
if(isValid(variables)) this.Variables = variables;
|
|
3531
|
+
}
|
|
3532
|
+
/**
|
|
3533
|
+
* Creates a new InputVariables object from an xml element.
|
|
3534
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
3535
|
+
* @returns Returns a new InputVariables object, or null if the xml is invalid.
|
|
3536
|
+
*/
|
|
3537
|
+
static fromXML(xml) {
|
|
3538
|
+
if(!isValid(xml)) return null;
|
|
3539
|
+
var vars = xml.getElementsByTagName("InputVariable");
|
|
3540
|
+
var invars = [];
|
|
3541
|
+
forEachElem(vars, (v) => {
|
|
3542
|
+
invars.push(InputVariable.fromXML(v));
|
|
3543
|
+
});
|
|
3544
|
+
return new InputVariables(invars);
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3547
|
+
/**
|
|
3548
|
+
*
|
|
3549
|
+
* @returns Returns a string of xml that represents the object.
|
|
3550
|
+
*/
|
|
3551
|
+
toXML() {
|
|
3552
|
+
return `<InputVariables>
|
|
3553
|
+
${this.Variables.map(v => v.toXML()).join("\n")}
|
|
3554
|
+
</InputVariables>`;
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
/**
|
|
3558
|
+
* Checks to see if one of the input variables is connected to the given output ID.
|
|
3559
|
+
* @param {string} refID The output ID to check.
|
|
3560
|
+
* @returns {string} Returns the name of the variable if connected, or an empty string if not.
|
|
3561
|
+
*/
|
|
3562
|
+
isConnectedTo(refID){
|
|
3563
|
+
var retval = "";
|
|
3564
|
+
try{
|
|
3565
|
+
forEachElem(this.Variables, (v) => {
|
|
3566
|
+
if(retval.length > 0){
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
retval = v.isConnectedTo(refID);
|
|
3570
|
+
|
|
3571
|
+
});
|
|
3572
|
+
}
|
|
3573
|
+
catch(e){
|
|
3574
|
+
console.error(e);
|
|
3575
|
+
}
|
|
3576
|
+
return retval;
|
|
3577
|
+
}
|
|
3578
|
+
|
|
3579
|
+
/**
|
|
3580
|
+
* Connects an output to a given input variable.
|
|
3581
|
+
* @param {string} refID The output ID to connect to.
|
|
3582
|
+
* @param {string} invar The input variable to connect the output to.
|
|
3583
|
+
*/
|
|
3584
|
+
connectTo(refID, invar){
|
|
3585
|
+
try{
|
|
3586
|
+
if(invar.length == 0) return;
|
|
3587
|
+
var found = false;
|
|
3588
|
+
forEachElem(this.Variables, (v) => {
|
|
3589
|
+
if(found) return;
|
|
3590
|
+
if(v.ParameterName == invar){
|
|
3591
|
+
v.connectTo(refID);
|
|
3592
|
+
found = true;
|
|
3593
|
+
}
|
|
3594
|
+
});
|
|
3595
|
+
}
|
|
3596
|
+
catch(e){
|
|
3597
|
+
console.error(e);
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
/**
|
|
3602
|
+
* Disconnects the output from one of the input variables.
|
|
3603
|
+
* @param {string} refID The output ID to disconnect.
|
|
3604
|
+
*/
|
|
3605
|
+
disconnect(refID){
|
|
3606
|
+
forEachElem(this.Variables, (v) => {
|
|
3607
|
+
if(v.isConnectedTo(refID)){
|
|
3608
|
+
v.disconnect(refID);
|
|
3609
|
+
}
|
|
3610
|
+
});
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
/**
|
|
3615
|
+
* Represents an OutputVariables element in an IEC project file.
|
|
3616
|
+
*/
|
|
3617
|
+
export class OutputVariables extends Serializable {
|
|
3618
|
+
/**
|
|
3619
|
+
* Constructs a new OutputVariables object.
|
|
3620
|
+
* @param {OutputVariable[]} variables An array of OutputVariable objects, or null/undefined
|
|
3621
|
+
*/
|
|
3622
|
+
constructor(variables) {
|
|
3623
|
+
super();
|
|
3624
|
+
this.TypeMap = {
|
|
3625
|
+
"Variables": []
|
|
3626
|
+
};
|
|
3627
|
+
this.Variables = [];
|
|
3628
|
+
if(isValid(variables)) this.Variables = variables;
|
|
3629
|
+
}
|
|
3630
|
+
/**
|
|
3631
|
+
* Creates a new OutputVariables object from an xml element.
|
|
3632
|
+
* @param {Element} xml The xml element from which to create an object.
|
|
3633
|
+
* @returns Returns a new OutputVariables object, or null if the xml is invalid.
|
|
3634
|
+
*/
|
|
3635
|
+
static fromXML(xml) {
|
|
3636
|
+
if(!isValid(xml)) return null;
|
|
3637
|
+
var vars = xml.getElementsByTagName("OutputVariable");
|
|
3638
|
+
var outvars = [];
|
|
3639
|
+
forEachElem(vars, (v) => {
|
|
3640
|
+
outvars.push(OutputVariable.fromXML(v));
|
|
3641
|
+
});
|
|
3642
|
+
return new OutputVariables(outvars);
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3645
|
+
/**
|
|
3646
|
+
*
|
|
3647
|
+
* @returns Returns an xml string representing the object.
|
|
3648
|
+
*/
|
|
3649
|
+
toXML() {
|
|
3650
|
+
return `<OutputVariables>
|
|
3651
|
+
${this.Variables.map(v => v.toXML()).join("\n")}
|
|
3652
|
+
</OutputVariables>`;
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
/**
|
|
3657
|
+
* Represents a Vars element in the IEC project file.
|
|
3658
|
+
*/
|
|
3659
|
+
export class Vars extends Serializable{
|
|
3660
|
+
/**
|
|
3661
|
+
* Constructs a new Vars object.
|
|
3662
|
+
* @param {Array} variables An array of Variable objects, or null/undefined
|
|
3663
|
+
*/
|
|
3664
|
+
constructor(access, variables) {
|
|
3665
|
+
super();
|
|
3666
|
+
this.TypeMap = {
|
|
3667
|
+
"Access": "",
|
|
3668
|
+
"Variables": []
|
|
3669
|
+
};
|
|
3670
|
+
this.Access = "private";
|
|
3671
|
+
this.Variables = [];
|
|
3672
|
+
if(isValid(access)) this.Access = access;
|
|
3673
|
+
if(isValid(variables)) this.Variables = variables;
|
|
3674
|
+
}
|
|
3675
|
+
|
|
3676
|
+
/**
|
|
3677
|
+
* Creates a Vars object from an xml element.
|
|
3678
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
3679
|
+
* @returns A new Vars object, or null if the xml is invalid.
|
|
3680
|
+
*/
|
|
3681
|
+
static fromXML(xml) {
|
|
3682
|
+
if(!isValid(xml)) return null;
|
|
3683
|
+
var list = xml.getElementsByTagName("Variable");
|
|
3684
|
+
var vl = [];
|
|
3685
|
+
forEachElem(list, (elem) => {
|
|
3686
|
+
vl.push(Variable.fromXML(elem));
|
|
3687
|
+
});
|
|
3688
|
+
return new Vars(
|
|
3689
|
+
xml.getAttribute("accessSpecifier"),
|
|
3690
|
+
vl
|
|
3691
|
+
);
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
/**
|
|
3695
|
+
*
|
|
3696
|
+
* @returns Returns a string of xml representing the object.
|
|
3697
|
+
*/
|
|
3698
|
+
toXML() {
|
|
3699
|
+
return `<Vars accessSpecifier="${this.Access}">
|
|
3700
|
+
${this.Variables.map(v => v.toXML()).join("\n")}
|
|
3701
|
+
</Vars>`;
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3705
|
+
/**
|
|
3706
|
+
* Represents an ExternalVars element in the IEC project file.
|
|
3707
|
+
*/
|
|
3708
|
+
export class ExternalVars extends Serializable {
|
|
3709
|
+
/**
|
|
3710
|
+
* Constructs a new ExternalVars object.
|
|
3711
|
+
* @param {Variable[]?} variables An array of Variable objects, or null/undefined
|
|
3712
|
+
*/
|
|
3713
|
+
constructor(variables) {
|
|
3714
|
+
super();
|
|
3715
|
+
this.TypeMap = {
|
|
3716
|
+
"Variables":[]
|
|
3717
|
+
};
|
|
3718
|
+
this.Variables = [];
|
|
3719
|
+
if(isValid(variables)) this.Variables = variables;
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
/**
|
|
3723
|
+
* Creates a new ExternalVars object based on the xml element.
|
|
3724
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
3725
|
+
* @returns Returns a new EternalVars object, or null if the xml is invalid.
|
|
3726
|
+
*/
|
|
3727
|
+
static fromXML(xml) {
|
|
3728
|
+
if(!isValid(xml)) return null;
|
|
3729
|
+
var list = xml.getElementsByTagName("Variable");
|
|
3730
|
+
var vl = [];
|
|
3731
|
+
if(isValid(list)){
|
|
3732
|
+
forEachElem(list, (elem) => {
|
|
3733
|
+
vl.push(Variable.fromXML(elem));
|
|
3734
|
+
});
|
|
3735
|
+
}
|
|
3736
|
+
return new ExternalVars(
|
|
3737
|
+
vl
|
|
3738
|
+
);
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
/**
|
|
3742
|
+
*
|
|
3743
|
+
* @returns Returns an xml string representing the object.
|
|
3744
|
+
*/
|
|
3745
|
+
toXML() {
|
|
3746
|
+
return `<ExternalVars>
|
|
3747
|
+
${this.Variables.map(v => v.toXML()).join("\n")}
|
|
3748
|
+
</ExternalVars>`;
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
/**
|
|
3753
|
+
* Represents a Variable element in the IEC project file.
|
|
3754
|
+
*/
|
|
3755
|
+
export class Variable extends Serializable{
|
|
3756
|
+
/**
|
|
3757
|
+
* Constructs a new Variable object.
|
|
3758
|
+
* @param {string?} name The name of the Variable, or null/undefined
|
|
3759
|
+
* @param {Type?} type The type of the variable, or null/undefined
|
|
3760
|
+
* @param {string?} order The order of the variable in the parameter list, or null/undefined
|
|
3761
|
+
* @param {Address?} address The address for the variable.
|
|
3762
|
+
*/
|
|
3763
|
+
constructor(name, type, order, address) {
|
|
3764
|
+
super();
|
|
3765
|
+
this.TypeMap = {
|
|
3766
|
+
"Name": "",
|
|
3767
|
+
"Type": Type,
|
|
3768
|
+
"Order": "Order",
|
|
3769
|
+
"Address": Address
|
|
3770
|
+
};
|
|
3771
|
+
this.Name = "Var1";
|
|
3772
|
+
this.Type = new Type("ULINT");
|
|
3773
|
+
this.Order = "";
|
|
3774
|
+
this.Address = null;
|
|
3775
|
+
if(isValid(name)) this.Name = name;
|
|
3776
|
+
if(isValid(type)) this.Type = type;
|
|
3777
|
+
if(isValid(order)) this.Order = order;
|
|
3778
|
+
if(isValid(address)) this.Address = address;
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3781
|
+
/**
|
|
3782
|
+
* Creates a new Variable object based on an xml element.
|
|
3783
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
3784
|
+
* @returns Returns a new Variable object, or null if the xml is invalid.
|
|
3785
|
+
*/
|
|
3786
|
+
static fromXML(xml) {
|
|
3787
|
+
if(!isValid(xml)) return null;
|
|
3788
|
+
return new Variable(
|
|
3789
|
+
xml.getAttribute("name"),
|
|
3790
|
+
Type.fromXML(xml.getElementsByTagName("Type")[0]),
|
|
3791
|
+
xml.getAttribute("orderWithinParamSet"),
|
|
3792
|
+
Address.fromXML(xml.getElementsByTagName("Address")[0])
|
|
3793
|
+
);
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
/**
|
|
3797
|
+
*
|
|
3798
|
+
* @returns Returns an xml string representing the variable.
|
|
3799
|
+
*/
|
|
3800
|
+
toXML() {
|
|
3801
|
+
return `<Variable name="${this.Name}" orderWithinParamSet="${this.Order}">
|
|
3802
|
+
${this.Type?.toXML()}
|
|
3803
|
+
${this.Address?.toXML()}
|
|
3804
|
+
</Variable>`;
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3808
|
+
/**
|
|
3809
|
+
* Represents an input variable on a FbdObject in the IEC file.
|
|
3810
|
+
*/
|
|
3811
|
+
export class InputVariable extends Serializable{
|
|
3812
|
+
/**
|
|
3813
|
+
* Constructs a new InputVariable object.
|
|
3814
|
+
* @param {string?} parameterName The name of the parameter, or null/undefined
|
|
3815
|
+
* @param {string?} negated true/false, indicates whether the input should be negated.
|
|
3816
|
+
* @param {ConnectionPointIn?} inPoint The connection point for the variable, or null/undefined
|
|
3817
|
+
*/
|
|
3818
|
+
constructor(parameterName, negated, inPoint) {
|
|
3819
|
+
super();
|
|
3820
|
+
this.TypeMap = {
|
|
3821
|
+
"ParameterName": "",
|
|
3822
|
+
"Negated": "",
|
|
3823
|
+
"InputPoint": ConnectionPointIn
|
|
3824
|
+
};
|
|
3825
|
+
this.ParameterName = "";
|
|
3826
|
+
this.Negated = "false";
|
|
3827
|
+
this.InputPoint = new ConnectionPointIn();
|
|
3828
|
+
if(isValid(parameterName)) this.ParameterName = parameterName;
|
|
3829
|
+
if(isValid(inPoint)) this.InputPoint = inPoint;
|
|
3830
|
+
if(isValid(negated)) this.Negated = negated;
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
/**
|
|
3834
|
+
* Creates a new InputVariable based on the xml element.
|
|
3835
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
3836
|
+
* @returns Returns a new InputVariable object, or null if the xml is invalid.
|
|
3837
|
+
*/
|
|
3838
|
+
static fromXML(xml) {
|
|
3839
|
+
if(!isValid(xml)) return null;
|
|
3840
|
+
return new InputVariable(
|
|
3841
|
+
xml.getAttribute("parameterName"),
|
|
3842
|
+
xml.getAttribute("negated"),
|
|
3843
|
+
ConnectionPointIn.fromXML(xml.getElementsByTagName("ConnectionPointIn")[0])
|
|
3844
|
+
);
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3847
|
+
/**
|
|
3848
|
+
*
|
|
3849
|
+
* @returns Returns a string of xml representing the object.
|
|
3850
|
+
*/
|
|
3851
|
+
toXML() {
|
|
3852
|
+
return `<InputVariable parameterName="${this.ParameterName}" negated="${this.Negated}">
|
|
3853
|
+
${this.InputPoint?.toXML()}
|
|
3854
|
+
</InputVariable>`;
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
/**
|
|
3858
|
+
* Checks to see if the variable is connected to an output.
|
|
3859
|
+
* @param {string} refID The output ID to look for.
|
|
3860
|
+
* @returns {string} Returns the name of the variable if it is connected, or an empty string if not.
|
|
3861
|
+
*/
|
|
3862
|
+
isConnectedTo(refID){
|
|
3863
|
+
var retval = "";
|
|
3864
|
+
try{
|
|
3865
|
+
if(this.InputPoint.isConnectedTo(refID)){
|
|
3866
|
+
retval = this.ParameterName;
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
catch(e){
|
|
3870
|
+
console.error(e);
|
|
3871
|
+
}
|
|
3872
|
+
return retval;
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
/**
|
|
3876
|
+
* Connects this variable to an output.
|
|
3877
|
+
* @param {string} refID The output ID to which we should connect.
|
|
3878
|
+
*/
|
|
3879
|
+
connectTo(refID){
|
|
3880
|
+
this.InputPoint.connectTo(refID);
|
|
3881
|
+
}
|
|
3882
|
+
/**
|
|
3883
|
+
* Disconnects an output ID from the input point of this variable.
|
|
3884
|
+
* @param {string} refID The output ID to disconnect
|
|
3885
|
+
*/
|
|
3886
|
+
disconnect(refID){
|
|
3887
|
+
this.InputPoint.disconnect(refID);
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
/**
|
|
3892
|
+
* Represents an OutputVariable element in the IEC project file.
|
|
3893
|
+
*/
|
|
3894
|
+
export class OutputVariable extends Serializable{
|
|
3895
|
+
/**
|
|
3896
|
+
* Constructs a new OutputVariable object.
|
|
3897
|
+
* @param {string} parameterName The name of the parameter, or null/undefined
|
|
3898
|
+
* @param {ConnectionPointIn} outPoint The connection point for the variable, or null/undefined
|
|
3899
|
+
*/
|
|
3900
|
+
constructor(parameterName, outPoint) {
|
|
3901
|
+
super();
|
|
3902
|
+
this.TypeMap = {
|
|
3903
|
+
"ParameterName": "",
|
|
3904
|
+
"OutputPoint": ConnectionPointOut
|
|
3905
|
+
};
|
|
3906
|
+
this.ParameterName = "";
|
|
3907
|
+
this.OutputPoint = new ConnectionPointOut();
|
|
3908
|
+
|
|
3909
|
+
if(isValid(parameterName)) this.ParameterName = parameterName;
|
|
3910
|
+
if(isValid(outPoint)) this.OutputPoint = outPoint;
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3913
|
+
/**
|
|
3914
|
+
* Creates a new OutputVariable based on the xml element.
|
|
3915
|
+
* @param {Element} xml The XML element from which to create the object.
|
|
3916
|
+
* @returns Returns a new OutputVariable object, or null if the xml is invalid.
|
|
3917
|
+
*/
|
|
3918
|
+
static fromXML(xml) {
|
|
3919
|
+
if(!isValid(xml)) return null;
|
|
3920
|
+
return new OutputVariable(
|
|
3921
|
+
xml.getAttribute("parameterName"),
|
|
3922
|
+
ConnectionPointOut.fromXML(xml.getElementsByTagName("ConnectionPointOut")[0])
|
|
3923
|
+
);
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
/**
|
|
3927
|
+
*
|
|
3928
|
+
* @returns Returns a string of xml representing the object.
|
|
3929
|
+
*/
|
|
3930
|
+
toXML() {
|
|
3931
|
+
return `<OutputVariable parameterName="${this.ParameterName}">
|
|
3932
|
+
${this.OutputPoint?.toXML()}
|
|
3933
|
+
</OutputVariable>`;
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
/**
|
|
3938
|
+
* Represents an OutputVars element in the IEC project file.
|
|
3939
|
+
*/
|
|
3940
|
+
export class OutputVars extends Serializable{
|
|
3941
|
+
/**
|
|
3942
|
+
* Constructs a new OutputVars object.
|
|
3943
|
+
* @param {Array} variables An array of Variable objects, or null/undefined
|
|
3944
|
+
*/
|
|
3945
|
+
constructor(variables) {
|
|
3946
|
+
super();
|
|
3947
|
+
this.TypeMap = {
|
|
3948
|
+
"Variables": []
|
|
3949
|
+
};
|
|
3950
|
+
this.Variables = [];
|
|
3951
|
+
if(isValid(variables)) this.Variables = variables;
|
|
3952
|
+
}
|
|
3953
|
+
|
|
3954
|
+
/**
|
|
3955
|
+
* Creates a new OutputVars object based on an xml element.
|
|
3956
|
+
* @param {Element} xml The xml element from which to create an object.
|
|
3957
|
+
* @returns Returns a new OutputVars object, or null if the xml is invalid.
|
|
3958
|
+
*/
|
|
3959
|
+
static fromXML(xml) {
|
|
3960
|
+
if(!isValid(xml)) return null;
|
|
3961
|
+
var vars = [];
|
|
3962
|
+
forEachElem(xml.getElementsByTagName("Variable"), (v) => {
|
|
3963
|
+
vars.push(Variable.fromXML(v));
|
|
3964
|
+
});
|
|
3965
|
+
return new OutputVars(
|
|
3966
|
+
vars
|
|
3967
|
+
);
|
|
3968
|
+
}
|
|
3969
|
+
|
|
3970
|
+
/**
|
|
3971
|
+
*
|
|
3972
|
+
* @returns Returns a string of xml that represents the object.
|
|
3973
|
+
*/
|
|
3974
|
+
toXML() {
|
|
3975
|
+
return `<OutputVars>
|
|
3976
|
+
${this.Variables.map(v => v.toXML()).join("\n")}
|
|
3977
|
+
</OutputVars>`;
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3981
|
+
/**
|
|
3982
|
+
* Represents an InputVars element in an IEC project file.
|
|
3983
|
+
*/
|
|
3984
|
+
export class InputVars extends Serializable{
|
|
3985
|
+
/**
|
|
3986
|
+
* Constructs a new InputVars object.
|
|
3987
|
+
* @param {Array} variables An array of Variable objects, or null/undefined
|
|
3988
|
+
*/
|
|
3989
|
+
constructor(variables) {
|
|
3990
|
+
super();
|
|
3991
|
+
this.TypeMap = {
|
|
3992
|
+
"Variables": []
|
|
3993
|
+
};
|
|
3994
|
+
this.Variables = [];
|
|
3995
|
+
if(isValid(variables)) this.Variables = variables;
|
|
3996
|
+
}
|
|
3997
|
+
|
|
3998
|
+
/**
|
|
3999
|
+
* Creates a new InputVars object based on an xml element.
|
|
4000
|
+
* @param {Element} xml The xml element from which to create an object.
|
|
4001
|
+
* @returns Returns a new InputVars object, or null if the xml is invalid.
|
|
4002
|
+
*/
|
|
4003
|
+
static fromXML(xml) {
|
|
4004
|
+
if(!isValid(xml)) return null;
|
|
4005
|
+
var vars = [];
|
|
4006
|
+
forEachElem(xml.getElementsByTagName("Variable"), (v) => {
|
|
4007
|
+
vars.push(Variable.fromXML(v));
|
|
4008
|
+
});
|
|
4009
|
+
return new InputVars(
|
|
4010
|
+
vars
|
|
4011
|
+
);
|
|
4012
|
+
}
|
|
4013
|
+
/**
|
|
4014
|
+
*
|
|
4015
|
+
* @returns Returns a string of xml representing the object.
|
|
4016
|
+
*/
|
|
4017
|
+
toXML() {
|
|
4018
|
+
return `<InputVars>
|
|
4019
|
+
${this.Variables.map(v => v.toXML()).join("\n")}
|
|
4020
|
+
</InputVars>`;
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
|
|
4024
|
+
/**
|
|
4025
|
+
* Represents a Type element in the IEC Project file.
|
|
4026
|
+
*/
|
|
4027
|
+
export class Type extends Serializable{
|
|
4028
|
+
/**
|
|
4029
|
+
* Constructs a new Type object.
|
|
4030
|
+
* @param {string} typeName The name of the type, or null/undefined
|
|
4031
|
+
*/
|
|
4032
|
+
constructor(typeName) {
|
|
4033
|
+
super();
|
|
4034
|
+
this.TypeMap = {
|
|
4035
|
+
"TypeName": ""
|
|
4036
|
+
};
|
|
4037
|
+
this.TypeName = "ULINT";
|
|
4038
|
+
|
|
4039
|
+
if(isValid(typeName)) this.TypeName = typeName;
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
/**
|
|
4043
|
+
* Creates a new Type object based on an xml element.
|
|
4044
|
+
* @param {Element} xml The element to create the object from.
|
|
4045
|
+
* @returns Returns a new Type object, or null if the xml is invalid.
|
|
4046
|
+
*/
|
|
4047
|
+
static fromXML(xml) {
|
|
4048
|
+
if(!isValid(xml)) return null;
|
|
4049
|
+
return new Type(
|
|
4050
|
+
xml.getElementsByTagName("TypeName")[0]?.textContent || ""
|
|
4051
|
+
);
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
/**
|
|
4055
|
+
*
|
|
4056
|
+
* @returns Returns an xml string representing the object.
|
|
4057
|
+
*/
|
|
4058
|
+
toXML() {
|
|
4059
|
+
return `<Type>
|
|
4060
|
+
<TypeName>${this.TypeName}</TypeName>
|
|
4061
|
+
</Type>`;
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
|
|
4065
|
+
}
|
|
4066
|
+
|
|
4067
|
+
/**
|
|
4068
|
+
* Represents an Address element in the IEC Project file.
|
|
4069
|
+
*/
|
|
4070
|
+
export class Address extends Serializable{
|
|
4071
|
+
/**
|
|
4072
|
+
* Constructs a new Address object.
|
|
4073
|
+
* @param {string} typeName The name of the type, or null/undefined
|
|
4074
|
+
*/
|
|
4075
|
+
constructor(location, size, address) {
|
|
4076
|
+
super();
|
|
4077
|
+
this.TypeMap = {
|
|
4078
|
+
"Location": "",
|
|
4079
|
+
"Size": "",
|
|
4080
|
+
"Address": ""
|
|
4081
|
+
};
|
|
4082
|
+
this.Location = "Q";
|
|
4083
|
+
this.Size = "X";
|
|
4084
|
+
this.Address = "";
|
|
4085
|
+
|
|
4086
|
+
if(isValid(location)) this.Location = location;
|
|
4087
|
+
if(isValid(size)) this.Size = size;
|
|
4088
|
+
if(isValid(address)) this.Address = address;
|
|
4089
|
+
}
|
|
4090
|
+
|
|
4091
|
+
/**
|
|
4092
|
+
* Creates a new Address object based on an xml element.
|
|
4093
|
+
* @param {Element} xml The element to create the object from.
|
|
4094
|
+
* @returns Returns a new Address object, or null if the xml is invalid.
|
|
4095
|
+
*/
|
|
4096
|
+
static fromXML(xml) {
|
|
4097
|
+
if(!isValid(xml)) return null;
|
|
4098
|
+
return new Address(xml.getAttribute("location"), xml.getAttribute("size"), xml.getAttribute("address"));
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
/**
|
|
4102
|
+
*
|
|
4103
|
+
* @returns Returns an xml string representing the object.
|
|
4104
|
+
*/
|
|
4105
|
+
toXML() {
|
|
4106
|
+
return `<Address location="${this.Location}" size="${this.Size}" address="${this.Address}"></Address>`;
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
|
|
4110
|
+
/**
|
|
4111
|
+
* Represents a Mapping Table for I/O to a PLC (not IEC standard).
|
|
4112
|
+
*/
|
|
4113
|
+
export class MappingTable extends Serializable{
|
|
4114
|
+
/**
|
|
4115
|
+
* Constructs a new MappingTable object.
|
|
4116
|
+
* @param {Map[]?} maps An array of Map objects.
|
|
4117
|
+
*/
|
|
4118
|
+
constructor(maps) {
|
|
4119
|
+
super();
|
|
4120
|
+
this.TypeMap = {
|
|
4121
|
+
"Maps": []
|
|
4122
|
+
};
|
|
4123
|
+
this.Maps = [];
|
|
4124
|
+
if(isValid(maps)) this.Maps = maps;
|
|
4125
|
+
}
|
|
4126
|
+
|
|
4127
|
+
/**
|
|
4128
|
+
* Creates a new MappingTable object based on an xml element.
|
|
4129
|
+
* @param {Element} xml The xml element from which to create the object.
|
|
4130
|
+
* @returns Returns a new MappingTable object, or null if the xml is invalid.
|
|
4131
|
+
*/
|
|
4132
|
+
static fromXML(xml) {
|
|
4133
|
+
if(!isValid(xml)) return null;
|
|
4134
|
+
var maps = [];
|
|
4135
|
+
forEachElem(xml.getElementsByTagName("Map"), (v) => {
|
|
4136
|
+
maps.push(Map.fromXML(v));
|
|
4137
|
+
});
|
|
4138
|
+
|
|
4139
|
+
return new MappingTable(maps);
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
/**
|
|
4143
|
+
*
|
|
4144
|
+
* @returns Returns an xml string representing the variable.
|
|
4145
|
+
*/
|
|
4146
|
+
toXML() {
|
|
4147
|
+
var maps = "";
|
|
4148
|
+
forEachElem(this.Maps, (m) => {
|
|
4149
|
+
maps += m.toXML() + "\n";
|
|
4150
|
+
});
|
|
4151
|
+
return `<MappingTable>
|
|
4152
|
+
${maps}
|
|
4153
|
+
</MappingTable>`;
|
|
4154
|
+
}
|
|
4155
|
+
|
|
4156
|
+
/**
|
|
4157
|
+
* Creates structured text references for the mapping table.
|
|
4158
|
+
* @param {string?} resource If the resource name is provided, it filters the table by this resource.
|
|
4159
|
+
*/
|
|
4160
|
+
toST(resource){
|
|
4161
|
+
var res = "";
|
|
4162
|
+
var maps = "";
|
|
4163
|
+
if(isValid(resource)) res = resource;
|
|
4164
|
+
forEachElem(this.Maps, m => {
|
|
4165
|
+
if(res === "" || m.Resource === res){
|
|
4166
|
+
maps += m.toST() + "\n";
|
|
4167
|
+
}
|
|
4168
|
+
});
|
|
4169
|
+
return maps;
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
export const ModuleProtocols = Object.freeze([
|
|
4174
|
+
"MODBUS-TCP",
|
|
4175
|
+
"MODBUS-RTU",
|
|
4176
|
+
"OPCUA",
|
|
4177
|
+
"BACNET-IP",
|
|
4178
|
+
"MTI"
|
|
4179
|
+
]);
|
|
4180
|
+
|
|
4181
|
+
/**
|
|
4182
|
+
* Represents a Map of remote I/O to internal memory on the PLC (not IEC standard.)
|
|
4183
|
+
*/
|
|
4184
|
+
export class Map extends Serializable{
|
|
4185
|
+
|
|
4186
|
+
/**
|
|
4187
|
+
* Constructs a new Map object.
|
|
4188
|
+
* @param {string?} moduleID The ID of the remote module. This can be the IP address or a unique ID used by the specific protocol.
|
|
4189
|
+
* @param {string?} modulePort the port to the remtoe module.
|
|
4190
|
+
* @param {string?} protocol Identifies the protocol for the remote module. Protocols are defined by the "ModuleProtocols" constant.
|
|
4191
|
+
* @param {string?} remoteAddress The address within the module to map.
|
|
4192
|
+
* @param {string?} remoteSize The size of the address, in bits.
|
|
4193
|
+
* @param {string?} internalAddress The address reference to internal PLC memory. This should be the standard address reference format, without the %.
|
|
4194
|
+
* @param {string?} resource The resource name assocated with this map.
|
|
4195
|
+
* @param {string?} pollTime The time in milliseconds that this module should be polled.
|
|
4196
|
+
* @param {string?} protocolProperties This is a JSON string defining additional properties that should be defined for the protocol. For example, in BACNET/IP you must identify the object, property, and value type.
|
|
4197
|
+
*/
|
|
4198
|
+
constructor(moduleID, modulePort, protocol, remoteAddress, remoteSize, internalAddress, resource, pollTime, protocolProperties) {
|
|
4199
|
+
super();
|
|
4200
|
+
this.TypeMap = {
|
|
4201
|
+
"ModuleID": "",
|
|
4202
|
+
"ModulePort": "",
|
|
4203
|
+
"Protocol": "",
|
|
4204
|
+
"RemoteAddress": "",
|
|
4205
|
+
"RemoteSize": "",
|
|
4206
|
+
"InternalAddress": "",
|
|
4207
|
+
"Resource": "",
|
|
4208
|
+
"PollTime": "",
|
|
4209
|
+
"ProtocolProperties": ""
|
|
4210
|
+
};
|
|
4211
|
+
this.ModuleID = "";
|
|
4212
|
+
this.ModulePort = "";
|
|
4213
|
+
this.Protocol = "";
|
|
4214
|
+
this.RemoteAddress = "";
|
|
4215
|
+
this.RemoteSize = "";
|
|
4216
|
+
this.InternalAddress = "";
|
|
4217
|
+
this.PollTime = "";
|
|
4218
|
+
this.ProtocolProperties = "";
|
|
4219
|
+
this.Resource = "";
|
|
4220
|
+
|
|
4221
|
+
if(isValid(moduleID)) this.ModuleID = moduleID;
|
|
4222
|
+
if(isValid(modulePort)) this.ModulePort = modulePort;
|
|
4223
|
+
if(isValid(protocol)) this.Protocol = protocol;
|
|
4224
|
+
if(isValid(remoteAddress)) this.RemoteAddress = remoteAddress;
|
|
4225
|
+
if(isValid(remoteSize)) this.RemoteSize = remoteSize;
|
|
4226
|
+
if(isValid(internalAddress)) this.InternalAddress = internalAddress;
|
|
4227
|
+
if(isValid(pollTime)) this.PollTime = pollTime;
|
|
4228
|
+
if(isValid(protocolProperties)) this.ProtocolProperties = protocolProperties;
|
|
4229
|
+
if(isValid(resource)) this.Resource = resource;
|
|
4230
|
+
}
|
|
4231
|
+
|
|
4232
|
+
/**
|
|
4233
|
+
* Creates a new Map object based on an xml element.
|
|
4234
|
+
* @param {Element} xml The element to create the object from.
|
|
4235
|
+
* @returns {Map} Returns a new Map object, or null if the xml is invalid.
|
|
4236
|
+
*/
|
|
4237
|
+
static fromXML(xml) {
|
|
4238
|
+
if(!isValid(xml)) return null;
|
|
4239
|
+
return new Map(xml.getAttribute("ModuleID"), xml.getAttribute("ModulePort"), xml.getAttribute("Protocol"), xml.getAttribute("RemoteAddress"), xml.getAttribute("RemoteSize"), xml.getAttribute("InternalAddress"), xml.getAttribute("Resource"), xml.getAttribute("PollTime"), xml.getAttribute("ProtocolProperties"));
|
|
4240
|
+
}
|
|
4241
|
+
|
|
4242
|
+
|
|
4243
|
+
/**
|
|
4244
|
+
*
|
|
4245
|
+
* @returns Returns an xml string representing the object.
|
|
4246
|
+
*/
|
|
4247
|
+
toXML() {
|
|
4248
|
+
return `<Map ModuleID="${this.ModuleID}" ModulePort="${this.ModulePort}" Protocol="${this.Protocol}" RemoteAddress="${this.RemoteAddress}" RemoteSize="${this.RemoteSize}" InternalAddress="${this.InternalAddress}" Resource="${this.Resource}" PollTime="${this.PollTime}" ProtocolProperties="${escapeXmlAttr(this.ProtocolProperties)}"></Map>`;
|
|
4249
|
+
}
|
|
4250
|
+
|
|
4251
|
+
toST(){
|
|
4252
|
+
return "//Map=" + this.toJSON().replaceAll("\\", "\\\\").replaceAll(`"`, `\\"`);
|
|
4253
|
+
}
|
|
4254
|
+
}
|