C# SCADA
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.

637 lines
22 KiB

using System;
using System.Collections.Generic;
using System.Threading;
using DataService;
namespace FileDriver
{
public class FileDeviceGroup : IGroup
{
//可采用定期轮询和消息通知改变两种方式
bool _isActive;
public bool IsActive
{
get
{
return _isActive;
}
set
{
_isActive = value;
if (value)
{
ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(this.OnUpdate), 1);
}
else
Update();
}
}
private void OnUpdate(object stateInfo)
{
while (true)
{
Thread.Sleep(_updateRate);
lock (this)
{
if (!_isActive)
{
return;
}
Update();
}
}
}
public void Update()
{
DateTime dt = DateTime.Now;
FileData[] list = _fileReader.ReadAll(_id);
if (list != null)
{
if (DataChange != null)
{
List<HistoryData> hdata = new List<HistoryData>();
foreach (ITag tag in _items)
{
int index = Array.BinarySearch(list, new FileData { ID = tag.ID });
if (index >= 0)
{
FileData data = list[index];
if (tag.Address.VarType == DataType.STR)
{
if (data.Text != tag.ToString())
{
(tag as StringTag).String = data.Text;
tag.Update(Storage.Empty, dt, QUALITIES.QUALITY_GOOD);
}
continue;
}
if (tag.Value != data.Value)
{
tag.Update(data.Value, dt, QUALITIES.QUALITY_GOOD);
hdata.Add(new HistoryData(data.ID, QUALITIES.QUALITY_GOOD, data.Value, dt));
}
}
}
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
{
deleg.BeginInvoke(this, new DataChangeEventArgs(1, hdata), null, null);
}
}
else
{
foreach (ITag tag in _items)
{
int index = Array.BinarySearch(list, new FileData { ID = tag.ID });
if (index >= 0)
{
if (tag.Value != list[index].Value)
{
tag.Update(list[index].Value, dt, QUALITIES.QUALITY_GOOD);
}
}
}
}
}
}
short _id;
public short ID
{
get
{
return _id;
}
}
int _updateRate;
public int UpdateRate
{
get
{
return _updateRate;
}
set
{
_updateRate = value;
}
}
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
float deadband;
public float DeadBand
{
get
{
return deadband;
}
set
{
deadband = value;
}
}
IFileDriver _fileReader;
public IDriver Parent
{
get
{
return _fileReader;
}
}
List<ITag> _items;
public IEnumerable<ITag> Items
{
get { return _items; }
}
IDataServer _server;
public IDataServer Server
{
get
{
return _server;
}
}
public FileDeviceGroup(short id, string name, int updateRate, bool active, IFileDriver plcReader)
{
this._id = id;
this._updateRate = updateRate;
this._isActive = active;
this._fileReader = plcReader;
this._name = name;
this._server = _fileReader.Parent;
}
public bool AddItems(IList<TagMetaData> items)
{
int count = items.Count;
if (_items == null) _items = new List<ITag>();
lock (_server.SyncRoot)
{
int j = 0;
for (int i = 0; i < count; i++)
{
ITag dataItem = null;
TagMetaData meta = items[i];
if (meta.GroupID == this._id)
{
DeviceAddress addr = new DeviceAddress(-1, (ushort)meta.GroupID, (ushort)meta.ID, j++, meta.Size, 0, meta.DataType);
switch (meta.DataType)
{
case DataType.BOOL:
dataItem = new BoolTag(meta.ID, addr, this);
break;
case DataType.BYTE:
dataItem = new ByteTag(meta.ID, addr, this);
break;
case DataType.WORD:
case DataType.SHORT:
dataItem = new ShortTag(meta.ID, addr, this);
break;
case DataType.TIME:
case DataType.INT:
dataItem = new IntTag(meta.ID, addr, this);
break;
case DataType.FLOAT:
dataItem = new FloatTag(meta.ID, addr, this);
break;
case DataType.STR:
dataItem = new StringTag(meta.ID, addr, this);
break;
default:
dataItem = new BoolTag(meta.ID, addr, this);
break;
}
_items.Add(dataItem);
_server.AddItemIndex(meta.Name, dataItem);
}
}
}
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);
}
}
return true;
}
public bool RemoveItems(params ITag[] items)
{
foreach (var item in items)
{
_server.RemoveItemIndex(item.GetTagName());
_items.Remove(item);
}
return true;
}
public bool SetActiveState(bool active, params short[] items)
{
return true;
}
public ITag FindItemByAddress(DeviceAddress addr)
{
int id = addr.CacheIndex;
for (int i = 0; i < _items.Count; i++)
{
if (id == _items[i].Address.CacheIndex)
return _items[i];
}
return null;
}
public virtual HistoryData[] BatchRead(DataSource source, bool isSync, params ITag[] itemArray)
{
int len = itemArray.Length;
HistoryData[] values = new HistoryData[len];
if (source == DataSource.Device)
{
IMultiReadWrite multi = _fileReader as IMultiReadWrite;
if (multi != null)
{
var itemArr = multi.ReadMultiple(Array.ConvertAll(itemArray, x => x.Address));
for (int i = 0; i < len; i++)
{
values[i].ID = itemArray[i].ID;
values[i].Value = itemArr[i].Value;
values[i].Quality = itemArr[i].Quality;
values[i].TimeStamp = itemArr[i].TimeStamp.ToDateTime();
itemArray[i].Update(itemArr[i].Value, values[i].TimeStamp, itemArr[i].Quality);
}
}
else
{
for (int i = 0; i < len; i++)
{
itemArray[i].Refresh(source);
values[i].ID = itemArray[i].ID;
values[i].Value = itemArray[i].Value;
values[i].Quality = itemArray[i].Quality;
values[i].TimeStamp = itemArray[i].TimeStamp;
}
}
}
else
{
for (int i = 0; i < len; i++)
{
values[i].ID = itemArray[i].ID;
values[i].Value = itemArray[i].Value;
values[i].Quality = itemArray[i].Quality;
values[i].TimeStamp = itemArray[i].TimeStamp;
}
}
return values;
}
public virtual int BatchWrite(SortedDictionary<ITag, object> items, bool isSync = true)
{
int len = items.Count;
int rev = 0;
IMultiReadWrite multi = _fileReader as IMultiReadWrite;
if (DataChange == null)
{
if (multi != null)
{
DeviceAddress[] addrs = new DeviceAddress[len];
object[] objs = new object[len];
int i = 0;
foreach (var item in items)
{
addrs[i] = item.Key.Address;
objs[i] = item.Value;
i++;
}
return multi.WriteMultiple(addrs, objs);
}
else
{
foreach (var tag in items)
{
tag.Key.Write(tag.Value);
}
return 0;
}
}
else
{
HistoryData[] data = new HistoryData[len];
int i = 0;
if (multi != null)
{
DeviceAddress[] addrs = new DeviceAddress[len];
object[] objs = new object[len];
foreach (var item in items)
{
ITag tag = item.Key;
addrs[i] = tag.Address;
objs[i] = item.Value;
data[i].ID = tag.ID;
data[i].TimeStamp = tag.TimeStamp;
data[i].Quality = tag.Quality;
data[i].Value = item.Key.ToStorage(item.Value);
i++;
}
rev = multi.WriteMultiple(addrs, objs);
}
else
{
foreach (var item in items)
{
ITag tag = item.Key;
if (tag.Write(tag.Value) >= 0)
{
data[i].ID = tag.ID;
data[i].TimeStamp = tag.TimeStamp;
data[i].Quality = tag.Quality;
data[i].Value = item.Key.ToStorage(item.Value);
i++;
}
}
}
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
{
deleg.BeginInvoke(this, new DataChangeEventArgs(1, data), null, null);
}
}
return rev;
}
public bool RecieveData(string data)//when sendmessge arrived WM_COPYDATA
{
int index = data.IndexOf('#');//格式:GroupID#TagID:Value|TagID:Value|TagID:Value
if (index > 0 && data.Substring(0, index) == _id.ToString())
{
string[] strs = data.Right(index).Split('|');
HistoryData[] hdata = new HistoryData[strs.Length];
DateTime date = DateTime.Now;
int i = 0;
foreach (string d in strs)
{
int ind = d.IndexOf(':');
if (ind > 0)
{
short tid;
if (short.TryParse(data.Substring(0, ind), out tid))
{
ITag tag = _server[tid];
if (tag != null)
{
Storage value = Storage.Empty;
DataType type = tag.Address.VarType;
switch (type)
{
case DataType.BOOL:
value.Boolean = Convert.ToBoolean(d.Right(ind));
break;
case DataType.BYTE:
value.Byte = Convert.ToByte(d.Right(ind));
break;
case DataType.WORD:
case DataType.SHORT:
value.Int16 = Convert.ToInt16(d.Right(ind));
break;
case DataType.TIME:
case DataType.INT:
value.Int32 = Convert.ToInt32(d.Right(ind));
break;
case DataType.FLOAT:
value.Single = Convert.ToSingle(d.Right(ind));
break;
case DataType.STR:
break;
}
tag.Update(value, date, QUALITIES.QUALITY_GOOD);//也可以不传值,tag自身refresh
hdata[i].ID = tag.ID;
hdata[i].Value = value;
hdata[i].TimeStamp = date;
hdata[i].Quality = QUALITIES.QUALITY_GOOD;
}
}
}
i++;
}
if (DataChange != null)
{
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
{
deleg.BeginInvoke(this, new DataChangeEventArgs(1, hdata), null, null);
}
}
return true;
}
return false;
}
public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
{
if (source == DataSource.Device) return _fileReader.ReadInt32(address);
else
{
ITag tag = _items[address.Start];
return new ItemData<int>(tag.Value.Int32, 0, tag.Quality);
}
}
public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
{
if (source == DataSource.Device) return _fileReader.ReadInt16(address);
else
{
ITag tag = _items[address.Start];
return new ItemData<short>(tag.Value.Int16, 0, tag.Quality);
}
}
public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
{
if (source == DataSource.Device) return _fileReader.ReadByte(address);
else
{
ITag tag = _items[address.Start];
return new ItemData<byte>(tag.Value.Byte, 0, tag.Quality);
}
}
public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
{
if (source == DataSource.Device) return _fileReader.ReadFloat(address);
else
{
ITag tag = _items[address.Start];
return new ItemData<float>(tag.Value.Single, 0, tag.Quality);
}
}
public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
{
if (source == DataSource.Device) return _fileReader.ReadBit(address);
else
{
ITag tag = _items[address.Start];
return new ItemData<bool>(tag.Value.Boolean, 0, tag.Quality);
}
}
public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
{
if (source == DataSource.Device) return _fileReader.ReadString(address, address.DataSize);
else
{
StringTag tag = _items[address.Start] as StringTag;
return tag == null ? new ItemData<string>(null, 0, QUALITIES.QUALITY_BAD) :
new ItemData<string>(tag.String, 0, tag.Quality);
}
}
public int WriteInt32(DeviceAddress address, int value)
{
int rs = _fileReader.WriteInt32(address, value);
if (rs >= 0)
{
Storage stor = new Storage { Int32 = value };
_items[address.Start].Update(stor, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
{
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData( (short)address.CacheIndex,QUALITIES.QUALITY_GOOD,stor, DateTime.Now)
}));
}
}
return rs;
}
public int WriteInt16(DeviceAddress address, short value)
{
int rs = _fileReader.WriteInt16(address, value);
if (rs >= 0)
{
Storage stor = new Storage { Int16 = value };
_items[address.Start].Update(stor, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
{
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData( (short)address.CacheIndex,QUALITIES.QUALITY_GOOD,stor, DateTime.Now)
}));
}
}
return rs;
}
public int WriteFloat(DeviceAddress address, float value)
{
int rs = _fileReader.WriteFloat(address, value);
if (rs >= 0)
{
Storage stor = new Storage { Single = value };
_items[address.Start].Update(stor, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
{
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData( (short)address.CacheIndex,QUALITIES.QUALITY_GOOD,stor, DateTime.Now)
}));
}
}
return rs;
}
public int WriteString(DeviceAddress address, string value)
{
int rs = _fileReader.WriteString(address, value);
if (rs >= 0)
{
StringTag tag = _items[address.Start] as StringTag;
if (tag != null && tag.String != value)
{
tag.String = value;
tag.Update(Storage.Empty, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
{
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData( (short)address.CacheIndex,tag.Quality,Storage.Empty, DateTime.Now)
}));
}
}
}
return rs;
}
public int WriteBit(DeviceAddress address, bool value)
{
int rs = _fileReader.WriteBit(address, value);
if (rs >= 0)
{
Storage stor = new Storage { Boolean = value };
_items[address.Start].Update(stor, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
{
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData( (short)address.CacheIndex,QUALITIES.QUALITY_GOOD,stor, DateTime.Now)
}));
}
}
return rs;
}
public int WriteBits(DeviceAddress address, byte value)
{
int rs = _fileReader.WriteBits(address, value);
if (rs >= 0)
{
Storage stor = new Storage { Byte = value };
_items[address.Start].Update(stor, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
{
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData( (short)address.CacheIndex,QUALITIES.QUALITY_GOOD,stor, DateTime.Now)
}));
}
}
return rs;
}
public void Dispose()
{
_items = null;
}
public event DataChangeEventHandler DataChange;
}
}