You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1098 lines
40 KiB
1098 lines
40 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.InteropServices.ComTypes;
|
|
using DataService;
|
|
using OPC.Data.Class;
|
|
using OPC.Data.Enum;
|
|
using OPC.Data.Interface;
|
|
using OPC.Data.Struct;
|
|
|
|
namespace OPCDriver
|
|
{
|
|
public class OPCGroup : IGroup, IOPCDataCallback
|
|
{
|
|
bool _isActive;
|
|
public bool IsActive
|
|
{
|
|
get
|
|
{
|
|
return _isActive;
|
|
}
|
|
set
|
|
{
|
|
//SetActive(value);
|
|
//_isActive = GetState().Active;
|
|
_isActive = value;//OPC 该接口因COM组件的问题导致不能用!
|
|
}
|
|
}
|
|
|
|
int _Id;
|
|
public short ID
|
|
{
|
|
get
|
|
{
|
|
return (short)_Id;
|
|
}
|
|
}
|
|
|
|
int _updateRate;
|
|
public int UpdateRate
|
|
{
|
|
get
|
|
{
|
|
return GetState().UpdateRate;
|
|
}
|
|
set
|
|
{
|
|
SetUpdateRate(value);
|
|
}
|
|
}
|
|
|
|
float _deadBand;
|
|
public float DeadBand
|
|
{
|
|
get
|
|
{
|
|
return GetState().Deadband;
|
|
}
|
|
set
|
|
{
|
|
SetState(new OPCGROUPSTATE { Deadband = value });
|
|
}
|
|
}
|
|
|
|
string _name;
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return _name;
|
|
}
|
|
set
|
|
{
|
|
_name = value;
|
|
}
|
|
}
|
|
|
|
OPCReader _plcReader;
|
|
public IDriver Parent
|
|
{
|
|
get
|
|
{
|
|
return _plcReader;
|
|
}
|
|
}
|
|
|
|
IDataServer _server;
|
|
public IDataServer Server
|
|
{
|
|
get
|
|
{
|
|
return _server;
|
|
}
|
|
}
|
|
|
|
Dictionary<short, ITag> mapping;
|
|
List<ITag> _items;
|
|
public IEnumerable<ITag> Items
|
|
{
|
|
get { return _items; }
|
|
}
|
|
|
|
object _grpObj;
|
|
private IOPCItemMgt _itemMgt;
|
|
private IOPCGroupStateMgt2 _grpState;
|
|
private IOPCAsyncIO3 _async;
|
|
private IOPCSyncIO2 _sync;
|
|
|
|
private void SetState(OPCGROUPSTATE state)
|
|
{
|
|
_grpState.SetState(new int[] { state.UpdateRate },
|
|
out state.UpdateRate, new bool[] { state.Active }, new int[] { state.TimeBias },
|
|
new float[] { state.Deadband }, new int[] { state.LocaleId }, new int[] { state.ClientId });
|
|
}
|
|
|
|
private OPCGROUPSTATE GetState()
|
|
{
|
|
OPCGROUPSTATE state = new OPCGROUPSTATE();
|
|
_grpState.GetState(out state.UpdateRate, out state.Active, out _name,
|
|
out state.TimeBias, out state.Deadband, out state.LocaleId, out state.ClientId, out _Id);
|
|
return state;
|
|
}
|
|
|
|
public int SetActive(bool active)
|
|
{
|
|
int updateRate;
|
|
return _grpState.SetState(null, out updateRate, new bool[] { active }, null, null, null, null);
|
|
}
|
|
|
|
public int SetUpdateRate(int updateRate)
|
|
{
|
|
int revised;
|
|
_grpState.SetState(new int[] { updateRate }, out revised, null, null, null, null, null);
|
|
return revised;
|
|
}
|
|
|
|
public bool AddItems(IList<TagMetaData> items)
|
|
{
|
|
int count = items.Count;
|
|
if (_items == null)
|
|
{
|
|
_items = new List<ITag>(count);
|
|
mapping = new Dictionary<short, ITag>(count);
|
|
}
|
|
List<OPCITEMDEF> itemArray = new List<OPCITEMDEF>(count);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (items[i].GroupID == this._Id)
|
|
{
|
|
itemArray.Add(new OPCITEMDEF { hClient = items[i].ID, szItemID = items[i].Address, bActive = true, wReserved = (short)i });
|
|
}
|
|
}
|
|
IntPtr pAddResults;
|
|
IntPtr pErrors;
|
|
if (!HRESULTS.Succeeded(_itemMgt.AddItems(itemArray.Count, itemArray.ToArray(), out pAddResults, out pErrors)))
|
|
return false;
|
|
int iStructSize = Marshal.SizeOf(typeof(OPCITEMRESULT));
|
|
lock (_server.SyncRoot)
|
|
{
|
|
for (int i = 0; i < itemArray.Count; i++)
|
|
{
|
|
try
|
|
{
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
ITag dataItem = null;
|
|
var itemDef = itemArray[i];
|
|
//string addr = string.Concat(_serverId, ',', Marshal.ReadInt32(pAddResults));
|
|
DataType type = items[itemDef.wReserved].DataType;
|
|
switch (type)
|
|
{
|
|
case DataType.BOOL:
|
|
dataItem = new BoolTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), 1, 0, DataType.BOOL), this);
|
|
break;
|
|
case DataType.BYTE:
|
|
dataItem = new ByteTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), 1, 0, DataType.BYTE), this);
|
|
break;
|
|
case DataType.WORD:
|
|
case DataType.SHORT:
|
|
dataItem = new ShortTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), 2, 0, DataType.SHORT), this);
|
|
break;
|
|
case DataType.INT:
|
|
case DataType.TIME:
|
|
dataItem = new IntTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), 4, 0, DataType.INT), this);
|
|
break;
|
|
case DataType.FLOAT:
|
|
dataItem = new FloatTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), 4, 0, DataType.FLOAT), this);
|
|
break;
|
|
case DataType.SYS:
|
|
case DataType.STR:
|
|
dataItem = new StringTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), 64, 0, DataType.STR), this);
|
|
break;
|
|
default:
|
|
break;
|
|
//case VarEnum.VT_ARRAY:
|
|
// dataItem = new ArrayTag((short)itemDef.hClient, new DeviceAddress(-0x100, 0, 0, Marshal.ReadInt32(pAddResults), (byte)Marshal.ReadInt16(pAddResults + 18), 0, DataType.ARRAY), this);
|
|
// break;
|
|
}
|
|
if (dataItem != null)
|
|
{
|
|
_items.Add(dataItem);
|
|
mapping.Add((short)itemDef.hClient, dataItem);
|
|
_server.AddItemIndex(items[itemDef.wReserved].Name, dataItem);
|
|
}
|
|
pAddResults += iStructSize;
|
|
pErrors += 4;
|
|
}
|
|
}
|
|
catch(Exception err)
|
|
{
|
|
if (err.Message != null) { }
|
|
}
|
|
}
|
|
//Marshal.FreeCoTaskMem(pAddResults);
|
|
//Marshal.FreeCoTaskMem(pErrors);
|
|
_items.TrimExcess();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public bool AddTags(IEnumerable<ITag> tags)
|
|
{
|
|
if (_items == null)
|
|
{
|
|
_items = new List<ITag>();
|
|
}
|
|
foreach (ITag tag in tags)
|
|
{
|
|
if (tag != null)
|
|
{
|
|
_items.Add(tag);
|
|
mapping.Add((short)tag.ID, tag);
|
|
}
|
|
}
|
|
_items.TrimExcess();
|
|
return true;
|
|
}
|
|
|
|
public bool RemoveItems(params ITag[] items)
|
|
{
|
|
int count = items.Length;
|
|
int[] arrSvr = new int[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
ITag item = items[i];
|
|
//if (item == null)
|
|
// return false;
|
|
|
|
arrSvr[i] = item.Address.Start;
|
|
_server.RemoveItemIndex(item.GetTagName());
|
|
_items.Remove(item);
|
|
}
|
|
IntPtr ptrErr;
|
|
int result = _itemMgt.RemoveItems(count, arrSvr, out ptrErr);
|
|
Marshal.FreeCoTaskMem(ptrErr);
|
|
return HRESULTS.Succeeded(result);
|
|
}
|
|
|
|
public bool SetActiveState(bool active, params short[] items)
|
|
{
|
|
int count = items.Length;
|
|
int[] arrSvr = new int[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
ITag item = GetItemByID(items[i]);
|
|
if (item != null)
|
|
arrSvr[i] = item.Address.Start;
|
|
}
|
|
IntPtr ptrErr;
|
|
if (HRESULTS.Succeeded(_itemMgt.SetActiveState(count, arrSvr, active, out ptrErr)))
|
|
{
|
|
Marshal.FreeCoTaskMem(ptrErr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public ITag GetItemByID(short id)
|
|
{
|
|
ITag item = null;
|
|
mapping.TryGetValue(id, out item);
|
|
return item;
|
|
}
|
|
|
|
public ITag FindItemByAddress(DeviceAddress addr)
|
|
{
|
|
int start = addr.Start;
|
|
for (int i = 0; i < _items.Count; i++)
|
|
{
|
|
if (start == _items[i].Address.Start)
|
|
return _items[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public HistoryData[] BatchRead(DataSource source, bool isSync, params ITag[] itemArray)
|
|
{
|
|
IntPtr pErrors;
|
|
int len = itemArray.Length;
|
|
int result = 0;
|
|
int[] arrHSrv = Array.ConvertAll(itemArray, c => c.Address.Start);
|
|
HistoryData[] values = new HistoryData[len];
|
|
if (isSync)
|
|
{
|
|
IntPtr pItemValues;
|
|
result = _sync.Read((OPCDATASOURCE)source, len, arrHSrv, out pItemValues, out pErrors);
|
|
if (HRESULTS.Succeeded(result))
|
|
{
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
var item = itemArray[i];
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
switch (item.Address.VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
values[i].Value.Boolean = Marshal.ReadByte(pItemValues + 16) > 0;
|
|
break;
|
|
case DataType.BYTE:
|
|
values[i].Value.Byte = Marshal.ReadByte(pItemValues + 16);
|
|
break;
|
|
case DataType.WORD:
|
|
case DataType.SHORT:
|
|
values[i].Value.Int16 = Marshal.ReadInt16(pItemValues + 16);
|
|
break;
|
|
case DataType.INT:
|
|
values[i].Value.Int32 = Marshal.ReadInt32(pItemValues + 16);
|
|
break;
|
|
case DataType.FLOAT:
|
|
float[] x = new float[1];
|
|
Marshal.Copy(pItemValues + 16, x, 0, 1);
|
|
values[i].Value.Single = x[0];
|
|
break;
|
|
case DataType.STR:
|
|
string str = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pItemValues + 16));
|
|
StringTag tag = item as StringTag;
|
|
if (tag != null)
|
|
tag.String = str;
|
|
break;
|
|
}
|
|
values[i].ID = item.ID;
|
|
values[i].Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
values[i].TimeStamp = Marshal.ReadInt64(pItemValues + 4).ToDateTime();
|
|
item.Update(values[i].Value, values[i].TimeStamp, values[i].Quality);
|
|
}
|
|
pItemValues += 32;
|
|
pErrors += 4;
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
}
|
|
else
|
|
{
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int cancelID = 0;
|
|
result = _async.Read(len, arrHSrv, 1, out cancelID, out pErrors);
|
|
}
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return values;
|
|
}
|
|
|
|
public int BatchWrite(SortedDictionary<ITag, object> items, bool isSync = true)
|
|
{
|
|
IntPtr pErrors;
|
|
int count = items.Count;
|
|
int i = 0;
|
|
int[] arrHSrv = new int[count];
|
|
object[] arrVal = new object[count];
|
|
foreach (var item in items)
|
|
{
|
|
ITag tag = item.Key;
|
|
if (tag != null)
|
|
{
|
|
//tag.Update(item.Value.ToStorage(), DateTime.Now, QUALITIES.QUALITY_GOOD);
|
|
arrHSrv[i] = tag.Address.Start;
|
|
arrVal[i] = item.Value;
|
|
i++;
|
|
}
|
|
}
|
|
int result = isSync ? _sync.Write(count, arrHSrv, arrVal, out pErrors)
|
|
: _async.Write(count, arrHSrv, arrVal, 1, out i, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return result;
|
|
}
|
|
|
|
public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
ItemData<int> rt = new ItemData<int>();
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
rt.TimeStamp = Marshal.ReadInt64(pItemValues + 4);
|
|
rt.Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_I4 || vt == VarEnum.VT_UI4)
|
|
{
|
|
rt.Value = Marshal.ReadInt32(pItemValues + 24);
|
|
}
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
ItemData<short> rt = new ItemData<short>();
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
rt.TimeStamp = Marshal.ReadInt64(pItemValues + 4);
|
|
rt.Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_I2 || vt == VarEnum.VT_UI2)
|
|
rt.Value = Marshal.ReadInt16(pItemValues + 24);
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
ItemData<byte> rt = new ItemData<byte>();
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
rt.TimeStamp = Marshal.ReadInt64(pItemValues + 4);
|
|
rt.Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_UI1)
|
|
rt.Value = Marshal.ReadByte(pItemValues + 24);
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
ItemData<float> rt = new ItemData<float>();
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
rt.TimeStamp = Marshal.ReadInt64(pItemValues + 4);
|
|
rt.Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_R4)
|
|
{
|
|
float[] x = new float[1];
|
|
Marshal.Copy(pItemValues + 24, x, 0, 1);
|
|
rt.Value = x[0];
|
|
}
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
ItemData<bool> rt = new ItemData<bool>();
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
rt.TimeStamp = Marshal.ReadInt64(pItemValues + 4);
|
|
rt.Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_BOOL)
|
|
rt.Value = Marshal.ReadByte(pItemValues + 24) > 0;
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
ItemData<string> rt = new ItemData<string>();
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
rt.TimeStamp = Marshal.ReadInt64(pItemValues + 4);
|
|
rt.Quality = (QUALITIES)Marshal.ReadInt16(pItemValues + 12);
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_BSTR || vt == VarEnum.VT_LPWSTR)
|
|
rt.Value = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pItemValues + 24));
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public byte[] ReadBytes(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
IntPtr pItemValues;
|
|
IntPtr pErrors;
|
|
byte[] rt = new byte[address.DataSize];
|
|
_sync.Read((OPCDATASOURCE)source, 1, new int[1] { address.Start }, out pItemValues, out pErrors);
|
|
|
|
if (Marshal.ReadInt32(pErrors) == 0)
|
|
{
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pItemValues + 16);
|
|
if (vt == VarEnum.VT_BLOB || vt == VarEnum.VT_ARRAY)
|
|
Marshal.PtrToStructure(Marshal.ReadIntPtr(pItemValues + 24), rt);
|
|
}
|
|
Marshal.FreeCoTaskMem(pItemValues);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteInt32(DeviceAddress address, int value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteInt16(DeviceAddress address, short value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteFloat(DeviceAddress address, float value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteString(DeviceAddress address, string value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteBit(DeviceAddress address, bool value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteBits(DeviceAddress address, byte value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public int WriteBytes(DeviceAddress address, byte[] value)
|
|
{
|
|
IntPtr pErrors;
|
|
int rt = _sync.Write(1, new int[1] { address.Start }, new object[] { value }, out pErrors);
|
|
Marshal.FreeCoTaskMem(pErrors);
|
|
return rt;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
int count = _items.Count;
|
|
int[] arrSvr = new int[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
arrSvr[i] = _items[i].Address.Start;
|
|
}
|
|
_items.Clear();
|
|
IntPtr ptrErr;
|
|
try
|
|
{
|
|
int result = _itemMgt.RemoveItems(count, arrSvr, out ptrErr);
|
|
Marshal.FreeCoTaskMem(ptrErr);
|
|
if (_grpObj != null)
|
|
{
|
|
Marshal.ReleaseComObject(_grpObj);
|
|
}
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
|
|
}
|
|
_grpObj = null;
|
|
_itemMgt = null;
|
|
_grpState = null;
|
|
_async = null;
|
|
_sync = null;
|
|
}
|
|
|
|
public OPCGroup(string name, short Id, int updateRate, float deadband, bool active, object grpObj, OPCReader reader)
|
|
{
|
|
_name = name;
|
|
_Id = Id;
|
|
_updateRate = updateRate;
|
|
_deadBand = deadband;
|
|
_isActive = active;
|
|
_grpObj = grpObj;
|
|
_plcReader = reader;
|
|
_server = reader.Parent;
|
|
_itemMgt = (IOPCItemMgt)_grpObj;
|
|
//_grpState = (IOPCGroupStateMgt2)_grpObj;
|
|
_async = (IOPCAsyncIO3)_grpObj;
|
|
_sync = (IOPCSyncIO2)_grpObj;
|
|
}
|
|
|
|
public void OnDataChange(int dwTransid, int hGroup, int hrMasterquality, int hrMastererror, int dwCount,
|
|
IntPtr phClientItems, IntPtr pvValues, IntPtr pwQualities, IntPtr pftTimeStamps, IntPtr ppErrors)
|
|
{
|
|
if (DataChange == null)
|
|
{
|
|
for (int i = 0; i < dwCount; i++)
|
|
{
|
|
ITag item = GetItemByID(Marshal.ReadInt16(phClientItems));
|
|
if (item == null) continue;
|
|
if (Marshal.ReadInt32(ppErrors) == 0)
|
|
{
|
|
Storage value = Storage.Empty;
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pvValues);
|
|
switch (item.Address.VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
value.Boolean = Marshal.ReadByte(pvValues + 8) > 0;
|
|
break;
|
|
case DataType.BYTE:
|
|
value.Byte = Marshal.ReadByte(pvValues + 8);
|
|
break;
|
|
case DataType.WORD:
|
|
case DataType.SHORT:
|
|
value.Int16 = Marshal.ReadInt16(pvValues + 8);
|
|
break;
|
|
case DataType.INT:
|
|
value.Int32 = Marshal.ReadInt32(pvValues + 8);
|
|
break;
|
|
case DataType.FLOAT:
|
|
if (vt == VarEnum.VT_UI2)
|
|
{
|
|
ushort us =(ushort) Marshal.ReadInt16(pvValues + 8);
|
|
value.Single = Convert.ToSingle(us); ;
|
|
}
|
|
else
|
|
{
|
|
float[] x = new float[1];
|
|
Marshal.Copy(pvValues + 8, x, 0, 1);
|
|
value.Single = x[0];
|
|
}
|
|
break;
|
|
case DataType.SYS:
|
|
case DataType.STR:
|
|
string str = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pvValues + 8));
|
|
StringTag tag = item as StringTag;
|
|
if (tag != null)
|
|
tag.String = str;
|
|
break;
|
|
default:
|
|
value.Boolean = Marshal.ReadByte(pvValues + 8) > 0;
|
|
break;
|
|
}
|
|
item.Update(value, DateTime.FromFileTime(Marshal.ReadInt64(pftTimeStamps)), (QUALITIES)Marshal.ReadInt16(pwQualities));
|
|
}
|
|
ppErrors += 4;
|
|
phClientItems += 4;
|
|
pvValues += 16;
|
|
pwQualities += 2;
|
|
pftTimeStamps += 8;
|
|
}
|
|
}
|
|
else
|
|
FireDataChange(dwTransid, hGroup, hrMasterquality, hrMastererror, dwCount,
|
|
phClientItems, pvValues, pwQualities, pftTimeStamps, ppErrors);
|
|
//Marshal.FreeCoTaskMem(phClientItems);
|
|
//Marshal.FreeCoTaskMem(pvValues);
|
|
//Marshal.FreeCoTaskMem(pwQualities);
|
|
//Marshal.FreeCoTaskMem(pftTimeStamps);
|
|
//Marshal.FreeCoTaskMem(ppErrors);
|
|
}
|
|
|
|
private void FireDataChange(int dwTransid, int hGroup, int hrMasterquality, int hrMastererror, int dwCount,
|
|
IntPtr phClientItems, IntPtr pvValues, IntPtr pwQualities, IntPtr pftTimeStamps, IntPtr ppErrors)
|
|
{
|
|
HistoryData[] clents = new HistoryData[dwCount];
|
|
for (int i = 0; i < dwCount; i++)
|
|
{
|
|
ITag item = GetItemByID(Marshal.ReadInt16(phClientItems));
|
|
if (item == null) continue;
|
|
if (HRESULTS.Succeeded(Marshal.ReadInt32(ppErrors)))
|
|
{
|
|
Storage value = Storage.Empty;
|
|
VarEnum vt = (VarEnum)Marshal.ReadInt32(pvValues);
|
|
switch (item.Address.VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
value.Boolean = Marshal.ReadByte(pvValues + 8) > 0;
|
|
break;
|
|
case DataType.BYTE:
|
|
value.Byte = Marshal.ReadByte(pvValues + 8);
|
|
break;
|
|
case DataType.WORD:
|
|
case DataType.SHORT:
|
|
value.Int16 = Marshal.ReadInt16(pvValues + 8);
|
|
break;
|
|
case DataType.INT:
|
|
value.Int32 = Marshal.ReadInt32(pvValues + 8);
|
|
break;
|
|
case DataType.FLOAT:
|
|
if (vt == VarEnum.VT_UI2)
|
|
{
|
|
ushort us = (ushort)Marshal.ReadInt16(pvValues + 8);
|
|
value.Single = Convert.ToSingle(us);
|
|
}
|
|
else
|
|
{
|
|
float[] x = new float[1];
|
|
Marshal.Copy(pvValues + 8, x, 0, 1);
|
|
value.Single = x[0];
|
|
}
|
|
break;
|
|
case DataType.SYS:
|
|
case DataType.STR:
|
|
string str = Marshal.PtrToStringUni(Marshal.ReadIntPtr(pvValues + 8));
|
|
StringTag tag = item as StringTag;
|
|
if (tag != null)
|
|
tag.String = str;
|
|
break;
|
|
default:
|
|
value.Boolean = Marshal.ReadByte(pvValues + 8) > 0;
|
|
break;
|
|
}
|
|
DateTime time = DateTime.FromFileTime(Marshal.ReadInt64(pftTimeStamps));
|
|
QUALITIES quality = (QUALITIES)Marshal.ReadInt16(pwQualities);
|
|
clents[i].ID = item.ID;
|
|
clents[i].Quality = quality;
|
|
clents[i].Value = value;
|
|
clents[i].TimeStamp = time;
|
|
item.Update(value, time, quality);
|
|
}
|
|
ppErrors += 4;
|
|
phClientItems += 4;
|
|
pvValues += 16;
|
|
pwQualities += 2;
|
|
pftTimeStamps += 8;
|
|
}
|
|
DataChange(this, new DataChangeEventArgs(1, clents));
|
|
}
|
|
|
|
public event DataChangeEventHandler DataChange;
|
|
|
|
|
|
public void OnReadComplete(int dwTransid, int hGroup, int hrMasterquality, int hrMastererror, int dwCount, IntPtr phClientItems, IntPtr pvValues, IntPtr pwQualities, IntPtr pftTimeStamps, IntPtr ppErrors)
|
|
{
|
|
|
|
}
|
|
|
|
public void OnWriteComplete(int dwTransid, int hGroup, int hrMastererr, int dwCount, IntPtr pClienthandles, IntPtr ppErrors)
|
|
{
|
|
|
|
}
|
|
|
|
public void OnCancelComplete(int dwTransid, int hGroup)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
[Description("OPC Client")]
|
|
public class OPCReader : IOPCShutdown, IDriver
|
|
{
|
|
private string _clsidOPCserver, _serverIP;
|
|
private object _opcServerObj;
|
|
private IOPCServer _opcServer;
|
|
private IOPCItemProperties _opcProp;
|
|
private IOPCBrowseServerAddressSpace _opcBrowser;
|
|
private IDataServer _dataServer;
|
|
private IConnectionPoint _shutDownPoint;
|
|
private int _shutDownCookie;
|
|
|
|
public OPCReader(IDataServer dataServer, short id, string name, string serverIP = null,
|
|
int timeout = 0, string clsidOPCserver = "{6E6170F0-FF2D-11D2-8087-00105AA8F840}", string spare2 = null)
|
|
{
|
|
this._id = id;
|
|
this._dataServer = dataServer;
|
|
this._clsidOPCserver = clsidOPCserver;
|
|
this._serverIP = serverIP;
|
|
if (string.IsNullOrEmpty(serverIP)) _serverIP = null;
|
|
this._name = name;
|
|
Connect();
|
|
}
|
|
|
|
public bool Connect()
|
|
{
|
|
if (_opcServerObj != null)
|
|
Dispose();
|
|
Guid cid;
|
|
Type svrComponenttype = Guid.TryParse(_clsidOPCserver, out cid) ? Type.GetTypeFromCLSID(cid, _serverIP, false)
|
|
: Type.GetTypeFromProgID(_clsidOPCserver, _serverIP, false);
|
|
if (svrComponenttype == null)
|
|
return false;
|
|
try
|
|
{
|
|
_opcServerObj = Activator.CreateInstance(svrComponenttype);
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
if (err.Message != null) { }
|
|
return false;
|
|
}
|
|
_opcServer = (IOPCServer)_opcServerObj;
|
|
_opcProp = (IOPCItemProperties)_opcServerObj;
|
|
_opcBrowser = (IOPCBrowseServerAddressSpace)_opcServerObj;
|
|
Guid sinkguid = typeof(IOPCShutdown).GUID;
|
|
((IConnectionPointContainer)_opcServerObj).FindConnectionPoint(ref sinkguid, out _shutDownPoint);
|
|
if (_shutDownPoint == null)
|
|
return false;
|
|
try
|
|
{
|
|
_shutDownPoint.Advise(this, out _shutDownCookie);
|
|
}
|
|
catch (COMException err)
|
|
{
|
|
_opcServerObj = null;
|
|
_opcServer = null;
|
|
_shutDownPoint = null;
|
|
return false;
|
|
}
|
|
if (_metaGroups.Count > 0 && _groups.Count == 0)
|
|
{
|
|
foreach (var metagrp in _metaGroups)
|
|
{
|
|
var grp = AddGroup(metagrp.Name, metagrp.ID, metagrp.UpdateRate, metagrp.DeadBand, metagrp.Active);
|
|
if (grp != null)
|
|
grp.AddItems(_dataServer.MetaDataList);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#region IOPCServer Members
|
|
public List<string> Browse(OPCBROWSETYPE type = OPCBROWSETYPE.OPC_FLAT, string szFilter = "", short typeFilter = 0, OPCACCESSRIGHTS rightFilter = 0)
|
|
{
|
|
if (_opcBrowser == null)
|
|
return null;
|
|
List<string> list = new List<string>(14000);
|
|
OPC.Data.Interface.IEnumString enumerator;
|
|
_opcBrowser.BrowseOPCItemIDs(type, szFilter, typeFilter, rightFilter, out enumerator);
|
|
if (enumerator == null)
|
|
return list;
|
|
|
|
int cft = 0;
|
|
string[] strF = new string[1000];
|
|
do
|
|
{
|
|
enumerator.RemoteNext(1000, strF, out cft);
|
|
for (int i = 0; i < cft; i++)
|
|
list.Add(strF[i]);
|
|
} while (cft > 0);
|
|
Marshal.ReleaseComObject(enumerator);
|
|
enumerator = null;
|
|
list.TrimExcess();
|
|
return list;
|
|
}
|
|
|
|
|
|
public object[] GetItemProperties(string itemID, params int[] propertyIDs)
|
|
{
|
|
int count = propertyIDs.Length;
|
|
if (count < 1)
|
|
return null;
|
|
|
|
IntPtr ptrDat;
|
|
IntPtr ptrErr;
|
|
if (HRESULTS.Succeeded(_opcProp.GetItemProperties(itemID, count, propertyIDs, out ptrDat, out ptrErr)))
|
|
{
|
|
object[] propertiesData = new object[count];
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (Marshal.ReadInt32(ptrErr) == 0)
|
|
{
|
|
propertiesData[i] = Marshal.GetObjectForNativeVariant(ptrDat);
|
|
}
|
|
ptrErr += 4;
|
|
ptrDat += 16;
|
|
}
|
|
|
|
Marshal.FreeCoTaskMem(ptrDat);
|
|
Marshal.FreeCoTaskMem(ptrErr);
|
|
return propertiesData;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IOPCShutdown Members
|
|
public event ShutdownRequestEventHandler OnClose;
|
|
|
|
public void ShutdownRequest(string szReason)
|
|
{
|
|
this.Close();
|
|
if (OnClose != null)
|
|
OnClose(this, new ShutdownRequestEventArgs(szReason));
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
public bool IsClosed
|
|
{
|
|
get { return _opcServerObj == null; }
|
|
}
|
|
|
|
short _id;
|
|
public short ID
|
|
{
|
|
get
|
|
{
|
|
return _id;
|
|
}
|
|
}
|
|
|
|
public int TimeOut
|
|
{
|
|
get { return 0; }
|
|
set { }
|
|
}
|
|
|
|
string _name;
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return _name;
|
|
}
|
|
}
|
|
|
|
public string ServerName
|
|
{
|
|
get
|
|
{
|
|
return _serverIP;
|
|
}
|
|
set
|
|
{
|
|
_serverIP = value;
|
|
}
|
|
}
|
|
|
|
public IDataServer Parent
|
|
{
|
|
get
|
|
{
|
|
return _dataServer;
|
|
}
|
|
}
|
|
|
|
void Close()
|
|
{
|
|
foreach (var grp in _groups.Values)
|
|
{
|
|
(grp.Items as IList<ITag>).Clear();
|
|
}
|
|
_groups.Clear();
|
|
_opcServerObj = null;
|
|
_opcServer = null;
|
|
_shutDownPoint = null;
|
|
_shutDownCookie = 0;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
try
|
|
{
|
|
if (_opcServer != null)
|
|
{
|
|
foreach (var grp in _groups)
|
|
{
|
|
_opcServer.RemoveGroup(grp.Key, true);
|
|
grp.Value.Dispose();
|
|
}
|
|
_groups.Clear();
|
|
}
|
|
if (_shutDownPoint != null)
|
|
{
|
|
if (_shutDownCookie != 0)
|
|
{
|
|
_shutDownPoint.Unadvise(_shutDownCookie);
|
|
}
|
|
Marshal.ReleaseComObject(_shutDownPoint);
|
|
}
|
|
if (_opcServerObj != null)
|
|
{
|
|
Marshal.ReleaseComObject(_opcServerObj);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ShutdownRequest(e.Message);
|
|
}
|
|
_opcServerObj = null;
|
|
_opcServer = null;
|
|
_shutDownPoint = null;
|
|
_shutDownCookie = 0;
|
|
}
|
|
|
|
Dictionary<int, OPCGroup> _groups = new Dictionary<int, OPCGroup>(30);
|
|
public IEnumerable<IGroup> Groups
|
|
{
|
|
get { return _groups.Values; }
|
|
}
|
|
|
|
List<MetaGroup> _metaGroups = new List<MetaGroup>();
|
|
|
|
public IGroup AddGroup(string name, short id, int updateRate, float deadBand, bool active)
|
|
{
|
|
if (!_metaGroups.Exists(x => x.ID == id))
|
|
_metaGroups.Add(new MetaGroup { ID = id, Name = name, UpdateRate = updateRate, DeadBand = deadBand, Active = active });
|
|
if (_opcServer == null) return null;
|
|
GCHandle hDeadband, hTimeBias;
|
|
hDeadband = GCHandle.Alloc(deadBand, GCHandleType.Pinned);
|
|
hTimeBias = GCHandle.Alloc(0, GCHandleType.Pinned);
|
|
Guid iidRequiredInterface = typeof(IOPCItemMgt).GUID;
|
|
int serverId, svrUpdateRate; object grpObj;
|
|
if (HRESULTS.Succeeded(_opcServer.AddGroup(name, active, updateRate, id,
|
|
hTimeBias.AddrOfPinnedObject(), hDeadband.AddrOfPinnedObject(), 0x0,
|
|
out serverId, out svrUpdateRate, ref iidRequiredInterface, out grpObj)))
|
|
{
|
|
IConnectionPointContainer pIConnectionPointContainer = (IConnectionPointContainer)grpObj;
|
|
Guid iid = typeof(IOPCDataCallback).GUID;
|
|
IConnectionPoint pIConnectionPoint;
|
|
pIConnectionPointContainer.FindConnectionPoint(ref iid, out pIConnectionPoint);
|
|
int dwCookie;
|
|
OPCGroup grp = new OPCGroup(name, id, svrUpdateRate, deadBand, active, grpObj, this);
|
|
_groups.Add(serverId, grp);
|
|
pIConnectionPoint.Advise(grp, out dwCookie);
|
|
//OPCGroups.Add(serverId, grp);
|
|
return grp;
|
|
}
|
|
else
|
|
return null;
|
|
}
|
|
|
|
public bool RemoveGroup(IGroup grp)
|
|
{
|
|
if (_opcServer != null)
|
|
{
|
|
foreach (var group in _groups)
|
|
{
|
|
if (group.Value.ID == grp.ID)
|
|
{
|
|
_opcServer.RemoveGroup(group.Key, true);
|
|
group.Value.Dispose();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal class MetaGroup
|
|
{
|
|
public string Name { get; set; }
|
|
public short ID { get; set; }
|
|
public bool Active { get; set; }
|
|
public int UpdateRate { get; set; }
|
|
public float DeadBand { get; set; }
|
|
}
|
|
}
|
|
|