node-opcua-address-space 2.59.0 → 2.62.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/address_space_ts.d.ts +0 -2
- package/dist/source/helpers/argument_list.js +12 -1
- package/dist/source/helpers/argument_list.js.map +1 -1
- package/dist/source/helpers/multiform_func.d.ts +11 -0
- package/dist/source/helpers/multiform_func.js +74 -0
- package/dist/source/helpers/multiform_func.js.map +1 -0
- package/dist/source/loader/load_nodeset2.js +47 -64
- package/dist/source/loader/load_nodeset2.js.map +1 -1
- package/dist/source/set_namespace_meta_data.js +1 -1
- package/dist/src/address_space.js +12 -6
- package/dist/src/address_space.js.map +1 -1
- package/dist/src/alarms_and_conditions/condition_snapshot.js +3 -3
- package/dist/src/alarms_and_conditions/condition_snapshot.js.map +1 -1
- package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.js +1 -1
- package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.js.map +1 -1
- package/dist/src/alarms_and_conditions/ua_condition_impl.js +8 -6
- package/dist/src/alarms_and_conditions/ua_condition_impl.js.map +1 -1
- package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.js +1 -1
- package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.js.map +1 -1
- package/dist/src/base_node_impl.js +2 -0
- package/dist/src/base_node_impl.js.map +1 -1
- package/dist/src/base_node_private.d.ts +3 -3
- package/dist/src/base_node_private.js +198 -25
- package/dist/src/base_node_private.js.map +1 -1
- package/dist/src/event_data.js +1 -1
- package/dist/src/event_data.js.map +1 -1
- package/dist/src/namespace_impl.js +5 -5
- package/dist/src/namespace_impl.js.map +1 -1
- package/dist/src/nodeset_tools/nodeset_to_xml.js +15 -9
- package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/src/nodeset_tools/typedictionary_to_xml.js +17 -10
- package/dist/src/nodeset_tools/typedictionary_to_xml.js.map +1 -1
- package/dist/src/state_machine/ua_shelving_state_machine_ex.js +20 -13
- package/dist/src/state_machine/ua_shelving_state_machine_ex.js.map +1 -1
- package/dist/src/ua_data_type_impl.d.ts +15 -5
- package/dist/src/ua_data_type_impl.js +129 -51
- package/dist/src/ua_data_type_impl.js.map +1 -1
- package/dist/src/ua_method_impl.js +2 -1
- package/dist/src/ua_method_impl.js.map +1 -1
- package/dist/src/ua_object_impl.js +2 -1
- package/dist/src/ua_object_impl.js.map +1 -1
- package/dist/src/ua_object_type_impl.js +1 -0
- package/dist/src/ua_object_type_impl.js.map +1 -1
- package/dist/src/ua_variable_impl.d.ts +12 -18
- package/dist/src/ua_variable_impl.js +287 -215
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/dist/src/ua_variable_type_impl.d.ts +3 -4
- package/dist/src/ua_variable_type_impl.js +61 -52
- package/dist/src/ua_variable_type_impl.js.map +1 -1
- package/dist/src/ua_view_impl.js +1 -1
- package/dist/src/ua_view_impl.js.map +1 -1
- package/distHelpers/mock_session.js +1 -1
- package/distHelpers/mock_session.js.map +1 -1
- package/package.json +35 -35
- package/source/address_space_ts.ts +0 -1
- package/source/helpers/argument_list.ts +13 -3
- package/source/helpers/multiform_func.ts +76 -0
- package/source/loader/load_nodeset2.ts +64 -80
- package/source/set_namespace_meta_data.ts +1 -1
- package/src/address_space.ts +16 -7
- package/src/alarms_and_conditions/condition_snapshot.ts +4 -4
- package/src/alarms_and_conditions/ua_alarm_condition_impl.ts +2 -2
- package/src/alarms_and_conditions/ua_condition_impl.ts +18 -8
- package/src/alarms_and_conditions/ua_off_normal_alarm_impl.ts +1 -1
- package/src/base_node_impl.ts +3 -1
- package/src/base_node_private.ts +282 -36
- package/src/event_data.ts +1 -1
- package/src/namespace_impl.ts +6 -6
- package/src/nodeset_tools/nodeset_to_xml.ts +20 -10
- package/src/nodeset_tools/typedictionary_to_xml.ts +17 -7
- package/src/state_machine/ua_shelving_state_machine_ex.ts +28 -16
- package/src/ua_data_type_impl.ts +168 -61
- package/src/ua_method_impl.ts +10 -2
- package/src/ua_object_impl.ts +10 -2
- package/src/ua_object_type_impl.ts +1 -0
- package/src/ua_variable_impl.ts +421 -325
- package/src/ua_variable_type_impl.ts +87 -52
- package/src/ua_view_impl.ts +1 -1
- package/test_helpers/mock_session.ts +1 -1
- package/test_helpers/test_fixtures/fixture_simple_statemachine_nodeset2.xml +18 -0
- package/test_helpers/test_fixtures/fixuture_nodeset_objects_with_some_methods.xml +9 -1
- package/test_helpers/test_fixtures/mini.Node.Set2.xml +22 -1
package/src/ua_variable_impl.ts
CHANGED
|
@@ -8,7 +8,19 @@
|
|
|
8
8
|
// tslint:disable:max-line-length
|
|
9
9
|
import * as chalk from "chalk";
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
CloneExtraInfo,
|
|
13
|
+
ContinuationData,
|
|
14
|
+
defaultCloneExtraInfo,
|
|
15
|
+
defaultCloneFilter,
|
|
16
|
+
GetFunc,
|
|
17
|
+
SetFunc,
|
|
18
|
+
VariableDataValueGetterCallback,
|
|
19
|
+
VariableDataValueGetterPromise,
|
|
20
|
+
VariableDataValueGetterSync,
|
|
21
|
+
VariableDataValueSetterWithCallback,
|
|
22
|
+
VariableDataValueSetterWithPromise
|
|
23
|
+
} from "node-opcua-address-space-base";
|
|
12
24
|
import { assert } from "node-opcua-assert";
|
|
13
25
|
import {
|
|
14
26
|
isValidDataEncoding,
|
|
@@ -37,17 +49,25 @@ import {
|
|
|
37
49
|
ReadProcessedDetails,
|
|
38
50
|
ReadRawModifiedDetails,
|
|
39
51
|
StructureDefinition,
|
|
52
|
+
StructureField,
|
|
40
53
|
WriteValueOptions
|
|
41
54
|
} from "node-opcua-types";
|
|
42
55
|
import * as utils from "node-opcua-utils";
|
|
43
56
|
import { lowerFirstLetter } from "node-opcua-utils";
|
|
44
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
Variant,
|
|
59
|
+
VariantLike,
|
|
60
|
+
DataType,
|
|
61
|
+
sameVariant,
|
|
62
|
+
VariantArrayType,
|
|
63
|
+
adjustVariant,
|
|
64
|
+
verifyRankAndDimensions
|
|
65
|
+
} from "node-opcua-variant";
|
|
45
66
|
import { StatusCodeCallback } from "node-opcua-status-code";
|
|
46
67
|
import {
|
|
47
68
|
IAddressSpace,
|
|
48
69
|
BindVariableOptions,
|
|
49
70
|
ContinuationPoint,
|
|
50
|
-
DataValueCallback,
|
|
51
71
|
IVariableHistorian,
|
|
52
72
|
TimestampGetFunc,
|
|
53
73
|
TimestampSetFunc,
|
|
@@ -56,7 +76,6 @@ import {
|
|
|
56
76
|
UAVariableType,
|
|
57
77
|
CloneOptions,
|
|
58
78
|
CloneFilter,
|
|
59
|
-
CloneExtraInfo,
|
|
60
79
|
ISessionContext,
|
|
61
80
|
BaseNode,
|
|
62
81
|
UAVariableT
|
|
@@ -64,6 +83,7 @@ import {
|
|
|
64
83
|
import { UAHistoricalDataConfiguration } from "node-opcua-nodeset-ua";
|
|
65
84
|
|
|
66
85
|
import { SessionContext } from "../source/session_context";
|
|
86
|
+
import { convertToCallbackFunction1 } from "../source/helpers/multiform_func";
|
|
67
87
|
import { BaseNodeImpl, InternalBaseNodeOptions } from "./base_node_impl";
|
|
68
88
|
import { _clone, ToStringBuilder, UAVariable_toString, valueRankToString } from "./base_node_private";
|
|
69
89
|
import { EnumerationInfo, IEnumItem, UADataTypeImpl } from "./ua_data_type_impl";
|
|
@@ -162,16 +182,16 @@ function validateDataType(
|
|
|
162
182
|
if (variantDataType === DataType.Null && !allowNulls) {
|
|
163
183
|
return false;
|
|
164
184
|
}
|
|
165
|
-
let builtInType:
|
|
185
|
+
let builtInType: DataType;
|
|
166
186
|
let builtInUADataType: UADataType;
|
|
167
187
|
|
|
168
|
-
const destUADataType = addressSpace.
|
|
188
|
+
const destUADataType = addressSpace.findDataType(dataTypeNodeId)!;
|
|
169
189
|
assert(destUADataType instanceof UADataTypeImpl);
|
|
170
190
|
|
|
171
191
|
if (destUADataType.isAbstract || destUADataType.nodeId.namespace !== 0) {
|
|
172
192
|
builtInUADataType = destUADataType;
|
|
173
193
|
} else {
|
|
174
|
-
builtInType =
|
|
194
|
+
builtInType = addressSpace.findCorrespondingBasicDataType(destUADataType);
|
|
175
195
|
builtInUADataType = addressSpace.findDataType(builtInType)!;
|
|
176
196
|
}
|
|
177
197
|
assert(builtInUADataType instanceof UADataTypeImpl);
|
|
@@ -183,8 +203,8 @@ function validateDataType(
|
|
|
183
203
|
if (destUADataType.isSupertypeOf(enumerationUADataType)) {
|
|
184
204
|
// istanbul ignore next
|
|
185
205
|
if (doDebug) {
|
|
186
|
-
|
|
187
|
-
|
|
206
|
+
debugLog("destUADataType.", destUADataType.browseName.toString(), destUADataType.nodeId.toString());
|
|
207
|
+
debugLog(
|
|
188
208
|
"enumerationUADataType.",
|
|
189
209
|
enumerationUADataType.browseName.toString(),
|
|
190
210
|
enumerationUADataType.nodeId.toString()
|
|
@@ -203,19 +223,23 @@ function validateDataType(
|
|
|
203
223
|
if (doDebug) {
|
|
204
224
|
if (dest_isSuperTypeOf_variant) {
|
|
205
225
|
/* istanbul ignore next*/
|
|
206
|
-
|
|
226
|
+
debugLog(chalk.green(" ---------- Type match !!! "), " on ", nodeId.toString());
|
|
207
227
|
} else {
|
|
208
228
|
/* istanbul ignore next*/
|
|
209
|
-
|
|
229
|
+
debugLog(chalk.red(" ---------- Type mismatch "), " on ", nodeId.toString());
|
|
210
230
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
debugLog(chalk.cyan(" Variable data Type is = "), destUADataType.browseName.toString());
|
|
232
|
+
debugLog(chalk.cyan(" which matches basic Type = "), builtInUADataType.browseName.toString());
|
|
233
|
+
debugLog(chalk.yellow(" Actual dataType = "), variantUADataType.browseName.toString());
|
|
214
234
|
}
|
|
215
235
|
|
|
216
236
|
return dest_isSuperTypeOf_variant;
|
|
217
237
|
}
|
|
218
238
|
|
|
239
|
+
function default_func(this: UAVariable, dataValue1: DataValue, callback1: CallbackT<StatusCode>) {
|
|
240
|
+
return _default_writable_timestamped_set_func.call(this, dataValue1, callback1);
|
|
241
|
+
}
|
|
242
|
+
|
|
219
243
|
interface UAVariableOptions extends InternalBaseNodeOptions {
|
|
220
244
|
value?: any;
|
|
221
245
|
dataType: NodeId | string;
|
|
@@ -227,50 +251,6 @@ interface UAVariableOptions extends InternalBaseNodeOptions {
|
|
|
227
251
|
historizing?: number;
|
|
228
252
|
}
|
|
229
253
|
|
|
230
|
-
export function verifyRankAndDimensions(options: { valueRank?: number; arrayDimensions?: number[] | null }): void {
|
|
231
|
-
// evaluate valueRank arrayDimensions is specified but valueRank is null
|
|
232
|
-
if (options.arrayDimensions && options.valueRank === undefined) {
|
|
233
|
-
options.valueRank = options.arrayDimensions.length;
|
|
234
|
-
}
|
|
235
|
-
options.valueRank = options.valueRank === undefined ? -1 : options.valueRank || 0; // UInt32
|
|
236
|
-
assert(typeof options.valueRank === "number");
|
|
237
|
-
|
|
238
|
-
options.arrayDimensions = options.arrayDimensions || null;
|
|
239
|
-
assert(options.arrayDimensions === null || Array.isArray(options.arrayDimensions));
|
|
240
|
-
|
|
241
|
-
if (options.arrayDimensions && options.valueRank <= 0) {
|
|
242
|
-
throw new Error("[CONFORMANCE] arrayDimensions must be null if valueRank <=0");
|
|
243
|
-
}
|
|
244
|
-
// specify default arrayDimension if not provided
|
|
245
|
-
if (options.valueRank > 0 && !options.arrayDimensions) {
|
|
246
|
-
options.arrayDimensions = new Array(options.valueRank).fill(0);
|
|
247
|
-
}
|
|
248
|
-
if (!options.arrayDimensions && options.valueRank > 0) {
|
|
249
|
-
throw new Error("[CONFORMANCE] arrayDimension must be specified if valueRank >0 " + options.valueRank);
|
|
250
|
-
}
|
|
251
|
-
if (options.valueRank > 0 && options.arrayDimensions!.length !== options.valueRank) {
|
|
252
|
-
throw new Error(
|
|
253
|
-
"[CONFORMANCE] when valueRank> 0, arrayDimensions must have valueRank elements, this.valueRank =" +
|
|
254
|
-
options.valueRank +
|
|
255
|
-
" whereas arrayDimensions.length =" +
|
|
256
|
-
options.arrayDimensions!.length
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
type TimestampGetFunction1 = () => DataValue | Promise<DataValue>;
|
|
262
|
-
type TimestampGetFunction2 = (callback: (err: Error | null, dataValue?: DataValue) => void) => void;
|
|
263
|
-
type TimestampGetFunction = TimestampGetFunction1 | TimestampGetFunction2;
|
|
264
|
-
|
|
265
|
-
type TimestampSetFunction1 = (this: UAVariable, dataValue: DataValue, indexRange: NumericRange) => void | Promise<void>;
|
|
266
|
-
type TimestampSetFunction2 = (
|
|
267
|
-
this: UAVariable,
|
|
268
|
-
dataValue: DataValue,
|
|
269
|
-
indexRange: NumericRange,
|
|
270
|
-
callback: (err: Error | null, StatusCode: StatusCode) => void
|
|
271
|
-
) => void;
|
|
272
|
-
type TimestampSetFunction = TimestampSetFunction1 | TimestampSetFunction2;
|
|
273
|
-
|
|
274
254
|
/**
|
|
275
255
|
* A OPCUA Variable Node
|
|
276
256
|
*
|
|
@@ -299,7 +279,9 @@ type TimestampSetFunction = TimestampSetFunction1 | TimestampSetFunction2;
|
|
|
299
279
|
*/
|
|
300
280
|
export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
301
281
|
public readonly nodeClass = NodeClass.Variable;
|
|
282
|
+
|
|
302
283
|
public dataType: NodeId;
|
|
284
|
+
private _basicDataType?: DataType;
|
|
303
285
|
|
|
304
286
|
public $extensionObject?: any;
|
|
305
287
|
|
|
@@ -307,9 +289,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
307
289
|
public varHistorian?: IVariableHistorian;
|
|
308
290
|
|
|
309
291
|
/**
|
|
310
|
-
* @internal
|
|
292
|
+
* @internal @private
|
|
311
293
|
*/
|
|
312
|
-
public
|
|
294
|
+
public $dataValue: DataValue;
|
|
313
295
|
public accessLevel: number;
|
|
314
296
|
public userAccessLevel?: number;
|
|
315
297
|
public valueRank: number;
|
|
@@ -318,11 +300,11 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
318
300
|
public semantic_version: number;
|
|
319
301
|
public arrayDimensions: null | number[];
|
|
320
302
|
|
|
321
|
-
public _timestamped_get_func?:
|
|
322
|
-
public _timestamped_set_func?:
|
|
303
|
+
public _timestamped_get_func?: TimestampGetFunc | null;
|
|
304
|
+
public _timestamped_set_func?: VariableDataValueSetterWithCallback | null;
|
|
323
305
|
public _get_func: any;
|
|
324
306
|
public _set_func: any;
|
|
325
|
-
public refreshFunc?: (callback:
|
|
307
|
+
public refreshFunc?: (callback: CallbackT<DataValue>) => void;
|
|
326
308
|
public __waiting_callbacks?: any[];
|
|
327
309
|
|
|
328
310
|
get typeDefinitionObj(): UAVariableType {
|
|
@@ -346,11 +328,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
346
328
|
|
|
347
329
|
this.minimumSamplingInterval = adjust_samplingInterval(options.minimumSamplingInterval || 0);
|
|
348
330
|
|
|
349
|
-
this.historizing = !!options.historizing; // coerced to boolean
|
|
350
|
-
|
|
351
|
-
this._dataValue = new DataValue({ statusCode: StatusCodes.UncertainInitialValue, value: {} });
|
|
331
|
+
this.historizing = !!options.historizing; // coerced to boolean"
|
|
352
332
|
|
|
353
|
-
|
|
333
|
+
this.$dataValue = new DataValue({ statusCode: StatusCodes.UncertainInitialValue, value: { dataType: DataType.Null } });
|
|
354
334
|
|
|
355
335
|
if (options.value) {
|
|
356
336
|
this.bindVariable(options.value);
|
|
@@ -453,11 +433,17 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
453
433
|
|
|
454
434
|
if (this._timestamped_get_func) {
|
|
455
435
|
if (this._timestamped_get_func.length === 0) {
|
|
456
|
-
|
|
436
|
+
const dataValueOrPromise = (this._timestamped_get_func as VariableDataValueGetterSync)();
|
|
437
|
+
if (!Object.prototype.hasOwnProperty.call(dataValueOrPromise, "then")) {
|
|
438
|
+
this.$dataValue = dataValueOrPromise as DataValue;
|
|
439
|
+
this.verifyVariantCompatibility(this.$dataValue.value);
|
|
440
|
+
} else {
|
|
441
|
+
errorLog("Unsupported: _timestamped_get_func returns a Promise !");
|
|
442
|
+
}
|
|
457
443
|
}
|
|
458
444
|
}
|
|
459
445
|
|
|
460
|
-
let dataValue = this
|
|
446
|
+
let dataValue = this.$dataValue;
|
|
461
447
|
|
|
462
448
|
if (isGoodish(dataValue.statusCode)) {
|
|
463
449
|
// note : extractRange will clone the dataValue
|
|
@@ -504,12 +490,16 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
504
490
|
return dataTypeNode._getEnumerationInfo();
|
|
505
491
|
}
|
|
506
492
|
|
|
507
|
-
public asyncRefresh(oldestDate: Date, callback:
|
|
493
|
+
public asyncRefresh(oldestDate: Date, callback: CallbackT<DataValue>): void;
|
|
508
494
|
public asyncRefresh(oldestDate: Date): Promise<DataValue>;
|
|
509
495
|
public asyncRefresh(...args: any[]): any {
|
|
496
|
+
if (isGoodish(this.$dataValue.statusCode)) {
|
|
497
|
+
this.verifyVariantCompatibility(this.$dataValue.value);
|
|
498
|
+
}
|
|
499
|
+
|
|
510
500
|
const oldestDate = args[0] as Date;
|
|
511
501
|
assert(oldestDate instanceof Date);
|
|
512
|
-
const callback = args[1] as
|
|
502
|
+
const callback = args[1] as CallbackT<DataValue>;
|
|
513
503
|
|
|
514
504
|
if (!this.refreshFunc) {
|
|
515
505
|
// no refresh func
|
|
@@ -524,22 +514,36 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
524
514
|
}
|
|
525
515
|
}
|
|
526
516
|
|
|
527
|
-
if (this.
|
|
517
|
+
if (this.$dataValue.serverTimestamp && oldestDate.getTime() <= this.$dataValue.serverTimestamp!.getTime()) {
|
|
528
518
|
const dataValue = this.readValue();
|
|
529
519
|
dataValue.serverTimestamp = oldestDate;
|
|
530
520
|
dataValue.serverPicoseconds = 0;
|
|
531
521
|
return callback(null, dataValue);
|
|
532
522
|
}
|
|
533
523
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
524
|
+
try {
|
|
525
|
+
this.refreshFunc.call(this, (err: Error | null, dataValue?: DataValueLike) => {
|
|
526
|
+
if (err || !dataValue) {
|
|
527
|
+
errorLog(
|
|
528
|
+
"-------------- refresh call failed",
|
|
529
|
+
this.browseName.toString(),
|
|
530
|
+
this.nodeId.toString(),
|
|
531
|
+
err?.message
|
|
532
|
+
);
|
|
533
|
+
dataValue = { statusCode: StatusCodes.BadNoDataAvailable };
|
|
534
|
+
}
|
|
535
|
+
if (dataValue !== this.$dataValue) {
|
|
536
|
+
this._internal_set_dataValue(coerceDataValue(dataValue), null);
|
|
537
|
+
}
|
|
538
|
+
callback(err, this.$dataValue);
|
|
539
|
+
});
|
|
540
|
+
} catch (err) {
|
|
541
|
+
errorLog("-------------- refresh call failed 2", this.browseName.toString(), this.nodeId.toString());
|
|
542
|
+
errorLog(err);
|
|
543
|
+
const dataValue = new DataValue({ statusCode: StatusCodes.BadInternalError });
|
|
544
|
+
this._internal_set_dataValue(dataValue, null);
|
|
545
|
+
callback(err as Error, this.$dataValue);
|
|
546
|
+
}
|
|
543
547
|
}
|
|
544
548
|
|
|
545
549
|
public readEnumValue(): IEnumItem {
|
|
@@ -629,10 +633,91 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
629
633
|
}
|
|
630
634
|
}
|
|
631
635
|
|
|
632
|
-
public
|
|
636
|
+
public getBasicDataType(): DataType {
|
|
637
|
+
if (this._basicDataType) {
|
|
638
|
+
return this._basicDataType;
|
|
639
|
+
}
|
|
640
|
+
if (this.dataType.namespace === 0 && this.dataType.value === 0) {
|
|
641
|
+
return DataType.Null;
|
|
642
|
+
}
|
|
633
643
|
const addressSpace = this.addressSpace;
|
|
634
|
-
const
|
|
635
|
-
|
|
644
|
+
const dataTypeNode = addressSpace.findDataType(this.dataType)!;
|
|
645
|
+
const basicDataType = dataTypeNode ? dataTypeNode.getBasicDataType() : DataType.Null;
|
|
646
|
+
// const basicDataType = addressSpace.findCorrespondingBasicDataType(this.dataType);
|
|
647
|
+
this._basicDataType = basicDataType;
|
|
648
|
+
return basicDataType;
|
|
649
|
+
}
|
|
650
|
+
public adjustVariant(variant: Variant): Variant {
|
|
651
|
+
return adjustVariant(variant, this.valueRank, this.getBasicDataType());
|
|
652
|
+
}
|
|
653
|
+
public verifyVariantCompatibility(variant: Variant): void {
|
|
654
|
+
try {
|
|
655
|
+
// istanbul ignore next
|
|
656
|
+
if (Object.prototype.hasOwnProperty.call(variant, "value")) {
|
|
657
|
+
if (variant.dataType === null || variant.dataType === undefined) {
|
|
658
|
+
throw new Error(
|
|
659
|
+
"Variant must provide a valid dataType : variant = " +
|
|
660
|
+
variant.toString() +
|
|
661
|
+
" this.dataType= " +
|
|
662
|
+
this.dataType.toString()
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
if (
|
|
666
|
+
variant.dataType === DataType.Boolean &&
|
|
667
|
+
(this.dataType.namespace !== 0 || this.dataType.value !== DataType.Boolean)
|
|
668
|
+
) {
|
|
669
|
+
throw new Error(
|
|
670
|
+
"Variant must provide a valid Boolean : variant = " +
|
|
671
|
+
variant.toString() +
|
|
672
|
+
" this.dataType= " +
|
|
673
|
+
this.dataType.toString()
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
if (
|
|
677
|
+
this.dataType.namespace === 0 &&
|
|
678
|
+
this.dataType.value === DataType.LocalizedText &&
|
|
679
|
+
variant.dataType !== DataType.LocalizedText
|
|
680
|
+
) {
|
|
681
|
+
throw new Error(
|
|
682
|
+
"Variant must provide a valid LocalizedText : variant = " +
|
|
683
|
+
variant.toString() +
|
|
684
|
+
" this.dataType= " +
|
|
685
|
+
this.dataType.toString()
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
const basicType = this.getBasicDataType();
|
|
690
|
+
if (
|
|
691
|
+
basicType !== DataType.Null &&
|
|
692
|
+
basicType !== DataType.Variant &&
|
|
693
|
+
variant.dataType !== DataType.Null &&
|
|
694
|
+
variant.dataType !== basicType
|
|
695
|
+
) {
|
|
696
|
+
const message =
|
|
697
|
+
"UAVariable.setValueFromSource " +
|
|
698
|
+
this.browseName.toString() +
|
|
699
|
+
" nodeId:" +
|
|
700
|
+
this.nodeId.toString() +
|
|
701
|
+
" dataType:" +
|
|
702
|
+
this.dataType.toString() +
|
|
703
|
+
":\n" +
|
|
704
|
+
"the provided variant must have the expected dataType!\n" +
|
|
705
|
+
" - the expected dataType is " +
|
|
706
|
+
chalk.cyan(DataType[basicType]) +
|
|
707
|
+
"\n" +
|
|
708
|
+
" - the actual dataType is " +
|
|
709
|
+
chalk.magenta(DataType[variant.dataType]) +
|
|
710
|
+
"\n" +
|
|
711
|
+
" - " +
|
|
712
|
+
variant.toString();
|
|
713
|
+
throw new Error(message);
|
|
714
|
+
}
|
|
715
|
+
} catch (err) {
|
|
716
|
+
errorLog("UAVariable ", (err as Error)?.message, this.browseName.toString(), " nodeId=", this.nodeId.toString());
|
|
717
|
+
errorLog((err as Error).message);
|
|
718
|
+
errorLog((err as Error).stack);
|
|
719
|
+
throw err;
|
|
720
|
+
}
|
|
636
721
|
}
|
|
637
722
|
/**
|
|
638
723
|
* setValueFromSource is used to let the device sets the variable values
|
|
@@ -646,39 +731,26 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
646
731
|
* @param [sourceTimestamp= Now]
|
|
647
732
|
*/
|
|
648
733
|
public setValueFromSource(variant: VariantLike, statusCode?: StatusCode, sourceTimestamp?: Date): void {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
)
|
|
666
|
-
|
|
667
|
-
|
|
734
|
+
try {
|
|
735
|
+
statusCode = statusCode || StatusCodes.Good;
|
|
736
|
+
const variant1 = Variant.coerce(variant);
|
|
737
|
+
this.verifyVariantCompatibility(variant1);
|
|
738
|
+
const now = coerceClock(sourceTimestamp, 0);
|
|
739
|
+
|
|
740
|
+
const dataValue = new DataValue(null);
|
|
741
|
+
dataValue.serverPicoseconds = now.picoseconds;
|
|
742
|
+
dataValue.serverTimestamp = now.timestamp;
|
|
743
|
+
dataValue.sourcePicoseconds = now.picoseconds;
|
|
744
|
+
dataValue.sourceTimestamp = now.timestamp;
|
|
745
|
+
dataValue.statusCode = statusCode;
|
|
746
|
+
dataValue.value = variant1;
|
|
747
|
+
this._internal_set_dataValue(dataValue);
|
|
748
|
+
} catch (err) {
|
|
749
|
+
errorLog("UAVariable#setValueFromString Error : ", this.browseName.toString(), this.nodeId.toString());
|
|
750
|
+
errorLog((err as Error).message);
|
|
751
|
+
errorLog(this.parent?.toString());
|
|
752
|
+
throw err;
|
|
668
753
|
}
|
|
669
|
-
|
|
670
|
-
const variant1 = Variant.coerce(variant);
|
|
671
|
-
|
|
672
|
-
const now = coerceClock(sourceTimestamp, 0);
|
|
673
|
-
|
|
674
|
-
const dataValue = new DataValue(null);
|
|
675
|
-
dataValue.serverPicoseconds = now.picoseconds;
|
|
676
|
-
dataValue.serverTimestamp = now.timestamp;
|
|
677
|
-
dataValue.sourcePicoseconds = now.picoseconds;
|
|
678
|
-
dataValue.sourceTimestamp = now.timestamp;
|
|
679
|
-
dataValue.statusCode = statusCode;
|
|
680
|
-
dataValue.value = variant1;
|
|
681
|
-
this._internal_set_dataValue(dataValue);
|
|
682
754
|
}
|
|
683
755
|
|
|
684
756
|
public writeValue(
|
|
@@ -749,16 +821,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
749
821
|
return callback!(null, statusCode);
|
|
750
822
|
}
|
|
751
823
|
|
|
752
|
-
|
|
753
|
-
this: UAVariable,
|
|
754
|
-
dataValue1: DataValue,
|
|
755
|
-
indexRange1: NumericRange,
|
|
756
|
-
callback1: (err: Error | null, statusCode: StatusCode, dataValue?: DataValue | null | undefined) => void
|
|
757
|
-
) {
|
|
758
|
-
// xx assert(!indexRange,"indexRange Not Implemented");
|
|
759
|
-
return _default_writable_timestamped_set_func.call(this, dataValue1, callback1);
|
|
760
|
-
}
|
|
761
|
-
const write_func = (this._timestamped_set_func || default_func) as any;
|
|
824
|
+
const write_func = this._timestamped_set_func || default_func;
|
|
762
825
|
|
|
763
826
|
if (!write_func) {
|
|
764
827
|
warningLog(" warning " + this.nodeId.toString() + " " + this.browseName.toString() + " has no setter. \n");
|
|
@@ -767,77 +830,70 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
767
830
|
}
|
|
768
831
|
assert(write_func);
|
|
769
832
|
|
|
770
|
-
write_func.call(
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
833
|
+
write_func.call(this, dataValue, (err?: Error | null, statusCode1?: StatusCode) => {
|
|
834
|
+
if (!err) {
|
|
835
|
+
dataValue && this.verifyVariantCompatibility(dataValue.value);
|
|
836
|
+
|
|
837
|
+
if (indexRange && !indexRange.isEmpty()) {
|
|
838
|
+
if (!indexRange.isValid()) {
|
|
839
|
+
return callback!(null, StatusCodes.BadIndexRangeInvalid);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const newArrayOrMatrix = dataValue.value.value;
|
|
843
|
+
|
|
844
|
+
if (dataValue.value.arrayType === VariantArrayType.Array) {
|
|
845
|
+
if (this.$dataValue.value.arrayType !== VariantArrayType.Array) {
|
|
846
|
+
return callback(null, StatusCodes.BadTypeMismatch);
|
|
783
847
|
}
|
|
848
|
+
// check that destination data is also an array
|
|
849
|
+
assert(check_valid_array(this.$dataValue.value.dataType, this.$dataValue.value.value));
|
|
850
|
+
const destArr = this.$dataValue.value.value;
|
|
851
|
+
const result = indexRange.set_values(destArr, newArrayOrMatrix);
|
|
784
852
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (result.statusCode.isNot(StatusCodes.Good)) {
|
|
797
|
-
return callback!(null, result.statusCode);
|
|
798
|
-
}
|
|
799
|
-
correctedDataValue.value.value = result.array;
|
|
800
|
-
|
|
801
|
-
// scrap original array so we detect range
|
|
802
|
-
this._dataValue.value.value = null;
|
|
803
|
-
} else if (correctedDataValue.value.arrayType === VariantArrayType.Matrix) {
|
|
804
|
-
const dimensions = this._dataValue.value.dimensions;
|
|
805
|
-
if (this._dataValue.value.arrayType !== VariantArrayType.Matrix || !dimensions) {
|
|
806
|
-
// not a matrix !
|
|
807
|
-
return callback!(null, StatusCodes.BadTypeMismatch);
|
|
808
|
-
}
|
|
809
|
-
const matrix = this._dataValue.value.value;
|
|
810
|
-
const result = indexRange.set_values_matrix(
|
|
811
|
-
{
|
|
812
|
-
matrix,
|
|
813
|
-
dimensions
|
|
814
|
-
},
|
|
815
|
-
newArrayOrMatrix
|
|
816
|
-
);
|
|
817
|
-
if (result.statusCode.isNot(StatusCodes.Good)) {
|
|
818
|
-
return callback!(null, result.statusCode);
|
|
819
|
-
}
|
|
820
|
-
correctedDataValue.value.dimensions = this._dataValue.value.dimensions;
|
|
821
|
-
correctedDataValue.value.value = result.matrix;
|
|
822
|
-
|
|
823
|
-
// scrap original array so we detect range
|
|
824
|
-
this._dataValue.value.value = null;
|
|
825
|
-
} else {
|
|
853
|
+
if (result.statusCode.isNot(StatusCodes.Good)) {
|
|
854
|
+
return callback!(null, result.statusCode);
|
|
855
|
+
}
|
|
856
|
+
dataValue.value.value = result.array;
|
|
857
|
+
|
|
858
|
+
// scrap original array so we detect range
|
|
859
|
+
this.$dataValue.value.value = null;
|
|
860
|
+
} else if (dataValue.value.arrayType === VariantArrayType.Matrix) {
|
|
861
|
+
const dimensions = this.$dataValue.value.dimensions;
|
|
862
|
+
if (this.$dataValue.value.arrayType !== VariantArrayType.Matrix || !dimensions) {
|
|
863
|
+
// not a matrix !
|
|
826
864
|
return callback!(null, StatusCodes.BadTypeMismatch);
|
|
827
865
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
866
|
+
const matrix = this.$dataValue.value.value;
|
|
867
|
+
const result = indexRange.set_values_matrix(
|
|
868
|
+
{
|
|
869
|
+
matrix,
|
|
870
|
+
dimensions
|
|
871
|
+
},
|
|
872
|
+
newArrayOrMatrix
|
|
873
|
+
);
|
|
874
|
+
if (result.statusCode.isNot(StatusCodes.Good)) {
|
|
875
|
+
return callback!(null, result.statusCode);
|
|
834
876
|
}
|
|
835
|
-
|
|
877
|
+
dataValue.value.dimensions = this.$dataValue.value.dimensions;
|
|
878
|
+
dataValue.value.value = result.matrix;
|
|
879
|
+
|
|
880
|
+
// scrap original array so we detect range
|
|
881
|
+
this.$dataValue.value.value = null;
|
|
882
|
+
} else {
|
|
883
|
+
return callback!(null, StatusCodes.BadTypeMismatch);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
try {
|
|
887
|
+
this._internal_set_dataValue(dataValue, indexRange);
|
|
888
|
+
} catch (err) {
|
|
889
|
+
if (err instanceof Error) {
|
|
890
|
+
warningLog(err.message);
|
|
836
891
|
}
|
|
892
|
+
return callback!(null, StatusCodes.BadInternalError);
|
|
837
893
|
}
|
|
838
|
-
callback!(err, statusCode1);
|
|
839
894
|
}
|
|
840
|
-
|
|
895
|
+
callback!(err || null, statusCode1);
|
|
896
|
+
});
|
|
841
897
|
}
|
|
842
898
|
|
|
843
899
|
public writeAttribute(context: ISessionContext | null, writeValue: WriteValueOptions, callback: StatusCodeCallback): void;
|
|
@@ -903,6 +959,11 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
903
959
|
if (!this._validate_DataType(value.dataType)) {
|
|
904
960
|
return StatusCodes.BadTypeMismatch;
|
|
905
961
|
}
|
|
962
|
+
try {
|
|
963
|
+
this.verifyVariantCompatibility(value);
|
|
964
|
+
} catch (err) {
|
|
965
|
+
return StatusCodes.BadTypeMismatch;
|
|
966
|
+
}
|
|
906
967
|
return StatusCodes.Good;
|
|
907
968
|
}
|
|
908
969
|
|
|
@@ -917,12 +978,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
917
978
|
*/
|
|
918
979
|
public touchValue(optionalNow?: PreciseClock): void {
|
|
919
980
|
const now = optionalNow || getCurrentClock();
|
|
920
|
-
this.
|
|
921
|
-
this.
|
|
922
|
-
this.
|
|
923
|
-
this.
|
|
981
|
+
this.$dataValue.sourceTimestamp = now.timestamp;
|
|
982
|
+
this.$dataValue.sourcePicoseconds = now.picoseconds;
|
|
983
|
+
this.$dataValue.serverTimestamp = now.timestamp;
|
|
984
|
+
this.$dataValue.serverPicoseconds = now.picoseconds;
|
|
924
985
|
|
|
925
|
-
this.
|
|
986
|
+
this.$dataValue.statusCode = StatusCodes.Good;
|
|
926
987
|
|
|
927
988
|
if (this.minimumSamplingInterval === 0) {
|
|
928
989
|
if (this.listenerCount("value_changed") > 0) {
|
|
@@ -1070,6 +1131,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1070
1131
|
|
|
1071
1132
|
assert(typeof this._timestamped_set_func !== "function", "UAVariable already bound");
|
|
1072
1133
|
assert(typeof this._timestamped_get_func !== "function", "UAVariable already bound");
|
|
1134
|
+
|
|
1073
1135
|
bind_getter.call(this, options);
|
|
1074
1136
|
bind_setter.call(this, options);
|
|
1075
1137
|
|
|
@@ -1081,9 +1143,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1081
1143
|
this._historyRead = _historyRead;
|
|
1082
1144
|
assert(this._historyRead.length === 6);
|
|
1083
1145
|
}
|
|
1084
|
-
|
|
1146
|
+
// post conditions
|
|
1085
1147
|
assert(typeof this._timestamped_set_func === "function");
|
|
1086
|
-
assert(this._timestamped_set_func!.length ===
|
|
1148
|
+
assert(this._timestamped_set_func!.length === 2, "expecting 2 parameters");
|
|
1087
1149
|
}
|
|
1088
1150
|
|
|
1089
1151
|
/**
|
|
@@ -1106,7 +1168,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1106
1168
|
}
|
|
1107
1169
|
|
|
1108
1170
|
const readImmediate = (innerCallback: (err: Error | null, dataValue: DataValue) => void) => {
|
|
1109
|
-
assert(this
|
|
1171
|
+
assert(this.$dataValue instanceof DataValue);
|
|
1110
1172
|
const dataValue = this.readValue();
|
|
1111
1173
|
innerCallback(null, dataValue);
|
|
1112
1174
|
};
|
|
@@ -1174,14 +1236,20 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1174
1236
|
valueRank: this.valueRank
|
|
1175
1237
|
};
|
|
1176
1238
|
|
|
1177
|
-
const newVariable = _clone.call(
|
|
1239
|
+
const newVariable = _clone.call(
|
|
1240
|
+
this,
|
|
1241
|
+
UAVariableImpl,
|
|
1242
|
+
options,
|
|
1243
|
+
optionalFilter || defaultCloneFilter,
|
|
1244
|
+
extraInfo || defaultCloneExtraInfo
|
|
1245
|
+
) as UAVariableImpl;
|
|
1178
1246
|
|
|
1179
1247
|
newVariable.bindVariable();
|
|
1180
1248
|
|
|
1181
1249
|
assert(typeof newVariable._timestamped_set_func === "function");
|
|
1182
1250
|
|
|
1183
1251
|
assert(newVariable.dataType === this.dataType);
|
|
1184
|
-
newVariable
|
|
1252
|
+
newVariable.$dataValue = this.$dataValue.clone();
|
|
1185
1253
|
return newVariable;
|
|
1186
1254
|
}
|
|
1187
1255
|
|
|
@@ -1204,8 +1272,10 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1204
1272
|
return true;
|
|
1205
1273
|
}
|
|
1206
1274
|
const addressSpace = this.addressSpace;
|
|
1275
|
+
|
|
1276
|
+
// istanbul ignore next
|
|
1207
1277
|
if (!(extObj && extObj.constructor)) {
|
|
1208
|
-
|
|
1278
|
+
errorLog(extObj);
|
|
1209
1279
|
throw new Error("expecting an valid extension object");
|
|
1210
1280
|
}
|
|
1211
1281
|
const dataType = addressSpace.findDataType(this.dataType);
|
|
@@ -1231,7 +1301,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1231
1301
|
return extObj.constructor.name === Constructor.name;
|
|
1232
1302
|
}
|
|
1233
1303
|
} catch (err) {
|
|
1234
|
-
|
|
1304
|
+
errorLog(err);
|
|
1235
1305
|
return false;
|
|
1236
1306
|
}
|
|
1237
1307
|
}
|
|
@@ -1252,7 +1322,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1252
1322
|
|
|
1253
1323
|
// istanbul ignore next
|
|
1254
1324
|
if (doDebug) {
|
|
1255
|
-
|
|
1325
|
+
debugLog(" ------------------------------ binding ", this.browseName.toString(), this.nodeId.toString());
|
|
1256
1326
|
}
|
|
1257
1327
|
assert(structure && structure.browseName.toString() === "Structure", "expecting DataType Structure to be in IAddressSpace");
|
|
1258
1328
|
|
|
@@ -1277,14 +1347,14 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1277
1347
|
// }
|
|
1278
1348
|
// istanbul ignore next
|
|
1279
1349
|
if (!this.checkExtensionObjectIsCorrect(this.$extensionObject!)) {
|
|
1280
|
-
|
|
1350
|
+
warningLog(
|
|
1281
1351
|
"on node : ",
|
|
1282
1352
|
this.browseName.toString(),
|
|
1283
1353
|
this.nodeId.toString(),
|
|
1284
1354
|
"dataType=",
|
|
1285
1355
|
this.dataType.toString({ addressSpace: this.addressSpace })
|
|
1286
1356
|
);
|
|
1287
|
-
|
|
1357
|
+
warningLog(this.$extensionObject?.toString());
|
|
1288
1358
|
throw new Error(
|
|
1289
1359
|
"bindExtensionObject: $extensionObject is incorrect: we are expecting a " +
|
|
1290
1360
|
this.dataType.toString({ addressSpace: this.addressSpace }) +
|
|
@@ -1299,45 +1369,32 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1299
1369
|
|
|
1300
1370
|
// ------------------------------------------------------------------
|
|
1301
1371
|
|
|
1302
|
-
function prepareVariantValue(dataType: DataType
|
|
1303
|
-
if (typeof dataType === "string") {
|
|
1304
|
-
dataType = (DataType as any)[dataType];
|
|
1305
|
-
}
|
|
1372
|
+
function prepareVariantValue(dataType: DataType, value: VariantLike): VariantLike {
|
|
1306
1373
|
if ((dataType === DataType.Int32 || dataType === DataType.UInt32) && value && (value as any).key) {
|
|
1307
1374
|
value = value.value;
|
|
1308
1375
|
}
|
|
1309
1376
|
return value;
|
|
1310
1377
|
}
|
|
1311
1378
|
|
|
1312
|
-
const bindProperty = (propertyNode: UAVariableImpl, name:
|
|
1313
|
-
const dataTypeAsString = DataType[dataTypeNodeId];
|
|
1314
|
-
|
|
1315
|
-
/*
|
|
1316
|
-
property.setValueFromSource(new Variant({
|
|
1317
|
-
dataType: dataType,
|
|
1318
|
-
value: prepareVariantValue(dataType, this.$extensionObject[name])
|
|
1319
|
-
}));
|
|
1320
|
-
*/
|
|
1321
|
-
|
|
1322
|
-
assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
|
|
1323
|
-
|
|
1379
|
+
const bindProperty = (propertyNode: UAVariableImpl, name: string, extensionObject: ExtensionObject, dataType: DataType) => {
|
|
1324
1380
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1325
1381
|
const self = this;
|
|
1326
1382
|
propertyNode.bindVariable(
|
|
1327
1383
|
{
|
|
1328
1384
|
timestamped_get: () => {
|
|
1329
|
-
const
|
|
1385
|
+
const propertyValue = self.$extensionObject[name];
|
|
1330
1386
|
|
|
1331
|
-
if (
|
|
1332
|
-
propertyNode.
|
|
1333
|
-
propertyNode.
|
|
1334
|
-
propertyNode.
|
|
1335
|
-
return new DataValue(propertyNode
|
|
1387
|
+
if (propertyValue === undefined) {
|
|
1388
|
+
propertyNode.$dataValue.value.dataType = DataType.Null;
|
|
1389
|
+
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
1390
|
+
propertyNode.$dataValue.value.value = null;
|
|
1391
|
+
return new DataValue(propertyNode.$dataValue);
|
|
1336
1392
|
}
|
|
1337
|
-
const value = prepareVariantValue(
|
|
1338
|
-
propertyNode.
|
|
1339
|
-
propertyNode.
|
|
1340
|
-
|
|
1393
|
+
const value = prepareVariantValue(dataType, propertyValue);
|
|
1394
|
+
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
1395
|
+
propertyNode.$dataValue.value.dataType = dataType;
|
|
1396
|
+
propertyNode.$dataValue.value.value = value;
|
|
1397
|
+
return new DataValue(propertyNode.$dataValue);
|
|
1341
1398
|
},
|
|
1342
1399
|
timestamped_set: (dataValue: DataValue, callback: CallbackT<StatusCode>) => {
|
|
1343
1400
|
dataValue;
|
|
@@ -1355,8 +1412,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1355
1412
|
const s = this.readValue();
|
|
1356
1413
|
// istanbul ignore next
|
|
1357
1414
|
if (this.dataTypeObj.isAbstract) {
|
|
1358
|
-
|
|
1359
|
-
|
|
1415
|
+
warningLog("Warning the DataType associated with this Variable is abstract ", this.dataTypeObj.browseName.toString());
|
|
1416
|
+
warningLog("You need to provide a extension object yourself ");
|
|
1360
1417
|
throw new Error("bindExtensionObject requires a extensionObject as associated dataType is only abstract");
|
|
1361
1418
|
}
|
|
1362
1419
|
if (s.value && (s.value.dataType === DataType.Null || (s.value.dataType === DataType.ExtensionObject && !s.value.value))) {
|
|
@@ -1376,8 +1433,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1376
1433
|
this.bindVariable(
|
|
1377
1434
|
{
|
|
1378
1435
|
timestamped_get() {
|
|
1379
|
-
self.
|
|
1380
|
-
const d = new DataValue(self
|
|
1436
|
+
self.$dataValue.value.value = self.$extensionObject;
|
|
1437
|
+
const d = new DataValue(self.$dataValue);
|
|
1381
1438
|
d.value = new Variant(d.value);
|
|
1382
1439
|
return d;
|
|
1383
1440
|
},
|
|
@@ -1386,7 +1443,6 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1386
1443
|
if (!self.checkExtensionObjectIsCorrect(ext)) {
|
|
1387
1444
|
return callback(null, StatusCodes.BadInvalidArgument);
|
|
1388
1445
|
}
|
|
1389
|
-
|
|
1390
1446
|
self.$extensionObject = new Proxy(ext, makeHandler(self));
|
|
1391
1447
|
self.touchValue();
|
|
1392
1448
|
callback(null, StatusCodes.Good);
|
|
@@ -1402,51 +1458,65 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1402
1458
|
assert(s.statusCode.equals(StatusCodes.Good));
|
|
1403
1459
|
}
|
|
1404
1460
|
|
|
1405
|
-
let property: any;
|
|
1406
|
-
let camelCaseName: any;
|
|
1407
1461
|
// ------------------------------------------------------
|
|
1408
1462
|
// now bind each member
|
|
1409
1463
|
// ------------------------------------------------------
|
|
1410
|
-
const definition = dt._getDefinition(
|
|
1464
|
+
const definition = dt._getDefinition() as StructureDefinition | null;
|
|
1411
1465
|
|
|
1412
1466
|
// istanbul ignore next
|
|
1413
1467
|
if (!definition) {
|
|
1414
1468
|
throw new Error("xx definition missing in " + dt.toString());
|
|
1415
1469
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1470
|
+
|
|
1471
|
+
const getOrCreateProperty = (field: StructureField): UAVariableImpl => {
|
|
1472
|
+
let property: UAVariableImpl;
|
|
1473
|
+
const selectedComponents = components.filter(
|
|
1474
|
+
(f) => f instanceof UAVariableImpl && f.browseName.name!.toString() === field.name
|
|
1475
|
+
);
|
|
1476
|
+
|
|
1477
|
+
if (field.dataType.value === DataType.Variant) {
|
|
1478
|
+
warningLog("Warning : variant is not supported in ExtensionObject");
|
|
1479
|
+
}
|
|
1480
|
+
if (selectedComponents.length === 1) {
|
|
1481
|
+
property = selectedComponents[0] as UAVariableImpl;
|
|
1421
1482
|
/* istanbul ignore next */
|
|
1422
1483
|
} else {
|
|
1484
|
+
debugLog("adding missing array variable", field.name, this.browseName.toString(), this.nodeId.toString());
|
|
1423
1485
|
// todo: Handle array appropriately...
|
|
1424
|
-
assert(
|
|
1486
|
+
assert(selectedComponents.length === 0);
|
|
1425
1487
|
// create a variable (Note we may use ns=1;s=parentName/0:PropertyName)
|
|
1426
1488
|
property = this.namespace.addVariable({
|
|
1427
1489
|
browseName: { namespaceIndex: structureNamespace, name: field.name!.toString() },
|
|
1428
1490
|
componentOf: this,
|
|
1429
1491
|
dataType: field.dataType,
|
|
1430
1492
|
minimumSamplingInterval: this.minimumSamplingInterval
|
|
1431
|
-
});
|
|
1493
|
+
}) as UAVariableImpl;
|
|
1432
1494
|
assert(property.minimumSamplingInterval === this.minimumSamplingInterval);
|
|
1433
1495
|
}
|
|
1496
|
+
return property;
|
|
1497
|
+
};
|
|
1434
1498
|
|
|
1435
|
-
|
|
1436
|
-
property.touchValue();
|
|
1437
|
-
|
|
1499
|
+
for (const field of definition.fields || []) {
|
|
1438
1500
|
if (NodeId.sameNodeId(NodeId.nullNodeId, field.dataType)) {
|
|
1439
|
-
|
|
1440
|
-
|
|
1501
|
+
warningLog("field.dataType is null ! ", field.toString(), NodeId.nullNodeId.toString());
|
|
1502
|
+
warningLog(" dataType replaced with BaseDataType ");
|
|
1503
|
+
warningLog(definition.toString());
|
|
1441
1504
|
field.dataType = this.resolveNodeId("BaseDataType");
|
|
1442
1505
|
}
|
|
1443
|
-
|
|
1506
|
+
|
|
1507
|
+
const camelCaseName = lowerFirstLetter(field.name!);
|
|
1444
1508
|
assert(Object.prototype.hasOwnProperty.call(this.$extensionObject, camelCaseName));
|
|
1445
1509
|
|
|
1510
|
+
const propertyNode = getOrCreateProperty(field);
|
|
1511
|
+
|
|
1512
|
+
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
1513
|
+
propertyNode.touchValue();
|
|
1514
|
+
|
|
1515
|
+
const basicDataType = addressSpace.findCorrespondingBasicDataType(field.dataType);
|
|
1516
|
+
|
|
1446
1517
|
// istanbul ignore next
|
|
1447
1518
|
if (doDebug) {
|
|
1448
1519
|
const x = addressSpace.findNode(field.dataType)!.browseName.toString();
|
|
1449
|
-
const basicType = addressSpace.findCorrespondingBasicDataType(field.dataType);
|
|
1450
1520
|
debugLog(
|
|
1451
1521
|
chalk.cyan("xxx"),
|
|
1452
1522
|
" dataType",
|
|
@@ -1456,52 +1526,56 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1456
1526
|
chalk.cyan(w(valueRankToString(field.valueRank), 10)),
|
|
1457
1527
|
chalk.green(w(x, 25)),
|
|
1458
1528
|
"basicType = ",
|
|
1459
|
-
chalk.yellow(w(
|
|
1460
|
-
|
|
1461
|
-
|
|
1529
|
+
chalk.yellow(w(basicDataType.toString(), 20)),
|
|
1530
|
+
propertyNode.nodeId.toString(),
|
|
1531
|
+
propertyNode.readValue().statusCode.toString()
|
|
1462
1532
|
);
|
|
1463
1533
|
}
|
|
1464
|
-
if (this.$extensionObject[camelCaseName] !== undefined &&
|
|
1534
|
+
if (this.$extensionObject[camelCaseName] !== undefined && basicDataType === DataType.ExtensionObject) {
|
|
1465
1535
|
assert(this.$extensionObject[camelCaseName] instanceof Object);
|
|
1466
|
-
this.$extensionObject[camelCaseName] = new Proxy(this.$extensionObject[camelCaseName], makeHandler(
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1536
|
+
this.$extensionObject[camelCaseName] = new Proxy(this.$extensionObject[camelCaseName], makeHandler(propertyNode));
|
|
1537
|
+
|
|
1538
|
+
propertyNode._internal_set_value(
|
|
1539
|
+
new Variant({
|
|
1540
|
+
dataType: DataType.ExtensionObject,
|
|
1541
|
+
value: this.$extensionObject[camelCaseName]
|
|
1542
|
+
})
|
|
1543
|
+
);
|
|
1544
|
+
|
|
1545
|
+
propertyNode.bindExtensionObject();
|
|
1546
|
+
propertyNode.$extensionObject = this.$extensionObject[camelCaseName];
|
|
1473
1547
|
} else {
|
|
1474
|
-
const dataTypeAsString = DataType[dataTypeNodeId];
|
|
1475
|
-
assert(typeof dataTypeAsString === "string");
|
|
1476
1548
|
const prop = this.$extensionObject[camelCaseName];
|
|
1477
|
-
|
|
1478
1549
|
if (prop === undefined) {
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1550
|
+
propertyNode._internal_set_value(
|
|
1551
|
+
new Variant({
|
|
1552
|
+
dataType: DataType.Null
|
|
1553
|
+
})
|
|
1554
|
+
);
|
|
1482
1555
|
} else {
|
|
1483
|
-
const preparedValue = prepareVariantValue(
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1556
|
+
const preparedValue = prepareVariantValue(basicDataType, prop);
|
|
1557
|
+
propertyNode._internal_set_value(
|
|
1558
|
+
new Variant({
|
|
1559
|
+
dataType: basicDataType,
|
|
1560
|
+
value: preparedValue
|
|
1561
|
+
})
|
|
1562
|
+
);
|
|
1488
1563
|
}
|
|
1489
1564
|
|
|
1490
1565
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1491
1566
|
const self = this;
|
|
1492
|
-
property.camelCaseName = camelCaseName;
|
|
1493
|
-
|
|
1567
|
+
// property.camelCaseName = camelCaseName;
|
|
1568
|
+
propertyNode.setValueFromSource = function (this: UAVariableImpl, variant: VariantLike) {
|
|
1494
1569
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1495
1570
|
const inner_this = this;
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
self.$extensionObject[inner_this.camelCaseName] = variant.value;
|
|
1571
|
+
const variant1 = Variant.coerce(variant);
|
|
1572
|
+
inner_this.verifyVariantCompatibility(variant1);
|
|
1573
|
+
self.$extensionObject[camelCaseName] = variant1.value;
|
|
1500
1574
|
self.touchValue();
|
|
1501
1575
|
};
|
|
1502
1576
|
}
|
|
1503
|
-
assert(
|
|
1504
|
-
bindProperty(
|
|
1577
|
+
assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
|
|
1578
|
+
bindProperty(propertyNode, camelCaseName, this.$extensionObject, basicDataType);
|
|
1505
1579
|
}
|
|
1506
1580
|
assert(this.$extensionObject instanceof Object);
|
|
1507
1581
|
return this.$extensionObject;
|
|
@@ -1543,7 +1617,6 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1543
1617
|
c1[name] = c2[name];
|
|
1544
1618
|
c1[name] += 1;
|
|
1545
1619
|
|
|
1546
|
-
// xx console.log(partialData);
|
|
1547
1620
|
setExtensionObjectValue(this, partialData);
|
|
1548
1621
|
}
|
|
1549
1622
|
|
|
@@ -1687,10 +1760,16 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1687
1760
|
return validateDataType(this.addressSpace, this.dataType, variantDataType, this.nodeId, /* allow Nulls */ false);
|
|
1688
1761
|
}
|
|
1689
1762
|
|
|
1763
|
+
public _internal_set_value(value: Variant): void {
|
|
1764
|
+
if (value.dataType !== DataType.Null) {
|
|
1765
|
+
this.verifyVariantCompatibility(value);
|
|
1766
|
+
}
|
|
1767
|
+
this.$dataValue.value = value;
|
|
1768
|
+
}
|
|
1690
1769
|
public _internal_set_dataValue(dataValue: DataValue, indexRange?: NumericRange | null): void {
|
|
1691
1770
|
assert(dataValue, "expecting a dataValue");
|
|
1692
1771
|
assert(dataValue instanceof DataValue, "expecting dataValue to be a DataValue");
|
|
1693
|
-
assert(dataValue !== this
|
|
1772
|
+
assert(dataValue !== this.$dataValue, "expecting dataValue to be different from previous DataValue instance");
|
|
1694
1773
|
|
|
1695
1774
|
if (dataValue.value.arrayType === VariantArrayType.Matrix) {
|
|
1696
1775
|
if (!dataValue.value.dimensions) {
|
|
@@ -1714,27 +1793,31 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1714
1793
|
// istanbul ignore next
|
|
1715
1794
|
if (this.dataType.namespace === 0) {
|
|
1716
1795
|
if (this.dataType.value === DataType.LocalizedText && dataValue.value.dataType !== DataType.LocalizedText) {
|
|
1717
|
-
|
|
1796
|
+
const message = "Invalid dataValue provided (expecting a LocalizedText) but got " + dataValue.toString();
|
|
1797
|
+
errorLog(message);
|
|
1798
|
+
throw new Error(message);
|
|
1718
1799
|
}
|
|
1719
1800
|
}
|
|
1720
1801
|
|
|
1721
|
-
|
|
1802
|
+
this.verifyVariantCompatibility(dataValue.value);
|
|
1722
1803
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1804
|
+
const old_dataValue = this.$dataValue;
|
|
1805
|
+
|
|
1806
|
+
this.$dataValue = dataValue;
|
|
1807
|
+
this.$dataValue.statusCode = this.$dataValue.statusCode || StatusCodes.Good;
|
|
1725
1808
|
|
|
1726
1809
|
// repair missing timestamps
|
|
1727
1810
|
if (!dataValue.serverTimestamp) {
|
|
1728
|
-
this.
|
|
1729
|
-
this.
|
|
1811
|
+
this.$dataValue.serverTimestamp = old_dataValue.serverTimestamp;
|
|
1812
|
+
this.$dataValue.serverPicoseconds = old_dataValue.serverPicoseconds;
|
|
1730
1813
|
}
|
|
1731
1814
|
if (!dataValue.sourceTimestamp) {
|
|
1732
|
-
this.
|
|
1733
|
-
this.
|
|
1815
|
+
this.$dataValue.sourceTimestamp = old_dataValue.sourceTimestamp;
|
|
1816
|
+
this.$dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds;
|
|
1734
1817
|
}
|
|
1735
1818
|
|
|
1736
1819
|
if (!sameDataValue(old_dataValue, dataValue)) {
|
|
1737
|
-
this.emit("value_changed", this
|
|
1820
|
+
this.emit("value_changed", this.$dataValue, indexRange);
|
|
1738
1821
|
}
|
|
1739
1822
|
}
|
|
1740
1823
|
|
|
@@ -1930,10 +2013,10 @@ function _calculateEffectiveUserAccessLevelFromPermission(
|
|
|
1930
2013
|
}
|
|
1931
2014
|
}
|
|
1932
2015
|
|
|
1933
|
-
function adjustVariant2(this:
|
|
2016
|
+
function adjustVariant2(this: UAVariableImpl, variant: Variant): Variant {
|
|
1934
2017
|
// convert Variant( Scalar|ByteString) => Variant(Array|ByteArray)
|
|
1935
2018
|
const addressSpace = this.addressSpace;
|
|
1936
|
-
const basicType =
|
|
2019
|
+
const basicType = this.getBasicDataType();
|
|
1937
2020
|
variant = adjustVariant(variant, this.valueRank, basicType);
|
|
1938
2021
|
return variant;
|
|
1939
2022
|
}
|
|
@@ -1950,7 +2033,6 @@ function _default_writable_timestamped_set_func(
|
|
|
1950
2033
|
dataValue: DataValue,
|
|
1951
2034
|
callback: (err: Error | null, statusCode: StatusCode, dataValue?: DataValue | null) => void
|
|
1952
2035
|
) {
|
|
1953
|
-
/* jshint validthis: true */
|
|
1954
2036
|
assert(dataValue instanceof DataValue);
|
|
1955
2037
|
callback(null, StatusCodes.Good, dataValue);
|
|
1956
2038
|
}
|
|
@@ -1992,7 +2074,7 @@ function _Variable_bind_with_async_refresh(this: UAVariableImpl, options: any) {
|
|
|
1992
2074
|
this.refreshFunc = options.refreshFunc;
|
|
1993
2075
|
|
|
1994
2076
|
// assert(this.readValue().statusCode === StatusCodes.BadNodeIdUnknown);
|
|
1995
|
-
this.
|
|
2077
|
+
this.$dataValue.statusCode = StatusCodes.UncertainInitialValue;
|
|
1996
2078
|
|
|
1997
2079
|
// TO DO : REVISIT THIS ASSUMPTION
|
|
1998
2080
|
if (false && this.minimumSamplingInterval === 0) {
|
|
@@ -2004,7 +2086,13 @@ function _Variable_bind_with_async_refresh(this: UAVariableImpl, options: any) {
|
|
|
2004
2086
|
}
|
|
2005
2087
|
|
|
2006
2088
|
// variation 2
|
|
2007
|
-
function _Variable_bind_with_timestamped_get(
|
|
2089
|
+
function _Variable_bind_with_timestamped_get(
|
|
2090
|
+
this: UAVariableImpl,
|
|
2091
|
+
options: {
|
|
2092
|
+
get: undefined;
|
|
2093
|
+
timestamped_get: TimestampGetFunc;
|
|
2094
|
+
}
|
|
2095
|
+
) {
|
|
2008
2096
|
/* jshint validthis: true */
|
|
2009
2097
|
assert(this instanceof UAVariableImpl);
|
|
2010
2098
|
assert(typeof options.timestamped_get === "function");
|
|
@@ -2012,17 +2100,20 @@ function _Variable_bind_with_timestamped_get(this: UAVariableImpl, options: any)
|
|
|
2012
2100
|
assert(!this._timestamped_get_func);
|
|
2013
2101
|
|
|
2014
2102
|
const async_refresh_func = (callback: (err: Error | null, dataValue?: DataValue) => void) => {
|
|
2015
|
-
Promise.resolve((this._timestamped_get_func! as
|
|
2103
|
+
Promise.resolve((this._timestamped_get_func! as VariableDataValueGetterSync).call(this))
|
|
2016
2104
|
.then((dataValue) => callback(null, dataValue))
|
|
2017
|
-
.catch((err) =>
|
|
2105
|
+
.catch((err) => {
|
|
2106
|
+
errorLog("asyncRefresh error: Variable is ", this.nodeId.toString(), this.browseName.toString());
|
|
2107
|
+
callback(err as Error);
|
|
2108
|
+
});
|
|
2018
2109
|
};
|
|
2019
|
-
|
|
2110
|
+
const pThis = this as UAVariable;
|
|
2020
2111
|
if (options.timestamped_get.length === 0) {
|
|
2021
|
-
const timestamped_get = options.timestamped_get as
|
|
2112
|
+
const timestamped_get = options.timestamped_get as (this: UAVariable) => DataValue | Promise<DataValue>;
|
|
2022
2113
|
// sync version | Promise version
|
|
2023
2114
|
this._timestamped_get_func = timestamped_get;
|
|
2024
2115
|
|
|
2025
|
-
const dataValue_verify = timestamped_get
|
|
2116
|
+
const dataValue_verify = timestamped_get.call(pThis);
|
|
2026
2117
|
// dataValue_verify should be a DataValue or a Promise
|
|
2027
2118
|
/* istanbul ignore next */
|
|
2028
2119
|
if (!(dataValue_verify instanceof DataValue) && typeof dataValue_verify.then !== "function") {
|
|
@@ -2045,11 +2136,11 @@ function _Variable_bind_with_timestamped_get(this: UAVariableImpl, options: any)
|
|
|
2045
2136
|
}
|
|
2046
2137
|
|
|
2047
2138
|
// variation 1
|
|
2048
|
-
function _Variable_bind_with_simple_get(this: UAVariableImpl, options:
|
|
2139
|
+
function _Variable_bind_with_simple_get(this: UAVariableImpl, options: GetterOptions) {
|
|
2049
2140
|
/* jshint validthis: true */
|
|
2050
2141
|
assert(this instanceof UAVariableImpl);
|
|
2051
2142
|
assert(typeof options.get === "function", "should specify get function");
|
|
2052
|
-
assert(options.get
|
|
2143
|
+
assert(options.get!.length === 0, "get function should not have arguments");
|
|
2053
2144
|
assert(!options.timestamped_get, "should not specify a timestamped_get function when get is specified");
|
|
2054
2145
|
assert(!this._timestamped_get_func);
|
|
2055
2146
|
assert(!this._get_func);
|
|
@@ -2073,16 +2164,15 @@ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: any) {
|
|
|
2073
2164
|
if (is_StatusCode(value)) {
|
|
2074
2165
|
return new DataValue({ statusCode: value });
|
|
2075
2166
|
} else {
|
|
2076
|
-
if (!this
|
|
2167
|
+
if (!this.$dataValue || !isGoodish(this.$dataValue.statusCode) || !sameVariant(this.$dataValue.value, value)) {
|
|
2077
2168
|
this.setValueFromSource(value, StatusCodes.Good);
|
|
2078
|
-
} else {
|
|
2079
|
-
// XX console.log("YYYYYYYYYYYYYYYYYYYYYYYYYY",this.browseName.toString());
|
|
2080
2169
|
}
|
|
2081
|
-
return this
|
|
2170
|
+
return this.$dataValue;
|
|
2082
2171
|
}
|
|
2083
2172
|
};
|
|
2084
2173
|
|
|
2085
2174
|
_Variable_bind_with_timestamped_get.call(this, {
|
|
2175
|
+
get: undefined,
|
|
2086
2176
|
timestamped_get: timestamped_get_func_from__Variable_bind_with_simple_get
|
|
2087
2177
|
});
|
|
2088
2178
|
}
|
|
@@ -2100,16 +2190,16 @@ function _Variable_bind_with_simple_set(this: UAVariableImpl, options: any) {
|
|
|
2100
2190
|
|
|
2101
2191
|
this._timestamped_set_func = (
|
|
2102
2192
|
timestamped_value: DataValue,
|
|
2103
|
-
indexRange: NumericRange,
|
|
2104
2193
|
callback: (err: Error | null, statusCode: StatusCode, dataValue: DataValue) => void
|
|
2105
2194
|
) => {
|
|
2106
2195
|
assert(timestamped_value instanceof DataValue);
|
|
2107
2196
|
this._set_func(timestamped_value.value, (err: Error | null, statusCode: StatusCode) => {
|
|
2197
|
+
// istanbul ignore next
|
|
2108
2198
|
if (!err && !statusCode) {
|
|
2109
|
-
|
|
2199
|
+
errorLog(
|
|
2110
2200
|
chalk.red("UAVariable Binding Error _set_func must return a StatusCode, check the bindVariable parameters")
|
|
2111
2201
|
);
|
|
2112
|
-
|
|
2202
|
+
errorLog(chalk.yellow("StatusCode.Good is assumed"));
|
|
2113
2203
|
return callback(err, StatusCodes.Good, timestamped_value);
|
|
2114
2204
|
}
|
|
2115
2205
|
callback(err, statusCode, timestamped_value);
|
|
@@ -2117,22 +2207,20 @@ function _Variable_bind_with_simple_set(this: UAVariableImpl, options: any) {
|
|
|
2117
2207
|
};
|
|
2118
2208
|
}
|
|
2119
2209
|
|
|
2120
|
-
function _Variable_bind_with_timestamped_set(
|
|
2121
|
-
|
|
2210
|
+
function _Variable_bind_with_timestamped_set(
|
|
2211
|
+
this: UAVariableImpl,
|
|
2212
|
+
options: {
|
|
2213
|
+
timestamped_set: TimestampSetFunc;
|
|
2214
|
+
set: undefined;
|
|
2215
|
+
}
|
|
2216
|
+
) {
|
|
2122
2217
|
assert(typeof options.timestamped_set === "function");
|
|
2123
2218
|
assert(
|
|
2124
2219
|
options.timestamped_set.length === 2,
|
|
2125
2220
|
"timestamped_set must have 2 parameters timestamped_set: function(dataValue,callback){}"
|
|
2126
2221
|
);
|
|
2127
2222
|
assert(!options.set, "should not specify set when timestamped_set_func exists ");
|
|
2128
|
-
this._timestamped_set_func = (
|
|
2129
|
-
dataValue: DataValue,
|
|
2130
|
-
indexRange: NumericRange,
|
|
2131
|
-
callback: (err: Error | null, statusCode: StatusCode, dataValue: DataValue) => void
|
|
2132
|
-
) => {
|
|
2133
|
-
// xx assert(!indexRange,"indexRange Not Implemented");
|
|
2134
|
-
return options.timestamped_set.call(this, dataValue, callback);
|
|
2135
|
-
};
|
|
2223
|
+
this._timestamped_set_func = convertToCallbackFunction1<StatusCode, DataValue, UAVariable>(options.timestamped_set);
|
|
2136
2224
|
}
|
|
2137
2225
|
|
|
2138
2226
|
interface SetterOptions {
|
|
@@ -2147,15 +2235,20 @@ function bind_setter(this: UAVariableImpl, options: SetterOptions) {
|
|
|
2147
2235
|
} else if (typeof options.timestamped_set === "function") {
|
|
2148
2236
|
// variation 2
|
|
2149
2237
|
assert(typeof options.timestamped_get === "function", "timestamped_set must be used with timestamped_get ");
|
|
2150
|
-
_Variable_bind_with_timestamped_set.call(this,
|
|
2238
|
+
_Variable_bind_with_timestamped_set.call(this, {
|
|
2239
|
+
set: undefined,
|
|
2240
|
+
timestamped_set: options.timestamped_set
|
|
2241
|
+
});
|
|
2151
2242
|
} else if (typeof options.timestamped_get === "function") {
|
|
2152
2243
|
// timestamped_get is specified but timestamped_set is not
|
|
2153
2244
|
// => Value is read-only
|
|
2154
2245
|
_Variable_bind_with_timestamped_set.call(this, {
|
|
2246
|
+
set: undefined,
|
|
2155
2247
|
timestamped_set: _not_writable_timestamped_set_func
|
|
2156
2248
|
});
|
|
2157
2249
|
} else {
|
|
2158
2250
|
_Variable_bind_with_timestamped_set.call(this, {
|
|
2251
|
+
set: undefined,
|
|
2159
2252
|
timestamped_set: _default_writable_timestamped_set_func
|
|
2160
2253
|
});
|
|
2161
2254
|
}
|
|
@@ -2164,7 +2257,7 @@ function bind_setter(this: UAVariableImpl, options: SetterOptions) {
|
|
|
2164
2257
|
interface GetterOptions {
|
|
2165
2258
|
get?: GetFunc;
|
|
2166
2259
|
timestamped_get?: TimestampGetFunc;
|
|
2167
|
-
refreshFunc?:
|
|
2260
|
+
refreshFunc?: (callback: CallbackT<DataValue>) => void;
|
|
2168
2261
|
dataType?: DataType | string;
|
|
2169
2262
|
value?: any;
|
|
2170
2263
|
}
|
|
@@ -2174,7 +2267,10 @@ function bind_getter(this: UAVariableImpl, options: GetterOptions) {
|
|
|
2174
2267
|
_Variable_bind_with_simple_get.call(this, options);
|
|
2175
2268
|
} else if (typeof options.timestamped_get === "function") {
|
|
2176
2269
|
// variation 2
|
|
2177
|
-
_Variable_bind_with_timestamped_get.call(this,
|
|
2270
|
+
_Variable_bind_with_timestamped_get.call(this, {
|
|
2271
|
+
get: undefined,
|
|
2272
|
+
timestamped_get: options.timestamped_get
|
|
2273
|
+
});
|
|
2178
2274
|
} else if (typeof options.refreshFunc === "function") {
|
|
2179
2275
|
// variation 3
|
|
2180
2276
|
_Variable_bind_with_async_refresh.call(this, options);
|