node-opcua-address-space 2.89.0 → 2.90.1
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/dist/source/loader/load_nodeset2.js +5 -5
- package/dist/source/loader/load_nodeset2.js.map +1 -1
- package/dist/src/base_node_private.js +6 -6
- package/dist/src/base_node_private.js.map +1 -1
- package/dist/src/check_value_rank_compatibility.d.ts +15 -0
- package/dist/src/check_value_rank_compatibility.js +82 -0
- package/dist/src/check_value_rank_compatibility.js.map +1 -0
- package/dist/src/extension_object_array_node.js +11 -0
- package/dist/src/extension_object_array_node.js.map +1 -1
- package/dist/src/namespace_impl.js +2 -3
- package/dist/src/namespace_impl.js.map +1 -1
- package/dist/src/nodeset_tools/nodeset_to_xml.js +6 -1
- package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/src/ua_variable_impl.d.ts +12 -0
- package/dist/src/ua_variable_impl.js +66 -14
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/dist/src/ua_variable_impl_ext_obj.d.ts +2 -0
- package/dist/src/ua_variable_impl_ext_obj.js +66 -21
- package/dist/src/ua_variable_impl_ext_obj.js.map +1 -1
- package/dist/src/ua_variable_type_impl.d.ts +11 -1
- package/dist/src/ua_variable_type_impl.js +6 -0
- package/dist/src/ua_variable_type_impl.js.map +1 -1
- package/package.json +34 -34
- package/source/loader/load_nodeset2.ts +11 -10
- package/src/base_node_private.ts +7 -7
- package/src/check_value_rank_compatibility.ts +79 -0
- package/src/extension_object_array_node.ts +11 -2
- package/src/namespace_impl.ts +4 -7
- package/src/nodeset_tools/nodeset_to_xml.ts +9 -4
- package/src/ua_variable_impl.ts +82 -19
- package/src/ua_variable_impl_ext_obj.ts +79 -26
- package/src/ua_variable_type_impl.ts +20 -1
- package/test_helpers/test_fixtures/eurange_issue.xml +3 -2
package/src/ua_variable_impl.ts
CHANGED
|
@@ -86,6 +86,8 @@ import { apply_condition_refresh, ConditionRefreshCache } from "./apply_conditio
|
|
|
86
86
|
import {
|
|
87
87
|
extractPartialData,
|
|
88
88
|
incrementElement,
|
|
89
|
+
propagateTouchValueDownward,
|
|
90
|
+
propagateTouchValueDownwardArray,
|
|
89
91
|
propagateTouchValueUpward,
|
|
90
92
|
setExtensionObjectPartialValue,
|
|
91
93
|
_bindExtensionObject,
|
|
@@ -245,6 +247,17 @@ function default_func(this: UAVariable, dataValue1: DataValue, callback1: Callba
|
|
|
245
247
|
interface UAVariableOptions extends InternalBaseNodeOptions {
|
|
246
248
|
value?: any;
|
|
247
249
|
dataType: NodeId | string;
|
|
250
|
+
/**
|
|
251
|
+
* This attribute indicates whether the Value attribute of the Variableis an array and how many dimensions the array has.
|
|
252
|
+
* It may have the following values:
|
|
253
|
+
* * n > 1: the Value is an array with the specified number of dimensions.
|
|
254
|
+
* * OneDimension (1): The value is an array with one dimension.
|
|
255
|
+
* * OneOrMoreDimensions (0): The value is an array with one or more dimensions.
|
|
256
|
+
* * Scalar (−1): The value is not an array.
|
|
257
|
+
* * Any (−2): The value can be a scalar or an array with any number of dimensions.
|
|
258
|
+
* * ScalarOrOneDimension (−3): The value can be a scalar or a one dimensional array.
|
|
259
|
+
* * All DataTypes are considered to be scalar, even if they have array-like semantics like ByteString and String.
|
|
260
|
+
*/
|
|
248
261
|
valueRank?: number;
|
|
249
262
|
arrayDimensions?: null | number[];
|
|
250
263
|
accessLevel?: any;
|
|
@@ -286,6 +299,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
286
299
|
private _basicDataType?: DataType;
|
|
287
300
|
|
|
288
301
|
public $extensionObject?: any;
|
|
302
|
+
public $set_ExtensionObject?: (newValue: ExtensionObject, sourceTimestamp: PreciseClock, cache: Set<UAVariableImpl>) => void;
|
|
289
303
|
|
|
290
304
|
public $historicalDataConfiguration?: UAHistoricalDataConfiguration;
|
|
291
305
|
public varHistorian?: IVariableHistorian;
|
|
@@ -312,6 +326,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
312
326
|
get typeDefinitionObj(): UAVariableType {
|
|
313
327
|
// istanbul ignore next
|
|
314
328
|
if (super.typeDefinitionObj && super.typeDefinitionObj.nodeClass !== NodeClass.VariableType) {
|
|
329
|
+
console.log(super.typeDefinitionObj.toString());
|
|
315
330
|
throw new Error(
|
|
316
331
|
"Invalid type definition node class , expecting a VariableType got " + NodeClass[super.typeDefinitionObj.nodeClass]
|
|
317
332
|
);
|
|
@@ -524,6 +539,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
524
539
|
|
|
525
540
|
public isExtensionObject(): boolean {
|
|
526
541
|
// DataType must be one of Structure
|
|
542
|
+
if (this.dataType.isEmpty()) return false;
|
|
527
543
|
const dataTypeNode = this.addressSpace.findDataType(this.dataType) as UADataType;
|
|
528
544
|
if (!dataTypeNode) {
|
|
529
545
|
throw new Error(" Cannot find DataType " + this.dataType.toString() + " in standard address Space");
|
|
@@ -572,9 +588,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
572
588
|
dataValue.serverPicoseconds = 0;
|
|
573
589
|
return callback(null, dataValue);
|
|
574
590
|
}
|
|
575
|
-
|
|
576
591
|
try {
|
|
577
592
|
this.refreshFunc.call(this, (err: Error | null, dataValue?: DataValueLike) => {
|
|
593
|
+
// istanbul ignore next
|
|
578
594
|
if (err || !dataValue) {
|
|
579
595
|
errorLog(
|
|
580
596
|
"-------------- refresh call failed",
|
|
@@ -814,19 +830,20 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
814
830
|
if (dataValue.value.dataType === DataType.ExtensionObject) {
|
|
815
831
|
const valueIsCorrect = this.checkExtensionObjectIsCorrect(dataValue.value.value);
|
|
816
832
|
if (!valueIsCorrect) {
|
|
817
|
-
errorLog("Invalid value !");
|
|
833
|
+
errorLog("setValueFromSource Invalid value !");
|
|
818
834
|
errorLog(this.toString());
|
|
819
835
|
errorLog(dataValue.toString());
|
|
820
836
|
this.checkExtensionObjectIsCorrect(dataValue.value.value);
|
|
821
837
|
}
|
|
822
|
-
this.$dataValue = dataValue;
|
|
823
838
|
// ----------------------------------
|
|
824
|
-
if (this.$extensionObject) {
|
|
839
|
+
if (this.$extensionObject || this.$$extensionObjectArray) {
|
|
825
840
|
// we have an extension object already bound to this node
|
|
826
841
|
// the client is asking us to replace the object entierly by a new one
|
|
827
842
|
// const ext = dataValue.value.value;
|
|
828
843
|
this._internal_set_dataValue(dataValue);
|
|
829
844
|
return;
|
|
845
|
+
} else {
|
|
846
|
+
this.$dataValue = dataValue;
|
|
830
847
|
}
|
|
831
848
|
} else {
|
|
832
849
|
this._internal_set_dataValue(dataValue);
|
|
@@ -1283,6 +1300,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1283
1300
|
const n = callbacks.length;
|
|
1284
1301
|
for (const callback1 of callbacks) {
|
|
1285
1302
|
callback1.call(this, err, dataValue);
|
|
1303
|
+
|
|
1286
1304
|
}
|
|
1287
1305
|
};
|
|
1288
1306
|
|
|
@@ -1487,12 +1505,21 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1487
1505
|
optionalExtensionObject?: ExtensionObject | ExtensionObject[],
|
|
1488
1506
|
options?: BindExtensionObjectOptions
|
|
1489
1507
|
): ExtensionObject | ExtensionObject[] | null {
|
|
1508
|
+
|
|
1509
|
+
// coerce to ExtensionObject[] when this.valueRank === 1
|
|
1510
|
+
if (optionalExtensionObject && this.valueRank === 1 && !Array.isArray(optionalExtensionObject) && optionalExtensionObject instanceof ExtensionObject) {
|
|
1511
|
+
warningLog("bindExtensionObject: coerce to ExtensionObject[] when this.valueRank === 1");
|
|
1512
|
+
optionalExtensionObject = [optionalExtensionObject];
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1490
1515
|
if (optionalExtensionObject) {
|
|
1491
1516
|
if (optionalExtensionObject instanceof Array) {
|
|
1492
|
-
assert(this.valueRank >= 1, "expecting an Array of Matrix variable here");
|
|
1517
|
+
assert(this.valueRank >= 1, "bindExtensionObject: expecting an Array of Matrix variable here");
|
|
1493
1518
|
return _bindExtensionObjectArrayOrMatrix(this, optionalExtensionObject, options);
|
|
1494
1519
|
} else {
|
|
1495
|
-
|
|
1520
|
+
if (this.valueRank !== -1 && this.valueRank !== 0) {
|
|
1521
|
+
throw new Error("bindExtensionObject: expecting an Scalar variable here but got value rank " + this.valueRank);
|
|
1522
|
+
}
|
|
1496
1523
|
return _bindExtensionObject(this, optionalExtensionObject, options) as ExtensionObject;
|
|
1497
1524
|
}
|
|
1498
1525
|
}
|
|
@@ -1712,7 +1739,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1712
1739
|
throw new Error("Invalid Extension Object on nodeId =" + this.nodeId.toString());
|
|
1713
1740
|
}
|
|
1714
1741
|
}
|
|
1715
|
-
|
|
1742
|
+
|
|
1716
1743
|
this.verifyVariantCompatibility(dataValue.value);
|
|
1717
1744
|
|
|
1718
1745
|
this._inner_replace_dataValue(dataValue, indexRange);
|
|
@@ -1722,23 +1749,59 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1722
1749
|
* @private
|
|
1723
1750
|
*/
|
|
1724
1751
|
public _inner_replace_dataValue(dataValue: DataValue, indexRange?: NumericRange | null) {
|
|
1725
|
-
const old_dataValue = this.$dataValue;
|
|
1726
1752
|
|
|
1727
|
-
this.$dataValue
|
|
1728
|
-
|
|
1753
|
+
assert(this.$dataValue.value instanceof Variant);
|
|
1754
|
+
const old_dataValue = this.$dataValue.clone();
|
|
1729
1755
|
|
|
1756
|
+
if (this.$$extensionObjectArray && dataValue.value.arrayType !== VariantArrayType.Scalar) {
|
|
1757
|
+
// we have a bounded array or matrix
|
|
1758
|
+
assert(Array.isArray(dataValue.value.value));
|
|
1759
|
+
if (this.$$extensionObjectArray !== this.$dataValue.value.value) {
|
|
1760
|
+
throw new Error("internal error");
|
|
1761
|
+
}
|
|
1762
|
+
this.$$extensionObjectArray = dataValue.value.value;
|
|
1763
|
+
this.$dataValue.value.value = dataValue.value.value;
|
|
1764
|
+
|
|
1765
|
+
this.$dataValue.statusCode = dataValue.statusCode || StatusCodes.Good;
|
|
1766
|
+
this.$dataValue.serverTimestamp = dataValue.serverTimestamp;
|
|
1767
|
+
this.$dataValue.serverPicoseconds = dataValue.serverPicoseconds;
|
|
1768
|
+
this.$dataValue.sourceTimestamp = dataValue.sourceTimestamp;
|
|
1769
|
+
this.$dataValue.sourcePicoseconds = dataValue.sourcePicoseconds;
|
|
1770
|
+
|
|
1771
|
+
} else if (this._basicDataType === DataType.ExtensionObject && this.valueRank === -1 && this.$set_ExtensionObject && dataValue.value.arrayType === VariantArrayType.Scalar) {
|
|
1772
|
+
// the entire extension object is changed.
|
|
1773
|
+
this.$dataValue.statusCode = this.$dataValue.statusCode || StatusCodes.Good;
|
|
1774
|
+
const preciseClock = coerceClock(this.$dataValue.sourceTimestamp, this.$dataValue.sourcePicoseconds);
|
|
1775
|
+
this.$set_ExtensionObject(dataValue.value.value, preciseClock, new Set())
|
|
1776
|
+
} else {
|
|
1777
|
+
this.$dataValue = dataValue;
|
|
1778
|
+
this.$dataValue.statusCode = this.$dataValue.statusCode || StatusCodes.Good;
|
|
1779
|
+
}
|
|
1730
1780
|
// repair missing timestamps
|
|
1781
|
+
const now = new Date();
|
|
1731
1782
|
if (!dataValue.serverTimestamp) {
|
|
1732
|
-
this.$dataValue.serverTimestamp = old_dataValue.serverTimestamp;
|
|
1733
|
-
this.$dataValue.serverPicoseconds = old_dataValue.serverPicoseconds;
|
|
1783
|
+
this.$dataValue.serverTimestamp = old_dataValue.serverTimestamp || now;
|
|
1784
|
+
this.$dataValue.serverPicoseconds = old_dataValue.serverPicoseconds || 0;
|
|
1734
1785
|
}
|
|
1735
1786
|
if (!dataValue.sourceTimestamp) {
|
|
1736
|
-
this.$dataValue.sourceTimestamp = old_dataValue.sourceTimestamp;
|
|
1737
|
-
this.$dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds;
|
|
1787
|
+
this.$dataValue.sourceTimestamp = old_dataValue.sourceTimestamp || now;
|
|
1788
|
+
this.$dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds || 0;
|
|
1738
1789
|
}
|
|
1739
1790
|
|
|
1740
1791
|
if (!sameDataValue(old_dataValue, dataValue)) {
|
|
1741
|
-
this.
|
|
1792
|
+
if (this.getBasicDataType() === DataType.ExtensionObject) {
|
|
1793
|
+
const preciseClock = coerceClock(this.$dataValue.sourceTimestamp, this.$dataValue.sourcePicoseconds);
|
|
1794
|
+
const cache: Set<UAVariable> = new Set();
|
|
1795
|
+
if (this.$$extensionObjectArray) {
|
|
1796
|
+
this.touchValue(preciseClock);
|
|
1797
|
+
propagateTouchValueDownwardArray(this, preciseClock, cache);
|
|
1798
|
+
} else {
|
|
1799
|
+
this.touchValue(preciseClock);
|
|
1800
|
+
propagateTouchValueDownward(this, preciseClock, cache);
|
|
1801
|
+
}
|
|
1802
|
+
} else {
|
|
1803
|
+
this.emit("value_changed", this.$dataValue, indexRange);
|
|
1804
|
+
}
|
|
1742
1805
|
}
|
|
1743
1806
|
}
|
|
1744
1807
|
|
|
@@ -2067,7 +2130,7 @@ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: GetterOpt
|
|
|
2067
2130
|
this._get_func = options.get;
|
|
2068
2131
|
|
|
2069
2132
|
const timestamped_get_func_from__Variable_bind_with_simple_get = () => {
|
|
2070
|
-
const value = this._get_func();
|
|
2133
|
+
const value: Variant | StatusCode = this._get_func();
|
|
2071
2134
|
|
|
2072
2135
|
/* istanbul ignore next */
|
|
2073
2136
|
if (!is_Variant_or_StatusCode(value)) {
|
|
@@ -2081,10 +2144,10 @@ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: GetterOpt
|
|
|
2081
2144
|
);
|
|
2082
2145
|
}
|
|
2083
2146
|
if (is_StatusCode(value)) {
|
|
2084
|
-
return new DataValue({ statusCode: value });
|
|
2147
|
+
return new DataValue({ statusCode: value as StatusCode });
|
|
2085
2148
|
} else {
|
|
2086
|
-
if (!this.$dataValue || !this.$dataValue.statusCode.isGoodish() || !sameVariant(this.$dataValue.value, value)) {
|
|
2087
|
-
this.
|
|
2149
|
+
if (!this.$dataValue || !this.$dataValue.statusCode.isGoodish() || !sameVariant(this.$dataValue.value, value as Variant)) {
|
|
2150
|
+
this._inner_replace_dataValue(new DataValue({ value }));
|
|
2088
2151
|
}
|
|
2089
2152
|
return this.$dataValue;
|
|
2090
2153
|
}
|
|
@@ -104,12 +104,12 @@ export function _touchValue(property: UAVariableImpl, now: PreciseClock): void {
|
|
|
104
104
|
property.$dataValue.serverTimestamp = now.timestamp;
|
|
105
105
|
property.$dataValue.serverPicoseconds = now.picoseconds;
|
|
106
106
|
property.$dataValue.statusCode = StatusCodes.Good;
|
|
107
|
-
if (property.minimumSamplingInterval === 0) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
107
|
+
// if (property.minimumSamplingInterval === 0) {
|
|
108
|
+
if (property.listenerCount("value_changed") > 0) {
|
|
109
|
+
const clonedDataValue = property.readValue();
|
|
110
|
+
property.emit("value_changed", clonedDataValue);
|
|
112
111
|
}
|
|
112
|
+
// }
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
@@ -126,7 +126,7 @@ export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseCloc
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
129
|
+
export function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
130
130
|
if (!self.isExtensionObject()) return;
|
|
131
131
|
// also propagate changes to embeded variables
|
|
132
132
|
const dataTypeNode = self.getDataTypeNode();
|
|
@@ -265,7 +265,7 @@ function installExt(uaVariable: UAVariableImpl, ext: ExtensionObject) {
|
|
|
265
265
|
return uaVariable.getComponentByName(field.name!) as UAVariable | null;
|
|
266
266
|
}));
|
|
267
267
|
} else {
|
|
268
|
-
warningLog("extension object is null");
|
|
268
|
+
doDebug && warningLog("extension object is null");
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
}
|
|
@@ -336,7 +336,7 @@ function _installFields2(uaVariable: UAVariableImpl, { get, set }: {
|
|
|
336
336
|
propertyNode.$dataValue.serverPicoseconds = uaVariable.$dataValue.serverPicoseconds;
|
|
337
337
|
propertyNode.$dataValue.value.dataType = propertyNode.dataTypeObj.basicDataType;
|
|
338
338
|
propertyNode.$dataValue.value.arrayType = propertyNode.valueRank === -1 ? VariantArrayType.Scalar : (propertyNode.valueRank === 1 ? VariantArrayType.Array : VariantArrayType.Matrix)
|
|
339
|
-
propertyNode.$dataValue.value.dimensions =propertyNode.valueRank > 1 ?
|
|
339
|
+
propertyNode.$dataValue.value.dimensions = propertyNode.valueRank > 1 ? propertyNode.arrayDimensions : null;
|
|
340
340
|
|
|
341
341
|
const fieldName = field.name!;
|
|
342
342
|
installDataValueGetter(propertyNode, () => get(fieldName));
|
|
@@ -398,7 +398,7 @@ function isVariableContainingExtensionObject(uaVariable: UAVariableImpl): boolea
|
|
|
398
398
|
function _innerBindExtensionObjectScalar(uaVariable: UAVariableImpl,
|
|
399
399
|
{ get, set }: {
|
|
400
400
|
get: () => ExtensionObject;
|
|
401
|
-
set: (value: ExtensionObject, sourceTimestamp: PreciseClock) => void;
|
|
401
|
+
set: (value: ExtensionObject, sourceTimestamp: PreciseClock, cache: Set<UAVariableImpl>) => void;
|
|
402
402
|
},
|
|
403
403
|
options?: BindExtensionObjectOptions
|
|
404
404
|
) {
|
|
@@ -412,13 +412,7 @@ function _innerBindExtensionObjectScalar(uaVariable: UAVariableImpl,
|
|
|
412
412
|
};
|
|
413
413
|
|
|
414
414
|
installDataValueGetter(uaVariable, get);
|
|
415
|
-
|
|
416
|
-
uaVariable._inner_replace_dataValue = (dataValue: DataValue, indexRange?: NumericRange | null) => {
|
|
417
|
-
/** */
|
|
418
|
-
const ext = dataValue.value.value;
|
|
419
|
-
const sourceTime = coerceClock(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
|
|
420
|
-
set(ext, sourceTime);
|
|
421
|
-
}
|
|
415
|
+
uaVariable.$set_ExtensionObject = set;
|
|
422
416
|
|
|
423
417
|
_installFields2(uaVariable, {
|
|
424
418
|
get: (fieldName: string) => {
|
|
@@ -436,6 +430,7 @@ function _innerBindExtensionObjectScalar(uaVariable: UAVariableImpl,
|
|
|
436
430
|
}
|
|
437
431
|
|
|
438
432
|
|
|
433
|
+
// eslint-disable-next-line complexity
|
|
439
434
|
export function _bindExtensionObject(
|
|
440
435
|
uaVariable: UAVariableImpl,
|
|
441
436
|
optionalExtensionObject?: ExtensionObject,
|
|
@@ -443,10 +438,16 @@ export function _bindExtensionObject(
|
|
|
443
438
|
): ExtensionObject | null {
|
|
444
439
|
options = options || { createMissingProp: false };
|
|
445
440
|
|
|
441
|
+
// istanbul ignore next
|
|
446
442
|
if (!isVariableContainingExtensionObject(uaVariable)) {
|
|
447
443
|
return null;
|
|
448
444
|
}
|
|
449
445
|
|
|
446
|
+
// istanbul ignore next
|
|
447
|
+
if (optionalExtensionObject && uaVariable.valueRank === 0) {
|
|
448
|
+
warningLog(uaVariable.browseName.toString() + ": valueRank was zero but needed to be adjusted to -1 (Scalar) in bindExtensionObject");
|
|
449
|
+
uaVariable.valueRank = -1;
|
|
450
|
+
}
|
|
450
451
|
const addressSpace = uaVariable.addressSpace;
|
|
451
452
|
let extensionObject_;
|
|
452
453
|
|
|
@@ -567,12 +568,16 @@ const composeBrowseNameAndNodeId = (uaVariable: UAVariable, indexes: number[]) =
|
|
|
567
568
|
}
|
|
568
569
|
|
|
569
570
|
|
|
570
|
-
// eslint-disable-next-line max-statements
|
|
571
|
+
// eslint-disable-next-line max-statements, complexity
|
|
571
572
|
export function _bindExtensionObjectArrayOrMatrix(
|
|
572
573
|
uaVariable: UAVariableImpl,
|
|
573
574
|
optionalExtensionObjectArray?: ExtensionObject[],
|
|
574
575
|
options?: BindExtensionObjectOptions
|
|
575
576
|
): ExtensionObject[] {
|
|
577
|
+
|
|
578
|
+
options = options || { createMissingProp: false};
|
|
579
|
+
options.createMissingProp = options.createMissingProp || false;
|
|
580
|
+
|
|
576
581
|
// istanbul ignore next
|
|
577
582
|
if (uaVariable.valueRank < 1) {
|
|
578
583
|
throw new Error("Variable must be a MultiDimensional array");
|
|
@@ -582,6 +587,12 @@ export function _bindExtensionObjectArrayOrMatrix(
|
|
|
582
587
|
if (!isVariableContainingExtensionObject(uaVariable)) {
|
|
583
588
|
return [];
|
|
584
589
|
}
|
|
590
|
+
|
|
591
|
+
if (!optionalExtensionObjectArray && uaVariable.$dataValue.value.value) {
|
|
592
|
+
assert(Array.isArray(uaVariable.$dataValue.value.value));
|
|
593
|
+
optionalExtensionObjectArray = uaVariable.$dataValue.value.value;
|
|
594
|
+
}
|
|
595
|
+
|
|
585
596
|
if ((arrayDimensions.length === 0 || arrayDimensions.length === 1 && arrayDimensions[0] === 0) && optionalExtensionObjectArray) {
|
|
586
597
|
arrayDimensions[0] = optionalExtensionObjectArray.length;
|
|
587
598
|
}
|
|
@@ -607,6 +618,21 @@ export function _bindExtensionObjectArrayOrMatrix(
|
|
|
607
618
|
uaVariable.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
608
619
|
uaVariable.$dataValue.value.value = uaVariable.$$extensionObjectArray;
|
|
609
620
|
|
|
621
|
+
|
|
622
|
+
// make sure uaVariable.$dataValue cannot be inadvertantly changed from this point onward
|
|
623
|
+
const $dataValue = uaVariable.$dataValue;
|
|
624
|
+
Object.defineProperty(uaVariable, "$dataValue", {
|
|
625
|
+
get(): DataValue {
|
|
626
|
+
return $dataValue;
|
|
627
|
+
},
|
|
628
|
+
set() {
|
|
629
|
+
throw new Error("$dataValue is now sealed , you should not change internal $dataValue!");
|
|
630
|
+
},
|
|
631
|
+
// writable: true,
|
|
632
|
+
enumerable: true,
|
|
633
|
+
configurable: true,
|
|
634
|
+
});
|
|
635
|
+
|
|
610
636
|
uaVariable.bindVariable({
|
|
611
637
|
get: () => uaVariable.$dataValue.value
|
|
612
638
|
}, true);
|
|
@@ -620,10 +646,13 @@ export function _bindExtensionObjectArrayOrMatrix(
|
|
|
620
646
|
|
|
621
647
|
const { browseName, nodeId } = composeBrowseNameAndNodeId(uaVariable, index);
|
|
622
648
|
|
|
623
|
-
|
|
624
|
-
|
|
625
649
|
let uaElement = uaVariable.getComponentByName(browseName) as UAVariableImpl | null;
|
|
626
650
|
if (!uaElement) {
|
|
651
|
+
|
|
652
|
+
if (!options.createMissingProp) {
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
|
|
627
656
|
uaElement = namespace.addVariable({
|
|
628
657
|
browseName,
|
|
629
658
|
nodeId,
|
|
@@ -634,7 +663,6 @@ export function _bindExtensionObjectArrayOrMatrix(
|
|
|
634
663
|
}) as UAVariableImpl;
|
|
635
664
|
}
|
|
636
665
|
|
|
637
|
-
uaElement.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
638
666
|
uaElement.$dataValue.statusCode = StatusCodes.Good;
|
|
639
667
|
uaElement.$dataValue.sourceTimestamp = uaVariable.$dataValue.sourceTimestamp;
|
|
640
668
|
uaElement.$dataValue.sourcePicoseconds = uaVariable.$dataValue.sourcePicoseconds;
|
|
@@ -645,16 +673,21 @@ export function _bindExtensionObjectArrayOrMatrix(
|
|
|
645
673
|
|
|
646
674
|
{
|
|
647
675
|
const capturedIndex = i;
|
|
676
|
+
const capturedUaElement = uaElement as UAVariableImpl;
|
|
648
677
|
_innerBindExtensionObjectScalar(uaElement,
|
|
649
678
|
{
|
|
650
679
|
get: () => uaVariable.$$extensionObjectArray[capturedIndex],
|
|
651
|
-
set: (newValue: ExtensionObject, sourceTimestamp: PreciseClock) => {
|
|
652
|
-
uaVariable.$$extensionObjectArray[capturedIndex] = newValue;
|
|
653
|
-
uaVariable.touchValue();
|
|
654
|
-
propagateTouchValueDownward(uaVariable, sourceTimestamp);
|
|
655
|
-
propagateTouchValueUpward(uaVariable, sourceTimestamp);
|
|
656
|
-
},
|
|
680
|
+
set: (newValue: ExtensionObject, sourceTimestamp: PreciseClock, cache: Set<UAVariableImpl>) => {
|
|
657
681
|
|
|
682
|
+
assert(!isProxy(uaVariable.$$extensionObjectArray[capturedIndex]));
|
|
683
|
+
uaVariable.$$extensionObjectArray[capturedIndex] = newValue;
|
|
684
|
+
if (uaVariable.$$extensionObjectArray !== uaVariable.$dataValue.value.value) {
|
|
685
|
+
console.log("uaVariable", uaVariable.nodeId.toString());
|
|
686
|
+
console.log("Houston! We have a problem ");
|
|
687
|
+
}
|
|
688
|
+
propagateTouchValueDownward(capturedUaElement, sourceTimestamp, cache);
|
|
689
|
+
propagateTouchValueUpward(capturedUaElement, sourceTimestamp, cache);
|
|
690
|
+
}
|
|
658
691
|
}, { ...options, force: true });
|
|
659
692
|
|
|
660
693
|
}
|
|
@@ -717,3 +750,23 @@ export function extractPartialData(path: string | string[], extensionObject: Ext
|
|
|
717
750
|
c1[name] = c2[name];
|
|
718
751
|
return partialData;
|
|
719
752
|
}
|
|
753
|
+
|
|
754
|
+
export function propagateTouchValueDownwardArray(uaVariable: UAVariableImpl, now: PreciseClock, cache: Set<UAVariable>) {
|
|
755
|
+
|
|
756
|
+
if (!uaVariable.$$extensionObjectArray) return;
|
|
757
|
+
const arrayDimensions = uaVariable.arrayDimensions || [];
|
|
758
|
+
const totalLength = uaVariable.$$extensionObjectArray.length;
|
|
759
|
+
|
|
760
|
+
const indexIterator = new IndexIterator(arrayDimensions);
|
|
761
|
+
for (let i = 0; i < totalLength; i++) {
|
|
762
|
+
|
|
763
|
+
const index = indexIterator.next();
|
|
764
|
+
|
|
765
|
+
const { browseName, nodeId } = composeBrowseNameAndNodeId(uaVariable, index);
|
|
766
|
+
const uaElement = uaVariable.getComponentByName(browseName) as UAVariableImpl | null;
|
|
767
|
+
if (uaElement?.nodeClass === NodeClass.Variable) {
|
|
768
|
+
uaElement.touchValue(now);
|
|
769
|
+
propagateTouchValueDownward(uaElement, now, cache);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
@@ -40,6 +40,7 @@ import { _clone_children_references, ToStringBuilder, UAVariableType_toString }
|
|
|
40
40
|
import * as tools from "./tool_isSupertypeOf";
|
|
41
41
|
import { get_subtypeOfObj } from "./tool_isSupertypeOf";
|
|
42
42
|
import { get_subtypeOf } from "./tool_isSupertypeOf";
|
|
43
|
+
import { checkValueRankCompatibility } from "./check_value_rank_compatibility";
|
|
43
44
|
|
|
44
45
|
const debugLog = make_debugLog(__filename);
|
|
45
46
|
const doDebug = checkDebugFlag(__filename);
|
|
@@ -50,6 +51,7 @@ const errorLog = make_errorLog(__filename);
|
|
|
50
51
|
let doTrace = checkDebugFlag("INSTANTIATE");
|
|
51
52
|
const traceLog = errorLog;
|
|
52
53
|
|
|
54
|
+
|
|
53
55
|
interface InstantiateS {
|
|
54
56
|
propertyOf?: any;
|
|
55
57
|
componentOf?: any;
|
|
@@ -83,7 +85,17 @@ export function topMostParentIsObjectTypeOrVariableType(addressSpace: AddressSpa
|
|
|
83
85
|
return false;
|
|
84
86
|
}
|
|
85
87
|
export interface UAVariableTypeOptions extends InternalBaseNodeOptions {
|
|
86
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* This attribute indicates whether the Value attribute of the Variableis an array and how many dimensions the array has.
|
|
90
|
+
* It may have the following values:
|
|
91
|
+
* * n > 1: the Value is an array with the specified number of dimensions.
|
|
92
|
+
* * OneDimension (1): The value is an array with one dimension.
|
|
93
|
+
* * OneOrMoreDimensions (0): The value is an array with one or more dimensions.
|
|
94
|
+
* * Scalar (−1): The value is not an array.
|
|
95
|
+
* * Any (−2): The value can be a scalar or an array with any number of dimensions.
|
|
96
|
+
* * ScalarOrOneDimension (−3): The value can be a scalar or a one dimensional array.
|
|
97
|
+
* * All DataTypes are considered to be scalar, even if they have array-like semantics like ByteString and String.
|
|
98
|
+
*/
|
|
87
99
|
valueRank?: number;
|
|
88
100
|
arrayDimensions?: number[] | null;
|
|
89
101
|
historizing?: boolean;
|
|
@@ -227,6 +239,13 @@ export class UAVariableTypeImpl extends BaseNodeImpl implements UAVariableType {
|
|
|
227
239
|
assert(dataType instanceof NodeId);
|
|
228
240
|
|
|
229
241
|
const valueRank = options.valueRank !== undefined ? options.valueRank : this.valueRank;
|
|
242
|
+
|
|
243
|
+
const { result, errorMessage } = checkValueRankCompatibility(valueRank, this.valueRank);
|
|
244
|
+
if (!result) {
|
|
245
|
+
errorLog(errorMessage);
|
|
246
|
+
throw new Error(errorMessage);
|
|
247
|
+
}
|
|
248
|
+
|
|
230
249
|
const arrayDimensions = options.arrayDimensions !== undefined ? options.arrayDimensions : this.arrayDimensions;
|
|
231
250
|
|
|
232
251
|
// istanbul ignore next
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
<Alias Alias="HasProperty">i=46</Alias>
|
|
19
19
|
<Alias Alias="HasSubtype">i=45</Alias>
|
|
20
20
|
<Alias Alias="HasTypeDefinition">i=40</Alias>
|
|
21
|
+
<Alias Alias="PropertyType">i=68</Alias>
|
|
21
22
|
<Alias Alias="Int32">i=6</Alias>
|
|
22
23
|
<Alias Alias="Range">i=884</Alias>
|
|
23
24
|
<Alias Alias="String">i=12</Alias>
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
|
|
34
35
|
<UAVariable NodeId="ns=1;i=1301" BrowseName="Range" AccessLevel="3" DataType="Range">
|
|
35
36
|
<References>
|
|
36
|
-
<Reference ReferenceType="HasTypeDefinition">i=1317</Reference>
|
|
37
|
+
<Reference ReferenceType="HasTypeDefinition">ns=1;i=1317</Reference>
|
|
37
38
|
<Reference ReferenceType="HasModellingRule">i=78</Reference>
|
|
38
39
|
</References>
|
|
39
40
|
<Value>
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
<UAVariableType NodeId="ns=1;i=1317" BrowseName="MyVariableType" AccessLevel="3" DataType="Range">
|
|
55
56
|
<DisplayName>EURange</DisplayName>
|
|
56
57
|
<References>
|
|
57
|
-
<Reference ReferenceType="HasSubtype" IsForward="false">
|
|
58
|
+
<Reference ReferenceType="HasSubtype" IsForward="false">PropertyType</Reference>
|
|
58
59
|
</References>
|
|
59
60
|
<Value>
|
|
60
61
|
<ExtensionObject>
|