Skip to content

Commit

Permalink
Merge pull request #3 from wetcon/bugfix/multiple-dtms
Browse files Browse the repository at this point in the history
Fix for projecting same Com DTM multiple times
  • Loading branch information
jjell authored Sep 26, 2019
2 parents 47aeb8c + aa3434d commit 02efe8d
Show file tree
Hide file tree
Showing 17 changed files with 314 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,26 +71,22 @@ public abstract class BaseDeviceModel : DeviceState
/// <summary>
/// Initializes a new instance of <see cref="BaseDeviceModel"/>.
/// </summary>
/// <param name="serverNamespaceIndex"></param>
/// <param name="pactwareProjectNode"></param>
/// <param name="fdtService"></param>
/// <param name="parent"></param>
/// <param name="deviceModelContext"></param>
/// <param name="readIOProcessData"></param>
protected BaseDeviceModel(ushort serverNamespaceIndex, IPACTwareProjectNode pactwareProjectNode,
IFdtServiceProvider fdtService, NodeState parent, bool readIOProcessData)
: base(parent)
protected BaseDeviceModel(DeviceModelContext deviceModelContext, bool readIOProcessData)
: base(deviceModelContext.Parent)
{
PactwareProjectNode = pactwareProjectNode;
FdtService = fdtService;
PactwareProjectNode = deviceModelContext.PactwareProjectNode;
FdtService = deviceModelContext.FdtServiceProvider;
DeviceId = PactwareProjectNode.CatalogueObject.Id;

NodeId = new NodeId($"{parent.NodeId.Identifier}.Device.{DeviceId}", 2);
NodeId = new NodeId($"{deviceModelContext.Parent.NodeId.Identifier}.Device.{DeviceId}", 2);

DeviceName = !string.IsNullOrWhiteSpace(PactwareProjectNode.Tagname) ?
PactwareProjectNode.Tagname : PactwareProjectNode.DeviceName;

ReadIOProcessData = readIOProcessData;
ServerNamespaceIndex = serverNamespaceIndex;
ServerNamespaceIndex = deviceModelContext.ServerNamespaceIndex;
ParameterSet = new ParameterSetModel(this);
WriteMask = AttributeWriteMask.None;
UserWriteMask = AttributeWriteMask.None;
Expand Down Expand Up @@ -120,7 +116,7 @@ private string GetDeviceClass()

if (!(PactwareProjectNode.CatalogueObject is IPACTwareCatalogueNodeInfo pactwareCatalogNodeInfo))
{
return deviceClass;
return null;
}

var classificationDomain = pactwareCatalogNodeInfo.ClassificationDomain;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* Copyright (c) 2019 wetcon gmbh. All rights reserved.
Wetcon provides this source code under a dual license model
designed to meet the development and distribution needs of both
commercial distributors (such as OEMs, ISVs and VARs) and open
source projects.
For open source projects the source code in this file is covered
under GPL V2.
See https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
OEMs (Original Equipment Manufacturers), ISVs (Independent Software
Vendors), VARs (Value Added Resellers) and other distributors that
combine and distribute commercially licensed software with this
source code and do not wish to distribute the source code for the
commercially licensed software under version 2 of the GNU General
Public License (the "GPL") must enter into a commercial license
agreement with wetcon.
This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

using System.Collections.Generic;
using Opc.Ua;
using PWID.Interfaces;
using Wetcon.PactwarePlugin.OpcUaServer.Fdt;

namespace Wetcon.PactwarePlugin.OpcUaServer.OpcUa.Models
{
/// <summary>
/// Represents the Offline Device model
/// </summary>
public struct DeviceModelContext
{
public DeviceModelContext(ushort serverNamespaceIndex, IPACTwareProjectNode projectNode,
IFdtServiceProvider fdtServiceProvider, NodeState parent, List<NodeId> existingNodeIds = null)
{
ServerNamespaceIndex = serverNamespaceIndex;
PactwareProjectNode = projectNode;
FdtServiceProvider = fdtServiceProvider;
Parent = parent;
ExistingNodeIds = existingNodeIds ?? new List<NodeId>();
}

public ushort ServerNamespaceIndex { get; private set; }
public IPACTwareProjectNode PactwareProjectNode { get; private set; }
public IFdtServiceProvider FdtServiceProvider { get; private set; }
public NodeState Parent { get; private set; }
public List<NodeId> ExistingNodeIds { get; private set; }

public DeviceModelContext WithNewParent(NodeState parent)
{
return new DeviceModelContext
{
ServerNamespaceIndex = ServerNamespaceIndex,
PactwareProjectNode = PactwareProjectNode,
FdtServiceProvider = FdtServiceProvider,
Parent = parent,
ExistingNodeIds = ExistingNodeIds
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
using Opc.Ua;
using Opc.Ua.Di;
using Opc.Ua.Server;
using PWID.Interfaces;
using Wetcon.PactwarePlugin.OpcUaServer.Fdt;

namespace Wetcon.PactwarePlugin.OpcUaServer.OpcUa.Models
Expand All @@ -36,8 +35,8 @@ namespace Wetcon.PactwarePlugin.OpcUaServer.OpcUa.Models
/// </summary>
public class OfflineDeviceModel : BaseDeviceModel
{
public OfflineDeviceModel(ushort serverNamespaceIndex, IPACTwareProjectNode pactwareProjectNode,
IFdtServiceProvider fdtServiceProvider, NodeState parent) : base(serverNamespaceIndex, pactwareProjectNode, fdtServiceProvider, parent, false)
public OfflineDeviceModel(DeviceModelContext deviceModelContext) :
base(deviceModelContext, false)
{
TransferService = new TransferServicesState(this);
}
Expand Down Expand Up @@ -150,34 +149,59 @@ private ServiceResult TransferToDevice(ISystemContext context, MethodState metho

private TransferServicesState m_transferService;

internal static List<NodeState> Add(IPACTwareProjectNode pactwareProjectNode,
IFdtServiceProvider fdtServiceProvider, NodeState parentNode, ServerSystemContext systemContext, ushort serverNamespaceIndex,
internal static List<NodeState> Add(DeviceModelContext deviceModelContext, ServerSystemContext systemContext,
bool readIOProcessData)
{
// Add the offline device node.
var offlineDeviceModel = new OfflineDeviceModel(serverNamespaceIndex, pactwareProjectNode,
fdtServiceProvider, parentNode);
var offlineDeviceModel = new OfflineDeviceModel(deviceModelContext);
var browseName = new QualifiedName(offlineDeviceModel.DeviceName + "." + offlineDeviceModel.DeviceId,
serverNamespaceIndex);
deviceModelContext.ServerNamespaceIndex);
var displayName = new LocalizedText(offlineDeviceModel.DeviceName);
var uniqueNodeId = MakeUniqueNodeId(offlineDeviceModel.NodeId, deviceModelContext.ExistingNodeIds);

parentNode.AddChild(offlineDeviceModel);
deviceModelContext.ExistingNodeIds.Add(uniqueNodeId);
deviceModelContext.Parent.AddChild(offlineDeviceModel);

offlineDeviceModel.Create(
systemContext,
offlineDeviceModel.NodeId,
uniqueNodeId,
browseName,
displayName,
true);

var onlineDeviceModel = OnlineDeviceModel.Add(pactwareProjectNode, fdtServiceProvider,
offlineDeviceModel, systemContext, serverNamespaceIndex, readIOProcessData);
var onlineDeviceModel = OnlineDeviceModel.Add(deviceModelContext.WithNewParent(offlineDeviceModel),
systemContext, readIOProcessData);

return new List<NodeState>()
{
offlineDeviceModel,
onlineDeviceModel
};
}

/// <summary>
/// Makes sure an OPC UA NodeId is unique, considering the existing node ids.
/// </summary>
/// <param name="nodeId"></param>
/// <param name="existingNodeIds"></param>
/// <returns></returns>
internal static NodeId MakeUniqueNodeId(NodeId nodeId, List<NodeId> existingNodeIds)
{
if (null == existingNodeIds || 0 == existingNodeIds.Count)
{
return nodeId;
}

var i = 0;
var result = new NodeId(nodeId);
var initialString = nodeId.Identifier.ToString();

while (existingNodeIds.Contains(result))
{
result = new NodeId($"{initialString}.{++i}", nodeId.NamespaceIndex);
}

return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

using Opc.Ua;
using Opc.Ua.Server;
using PWID.Interfaces;
using Wetcon.PactwarePlugin.OpcUaServer.Fdt;

namespace Wetcon.PactwarePlugin.OpcUaServer.OpcUa.Models
{
Expand All @@ -36,25 +34,22 @@ public class OnlineDeviceModel : BaseDeviceModel
{
protected override DeviceModelType DeviceModelType => DeviceModelType.Online;

public OnlineDeviceModel(ushort serverNamespaceIndex, IPACTwareProjectNode pactwareProjectNode,
IFdtServiceProvider fdtServiceProvider, NodeState parent, bool readIOProcessData)
: base(serverNamespaceIndex, pactwareProjectNode, fdtServiceProvider, parent, readIOProcessData)
public OnlineDeviceModel(DeviceModelContext deviceModelContext, bool readIOProcessData)
: base(deviceModelContext, readIOProcessData)
{
DisplayName = new LocalizedText("Online");
BrowseName = new QualifiedName(Opc.Ua.Di.BrowseNames.IsOnline, 1);
}

internal static BaseObjectState Add(IPACTwareProjectNode pactwareProjectNode,
IFdtServiceProvider fdtServiceProvider, OfflineDeviceModel parentNode, ServerSystemContext systemContext, ushort serverNamespaceIndex,
internal static BaseObjectState Add(DeviceModelContext deviceModelContext, ServerSystemContext systemContext,
bool readIOProcessData)
{
// Add the online device node.
var onlineDeviceModel = new OnlineDeviceModel(serverNamespaceIndex, pactwareProjectNode, fdtServiceProvider,
parentNode, readIOProcessData);
var onlineDeviceModel = new OnlineDeviceModel(deviceModelContext, readIOProcessData);
var displayName = new LocalizedText("Online");
var browseName = new QualifiedName(Opc.Ua.Di.BrowseNames.IsOnline, 1);

parentNode.AddChild(onlineDeviceModel);
deviceModelContext.Parent.AddChild(onlineDeviceModel);

onlineDeviceModel.Create(
systemContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ public async Task<bool> StartApplicationAsync()
}

// check the application certificate.
bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0);
if (!haveAppCertificate)
var hasAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0);
if (!hasAppCertificate)
{
throw new Exception("Application instance certificate invalid!");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ private void UpdateDeviceSet()

var devices = _pactwareUIKernel.GetDeviceProjectNodes();
var offlineDeviceNodes = FindChildNodes<BaseDeviceModel>(DeviceSetNode).ToArray();
var existingNodeIds = offlineDeviceNodes.Select(d => d.NodeId).ToList();

foreach (var device in devices)
{
Expand All @@ -284,7 +285,7 @@ private void UpdateDeviceSet()
}

// Add the offline and online device nodes to the DeviceSet.
AddDeviceToDeviceSet(device, DeviceSetNode);
AddDeviceToDeviceSet(device, DeviceSetNode, existingNodeIds);
}
}

Expand All @@ -308,12 +309,15 @@ private void UnloadDeviceSet()
}
}

private void AddDeviceToDeviceSet(IPACTwareProjectNode pactwareProjectNode, NodeState deviceSetNode)
private void AddDeviceToDeviceSet(IPACTwareProjectNode pactwareProjectNode, NodeState deviceSetNode,
List<NodeId> existingNodeIds)
{
var fdtServiceProvider = new FdtServiceProvider();
fdtServiceProvider.OnLoadProjectNode(pactwareProjectNode);
var nodeStates = OfflineDeviceModel.Add(pactwareProjectNode, fdtServiceProvider, deviceSetNode,
SystemContext, ServerNamespaceIndex, _pluginSettings.PluginReadIOProcessData);
var deviceModelContext = new DeviceModelContext(ServerNamespaceIndex, pactwareProjectNode,
fdtServiceProvider, deviceSetNode, existingNodeIds);
var nodeStates = OfflineDeviceModel.Add(deviceModelContext, SystemContext,
_pluginSettings.PluginReadIOProcessData);

foreach (var nodeState in nodeStates)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
Expand All @@ -38,3 +39,4 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("884780dc-0864-40ce-ad60-d7c2ee426da0")]
[assembly: InternalsVisibleTo("Wetcon.PactwarePlugin.OpcUaServer.Plugin.Tests")]
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@
<Compile Include="Fdt\Services\Base\BaseFdtService.cs" />
<Compile Include="Fdt\Services\Base\DtmInterface.cs" />
<Compile Include="Fdt\Services\Base\IBaseFdtService.cs" />
<Compile Include="Fdt\Services\Base\IProjectNodeDependent.cs" />
<Compile Include="Fdt\Services\Base\IProjectNodeEvents.cs" />
<Compile Include="Fdt\Services\Base\IFdtServiceProvider.cs" />
<Compile Include="Fdt\Services\FdtContainerService.cs" />
<Compile Include="Fdt\Services\DtmParameterService.cs" />
Expand Down Expand Up @@ -386,6 +386,7 @@
<Compile Include="OpcUa\Di\Opc.Ua.Di.Classes.cs" />
<Compile Include="OpcUa\Di\Opc.Ua.Di.Constants.cs" />
<Compile Include="OpcUa\Di\Opc.Ua.Di.DataTypes.cs" />
<Compile Include="OpcUa\Models\Device\DeviceModelContext.cs" />
<Compile Include="OpcUa\Models\Parameter\Base\BaseParameterModel.cs" />
<Compile Include="OpcUa\Models\Device\OnlineDeviceModel.cs" />
<Compile Include="OpcUa\Models\Device\OfflineDeviceModel.cs" />
Expand Down Expand Up @@ -463,11 +464,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="IODD\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>REM powershell -command "Start-Process $(ProjectDir)Wetcon.PactwarePlugin.OpcUaServer_x64.bat -Verb runas"</PostBuildEvent>
</PropertyGroup>
</Project>
</Project>
Loading

0 comments on commit 02efe8d

Please sign in to comment.