This commit is contained in:
luosheng
2023-07-12 06:42:28 +08:00
parent 25555cad18
commit db591e0367
188 changed files with 56088 additions and 9 deletions

View File

@@ -0,0 +1,45 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// <para>Defines possible item access rights.</para>
/// <para align="left">Indicates if this item is read only, write only or read/write.
/// This is NOT related to security but rather to the nature of the underlying
/// hardware.</para>
/// </summary>
public enum TsDaAccessRights
{
/// <summary>The access rights for this item are server.</summary>
Unknown = 0x00,
/// <summary>The client can read the data item's value.</summary>
Readable = 0x01,
/// <summary>The client can change the data item's value.</summary>
Writable = 0x02,
/// <summary>The client can read and change the data item's value.</summary>
ReadWritable = 0x03
}
}

View File

@@ -0,0 +1,93 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Stores the state of a browse operation.
/// </summary>
[Serializable]
public class TsCDaBrowsePosition : IOpcBrowsePosition
{
#region Fields
private TsCDaBrowseFilters browseFilters_;
private OpcItem itemId_;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Saves the parameters for an incomplete browse information.
/// </summary>
public TsCDaBrowsePosition(OpcItem itemId, TsCDaBrowseFilters filters)
{
if (filters == null) throw new ArgumentNullException(nameof(filters));
itemId_ = (OpcItem)itemId?.Clone();
browseFilters_ = (TsCDaBrowseFilters)filters.Clone();
}
/// <summary>
/// Releases unmanaged resources held by the object.
/// </summary>
public virtual void Dispose()
{
// does nothing.
}
#endregion
#region Properties
/// <summary>
/// The item identifier of the branch being browsed.
/// </summary>
public OpcItem ItemID => itemId_;
/// <summary>
/// The filters applied during the browse operation.
/// </summary>
public TsCDaBrowseFilters Filters => (TsCDaBrowseFilters)browseFilters_.Clone();
/// <summary>
/// The maximum number of elements that may be returned in a single browse.
/// </summary>
// ReSharper disable once UnusedMember.Global
public int MaxElementsReturned
{
get => browseFilters_.MaxElementsReturned;
set => browseFilters_.MaxElementsReturned = value;
}
#endregion
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public virtual object Clone()
{
return (TsCDaBrowsePosition)MemberwiseClone();
}
#endregion
}
}

View File

@@ -0,0 +1,87 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Contains a description of an element in the server address space.
/// </summary>
[Serializable]
public class TsCDaBrowseElement : ICloneable
{
#region Fields
private TsCDaItemProperty[] itemProperties_ = new TsCDaItemProperty[0];
#endregion
#region Properties
/// <summary>
/// A descriptive name for element that is unique within a branch.
/// </summary>
public string Name { get; set; }
/// <summary>
/// The primary identifier for the element within the server namespace.
/// </summary>
public string ItemName { get; set; }
/// <summary>
/// An secondary identifier for the element within the server namespace.
/// </summary>
public string ItemPath { get; set; }
/// <summary>
/// Whether the element refers to an item with data that can be accessed.
/// </summary>
public bool IsItem { get; set; }
/// <summary>
/// Whether the element has children.
/// </summary>
public bool HasChildren { get; set; }
/// <summary>
/// The set of properties for the element.
/// </summary>
public TsCDaItemProperty[] Properties
{
get => itemProperties_;
set => itemProperties_ = value;
}
#endregion
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public virtual object Clone()
{
var clone = (TsCDaBrowseElement)MemberwiseClone();
clone.itemProperties_ = (TsCDaItemProperty[])OpcConvert.Clone(itemProperties_);
return clone;
}
#endregion
};
}

View File

@@ -0,0 +1,48 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// The type of browse elements to return during a browse.
/// </summary>
public enum TsCDaBrowseFilter
{
/// <summary>
/// Return all types of browse elements.
/// </summary>
All,
/// <summary>
/// Return only elements that contain other elements.
/// </summary>
Branch,
/// <summary>
/// Return only elements that represent items.
/// </summary>
Item
}
}

View File

@@ -0,0 +1,97 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Defines a set of filters to apply when browsing.
/// </summary>
[Serializable]
public class TsCDaBrowseFilters : ICloneable
{
#region Fields
private TsCDaBrowseFilter browseFilter_ = TsCDaBrowseFilter.All;
private TsDaPropertyID[] propertyIds_;
#endregion
#region Properties
/// <summary>
/// The maximum number of elements to return. Zero means no limit.
/// </summary>
public int MaxElementsReturned { get; set; }
/// <summary>
/// The type of element to return.
/// </summary>
public TsCDaBrowseFilter BrowseFilter
{
get => browseFilter_;
set => browseFilter_ = value;
}
/// <summary>
/// An expression used to match the name of the element.
/// </summary>
public string ElementNameFilter { get; set; }
/// <summary>
/// A filter which has semantics that defined by the server.
/// </summary>
public string VendorFilter { get; set; }
/// <summary>
/// Whether all supported properties to return with each element.
/// </summary>
public bool ReturnAllProperties { get; set; }
/// <summary>
/// A list of names of the properties to return with each element.
/// </summary>
public TsDaPropertyID[] PropertyIDs
{
get => propertyIds_;
set => propertyIds_ = value;
}
/// <summary>
/// Whether property values should be returned with the properties.
/// </summary>
public bool ReturnPropertyValues { get; set; }
#endregion
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public virtual object Clone()
{
var clone = (TsCDaBrowseFilters)MemberwiseClone();
clone.PropertyIDs = (TsDaPropertyID[])PropertyIDs?.Clone();
return clone;
}
#endregion
}
}

View File

@@ -0,0 +1,45 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary><para>Defines possible item engineering unit types</para></summary>
public enum TsDaEuType
{
/// <summary>No engineering unit information available</summary>
NoEnum = 0x01,
/// <summary>
/// Analog engineering unit - will contain a SAFE ARRAY of exactly two doubles
/// (VT_ARRAY | VT_R8) corresponding to the LOW and HI EU range.
/// </summary>
Analog = 0x02,
/// <summary>
/// Enumerated engineering unit - will contain a SAFE ARRAY of strings (VT_ARRAY |
/// VT_BSTR) which contains a list of strings (Example: “OPEN”, “CLOSE”, “IN TRANSIT”,
/// etc.) corresponding to sequential numeric values (0, 1, 2, etc.)
/// </summary>
Enumerated = 0x03
}
}

View File

@@ -0,0 +1,109 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Defines functionality that is common to all OPC Data Access servers.
/// </summary>
public interface ITsDaServer : IOpcServer
{
/// <summary>
/// Returns the filters applied by the server to any item results returned to the client.
/// </summary>
/// <returns>A bit mask indicating which fields should be returned in any item results.</returns>
int GetResultFilters();
/// <summary>
/// Sets the filters applied by the server to any item results returned to the client.
/// </summary>
/// <param name="filters">A bit mask indicating which fields should be returned in any item results.</param>
void SetResultFilters(int filters);
/// <summary>
/// Returns the current server status.
/// </summary>
/// <returns>The current server status.</returns>
OpcServerStatus GetServerStatus();
/// <summary>
/// Reads the current values for a set of items.
/// </summary>
/// <param name="items">The set of items to read.</param>
/// <returns>The results of the read operation for each item.</returns>
TsCDaItemValueResult[] Read(TsCDaItem[] items);
/// <summary>
/// Writes the value, quality and timestamp for a set of items.
/// </summary>
/// <param name="values">The set of item values to write.</param>
/// <returns>The results of the write operation for each item.</returns>
OpcItemResult[] Write(TsCDaItemValue[] values);
/// <summary>
/// Creates a new subscription.
/// </summary>
/// <param name="state">The initial state of the subscription.</param>
/// <returns>The new subscription object.</returns>
ITsCDaSubscription CreateSubscription(TsCDaSubscriptionState state);
/// <summary>
/// Cancels a subscription and releases all resources allocated for it.
/// </summary>
/// <param name="subscription">The subscription to cancel.</param>
void CancelSubscription(ITsCDaSubscription subscription);
/// <summary>
/// Fetches the children of a branch that meet the filter criteria.
/// </summary>
/// <param name="itemId">The identifier of branch which is the target of the search.</param>
/// <param name="filters">The filters to use to limit the set of child elements returned.</param>
/// <param name="position">An object used to continue a browse that could not be completed.</param>
/// <returns>The set of elements found.</returns>
TsCDaBrowseElement[] Browse(
OpcItem itemId,
TsCDaBrowseFilters filters,
out TsCDaBrowsePosition position);
/// <summary>
/// Continues a browse operation with previously specified search criteria.
/// </summary>
/// <param name="position">An object containing the browse operation state information.</param>
/// <returns>The set of elements found.</returns>
TsCDaBrowseElement[] BrowseNext(ref TsCDaBrowsePosition position);
/// <summary>
/// Returns the item properties for a set of items.
/// </summary>
/// <param name="itemIds">A list of item identifiers.</param>
/// <param name="propertyIDs">A list of properties to fetch for each item.</param>
/// <param name="returnValues">Whether the property values should be returned with the properties.</param>
/// <returns>A list of properties for each item.</returns>
TsCDaItemPropertyCollection[] GetProperties(
OpcItem[] itemIds,
TsDaPropertyID[] propertyIDs,
bool returnValues);
}
}

View File

@@ -0,0 +1,226 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// A subscription for a set of items on a single OPC server.
/// </summary>
public interface ITsCDaSubscription : IDisposable
{
#region Events
/// <summary>
/// An event to receive data change updates.
/// </summary>
event TsCDaDataChangedEventHandler DataChangedEvent;
#endregion
#region Result Filters
/// <summary>
/// Returns the filters applied by the server to any item results returned to the client.
/// </summary>
/// <returns>A bit mask indicating which fields should be returned in any item results.</returns>
int GetResultFilters();
/// <summary>
/// Sets the filters applied by the server to any item results returned to the client.
/// </summary>
/// <param name="filters">A bit mask indicating which fields should be returned in any item results.</param>
void SetResultFilters(int filters);
#endregion
#region State Management
/// <summary>
/// Returns the current state of the subscription.
/// </summary>
/// <returns>The current state of the subscription.</returns>
TsCDaSubscriptionState GetState();
/// <summary>
/// Changes the state of a subscription.
/// </summary>
/// <param name="masks">A bit mask that indicates which elements of the subscription state are changing.</param>
/// <param name="state">The new subscription state.</param>
/// <returns>The actual subscription state after applying the changes.</returns>
TsCDaSubscriptionState ModifyState(int masks, TsCDaSubscriptionState state);
#endregion
#region Item Management
/// <summary>
/// Adds items to the subscription.
/// </summary>
/// <param name="items">The set of items to add to the subscription.</param>
/// <returns>The results of the add item operation for each item.</returns>
TsCDaItemResult[] AddItems(TsCDaItem[] items);
/// <summary>
/// Modifies the state of items in the subscription
/// </summary>
/// <param name="masks">Specifies which item state parameters are being modified.</param>
/// <param name="items">The new state for each item.</param>
/// <returns>The results of the modify item operation for each item.</returns>
TsCDaItemResult[] ModifyItems(int masks, TsCDaItem[] items);
/// <summary>
/// Removes items from the subscription.
/// </summary>
/// <param name="items">The identifiers (i.e. server handles) for the items being removed.</param>
/// <returns>The results of the remove item operation for each item.</returns>
OpcItemResult[] RemoveItems(OpcItem[] items);
#endregion
#region Synchronous I/O
/// <summary>
/// Reads the values for a set of items in the subscription.
/// </summary>
/// <param name="items">The identifiers (i.e. server handles) for the items being read.</param>
/// <returns>The value for each of items.</returns>
TsCDaItemValueResult[] Read(TsCDaItem[] items);
/// <summary>
/// Writes the value, quality and timestamp for a set of items in the subscription.
/// </summary>
/// <param name="items">The item values to write.</param>
/// <returns>The results of the write operation for each item.</returns>
OpcItemResult[] Write(TsCDaItemValue[] items);
#endregion
#region Asynchronous I/O
/// <summary>
/// Begins an asynchronous read operation for a set of items.
/// </summary>
/// <param name="items">The set of items to read (must include the item name).</param>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
/// <param name="callback">A delegate used to receive notifications when the request completes.</param>
/// <param name="request">An object that contains the state of the request (used to cancel the request).</param>
/// <returns>A set of results containing any errors encountered when the server validated the items.</returns>
OpcItemResult[] Read(
TsCDaItem[] items,
object requestHandle,
TsCDaReadCompleteEventHandler callback,
out IOpcRequest request);
/// <summary>
/// Begins an asynchronous write operation for a set of items.
/// </summary>
/// <param name="items">The set of item values to write (must include the item name).</param>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
/// <param name="callback">A delegate used to receive notifications when the request completes.</param>
/// <param name="request">An object that contains the state of the request (used to cancel the request).</param>
/// <returns>A set of results containing any errors encountered when the server validated the items.</returns>
OpcItemResult[] Write(
TsCDaItemValue[] items,
object requestHandle,
TsCDaWriteCompleteEventHandler callback,
out IOpcRequest request);
/// <summary>
/// Cancels an asynchronous read or write operation.
/// </summary>
/// <param name="request">The object returned from the BeginRead or BeginWrite request.</param>
/// <param name="callback">The function to invoke when the cancel completes.</param>
void Cancel(IOpcRequest request, TsCDaCancelCompleteEventHandler callback);
/// <summary>
/// Causes the server to send a data changed notification for all active items.
/// </summary>
void Refresh();
/// <summary>
/// Causes the server to send a data changed notification for all active items.
/// </summary>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
/// <param name="request">An object that contains the state of the request (used to cancel the request).</param>
/// <returns>A set of results containing any errors encountered when the server validated the items.</returns>
void Refresh(
object requestHandle,
out IOpcRequest request);
/// <summary>
/// Enables or disables data change notifications from the server.
/// </summary>
/// <param name="enabled">Whether data change notifications are enabled.</param>
void SetEnabled(bool enabled);
/// <summary>
/// Checks whether data change notifications from the server are enabled.
/// </summary>
/// <returns>Whether data change notifications are enabled.</returns>
bool GetEnabled();
#endregion
}
#region Delegate Declarations
/// <summary>
/// A delegate to receive data change updates from the server.
/// </summary>
/// <param name="subscriptionHandle">
/// A unique identifier for the subscription assigned by the client. If the parameter
/// <see cref="TsCDaSubscriptionState.ClientHandle">ClientHandle</see> is not defined this
/// parameter is empty.
/// </param>
/// <param name="requestHandle">
/// An identifier for the request assigned by the caller. This parameter is empty if
/// the corresponding parameter in the calls Read(), Write() or Refresh() is not defined.
/// Can be used to Cancel an outstanding operation.
/// </param>
/// <param name="values">
/// <para class="MsoBodyText" style="MARGIN: 1pt 0in">The set of changed values.</para>
/// <para class="MsoBodyText" style="MARGIN: 1pt 0in">Each value will always have
/// items ClientHandle field specified.</para>
/// </param>
public delegate void TsCDaDataChangedEventHandler(object subscriptionHandle, object requestHandle, TsCDaItemValueResult[] values);
/// <summary>
/// A delegate to receive asynchronous read completed notifications.
/// </summary>
/// <param name="requestHandle">
/// An identifier for the request assigned by the caller. This parameter is empty if
/// the corresponding parameter in the calls Read(), Write() or Refresh() is not defined.
/// Can be used to Cancel an outstanding operation.
/// </param>
/// <param name="results">The results of the last asynchronous read operation.</param>
public delegate void TsCDaReadCompleteEventHandler(object requestHandle, TsCDaItemValueResult[] results);
/// <summary>
/// A delegate to receive asynchronous write completed notifications.
/// </summary>
/// <param name="requestHandle">
/// An identifier for the request assigned by the caller. This parameter is empty if
/// the corresponding parameter in the calls Read(), Write() or Refresh() is not defined.
/// Can be used to Cancel an outstanding operation.
/// </param>
/// <param name="results">The results of the last asynchronous write operation.</param>
public delegate void TsCDaWriteCompleteEventHandler(object requestHandle, OpcItemResult[] results);
/// <summary>
/// A delegate to receive asynchronous cancel completed notifications.
/// </summary>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
public delegate void TsCDaCancelCompleteEventHandler(object requestHandle);
#endregion
}

View File

@@ -0,0 +1,150 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Describes how an item in the server address space should be accessed.
/// </summary>
[Serializable]
public class TsCDaItem : OpcItem
{
#region Fields
private bool active_ = true;
private float deadband_;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with default values.
/// </summary>
public TsCDaItem() { }
/// <summary>
/// Initializes object with the specified ItemIdentifier object.
/// </summary>
public TsCDaItem(OpcItem item)
{
if (item == null)
{
return;
}
ItemName = item.ItemName;
ItemPath = item.ItemPath;
ClientHandle = item.ClientHandle;
ServerHandle = item.ServerHandle;
}
/// <summary>
/// Initializes object with the specified Item object.
/// </summary>
public TsCDaItem(TsCDaItem item)
: base(item)
{
if (item == null)
{
return;
}
ReqType = item.ReqType;
MaxAge = item.MaxAge;
MaxAgeSpecified = item.MaxAgeSpecified;
Active = item.Active;
ActiveSpecified = item.ActiveSpecified;
Deadband = item.Deadband;
DeadbandSpecified = item.DeadbandSpecified;
SamplingRate = item.SamplingRate;
SamplingRateSpecified = item.SamplingRateSpecified;
EnableBuffering = item.EnableBuffering;
EnableBufferingSpecified = item.EnableBufferingSpecified;
}
#endregion
#region Properties
/// <summary>
/// The data type to use when returning the item value.
/// </summary>
public Type ReqType { get; set; }
/// <summary>
/// The oldest (in milliseconds) acceptable cached value when reading an item.
/// </summary>
public int MaxAge { get; set; }
/// <summary>
/// Whether the Max Age is specified.
/// </summary>
public bool MaxAgeSpecified { get; set; }
/// <summary>
/// Whether the server should send data change updates.
/// </summary>
public bool Active
{
get => active_;
set => active_ = value;
}
/// <summary>
/// Whether the Active state is specified.
/// </summary>
public bool ActiveSpecified { get; set; }
/// <summary>
/// The minimum percentage change required to trigger a data update for an item.
/// </summary>
public float Deadband
{
get => deadband_;
set => deadband_ = value;
}
/// <summary>
/// Whether the Deadband is specified.
/// </summary>
public bool DeadbandSpecified { get; set; }
/// <summary>
/// How frequently the server should sample the item value.
/// </summary>
public int SamplingRate { get; set; }
/// <summary>
/// Whether the Sampling Rate is specified.
/// </summary>
public bool SamplingRateSpecified { get; set; }
/// <summary>
/// Whether the server should buffer multiple data changes between data updates.
/// </summary>
public bool EnableBuffering { get; set; }
/// <summary>
/// Whether the Enable Buffering is specified.
/// </summary>
public bool EnableBufferingSpecified { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,313 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Collections;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// A collection of items.
/// </summary>
[Serializable]
public class TsCDaItemCollection : ICloneable, IList
{
#region Fields
private ArrayList items_ = new ArrayList();
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes object with the default values.
/// </summary>
public TsCDaItemCollection() { }
/// <summary>
/// Initializes object with the specified ResultCollection object.
/// </summary>
public TsCDaItemCollection(TsCDaItemCollection items)
{
if (items == null)
{
return;
}
foreach (TsCDaItem item in items)
{
Add(item);
}
}
#endregion
#region Properties
/// <summary>
/// Gets the item at the specified index.
/// </summary>
public TsCDaItem this[int index]
{
get => (TsCDaItem)items_[index];
set => items_[index] = value;
}
/// <summary>
/// Gets the first item with the specified item id.
/// </summary>
public TsCDaItem this[OpcItem itemId]
{
get
{
foreach (TsCDaItem item in items_)
{
if (itemId.Key == item.Key)
{
return item;
}
}
return null;
}
}
#endregion
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public virtual object Clone()
{
var clone = (TsCDaItemCollection)MemberwiseClone();
clone.items_ = new ArrayList();
foreach (TsCDaItem item in items_)
{
clone.items_.Add(item.Clone());
}
return clone;
}
#endregion
#region ICollection Members
/// <summary>
/// Indicates whether access to the ICollection is synchronized (thread-safe).
/// </summary>
public bool IsSynchronized => false;
/// <summary>
/// Gets the number of objects in the collection.
/// </summary>
public int Count => items_?.Count ?? 0;
/// <summary>
/// Copies the objects to an Array, starting at a the specified index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination for the objects.</param>
/// <param name="index">The zero-based index in the Array at which copying begins.</param>
public void CopyTo(Array array, int index)
{
items_?.CopyTo(array, index);
}
/// <summary>
/// Copies the objects to an Array, starting at a the specified index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination for the objects.</param>
/// <param name="index">The zero-based index in the Array at which copying begins.</param>
public void CopyTo(TsCDaItem[] array, int index)
{
CopyTo((Array)array, index);
}
/// <summary>
/// Indicates whether access to the ICollection is synchronized (thread-safe).
/// </summary>
public object SyncRoot => this;
#endregion
#region IEnumerable Members
/// <summary>
/// Returns an enumerator that can iterate through a collection.
/// </summary>
/// <returns>An IEnumerator that can be used to iterate through the collection.</returns>
public IEnumerator GetEnumerator()
{
return items_.GetEnumerator();
}
#endregion
#region IList Members
/// <summary>
/// Gets a value indicating whether the IList is read-only.
/// </summary>
public bool IsReadOnly => false;
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
object IList.this[int index]
{
get => items_[index];
set
{
if (!typeof(TsCDaItem).IsInstanceOfType(value))
{
throw new ArgumentException("May only add Item objects into the collection.");
}
items_[index] = value;
}
}
/// <summary>
/// Removes the IList item at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the item to remove.</param>
public void RemoveAt(int index)
{
items_.RemoveAt(index);
}
/// <summary>
/// Inserts an item to the IList at the specified position.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The Object to insert into the IList. </param>
public void Insert(int index, object value)
{
if (!typeof(TsCDaItem).IsInstanceOfType(value))
{
throw new ArgumentException("May only add Item objects into the collection.");
}
items_.Insert(index, value);
}
/// <summary>
/// Removes the first occurrence of a specific object from the IList.
/// </summary>
/// <param name="value">The Object to remove from the IList.</param>
public void Remove(object value)
{
items_.Remove(value);
}
/// <summary>
/// Determines whether the IList contains a specific value.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>true if the Object is found in the IList; otherwise, false.</returns>
public bool Contains(object value)
{
return items_.Contains(value);
}
/// <summary>
/// Removes all items from the IList.
/// </summary>
public void Clear()
{
items_.Clear();
}
/// <summary>
/// Determines the index of a specific item in the IList.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
public int IndexOf(object value)
{
return items_.IndexOf(value);
}
/// <summary>
/// Adds an item to the IList.
/// </summary>
/// <param name="value">The Object to add to the IList. </param>
/// <returns>The position into which the new element was inserted.</returns>
public int Add(object value)
{
if (!typeof(TsCDaItem).IsInstanceOfType(value))
{
throw new ArgumentException("May only add Item objects into the collection.");
}
return items_.Add(value);
}
/// <summary>
/// Indicates whether the IList has a fixed size.
/// </summary>
public bool IsFixedSize => false;
/// <summary>
/// Inserts an item to the IList at the specified position.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The Object to insert into the IList. </param>
public void Insert(int index, TsCDaItem value)
{
Insert(index, (object)value);
}
/// <summary>
/// Removes the first occurrence of a specific object from the IList.
/// </summary>
/// <param name="value">The Object to remove from the IList.</param>
public void Remove(TsCDaItem value)
{
Remove((object)value);
}
/// <summary>
/// Determines whether the IList contains a specific value.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>true if the Object is found in the IList; otherwise, false.</returns>
public bool Contains(TsCDaItem value)
{
return Contains((object)value);
}
/// <summary>
/// Determines the index of a specific item in the IList.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
public int IndexOf(TsCDaItem value)
{
return IndexOf((object)value);
}
/// <summary>
/// Adds an item to the IList.
/// </summary>
/// <param name="value">The Object to add to the IList. </param>
/// <returns>The position into which the new element was inserted.</returns>
public int Add(TsCDaItem value)
{
return Add((object)value);
}
#endregion
}
}

View File

@@ -0,0 +1,100 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Contains a description of a single item property.
/// </summary>
[Serializable]
public class TsCDaItemProperty : ICloneable, IOpcResult
{
#region Fields
private OpcResult result_ = OpcResult.S_OK;
#endregion
#region Properties
/// <summary>
/// The property identifier.
/// </summary>
public TsDaPropertyID ID { get; set; }
/// <summary>
/// A short description of the property.
/// </summary>
public string Description { get; set; }
/// <summary>
/// The data type of the property.
/// </summary>
public Type DataType { get; set; }
/// <summary>
/// The value of the property.
/// </summary>
public object Value { get; set; }
/// <summary>
/// The primary identifier for the property if it is directly accessible as an item.
/// </summary>
public string ItemName { get; set; }
/// <summary>
/// The secondary identifier for the property if it is directly accessible as an item.
/// </summary>
public string ItemPath { get; set; }
#endregion
#region IOpcResult Members
/// <summary>
/// The <see cref="OpcResult" /> object with the result of an operation on an property.
/// </summary>
public OpcResult Result
{
get => result_;
set => result_ = value;
}
/// <summary>
/// Vendor specific diagnostic information (not the localized error text).
/// </summary>
public string DiagnosticInfo { get; set; }
#endregion
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public virtual object Clone()
{
var clone = (TsCDaItemProperty)MemberwiseClone();
clone.Value = OpcConvert.Clone(Value);
return clone;
}
#endregion
}
}

View File

@@ -0,0 +1,175 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Collections;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// A list of properties for a single item.
/// </summary>
[Serializable]
public class TsCDaItemPropertyCollection : ArrayList, IOpcResult
{
#region Fields
private OpcResult result_ = OpcResult.S_OK;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with its default values.
/// </summary>
public TsCDaItemPropertyCollection()
{
}
/// <summary>
/// Initializes the object with the specified item identifier.
/// </summary>
public TsCDaItemPropertyCollection(OpcItem itemId)
{
if (itemId != null)
{
ItemName = itemId.ItemName;
ItemPath = itemId.ItemPath;
}
}
/// <summary>
/// Initializes the object with the specified item identifier and result.
/// </summary>
public TsCDaItemPropertyCollection(OpcItem itemId, OpcResult result)
{
if (itemId != null)
{
ItemName = itemId.ItemName;
ItemPath = itemId.ItemPath;
}
result_ = result;
}
#endregion
#region Properties
/// <summary>
/// The primary identifier for the item within the server namespace.
/// </summary>
public string ItemName { get; set; }
/// <summary>
/// An secondary identifier for the item within the server namespace.
/// </summary>
public string ItemPath { get; set; }
/// <summary>
/// Accesses the items at the specified index.
/// </summary>
public new TsCDaItemProperty this[int index]
{
get => (TsCDaItemProperty)base[index];
set => base[index] = value;
}
#endregion
#region IOpcResult Members
/// <summary>
/// The error id for the result of an operation on an item.
/// </summary>
public OpcResult Result
{
get => result_;
set => result_ = value;
}
/// <summary>
/// Vendor specific diagnostic information (not the localized error text).
/// </summary>
public string DiagnosticInfo { get; set; }
#endregion
#region ICollection Members
/// <summary>
/// Copies the objects to an Array, starting at a the specified index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination for the objects.</param>
/// <param name="index">The zero-based index in the Array at which copying begins.</param>
public void CopyTo(TsCDaItemProperty[] array, int index)
{
CopyTo((Array)array, index);
}
#endregion
#region IList Members
/// <summary>
/// Inserts an item to the IList at the specified position.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The Object to insert into the IList. </param>
public void Insert(int index, TsCDaItemProperty value)
{
Insert(index, (object)value);
}
/// <summary>
/// Removes the first occurrence of a specific object from the IList.
/// </summary>
/// <param name="value">The Object to remove from the IList.</param>
public void Remove(TsCDaItemProperty value)
{
Remove((object)value);
}
/// <summary>
/// Determines whether the IList contains a specific value.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>true if the Object is found in the IList; otherwise, false.</returns>
public bool Contains(TsCDaItemProperty value)
{
return Contains((object)value);
}
/// <summary>
/// Determines the index of a specific item in the IList.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
public int IndexOf(TsCDaItemProperty value)
{
return IndexOf((object)value);
}
/// <summary>
/// Adds an item to the IList.
/// </summary>
/// <param name="value">The Object to add to the IList. </param>
/// <returns>The position into which the new element was inserted.</returns>
public int Add(TsCDaItemProperty value)
{
return Add((object)value);
}
#endregion
}
}

View File

@@ -0,0 +1,104 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// The results of an operation on a uniquely identifiable item.
/// </summary>
[Serializable]
public class TsCDaItemResult : TsCDaItem, IOpcResult
{
#region Fields
private OpcResult result_ = OpcResult.S_OK;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with default values.
/// </summary>
public TsCDaItemResult() { }
/// <summary>
/// Initializes the object with an ItemIdentifier object.
/// </summary>
public TsCDaItemResult(OpcItem item) : base(item) { }
/// <summary>
/// Initializes the object with an ItemIdentifier object and Result.
/// </summary>
public TsCDaItemResult(OpcItem item, OpcResult resultId)
: base(item)
{
Result = resultId;
}
/// <summary>
/// Initializes the object with an Item object.
/// </summary>
public TsCDaItemResult(TsCDaItem item) : base(item) { }
/// <summary>
/// Initializes the object with an Item object and Result.
/// </summary>
public TsCDaItemResult(TsCDaItem item, OpcResult resultId)
: base(item)
{
Result = resultId;
}
/// <summary>
/// Initializes object with the specified ItemResult object.
/// </summary>
public TsCDaItemResult(TsCDaItemResult item)
: base(item)
{
if (item != null)
{
Result = item.Result;
DiagnosticInfo = item.DiagnosticInfo;
}
}
#endregion
#region IOpcResult Members
/// <summary>
/// The error id for the result of an operation on an property.
/// </summary>
public OpcResult Result
{
get => result_;
set => result_ = value;
}
/// <summary>
/// Vendor specific diagnostic information (not the localized error text).
/// </summary>
public string DiagnosticInfo { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,137 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Contains the value for a single item.
/// </summary>
[Serializable]
public class TsCDaItemValue : OpcItem
{
#region Fields
private TsCDaQuality daQuality_ = TsCDaQuality.Bad;
private DateTime timestamp_ = DateTime.MinValue;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with default values.
/// </summary>
public TsCDaItemValue() { }
/// <summary>
/// Initializes the object with and ItemIdentifier object.
/// </summary>
public TsCDaItemValue(OpcItem item)
{
if (item == null)
{
return;
}
ItemName = item.ItemName;
ItemPath = item.ItemPath;
ClientHandle = item.ClientHandle;
ServerHandle = item.ServerHandle;
}
/// <summary>
/// Initializes the object with the specified item name.
/// </summary>
public TsCDaItemValue(string itemName)
: base(itemName)
{
}
/// <summary>
/// Initializes object with the specified ItemValue object.
/// </summary>
public TsCDaItemValue(TsCDaItemValue item)
: base(item)
{
if (item == null)
{
return;
}
Value = OpcConvert.Clone(item.Value);
Quality = item.Quality;
QualitySpecified = item.QualitySpecified;
Timestamp = item.Timestamp;
TimestampSpecified = item.TimestampSpecified;
}
#endregion
#region Properties
/// <summary>
/// The item value.
/// </summary>
public object Value { get; set; }
/// <summary>
/// The quality of the item value.
/// </summary>
public TsCDaQuality Quality
{
get => daQuality_;
set => daQuality_ = value;
}
/// <summary>
/// Whether the quality is specified.
/// </summary>
public bool QualitySpecified { get; set; }
/// <summary>
/// The timestamp for the item value.
/// The <see cref="ApplicationInstance.TimeAsUtc">ApplicationInstance.TimeAsUtc</see> property defines
/// the time format (UTC or local time).
/// </summary>
public DateTime Timestamp
{
get => timestamp_;
set => timestamp_ = value;
}
/// <summary>
/// Whether the timestamp is specified.
/// </summary>
public bool TimestampSpecified { get; set; }
#endregion
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public override object Clone()
{
var clone = (TsCDaItemValue)MemberwiseClone();
clone.Value = OpcConvert.Clone(Value);
return clone;
}
#endregion
}
}

View File

@@ -0,0 +1,123 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// The results of an operation on a uniquely identifiable item value.
/// </summary>
[Serializable]
public class TsCDaItemValueResult : TsCDaItemValue, IOpcResult
{
#region Fields
private OpcResult result_ = OpcResult.S_OK;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with default values.
/// </summary>
public TsCDaItemValueResult() { }
/// <summary>
/// Initializes the object with an ItemIdentifier object.
/// </summary>
public TsCDaItemValueResult(OpcItem item) : base(item) { }
/// <summary>
/// Initializes the object with an ItemValue object.
/// </summary>
public TsCDaItemValueResult(TsCDaItemValue item) : base(item) { }
/// <summary>
/// Initializes object with the specified ItemValueResult object.
/// </summary>
public TsCDaItemValueResult(TsCDaItemValueResult item)
: base(item)
{
if (item != null)
{
Result = item.Result;
DiagnosticInfo = item.DiagnosticInfo;
}
}
/// <summary>
/// Initializes the object with the specified item name and result code.
/// </summary>
public TsCDaItemValueResult(string itemName, OpcResult resultId)
: base(itemName)
{
Result = resultId;
}
/// <summary>
/// Initializes the object with the specified item name, result code and diagnostic info.
/// </summary>
public TsCDaItemValueResult(string itemName, OpcResult resultId, string diagnosticInfo)
: base(itemName)
{
Result = resultId;
DiagnosticInfo = diagnosticInfo;
}
/// <summary>
/// Initialize object with the specified ItemIdentifier and result code.
/// </summary>
public TsCDaItemValueResult(OpcItem item, OpcResult resultId)
: base(item)
{
Result = resultId;
}
/// <summary>
/// Initializes the object with the specified ItemIdentifier, result code and diagnostic info.
/// </summary>
public TsCDaItemValueResult(OpcItem item, OpcResult resultId, string diagnosticInfo)
: base(item)
{
Result = resultId;
DiagnosticInfo = diagnosticInfo;
}
#endregion
#region IOpcResult Members
/// <summary>
/// The error id for the result of an operation on an property.
/// </summary>
public OpcResult Result
{
get => result_;
set => result_ = value;
}
/// <summary>
/// Vendor specific diagnostic information (not the localized error text).
/// </summary>
public string DiagnosticInfo { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,44 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// <para>Defines the possible limit status bits.</para>
/// <para>The Limit Field is valid regardless of the Quality and Substatus. In some
/// cases such as Sensor Failure it can provide useful diagnostic information.</para>
/// </summary>
public enum TsDaLimitBits
{
/// <summary>The value is free to move up or down</summary>
None = 0x0,
/// <summary>The value has pegged at some lower limit</summary>
Low = 0x1,
/// <summary>The value has pegged at some high limit</summary>
High = 0x2,
/// <summary>The value is a constant and cannot move</summary>
Constant = 0x3
}
}

View File

@@ -0,0 +1,328 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Defines identifiers for well-known properties.
/// </summary>
public class TsDaProperty
{
#region Data Access Properties
/// <summary><para>Item Canonical DataType</para></summary>
public static readonly TsDaPropertyID DATATYPE = new TsDaPropertyID("dataType", 1, OpcNamespace.OPC_DATA_ACCESS);
/// <summary><para>Item Value</para></summary>
/// <remarks>
/// Note the type of value returned is as indicated by the "Item Canonical DataType"
/// and depends on the item. This will behave like a read from DEVICE.
/// </remarks>
public static readonly TsDaPropertyID VALUE = new TsDaPropertyID("value", 2, OpcNamespace.OPC_DATA_ACCESS);
/// <summary><para>Item Quality</para></summary>
/// <remarks>(OPCQUALITY stored in an I2). This will behave like a read from DEVICE.</remarks>
public static readonly TsDaPropertyID QUALITY = new TsDaPropertyID("quality", 3, OpcNamespace.OPC_DATA_ACCESS);
/// <summary><para>Item Timestamp</para></summary>
/// <remarks>
/// (will be converted from FILETIME). This will behave like a read from
/// DEVICE.
/// </remarks>
public static readonly TsDaPropertyID TIMESTAMP = new TsDaPropertyID("timestamp", 4, OpcNamespace.OPC_DATA_ACCESS);
/// <summary><para>Item Access Rights</para></summary>
/// <remarks>(OPCACCESSRIGHTS stored in an I4)</remarks>
public static readonly TsDaPropertyID ACCESSRIGHTS = new TsDaPropertyID("accessRights", 5, OpcNamespace.OPC_DATA_ACCESS);
/// <summary><para>Server Scan Rate</para></summary>
/// <remarks>
/// In Milliseconds. This represents the fastest rate at which the server could
/// obtain data from the underlying data source. The nature of this source is not defined
/// but is typically a DCS system, a SCADA system, a PLC via a COMM port or network, a
/// Device Network, etc. This value generally represents the best case fastest
/// RequestedUpdateRate which could be used if this item were added to an OPCGroup.<br/>
/// The accuracy of this value (the ability of the server to attain best case
/// performance) can be greatly affected by system load and other factors.
/// </remarks>
public static readonly TsDaPropertyID SCANRATE = new TsDaPropertyID("scanRate", 6, OpcNamespace.OPC_DATA_ACCESS);
/// <remarks>
/// <para>Indicate the type of Engineering Units (EU) information (if any) contained in
/// EUINFO.</para>
/// <list type="bullet">
/// <item>
/// 0 - No EU information available (EUINFO will be VT_EMPTY).
/// </item>
/// <item>
/// 1 - Analog - EUINFO will contain a SAFEARRAY of exactly two doubles
/// (VT_ARRAY | VT_R8) corresponding to the LOW and HI EU range.
/// </item>
/// <item>2 - Enumerated - EUINFO will contain a SAFEARRAY of strings (VT_ARRAY |
/// VT_BSTR) which contains a list of strings (Example: “OPEN”, “CLOSE”, “IN
/// TRANSIT”, etc.) corresponding to sequential numeric values (0, 1, 2,
/// etc.)</item>
/// </list>
/// </remarks>
/// <summary><para>Item EU Type</para></summary>
public static readonly TsDaPropertyID EUTYPE = new TsDaPropertyID("euType", 7, OpcNamespace.OPC_DATA_ACCESS);
/// <summary><para>Item EUInfo</para></summary>
/// <value>
/// <para>
/// If EUTYPE is “Analog” EUINFO will contain a SAFEARRAY of exactly two doubles
/// (VT_ARRAY | VT_R8) corresponding to the LOW and HI EU range.
/// </para>
/// <para>If EUTYPE is “Enumerated” - EUINFO will contain a SAFEARRAY of strings
/// (VT_ARRAY | VT_BSTR) which contains a list of strings (Example: “OPEN”, “CLOSE”,
/// “IN TRANSIT”, etc.) corresponding to sequential numeric values (0, 1, 2,
/// etc.)</para>
/// </value>
public static readonly TsDaPropertyID EUINFO = new TsDaPropertyID("euInfo", 8, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>EU Units</para>
/// <para>e.g. "DEGC" or "GALLONS"</para>
/// </summary>
public static readonly TsDaPropertyID ENGINEERINGUINTS = new TsDaPropertyID("engineeringUnits", 100, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Item Description</para>
/// <para>e.g. "Evaporator 6 Coolant Temp"</para>
/// </summary>
public static readonly TsDaPropertyID DESCRIPTION = new TsDaPropertyID("description", 101, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>High EU</para>
/// <para>Present only for 'analog' data. This represents the highest value likely to
/// be obtained in normal operation and is intended for such use as automatically
/// scaling a bargraph display.</para>
/// <para>e.g. 1400.0</para>
/// </summary>
public static readonly TsDaPropertyID HIGHEU = new TsDaPropertyID("highEU", 102, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Low EU</para>
/// <para>Present only for 'analog' data. This represents the lowest value likely to be
/// obtained in normal operation and is intended for such use as automatically scaling
/// a bargraph display.</para>
/// <para>e.g. -200.0</para>
/// </summary>
public static readonly TsDaPropertyID LOWEU = new TsDaPropertyID("lowEU", 103, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>High Instrument Range</para>
/// <para>Present only for analog data. This represents the highest value that can be
/// returned by the instrument.</para>
/// <para>e.g. 9999.9</para>
/// </summary>
public static readonly TsDaPropertyID HIGHIR = new TsDaPropertyID("highIR", 104, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Low Instrument Range</para>
/// <para>Present only for analog data. This represents the lowest value that can be
/// returned by the instrument.</para>
/// <para>e.g. -9999.9</para>
/// </summary>
public static readonly TsDaPropertyID LOWIR = new TsDaPropertyID("lowIR", 105, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Contact Close Label</para>
/// <para>Present only for discrete' data. This represents a string to be associated
/// with this contact when it is in the closed (non-zero) state</para>
/// <para>e.g. "RUN", "CLOSE", "ENABLE", "SAFE" ,etc.</para>
/// </summary>
public static readonly TsDaPropertyID CLOSELABEL = new TsDaPropertyID("closeLabel", 106, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Contact Open Label</para>
/// <para>Present only for discrete' data. This represents a string to be associated
/// with this contact when it is in the open (zero) state</para>
/// <para>e.g. "STOP", "OPEN", "DISABLE", "UNSAFE" ,etc.</para>
/// </summary>
public static readonly TsDaPropertyID OPENLABEL = new TsDaPropertyID("openLabel", 107, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Item Timezone</para>
/// <para>The difference in minutes between the items UTC Timestamp and the local time
/// in which the item value was obtained.</para>
/// </summary>
/// <remarks>
/// See the OPCGroup TimeBias property. Also see the WIN32 TIME_ZONE_INFORMATION
/// structure.
/// </remarks>
public static readonly TsDaPropertyID TIMEZONE = new TsDaPropertyID("timeZone", 108, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Condition Status</para>
/// <para>The current alarm or condition status associated with the Item<br/>
/// e.g. "NORMAL", "ACTIVE", "HI ALARM", etc</para>
/// </summary>
public static readonly TsDaPropertyID CONDITION_STATUS = new TsDaPropertyID("conditionStatus", 300, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Alarm Quick Help</para>
/// <para>A short text string providing a brief set of instructions for the operator to
/// follow when this alarm occurs.</para>
/// </summary>
public static readonly TsDaPropertyID ALARM_QUICK_HELP = new TsDaPropertyID("alarmQuickHelp", 301, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Alarm Area List</para>
/// <para>An array of stings indicating the plant or alarm areas which include this
/// ItemID.</para>
/// </summary>
public static readonly TsDaPropertyID ALARM_AREA_LIST = new TsDaPropertyID("alarmAreaList", 302, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Primary Alarm Area</para>
/// <para>A string indicating the primary plant or alarm area including this
/// ItemID</para>
/// </summary>
public static readonly TsDaPropertyID PRIMARY_ALARM_AREA = new TsDaPropertyID("primaryAlarmArea", 303, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Condition Logic</para>
/// <para>An arbitrary string describing the test being performed.</para>
/// <para>e.g. "High Limit Exceeded" or "TAG.PV &gt;= TAG.HILIM"</para>
/// </summary>
public static readonly TsDaPropertyID CONDITION_LOGIC = new TsDaPropertyID("conditionLogic", 304, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Limit Exceeded</para>
/// <para>For multistate alarms, the condition exceeded</para>
/// <para>e.g. HIHI, HI, LO, LOLO</para>
/// </summary>
public static readonly TsDaPropertyID LIMIT_EXCEEDED = new TsDaPropertyID("limitExceeded", 305, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>Deadband</summary>
public static readonly TsDaPropertyID DEADBAND = new TsDaPropertyID("deadband", 306, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>HiHi limit</summary>
public static readonly TsDaPropertyID HIHI_LIMIT = new TsDaPropertyID("hihiLimit", 307, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>Hi Limit</summary>
public static readonly TsDaPropertyID HI_LIMIT = new TsDaPropertyID("hiLimit", 308, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>Lo Limit</summary>
public static readonly TsDaPropertyID LO_LIMIT = new TsDaPropertyID("loLimit", 309, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>LoLo Limit</summary>
public static readonly TsDaPropertyID LOLO_LIMIT = new TsDaPropertyID("loloLimit", 310, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>Rate of Change Limit</summary>
public static readonly TsDaPropertyID RATE_CHANGE_LIMIT = new TsDaPropertyID("rangeOfChangeLimit", 311, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>Deviation Limit</summary>
public static readonly TsDaPropertyID DEVIATION_LIMIT = new TsDaPropertyID("deviationLimit", 312, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Sound File</para>
/// <para>e.g. C:\MEDIA\FIC101.WAV, or .MID</para>
/// </summary>
public static readonly TsDaPropertyID SOUNDFILE = new TsDaPropertyID("soundFile", 313, OpcNamespace.OPC_DATA_ACCESS);
#endregion
#region Complex Data Properties
/// <summary>
/// <para>Type System ID</para>
/// <para>Complex Data Property</para>
/// </summary>
public static readonly TsDaPropertyID TYPE_SYSTEM_ID = new TsDaPropertyID("typeSystemID", 600, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Dictionary ID</para>
/// <para>Complex Data Property</para>
/// </summary>
public static readonly TsDaPropertyID DICTIONARY_ID = new TsDaPropertyID("dictionaryID", 601, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Type ID</para>
/// <para>Complex Data Property</para>
/// </summary>
public static readonly TsDaPropertyID TYPE_ID = new TsDaPropertyID("typeID", 602, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Dictionary</para>
/// <para>Complex Data Property</para>
/// </summary>
public static readonly TsDaPropertyID DICTIONARY = new TsDaPropertyID("dictionary", 603, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Type description</para>
/// <para>Complex Data Property</para>
/// </summary>
public static readonly TsDaPropertyID TYPE_DESCRIPTION = new TsDaPropertyID("typeDescription", 604, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Consistency Window</para>
/// <para>Complex Data Property</para>
/// </summary>
public static readonly TsDaPropertyID CONSISTENCY_WINDOW = new TsDaPropertyID("consistencyWindow", 605, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Write Behaviour</para>
/// <para>Complex Data Property, defaults to “All or Nothing” if the complex data item
/// is writable. Not used for Read-Only items.</para>
/// </summary>
public static readonly TsDaPropertyID WRITE_BEHAVIOR = new TsDaPropertyID("writeBehavior", 606, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Unconverted Item ID</para>
/// <para>Complex Data Property, the ID of the item that exposes the same complex data
/// value in its native format. This property is mandatory for items that implement
/// complex data type conversions.</para>
/// </summary>
public static readonly TsDaPropertyID UNCONVERTED_ITEM_ID = new TsDaPropertyID("unconvertedItemID", 607, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Unfiltered Item ID</para>
/// <para>Complex Data Property, the ID the item that exposes the same complex data
/// value without any data filter or with the default query applied to it. It is
/// mandatory for items that implement complex data filters or queries.</para>
/// </summary>
public static readonly TsDaPropertyID UNFILTERED_ITEM_ID = new TsDaPropertyID("unfilteredItemID", 608, OpcNamespace.OPC_DATA_ACCESS);
/// <summary>
/// <para>Data Filter Value</para>
/// <para>Complex Data Property, the value of the filter that is currently applied to
/// the item. It is mandatory for items that implement complex data filters or
/// queries.</para>
/// </summary>
public static readonly TsDaPropertyID DATA_FILTER_VALUE = new TsDaPropertyID("dataFilterValue", 609, OpcNamespace.OPC_DATA_ACCESS);
#endregion
#region XML Data Access Properties
/// <remarks/>
public static readonly TsDaPropertyID MINIMUM_VALUE = new TsDaPropertyID("minimumValue", 109, OpcNamespace.OPC_DATA_ACCESS);
/// <remarks/>
public static readonly TsDaPropertyID MAXIMUM_VALUE = new TsDaPropertyID("maximumValue", 110, OpcNamespace.OPC_DATA_ACCESS);
/// <remarks/>
public static readonly TsDaPropertyID VALUE_PRECISION = new TsDaPropertyID("valuePrecision", 111, OpcNamespace.OPC_DATA_ACCESS);
#endregion
}
}

View File

@@ -0,0 +1,200 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Collections;
using System.Reflection;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Describes an item property.
/// </summary>
[Serializable]
public class TsDaPropertyDescription
{
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with the specified values.
/// </summary>
public TsDaPropertyDescription(TsDaPropertyID id, Type type, string name)
{
ID = id;
Type = type;
Name = name;
}
#endregion
#region Properties
/// <summary>
/// The unique identifier for the property.
/// </summary>
public TsDaPropertyID ID { get; set; }
/// <summary>
/// The .NET data type for the property.
/// </summary>
public Type Type { get; set; }
/// <summary>
/// The short description defined in the OPC specifications.
/// </summary>
public string Name { get; set; }
#endregion
#region Data Access Properties
/// <remarks/>
public static readonly TsDaPropertyDescription DATATYPE = new TsDaPropertyDescription(TsDaProperty.DATATYPE, typeof(Type), "Item Canonical DataType");
/// <remarks/>
public static readonly TsDaPropertyDescription VALUE = new TsDaPropertyDescription(TsDaProperty.VALUE, typeof(object), "Item Value");
/// <remarks/>
public static readonly TsDaPropertyDescription QUALITY = new TsDaPropertyDescription(TsDaProperty.QUALITY, typeof(TsCDaQuality), "Item Quality");
/// <remarks/>
public static readonly TsDaPropertyDescription TIMESTAMP = new TsDaPropertyDescription(TsDaProperty.TIMESTAMP, typeof(DateTime), "Item Timestamp");
/// <remarks/>
public static readonly TsDaPropertyDescription ACCESSRIGHTS = new TsDaPropertyDescription(TsDaProperty.ACCESSRIGHTS, typeof(TsDaAccessRights), "Item Access Rights");
/// <remarks/>
public static readonly TsDaPropertyDescription SCANRATE = new TsDaPropertyDescription(TsDaProperty.SCANRATE, typeof(float), "Server Scan Rate");
/// <remarks/>
public static readonly TsDaPropertyDescription EUTYPE = new TsDaPropertyDescription(TsDaProperty.EUTYPE, typeof(TsDaEuType), "Item EU Type");
/// <remarks/>
public static readonly TsDaPropertyDescription EUINFO = new TsDaPropertyDescription(TsDaProperty.EUINFO, typeof(string[]), "Item EU Info");
/// <remarks/>
public static readonly TsDaPropertyDescription ENGINEERINGUINTS = new TsDaPropertyDescription(TsDaProperty.ENGINEERINGUINTS, typeof(string), "EU Units");
/// <remarks/>
public static readonly TsDaPropertyDescription DESCRIPTION = new TsDaPropertyDescription(TsDaProperty.DESCRIPTION, typeof(string), "Item Description");
/// <remarks/>
public static readonly TsDaPropertyDescription HIGHEU = new TsDaPropertyDescription(TsDaProperty.HIGHEU, typeof(double), "High EU");
/// <remarks/>
public static readonly TsDaPropertyDescription LOWEU = new TsDaPropertyDescription(TsDaProperty.LOWEU, typeof(double), "Low EU");
/// <remarks/>
public static readonly TsDaPropertyDescription HIGHIR = new TsDaPropertyDescription(TsDaProperty.HIGHIR, typeof(double), "High Instrument Range");
/// <remarks/>
public static readonly TsDaPropertyDescription LOWIR = new TsDaPropertyDescription(TsDaProperty.LOWIR, typeof(double), "Low Instrument Range");
/// <remarks/>
public static readonly TsDaPropertyDescription CLOSELABEL = new TsDaPropertyDescription(TsDaProperty.CLOSELABEL, typeof(string), "Contact Close Label");
/// <remarks/>
public static readonly TsDaPropertyDescription OPENLABEL = new TsDaPropertyDescription(TsDaProperty.OPENLABEL, typeof(string), "Contact Open Label");
/// <remarks/>
public static readonly TsDaPropertyDescription TIMEZONE = new TsDaPropertyDescription(TsDaProperty.TIMEZONE, typeof(int), "Timezone");
/// <remarks/>
public static readonly TsDaPropertyDescription CONDITION_STATUS = new TsDaPropertyDescription(TsDaProperty.CONDITION_STATUS, typeof(string), "Condition Status");
/// <remarks/>
public static readonly TsDaPropertyDescription ALARM_QUICK_HELP = new TsDaPropertyDescription(TsDaProperty.ALARM_QUICK_HELP, typeof(string), "Alarm Quick Help");
/// <remarks/>
public static readonly TsDaPropertyDescription ALARM_AREA_LIST = new TsDaPropertyDescription(TsDaProperty.ALARM_AREA_LIST, typeof(string), "Alarm Area List");
/// <remarks/>
public static readonly TsDaPropertyDescription PRIMARY_ALARM_AREA = new TsDaPropertyDescription(TsDaProperty.PRIMARY_ALARM_AREA, typeof(string), "Primary Alarm Area");
/// <remarks/>
public static readonly TsDaPropertyDescription CONDITION_LOGIC = new TsDaPropertyDescription(TsDaProperty.CONDITION_LOGIC, typeof(string), "Condition Logic");
/// <remarks/>
public static readonly TsDaPropertyDescription LIMIT_EXCEEDED = new TsDaPropertyDescription(TsDaProperty.LIMIT_EXCEEDED, typeof(string), "Limit Exceeded");
/// <remarks/>
public static readonly TsDaPropertyDescription DEADBAND = new TsDaPropertyDescription(TsDaProperty.DEADBAND, typeof(double), "Deadband");
/// <remarks/>
public static readonly TsDaPropertyDescription HIHI_LIMIT = new TsDaPropertyDescription(TsDaProperty.HIHI_LIMIT, typeof(double), "HiHi Limit");
/// <remarks/>
public static readonly TsDaPropertyDescription HI_LIMIT = new TsDaPropertyDescription(TsDaProperty.HI_LIMIT, typeof(double), "Hi Limit");
/// <remarks/>
public static readonly TsDaPropertyDescription LO_LIMIT = new TsDaPropertyDescription(TsDaProperty.LO_LIMIT, typeof(double), "Lo Limit");
/// <remarks/>
public static readonly TsDaPropertyDescription LOLO_LIMIT = new TsDaPropertyDescription(TsDaProperty.LOLO_LIMIT, typeof(double), "LoLo Limit");
/// <remarks/>
public static readonly TsDaPropertyDescription RATE_CHANGE_LIMIT = new TsDaPropertyDescription(TsDaProperty.RATE_CHANGE_LIMIT, typeof(double), "Rate of Change Limit");
/// <remarks/>
public static readonly TsDaPropertyDescription DEVIATION_LIMIT = new TsDaPropertyDescription(TsDaProperty.DEVIATION_LIMIT, typeof(double), "Deviation Limit");
/// <remarks/>
public static readonly TsDaPropertyDescription SOUNDFILE = new TsDaPropertyDescription(TsDaProperty.SOUNDFILE, typeof(string), "Sound File");
#endregion
#region Complex Data Properties
/// <remarks/>
public static readonly TsDaPropertyDescription TYPE_SYSTEM_ID = new TsDaPropertyDescription(TsDaProperty.TYPE_SYSTEM_ID, typeof(string), "Type System ID");
/// <remarks/>
public static readonly TsDaPropertyDescription DICTIONARY_ID = new TsDaPropertyDescription(TsDaProperty.DICTIONARY_ID, typeof(string), "Dictionary ID");
/// <remarks/>
public static readonly TsDaPropertyDescription TYPE_ID = new TsDaPropertyDescription(TsDaProperty.TYPE_ID, typeof(string), "Type ID");
/// <remarks/>
public static readonly TsDaPropertyDescription DICTIONARY = new TsDaPropertyDescription(TsDaProperty.DICTIONARY, typeof(object), "Dictionary");
/// <remarks/>
public static readonly TsDaPropertyDescription TYPE_DESCRIPTION = new TsDaPropertyDescription(TsDaProperty.TYPE_DESCRIPTION, typeof(string), "Type Description");
/// <remarks/>
public static readonly TsDaPropertyDescription CONSISTENCY_WINDOW = new TsDaPropertyDescription(TsDaProperty.CONSISTENCY_WINDOW, typeof(string), "Consistency Window");
/// <remarks/>
public static readonly TsDaPropertyDescription WRITE_BEHAVIOR = new TsDaPropertyDescription(TsDaProperty.WRITE_BEHAVIOR, typeof(string), "Write Behavior");
/// <remarks/>
public static readonly TsDaPropertyDescription UNCONVERTED_ITEM_ID = new TsDaPropertyDescription(TsDaProperty.UNCONVERTED_ITEM_ID, typeof(string), "Unconverted Item ID");
/// <remarks/>
public static readonly TsDaPropertyDescription UNFILTERED_ITEM_ID = new TsDaPropertyDescription(TsDaProperty.UNFILTERED_ITEM_ID, typeof(string), "Unfiltered Item ID");
/// <remarks/>
public static readonly TsDaPropertyDescription DATA_FILTER_VALUE = new TsDaPropertyDescription(TsDaProperty.DATA_FILTER_VALUE, typeof(string), "Data Filter Value");
#endregion
#region Object Member Overrides
/// <summary>
/// Converts the description to a string.
/// </summary>
public override string ToString()
{
return Name;
}
#endregion
#region Public Methods
/// <summary>
/// Returns the description for the specified property.
/// </summary>
public static TsDaPropertyDescription Find(TsDaPropertyID id)
{
var fields = typeof(TsDaPropertyDescription).GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (var field in fields)
{
var property = (TsDaPropertyDescription)field.GetValue(typeof(TsDaPropertyDescription));
if (property.ID == id)
{
return property;
}
}
return null;
}
/// <summary>
/// Returns an array of all well-known property descriptions.
/// </summary>
public static TsDaPropertyDescription[] Enumerate()
{
var values = new ArrayList();
var fields = typeof(TsDaPropertyDescription).GetFields(BindingFlags.Static | BindingFlags.Public);
Array.ForEach(fields, field => values.Add(field.GetValue(typeof(TsDaPropertyDescription))));
return (TsDaPropertyDescription[])values.ToArray(typeof(TsDaPropertyDescription));
}
#endregion
}
}

View File

@@ -0,0 +1,198 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Xml;
using System.Runtime.Serialization;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Contains a unique identifier for a property.
/// </summary>
[Serializable]
public struct TsDaPropertyID : ISerializable
{
#region Names Class
/// <summary>
/// A set of names for fields used in serialization.
/// </summary>
private class Names
{
internal const string Name = "NA";
internal const string Namespace = "NS";
internal const string Code = "CO";
}
#endregion
#region Fields
private int code_;
private XmlQualifiedName qualifiedName_;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes a property identified by a qualified name.
/// </summary>
public TsDaPropertyID(XmlQualifiedName name) { qualifiedName_ = name; code_ = 0; }
/// <summary>
/// Initializes a property identified by an integer.
/// </summary>
public TsDaPropertyID(int code) { qualifiedName_ = null; code_ = code; }
/// <summary>
/// Initializes a property identified by a property description.
/// </summary>
public TsDaPropertyID(string name, int code, string ns) { qualifiedName_ = new XmlQualifiedName(name, ns); code_ = code; }
///<remarks>
/// During deserialization, SerializationInfo is passed to the class using the constructor provided for this purpose. Any visibility
/// constraints placed on the constructor are ignored when the object is deserialized; so you can mark the class as public,
/// protected, internal, or private. However, it is best practice to make the constructor protected unless the class is sealed, in which case
/// the constructor should be marked private. The constructor should also perform thorough input validation. To avoid misuse by malicious code,
/// the constructor should enforce the same security checks and permissions required to obtain an instance of the class using any other
/// constructor.
/// </remarks>
/// <summary>
/// Constructs a server by de-serializing its OpcUrl from the stream.
/// </summary>
private TsDaPropertyID(SerializationInfo info, StreamingContext context)
{
var enumerator = info.GetEnumerator();
var name = "";
var ns = "";
enumerator.Reset();
while (enumerator.MoveNext())
{
if (enumerator.Current.Name.Equals(Names.Name))
{
name = (string)enumerator.Current.Value;
continue;
}
if (enumerator.Current.Name.Equals(Names.Namespace))
{
ns = (string)enumerator.Current.Value;
}
}
qualifiedName_ = new XmlQualifiedName(name, ns);
code_ = (int)info.GetValue(Names.Code, typeof(int));
}
#endregion
#region Properties
/// <summary>
/// Used for properties identified by a qualified name.
/// </summary>
public XmlQualifiedName Name => qualifiedName_;
/// <summary>
/// Used for properties identified by a integer.
/// </summary>
public int Code => code_;
#endregion
#region Public Methods
/// <summary>
/// Returns true if the objects are equal.
/// </summary>
public static bool operator ==(TsDaPropertyID a, TsDaPropertyID b)
{
return a.Equals(b);
}
/// <summary>
/// Returns true if the objects are not equal.
/// </summary>
public static bool operator !=(TsDaPropertyID a, TsDaPropertyID b)
{
return !a.Equals(b);
}
#endregion
#region Serialization Functions
/// <summary>
/// Serializes a server into a stream.
/// </summary>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (qualifiedName_ != null)
{
info.AddValue(Names.Name, qualifiedName_.Name);
info.AddValue(Names.Namespace, qualifiedName_.Namespace);
}
info.AddValue(Names.Code, code_);
}
#endregion
#region Object Member Overrides
/// <summary>
/// Returns true if the target object is equal to the object.
/// </summary>
public override bool Equals(object target)
{
if (target != null && target.GetType() == typeof(TsDaPropertyID))
{
var propertyId = (TsDaPropertyID)target;
// compare by integer if both specify valid integers.
if (propertyId.Code != 0 && Code != 0)
{
return (propertyId.Code == Code);
}
// compare by name if both specify valid names.
if (propertyId.Name != null && Name != null)
{
return (propertyId.Name == Name);
}
}
return false;
}
/// <summary>
/// Returns a useful hash code for the object.
/// </summary>
public override int GetHashCode()
{
if (Code != 0) return Code.GetHashCode();
if (Name != null) return Name.GetHashCode();
return base.GetHashCode();
}
/// <summary>
/// Converts the property id to a string.
/// </summary>
public override string ToString()
{
if (Name != null && Code != 0) return $"{Name.Name} ({Code})";
if (Name != null) return Name.Name;
if (Code != 0) return $"{Code}";
return "";
}
#endregion
}
}

View File

@@ -0,0 +1,251 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Contains the quality field for an item value.
/// </summary>
[Serializable]
public struct TsCDaQuality
{
#region Fields
private TsDaQualityBits qualityBits_;
private TsDaLimitBits limitBits_;
private byte vendorBits_;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with the specified quality.
/// </summary>
public TsCDaQuality(TsDaQualityBits quality)
{
qualityBits_ = quality;
limitBits_ = TsDaLimitBits.None;
vendorBits_ = 0;
}
/// <summary>
/// Initializes the object from the contents of a 16 bit integer.
/// </summary>
public TsCDaQuality(short code)
{
qualityBits_ = (TsDaQualityBits)(code & (short)TsDaQualityMasks.QualityMask);
limitBits_ = (TsDaLimitBits)(code & (short)TsDaQualityMasks.LimitMask);
vendorBits_ = (byte)((code & (short)TsDaQualityMasks.VendorMask) >> 8);
}
#endregion
#region Properties
/// <summary>
/// The value in the quality bits field.
/// </summary>
public TsDaQualityBits QualityBits
{
get => qualityBits_;
set => qualityBits_ = value;
}
/// <summary>
/// The value in the limit bits field.
/// </summary>
public TsDaLimitBits LimitBits
{
get => limitBits_;
set => limitBits_ = value;
}
/// <summary>
/// The value in the quality bits field.
/// </summary>
public byte VendorBits
{
get => vendorBits_;
set => vendorBits_ = value;
}
/// <summary>
/// A 'good' quality value.
/// </summary>
public static readonly TsCDaQuality Good = new TsCDaQuality(TsDaQualityBits.Good);
/// <summary>
/// An 'bad' quality value.
/// </summary>
public static readonly TsCDaQuality Bad = new TsCDaQuality(TsDaQualityBits.Bad);
#endregion
#region Public Methods
/// <summary>
/// Returns the quality as a 16 bit integer.
/// </summary>
public short GetCode()
{
ushort code = 0;
code |= (ushort)QualityBits;
code |= (ushort)LimitBits;
code |= (ushort)(VendorBits << 8);
return (code <= short.MaxValue) ? (short)code : (short)-((ushort.MaxValue + 1 - code));
}
/// <summary>
/// Initializes the quality from a 16 bit integer.
/// </summary>
public void SetCode(short code)
{
qualityBits_ = (TsDaQualityBits)(code & (short)TsDaQualityMasks.QualityMask);
limitBits_ = (TsDaLimitBits)(code & (short)TsDaQualityMasks.LimitMask);
vendorBits_ = (byte)((code & (short)TsDaQualityMasks.VendorMask) >> 8);
}
/// <summary>
/// Returns true if the objects are equal.
/// </summary>
public static bool operator ==(TsCDaQuality a, TsCDaQuality b)
{
return a.Equals(b);
}
/// <summary>
/// Returns true if the objects are not equal.
/// </summary>
public static bool operator !=(TsCDaQuality a, TsCDaQuality b)
{
return !a.Equals(b);
}
#endregion
#region Object Member Overrides
/// <summary>
/// Converts a quality to a string with the format: 'quality[limit]:vendor'.
/// </summary>
public override string ToString()
{
string text = null;
switch (QualityBits)
{
case TsDaQualityBits.Good:
text += "(Good";
break;
case TsDaQualityBits.GoodLocalOverride:
text += "(Good:Local Override";
break;
case TsDaQualityBits.Bad:
text += "(Bad";
break;
case TsDaQualityBits.BadConfigurationError:
text += "(Bad:Configuration Error";
break;
case TsDaQualityBits.BadNotConnected:
text += "(Bad:Not Connected";
break;
case TsDaQualityBits.BadDeviceFailure:
text += "(Bad:Device Failure";
break;
case TsDaQualityBits.BadSensorFailure:
text += "(Bad:Sensor Failure";
break;
case TsDaQualityBits.BadLastKnownValue:
text += "(Bad:Last Known Value";
break;
case TsDaQualityBits.BadCommFailure:
text += "(Bad:Communication Failure";
break;
case TsDaQualityBits.BadOutOfService:
text += "(Bad:Out of Service";
break;
case TsDaQualityBits.BadWaitingForInitialData:
text += "(Bad:Waiting for Initial Data";
break;
case TsDaQualityBits.Uncertain:
text += "(Uncertain";
break;
case TsDaQualityBits.UncertainLastUsableValue:
text += "(Uncertain:Last Usable Value";
break;
case TsDaQualityBits.UncertainSensorNotAccurate:
text += "(Uncertain:Sensor not Accurate";
break;
case TsDaQualityBits.UncertainEUExceeded:
text += "(Uncertain:Engineering Unit exceeded";
break;
case TsDaQualityBits.UncertainSubNormal:
text += "(Uncertain:Sub Normal";
break;
}
if (LimitBits != TsDaLimitBits.None)
{
text += $":[{LimitBits.ToString()}]";
}
else
{
text += ":Not Limited";
}
if (VendorBits != 0)
{
text += $":{VendorBits,0:X})";
}
else
{
text += ")";
}
return text;
}
/// <summary>
/// Determines whether the specified Object is equal to the current Quality
/// </summary>
public override bool Equals(object target)
{
if (target == null || target.GetType() != typeof(TsCDaQuality)) return false;
var quality = (TsCDaQuality)target;
if (QualityBits != quality.QualityBits) return false;
if (LimitBits != quality.LimitBits) return false;
if (VendorBits != quality.VendorBits) return false;
return true;
}
/// <summary>
/// Returns hash code for the current Quality.
/// </summary>
public override int GetHashCode()
{
return GetCode();
}
#endregion
}
}

View File

@@ -0,0 +1,114 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// <para>Defines the possible quality status bits.</para>
/// <para>These flags represent the quality state for an item's data value. This is
/// intended to be similar to but slightly simpler than the Field-bus Data Quality
/// Specification (section 4.4.1 in the H1 Final Specifications). This design makes it
/// fairly easy for both servers and client applications to determine how much
/// functionality they want to implement.</para>
/// </summary>
public enum TsDaQualityBits
{
/// <summary>The Quality of the value is Good.</summary>
Good = 0x000000C0,
/// <summary>The value has been Overridden. Typically this means the input has been disconnected and a manually entered value has been 'forced'.</summary>
GoodLocalOverride = 0x000000D8,
/// <summary>The value is bad but no specific reason is known.</summary>
Bad = 0x00000000,
/// <summary>
/// There is some server specific problem with the configuration. For example the
/// item in question has been deleted from the configuration.
/// </summary>
BadConfigurationError = 0x00000004,
/// <summary>
/// The input is required to be logically connected to something but is not. This
/// quality may reflect that no value is available at this time, for reasons like the value
/// may have not been provided by the data source.
/// </summary>
BadNotConnected = 0x00000008,
/// <summary>A device failure has been detected.</summary>
BadDeviceFailure = 0x0000000c,
/// <summary>
/// A sensor failure had been detected (the Limits field can provide additional
/// diagnostic information in some situations).
/// </summary>
BadSensorFailure = 0x00000010,
/// <summary>
/// Communications have failed. However, the last known value is available. Note that
/// the age of the value may be determined from the time stamp in the item state.
/// </summary>
BadLastKnownValue = 0x00000014,
/// <summary>Communications have failed. There is no last known value is available.</summary>
BadCommFailure = 0x00000018,
/// <summary>
/// The block is off scan or otherwise locked. This quality is also used when the
/// active state of the item or the subscription containing the item is InActive.
/// </summary>
BadOutOfService = 0x0000001C,
/// <summary>
/// After Items are added to a subscription, it may take some time for the server to
/// actually obtain values for these items. In such cases the client might perform a read
/// (from cache), or establish a ConnectionPoint based subscription and/or execute a
/// Refresh on such a subscription before the values are available. This sub-status is only
/// available from OPC DA 3.0 or newer servers.
/// </summary>
BadWaitingForInitialData = 0x00000020,
/// <summary>There is no specific reason why the value is uncertain.</summary>
Uncertain = 0x00000040,
/// <summary>
/// Whatever was writing this value has stopped doing so. The returned value should
/// be regarded as stale. Note that this differs from a BAD value with sub-status
/// badLastKnownValue (Last Known Value). That status is associated specifically with a
/// detectable communications error on a fetched value. This error is associated with the
/// failure of some external source to put something into the value within an acceptable
/// period of time. Note that the age of the value can be determined from the time stamp
/// in the item state.
/// </summary>
UncertainLastUsableValue = 0x00000044,
/// <summary>
/// Either the value has pegged at one of the sensor limits (in which case the
/// limit field should be set to low or high) or the sensor is otherwise known to be out of
/// calibration via some form of internal diagnostics (in which case the limit field should
/// be none).
/// </summary>
UncertainSensorNotAccurate = 0x00000050,
/// <summary>
/// The returned value is outside the limits defined for this parameter. Note that in
/// this case (per the Field-bus Specification) the Limits field indicates which limit has
/// been exceeded but does NOT necessarily imply that the value cannot move farther out of
/// range.
/// </summary>
UncertainEUExceeded = 0x00000054,
/// <summary>
/// The value is derived from multiple sources and has less than the required number
/// of Good sources.
/// </summary>
UncertainSubNormal = 0x00000058
}
}

View File

@@ -0,0 +1,40 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Defines bit masks for the quality.
/// </summary>
public enum TsDaQualityMasks : int
{
/// <summary>Quality related bits</summary>
QualityMask = +0x00FC,
/// <summary>Limit related bits</summary>
LimitMask = +0x0003,
/// <summary>Vendor specific bits</summary>
VendorMask = -0x00FD
}
}

View File

@@ -0,0 +1,70 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Describes the state of a subscription.
/// </summary>
[Serializable]
public class TsCDaRequest : IOpcRequest
{
#region Fields
private ITsCDaSubscription subscription_;
private object handle_;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object with a subscription and a unique id.
/// </summary>
public TsCDaRequest(ITsCDaSubscription subscription, object handle)
{
subscription_ = subscription;
handle_ = handle;
}
#endregion
#region Properties
/// <summary>
/// The subscription processing the request.
/// </summary>
public ITsCDaSubscription Subscription => subscription_;
/// <summary>
/// An unique identifier, assigned by the client, for the request.
/// </summary>
public object Handle => handle_;
#endregion
#region Public Methods
/// <summary>
/// Cancels the request, if possible.
/// </summary>
public void Cancel(TsCDaCancelCompleteEventHandler callback) { subscription_.Cancel(this, callback); }
#endregion
}
}

View File

@@ -0,0 +1,75 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Filters applied by the server before returning item results.
/// </summary>
[Flags]
public enum TsCDaResultFilter
{
/// <summary>
/// Include the ItemName in the ItemIdentifier if bit is set.
/// </summary>
ItemName = 0x01,
/// <summary>
/// Include the ItemPath in the ItemIdentifier if bit is set.
/// </summary>
ItemPath = 0x02,
/// <summary>
/// Include the ClientHandle in the ItemIdentifier if bit is set.
/// </summary>
ClientHandle = 0x04,
/// <summary>
/// Include the Timestamp in the ItemValue if bit is set.
/// </summary>
ItemTime = 0x08,
/// <summary>
/// Include verbose, localized error text with result if bit is set.
/// </summary>
ErrorText = 0x10,
/// <summary>
/// Include additional diagnostic information with result if bit is set.
/// </summary>
DiagnosticInfo = 0x20,
/// <summary>
/// Include the ItemName and Timestamp if bit is set.
/// </summary>
Minimal = ItemName | ItemTime,
/// <summary>
/// Include all information in the results if bit is set.
/// </summary>
All = 0x3F
}
}

View File

@@ -0,0 +1,500 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Runtime.Serialization;
using System.Collections.Generic;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// This class is the main interface to access an OPC Data Access server.
/// </summary>
[Serializable]
public class TsCDaServer : OpcServer, ITsDaServer
{
#region Names Class
/// <summary>A set of names for fields used in serialization.</summary>
private class Names
{
internal const string Filters = "Filters";
internal const string Subscriptions = "Subscription";
}
#endregion
#region Fields
/// <summary>
/// A list of subscriptions for the server.
/// </summary>
private TsCDaSubscriptionCollection subscriptions_ = new TsCDaSubscriptionCollection();
/// <summary>
/// The local copy of the result filters.
/// </summary>
private int filters_ = (int)TsCDaResultFilter.All | (int)TsCDaResultFilter.ClientHandle;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes the object.
/// </summary>
public TsCDaServer()
{
}
/// <summary>
/// Initializes the object with a factory and a default OpcUrl.
/// </summary>
/// <param name="factory">The OpcFactory used to connect to remote servers.</param>
/// <param name="url">The network address of a remote server.</param>
public TsCDaServer(OpcFactory factory, OpcUrl url)
:
base(factory, url)
{
}
/// <summary>
/// Constructs a server by de-serializing its OpcUrl from the stream.
/// </summary>
protected TsCDaServer(SerializationInfo info, StreamingContext context)
:
base(info, context)
{
filters_ = (int)info.GetValue(Names.Filters, typeof(int));
var subscriptions = (TsCDaSubscription[])info.GetValue(Names.Subscriptions, typeof(TsCDaSubscription[]));
if (subscriptions != null)
{
Array.ForEach(subscriptions, subscription => subscriptions_.Add(subscription));
}
}
#endregion
#region Properties
/// <summary>
/// Returns an array of all subscriptions for the server.
/// </summary>
public TsCDaSubscriptionCollection Subscriptions => subscriptions_;
/// <summary>
/// The current result filters applied by the server.
/// </summary>
public int Filters => filters_;
#endregion
#region Class properties serialization helpers
/// <summary>Serializes a server into a stream.</summary>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(Names.Filters, filters_);
TsCDaSubscription[] subscriptions = null;
if (subscriptions_.Count > 0)
{
subscriptions = new TsCDaSubscription[subscriptions_.Count];
for (var ii = 0; ii < subscriptions.Length; ii++)
{
subscriptions[ii] = subscriptions_[ii];
}
}
info.AddValue(Names.Subscriptions, subscriptions);
}
#endregion
#region Public Methods
/// <summary>Returns an unconnected copy of the server with the same OpcUrl.</summary>
public override object Clone()
{
// clone the base object.
var clone = (TsCDaServer)base.Clone();
// clone subscriptions.
if (clone.subscriptions_ != null)
{
var subscriptions = new TsCDaSubscriptionCollection();
foreach (TsCDaSubscription subscription in clone.subscriptions_)
{
subscriptions.Add(subscription.Clone());
}
clone.subscriptions_ = subscriptions;
}
// return clone.
return clone;
}
/// <summary>Connects to the server with the specified OpcUrl and credentials.</summary>
/// <exception caption="OpcResultException Class" cref="OpcResultException">If an OPC specific error occur this exception is raised. The Result field includes then the OPC specific code.</exception>
/// <param name="url">The network address of the remote server.</param>
/// <param name="connectData">Any protocol configuration or user authentication information.</param>
public override void Connect(OpcUrl url, OpcConnectData connectData)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
// connect to server.
base.Connect(url, connectData);
// all done if no subscriptions.
if (subscriptions_ == null)
{
return;
}
// create subscriptions (should only happen if server has been deserialized).
var subscriptions = new TsCDaSubscriptionCollection();
foreach (TsCDaSubscription template in subscriptions_)
{
// create subscription for template.
try
{
subscriptions.Add(EstablishSubscription(template));
}
catch
{
// Ignore exceptions here
}
}
// save new set of subscriptions.
subscriptions_ = subscriptions;
}
/// <summary>Disconnects from the server and releases all network resources.</summary>
public override void Disconnect()
{
if (Server == null) throw new NotConnectedException();
// dispose of all subscriptions first.
if (subscriptions_ != null)
{
foreach (TsCDaSubscription subscription in subscriptions_)
{
subscription.Dispose();
}
subscriptions_ = null;
}
// disconnect from server.
base.Disconnect();
}
/// <summary>Returns the filters applied by the server to any item results returned to the client.</summary>
/// <returns>A bit mask indicating which fields should be returned in any item results.</returns>
public int GetResultFilters()
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
// update local cache.
filters_ = ((ITsDaServer)Server).GetResultFilters();
// return filters.
return filters_;
}
/// <summary>Sets the filters applied by the server to any item results returned to the client.</summary>
/// <param name="filters">A bit mask indicating which fields should be returned in any item results.</param>
public void SetResultFilters(int filters)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
// set filters on server.
((ITsDaServer)Server).SetResultFilters(filters);
// cache updated filters.
filters_ = filters;
}
/// <summary>Returns the current server status.</summary>
/// <returns>The current server status.</returns>
public OpcServerStatus GetServerStatus()
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
var status = ((ITsDaServer)Server).GetServerStatus();
if (status != null)
{
if (status.StatusInfo == null)
{
status.StatusInfo = GetString($"serverState.{status.ServerState}");
}
}
else
{
throw new NotConnectedException();
}
return status;
}
/// <summary>Reads the current values for a set of items.</summary>
/// <returns>The results of the read operation for each item.</returns>
/// <requirements>OPC XML-DA Server or OPC Data Access Server V3.x</requirements>
/// <param name="items">The set of items to read.</param>
public TsCDaItemValueResult[] Read(TsCDaItem[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
return ((ITsDaServer)Server).Read(items);
}
/// <summary>Writes the value, quality and timestamp for a set of items.</summary>
/// <returns>The results of the write operation for each item.</returns>
/// <requirements>OPC XML-DA Server or OPC Data Access Server V3.x</requirements>
/// <param name="items">The set of item values to write.</param>
public OpcItemResult[] Write(TsCDaItemValue[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
return ((ITsDaServer)Server).Write(items);
}
/// <summary>
/// Creates a new subscription.
/// </summary>
/// <returns>The new subscription object.</returns>
/// <requirements>OPC XML-DA Server or OPC Data Access Server V2.x / V3.x</requirements>
/// <param name="state">The initial state of the subscription.</param>
public virtual ITsCDaSubscription CreateSubscription(TsCDaSubscriptionState state)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (state == null) throw new ArgumentNullException(nameof(state));
if (Server == null) throw new NotConnectedException();
// create subscription on server.
var subscription = ((ITsDaServer)Server).CreateSubscription(state);
// set filters.
subscription.SetResultFilters(filters_);
// append new subscription to existing list.
var subscriptions = new TsCDaSubscriptionCollection();
if (subscriptions_ != null)
{
foreach (TsCDaSubscription value in subscriptions_)
{
subscriptions.Add(value);
}
}
subscriptions.Add(CreateSubscription(subscription));
// save new subscription list.
subscriptions_ = subscriptions;
// return new subscription.
return subscriptions_[subscriptions_.Count - 1];
}
/// <summary>
/// Creates a new instance of the appropriate subscription object.
/// </summary>
/// <param name="subscription">The remote subscription object.</param>
protected virtual TsCDaSubscription CreateSubscription(ITsCDaSubscription subscription)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
return new TsCDaSubscription(this, subscription);
}
/// <summary>Cancels a subscription and releases all resources allocated for it.</summary>
/// <requirements>OPC XML-DA Server or OPC Data Access Server V2.x / V3.x</requirements>
/// <param name="subscription">The subscription to cancel.</param>
public virtual void CancelSubscription(ITsCDaSubscription subscription)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (subscription == null) throw new ArgumentNullException(nameof(subscription));
if (Server == null) throw new NotConnectedException();
// validate argument.
if (!typeof(TsCDaSubscription).IsInstanceOfType(subscription))
{
throw new ArgumentException(@"Incorrect object type.", nameof(subscription));
}
if (!Equals(((TsCDaSubscription)subscription).Server))
{
throw new ArgumentException(@"Server subscription.", nameof(subscription));
}
// search for subscription in list of subscriptions.
var subscriptions = new TsCDaSubscriptionCollection();
foreach (TsCDaSubscription current in subscriptions_)
{
if (!subscription.Equals(current))
{
subscriptions.Add(current);
}
}
// check if subscription was not found.
if (subscriptions.Count == subscriptions_.Count)
{
throw new ArgumentException(@"Subscription not found.", nameof(subscription));
}
// remove subscription from list of subscriptions.
subscriptions_ = subscriptions;
// cancel subscription on server.
((ITsDaServer)Server).CancelSubscription(((TsCDaSubscription)subscription).Subscription);
}
/// <summary>Fetches all the children of the root branch that meet the filter criteria.</summary>
/// <returns>The set of elements found.</returns>
/// <requirements>OPC Data Access Server V2.x / V3.x</requirements>
/// <param name="filters">The filters to use to limit the set of child elements returned.</param>
private TsCDaBrowseElement[] Browse(
TsCDaBrowseFilters filters)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
TsCDaBrowsePosition position;
var elementsList = new List<TsCDaBrowseElement>();
var elements = ((ITsDaServer)Server).Browse(null, filters, out position);
if (elements != null)
{
Browse(elements, filters, ref elementsList);
}
return elementsList.ToArray();
}
private void Browse(TsCDaBrowseElement[] elements, TsCDaBrowseFilters filters, ref List<TsCDaBrowseElement> elementsList)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
TsCDaBrowsePosition position;
foreach (var element in elements)
{
if (element.HasChildren)
{
var itemId = new OpcItem(element.ItemPath, element.ItemName);
var childElements = ((ITsDaServer)Server).Browse(itemId, filters, out position);
if (childElements != null)
{
Browse(childElements, filters, ref elementsList);
}
}
else
{
elementsList.Add(element);
}
}
}
/// <summary>Fetches the children of a branch that meet the filter criteria.</summary>
/// <returns>The set of elements found.</returns>
/// <requirements>OPC XML-DA Server or OPC Data Access Server V2.x / V3.x</requirements>
/// <param name="itemId">The identifier of branch which is the target of the search.</param>
/// <param name="filters">The filters to use to limit the set of child elements returned.</param>
/// <param name="position">An object used to continue a browse that could not be completed.</param>
public TsCDaBrowseElement[] Browse(
OpcItem itemId,
TsCDaBrowseFilters filters,
out TsCDaBrowsePosition position)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
return ((ITsDaServer)Server).Browse(itemId, filters, out position);
}
/// <summary>Continues a browse operation with previously specified search criteria.</summary>
/// <returns>The set of elements found.</returns>
/// <requirements>OPC XML-DA Server or OPC Data Access Server V2.x / V3.x</requirements>
/// <param name="position">An object containing the browse operation state information.</param>
public TsCDaBrowseElement[] BrowseNext(ref TsCDaBrowsePosition position)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
return ((ITsDaServer)Server).BrowseNext(ref position);
}
/// <summary>Returns the item properties for a set of items.</summary>
/// <param name="itemIds">A list of item identifiers.</param>
/// <param name="propertyIDs">A list of properties to fetch for each item.</param>
/// <param name="returnValues">Whether the property values should be returned with the properties.</param>
/// <returns>A list of properties for each item.</returns>
public TsCDaItemPropertyCollection[] GetProperties(
OpcItem[] itemIds,
TsDaPropertyID[] propertyIDs,
bool returnValues)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (Server == null) throw new NotConnectedException();
return ((ITsDaServer)Server).GetProperties(itemIds, propertyIDs, returnValues);
}
#endregion
#region Private Methods
/// <summary>
/// Establishes a subscription based on the template provided.
/// </summary>
private TsCDaSubscription EstablishSubscription(TsCDaSubscription template)
{
// create subscription.
var subscription = new TsCDaSubscription(this, ((ITsDaServer)Server).CreateSubscription(template.State));
// set filters.
subscription.SetResultFilters(template.Filters);
// add items.
try
{
subscription.AddItems(template.Items);
}
catch
{
subscription.Dispose();
subscription = null;
}
// return new subscription.
return subscription;
}
#endregion
}
}

View File

@@ -0,0 +1,68 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// The set of possible server states.
/// </summary>
public enum TsCDaServerState
{
/// <summary>
/// The server state is not known.
/// </summary>
Unknown,
/// <summary>
/// The server is running normally.
/// </summary>
Running,
/// <summary>
/// The server is not functioning due to a fatal error.
/// </summary>
Failed,
/// <summary>
/// The server cannot load its configuration information.
/// </summary>
NoConfig,
/// <summary>
/// The server has halted all communication with the underlying hardware.
/// </summary>
Suspended,
/// <summary>
/// The server is disconnected from the underlying hardware.
/// </summary>
Test,
/// <summary>
/// The server cannot communicate with the underlying hardware.
/// </summary>
CommFault
}
}

View File

@@ -0,0 +1,92 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Defines masks to be used when modifying the subscription or item state.
/// </summary>
[Flags]
public enum TsCDaStateMask
{
/// <summary>
/// The name of the subscription.
/// </summary>
Name = 0x0001,
/// <summary>
/// The client assigned handle for the item or subscription.
/// </summary>
ClientHandle = 0x0002,
/// <summary>
/// The locale to use for results returned to the client from the subscription.
/// </summary>
Locale = 0x0004,
/// <summary>
/// Whether the item or subscription is active.
/// </summary>
Active = 0x0008,
/// <summary>
/// The maximum rate at which data update notifications are sent.
/// </summary>
UpdateRate = 0x0010,
/// <summary>
/// The longest period between data update notifications.<br/>
/// <strong>Note:</strong> This feature is only supported with OPC Data Access 3.0
/// Servers.
/// </summary>
KeepAlive = 0x0020,
/// <summary>
/// The requested data type for the item.
/// </summary>
ReqType = 0x0040,
/// <summary>
/// The deadband for the item or subscription.
/// </summary>
Deadband = 0x0080,
/// <summary>
/// The rate at which the server should check for changes to an item value.
/// </summary>
SamplingRate = 0x0100,
/// <summary>
/// Whether the server should buffer multiple changes to a single item.
/// </summary>
EnableBuffering = 0x0200,
/// <summary>
/// All fields are valid.
/// </summary>
All = 0xFFFF
}
}

View File

@@ -0,0 +1,571 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Collections;
using System.Runtime.Serialization;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// An in-process object used to access subscriptions on OPC Data Access servers.
/// </summary>
[Serializable]
public class TsCDaSubscription : ITsCDaSubscription, ISerializable, ICloneable
{
#region Names Class
/// <summary>
/// A set of names for fields used in serialization.
/// </summary>
private class Names
{
internal const string State = "State";
internal const string Filters = "Filters";
internal const string Items = "Items";
}
#endregion
#region Fields
private bool disposed_;
/// <summary>
/// The containing server object.
/// </summary>
private TsCDaServer server_;
/// <summary>
/// The remote subscription object.
/// </summary>
internal ITsCDaSubscription Subscription;
/// <summary>
/// The local copy of the subscription state.
/// </summary>
private TsCDaSubscriptionState subscriptionState_ = new TsCDaSubscriptionState();
/// <summary>
/// The local copy of all subscription items.
/// </summary>
private TsCDaItem[] daItems_;
/// <summary>
/// Whether data callbacks are enabled.
/// </summary>
private bool enabled_ = true;
/// <summary>
/// The local copy of the result filters.
/// </summary>
private int filters_ = (int)TsCDaResultFilter.All | (int)TsCDaResultFilter.ClientHandle;
#endregion
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes object with default values.
/// </summary>
public TsCDaSubscription(TsCDaServer server, ITsCDaSubscription subscription)
{
server_ = server ?? throw new ArgumentNullException(nameof(server));
Subscription = subscription ?? throw new ArgumentNullException(nameof(subscription));
GetResultFilters();
GetState();
}
/// <summary>
/// Constructs a server by de-serializing its OpcUrl from the stream.
/// </summary>
protected TsCDaSubscription(SerializationInfo info, StreamingContext context)
{
subscriptionState_ = (TsCDaSubscriptionState)info.GetValue(Names.State, typeof(TsCDaSubscriptionState));
filters_ = (int)info.GetValue(Names.Filters, typeof(int));
daItems_ = (TsCDaItem[])info.GetValue(Names.Items, typeof(TsCDaItem[]));
}
/// <summary>
/// The finalizer implementation.
/// </summary>
~TsCDaSubscription()
{
Dispose(false);
}
/// <summary>
/// This must be called explicitly by clients to ensure the remote server is released.
/// </summary>
public virtual void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">If true managed and unmanaged resources can be disposed. If false only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!disposed_)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
if (Subscription != null)
{
Subscription.Dispose();
server_ = null;
Subscription = null;
daItems_ = null;
}
}
// Release unmanaged resources. If disposing is false,
// only the following code is executed.
}
disposed_ = true;
}
#endregion
#region Properties
/// <summary>
/// The server that the subscription is attached to.
/// </summary>
public TsCDaServer Server => server_;
/// <summary>
/// The name assigned to the subscription by the client.
/// </summary>
public string Name => subscriptionState_.Name;
/// <summary>
/// The handle assigned to the subscription by the client.
/// </summary>
public object ClientHandle => subscriptionState_.ClientHandle;
/// <summary>
/// The handle assigned to the subscription by the server.
/// </summary>
public object ServerHandle => subscriptionState_.ServerHandle;
/// <summary>
/// Whether the subscription is active.
/// </summary>
public bool Active => subscriptionState_.Active;
/// <summary>
/// Whether data callbacks are enabled.
/// </summary>
public bool Enabled => enabled_;
/// <summary>
/// The current locale used by the subscription.
/// </summary>
public string Locale => subscriptionState_.Locale;
/// <summary>
/// The current result filters applied by the subscription.
/// </summary>
public int Filters => filters_;
/// <summary>
/// Returns a copy of the current subscription state.
/// </summary>
public TsCDaSubscriptionState State => (TsCDaSubscriptionState)subscriptionState_.Clone();
/// <summary>
/// The items belonging to the subscription.
/// </summary>
public TsCDaItem[] Items {
get {
if (daItems_ == null) return new TsCDaItem[0];
var items = new TsCDaItem[daItems_.Length];
for (var ii = 0; ii < daItems_.Length; ii++) items[ii] = (TsCDaItem)daItems_[ii].Clone();
return items;
}
}
#endregion
#region Public Methods
/// <summary>
/// Serializes a server into a stream.
/// </summary>
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(Names.State, subscriptionState_);
info.AddValue(Names.Filters, filters_);
info.AddValue(Names.Items, daItems_);
}
/// <summary>
/// Returns an unconnected copy of the subscription with the same items.
/// </summary>
public virtual object Clone()
{
// do a memberwise clone.
var clone = (TsCDaSubscription)MemberwiseClone();
// place clone in disconnected state.
clone.server_ = null;
clone.Subscription = null;
clone.subscriptionState_ = (TsCDaSubscriptionState)subscriptionState_.Clone();
// clear server handles.
clone.subscriptionState_.ServerHandle = null;
// always make cloned subscriptions inactive.
clone.subscriptionState_.Active = false;
// clone items.
if (clone.daItems_ != null)
{
var items = new ArrayList();
Array.ForEach(clone.daItems_, item => items.Add(item.Clone()));
clone.daItems_ = (TsCDaItem[])items.ToArray(typeof(TsCDaItem));
}
// return clone.
return clone;
}
/// <summary>
/// Gets default result filters for the server.
/// </summary>
public int GetResultFilters()
{
filters_ = Subscription.GetResultFilters();
return filters_;
}
/// <summary>
/// Sets default result filters for the server.
/// </summary>
public void SetResultFilters(int filters)
{
Subscription.SetResultFilters(filters);
filters_ = filters;
}
/// <summary>
/// Returns the current subscription state.
/// </summary>
public TsCDaSubscriptionState GetState()
{
subscriptionState_ = Subscription.GetState();
return subscriptionState_;
}
/// <summary>
/// Updates the current subscription state.
/// </summary>
public TsCDaSubscriptionState ModifyState(int masks, TsCDaSubscriptionState state)
{
subscriptionState_ = Subscription.ModifyState(masks, state);
return subscriptionState_;
}
/// <summary>
/// Adds items to the subscription.
/// </summary>
public virtual TsCDaItemResult[] AddItems(TsCDaItem[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (items == null) throw new ArgumentNullException(nameof(items));
// check if there is nothing to do.
if (items.Length == 0)
{
return new TsCDaItemResult[0];
}
// add items.
var results = Subscription.AddItems(items);
if (results == null || results.Length == 0)
{
throw new OpcResultException(new OpcResult(OpcResult.E_FAIL.Code, OpcResult.FuncCallType.SysFuncCall, null), "The browse operation cannot continue");
}
// update locale item list.
var itemList = new ArrayList();
if (daItems_ != null) itemList.AddRange(daItems_);
for (var ii = 0; ii < results.Length; ii++)
{
// check for failure.
if (results[ii].Result.Failed())
{
continue;
}
// create locale copy of the item.
// item name, item path and client handle may not be returned by server.
var item = new TsCDaItem(results[ii]) { ItemName = items[ii].ItemName, ItemPath = items[ii].ItemPath, ClientHandle = items[ii].ClientHandle };
itemList.Add(item);
}
// save the new item list.
daItems_ = (TsCDaItem[])itemList.ToArray(typeof(TsCDaItem));
// update the local state.
GetState();
// return results.
return results;
}
/// <summary>
/// Modifies items that are already part of the subscription.
/// </summary>
public virtual TsCDaItemResult[] ModifyItems(int masks, TsCDaItem[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (items == null) throw new ArgumentNullException(nameof(items));
// check if there is nothing to do.
if (items.Length == 0)
{
return new TsCDaItemResult[0];
}
// modify items.
var results = Subscription.ModifyItems(masks, items);
if (results == null || results.Length == 0)
{
throw new OpcResultException(new OpcResult(OpcResult.E_FAIL.Code, OpcResult.FuncCallType.SysFuncCall, null), "The browse operation cannot continue");
}
// update local item - modify item success means all fields were updated successfully.
for (var ii = 0; ii < results.Length; ii++)
{
// check for failure.
if (results[ii].Result.Failed())
{
continue;
}
// search local item list.
for (var jj = 0; jj < daItems_.Length; jj++)
{
if (daItems_[jj].ServerHandle.Equals(items[ii].ServerHandle))
{
// update locale copy of the item.
// item name, item path and client handle may not be returned by server.
var item = new TsCDaItem(results[ii]) { ItemName = daItems_[jj].ItemName, ItemPath = daItems_[jj].ItemPath, ClientHandle = daItems_[jj].ClientHandle };
daItems_[jj] = item;
break;
}
}
}
// update the local state.
GetState();
// return results.
return results;
}
/// <summary>
/// Removes items from a subscription.
/// </summary>
public virtual OpcItemResult[] RemoveItems(OpcItem[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
if (items == null) throw new ArgumentNullException(nameof(items));
// check if there is nothing to do.
if (items.Length == 0)
{
return new OpcItemResult[0];
}
// remove items from server.
var results = Subscription.RemoveItems(items);
if (results == null || results.Length == 0)
{
throw new OpcResultException(new OpcResult(OpcResult.E_FAIL.Code, OpcResult.FuncCallType.SysFuncCall, null), "The browse operation cannot continue");
}
// remove items from local list if successful.
var itemList = new ArrayList();
foreach (var item in daItems_)
{
var removed = false;
for (var ii = 0; ii < results.Length; ii++)
{
if (item.ServerHandle.Equals(items[ii].ServerHandle))
{
removed = results[ii].Result.Succeeded();
break;
}
}
if (!removed) itemList.Add(item);
}
// update local list.
daItems_ = (TsCDaItem[])itemList.ToArray(typeof(TsCDaItem));
// update the local state.
GetState();
// return results.
return results;
}
/// <summary>
/// Reads a set of subscription items.
/// </summary>
public TsCDaItemValueResult[] Read(TsCDaItem[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
return Subscription.Read(items);
}
/// <summary>
/// Writes a set of subscription items.
/// </summary>
public OpcItemResult[] Write(TsCDaItemValue[] items)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
return Subscription.Write(items);
}
/// <summary>
/// Begins an asynchronous read operation for a set of items.
/// </summary>
/// <param name="items">The set of items to read (must include the item name).</param>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
/// <param name="callback">A delegate used to receive notifications when the request completes.</param>
/// <param name="request">An object that contains the state of the request (used to cancel the request).</param>
/// <returns>A set of results containing any errors encountered when the server validated the items.</returns>
public OpcItemResult[] Read(
TsCDaItem[] items,
object requestHandle,
TsCDaReadCompleteEventHandler callback,
out IOpcRequest request)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
return Subscription.Read(items, requestHandle, callback, out request);
}
/// <summary>
/// Begins an asynchronous write operation for a set of items.
/// </summary>
/// <param name="items">The set of item values to write (must include the item name).</param>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
/// <param name="callback">A delegate used to receive notifications when the request completes.</param>
/// <param name="request">An object that contains the state of the request (used to cancel the request).</param>
/// <returns>A set of results containing any errors encountered when the server validated the items.</returns>
public OpcItemResult[] Write(
TsCDaItemValue[] items,
object requestHandle,
TsCDaWriteCompleteEventHandler callback,
out IOpcRequest request)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
return Subscription.Write(items, requestHandle, callback, out request);
}
/// <summary>
/// Cancels an asynchronous request.
/// </summary>
public void Cancel(IOpcRequest request, TsCDaCancelCompleteEventHandler callback)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
Subscription.Cancel(request, callback);
}
/// <summary>
/// Tells the server to send an data change update for all subscription items.
/// </summary>
public void Refresh() { Subscription.Refresh(); }
/// <summary>
/// Causes the server to send a data changed notification for all active items.
/// </summary>
/// <param name="requestHandle">An identifier for the request assigned by the caller.</param>
/// <param name="request">An object that contains the state of the request (used to cancel the request).</param>
/// <returns>A set of results containing any errors encountered when the server validated the items.</returns>
public void Refresh(
object requestHandle,
out IOpcRequest request)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
Subscription.Refresh(requestHandle, out request);
}
/// <summary>
/// Sets whether data change callbacks are enabled.
/// </summary>
public void SetEnabled(bool enabled)
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
Subscription.SetEnabled(enabled);
enabled_ = enabled;
}
/// <summary>
/// Gets whether data change callbacks are enabled.
/// </summary>
public bool GetEnabled()
{
LicenseHandler.ValidateFeatures(LicenseHandler.ProductFeature.DataAccess);
enabled_ = Subscription.GetEnabled();
return enabled_;
}
#endregion
#region ISubscription
/// <summary>
/// An event to receive data change updates.
/// </summary>
public event TsCDaDataChangedEventHandler DataChangedEvent {
add => Subscription.DataChangedEvent += value;
remove => Subscription.DataChangedEvent -= value;
}
#endregion
}
}

View File

@@ -0,0 +1,316 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Collections;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>A collection of subscriptions.</summary>
[Serializable]
public class TsCDaSubscriptionCollection : ICollection, ICloneable, IList
{
///////////////////////////////////////////////////////////////////////
#region Fields
private ArrayList _subscriptions = new ArrayList();
#endregion
///////////////////////////////////////////////////////////////////////
#region Constructors, Destructor, Initialization
/// <summary>
/// Initializes object with the default values.
/// </summary>
public TsCDaSubscriptionCollection() { }
/// <summary>
/// Initializes object with the specified SubscriptionCollection object.
/// </summary>
public TsCDaSubscriptionCollection(TsCDaSubscriptionCollection subscriptions)
{
if (subscriptions != null)
{
foreach (TsCDaSubscription subscription in subscriptions)
{
Add(subscription);
}
}
}
#endregion
///////////////////////////////////////////////////////////////////////
#region Properties
/// <summary>
/// Gets the item at the specified index.
/// </summary>
public TsCDaSubscription this[int index]
{
get => (TsCDaSubscription)_subscriptions[index];
set => _subscriptions[index] = value;
}
#endregion
///////////////////////////////////////////////////////////////////////
#region ICloneable Members
/// <summary>
/// Creates a deep copy of the object.
/// </summary>
public virtual object Clone()
{
var clone = (TsCDaSubscriptionCollection)MemberwiseClone();
clone._subscriptions = new ArrayList();
foreach (TsCDaSubscription subscription in _subscriptions)
{
clone._subscriptions.Add(subscription.Clone());
}
return clone;
}
#endregion
///////////////////////////////////////////////////////////////////////
#region ICollection Members
/// <summary>
/// Indicates whether access to the ICollection is synchronized (thread-safe).
/// </summary>
public bool IsSynchronized => false;
/// <summary>
/// Gets the number of objects in the collection.
/// </summary>
public int Count => (_subscriptions != null) ? _subscriptions.Count : 0;
/// <summary>
/// Copies the objects to an Array, starting at a the specified index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination for the objects.</param>
/// <param name="index">The zero-based index in the Array at which copying begins.</param>
public void CopyTo(Array array, int index)
{
if (_subscriptions != null)
{
_subscriptions.CopyTo(array, index);
}
}
/// <summary>
/// Copies the objects to an Array, starting at a the specified index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination for the objects.</param>
/// <param name="index">The zero-based index in the Array at which copying begins.</param>
public void CopyTo(TsCDaSubscription[] array, int index)
{
CopyTo((Array)array, index);
}
/// <summary>
/// Indicates whether access to the ICollection is synchronized (thread-safe).
/// </summary>
public object SyncRoot => this;
#endregion
///////////////////////////////////////////////////////////////////////
#region IEnumerable Members
/// <summary>
/// Returns an enumerator that can iterate through a collection.
/// </summary>
/// <returns>An IEnumerator that can be used to iterate through the collection.</returns>
public IEnumerator GetEnumerator()
{
return _subscriptions.GetEnumerator();
}
#endregion
///////////////////////////////////////////////////////////////////////
#region IList Members
/// <summary>
/// Gets a value indicating whether the IList is read-only.
/// </summary>
public bool IsReadOnly => false;
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
object IList.this[int index]
{
get => _subscriptions[index];
set
{
if (!typeof(TsCDaSubscription).IsInstanceOfType(value))
{
throw new ArgumentException("May only add Subscription objects into the collection.");
}
_subscriptions[index] = value;
}
}
/// <summary>
/// Removes the IList subscription at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the subscription to remove.</param>
public void RemoveAt(int index)
{
_subscriptions.RemoveAt(index);
}
/// <summary>
/// Inserts an subscription to the IList at the specified position.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The Object to insert into the IList. </param>
public void Insert(int index, object value)
{
if (!typeof(TsCDaSubscription).IsInstanceOfType(value))
{
throw new ArgumentException("May only add Subscription objects into the collection.");
}
_subscriptions.Insert(index, value);
}
/// <summary>
/// Removes the first occurrence of a specific object from the IList.
/// </summary>
/// <param name="value">The Object to remove from the IList.</param>
public void Remove(object value)
{
_subscriptions.Remove(value);
}
/// <summary>
/// Determines whether the IList contains a specific value.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>true if the Object is found in the IList; otherwise, false.</returns>
public bool Contains(object value)
{
return _subscriptions.Contains(value);
}
/// <summary>
/// Removes all subscriptions from the IList.
/// </summary>
public void Clear()
{
_subscriptions.Clear();
}
/// <summary>
/// Determines the index of a specific subscription in the IList.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
public int IndexOf(object value)
{
return _subscriptions.IndexOf(value);
}
/// <summary>
/// Adds an subscription to the IList.
/// </summary>
/// <param name="value">The Object to add to the IList. </param>
/// <returns>The position into which the new element was inserted.</returns>
public int Add(object value)
{
if (!typeof(TsCDaSubscription).IsInstanceOfType(value))
{
throw new ArgumentException("May only add Subscription objects into the collection.");
}
return _subscriptions.Add(value);
}
/// <summary>
/// Indicates whether the IList has a fixed size.
/// </summary>
public bool IsFixedSize => false;
/// <summary>
/// Inserts an subscription to the IList at the specified position.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The Object to insert into the IList. </param>
public void Insert(int index, TsCDaSubscription value)
{
Insert(index, (object)value);
}
/// <summary>
/// Removes the first occurrence of a specific object from the IList.
/// </summary>
/// <param name="value">The Object to remove from the IList.</param>
public void Remove(TsCDaSubscription value)
{
Remove((object)value);
}
/// <summary>
/// Determines whether the IList contains a specific value.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>true if the Object is found in the IList; otherwise, false.</returns>
public bool Contains(TsCDaSubscription value)
{
return Contains((object)value);
}
/// <summary>
/// Determines the index of a specific subscription in the IList.
/// </summary>
/// <param name="value">The Object to locate in the IList.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
public int IndexOf(TsCDaSubscription value)
{
return IndexOf((object)value);
}
/// <summary>
/// Adds an subscription to the IList.
/// </summary>
/// <param name="value">The Object to add to the IList. </param>
/// <returns>The position into which the new element was inserted.</returns>
public int Add(TsCDaSubscription value)
{
return Add((object)value);
}
#endregion
}
}

View File

@@ -0,0 +1,172 @@
#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// 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.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
#endregion
namespace Technosoftware.DaAeHdaClient.Da
{
/// <summary>
/// Describes the state of a subscription.
/// </summary>
[Serializable]
public class TsCDaSubscriptionState : ICloneable
{
#region Fields
private bool active_ = true;
private int updateRate_ = 500;
private float deadband_;
#endregion
#region Properties
/// <summary>
/// A unique name for the subscription controlled by the client.
/// </summary>
public string Name { get; set; }
/// <summary>
/// A unique identifier for the subscription assigned by the client.
/// </summary>
public object ClientHandle { get; set; }
/// <summary>
/// A unique subscription identifier assigned by the server.
/// </summary>
public object ServerHandle { get; set; }
/// <summary>
/// The locale used for any error messages or results returned to the client.
/// </summary>
public string Locale { get; set; }
/// <summary>
/// Whether the subscription is scanning for updates to send to the client.
/// </summary>
public bool Active
{
get => active_;
set => active_ = value;
}
/// <summary>
/// The rate in milliseconds at which the server checks of updates to send to the
/// client.
/// </summary>
/// <remarks>
/// Client Specifies the fastest rate at which data changes may be sent to the
/// <see cref="TsCDaDataChangedEventHandler">DataChangedHandler</see>
/// for items in this subscription. This also indicates the desired accuracy of Cached
/// Data. This is intended only to control the behavior of the interface. How the
/// server deals with the update rate and how often it actually polls the hardware
/// internally is an implementation detail. Passing 0 indicates the server should use
/// the fastest practical rate.
/// </remarks>
public int UpdateRate
{
get => updateRate_;
set => updateRate_ = value;
}
/// <summary><para>The maximum period in milliseconds between updates sent to the client.</para></summary>
/// <remarks>
/// <para>Clients can set the keep-alive time for a subscription to cause the server to
/// provide client callbacks on the subscription when there are no new events to
/// report. Clients can then be assured of the health of the server and subscription
/// without resorting to pinging the server with calls to GetStatus().</para>
/// <para>Using this facility, a client can expect a callback (data or keep-alive)
/// within the specified keep-alive time.</para>
/// <para>Servers shall reset their keep-alive timers when real data is sent (i.e. it
/// is not acceptable to constantly send the keep-alive callback at a fixed period
/// equal to the keep-alive time irrespective of data callbacks).</para>
/// <para>
/// The keep-alive callback consists of a call to the
/// <see cref="TsCDaDataChangedEventHandler">DataChangedEventHandler</see>
/// with an empty value list.
/// </para>
/// <para>
/// Keep-alive callbacks will not occur when the subscription is inactive.
/// Keep-alive callbacks do not affect the value of the
/// <see cref="OpcServerStatus.LastUpdateTime">LastUpdateTime</see> returned by
/// <see cref="TsCDaServer.GetServerStatus">GetServerStatus()</see> .
/// </para>
/// <para><strong>Available only for OPC Data Access 3.0 and OPC XML-DA
/// servers.</strong></para>
/// </remarks>
public int KeepAlive { get; set; }
/// <summary>
/// The minimum percentage change from 0.0 to 100.0 required to trigger a data update
/// for an item.
/// </summary>
/// <remarks>
/// <para>The range of the Deadband is from 0.0 to 100.0 Percent. Deadband will only
/// apply to items in the subscription that have a dwEUType of Analog available. If the
/// EU Type is Analog, then the EU Low and EU High values for the item can be used to
/// calculate the range for the item. This range will be multiplied with the Deadband
/// to generate an exception limit. An exception is determined as follows:</para>
/// <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
/// <para>Exception if (absolute value of (last cached value - current value) &gt;
/// (pPercentDeadband/100.0) * (EU High - EU Low) )</para>
/// </blockquote>
/// <para>The PercentDeadband can be set when CreateSubscription is called, allowing
/// the same PercentDeadband to be used for all items within that particular
/// subscription. However, with OPC DA 3.0, it is allowable to set the PercentDeadband
/// on a per item basis. This means that each item can potentially override the
/// PercentDeadband set for the subscription it resides within.</para>
/// <para>If the exception limit is exceeded, then the last cached value is updated
/// with the new value and a notification will be sent to the clients callback (if
/// any). The PercentDeadband is an optional behavior for the server. If the client
/// does not specify this value on a server that does support the behavior, the default
/// value of 0 (zero) will be assumed, and all value changes will update the CACHE.
/// Note that the timestamp will be updated regardless of whether the cached value is
/// updated. A server which does not support deadband should return an error
/// (OPC_E_DEADBANDNOTSUPPORTED) if the client requests a deadband other than
/// 0.0.</para>
/// <para>The UpdateRate for a subscription or the sampling rate of the item, if set,
/// determines time between when a value is checked to see if the exception limit has
/// been exceeded. The PercentDeadband is used to keep noisy signals from updating the
/// client unnecessarily.</para>
/// </remarks>
public float Deadband
{
get => deadband_;
set => deadband_ = value;
}
/// <summary>
/// TimeZone Bias of Group (in minutes).
/// </summary>
public int TimeBias { get; set; }
#endregion
#region ICloneable Members
/// <summary>
/// Creates a shallow copy of the object.
/// </summary>
public virtual object Clone()
{
return MemberwiseClone();
}
#endregion
}
}