mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-29 07:07:24 +08:00
# Description Adopt [`System.TimeProvider`](https://learn.microsoft.com/dotnet/api/system.timeprovider) across the stack so that every place that creates timers, runs duration math, or schedules periodic work is mockable, deterministic in tests, and immune to wall-clock changes. The migration touches Core, Core.Types, Server, Client, PubSub, Configuration, Gds (server + client), Lds, and the Quickstarts/Console reference apps. Per-component changes follow the same pattern: 1. Add a `private readonly TimeProvider m_timeProvider;` field. 2. Accept a nullable `TimeProvider? timeProvider = null` as the **last** constructor parameter (new overload; legacy constructor stays for binary compatibility and delegates with `timeProvider: null`). 3. Initialise the field with `m_timeProvider = timeProvider ??= TimeProvider.System;`. 4. Replace `new Timer(...)`, `Stopwatch`, `HiResClock.*`, `DateTime.UtcNow`-based duration math, and `Task.Delay(delay, ct)` in timing loops with the matching `m_timeProvider` API (`CreateTimer`, `GetTimestamp` / `GetElapsedTime`, `GetUtcNow().UtcDateTime`, `Task.Delay(delay, m_timeProvider, ct)`). 5. Wire the provider through DI: `AddOpcUaServerBuilder` / `AddOpcUaClientBuilder` register `TimeProvider.System` via `TryAddSingleton<TimeProvider>()` so tests can swap in `Microsoft.Extensions.Time.Testing.FakeTimeProvider`. `HiResClock` itself is kept (so the `ApplicationConfiguration.DisableHiResClock` schema flag still round-trips), but **every public member** is now `[Obsolete]` with a single shared message pointing to the new migration-guide section. The few internal call sites that still need to set/read `HiResClock` are wrapped with `#pragma warning disable CS0618`. ### Highlights per component - **Core / Stack** — `Opc.Ua.Core`, `Opc.Ua.Core.Types`, channel pipeline (`UaSCBinaryClientChannel`, `ChannelToken`, `UaSCBinaryChannel`), `ApplicationConfiguration`, certificate validators, `JwksIssuerKeyResolver`, `TimeProviderExtensions` polyfills (`GetTimestampMilliseconds`, `GetTickCount`, `CancellationTokenSource(timeout, timeProvider)`, `Task.Delay(delay, provider, ct)` polyfill for older TFMs). - **Server** — session lockout, subscription pipeline (publish/sample/keep-alive/lifetime), `MonitoredItemQueue`, alarm sampling rate, `IntervalRunner`, server diagnostics, configuration state machines, hosted services. - **Client** — `Session`, managed/V2 subscription engines, reconnect handlers, channel keep-alive, periodic publishing, complex-type discovery polling. - **PubSub** — `IntervalRunner` pipeline, message-receive timers, MQTT/UDP keep-alive, publishers/readers. - **Gds / Lds** — `LdsServer`, `LinqApplicationsDatabase` expiry housekeeping, GDS clients (push, pull), `DirectoryCertificateStore`, `ConnectionStateMachine`, classic subscription engine. - **Quickstarts / Console samples** — `SampleNodeManager`, `ReferenceNodeManager`, `AlarmNodeManager`, `BoilerState`, `MemoryBufferState`, `PublishedValuesWrites`. Samples resolve via `(Server as ITimeProviderProvider)?.TimeProvider ?? TimeProvider.System` so existing ctor signatures stay binary-compatible. - **Tests** — `Opc.Ua.PubSub.Tests` adds `IntervalRunnerTests`; existing `SubscriptionTests`, `UaPublisherTests`, and `TestDataSystem` move off `HiResClock`. Added `Microsoft.Extensions.TimeProvider.Testing` package for `FakeTimeProvider` (project-load warning surfaces on net48/net472 only — runtime is .NET 8+). ### Migration guide New section [**Time and Timer abstraction (`TimeProvider`)**](Docs/MigrationGuide.md#time-and-timer-abstraction-timeprovider) documents: - The canonical replacement table (`HiResClock.UtcNow` → `timeProvider.GetUtcNow().UtcDateTime`, `HiResClock.TickCount64` → `timeProvider.GetTimestamp()`, `new Timer` → `timeProvider.CreateTimer`, `Task.Delay(delay, ct)` → `Task.Delay(delay, timeProvider, ct)`, …). - The `TimeProvider? timeProvider = null` + `??=` constructor pattern. - DI wiring and how to swap in `FakeTimeProvider` in tests. - Before/after snippets for `HiResClock.TickCount64`, `HiResClock.UtcNow`, and `new Timer(...)`. ## Related Issues - Fixes #2458 ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received.
5606 lines
248 KiB
C#
5606 lines
248 KiB
C#
/* ========================================================================
|
|
* Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved.
|
|
*
|
|
* OPC Foundation MIT License 1.00
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* The complete license agreement can be found here:
|
|
* http://opcfoundation.org/License/MIT/1.00/
|
|
* ======================================================================*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Numerics;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml;
|
|
using Microsoft.Extensions.Logging;
|
|
using Opc.Ua;
|
|
using Opc.Ua.Server;
|
|
using Opc.Ua.Server.Historian;
|
|
using Opc.Ua.Server.Historian.InMemory;
|
|
using Opc.Ua.Test;
|
|
using Range = Opc.Ua.Range;
|
|
|
|
namespace Quickstarts.ReferenceServer
|
|
{
|
|
/// <summary>
|
|
/// A node manager for a server that exposes several variables.
|
|
/// </summary>
|
|
public class ReferenceNodeManager : AsyncCustomNodeManager
|
|
{
|
|
/// <summary>
|
|
/// Initializes the node manager.
|
|
/// </summary>
|
|
public ReferenceNodeManager(
|
|
IServerInternal server,
|
|
ApplicationConfiguration configuration,
|
|
bool useSamplingGroups = false)
|
|
: base(
|
|
server,
|
|
configuration,
|
|
useSamplingGroups,
|
|
server.Telemetry.CreateLogger<ReferenceNodeManager>(),
|
|
Namespaces.ReferenceServer)
|
|
{
|
|
SystemContext.NodeIdFactory = this;
|
|
|
|
// use suitable defaults if no configuration exists.
|
|
}
|
|
|
|
/// <summary>
|
|
/// An overrideable version of the Dispose.
|
|
/// </summary>
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
// Dispose the simulation timer first so the threadpool stops
|
|
// scheduling DoSimulation callbacks before the semaphore is
|
|
// disposed. DoSimulation's own try/catch swallows the racy
|
|
// ObjectDisposedException on m_semaphore if a callback was
|
|
// already in-flight when Timer.Dispose() returned — that's
|
|
// an acceptable trade-off versus blocking Dispose on a
|
|
// Timer.Dispose(WaitHandle) which itself can throw a worse
|
|
// unhandled ObjectDisposedException when the supplied
|
|
// WaitHandle is collected before the runtime signals it.
|
|
m_simulationTimer?.Dispose();
|
|
m_simulationTimer = null;
|
|
m_historian?.Dispose();
|
|
m_historian = null;
|
|
|
|
m_semaphore?.Dispose();
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the NodeId for the specified node.
|
|
/// </summary>
|
|
public override NodeId New(ISystemContext context, NodeState node)
|
|
{
|
|
if (node is BaseInstanceState instance &&
|
|
instance.Parent != null &&
|
|
instance.Parent.NodeId.TryGetValue(out string id))
|
|
{
|
|
return new NodeId(
|
|
id + "_" + instance.SymbolicName,
|
|
instance.Parent.NodeId.NamespaceIndex);
|
|
}
|
|
|
|
return node.NodeId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a new instance node to the address space under a parent that may
|
|
/// belong to a different node manager. Used by the AddNodes service
|
|
/// implementation in <see cref="ReferenceServer"/> to allow the test
|
|
/// fixture to exercise the Node Management service set.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The node is registered in this manager's namespace, an inverse
|
|
/// reference back to the parent is attached, and a forward reference
|
|
/// from the parent to the new node is added through the master node
|
|
/// manager so the parent's node manager records the link as well.
|
|
/// </remarks>
|
|
public async ValueTask<NodeId> AddInstanceNodeAsync(
|
|
ServerSystemContext context,
|
|
NodeId parentNodeId,
|
|
NodeId referenceTypeId,
|
|
BaseInstanceState instance,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
if (instance == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(instance));
|
|
}
|
|
|
|
ServerSystemContext contextToUse = SystemContext.Copy(context);
|
|
|
|
if (instance.NodeId.IsNull)
|
|
{
|
|
instance.NodeId = new NodeId(
|
|
Guid.NewGuid().ToString(),
|
|
NamespaceIndexes[0]);
|
|
}
|
|
|
|
instance.ReferenceTypeId = referenceTypeId;
|
|
instance.AddReference(referenceTypeId, true, parentNodeId);
|
|
|
|
await AddPredefinedNodeAsync(contextToUse, instance, cancellationToken)
|
|
.ConfigureAwait(false);
|
|
|
|
var references = new List<IReference>
|
|
{
|
|
new NodeStateReference(referenceTypeId, false, instance.NodeId)
|
|
};
|
|
|
|
await Server.NodeManager.AddReferencesAsync(
|
|
parentNodeId,
|
|
references,
|
|
cancellationToken).ConfigureAwait(false);
|
|
|
|
return instance.NodeId;
|
|
}
|
|
|
|
private static bool IsAnalogType(BuiltInType builtInType)
|
|
{
|
|
switch (builtInType)
|
|
{
|
|
case BuiltInType.Byte:
|
|
case BuiltInType.UInt16:
|
|
case BuiltInType.UInt32:
|
|
case BuiltInType.UInt64:
|
|
case BuiltInType.SByte:
|
|
case BuiltInType.Int16:
|
|
case BuiltInType.Int32:
|
|
case BuiltInType.Int64:
|
|
case BuiltInType.Float:
|
|
case BuiltInType.Double:
|
|
return true;
|
|
case >= BuiltInType.Null and <= BuiltInType.Enumeration:
|
|
return false;
|
|
default:
|
|
Debug.Fail($"Unexpected BuiltInType {builtInType}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static Range GetAnalogRange(BuiltInType builtInType)
|
|
{
|
|
switch (builtInType)
|
|
{
|
|
case BuiltInType.UInt16:
|
|
return new Range(ushort.MaxValue, ushort.MinValue);
|
|
case BuiltInType.UInt32:
|
|
return new Range(uint.MaxValue, uint.MinValue);
|
|
case BuiltInType.UInt64:
|
|
return new Range(ulong.MaxValue, ulong.MinValue);
|
|
case BuiltInType.SByte:
|
|
return new Range(sbyte.MaxValue, sbyte.MinValue);
|
|
case BuiltInType.Int16:
|
|
return new Range(short.MaxValue, short.MinValue);
|
|
case BuiltInType.Int32:
|
|
return new Range(int.MaxValue, int.MinValue);
|
|
case BuiltInType.Int64:
|
|
return new Range(long.MaxValue, long.MinValue);
|
|
case BuiltInType.Float:
|
|
return new Range(float.MaxValue, float.MinValue);
|
|
case BuiltInType.Double:
|
|
return new Range(double.MaxValue, double.MinValue);
|
|
case BuiltInType.Byte:
|
|
return new Range(byte.MaxValue, byte.MinValue);
|
|
case >= BuiltInType.Null and <= BuiltInType.Enumeration:
|
|
return new Range(sbyte.MaxValue, sbyte.MinValue);
|
|
default:
|
|
Debug.Fail($"Unexpected BuiltInType {builtInType}");
|
|
return new Range(sbyte.MaxValue, sbyte.MinValue);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Does any initialization required before the address space can be used.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The externalReferences is an out parameter that allows the node manager to link to nodes
|
|
/// in other node managers. For example, the 'Objects' node is managed by the CoreNodeManager and
|
|
/// should have a reference to the root folder node(s) exposed by this node manager.
|
|
/// </remarks>
|
|
public override async ValueTask CreateAddressSpaceAsync(
|
|
IDictionary<NodeId, IList<IReference>> externalReferences,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
|
try
|
|
{
|
|
if (!externalReferences.TryGetValue(
|
|
ObjectIds.ObjectsFolder,
|
|
out IList<IReference>? references))
|
|
{
|
|
externalReferences[ObjectIds.ObjectsFolder] = references = [];
|
|
}
|
|
|
|
FolderState root = CreateFolder(null, "CTT", "CTT");
|
|
root.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder);
|
|
references.Add(
|
|
new NodeStateReference(ReferenceTypeIds.Organizes, false, root.NodeId));
|
|
root.EventNotifier = EventNotifiers.SubscribeToEvents;
|
|
await AddRootNotifierAsync(root, cancellationToken).ConfigureAwait(false);
|
|
|
|
var variables = new List<BaseDataVariableState>();
|
|
|
|
try
|
|
{
|
|
ResetRandomGenerator(1);
|
|
FolderState scalarFolder = CreateFolder(root, "Scalar", "Scalar");
|
|
BaseDataVariableState scalarInstructions = CreateVariable(
|
|
scalarFolder,
|
|
"Scalar_Instructions",
|
|
"Scalar_Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
scalarInstructions.Value
|
|
= "A library of Read/Write Variables of all supported data-types.";
|
|
variables.Add(scalarInstructions);
|
|
|
|
FolderState staticFolder = CreateFolder(
|
|
scalarFolder,
|
|
"Scalar_Static",
|
|
"Scalar_Static");
|
|
const string scalarStatic = "Scalar_Static_";
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.Scalar));
|
|
BaseDataVariableState floatVal = CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.Scalar)
|
|
.MinimumSamplingInterval(100);
|
|
floatVal.Value = (float)5;
|
|
variables.Add(floatVal);
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar));
|
|
BaseDataVariableState int32Static = CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.Scalar);
|
|
// Expose RolePermissions / UserRolePermissions
|
|
// on the Int32 static scalar so the conformance attribute
|
|
// tests (AttributeReadComplexTests RolePermissions /
|
|
// UserRolePermissions read) return Good rather than
|
|
// BadAttributeIdInvalid. Anonymous users are granted
|
|
// Browse + Read + ReadRolePermissions; SecurityAdmin gets
|
|
// full permissions for write-attribute scenarios.
|
|
var anonPerms = new RolePermissionType
|
|
{
|
|
RoleId = ObjectIds.WellKnownRole_Anonymous,
|
|
Permissions =
|
|
(uint)PermissionType.Browse |
|
|
(uint)PermissionType.Read |
|
|
(uint)PermissionType.Write |
|
|
(uint)PermissionType.ReadRolePermissions
|
|
};
|
|
var adminPerms = new RolePermissionType
|
|
{
|
|
RoleId = ObjectIds.WellKnownRole_SecurityAdmin,
|
|
Permissions = 0xFFFF
|
|
};
|
|
int32Static.RolePermissions = new[] { anonPerms, adminPerms }.ToArrayOf();
|
|
int32Static.UserRolePermissions = new[] { anonPerms }.ToArrayOf();
|
|
variables.Add(int32Static);
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.Scalar)
|
|
.MinimumSamplingInterval(100));
|
|
|
|
BaseDataVariableState decimalVariable = CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Decimal",
|
|
"Decimal",
|
|
DataTypeIds.DecimalDataType,
|
|
ValueRanks.Scalar);
|
|
// Set an arbitrary precision decimal value.
|
|
var largeInteger = BigInteger.Parse(
|
|
"1234567890123546789012345678901234567890123456789012345",
|
|
CultureInfo.InvariantCulture);
|
|
decimalVariable.Value = Variant.FromStructure(new DecimalDataType
|
|
{
|
|
Scale = 100,
|
|
Value = largeInteger.ToByteString()
|
|
});
|
|
variables.Add(decimalVariable);
|
|
|
|
// Enumeration variable (NodeClass is a concrete subtype of Enumeration)
|
|
BaseDataVariableState enumerationVariable = CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Enumeration",
|
|
"Enumeration",
|
|
new NodeId(DataTypes.NodeClass),
|
|
ValueRanks.Scalar);
|
|
enumerationVariable.Value = new Variant((int)NodeClass.Object);
|
|
variables.Add(enumerationVariable);
|
|
|
|
// Image type variables (ByteString subtypes)
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "Image",
|
|
"Image",
|
|
new NodeId(DataTypes.Image),
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "ImageBMP",
|
|
"ImageBMP",
|
|
new NodeId(DataTypes.ImageBMP),
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "ImageGIF",
|
|
"ImageGIF",
|
|
new NodeId(DataTypes.ImageGIF),
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "ImageJPG",
|
|
"ImageJPG",
|
|
new NodeId(DataTypes.ImageJPG),
|
|
ValueRanks.Scalar));
|
|
variables.Add(
|
|
CreateVariable(
|
|
staticFolder,
|
|
scalarStatic + "ImagePNG",
|
|
"ImagePNG",
|
|
new NodeId(DataTypes.ImagePNG),
|
|
ValueRanks.Scalar));
|
|
|
|
ResetRandomGenerator(2);
|
|
FolderState arraysFolder = CreateFolder(
|
|
staticFolder,
|
|
"Scalar_Static_Arrays",
|
|
"Arrays");
|
|
const string staticArrays = "Scalar_Static_Arrays_";
|
|
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.OneDimension));
|
|
|
|
BaseDataVariableState doubleArrayVar = CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.OneDimension);
|
|
// Set the first elements of the array to a smaller value.
|
|
double[] doubleArrayVal = ((ArrayOf<double>)doubleArrayVar.Value).ToArray()!;
|
|
doubleArrayVal[0] %= 10E+10;
|
|
doubleArrayVal[1] %= 10E+10;
|
|
doubleArrayVal[2] %= 10E+10;
|
|
doubleArrayVal[3] %= 10E+10;
|
|
doubleArrayVar.Value = Variant.From(doubleArrayVal.ToArrayOf());
|
|
variables.Add(doubleArrayVar);
|
|
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.OneDimension));
|
|
|
|
BaseDataVariableState floatArrayVar = CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.OneDimension);
|
|
// Set the first elements of the array to a smaller value.
|
|
float[] floatArrayVal = ((ArrayOf<float>)floatArrayVar.Value).ToArray()!;
|
|
floatArrayVal[0] %= 0xf10E + 4;
|
|
floatArrayVal[1] %= 0xf10E + 4;
|
|
floatArrayVal[2] %= 0xf10E + 4;
|
|
floatArrayVal[3] %= 0xf10E + 4;
|
|
floatArrayVar.Value = Variant.From(floatArrayVal.ToArrayOf());
|
|
variables.Add(floatArrayVar);
|
|
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.OneDimension));
|
|
|
|
BaseDataVariableState stringArrayVar = CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.OneDimension);
|
|
stringArrayVar.Value = Variant.From(
|
|
[
|
|
"Лошадь_ Пурпурово( Змейка( Слон",
|
|
"猪 绿色 绵羊 大象~ 狗 菠萝 猪鼠猪 绿色 绵羊 大象~ 狗 菠萝 猪鼠",
|
|
"Лошадь Овцы Голубика Овцы Змейка",
|
|
"Чернота` Дракон Бело Дракон",
|
|
"Horse# Black Lemon Lemon Grape",
|
|
"猫< パイナップル; ドラゴン 犬 モモ",
|
|
"레몬} 빨간% 자주색 쥐 백색; 들",
|
|
"Yellow Sheep Peach Elephant Cow",
|
|
"Крыса Корова Свинья Собака Кот",
|
|
"龙_ 绵羊 大象 芒果; 猫'"
|
|
]);
|
|
variables.Add(stringArrayVar);
|
|
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.OneDimension));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arraysFolder,
|
|
staticArrays + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.OneDimension));
|
|
|
|
ResetRandomGenerator(3);
|
|
FolderState arrays2DFolder = CreateFolder(
|
|
staticFolder,
|
|
"Scalar_Static_Arrays2D",
|
|
"Arrays2D");
|
|
const string staticArrays2D = "Scalar_Static_Arrays2D_";
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.TwoDimensions)
|
|
.MinimumSamplingInterval(1000));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.TwoDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrays2DFolder,
|
|
staticArrays2D + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.TwoDimensions)
|
|
.MinimumSamplingInterval(1000));
|
|
|
|
ResetRandomGenerator(4);
|
|
FolderState arrayDynamicFolder = CreateFolder(
|
|
staticFolder,
|
|
"Scalar_Static_ArrayDynamic",
|
|
"ArrayDynamic");
|
|
const string staticArraysDynamic = "Scalar_Static_ArrayDynamic_";
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.OneOrMoreDimensions)
|
|
.MinimumSamplingInterval(1000));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.OneOrMoreDimensions)
|
|
.MinimumSamplingInterval(1000));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.OneOrMoreDimensions));
|
|
variables.Add(
|
|
CreateVariable(
|
|
arrayDynamicFolder,
|
|
staticArraysDynamic + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.OneOrMoreDimensions)
|
|
.MinimumSamplingInterval(1000));
|
|
|
|
ResetRandomGenerator(5);
|
|
// create 100 instances of each static scalar type
|
|
FolderState massFolder = CreateFolder(
|
|
staticFolder,
|
|
"Scalar_Static_Mass",
|
|
"Mass");
|
|
const string staticMass = "Scalar_Static_Mass_";
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
variables.AddRange(
|
|
CreateVariables(
|
|
massFolder,
|
|
staticMass + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.Scalar,
|
|
100));
|
|
|
|
ResetRandomGenerator(6);
|
|
FolderState simulationFolder = CreateFolder(
|
|
scalarFolder,
|
|
"Scalar_Simulation",
|
|
"Simulation");
|
|
const string scalarSimulation = "Scalar_Simulation_";
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.Scalar);
|
|
CreateDynamicVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.Scalar);
|
|
|
|
BaseDataVariableState intervalVariable = CreateVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Interval",
|
|
"Interval",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.Scalar);
|
|
intervalVariable.Value = m_simulationInterval;
|
|
intervalVariable.OnSimpleWriteValue = OnWriteInterval;
|
|
|
|
BaseDataVariableState enabledVariable = CreateVariable(
|
|
simulationFolder,
|
|
scalarSimulation + "Enabled",
|
|
"Enabled",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.Scalar);
|
|
enabledVariable.Value = m_simulationEnabled;
|
|
enabledVariable.OnSimpleWriteValue = OnWriteEnabled;
|
|
|
|
ResetRandomGenerator(7);
|
|
FolderState arraysSimulationFolder = CreateFolder(
|
|
simulationFolder,
|
|
"Scalar_Simulation_Arrays",
|
|
"Arrays");
|
|
const string simulationArrays = "Scalar_Simulation_Arrays_";
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.OneDimension);
|
|
CreateDynamicVariable(
|
|
arraysSimulationFolder,
|
|
simulationArrays + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.OneDimension);
|
|
|
|
ResetRandomGenerator(8);
|
|
FolderState massSimulationFolder = CreateFolder(
|
|
simulationFolder,
|
|
"Scalar_Simulation_Mass",
|
|
"Mass");
|
|
const string massSimulation = "Scalar_Simulation_Mass_";
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Boolean",
|
|
"Boolean",
|
|
DataTypeIds.Boolean,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "ByteString",
|
|
"ByteString",
|
|
DataTypeIds.ByteString,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "DateTime",
|
|
"DateTime",
|
|
DataTypeIds.DateTime,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Double",
|
|
"Double",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Float",
|
|
"Float",
|
|
DataTypeIds.Float,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Guid",
|
|
"Guid",
|
|
DataTypeIds.Guid,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Integer",
|
|
"Integer",
|
|
DataTypeIds.Integer,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "LocaleId",
|
|
"LocaleId",
|
|
DataTypeIds.LocaleId,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "LocalizedText",
|
|
"LocalizedText",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.NodeId,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Number",
|
|
"Number",
|
|
DataTypeIds.Number,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "QualifiedName",
|
|
"QualifiedName",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "String",
|
|
"String",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "UInteger",
|
|
"UInteger",
|
|
DataTypeIds.UInteger,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "UtcTime",
|
|
"UtcTime",
|
|
DataTypeIds.UtcTime,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "Variant",
|
|
"Variant",
|
|
BuiltInType.Variant,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
CreateDynamicVariables(
|
|
massSimulationFolder,
|
|
massSimulation + "XmlElement",
|
|
"XmlElement",
|
|
DataTypeIds.XmlElement,
|
|
ValueRanks.Scalar,
|
|
100);
|
|
|
|
ResetRandomGenerator(9);
|
|
FolderState daFolder = CreateFolder(root, "DataAccess", "DataAccess");
|
|
BaseDataVariableState daInstructions = CreateVariable(
|
|
daFolder,
|
|
"DataAccess_Instructions",
|
|
"Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
daInstructions.Value
|
|
= "A library of Read/Write Variables of all supported data-types.";
|
|
variables.Add(daInstructions);
|
|
|
|
FolderState dataItemFolder = CreateFolder(
|
|
daFolder,
|
|
"DataAccess_DataItem",
|
|
"DataItem");
|
|
const string daDataItem = "DataAccess_DataItem_";
|
|
|
|
#if NET8_0_OR_GREATER
|
|
BuiltInType[] builtInTypes = Enum.GetValues<BuiltInType>();
|
|
#else
|
|
var builtInTypes = (BuiltInType[])Enum.GetValues(typeof(BuiltInType));
|
|
#endif
|
|
foreach (BuiltInType builtInType in builtInTypes)
|
|
{
|
|
string name = builtInType.ToString();
|
|
DataItemState item = CreateDataItemVariable(
|
|
dataItemFolder,
|
|
daDataItem + name,
|
|
name,
|
|
builtInType,
|
|
ValueRanks.Scalar);
|
|
|
|
// set initial value to String.Empty for String node.
|
|
if (builtInType == BuiltInType.String)
|
|
{
|
|
item.Value = string.Empty;
|
|
}
|
|
}
|
|
|
|
ResetRandomGenerator(10);
|
|
FolderState analogItemFolder = CreateFolder(
|
|
daFolder,
|
|
"DataAccess_AnalogType",
|
|
"AnalogType");
|
|
const string daAnalogItem = "DataAccess_AnalogType_";
|
|
|
|
foreach (BuiltInType builtInType in builtInTypes)
|
|
{
|
|
if (IsAnalogType(builtInType))
|
|
{
|
|
string name = builtInType.ToString();
|
|
AnalogItemState item = CreateAnalogItemVariable(
|
|
analogItemFolder,
|
|
daAnalogItem + name,
|
|
name,
|
|
builtInType,
|
|
ValueRanks.Scalar);
|
|
|
|
if (builtInType is BuiltInType.Int64 or BuiltInType.UInt64)
|
|
{
|
|
// make test case without optional ranges
|
|
item.EngineeringUnits = null;
|
|
item.InstrumentRange = null;
|
|
}
|
|
else if (builtInType == BuiltInType.Float)
|
|
{
|
|
item.EURange!.Value.High = 0;
|
|
item.EURange.Value.Low = 0;
|
|
}
|
|
|
|
//set default value for Definition property
|
|
item.Definition?.Value = string.Empty;
|
|
}
|
|
}
|
|
|
|
ResetRandomGenerator(11);
|
|
FolderState analogArrayFolder = CreateFolder(
|
|
analogItemFolder,
|
|
"DataAccess_AnalogType_Array",
|
|
"Array");
|
|
const string daAnalogArray = "DataAccess_AnalogType_Array_";
|
|
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Byte",
|
|
"Byte",
|
|
BuiltInType.Byte,
|
|
ValueRanks.OneDimension,
|
|
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Double",
|
|
"Double",
|
|
BuiltInType.Double,
|
|
ValueRanks.OneDimension,
|
|
s_doubleArray);
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Duration",
|
|
"Duration",
|
|
DataTypeIds.Duration,
|
|
ValueRanks.OneDimension,
|
|
s_doubleArray,
|
|
null);
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Float",
|
|
"Float",
|
|
BuiltInType.Float,
|
|
ValueRanks.OneDimension,
|
|
s_singleArray);
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Int16",
|
|
"Int16",
|
|
BuiltInType.Int16,
|
|
ValueRanks.OneDimension,
|
|
s_shortArray);
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Int32",
|
|
"Int32",
|
|
BuiltInType.Int32,
|
|
ValueRanks.OneDimension,
|
|
s_int32Array);
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Int64",
|
|
"Int64",
|
|
BuiltInType.Int64,
|
|
ValueRanks.OneDimension,
|
|
new long[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Integer",
|
|
"Integer",
|
|
BuiltInType.Integer,
|
|
ValueRanks.OneDimension,
|
|
new long[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "Number",
|
|
"Number",
|
|
BuiltInType.Number,
|
|
ValueRanks.OneDimension,
|
|
s_shortArray);
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "SByte",
|
|
"SByte",
|
|
BuiltInType.SByte,
|
|
ValueRanks.OneDimension,
|
|
new sbyte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "UInt16",
|
|
"UInt16",
|
|
BuiltInType.UInt16,
|
|
ValueRanks.OneDimension,
|
|
new ushort[] { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "UInt32",
|
|
"UInt32",
|
|
BuiltInType.UInt32,
|
|
ValueRanks.OneDimension,
|
|
new uint[] { 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "UInt64",
|
|
"UInt64",
|
|
BuiltInType.UInt64,
|
|
ValueRanks.OneDimension,
|
|
new ulong[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }.ToArrayOf());
|
|
CreateAnalogItemVariable(
|
|
analogArrayFolder,
|
|
daAnalogArray + "UInteger",
|
|
"UInteger",
|
|
BuiltInType.UInteger,
|
|
ValueRanks.OneDimension,
|
|
new ulong[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }.ToArrayOf());
|
|
var doc1 = new XmlDocument();
|
|
|
|
ResetRandomGenerator(12);
|
|
FolderState discreteTypeFolder = CreateFolder(
|
|
daFolder,
|
|
"DataAccess_DiscreteType",
|
|
"DiscreteType");
|
|
FolderState twoStateDiscreteFolder = CreateFolder(
|
|
discreteTypeFolder,
|
|
"DataAccess_TwoStateDiscreteType",
|
|
"TwoStateDiscreteType");
|
|
const string daTwoStateDiscrete = "DataAccess_TwoStateDiscreteType_";
|
|
|
|
// Add our Nodes to the folder, and specify their customized discrete enumerations
|
|
CreateTwoStateDiscreteItemVariable(
|
|
twoStateDiscreteFolder,
|
|
daTwoStateDiscrete + "001",
|
|
"001",
|
|
"red",
|
|
"blue");
|
|
CreateTwoStateDiscreteItemVariable(
|
|
twoStateDiscreteFolder,
|
|
daTwoStateDiscrete + "002",
|
|
"002",
|
|
"open",
|
|
"close");
|
|
CreateTwoStateDiscreteItemVariable(
|
|
twoStateDiscreteFolder,
|
|
daTwoStateDiscrete + "003",
|
|
"003",
|
|
"up",
|
|
"down");
|
|
CreateTwoStateDiscreteItemVariable(
|
|
twoStateDiscreteFolder,
|
|
daTwoStateDiscrete + "004",
|
|
"004",
|
|
"left",
|
|
"right");
|
|
CreateTwoStateDiscreteItemVariable(
|
|
twoStateDiscreteFolder,
|
|
daTwoStateDiscrete + "005",
|
|
"005",
|
|
"circle",
|
|
"cross");
|
|
|
|
FolderState multiStateDiscreteFolder = CreateFolder(
|
|
discreteTypeFolder,
|
|
"DataAccess_MultiStateDiscreteType",
|
|
"MultiStateDiscreteType");
|
|
const string daMultiStateDiscrete = "DataAccess_MultiStateDiscreteType_";
|
|
|
|
// Add our Nodes to the folder, and specify their customized discrete enumerations
|
|
CreateMultiStateDiscreteItemVariable(
|
|
multiStateDiscreteFolder,
|
|
daMultiStateDiscrete + "001",
|
|
"001",
|
|
"open",
|
|
"closed",
|
|
"jammed");
|
|
CreateMultiStateDiscreteItemVariable(
|
|
multiStateDiscreteFolder,
|
|
daMultiStateDiscrete + "002",
|
|
"002",
|
|
"red",
|
|
"green",
|
|
"blue",
|
|
"cyan");
|
|
CreateMultiStateDiscreteItemVariable(
|
|
multiStateDiscreteFolder,
|
|
daMultiStateDiscrete + "003",
|
|
"003",
|
|
"lolo",
|
|
"lo",
|
|
"normal",
|
|
"hi",
|
|
"hihi");
|
|
CreateMultiStateDiscreteItemVariable(
|
|
multiStateDiscreteFolder,
|
|
daMultiStateDiscrete + "004",
|
|
"004",
|
|
"left",
|
|
"right",
|
|
"center");
|
|
CreateMultiStateDiscreteItemVariable(
|
|
multiStateDiscreteFolder,
|
|
daMultiStateDiscrete + "005",
|
|
"005",
|
|
"circle",
|
|
"cross",
|
|
"triangle");
|
|
|
|
ResetRandomGenerator(13);
|
|
FolderState multiStateValueDiscreteFolder = CreateFolder(
|
|
discreteTypeFolder,
|
|
"DataAccess_MultiStateValueDiscreteType",
|
|
"MultiStateValueDiscreteType");
|
|
const string daMultiStateValueDiscrete
|
|
= "DataAccess_MultiStateValueDiscreteType_";
|
|
|
|
// Add our Nodes to the folder, and specify their customized discrete enumerations
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "001",
|
|
"001",
|
|
s_stringArray1);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "002",
|
|
"002",
|
|
s_stringArray2);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "003",
|
|
"003",
|
|
s_stringArray3);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "004",
|
|
"004",
|
|
s_stringArray4);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "005",
|
|
"005",
|
|
s_stringArray5);
|
|
|
|
// Add our Nodes to the folder and specify varying data types
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "Byte",
|
|
"Byte",
|
|
DataTypeIds.Byte,
|
|
s_stringArray1);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "Int16",
|
|
"Int16",
|
|
DataTypeIds.Int16,
|
|
s_stringArray2);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "Int32",
|
|
"Int32",
|
|
DataTypeIds.Int32,
|
|
s_stringArray3);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "Int64",
|
|
"Int64",
|
|
DataTypeIds.Int64,
|
|
s_stringArray4);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "SByte",
|
|
"SByte",
|
|
DataTypeIds.SByte,
|
|
s_stringArray6);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "UInt16",
|
|
"UInt16",
|
|
DataTypeIds.UInt16,
|
|
s_stringArray7);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "UInt32",
|
|
"UInt32",
|
|
DataTypeIds.UInt32,
|
|
s_stringArray8);
|
|
CreateMultiStateValueDiscreteItemVariable(
|
|
multiStateValueDiscreteFolder,
|
|
daMultiStateValueDiscrete + "UInt64",
|
|
"UInt64",
|
|
DataTypeIds.UInt64,
|
|
s_stringArray9);
|
|
|
|
FolderState arrayItemTypeFolder = CreateFolder(daFolder, "DataAccess_ArrayItemType", "ArrayItemType");
|
|
const string daArrayItemType = "DataAccess_ArrayItemType_";
|
|
|
|
CreateYArrayItemVariable(arrayItemTypeFolder, daArrayItemType + "YArray", "YArray");
|
|
CreateXYArrayItemVariable(arrayItemTypeFolder, daArrayItemType + "XYArray", "XYArray");
|
|
CreateImageItemVariable(arrayItemTypeFolder, daArrayItemType + "Image", "Image");
|
|
CreateCubeItemVariable(arrayItemTypeFolder, daArrayItemType + "Cube", "Cube");
|
|
CreateNDimensionArrayItemVariable(arrayItemTypeFolder, daArrayItemType + "NDimension", "NDimension");
|
|
|
|
ResetRandomGenerator(14);
|
|
FolderState referencesFolder = CreateFolder(root, "References", "References");
|
|
const string referencesPrefix = "References_";
|
|
|
|
BaseDataVariableState referencesInstructions = CreateVariable(
|
|
referencesFolder,
|
|
"References_Instructions",
|
|
"Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
referencesInstructions.Value =
|
|
"This folder will contain nodes that have specific Reference configurations.";
|
|
variables.Add(referencesInstructions);
|
|
|
|
// create variable nodes with specific references
|
|
BaseDataVariableState hasForwardReference = CreateMeshVariable(
|
|
referencesFolder,
|
|
referencesPrefix + "HasForwardReference",
|
|
"HasForwardReference");
|
|
hasForwardReference.AddReference(
|
|
ReferenceTypeIds.HasCause,
|
|
false,
|
|
variables[0].NodeId);
|
|
variables.Add(hasForwardReference);
|
|
|
|
BaseDataVariableState hasInverseReference = CreateMeshVariable(
|
|
referencesFolder,
|
|
referencesPrefix + "HasInverseReference",
|
|
"HasInverseReference");
|
|
hasInverseReference.AddReference(
|
|
ReferenceTypeIds.HasCause,
|
|
true,
|
|
variables[0].NodeId);
|
|
variables.Add(hasInverseReference);
|
|
|
|
BaseDataVariableState? has3InverseReference = null;
|
|
for (int i = 1; i <= 5; i++)
|
|
{
|
|
string referenceString = "Has3ForwardReferences";
|
|
if (i > 1)
|
|
{
|
|
referenceString += i.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
BaseDataVariableState has3ForwardReferences = CreateMeshVariable(
|
|
referencesFolder,
|
|
referencesPrefix + referenceString,
|
|
referenceString);
|
|
has3ForwardReferences.AddReference(
|
|
ReferenceTypeIds.HasCause,
|
|
false,
|
|
variables[0].NodeId);
|
|
has3ForwardReferences.AddReference(
|
|
ReferenceTypeIds.HasCause,
|
|
false,
|
|
variables[1].NodeId);
|
|
has3ForwardReferences.AddReference(
|
|
ReferenceTypeIds.HasCause,
|
|
false,
|
|
variables[2].NodeId);
|
|
if (i == 1)
|
|
{
|
|
has3InverseReference = has3ForwardReferences;
|
|
}
|
|
variables.Add(has3ForwardReferences);
|
|
}
|
|
|
|
BaseDataVariableState has3InverseReferences = CreateMeshVariable(
|
|
referencesFolder,
|
|
referencesPrefix + "Has3InverseReferences",
|
|
"Has3InverseReferences");
|
|
has3InverseReferences.AddReference(
|
|
ReferenceTypeIds.HasEffect,
|
|
true,
|
|
variables[0].NodeId);
|
|
has3InverseReferences.AddReference(
|
|
ReferenceTypeIds.HasEffect,
|
|
true,
|
|
variables[1].NodeId);
|
|
has3InverseReferences.AddReference(
|
|
ReferenceTypeIds.HasEffect,
|
|
true,
|
|
variables[2].NodeId);
|
|
variables.Add(has3InverseReferences);
|
|
|
|
BaseDataVariableState hasForwardAndInverseReferences = CreateMeshVariable(
|
|
referencesFolder,
|
|
referencesPrefix + "HasForwardAndInverseReference",
|
|
"HasForwardAndInverseReference",
|
|
hasForwardReference,
|
|
hasInverseReference,
|
|
has3InverseReference!,
|
|
has3InverseReferences,
|
|
variables[0]);
|
|
variables.Add(hasForwardAndInverseReferences);
|
|
|
|
// Node with both a ReferenceType and a SubType of that ReferenceType
|
|
// (HasComponent forward + HasOrderedComponent forward, where HasOrderedComponent
|
|
// is a subtype of HasComponent — satisfies CTT "HasReferencesOfReferenceTypeAndSubType")
|
|
BaseDataVariableState hasReferenceTypeAndSubType = CreateMeshVariable(
|
|
referencesFolder,
|
|
referencesPrefix + "HasReferenceTypeAndSubType",
|
|
"HasReferenceTypeAndSubType");
|
|
hasReferenceTypeAndSubType.AddReference(
|
|
ReferenceTypeIds.HasComponent,
|
|
false,
|
|
variables[0].NodeId);
|
|
hasReferenceTypeAndSubType.AddReference(
|
|
ReferenceTypeIds.HasOrderedComponent,
|
|
false,
|
|
variables[1].NodeId);
|
|
variables.Add(hasReferenceTypeAndSubType);
|
|
|
|
ResetRandomGenerator(15);
|
|
FolderState folderAccessRights = CreateFolder(
|
|
root,
|
|
"AccessRights",
|
|
"AccessRights");
|
|
const string accessRights = "AccessRights_";
|
|
|
|
BaseDataVariableState accessRightsInstructions = CreateVariable(
|
|
folderAccessRights,
|
|
accessRights + "Instructions",
|
|
"Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
accessRightsInstructions.Value =
|
|
"This folder will be accessible to all who enter, but contents therein will be secured.";
|
|
variables.Add(accessRightsInstructions);
|
|
|
|
// sub-folder for "AccessAll"
|
|
FolderState folderAccessRightsAccessAll = CreateFolder(
|
|
folderAccessRights,
|
|
"AccessRights_AccessAll",
|
|
"AccessAll");
|
|
const string accessRightsAccessAll = "AccessRights_AccessAll_";
|
|
|
|
BaseDataVariableState arAllRO = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "RO",
|
|
"RO",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllRO.AccessLevel = AccessLevels.CurrentRead;
|
|
arAllRO.UserAccessLevel = AccessLevels.CurrentRead;
|
|
variables.Add(arAllRO);
|
|
BaseDataVariableState arAllWO = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "WO",
|
|
"WO",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllWO.AccessLevel = AccessLevels.CurrentWrite;
|
|
arAllWO.UserAccessLevel = AccessLevels.CurrentWrite;
|
|
variables.Add(arAllWO);
|
|
BaseDataVariableState arAllRW = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "RW",
|
|
"RW",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllRW.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
arAllRW.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variables.Add(arAllRW);
|
|
BaseDataVariableState arAllRONotUser = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "RO_NotUser",
|
|
"RO_NotUser",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllRONotUser.AccessLevel = AccessLevels.CurrentRead;
|
|
arAllRONotUser.UserAccessLevel = AccessLevels.None;
|
|
variables.Add(arAllRONotUser);
|
|
BaseDataVariableState arAllWONotUser = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "WO_NotUser",
|
|
"WO_NotUser",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllWONotUser.AccessLevel = AccessLevels.CurrentWrite;
|
|
arAllWONotUser.UserAccessLevel = AccessLevels.None;
|
|
variables.Add(arAllWONotUser);
|
|
BaseDataVariableState arAllRWNotUser = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "RW_NotUser",
|
|
"RW_NotUser",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllRWNotUser.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
arAllRWNotUser.UserAccessLevel = AccessLevels.CurrentRead;
|
|
variables.Add(arAllRWNotUser);
|
|
BaseDataVariableState arAllROUserRW = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "RO_User1_RW",
|
|
"RO_User1_RW",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllROUserRW.AccessLevel = AccessLevels.CurrentRead;
|
|
arAllROUserRW.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variables.Add(arAllROUserRW);
|
|
BaseDataVariableState arAllROGroupRW = CreateVariable(
|
|
folderAccessRightsAccessAll,
|
|
accessRightsAccessAll + "RO_Group1_RW",
|
|
"RO_Group1_RW",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arAllROGroupRW.AccessLevel = AccessLevels.CurrentRead;
|
|
arAllROGroupRW.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variables.Add(arAllROGroupRW);
|
|
|
|
// sub-folder for "AccessUser1"
|
|
FolderState folderAccessRightsAccessUser1 = CreateFolder(
|
|
folderAccessRights,
|
|
"AccessRights_AccessUser1",
|
|
"AccessUser1");
|
|
const string accessRightsAccessUser1 = "AccessRights_AccessUser1_";
|
|
|
|
BaseDataVariableState arUserRO = CreateVariable(
|
|
folderAccessRightsAccessUser1,
|
|
accessRightsAccessUser1 + "RO",
|
|
"RO",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arUserRO.AccessLevel = AccessLevels.CurrentRead;
|
|
arUserRO.UserAccessLevel = AccessLevels.CurrentRead;
|
|
variables.Add(arUserRO);
|
|
BaseDataVariableState arUserWO = CreateVariable(
|
|
folderAccessRightsAccessUser1,
|
|
accessRightsAccessUser1 + "WO",
|
|
"WO",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arUserWO.AccessLevel = AccessLevels.CurrentWrite;
|
|
arUserWO.UserAccessLevel = AccessLevels.CurrentWrite;
|
|
variables.Add(arUserWO);
|
|
BaseDataVariableState arUserRW = CreateVariable(
|
|
folderAccessRightsAccessUser1,
|
|
accessRightsAccessUser1 + "RW",
|
|
"RW",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arUserRW.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
arUserRW.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variables.Add(arUserRW);
|
|
|
|
// sub-folder for "AccessGroup1"
|
|
FolderState folderAccessRightsAccessGroup1 = CreateFolder(
|
|
folderAccessRights,
|
|
"AccessRights_AccessGroup1",
|
|
"AccessGroup1");
|
|
const string accessRightsAccessGroup1 = "AccessRights_AccessGroup1_";
|
|
|
|
BaseDataVariableState arGroupRO = CreateVariable(
|
|
folderAccessRightsAccessGroup1,
|
|
accessRightsAccessGroup1 + "RO",
|
|
"RO",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arGroupRO.AccessLevel = AccessLevels.CurrentRead;
|
|
arGroupRO.UserAccessLevel = AccessLevels.CurrentRead;
|
|
variables.Add(arGroupRO);
|
|
BaseDataVariableState arGroupWO = CreateVariable(
|
|
folderAccessRightsAccessGroup1,
|
|
accessRightsAccessGroup1 + "WO",
|
|
"WO",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arGroupWO.AccessLevel = AccessLevels.CurrentWrite;
|
|
arGroupWO.UserAccessLevel = AccessLevels.CurrentWrite;
|
|
variables.Add(arGroupWO);
|
|
BaseDataVariableState arGroupRW = CreateVariable(
|
|
folderAccessRightsAccessGroup1,
|
|
accessRightsAccessGroup1 + "RW",
|
|
"RW",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arGroupRW.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
arGroupRW.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variables.Add(arGroupRW);
|
|
|
|
// sub folder for "RolePermissions"
|
|
FolderState folderRolePermissions = CreateFolder(
|
|
folderAccessRights,
|
|
"AccessRights_RolePermissions",
|
|
"RolePermissions");
|
|
const string rolePermissions = "AccessRights_RolePermissions_";
|
|
|
|
BaseDataVariableState rpAnonymous = CreateVariable(
|
|
folderRolePermissions,
|
|
rolePermissions + "AnonymousAccess",
|
|
"AnonymousAccess",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
rpAnonymous.Description = LocalizedText.From(
|
|
"This node can be accessed by users that have Anonymous Role");
|
|
rpAnonymous.RolePermissions =
|
|
[
|
|
// allow access to users with Anonymous role
|
|
new RolePermissionType
|
|
{
|
|
RoleId = ObjectIds.WellKnownRole_Anonymous,
|
|
Permissions = (uint)(
|
|
PermissionType.Browse |
|
|
PermissionType.Read |
|
|
PermissionType.ReadRolePermissions |
|
|
PermissionType.Write)
|
|
}
|
|
];
|
|
variables.Add(rpAnonymous);
|
|
|
|
BaseDataVariableState rpAuthenticatedUser = CreateVariable(
|
|
folderRolePermissions,
|
|
rolePermissions + "AuthenticatedUser",
|
|
"AuthenticatedUser",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
rpAuthenticatedUser.Description =
|
|
LocalizedText.From("This node can be accessed by users that have AuthenticatedUser Role");
|
|
rpAuthenticatedUser.RolePermissions =
|
|
[
|
|
// allow access to users with AuthenticatedUser role
|
|
new RolePermissionType
|
|
{
|
|
RoleId = ObjectIds.WellKnownRole_AuthenticatedUser,
|
|
Permissions = (uint)(
|
|
PermissionType.Browse |
|
|
PermissionType.Read |
|
|
PermissionType.ReadRolePermissions |
|
|
PermissionType.Write)
|
|
}
|
|
];
|
|
variables.Add(rpAuthenticatedUser);
|
|
|
|
BaseDataVariableState rpSecurityAdminUser = CreateVariable(
|
|
folderRolePermissions,
|
|
rolePermissions + "SecurityAdmin",
|
|
"SecurityAdmin",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
rpSecurityAdminUser.Description = LocalizedText.From(
|
|
"This node can be accessed by users that have SecurityAdmin Role over an encrypted connection");
|
|
rpSecurityAdminUser.AccessRestrictions
|
|
= AccessRestrictionType.EncryptionRequired;
|
|
rpSecurityAdminUser.RolePermissions =
|
|
[
|
|
// allow access to users with SecurityAdmin role
|
|
new RolePermissionType
|
|
{
|
|
RoleId = ObjectIds.WellKnownRole_SecurityAdmin,
|
|
Permissions = (uint)(
|
|
PermissionType.Browse |
|
|
PermissionType.Read |
|
|
PermissionType.ReadRolePermissions |
|
|
PermissionType.Write)
|
|
}
|
|
];
|
|
variables.Add(rpSecurityAdminUser);
|
|
|
|
BaseDataVariableState rpConfigAdminUser = CreateVariable(
|
|
folderRolePermissions,
|
|
rolePermissions + "ConfigureAdmin",
|
|
"ConfigureAdmin",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
rpConfigAdminUser.Description = LocalizedText.From(
|
|
"This node can be accessed by users that have ConfigureAdmin Role over an encrypted connection");
|
|
rpConfigAdminUser.AccessRestrictions = AccessRestrictionType.EncryptionRequired;
|
|
rpConfigAdminUser.RolePermissions =
|
|
[
|
|
// allow access to users with ConfigureAdmin role
|
|
new RolePermissionType
|
|
{
|
|
RoleId = ObjectIds.WellKnownRole_ConfigureAdmin,
|
|
Permissions = (uint)(
|
|
PermissionType.Browse |
|
|
PermissionType.Read |
|
|
PermissionType.ReadRolePermissions |
|
|
PermissionType.Write)
|
|
}
|
|
];
|
|
variables.Add(rpConfigAdminUser);
|
|
|
|
// sub-folder for "AccessRestrictions"
|
|
FolderState folderAccessRestrictions = CreateFolder(
|
|
folderAccessRights,
|
|
"AccessRights_AccessRestrictions",
|
|
"AccessRestrictions");
|
|
const string accessRestrictions = "AccessRights_AccessRestrictions_";
|
|
|
|
BaseDataVariableState arNone = CreateVariable(
|
|
folderAccessRestrictions,
|
|
accessRestrictions + "None",
|
|
"None",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arNone.AccessLevel = AccessLevels.CurrentRead;
|
|
arNone.UserAccessLevel = AccessLevels.CurrentRead;
|
|
arNone.AccessRestrictions = AccessRestrictionType.None;
|
|
variables.Add(arNone);
|
|
|
|
BaseDataVariableState arSigningRequired = CreateVariable(
|
|
folderAccessRestrictions,
|
|
accessRestrictions + "SigningRequired",
|
|
"SigningRequired",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arSigningRequired.AccessLevel = AccessLevels.CurrentRead;
|
|
arSigningRequired.UserAccessLevel = AccessLevels.CurrentRead;
|
|
arSigningRequired.AccessRestrictions = AccessRestrictionType.SigningRequired;
|
|
variables.Add(arSigningRequired);
|
|
|
|
BaseDataVariableState arEncryptionRequired = CreateVariable(
|
|
folderAccessRestrictions,
|
|
accessRestrictions + "EncryptionRequired",
|
|
"EncryptionRequired",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arEncryptionRequired.AccessLevel = AccessLevels.CurrentRead;
|
|
arEncryptionRequired.UserAccessLevel = AccessLevels.CurrentRead;
|
|
arEncryptionRequired.AccessRestrictions
|
|
= AccessRestrictionType.EncryptionRequired;
|
|
variables.Add(arEncryptionRequired);
|
|
|
|
BaseDataVariableState arSessionRequired = CreateVariable(
|
|
folderAccessRestrictions,
|
|
accessRestrictions + "SessionRequired",
|
|
"SessionRequired",
|
|
BuiltInType.Int16,
|
|
ValueRanks.Scalar);
|
|
arSessionRequired.AccessLevel = AccessLevels.CurrentRead;
|
|
arSessionRequired.UserAccessLevel = AccessLevels.CurrentRead;
|
|
arSessionRequired.AccessRestrictions = AccessRestrictionType.SessionRequired;
|
|
variables.Add(arSessionRequired);
|
|
|
|
ResetRandomGenerator(16);
|
|
FolderState nodeIdsFolder = CreateFolder(root, "NodeIds", "NodeIds");
|
|
const string nodeIds = "NodeIds_";
|
|
|
|
BaseDataVariableState nodeIdsInstructions = CreateVariable(
|
|
nodeIdsFolder,
|
|
nodeIds + "Instructions",
|
|
"Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
nodeIdsInstructions.Value =
|
|
"All supported Node types are available except whichever is in use for the other nodes.";
|
|
variables.Add(nodeIdsInstructions);
|
|
|
|
BaseDataVariableState integerNodeId = CreateVariable(
|
|
nodeIdsFolder,
|
|
nodeIds + "Int16Integer",
|
|
"Int16Integer",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar);
|
|
integerNodeId.NodeId = new NodeId(9202, NamespaceIndex);
|
|
variables.Add(integerNodeId);
|
|
|
|
variables.Add(
|
|
CreateVariable(
|
|
nodeIdsFolder,
|
|
nodeIds + "Int16String",
|
|
"Int16String",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar));
|
|
|
|
BaseDataVariableState guidNodeId = CreateVariable(
|
|
nodeIdsFolder,
|
|
nodeIds + "Int16GUID",
|
|
"Int16GUID",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar);
|
|
guidNodeId.NodeId = new NodeId(
|
|
new Guid("00000000-0000-0000-0000-000000009204"),
|
|
NamespaceIndex);
|
|
variables.Add(guidNodeId);
|
|
|
|
BaseDataVariableState opaqueNodeId = CreateVariable(
|
|
nodeIdsFolder,
|
|
nodeIds + "Int16Opaque",
|
|
"Int16Opaque",
|
|
DataTypeIds.Int16,
|
|
ValueRanks.Scalar);
|
|
opaqueNodeId.NodeId = new NodeId(ByteString.From([9, 2, 0, 5]), NamespaceIndex);
|
|
variables.Add(opaqueNodeId);
|
|
|
|
FolderState eventsFolder = CreateFolder(nodeIdsFolder, "NodeIds_Events", "Events");
|
|
const string nodeIdsEvents = "NodeIds_Events_";
|
|
|
|
BaseDataVariableState triggerNode01 = CreateVariable(
|
|
eventsFolder,
|
|
nodeIdsEvents + "TriggerNode01",
|
|
"TriggerNode01",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.Scalar);
|
|
triggerNode01.OnSimpleWriteValue = OnWriteTriggerNode;
|
|
variables.Add(triggerNode01);
|
|
|
|
BaseDataVariableState triggerNode02 = CreateVariable(
|
|
eventsFolder,
|
|
nodeIdsEvents + "TriggerNode02",
|
|
"TriggerNode02",
|
|
DataTypeIds.Int32,
|
|
ValueRanks.Scalar);
|
|
triggerNode02.OnSimpleWriteValue = OnWriteTriggerNode;
|
|
variables.Add(triggerNode02);
|
|
|
|
ResetRandomGenerator(17);
|
|
FolderState methodsFolder = CreateFolder(root, "Methods", "Methods");
|
|
const string methods = "Methods_";
|
|
|
|
BaseDataVariableState methodsInstructions = CreateVariable(
|
|
methodsFolder,
|
|
methods + "Instructions",
|
|
"Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
methodsInstructions.Value
|
|
= "Contains methods with varying parameter definitions.";
|
|
variables.Add(methodsInstructions);
|
|
|
|
MethodState voidMethod = CreateMethod(methodsFolder, methods + "Void", "Void");
|
|
voidMethod.OnCallMethod = new GenericMethodCalledEventHandler(OnVoidCall);
|
|
|
|
MethodState addMethod = CreateMethod(methodsFolder, methods + "Add", "Add");
|
|
// set input arguments
|
|
addMethod.InputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(addMethod)
|
|
{
|
|
NodeId = new NodeId(addMethod.BrowseName.Name + "InArgs", NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.InputArguments)
|
|
};
|
|
addMethod.InputArguments.DisplayName = LocalizedText.From(addMethod.InputArguments.BrowseName.Name!);
|
|
addMethod.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
addMethod.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
addMethod.InputArguments.DataType = DataTypeIds.Argument;
|
|
addMethod.InputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
addMethod.InputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Float value",
|
|
Description = LocalizedText.From("Float value"),
|
|
DataType = DataTypeIds.Float,
|
|
ValueRank = ValueRanks.Scalar
|
|
},
|
|
new Argument
|
|
{
|
|
Name = "UInt32 value",
|
|
Description = LocalizedText.From("UInt32 value"),
|
|
DataType = DataTypeIds.UInt32,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
// set output arguments
|
|
addMethod.OutputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(addMethod)
|
|
{
|
|
NodeId = new NodeId(addMethod.BrowseName.Name + "OutArgs", NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.OutputArguments)
|
|
};
|
|
addMethod.OutputArguments.DisplayName = LocalizedText.From(addMethod.OutputArguments.BrowseName.Name!);
|
|
addMethod.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
addMethod.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
addMethod.OutputArguments.DataType = DataTypeIds.Argument;
|
|
addMethod.OutputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
addMethod.OutputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Add Result",
|
|
Description = LocalizedText.From("Add Result"),
|
|
DataType = DataTypeIds.Float,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
addMethod.OnCallMethod = new GenericMethodCalledEventHandler(OnAddCall);
|
|
|
|
MethodState multiplyMethod = CreateMethod(
|
|
methodsFolder,
|
|
methods + "Multiply",
|
|
"Multiply");
|
|
// set input arguments
|
|
multiplyMethod.InputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(multiplyMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
multiplyMethod.BrowseName.Name + "InArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.InputArguments)
|
|
};
|
|
multiplyMethod.InputArguments.DisplayName = LocalizedText.From(
|
|
multiplyMethod.InputArguments.BrowseName.Name!);
|
|
multiplyMethod.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
multiplyMethod.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
multiplyMethod.InputArguments.DataType = DataTypeIds.Argument;
|
|
multiplyMethod.InputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
multiplyMethod.InputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Int16 value",
|
|
Description = LocalizedText.From("Int16 value"),
|
|
DataType = DataTypeIds.Int16,
|
|
ValueRank = ValueRanks.Scalar
|
|
},
|
|
new Argument
|
|
{
|
|
Name = "UInt16 value",
|
|
Description = LocalizedText.From("UInt16 value"),
|
|
DataType = DataTypeIds.UInt16,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
// set output arguments
|
|
multiplyMethod.OutputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(multiplyMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
multiplyMethod.BrowseName.Name + "OutArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.OutputArguments)
|
|
};
|
|
multiplyMethod.OutputArguments.DisplayName = LocalizedText.From(
|
|
multiplyMethod.OutputArguments.BrowseName.Name!);
|
|
multiplyMethod.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
multiplyMethod.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
multiplyMethod.OutputArguments.DataType = DataTypeIds.Argument;
|
|
multiplyMethod.OutputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
multiplyMethod.OutputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Multiply Result",
|
|
Description = LocalizedText.From("Multiply Result"),
|
|
DataType = DataTypeIds.Int32,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
multiplyMethod.OnCallMethod
|
|
= new GenericMethodCalledEventHandler(OnMultiplyCall);
|
|
|
|
MethodState divideMethod = CreateMethod(
|
|
methodsFolder,
|
|
methods + "Divide",
|
|
"Divide");
|
|
// set input arguments
|
|
divideMethod.InputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(divideMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
divideMethod.BrowseName.Name + "InArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.InputArguments)
|
|
};
|
|
divideMethod.InputArguments.DisplayName = LocalizedText.From(
|
|
divideMethod.InputArguments.BrowseName.Name!);
|
|
divideMethod.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
divideMethod.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
divideMethod.InputArguments.DataType = DataTypeIds.Argument;
|
|
divideMethod.InputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
divideMethod.InputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Int32 value",
|
|
Description = LocalizedText.From("Int32 value"),
|
|
DataType = DataTypeIds.Int32,
|
|
ValueRank = ValueRanks.Scalar
|
|
},
|
|
new Argument
|
|
{
|
|
Name = "UInt16 value",
|
|
Description = LocalizedText.From("UInt16 value"),
|
|
DataType = DataTypeIds.UInt16,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
// set output arguments
|
|
divideMethod.OutputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(divideMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
divideMethod.BrowseName.Name + "OutArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.OutputArguments)
|
|
};
|
|
divideMethod.OutputArguments.DisplayName = LocalizedText.From(
|
|
divideMethod.OutputArguments.BrowseName.Name!);
|
|
divideMethod.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
divideMethod.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
divideMethod.OutputArguments.DataType = DataTypeIds.Argument;
|
|
divideMethod.OutputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
divideMethod.OutputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Divide Result",
|
|
Description = LocalizedText.From("Divide Result"),
|
|
DataType = DataTypeIds.Float,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
divideMethod.OnCallMethod = new GenericMethodCalledEventHandler(OnDivideCall);
|
|
|
|
MethodState substractMethod = CreateMethod(
|
|
methodsFolder,
|
|
methods + "Substract",
|
|
"Substract");
|
|
// set input arguments
|
|
substractMethod.InputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(substractMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
substractMethod.BrowseName.Name + "InArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.InputArguments)
|
|
};
|
|
substractMethod.InputArguments.DisplayName = LocalizedText.From(
|
|
substractMethod.InputArguments.BrowseName.Name!);
|
|
substractMethod.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
substractMethod.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
substractMethod.InputArguments.DataType = DataTypeIds.Argument;
|
|
substractMethod.InputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
substractMethod.InputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Int16 value",
|
|
Description = LocalizedText.From("Int16 value"),
|
|
DataType = DataTypeIds.Int16,
|
|
ValueRank = ValueRanks.Scalar
|
|
},
|
|
new Argument
|
|
{
|
|
Name = "Byte value",
|
|
Description = LocalizedText.From("Byte value"),
|
|
DataType = DataTypeIds.Byte,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
// set output arguments
|
|
substractMethod.OutputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(substractMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
substractMethod.BrowseName.Name + "OutArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.OutputArguments)
|
|
};
|
|
substractMethod.OutputArguments.DisplayName = LocalizedText.From(
|
|
substractMethod.OutputArguments.BrowseName.Name!);
|
|
substractMethod.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
substractMethod.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
substractMethod.OutputArguments.DataType = DataTypeIds.Argument;
|
|
substractMethod.OutputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
substractMethod.OutputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Substract Result",
|
|
Description = LocalizedText.From("Substract Result"),
|
|
DataType = DataTypeIds.Int16,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
substractMethod.OnCallMethod
|
|
= new GenericMethodCalledEventHandler(OnSubstractCall);
|
|
|
|
MethodState helloMethod = CreateMethod(
|
|
methodsFolder,
|
|
methods + "Hello",
|
|
"Hello");
|
|
// set input arguments
|
|
helloMethod.InputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(helloMethod)
|
|
{
|
|
NodeId = new NodeId(helloMethod.BrowseName.Name + "InArgs", NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.InputArguments)
|
|
};
|
|
helloMethod.InputArguments.DisplayName = LocalizedText.From(
|
|
helloMethod.InputArguments.BrowseName.Name!);
|
|
helloMethod.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
helloMethod.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
helloMethod.InputArguments.DataType = DataTypeIds.Argument;
|
|
helloMethod.InputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
helloMethod.InputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "String value",
|
|
Description = LocalizedText.From("String value"),
|
|
DataType = DataTypeIds.String,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
// set output arguments
|
|
helloMethod.OutputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(helloMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
helloMethod.BrowseName.Name + "OutArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.OutputArguments)
|
|
};
|
|
helloMethod.OutputArguments.DisplayName = LocalizedText.From(
|
|
helloMethod.OutputArguments.BrowseName.Name!);
|
|
helloMethod.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
helloMethod.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
helloMethod.OutputArguments.DataType = DataTypeIds.Argument;
|
|
helloMethod.OutputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
helloMethod.OutputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Hello Result",
|
|
Description = LocalizedText.From("Hello Result"),
|
|
DataType = DataTypeIds.String,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
helloMethod.OnCallMethod = new GenericMethodCalledEventHandler(OnHelloCall);
|
|
|
|
MethodState inputMethod = CreateMethod(
|
|
methodsFolder,
|
|
methods + "Input",
|
|
"Input");
|
|
// set input arguments
|
|
inputMethod.InputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(inputMethod)
|
|
{
|
|
NodeId = new NodeId(inputMethod.BrowseName.Name + "InArgs", NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.InputArguments)
|
|
};
|
|
inputMethod.InputArguments.DisplayName = LocalizedText.From(
|
|
inputMethod.InputArguments.BrowseName.Name!);
|
|
inputMethod.InputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
inputMethod.InputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
inputMethod.InputArguments.DataType = DataTypeIds.Argument;
|
|
inputMethod.InputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
inputMethod.InputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "String value",
|
|
Description = LocalizedText.From("String value"),
|
|
DataType = DataTypeIds.String,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
inputMethod.OnCallMethod = new GenericMethodCalledEventHandler(OnInputCall);
|
|
|
|
MethodState outputMethod = CreateMethod(
|
|
methodsFolder,
|
|
methods + "Output",
|
|
"Output");
|
|
|
|
// set output arguments
|
|
outputMethod.OutputArguments = new PropertyState<ArrayOf<Argument>>.Implementation<StructureBuilder<Argument>>(helloMethod)
|
|
{
|
|
NodeId = new NodeId(
|
|
helloMethod.BrowseName.Name + "OutArgs",
|
|
NamespaceIndex),
|
|
BrowseName = QualifiedName.From(BrowseNames.OutputArguments)
|
|
};
|
|
outputMethod.OutputArguments.DisplayName = LocalizedText.From(
|
|
outputMethod.OutputArguments.BrowseName.Name!);
|
|
outputMethod.OutputArguments.TypeDefinitionId = VariableTypeIds.PropertyType;
|
|
outputMethod.OutputArguments.ReferenceTypeId = ReferenceTypeIds.HasProperty;
|
|
outputMethod.OutputArguments.DataType = DataTypeIds.Argument;
|
|
outputMethod.OutputArguments.ValueRank = ValueRanks.OneDimension;
|
|
|
|
outputMethod.OutputArguments.Value =
|
|
[
|
|
new Argument
|
|
{
|
|
Name = "Output Result",
|
|
Description = LocalizedText.From("Output Result"),
|
|
DataType = DataTypeIds.String,
|
|
ValueRank = ValueRanks.Scalar
|
|
}
|
|
];
|
|
|
|
outputMethod.OnCallMethod = new GenericMethodCalledEventHandler(OnOutputCall);
|
|
|
|
ResetRandomGenerator(18);
|
|
FolderState viewsFolder = CreateFolder(root, "Views", "Views");
|
|
const string views = "Views_";
|
|
ViewState viewStateOperations = await CreateViewAsync(
|
|
viewsFolder,
|
|
externalReferences,
|
|
views + "Operations",
|
|
"Operations",
|
|
cancellationToken).ConfigureAwait(false);
|
|
viewStateOperations.AddReference(
|
|
ReferenceTypeIds.Organizes,
|
|
false,
|
|
massFolder.NodeId);
|
|
massFolder.AddReference(
|
|
ReferenceTypeIds.Organizes,
|
|
true,
|
|
viewStateOperations.NodeId);
|
|
|
|
ViewState viewStateEngineering = await CreateViewAsync(
|
|
viewsFolder,
|
|
externalReferences,
|
|
views + "Engineering",
|
|
"Engineering",
|
|
cancellationToken).ConfigureAwait(false);
|
|
viewStateEngineering.AddReference(
|
|
ReferenceTypeIds.Organizes,
|
|
false,
|
|
simulationFolder.NodeId);
|
|
simulationFolder.AddReference(
|
|
ReferenceTypeIds.Organizes,
|
|
true,
|
|
viewStateEngineering.NodeId);
|
|
|
|
ResetRandomGenerator(19);
|
|
FolderState localesFolder = CreateFolder(root, "Locales", "Locales");
|
|
const string locales = "Locales_";
|
|
|
|
BaseDataVariableState qnEnglishVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNEnglish",
|
|
"QNEnglish",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnEnglishVariable.Description = new LocalizedText("en", "English");
|
|
qnEnglishVariable.Value = new QualifiedName("Hello World", NamespaceIndex);
|
|
variables.Add(qnEnglishVariable);
|
|
BaseDataVariableState ltEnglishVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTEnglish",
|
|
"LTEnglish",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltEnglishVariable.Description = new LocalizedText("en", "English");
|
|
ltEnglishVariable.Value = new LocalizedText("en", "Hello World");
|
|
variables.Add(ltEnglishVariable);
|
|
|
|
BaseDataVariableState qnFrancaisVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNFrancais",
|
|
"QNFrancais",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnFrancaisVariable.Description = new LocalizedText("en", "Francais");
|
|
qnFrancaisVariable.Value
|
|
= new QualifiedName("Salut tout le monde", NamespaceIndex);
|
|
variables.Add(qnFrancaisVariable);
|
|
BaseDataVariableState ltFrancaisVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTFrancais",
|
|
"LTFrancais",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltFrancaisVariable.Description = new LocalizedText("en", "Francais");
|
|
ltFrancaisVariable.Value = new LocalizedText("fr", "Salut tout le monde");
|
|
variables.Add(ltFrancaisVariable);
|
|
|
|
BaseDataVariableState qnDeutschVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNDeutsch",
|
|
"QNDeutsch",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnDeutschVariable.Description = new LocalizedText("en", "Deutsch");
|
|
qnDeutschVariable.Value = new QualifiedName("Hallo Welt", NamespaceIndex);
|
|
variables.Add(qnDeutschVariable);
|
|
BaseDataVariableState ltDeutschVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTDeutsch",
|
|
"LTDeutsch",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltDeutschVariable.Description = new LocalizedText("en", "Deutsch");
|
|
ltDeutschVariable.Value = new LocalizedText("de", "Hallo Welt");
|
|
variables.Add(ltDeutschVariable);
|
|
|
|
BaseDataVariableState qnEspanolVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNEspanol",
|
|
"QNEspanol",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnEspanolVariable.Description = new LocalizedText("en", "Espanol");
|
|
qnEspanolVariable.Value = new QualifiedName("Hola mundo", NamespaceIndex);
|
|
variables.Add(qnEspanolVariable);
|
|
BaseDataVariableState ltEspanolVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTEspanol",
|
|
"LTEspanol",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltEspanolVariable.Description = new LocalizedText("en", "Espanol");
|
|
ltEspanolVariable.Value = new LocalizedText("es", "Hola mundo");
|
|
variables.Add(ltEspanolVariable);
|
|
|
|
BaseDataVariableState qnJapaneseVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QN日本の",
|
|
"QN日本の",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnJapaneseVariable.Description = new LocalizedText("en", "Japanese");
|
|
qnJapaneseVariable.Value = new QualifiedName("ハローワールド", NamespaceIndex);
|
|
variables.Add(qnJapaneseVariable);
|
|
BaseDataVariableState ltJapaneseVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LT日本の",
|
|
"LT日本の",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltJapaneseVariable.Description = new LocalizedText("en", "Japanese");
|
|
ltJapaneseVariable.Value = new LocalizedText("jp", "ハローワールド");
|
|
variables.Add(ltJapaneseVariable);
|
|
|
|
BaseDataVariableState qnChineseVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QN中國的",
|
|
"QN中國的",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnChineseVariable.Description = new LocalizedText("en", "Chinese");
|
|
qnChineseVariable.Value = new QualifiedName("世界您好", NamespaceIndex);
|
|
variables.Add(qnChineseVariable);
|
|
BaseDataVariableState ltChineseVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LT中國的",
|
|
"LT中國的",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltChineseVariable.Description = new LocalizedText("en", "Chinese");
|
|
ltChineseVariable.Value = new LocalizedText("ch", "世界您好");
|
|
variables.Add(ltChineseVariable);
|
|
|
|
BaseDataVariableState qnRussianVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNрусский",
|
|
"QNрусский",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnRussianVariable.Description = new LocalizedText("en", "Russian");
|
|
qnRussianVariable.Value = new QualifiedName("LTрусский", NamespaceIndex);
|
|
variables.Add(qnRussianVariable);
|
|
BaseDataVariableState ltRussianVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTрусский",
|
|
"LTрусский",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltRussianVariable.Description = new LocalizedText("en", "Russian");
|
|
ltRussianVariable.Value = new LocalizedText("ru", "LTрусский");
|
|
variables.Add(ltRussianVariable);
|
|
|
|
BaseDataVariableState qnArabicVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNالعربية",
|
|
"QNالعربية",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnArabicVariable.Description = new LocalizedText("en", "Arabic");
|
|
qnArabicVariable.Value = new QualifiedName("مرحبا بالعال", NamespaceIndex);
|
|
variables.Add(qnArabicVariable);
|
|
BaseDataVariableState ltArabicVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTالعربية",
|
|
"LTالعربية",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltArabicVariable.Description = new LocalizedText("en", "Arabic");
|
|
ltArabicVariable.Value = new LocalizedText("ae", "مرحبا بالعال");
|
|
variables.Add(ltArabicVariable);
|
|
|
|
BaseDataVariableState qnKlingonVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "QNtlhIngan",
|
|
"QNtlhIngan",
|
|
DataTypeIds.QualifiedName,
|
|
ValueRanks.Scalar);
|
|
qnKlingonVariable.Description = new LocalizedText("en", "Klingon");
|
|
qnKlingonVariable.Value = new QualifiedName("qo' vIvan", NamespaceIndex);
|
|
variables.Add(qnKlingonVariable);
|
|
BaseDataVariableState ltKlingonVariable = CreateVariable(
|
|
localesFolder,
|
|
locales + "LTtlhIngan",
|
|
"LTtlhIngan",
|
|
DataTypeIds.LocalizedText,
|
|
ValueRanks.Scalar);
|
|
ltKlingonVariable.Description = new LocalizedText("en", "Klingon");
|
|
ltKlingonVariable.Value = new LocalizedText("ko", "qo' vIvan");
|
|
variables.Add(ltKlingonVariable);
|
|
|
|
ResetRandomGenerator(20);
|
|
FolderState folderAttributes = CreateFolder(root, "Attributes", "Attributes");
|
|
|
|
FolderState folderAttributesAccessAll = CreateFolder(
|
|
folderAttributes,
|
|
"Attributes_AccessAll",
|
|
"AccessAll");
|
|
const string attributesAccessAll = "Attributes_AccessAll_";
|
|
|
|
BaseDataVariableState accessLevelAccessAll = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "AccessLevel",
|
|
"AccessLevel",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
accessLevelAccessAll.WriteMask = AttributeWriteMask.AccessLevel;
|
|
accessLevelAccessAll.UserWriteMask = AttributeWriteMask.AccessLevel;
|
|
variables.Add(accessLevelAccessAll);
|
|
|
|
BaseDataVariableState arrayDimensionsAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "ArrayDimensions",
|
|
"ArrayDimensions",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
arrayDimensionsAccessLevel.WriteMask = AttributeWriteMask.ArrayDimensions;
|
|
arrayDimensionsAccessLevel.UserWriteMask = AttributeWriteMask.ArrayDimensions;
|
|
variables.Add(arrayDimensionsAccessLevel);
|
|
|
|
BaseDataVariableState browseNameAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "BrowseName",
|
|
"BrowseName",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
browseNameAccessLevel.WriteMask = AttributeWriteMask.BrowseName;
|
|
browseNameAccessLevel.UserWriteMask = AttributeWriteMask.BrowseName;
|
|
variables.Add(browseNameAccessLevel);
|
|
|
|
BaseDataVariableState containsNoLoopsAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "ContainsNoLoops",
|
|
"ContainsNoLoops",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
containsNoLoopsAccessLevel.WriteMask = AttributeWriteMask.ContainsNoLoops;
|
|
containsNoLoopsAccessLevel.UserWriteMask = AttributeWriteMask.ContainsNoLoops;
|
|
variables.Add(containsNoLoopsAccessLevel);
|
|
|
|
BaseDataVariableState dataTypeAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "DataType",
|
|
"DataType",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
dataTypeAccessLevel.WriteMask = AttributeWriteMask.DataType;
|
|
dataTypeAccessLevel.UserWriteMask = AttributeWriteMask.DataType;
|
|
variables.Add(dataTypeAccessLevel);
|
|
|
|
BaseDataVariableState descriptionAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "Description",
|
|
"Description",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
descriptionAccessLevel.WriteMask = AttributeWriteMask.Description;
|
|
descriptionAccessLevel.UserWriteMask = AttributeWriteMask.Description;
|
|
variables.Add(descriptionAccessLevel);
|
|
|
|
BaseDataVariableState eventNotifierAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "EventNotifier",
|
|
"EventNotifier",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
eventNotifierAccessLevel.WriteMask = AttributeWriteMask.EventNotifier;
|
|
eventNotifierAccessLevel.UserWriteMask = AttributeWriteMask.EventNotifier;
|
|
variables.Add(eventNotifierAccessLevel);
|
|
|
|
BaseDataVariableState executableAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "Executable",
|
|
"Executable",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
executableAccessLevel.WriteMask = AttributeWriteMask.Executable;
|
|
executableAccessLevel.UserWriteMask = AttributeWriteMask.Executable;
|
|
variables.Add(executableAccessLevel);
|
|
|
|
BaseDataVariableState historizingAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "Historizing",
|
|
"Historizing",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
historizingAccessLevel.WriteMask = AttributeWriteMask.Historizing;
|
|
historizingAccessLevel.UserWriteMask = AttributeWriteMask.Historizing;
|
|
variables.Add(historizingAccessLevel);
|
|
|
|
BaseDataVariableState inverseNameAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "InverseName",
|
|
"InverseName",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
inverseNameAccessLevel.WriteMask = AttributeWriteMask.InverseName;
|
|
inverseNameAccessLevel.UserWriteMask = AttributeWriteMask.InverseName;
|
|
variables.Add(inverseNameAccessLevel);
|
|
|
|
BaseDataVariableState isAbstractAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "IsAbstract",
|
|
"IsAbstract",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
isAbstractAccessLevel.WriteMask = AttributeWriteMask.IsAbstract;
|
|
isAbstractAccessLevel.UserWriteMask = AttributeWriteMask.IsAbstract;
|
|
variables.Add(isAbstractAccessLevel);
|
|
|
|
BaseDataVariableState minimumSamplingIntervalAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "MinimumSamplingInterval",
|
|
"MinimumSamplingInterval",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
minimumSamplingIntervalAccessLevel.WriteMask
|
|
= AttributeWriteMask.MinimumSamplingInterval;
|
|
minimumSamplingIntervalAccessLevel.UserWriteMask
|
|
= AttributeWriteMask.MinimumSamplingInterval;
|
|
variables.Add(minimumSamplingIntervalAccessLevel);
|
|
|
|
BaseDataVariableState nodeClassIntervalAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "NodeClass",
|
|
"NodeClass",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
nodeClassIntervalAccessLevel.WriteMask = AttributeWriteMask.NodeClass;
|
|
nodeClassIntervalAccessLevel.UserWriteMask = AttributeWriteMask.NodeClass;
|
|
variables.Add(nodeClassIntervalAccessLevel);
|
|
|
|
BaseDataVariableState nodeIdAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
nodeIdAccessLevel.WriteMask = AttributeWriteMask.NodeId;
|
|
nodeIdAccessLevel.UserWriteMask = AttributeWriteMask.NodeId;
|
|
variables.Add(nodeIdAccessLevel);
|
|
|
|
BaseDataVariableState symmetricAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "Symmetric",
|
|
"Symmetric",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
symmetricAccessLevel.WriteMask = AttributeWriteMask.Symmetric;
|
|
symmetricAccessLevel.UserWriteMask = AttributeWriteMask.Symmetric;
|
|
variables.Add(symmetricAccessLevel);
|
|
|
|
BaseDataVariableState userAccessLevelAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "UserAccessLevel",
|
|
"UserAccessLevel",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
userAccessLevelAccessLevel.WriteMask = AttributeWriteMask.UserAccessLevel;
|
|
userAccessLevelAccessLevel.UserWriteMask = AttributeWriteMask.UserAccessLevel;
|
|
variables.Add(userAccessLevelAccessLevel);
|
|
|
|
BaseDataVariableState userExecutableAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "UserExecutable",
|
|
"UserExecutable",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
userExecutableAccessLevel.WriteMask = AttributeWriteMask.UserExecutable;
|
|
userExecutableAccessLevel.UserWriteMask = AttributeWriteMask.UserExecutable;
|
|
variables.Add(userExecutableAccessLevel);
|
|
|
|
BaseDataVariableState valueRankAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "ValueRank",
|
|
"ValueRank",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
valueRankAccessLevel.WriteMask = AttributeWriteMask.ValueRank;
|
|
valueRankAccessLevel.UserWriteMask = AttributeWriteMask.ValueRank;
|
|
variables.Add(valueRankAccessLevel);
|
|
|
|
BaseDataVariableState writeMaskAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "WriteMask",
|
|
"WriteMask",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
writeMaskAccessLevel.WriteMask = AttributeWriteMask.WriteMask;
|
|
writeMaskAccessLevel.UserWriteMask = AttributeWriteMask.WriteMask;
|
|
variables.Add(writeMaskAccessLevel);
|
|
|
|
BaseDataVariableState valueForVariableTypeAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "ValueForVariableType",
|
|
"ValueForVariableType",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
valueForVariableTypeAccessLevel.WriteMask
|
|
= AttributeWriteMask.ValueForVariableType;
|
|
valueForVariableTypeAccessLevel.UserWriteMask
|
|
= AttributeWriteMask.ValueForVariableType;
|
|
variables.Add(valueForVariableTypeAccessLevel);
|
|
|
|
BaseDataVariableState allAccessLevel = CreateVariable(
|
|
folderAttributesAccessAll,
|
|
attributesAccessAll + "All",
|
|
"All",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
allAccessLevel.WriteMask =
|
|
AttributeWriteMask.AccessLevel |
|
|
AttributeWriteMask.ArrayDimensions |
|
|
AttributeWriteMask.BrowseName |
|
|
AttributeWriteMask.ContainsNoLoops |
|
|
AttributeWriteMask.DataType |
|
|
AttributeWriteMask.Description |
|
|
AttributeWriteMask.DisplayName |
|
|
AttributeWriteMask.EventNotifier |
|
|
AttributeWriteMask.Executable |
|
|
AttributeWriteMask.Historizing |
|
|
AttributeWriteMask.InverseName |
|
|
AttributeWriteMask.IsAbstract |
|
|
AttributeWriteMask.MinimumSamplingInterval |
|
|
AttributeWriteMask.NodeClass |
|
|
AttributeWriteMask.NodeId |
|
|
AttributeWriteMask.Symmetric |
|
|
AttributeWriteMask.UserAccessLevel |
|
|
AttributeWriteMask.UserExecutable |
|
|
AttributeWriteMask.UserWriteMask |
|
|
AttributeWriteMask.ValueForVariableType |
|
|
AttributeWriteMask.ValueRank |
|
|
AttributeWriteMask.WriteMask;
|
|
allAccessLevel.UserWriteMask =
|
|
AttributeWriteMask.AccessLevel |
|
|
AttributeWriteMask.ArrayDimensions |
|
|
AttributeWriteMask.BrowseName |
|
|
AttributeWriteMask.ContainsNoLoops |
|
|
AttributeWriteMask.DataType |
|
|
AttributeWriteMask.Description |
|
|
AttributeWriteMask.DisplayName |
|
|
AttributeWriteMask.EventNotifier |
|
|
AttributeWriteMask.Executable |
|
|
AttributeWriteMask.Historizing |
|
|
AttributeWriteMask.InverseName |
|
|
AttributeWriteMask.IsAbstract |
|
|
AttributeWriteMask.MinimumSamplingInterval |
|
|
AttributeWriteMask.NodeClass |
|
|
AttributeWriteMask.NodeId |
|
|
AttributeWriteMask.Symmetric |
|
|
AttributeWriteMask.UserAccessLevel |
|
|
AttributeWriteMask.UserExecutable |
|
|
AttributeWriteMask.UserWriteMask |
|
|
AttributeWriteMask.ValueForVariableType |
|
|
AttributeWriteMask.ValueRank |
|
|
AttributeWriteMask.WriteMask;
|
|
variables.Add(allAccessLevel);
|
|
|
|
FolderState folderAttributesAccessUser1 = CreateFolder(
|
|
folderAttributes,
|
|
"Attributes_AccessUser1",
|
|
"AccessUser1");
|
|
const string attributesAccessUser1 = "Attributes_AccessUser1_";
|
|
|
|
BaseDataVariableState accessLevelAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "AccessLevel",
|
|
"AccessLevel",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
accessLevelAccessAll.WriteMask = AttributeWriteMask.AccessLevel;
|
|
accessLevelAccessAll.UserWriteMask = AttributeWriteMask.AccessLevel;
|
|
variables.Add(accessLevelAccessAll);
|
|
|
|
BaseDataVariableState arrayDimensionsAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "ArrayDimensions",
|
|
"ArrayDimensions",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
arrayDimensionsAccessUser1.WriteMask = AttributeWriteMask.ArrayDimensions;
|
|
arrayDimensionsAccessUser1.UserWriteMask = AttributeWriteMask.ArrayDimensions;
|
|
variables.Add(arrayDimensionsAccessUser1);
|
|
|
|
BaseDataVariableState browseNameAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "BrowseName",
|
|
"BrowseName",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
browseNameAccessUser1.WriteMask = AttributeWriteMask.BrowseName;
|
|
browseNameAccessUser1.UserWriteMask = AttributeWriteMask.BrowseName;
|
|
variables.Add(browseNameAccessUser1);
|
|
|
|
BaseDataVariableState containsNoLoopsAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "ContainsNoLoops",
|
|
"ContainsNoLoops",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
containsNoLoopsAccessUser1.WriteMask = AttributeWriteMask.ContainsNoLoops;
|
|
containsNoLoopsAccessUser1.UserWriteMask = AttributeWriteMask.ContainsNoLoops;
|
|
variables.Add(containsNoLoopsAccessUser1);
|
|
|
|
BaseDataVariableState dataTypeAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "DataType",
|
|
"DataType",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
dataTypeAccessUser1.WriteMask = AttributeWriteMask.DataType;
|
|
dataTypeAccessUser1.UserWriteMask = AttributeWriteMask.DataType;
|
|
variables.Add(dataTypeAccessUser1);
|
|
|
|
BaseDataVariableState descriptionAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "Description",
|
|
"Description",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
descriptionAccessUser1.WriteMask = AttributeWriteMask.Description;
|
|
descriptionAccessUser1.UserWriteMask = AttributeWriteMask.Description;
|
|
variables.Add(descriptionAccessUser1);
|
|
|
|
BaseDataVariableState eventNotifierAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "EventNotifier",
|
|
"EventNotifier",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
eventNotifierAccessUser1.WriteMask = AttributeWriteMask.EventNotifier;
|
|
eventNotifierAccessUser1.UserWriteMask = AttributeWriteMask.EventNotifier;
|
|
variables.Add(eventNotifierAccessUser1);
|
|
|
|
BaseDataVariableState executableAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "Executable",
|
|
"Executable",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
executableAccessUser1.WriteMask = AttributeWriteMask.Executable;
|
|
executableAccessUser1.UserWriteMask = AttributeWriteMask.Executable;
|
|
variables.Add(executableAccessUser1);
|
|
|
|
BaseDataVariableState historizingAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "Historizing",
|
|
"Historizing",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
historizingAccessUser1.WriteMask = AttributeWriteMask.Historizing;
|
|
historizingAccessUser1.UserWriteMask = AttributeWriteMask.Historizing;
|
|
variables.Add(historizingAccessUser1);
|
|
|
|
BaseDataVariableState inverseNameAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "InverseName",
|
|
"InverseName",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
inverseNameAccessUser1.WriteMask = AttributeWriteMask.InverseName;
|
|
inverseNameAccessUser1.UserWriteMask = AttributeWriteMask.InverseName;
|
|
variables.Add(inverseNameAccessUser1);
|
|
|
|
BaseDataVariableState isAbstractAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "IsAbstract",
|
|
"IsAbstract",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
isAbstractAccessUser1.WriteMask = AttributeWriteMask.IsAbstract;
|
|
isAbstractAccessUser1.UserWriteMask = AttributeWriteMask.IsAbstract;
|
|
variables.Add(isAbstractAccessUser1);
|
|
|
|
BaseDataVariableState minimumSamplingIntervalAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "MinimumSamplingInterval",
|
|
"MinimumSamplingInterval",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
minimumSamplingIntervalAccessUser1.WriteMask
|
|
= AttributeWriteMask.MinimumSamplingInterval;
|
|
minimumSamplingIntervalAccessUser1.UserWriteMask
|
|
= AttributeWriteMask.MinimumSamplingInterval;
|
|
variables.Add(minimumSamplingIntervalAccessUser1);
|
|
|
|
BaseDataVariableState nodeClassIntervalAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "NodeClass",
|
|
"NodeClass",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
nodeClassIntervalAccessUser1.WriteMask = AttributeWriteMask.NodeClass;
|
|
nodeClassIntervalAccessUser1.UserWriteMask = AttributeWriteMask.NodeClass;
|
|
variables.Add(nodeClassIntervalAccessUser1);
|
|
|
|
BaseDataVariableState nodeIdAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "NodeId",
|
|
"NodeId",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
nodeIdAccessUser1.WriteMask = AttributeWriteMask.NodeId;
|
|
nodeIdAccessUser1.UserWriteMask = AttributeWriteMask.NodeId;
|
|
variables.Add(nodeIdAccessUser1);
|
|
|
|
BaseDataVariableState symmetricAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "Symmetric",
|
|
"Symmetric",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
symmetricAccessUser1.WriteMask = AttributeWriteMask.Symmetric;
|
|
symmetricAccessUser1.UserWriteMask = AttributeWriteMask.Symmetric;
|
|
variables.Add(symmetricAccessUser1);
|
|
|
|
BaseDataVariableState userAccessUser1AccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "UserAccessUser1",
|
|
"UserAccessUser1",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
userAccessUser1AccessUser1.WriteMask = AttributeWriteMask.UserAccessLevel;
|
|
userAccessUser1AccessUser1.UserWriteMask = AttributeWriteMask.UserAccessLevel;
|
|
variables.Add(userAccessUser1AccessUser1);
|
|
|
|
BaseDataVariableState userExecutableAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "UserExecutable",
|
|
"UserExecutable",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
userExecutableAccessUser1.WriteMask = AttributeWriteMask.UserExecutable;
|
|
userExecutableAccessUser1.UserWriteMask = AttributeWriteMask.UserExecutable;
|
|
variables.Add(userExecutableAccessUser1);
|
|
|
|
BaseDataVariableState valueRankAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "ValueRank",
|
|
"ValueRank",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
valueRankAccessUser1.WriteMask = AttributeWriteMask.ValueRank;
|
|
valueRankAccessUser1.UserWriteMask = AttributeWriteMask.ValueRank;
|
|
variables.Add(valueRankAccessUser1);
|
|
|
|
BaseDataVariableState writeMaskAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "WriteMask",
|
|
"WriteMask",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
writeMaskAccessUser1.WriteMask = AttributeWriteMask.WriteMask;
|
|
writeMaskAccessUser1.UserWriteMask = AttributeWriteMask.WriteMask;
|
|
variables.Add(writeMaskAccessUser1);
|
|
|
|
BaseDataVariableState valueForVariableTypeAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "ValueForVariableType",
|
|
"ValueForVariableType",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
valueForVariableTypeAccessUser1.WriteMask
|
|
= AttributeWriteMask.ValueForVariableType;
|
|
valueForVariableTypeAccessUser1.UserWriteMask
|
|
= AttributeWriteMask.ValueForVariableType;
|
|
variables.Add(valueForVariableTypeAccessUser1);
|
|
|
|
BaseDataVariableState allAccessUser1 = CreateVariable(
|
|
folderAttributesAccessUser1,
|
|
attributesAccessUser1 + "All",
|
|
"All",
|
|
DataTypeIds.Double,
|
|
ValueRanks.Scalar);
|
|
allAccessUser1.WriteMask =
|
|
AttributeWriteMask.AccessLevel |
|
|
AttributeWriteMask.ArrayDimensions |
|
|
AttributeWriteMask.BrowseName |
|
|
AttributeWriteMask.ContainsNoLoops |
|
|
AttributeWriteMask.DataType |
|
|
AttributeWriteMask.Description |
|
|
AttributeWriteMask.DisplayName |
|
|
AttributeWriteMask.EventNotifier |
|
|
AttributeWriteMask.Executable |
|
|
AttributeWriteMask.Historizing |
|
|
AttributeWriteMask.InverseName |
|
|
AttributeWriteMask.IsAbstract |
|
|
AttributeWriteMask.MinimumSamplingInterval |
|
|
AttributeWriteMask.NodeClass |
|
|
AttributeWriteMask.NodeId |
|
|
AttributeWriteMask.Symmetric |
|
|
AttributeWriteMask.UserAccessLevel |
|
|
AttributeWriteMask.UserExecutable |
|
|
AttributeWriteMask.UserWriteMask |
|
|
AttributeWriteMask.ValueForVariableType |
|
|
AttributeWriteMask.ValueRank |
|
|
AttributeWriteMask.WriteMask;
|
|
allAccessUser1.UserWriteMask =
|
|
AttributeWriteMask.AccessLevel |
|
|
AttributeWriteMask.ArrayDimensions |
|
|
AttributeWriteMask.BrowseName |
|
|
AttributeWriteMask.ContainsNoLoops |
|
|
AttributeWriteMask.DataType |
|
|
AttributeWriteMask.Description |
|
|
AttributeWriteMask.DisplayName |
|
|
AttributeWriteMask.EventNotifier |
|
|
AttributeWriteMask.Executable |
|
|
AttributeWriteMask.Historizing |
|
|
AttributeWriteMask.InverseName |
|
|
AttributeWriteMask.IsAbstract |
|
|
AttributeWriteMask.MinimumSamplingInterval |
|
|
AttributeWriteMask.NodeClass |
|
|
AttributeWriteMask.NodeId |
|
|
AttributeWriteMask.Symmetric |
|
|
AttributeWriteMask.UserAccessLevel |
|
|
AttributeWriteMask.UserExecutable |
|
|
AttributeWriteMask.UserWriteMask |
|
|
AttributeWriteMask.ValueForVariableType |
|
|
AttributeWriteMask.ValueRank |
|
|
AttributeWriteMask.WriteMask;
|
|
variables.Add(allAccessUser1);
|
|
|
|
ResetRandomGenerator(21);
|
|
FolderState myCompanyFolder = CreateFolder(root, "MyCompany", "MyCompany");
|
|
const string myCompany = "MyCompany_";
|
|
|
|
BaseDataVariableState myCompanyInstructions = CreateVariable(
|
|
myCompanyFolder,
|
|
myCompany + "Instructions",
|
|
"Instructions",
|
|
DataTypeIds.String,
|
|
ValueRanks.Scalar);
|
|
myCompanyInstructions.Value
|
|
= "A place for the vendor to describe their address-space.";
|
|
variables.Add(myCompanyInstructions);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_logger.LogError(e, "Error creating the ReferenceNodeManager address space.");
|
|
}
|
|
|
|
await AddPredefinedNodeAsync(SystemContext, root, cancellationToken).ConfigureAwait(false);
|
|
|
|
// Enable history archiving for selected scalar variables.
|
|
await EnableHistoryArchivingAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
if (m_simulationEnabled)
|
|
{
|
|
// reset random generator and generate boundary values
|
|
ResetRandomGenerator(100, 1);
|
|
|
|
TimeProvider timeProvider = (Server as ITimeProviderProvider)?.TimeProvider
|
|
?? TimeProvider.System;
|
|
m_simulationTimer?.Dispose();
|
|
m_simulationTimer = timeProvider.CreateTimer(
|
|
DoSimulation,
|
|
null,
|
|
TimeSpan.FromMilliseconds(m_simulationInterval),
|
|
TimeSpan.FromMilliseconds(m_simulationInterval));
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
m_semaphore.Release();
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnWriteInterval(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
ref Variant value)
|
|
{
|
|
try
|
|
{
|
|
m_simulationInterval = (ushort)value;
|
|
|
|
if (m_simulationEnabled)
|
|
{
|
|
m_simulationTimer!.Change(
|
|
TimeSpan.FromMilliseconds(100),
|
|
TimeSpan.FromMilliseconds(m_simulationInterval));
|
|
}
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_logger.LogError(e, "Error writing Interval variable.");
|
|
return ServiceResult.Create(e, StatusCodes.Bad, "Error writing Interval variable.");
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnWriteEnabled(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
ref Variant value)
|
|
{
|
|
try
|
|
{
|
|
m_simulationEnabled = (bool)value;
|
|
|
|
if (m_simulationEnabled)
|
|
{
|
|
m_simulationTimer!.Change(
|
|
TimeSpan.FromMilliseconds(100),
|
|
TimeSpan.FromMilliseconds(m_simulationInterval));
|
|
}
|
|
else
|
|
{
|
|
m_simulationTimer!.Change(
|
|
TimeSpan.FromMilliseconds(100),
|
|
TimeSpan.Zero);
|
|
}
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_logger.LogError(e, "Error writing Enabled variable.");
|
|
return ServiceResult.Create(e, StatusCodes.Bad, "Error writing Enabled variable.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new folder.
|
|
/// </summary>
|
|
private FolderState CreateFolder(NodeState? parent, string path, string name)
|
|
{
|
|
var folder = new FolderState(parent)
|
|
{
|
|
SymbolicName = name,
|
|
ReferenceTypeId = ReferenceTypeIds.Organizes,
|
|
TypeDefinitionId = ObjectTypeIds.FolderType,
|
|
NodeId = new NodeId(path, NamespaceIndex),
|
|
BrowseName = new QualifiedName(path, NamespaceIndex),
|
|
DisplayName = new LocalizedText("en", name),
|
|
WriteMask = AttributeWriteMask.None,
|
|
UserWriteMask = AttributeWriteMask.None,
|
|
EventNotifier = EventNotifiers.None
|
|
};
|
|
|
|
parent?.AddChild(folder);
|
|
return folder;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private BaseDataVariableState CreateMeshVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
params NodeState[] peers)
|
|
{
|
|
BaseDataVariableState variable = CreateVariable(
|
|
parent,
|
|
path,
|
|
name,
|
|
BuiltInType.Double,
|
|
ValueRanks.Scalar);
|
|
|
|
if (peers != null)
|
|
{
|
|
foreach (NodeState peer in peers)
|
|
{
|
|
peer.AddReference(ReferenceTypeIds.HasCause, false, variable.NodeId);
|
|
variable.AddReference(ReferenceTypeIds.HasCause, true, peer.NodeId);
|
|
peer.AddReference(ReferenceTypeIds.HasEffect, true, variable.NodeId);
|
|
variable.AddReference(ReferenceTypeIds.HasEffect, false, peer.NodeId);
|
|
}
|
|
}
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private DataItemState CreateDataItemVariable(
|
|
FolderState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank)
|
|
{
|
|
var variable = new DataItemState(parent);
|
|
variable.ValuePrecision = PropertyState<double>.With<VariantBuilder>(variable);
|
|
variable.Definition = PropertyState<string>.With<VariantBuilder>(variable);
|
|
|
|
variable.Create(SystemContext, default, variable.BrowseName, default, true);
|
|
|
|
variable.SymbolicName = name;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.BrowseName = new QualifiedName(path, NamespaceIndex);
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.DataType = (NodeId)(uint)dataType;
|
|
variable.ValueRank = valueRank;
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = TypeInfo.GetDefaultVariantValue((NodeId)(uint)dataType, valueRank, Server.TypeTree);
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
if (valueRank == ValueRanks.OneDimension)
|
|
{
|
|
variable.ArrayDimensions = [0];
|
|
}
|
|
else if (valueRank == ValueRanks.TwoDimensions)
|
|
{
|
|
variable.ArrayDimensions = [0, 0];
|
|
}
|
|
|
|
variable.ValuePrecision.Value = 2;
|
|
variable.ValuePrecision.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.ValuePrecision.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Definition.Value = string.Empty;
|
|
variable.Definition.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Definition.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
|
|
parent?.AddChild(variable);
|
|
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private AnalogItemState CreateAnalogItemVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank)
|
|
{
|
|
return CreateAnalogItemVariable(parent, path, name, dataType, valueRank, default);
|
|
}
|
|
|
|
private AnalogItemState CreateAnalogItemVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank,
|
|
Variant initialValues)
|
|
{
|
|
return CreateAnalogItemVariable(
|
|
parent,
|
|
path,
|
|
name,
|
|
dataType,
|
|
valueRank,
|
|
initialValues,
|
|
null);
|
|
}
|
|
|
|
private AnalogItemState CreateAnalogItemVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank,
|
|
Variant initialValues,
|
|
Range? customRange)
|
|
{
|
|
return CreateAnalogItemVariable(
|
|
parent,
|
|
path,
|
|
name,
|
|
(NodeId)(uint)dataType,
|
|
valueRank,
|
|
initialValues,
|
|
customRange);
|
|
}
|
|
|
|
private AnalogItemState CreateAnalogItemVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
NodeId dataType,
|
|
int valueRank,
|
|
Variant initialValues,
|
|
Range? customRange)
|
|
{
|
|
var variable = new AnalogItemState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex)
|
|
};
|
|
variable.EngineeringUnits = PropertyState<EUInformation>.With<StructureBuilder<EUInformation>>(variable);
|
|
variable.InstrumentRange = PropertyState<Range>.With<StructureBuilder<Range>>(variable);
|
|
|
|
variable.Create(
|
|
SystemContext,
|
|
new NodeId(path, NamespaceIndex),
|
|
variable.BrowseName,
|
|
default,
|
|
true);
|
|
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.SymbolicName = name;
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = dataType;
|
|
variable.ValueRank = valueRank;
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
|
|
if (valueRank == ValueRanks.OneDimension)
|
|
{
|
|
variable.ArrayDimensions = [0];
|
|
}
|
|
else if (valueRank == ValueRanks.TwoDimensions)
|
|
{
|
|
variable.ArrayDimensions = [0, 0];
|
|
}
|
|
|
|
BuiltInType builtInType = TypeInfo.GetBuiltInType(dataType, Server.TypeTree);
|
|
|
|
if (!TypeInfo.IsNumericType(builtInType))
|
|
{
|
|
throw new ArgumentException("AnalogItem must have a numeric DataType.", nameof(dataType));
|
|
}
|
|
|
|
// Simulate a mV Voltmeter
|
|
Range newRange = GetAnalogRange(builtInType);
|
|
// Using anything but 120,-10 fails a few tests
|
|
newRange.High = Math.Min(newRange.High, 120);
|
|
newRange.Low = Math.Max(newRange.Low, -10);
|
|
variable.InstrumentRange.Value = newRange;
|
|
|
|
variable.EURange!.Value = customRange ?? new Range(100, 0);
|
|
|
|
variable.Value = initialValues;
|
|
if (variable.Value.IsNull)
|
|
{
|
|
variable.Value = TypeInfo.GetDefaultVariantValue(dataType, valueRank, Server.TypeTree);
|
|
}
|
|
|
|
variable.StatusCode = StatusCodes.Good;
|
|
// The latest UNECE version (Rev 11, published in 2015) is available here:
|
|
// http://www.opcfoundation.org/UA/EngineeringUnits/UNECE/rec20_latest_08052015.zip
|
|
variable.EngineeringUnits.Value = new EUInformation(
|
|
"mV",
|
|
"millivolt",
|
|
"http://www.opcfoundation.org/UA/units/un/cefact")
|
|
{
|
|
// The mapping of the UNECE codes to OPC UA(EUInformation.unitId) is available here:
|
|
// http://www.opcfoundation.org/UA/EngineeringUnits/UNECE/UNECE_to_OPCUA.csv
|
|
UnitId = 12890 // "2Z"
|
|
};
|
|
variable.OnWriteValue = OnWriteAnalog;
|
|
variable.EURange.OnWriteValue = OnWriteAnalogRange;
|
|
variable.EURange.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.EURange.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.EngineeringUnits.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.EngineeringUnits.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.InstrumentRange.OnWriteValue = OnWriteAnalogRange;
|
|
variable.InstrumentRange.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.InstrumentRange.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
|
|
parent?.AddChild(variable);
|
|
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private TwoStateDiscreteState CreateTwoStateDiscreteItemVariable(
|
|
FolderState parent,
|
|
string path,
|
|
string name,
|
|
string trueState,
|
|
string falseState)
|
|
{
|
|
var variable = new TwoStateDiscreteState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex),
|
|
DisplayName = new LocalizedText("en", name),
|
|
WriteMask = AttributeWriteMask.None,
|
|
UserWriteMask = AttributeWriteMask.None
|
|
};
|
|
|
|
variable.Create(SystemContext, default, variable.BrowseName, default, true);
|
|
|
|
variable.SymbolicName = name;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = DataTypeIds.Boolean;
|
|
variable.ValueRank = ValueRanks.Scalar;
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = (bool)GetNewValue(variable);
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
variable.TrueState!.Value = LocalizedText.From(trueState);
|
|
variable.TrueState.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.TrueState.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
|
|
variable.FalseState!.Value = LocalizedText.From(falseState);
|
|
variable.FalseState.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.FalseState.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
|
|
parent?.AddChild(variable);
|
|
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private MultiStateDiscreteState CreateMultiStateDiscreteItemVariable(
|
|
FolderState parent,
|
|
string path,
|
|
string name,
|
|
params string[] values)
|
|
{
|
|
var variable = new MultiStateDiscreteState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex),
|
|
DisplayName = new LocalizedText("en", name),
|
|
WriteMask = AttributeWriteMask.None,
|
|
UserWriteMask = AttributeWriteMask.None
|
|
};
|
|
|
|
variable.Create(SystemContext, default, variable.BrowseName, default, true);
|
|
|
|
variable.SymbolicName = name;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = DataTypeIds.UInt32;
|
|
variable.ValueRank = ValueRanks.Scalar;
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = (uint)0;
|
|
variable.StatusCode = StatusCodes.Good;
|
|
variable.OnWriteValue = OnWriteDiscrete;
|
|
|
|
var strings = new LocalizedText[values.Length];
|
|
|
|
for (int ii = 0; ii < strings.Length; ii++)
|
|
{
|
|
strings[ii] = LocalizedText.From(values[ii]);
|
|
}
|
|
|
|
variable.EnumStrings!.Value = strings;
|
|
variable.EnumStrings.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.EnumStrings.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
|
|
parent?.AddChild(variable);
|
|
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new UInt32 variable.
|
|
/// </summary>
|
|
private MultiStateValueDiscreteState CreateMultiStateValueDiscreteItemVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
ArrayOf<string> enumNames)
|
|
{
|
|
return CreateMultiStateValueDiscreteItemVariable(parent, path, name, default, enumNames);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private MultiStateValueDiscreteState CreateMultiStateValueDiscreteItemVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
NodeId nodeId,
|
|
ArrayOf<string> enumNames)
|
|
{
|
|
var variable = new MultiStateValueDiscreteState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex),
|
|
DisplayName = new LocalizedText("en", name),
|
|
WriteMask = AttributeWriteMask.None,
|
|
UserWriteMask = AttributeWriteMask.None
|
|
};
|
|
|
|
variable.Create(SystemContext, default, variable.BrowseName, default, true);
|
|
|
|
variable.SymbolicName = name;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = nodeId.IsNull ? DataTypeIds.UInt32 : nodeId;
|
|
variable.ValueRank = ValueRanks.Scalar;
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = (uint)0;
|
|
variable.StatusCode = StatusCodes.Good;
|
|
variable.OnWriteValue = OnWriteValueDiscrete;
|
|
|
|
// there are two enumerations for this type:
|
|
// EnumStrings = the string representations for enumerated values
|
|
// ValueAsText = the actual enumerated value
|
|
|
|
// set the enumerated strings
|
|
var strings = new LocalizedText[enumNames.Count];
|
|
for (int ii = 0; ii < strings.Length; ii++)
|
|
{
|
|
strings[ii] = LocalizedText.From(enumNames[ii]);
|
|
}
|
|
|
|
// set the enumerated values
|
|
var values = new EnumValueType[enumNames.Count];
|
|
for (int ii = 0; ii < values.Length; ii++)
|
|
{
|
|
values[ii] = new EnumValueType
|
|
{
|
|
Value = ii,
|
|
Description = strings[ii],
|
|
DisplayName = strings[ii]
|
|
};
|
|
}
|
|
variable.EnumValues!.Value = values;
|
|
variable.EnumValues.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.EnumValues.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.ValueAsText!.Value = variable.EnumValues.Value[0].DisplayName;
|
|
|
|
parent?.AddChild(variable);
|
|
return variable;
|
|
}
|
|
|
|
private ServiceResult OnWriteDiscrete(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
NumericRange indexRange,
|
|
QualifiedName dataEncoding,
|
|
ref Variant value,
|
|
ref StatusCode statusCode,
|
|
ref DateTimeUtc timestamp)
|
|
{
|
|
var variable = node as MultiStateDiscreteState;
|
|
|
|
// verify data type.
|
|
var typeInfo = TypeInfo.IsInstanceOfDataType(
|
|
value,
|
|
variable!.DataType,
|
|
variable.ValueRank,
|
|
context.NamespaceUris,
|
|
context.TypeTable);
|
|
|
|
if (typeInfo.IsUnknown)
|
|
{
|
|
return StatusCodes.BadTypeMismatch;
|
|
}
|
|
|
|
if (!indexRange.IsNull)
|
|
{
|
|
return StatusCodes.BadIndexRangeInvalid;
|
|
}
|
|
|
|
double number = value.GetDouble();
|
|
|
|
if (number >= variable.EnumStrings!.Value.Count || number < 0)
|
|
{
|
|
return StatusCodes.BadOutOfRange;
|
|
}
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
private ServiceResult OnWriteValueDiscrete(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
NumericRange indexRange,
|
|
QualifiedName dataEncoding,
|
|
ref Variant value,
|
|
ref StatusCode statusCode,
|
|
ref DateTimeUtc timestamp)
|
|
{
|
|
TypeInfo typeInfo = value.TypeInfo;
|
|
|
|
if (node is not MultiStateValueDiscreteState variable ||
|
|
typeInfo.IsUnknown ||
|
|
!TypeInfo.IsNumericType(typeInfo.BuiltInType))
|
|
{
|
|
return StatusCodes.BadTypeMismatch;
|
|
}
|
|
|
|
if (!indexRange.IsNull)
|
|
{
|
|
return StatusCodes.BadIndexRangeInvalid;
|
|
}
|
|
|
|
int number = (int)value.GetUInt32();
|
|
if (number >= variable.EnumValues!.Value.Count || number < 0)
|
|
{
|
|
return StatusCodes.BadOutOfRange;
|
|
}
|
|
|
|
if (!node.SetChildValue(
|
|
context,
|
|
BrowseNames.ValueAsText,
|
|
variable.EnumValues.Value[number].DisplayName,
|
|
true
|
|
))
|
|
{
|
|
return StatusCodes.BadOutOfRange;
|
|
}
|
|
|
|
node.ClearChangeMasks(context, true);
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
private ServiceResult OnWriteAnalog(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
NumericRange indexRange,
|
|
QualifiedName dataEncoding,
|
|
ref Variant value,
|
|
ref StatusCode statusCode,
|
|
ref DateTimeUtc timestamp)
|
|
{
|
|
var variable = node as AnalogItemState;
|
|
|
|
// verify data type.
|
|
var typeInfo = TypeInfo.IsInstanceOfDataType(
|
|
value,
|
|
variable!.DataType,
|
|
variable.ValueRank,
|
|
context.NamespaceUris,
|
|
context.TypeTable);
|
|
|
|
if (typeInfo.IsUnknown)
|
|
{
|
|
return StatusCodes.BadTypeMismatch;
|
|
}
|
|
|
|
// check index range.
|
|
if (variable.ValueRank >= 0)
|
|
{
|
|
if (!indexRange.IsNull)
|
|
{
|
|
Variant target = variable.Value;
|
|
ServiceResult result = indexRange.UpdateRange(ref target, value);
|
|
|
|
if (ServiceResult.IsBad(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
value = target;
|
|
}
|
|
}
|
|
// check instrument range.
|
|
else
|
|
{
|
|
if (!indexRange.IsNull)
|
|
{
|
|
return StatusCodes.BadIndexRangeInvalid;
|
|
}
|
|
|
|
double number = value.GetDouble();
|
|
|
|
if (variable.InstrumentRange != null &&
|
|
(number < variable.InstrumentRange.Value.Low ||
|
|
number > variable.InstrumentRange.Value.High))
|
|
{
|
|
return StatusCodes.BadOutOfRange;
|
|
}
|
|
}
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
private ServiceResult OnWriteAnalogRange(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
NumericRange indexRange,
|
|
QualifiedName dataEncoding,
|
|
ref Variant value,
|
|
ref StatusCode statusCode,
|
|
ref DateTimeUtc timestamp)
|
|
{
|
|
TypeInfo typeInfo = value.TypeInfo;
|
|
|
|
if (node is not PropertyState<Range> variable ||
|
|
!value.TryGetValue(out ExtensionObject extensionObject) ||
|
|
typeInfo.IsUnknown)
|
|
{
|
|
return StatusCodes.BadTypeMismatch;
|
|
}
|
|
if (!extensionObject.TryGetValue(out Range? newRange) ||
|
|
variable.Parent is not AnalogItemState parent)
|
|
{
|
|
return StatusCodes.BadTypeMismatch;
|
|
}
|
|
|
|
if (!indexRange.IsNull)
|
|
{
|
|
return StatusCodes.BadIndexRangeInvalid;
|
|
}
|
|
|
|
TypeInfo parentTypeInfo = parent.Value.TypeInfo;
|
|
Range parentRange = GetAnalogRange(parentTypeInfo.BuiltInType);
|
|
if (parentRange.High < newRange.High || parentRange.Low > newRange.Low)
|
|
{
|
|
return StatusCodes.BadOutOfRange;
|
|
}
|
|
|
|
value = Variant.FromStructure(newRange);
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fires a base event whenever the trigger node is written to.
|
|
/// </summary>
|
|
private ServiceResult OnWriteTriggerNode(
|
|
ISystemContext context,
|
|
NodeState node,
|
|
ref Variant value)
|
|
{
|
|
var e = new BaseEventState(null);
|
|
e.Initialize(
|
|
context,
|
|
node,
|
|
EventSeverity.Medium,
|
|
new LocalizedText($"Trigger event from '{node.DisplayName.Text}'"));
|
|
Server.ReportEvent(context, e);
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a default <see cref="AxisInformation"/> instance with the given title.
|
|
/// </summary>
|
|
private static AxisInformation CreateDefaultAxisInformation(string title)
|
|
{
|
|
return new()
|
|
{
|
|
EngineeringUnits = new EUInformation("s", "seconds", "http://www.opcfoundation.org/UA/units/un/cefact"),
|
|
EURange = new Range(100, 0),
|
|
Title = new LocalizedText("en", title),
|
|
AxisScaleType = AxisScaleEnumeration.Linear
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies common read/write access settings to a mandatory child property of an array item variable.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
private static void SetArrayItemChildAccess<T>(PropertyState<T> property)
|
|
{
|
|
if (property != null)
|
|
{
|
|
property.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
property.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and adds a <see cref="YArrayItemState"/> variable to the address space.
|
|
/// </summary>
|
|
private YArrayItemState CreateYArrayItemVariable(NodeState parent, string path, string name)
|
|
{
|
|
var variable = new YArrayItemState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex)
|
|
};
|
|
variable.Create(
|
|
SystemContext,
|
|
new NodeId(path, NamespaceIndex),
|
|
variable.BrowseName,
|
|
default,
|
|
true);
|
|
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.SymbolicName = name;
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = DataTypeIds.Double;
|
|
variable.ValueRank = ValueRanks.OneDimension;
|
|
variable.ArrayDimensions = [0];
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = Variant.From(s_doubleArray);
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
if (variable.XAxisDefinition != null)
|
|
{
|
|
variable.XAxisDefinition.Value = CreateDefaultAxisInformation("X Axis");
|
|
SetArrayItemChildAccess(variable.XAxisDefinition);
|
|
}
|
|
if (variable.EURange != null)
|
|
{
|
|
variable.EURange.Value = new Range(100, 0);
|
|
SetArrayItemChildAccess(variable.EURange);
|
|
}
|
|
if (variable.InstrumentRange != null)
|
|
{
|
|
variable.InstrumentRange.Value = new Range(120, -10);
|
|
SetArrayItemChildAccess(variable.InstrumentRange);
|
|
}
|
|
|
|
parent?.AddChild(variable);
|
|
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and adds a <see cref="XYArrayItemState"/> variable to the address space.
|
|
/// </summary>
|
|
private XYArrayItemState CreateXYArrayItemVariable(NodeState parent, string path, string name)
|
|
{
|
|
var variable = new XYArrayItemState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex)
|
|
};
|
|
variable.Create(
|
|
SystemContext,
|
|
new NodeId(path, NamespaceIndex),
|
|
variable.BrowseName,
|
|
default,
|
|
true);
|
|
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.SymbolicName = name;
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = new NodeId(DataTypes.XVType);
|
|
variable.ValueRank = ValueRanks.OneDimension;
|
|
variable.ArrayDimensions = [0];
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = Variant.FromStructure(ArrayOf.Wrapped(
|
|
new XVType { X = 0.0, Value = 0.0f },
|
|
new XVType { X = 1.0, Value = 1.0f },
|
|
new XVType { X = 2.0, Value = 4.0f },
|
|
new XVType { X = 3.0, Value = 9.0f },
|
|
new XVType { X = 4.0, Value = 16.0f }
|
|
));
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
if (variable.XAxisDefinition != null)
|
|
{
|
|
variable.XAxisDefinition.Value = CreateDefaultAxisInformation("X Axis");
|
|
SetArrayItemChildAccess(variable.XAxisDefinition);
|
|
}
|
|
if (variable.EURange != null)
|
|
{
|
|
variable.EURange.Value = new Range(100, 0);
|
|
SetArrayItemChildAccess(variable.EURange);
|
|
}
|
|
if (variable.InstrumentRange != null)
|
|
{
|
|
variable.InstrumentRange.Value = new Range(120, -10);
|
|
SetArrayItemChildAccess(variable.InstrumentRange);
|
|
}
|
|
|
|
parent?.AddChild(variable);
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and adds an <see cref="ImageItemState"/> variable to the address space.
|
|
/// </summary>
|
|
private ImageItemState CreateImageItemVariable(NodeState parent, string path, string name)
|
|
{
|
|
var variable = new ImageItemState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex)
|
|
};
|
|
variable.Create(
|
|
SystemContext,
|
|
new NodeId(path, NamespaceIndex),
|
|
variable.BrowseName,
|
|
default,
|
|
true);
|
|
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.SymbolicName = name;
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = DataTypeIds.Double;
|
|
variable.ValueRank = ValueRanks.TwoDimensions;
|
|
variable.ArrayDimensions = [0, 0];
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = Variant.From(
|
|
MatrixOf<double>.CreateFromArray(new double[,]
|
|
{
|
|
{ 0.0, 1.0, 2.0 },
|
|
{ 3.0, 4.0, 5.0 }
|
|
}));
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
if (variable.XAxisDefinition != null)
|
|
{
|
|
variable.XAxisDefinition.Value = CreateDefaultAxisInformation("X Axis");
|
|
SetArrayItemChildAccess(variable.XAxisDefinition);
|
|
}
|
|
if (variable.YAxisDefinition != null)
|
|
{
|
|
variable.YAxisDefinition.Value = CreateDefaultAxisInformation("Y Axis");
|
|
SetArrayItemChildAccess(variable.YAxisDefinition);
|
|
}
|
|
if (variable.EURange != null)
|
|
{
|
|
variable.EURange.Value = new Range(100, 0);
|
|
SetArrayItemChildAccess(variable.EURange);
|
|
}
|
|
if (variable.InstrumentRange != null)
|
|
{
|
|
variable.InstrumentRange.Value = new Range(120, -10);
|
|
SetArrayItemChildAccess(variable.InstrumentRange);
|
|
}
|
|
|
|
parent?.AddChild(variable);
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and adds a <see cref="CubeItemState"/> variable to the address space.
|
|
/// </summary>
|
|
private CubeItemState CreateCubeItemVariable(NodeState parent, string path, string name)
|
|
{
|
|
var variable = new CubeItemState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex)
|
|
};
|
|
variable.Create(
|
|
SystemContext,
|
|
new NodeId(path, NamespaceIndex),
|
|
variable.BrowseName,
|
|
default,
|
|
true);
|
|
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.SymbolicName = name;
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = DataTypeIds.Double;
|
|
variable.ValueRank = 3;
|
|
variable.ArrayDimensions = [0, 0, 0];
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = Variant.From(
|
|
MatrixOf<double>.CreateFromArray(new double[,,]
|
|
{
|
|
{ { 0.0, 1.0 }, { 2.0, 3.0 } },
|
|
{ { 4.0, 5.0 }, { 6.0, 7.0 } }
|
|
}));
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
if (variable.XAxisDefinition != null)
|
|
{
|
|
variable.XAxisDefinition.Value = CreateDefaultAxisInformation("X Axis");
|
|
SetArrayItemChildAccess(variable.XAxisDefinition);
|
|
}
|
|
if (variable.YAxisDefinition != null)
|
|
{
|
|
variable.YAxisDefinition.Value = CreateDefaultAxisInformation("Y Axis");
|
|
SetArrayItemChildAccess(variable.YAxisDefinition);
|
|
}
|
|
if (variable.ZAxisDefinition != null)
|
|
{
|
|
variable.ZAxisDefinition.Value = CreateDefaultAxisInformation("Z Axis");
|
|
SetArrayItemChildAccess(variable.ZAxisDefinition);
|
|
}
|
|
if (variable.EURange != null)
|
|
{
|
|
variable.EURange.Value = new Range(100, 0);
|
|
SetArrayItemChildAccess(variable.EURange);
|
|
}
|
|
if (variable.InstrumentRange != null)
|
|
{
|
|
variable.InstrumentRange.Value = new Range(120, -10);
|
|
SetArrayItemChildAccess(variable.InstrumentRange);
|
|
}
|
|
|
|
parent?.AddChild(variable);
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and adds an <see cref="NDimensionArrayItemState"/> variable to the address space.
|
|
/// </summary>
|
|
private NDimensionArrayItemState CreateNDimensionArrayItemVariable(NodeState parent, string path, string name)
|
|
{
|
|
var variable = new NDimensionArrayItemState(parent)
|
|
{
|
|
BrowseName = new QualifiedName(path, NamespaceIndex)
|
|
};
|
|
variable.Create(
|
|
SystemContext,
|
|
new NodeId(path, NamespaceIndex),
|
|
variable.BrowseName,
|
|
default,
|
|
true);
|
|
|
|
variable.NodeId = new NodeId(path, NamespaceIndex);
|
|
variable.SymbolicName = name;
|
|
variable.DisplayName = new LocalizedText("en", name);
|
|
variable.WriteMask = AttributeWriteMask.None;
|
|
variable.UserWriteMask = AttributeWriteMask.None;
|
|
variable.ReferenceTypeId = ReferenceTypeIds.Organizes;
|
|
variable.DataType = DataTypeIds.Double;
|
|
variable.ValueRank = ValueRanks.TwoDimensions;
|
|
variable.ArrayDimensions = [0, 0];
|
|
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
|
|
variable.Historizing = false;
|
|
variable.Value = Variant.From(
|
|
MatrixOf<double>.CreateFromArray(new double[,]
|
|
{
|
|
{ 0.0, 1.0, 2.0 },
|
|
{ 3.0, 4.0, 5.0 }
|
|
}));
|
|
variable.StatusCode = StatusCodes.Good;
|
|
|
|
if (variable.AxisDefinition != null)
|
|
{
|
|
variable.AxisDefinition.Value = new AxisInformation[]
|
|
{
|
|
CreateDefaultAxisInformation("X Axis"),
|
|
CreateDefaultAxisInformation("Y Axis")
|
|
}.ToArrayOf();
|
|
SetArrayItemChildAccess(variable.AxisDefinition);
|
|
}
|
|
if (variable.EURange != null)
|
|
{
|
|
variable.EURange.Value = new Range(100, 0);
|
|
SetArrayItemChildAccess(variable.EURange);
|
|
}
|
|
if (variable.InstrumentRange != null)
|
|
{
|
|
variable.InstrumentRange.Value = new Range(120, -10);
|
|
SetArrayItemChildAccess(variable.InstrumentRange);
|
|
}
|
|
|
|
parent?.AddChild(variable);
|
|
return variable;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private BaseDataVariableState CreateVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank)
|
|
{
|
|
return CreateVariable(parent, path, name, (NodeId)(uint)dataType, valueRank);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private BaseDataVariableState CreateVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
NodeId dataType,
|
|
int valueRank)
|
|
{
|
|
var variable = new BaseDataVariableState(parent)
|
|
{
|
|
SymbolicName = name,
|
|
ReferenceTypeId = ReferenceTypeIds.Organizes,
|
|
TypeDefinitionId = VariableTypeIds.BaseDataVariableType,
|
|
NodeId = new NodeId(path, NamespaceIndex),
|
|
BrowseName = new QualifiedName(path, NamespaceIndex),
|
|
DisplayName = new LocalizedText("en", name),
|
|
WriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description,
|
|
UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description,
|
|
DataType = dataType,
|
|
ValueRank = valueRank,
|
|
AccessLevel = AccessLevels.CurrentReadOrWrite,
|
|
UserAccessLevel = AccessLevels.CurrentReadOrWrite,
|
|
Historizing = false
|
|
};
|
|
|
|
variable.Value = GetNewValue(variable);
|
|
variable.StatusCode = StatusCodes.Good;
|
|
variable.Description = LocalizedText.From("Default Description");
|
|
|
|
if (valueRank == ValueRanks.OneDimension)
|
|
{
|
|
variable.ArrayDimensions = [0];
|
|
}
|
|
else if (valueRank == ValueRanks.TwoDimensions)
|
|
{
|
|
variable.ArrayDimensions = [0, 0];
|
|
}
|
|
|
|
parent?.AddChild(variable);
|
|
return variable;
|
|
}
|
|
|
|
private BaseDataVariableState[] CreateVariables(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank,
|
|
ushort numVariables)
|
|
{
|
|
return CreateVariables(parent, path, name, (NodeId)(uint)dataType, valueRank, numVariables);
|
|
}
|
|
|
|
private BaseDataVariableState[] CreateVariables(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
NodeId dataType,
|
|
int valueRank,
|
|
ushort numVariables)
|
|
{
|
|
// first, create a new Parent folder for this data-type
|
|
FolderState newParentFolder = CreateFolder(parent, path, name);
|
|
|
|
var itemsCreated = new List<BaseDataVariableState>();
|
|
// now to create the remaining NUMBERED items
|
|
for (uint i = 0; i < numVariables; i++)
|
|
{
|
|
string newName = string.Format(
|
|
CultureInfo.InvariantCulture,
|
|
"{0}_{1}",
|
|
name,
|
|
i.ToString("00", CultureInfo.InvariantCulture));
|
|
string newPath = string.Format(
|
|
CultureInfo.InvariantCulture,
|
|
"{0}_{1}",
|
|
path,
|
|
newName);
|
|
itemsCreated.Add(
|
|
CreateVariable(newParentFolder, newPath, newName, dataType, valueRank));
|
|
}
|
|
return [.. itemsCreated];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private BaseDataVariableState CreateDynamicVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank)
|
|
{
|
|
return CreateDynamicVariable(parent, path, name, (NodeId)(uint)dataType, valueRank);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new variable.
|
|
/// </summary>
|
|
private BaseDataVariableState CreateDynamicVariable(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
NodeId dataType,
|
|
int valueRank)
|
|
{
|
|
BaseDataVariableState variable = CreateVariable(
|
|
parent,
|
|
path,
|
|
name,
|
|
dataType,
|
|
valueRank);
|
|
m_dynamicNodes.Add(variable);
|
|
return variable;
|
|
}
|
|
|
|
private BaseDataVariableState[] CreateDynamicVariables(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
BuiltInType dataType,
|
|
int valueRank,
|
|
uint numVariables)
|
|
{
|
|
return CreateDynamicVariables(
|
|
parent,
|
|
path,
|
|
name,
|
|
(NodeId)(uint)dataType,
|
|
valueRank,
|
|
numVariables);
|
|
}
|
|
|
|
private BaseDataVariableState[] CreateDynamicVariables(
|
|
NodeState parent,
|
|
string path,
|
|
string name,
|
|
NodeId dataType,
|
|
int valueRank,
|
|
uint numVariables)
|
|
{
|
|
// first, create a new Parent folder for this data-type
|
|
FolderState newParentFolder = CreateFolder(parent, path, name);
|
|
|
|
var itemsCreated = new List<BaseDataVariableState>();
|
|
// now to create the remaining NUMBERED items
|
|
for (uint i = 0; i < numVariables; i++)
|
|
{
|
|
string newName = string.Format(
|
|
CultureInfo.InvariantCulture,
|
|
"{0}_{1}",
|
|
name,
|
|
i.ToString("00", CultureInfo.InvariantCulture));
|
|
string newPath = string.Format(
|
|
CultureInfo.InvariantCulture,
|
|
"{0}_{1}",
|
|
path,
|
|
newName);
|
|
itemsCreated.Add(
|
|
CreateDynamicVariable(newParentFolder, newPath, newName, dataType, valueRank));
|
|
} //for i
|
|
return [.. itemsCreated];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new view.
|
|
/// </summary>
|
|
private async ValueTask<ViewState> CreateViewAsync(
|
|
NodeState parent,
|
|
IDictionary<NodeId, IList<IReference>> externalReferences,
|
|
string path,
|
|
string name,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var type = new ViewState
|
|
{
|
|
SymbolicName = name,
|
|
NodeId = new NodeId(path, NamespaceIndex),
|
|
BrowseName = new QualifiedName(name, NamespaceIndex)
|
|
};
|
|
type.DisplayName = LocalizedText.From(type.BrowseName.Name!);
|
|
type.WriteMask = AttributeWriteMask.None;
|
|
type.UserWriteMask = AttributeWriteMask.None;
|
|
type.ContainsNoLoops = true;
|
|
|
|
if (!externalReferences.TryGetValue(
|
|
ObjectIds.ViewsFolder,
|
|
out IList<IReference>? references))
|
|
{
|
|
externalReferences[ObjectIds.ViewsFolder] = references = [];
|
|
}
|
|
|
|
type.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ViewsFolder);
|
|
references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, type.NodeId));
|
|
|
|
if (parent != null)
|
|
{
|
|
parent.AddReference(ReferenceTypeIds.Organizes, false, type.NodeId);
|
|
type.AddReference(ReferenceTypeIds.Organizes, true, parent.NodeId);
|
|
}
|
|
|
|
await AddPredefinedNodeAsync(SystemContext, type, cancellationToken).ConfigureAwait(false);
|
|
return type;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new method.
|
|
/// </summary>
|
|
private MethodState CreateMethod(FolderState parent, string path, string name)
|
|
{
|
|
var method = new MethodState(parent)
|
|
{
|
|
SymbolicName = name,
|
|
ReferenceTypeId = ReferenceTypeIds.HasComponent,
|
|
NodeId = new NodeId(path, NamespaceIndex),
|
|
BrowseName = new QualifiedName(path, NamespaceIndex),
|
|
DisplayName = new LocalizedText("en", name),
|
|
WriteMask = AttributeWriteMask.None,
|
|
UserWriteMask = AttributeWriteMask.None,
|
|
Executable = true,
|
|
UserExecutable = true
|
|
};
|
|
|
|
parent?.AddChild(method);
|
|
return method;
|
|
}
|
|
|
|
private ServiceResult OnVoidCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
private ServiceResult OnAddCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
if (inputArguments.Count < 2)
|
|
{
|
|
return StatusCodes.BadArgumentsMissing;
|
|
}
|
|
|
|
try
|
|
{
|
|
float floatValue = (float)inputArguments[0];
|
|
uint uintValue = (uint)inputArguments[1];
|
|
|
|
// set output parameter
|
|
outputArguments[0] = floatValue + uintValue;
|
|
return ServiceResult.Good;
|
|
}
|
|
catch
|
|
{
|
|
return new ServiceResult(StatusCodes.BadInvalidArgument);
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnMultiplyCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
if (inputArguments.Count < 2)
|
|
{
|
|
return StatusCodes.BadArgumentsMissing;
|
|
}
|
|
|
|
try
|
|
{
|
|
short op1 = (short)inputArguments[0];
|
|
ushort op2 = (ushort)inputArguments[1];
|
|
|
|
// set output parameter
|
|
outputArguments[0] = op1 * op2;
|
|
return ServiceResult.Good;
|
|
}
|
|
catch
|
|
{
|
|
return new ServiceResult(StatusCodes.BadInvalidArgument);
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnDivideCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
if (inputArguments.Count < 2)
|
|
{
|
|
return StatusCodes.BadArgumentsMissing;
|
|
}
|
|
|
|
try
|
|
{
|
|
int op1 = (int)inputArguments[0];
|
|
ushort op2 = (ushort)inputArguments[1];
|
|
|
|
// set output parameter
|
|
outputArguments[0] = op1 / (float)op2;
|
|
return ServiceResult.Good;
|
|
}
|
|
catch
|
|
{
|
|
return new ServiceResult(StatusCodes.BadInvalidArgument);
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnSubstractCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
if (inputArguments.Count < 2)
|
|
{
|
|
return StatusCodes.BadArgumentsMissing;
|
|
}
|
|
|
|
try
|
|
{
|
|
short op1 = (short)inputArguments[0];
|
|
byte op2 = (byte)inputArguments[1];
|
|
|
|
// set output parameter
|
|
outputArguments[0] = (short)(op1 - op2);
|
|
return ServiceResult.Good;
|
|
}
|
|
catch
|
|
{
|
|
return new ServiceResult(StatusCodes.BadInvalidArgument);
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnHelloCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
if (inputArguments.Count < 1)
|
|
{
|
|
return StatusCodes.BadArgumentsMissing;
|
|
}
|
|
|
|
try
|
|
{
|
|
string op1 = (string)inputArguments[0];
|
|
|
|
// set output parameter
|
|
outputArguments[0] = "hello " + op1;
|
|
return ServiceResult.Good;
|
|
}
|
|
catch
|
|
{
|
|
return new ServiceResult(StatusCodes.BadInvalidArgument);
|
|
}
|
|
}
|
|
|
|
private ServiceResult OnInputCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
if (inputArguments.Count < 1)
|
|
{
|
|
return StatusCodes.BadArgumentsMissing;
|
|
}
|
|
|
|
return ServiceResult.Good;
|
|
}
|
|
|
|
private ServiceResult OnOutputCall(
|
|
ISystemContext context,
|
|
MethodState method,
|
|
ArrayOf<Variant> inputArguments,
|
|
List<Variant> outputArguments)
|
|
{
|
|
// all arguments must be provided.
|
|
try
|
|
{
|
|
// set output parameter
|
|
outputArguments[0] = "Output";
|
|
return ServiceResult.Good;
|
|
}
|
|
catch
|
|
{
|
|
return new ServiceResult(StatusCodes.BadInvalidArgument);
|
|
}
|
|
}
|
|
|
|
private void ResetRandomGenerator(int seed, int boundaryValueFrequency = 0)
|
|
{
|
|
m_randomSource = new RandomSource(seed);
|
|
m_generator = new DataGenerator(m_randomSource, Server.Telemetry)
|
|
{
|
|
BoundaryValueFrequency = boundaryValueFrequency
|
|
};
|
|
}
|
|
|
|
private Variant GetNewValue(BaseVariableState variable)
|
|
{
|
|
Debug.Assert(m_generator != null, "Need a random generator!");
|
|
|
|
Variant value = default;
|
|
for (int retryCount = 0; value.IsNull && retryCount < 10; retryCount++)
|
|
{
|
|
value = m_generator!.GetRandom(
|
|
variable.DataType,
|
|
variable.ValueRank,
|
|
[10],
|
|
Server.TypeTree);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private void DoSimulation(object? state)
|
|
{
|
|
if (!m_simulationEnabled)
|
|
{
|
|
return;
|
|
}
|
|
int running = Interlocked.Increment(ref m_simulationsRunning);
|
|
try
|
|
{
|
|
if (running > 0)
|
|
{
|
|
LogLevel logLevel = running > 1 ?
|
|
running > 4 ? LogLevel.Warning : LogLevel.Information :
|
|
LogLevel.Debug;
|
|
m_logger.Log(logLevel,
|
|
"Simulation timer fired while {Count} simulations are already queued to run.",
|
|
running);
|
|
}
|
|
m_semaphore.Wait();
|
|
try
|
|
{
|
|
DateTimeUtc timeStamp = DateTimeUtc.Now;
|
|
foreach (BaseDataVariableState variable in m_dynamicNodes)
|
|
{
|
|
variable.Value = GetNewValue(variable);
|
|
variable.Timestamp = timeStamp;
|
|
variable.ClearChangeMasks(SystemContext, false);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
m_semaphore.Release();
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_logger.LogError(e, "Unexpected error doing simulation #{Count}.", running);
|
|
}
|
|
finally
|
|
{
|
|
Interlocked.Decrement(ref m_simulationsRunning);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Frees any resources allocated for the address space.
|
|
/// </summary>
|
|
public override ValueTask DeleteAddressSpaceAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
// TBD
|
|
return new ValueTask();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a unique handle for the node.
|
|
/// </summary>
|
|
protected override ValueTask<NodeHandle> GetManagerHandleAsync(
|
|
ServerSystemContext context,
|
|
NodeId nodeId,
|
|
IDictionary<NodeId, NodeState> cache,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
// quickly exclude nodes that are not in the namespace.
|
|
if (!IsNodeIdInNamespace(nodeId))
|
|
{
|
|
return default;
|
|
}
|
|
|
|
if (!PredefinedNodes.TryGetValue(nodeId, out NodeState? node))
|
|
{
|
|
return default;
|
|
}
|
|
|
|
return new ValueTask<NodeHandle>(new NodeHandle
|
|
{
|
|
NodeId = nodeId,
|
|
Node = node,
|
|
Validated = true
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that the specified node exists.
|
|
/// </summary>
|
|
protected override ValueTask<NodeState> ValidateNodeAsync(
|
|
ServerSystemContext context,
|
|
NodeHandle handle,
|
|
IDictionary<NodeId, NodeState> cache,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
// not valid if no root.
|
|
if (handle == null)
|
|
{
|
|
return default;
|
|
}
|
|
|
|
// check if previously validated.
|
|
if (handle.Validated)
|
|
{
|
|
return new ValueTask<NodeState>(handle.Node);
|
|
}
|
|
|
|
// TBD
|
|
|
|
return default;
|
|
}
|
|
|
|
private readonly SemaphoreSlim m_semaphore = new(1, 1);
|
|
private RandomSource m_randomSource = null!;
|
|
private DataGenerator m_generator = null!;
|
|
private ITimer? m_simulationTimer;
|
|
private ushort m_simulationInterval = 1000;
|
|
private bool m_simulationEnabled = true;
|
|
private int m_simulationsRunning;
|
|
private readonly List<BaseDataVariableState> m_dynamicNodes = [];
|
|
|
|
private InMemoryHistorianProvider? m_historian;
|
|
|
|
/// <summary>
|
|
/// Identifiers of the nodes that support history archiving.
|
|
/// </summary>
|
|
private static readonly string[] HistoricalNodeNames =
|
|
[
|
|
"Scalar_Static_Double",
|
|
"Scalar_Static_Int32",
|
|
"Scalar_Static_Float"
|
|
];
|
|
|
|
/// <inheritdoc/>
|
|
protected override IHistorianProvider? GetHistorianProvider(NodeState node)
|
|
{
|
|
return m_historian;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables history archiving on selected scalar variables using
|
|
/// the fluent <see cref="HistorianBuilder"/> API.
|
|
/// </summary>
|
|
private async Task EnableHistoryArchivingAsync(CancellationToken cancellationToken)
|
|
{
|
|
m_historian = new InMemoryHistorianProvider();
|
|
|
|
// Make the provider discoverable to the server-wide registry so
|
|
// server capabilities (HistoryServerCapabilities) reflect what the
|
|
// provider supports. The dispatcher will still prefer the
|
|
// per-node-manager override returned by GetHistorianProvider.
|
|
if (Server is IHistorianRegistryProvider registry)
|
|
{
|
|
registry.HistorianRegistry.RegisterDefault(m_historian);
|
|
}
|
|
|
|
foreach (string name in HistoricalNodeNames)
|
|
{
|
|
var nodeId = new NodeId(name, NamespaceIndex);
|
|
|
|
if (!PredefinedNodes.TryGetValue(nodeId, out NodeState? node))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (node is not BaseVariableState variable)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
variable.Historizing = true;
|
|
variable.AccessLevel = (byte)(variable.AccessLevel | AccessLevels.HistoryRead | AccessLevels.HistoryWrite);
|
|
variable.UserAccessLevel = (byte)(variable.UserAccessLevel | AccessLevels.HistoryRead | AccessLevels.HistoryWrite);
|
|
|
|
m_historian.Register(nodeId);
|
|
await SeedHistoricalNodeAsync(nodeId, TypeInfo.GetBuiltInType(variable.DataType), cancellationToken).ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
private async Task SeedHistoricalNodeAsync(NodeId nodeId, BuiltInType dataType, CancellationToken cancellationToken)
|
|
{
|
|
DateTime now = DateTime.UtcNow;
|
|
var seed = new List<DataValue>(1001);
|
|
for (int ii = 1000; ii >= 0; ii--)
|
|
{
|
|
int value = 1000 - ii;
|
|
Variant variant = dataType switch
|
|
{
|
|
BuiltInType.Int32 => new Variant(value),
|
|
BuiltInType.Float => new Variant((float)value),
|
|
BuiltInType.Double => new Variant((double)value),
|
|
_ => new Variant(value)
|
|
};
|
|
seed.Add(new DataValue(
|
|
variant,
|
|
StatusCodes.Good,
|
|
sourceTimestamp: now.AddSeconds(-(ii * 10)).AddMilliseconds(1234),
|
|
serverTimestamp: now.AddSeconds(-(ii * 10))));
|
|
}
|
|
var opContext = new OperationContext(new RequestHeader(), null, RequestType.HistoryUpdate, RequestLifetime.None);
|
|
var systemContext = new ServerSystemContext(Server, opContext);
|
|
var historianContext = new HistorianOperationContext(systemContext, opContext, null, HistoryUpdateType.Insert);
|
|
_ = await m_historian!.InsertAsync(historianContext, nodeId, seed, cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
private static readonly ArrayOf<double> s_doubleArray =
|
|
[
|
|
9.00001d,
|
|
9.0002d,
|
|
9.003d,
|
|
9.04d,
|
|
9.5d,
|
|
9.06d,
|
|
9.007d,
|
|
9.008d,
|
|
9.0009d
|
|
];
|
|
|
|
private static readonly ArrayOf<float> s_singleArray
|
|
= [0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 1.1f, 2.2f, 3.3f, 4.4f, 5.5f];
|
|
|
|
private static readonly ArrayOf<short> s_shortArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
private static readonly ArrayOf<int> s_int32Array = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
|
|
|
|
private static readonly ArrayOf<string> s_stringArray1 = ["open", "closed", "jammed"];
|
|
private static readonly ArrayOf<string> s_stringArray2 = ["red", "green", "blue", "cyan"];
|
|
private static readonly ArrayOf<string> s_stringArray3 = ["lolo", "lo", "normal", "hi", "hihi"];
|
|
private static readonly ArrayOf<string> s_stringArray4 = ["left", "right", "center"];
|
|
private static readonly ArrayOf<string> s_stringArray5 = ["circle", "cross", "triangle"];
|
|
private static readonly ArrayOf<string> s_stringArray6 = ["open", "closed", "jammed"];
|
|
private static readonly ArrayOf<string> s_stringArray7 = ["red", "green", "blue", "cyan"];
|
|
private static readonly ArrayOf<string> s_stringArray8 = ["lolo", "lo", "normal", "hi", "hihi"];
|
|
private static readonly ArrayOf<string> s_stringArray9 = ["left", "right", "center"];
|
|
}
|
|
|
|
public static class VariableExtensions
|
|
{
|
|
public static BaseDataVariableState MinimumSamplingInterval(
|
|
this BaseDataVariableState variable,
|
|
int minimumSamplingInterval)
|
|
{
|
|
variable.MinimumSamplingInterval = minimumSamplingInterval;
|
|
return variable;
|
|
}
|
|
}
|
|
}
|