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.

481 lines
15 KiB

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using DataService;
namespace FileDriver
{
[Description("内存映射文件")]
public class MemoryReader : IFileDriver
{
internal struct MemoryVar
{
public DataType VarType;
public ushort Size;
public MemoryVar(DataType varType, ushort size)
{
VarType = varType;
Size = size;
}
}
//共享内存如何释放?还是长久保存在内存中
string _fileName;
public string FileName
{
get
{
return _fileName;
}
set
{
_fileName = value;
}
}
short _id;//内存及文件中的地址与ID相关
public short ID
{
get
{
return _id;
}
}
string _name;
public string Name
{
get
{
return _name;
}
}
string _server;
public string ServerName
{
get
{
return _server;
}
set
{
_server = value;
}
}
public bool IsClosed
{
get { return mapp == null; }
}
int _timeOut;
public int TimeOut
{
get
{
return _timeOut;
}
set
{
_timeOut = value;
}
}
List<IGroup> _groups = new List<IGroup>();
public IEnumerable<IGroup> Groups
{
get { return _groups; }
}
IDataServer _parent;
public IDataServer Parent
{
get { return _parent; }
}
int _count = 0;
MemoryMappedFile mapp = null;
MemoryMappedViewAccessor accessor = null;
SortedList<short, int> psList = new SortedList<short, int>();
public MemoryReader(IDataServer parent, short id, string name)
{
_parent = parent;
_id = id;
_name = name;
}
public bool Connect()
{
try
{
if (File.Exists(_fileName))
{
using (FileStream stream = File.Open(_fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
mapp = MemoryMappedFile.CreateFromFile(stream, _name, 0, MemoryMappedFileAccess.ReadWrite,
new MemoryMappedFileSecurity(), HandleInheritability.Inheritable, false);
using (var reader = new BinaryReader(stream))
{
_count = reader.ReadInt32();
for (int i = 0; i < _count; i++)
{
psList.Add(reader.ReadInt16(), reader.ReadInt32());
}
}
}
}
else
{
int len = 0;
List<MemoryVar> hdata = new List<MemoryVar>();
foreach (IGroup grp in _groups)
{
foreach (ITag tag in grp.Items)
{
_count++;
psList.Add(tag.ID, len);
ushort size = tag.Address.DataSize;
len += 3 + size;
hdata.Add(new MemoryVar(tag.Address.VarType, size));
}
}
if (string.IsNullOrEmpty(_fileName))
{
mapp = MemoryMappedFile.CreateOrOpen(_name, 4 + _count * 6 + len);
using (MemoryMappedViewStream stream = mapp.CreateViewStream())
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(_count);
foreach (var item in psList)
{
writer.Write(item.Key);
writer.Write(item.Value);
}
for (int i = 0; i < _count; i++)
{
writer.Write((byte)hdata[i].VarType);
writer.Write(hdata[i].Size);
writer.Seek(hdata[i].Size, SeekOrigin.Current);
}
}
}
}
else
{
using (FileStream stream = File.Create(_fileName))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(_count);
foreach (var item in psList)
{
writer.Write(item.Key);
writer.Write(item.Value);
}
for (int i = 0; i < _count; i++)
{
writer.Write((byte)hdata[i].VarType);
writer.Write(hdata[i].Size);
writer.Seek(hdata[i].Size, SeekOrigin.Current);
}
}
}
mapp = MemoryMappedFile.CreateFromFile(_fileName, FileMode.Open, _name);
}
}
if (mapp != null)
accessor = mapp.CreateViewAccessor(0, 0);
return true;
}
catch (Exception err)
{
if (OnError != null)
OnError(this, new IOErrorEventArgs(err.Message));
return false;
}
}
long FindPosition(DeviceAddress addr)
{
int offset = psList[(short)addr.CacheIndex];
return offset + 6 * _count + 7;
}
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
FileDeviceGroup grp = new FileDeviceGroup(id, name, updateRate, active, this);
_groups.Add(grp);
return grp;
}
public bool RemoveGroup(IGroup grp)
{
grp.IsActive = false;
return _groups.Remove(grp);
}
public void Dispose()
{
foreach (IGroup grp in _groups)
{
grp.Dispose();
}
_groups.Clear();
if (mapp != null)
{
accessor.Dispose();
mapp.Dispose();
mapp = null;
if (OnError != null)
OnError(this, new IOErrorEventArgs("mapp file closed"));
}
}
public event IOErrorEventHandler OnError;
public byte[] ReadBytes(DeviceAddress address, ushort size)
{
byte[] bytes = new byte[size];
try
{
int result = accessor.ReadArray(FindPosition(address), bytes, 0, size);
return bytes;
}
catch { return null; }
}
public ItemData<int> ReadInt32(DeviceAddress address)
{
try
{
return new ItemData<int>(accessor.ReadInt32(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<int>(0, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<uint> ReadUInt32(DeviceAddress address)
{
try
{
return new ItemData<uint>(accessor.ReadUInt32(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<uint>(0, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<ushort> ReadUInt16(DeviceAddress address)
{
try
{
return new ItemData<ushort>(accessor.ReadUInt16(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<ushort>(0, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<short> ReadInt16(DeviceAddress address)
{
try
{
return new ItemData<short>(accessor.ReadInt16(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<short>(0, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<byte> ReadByte(DeviceAddress address)
{
try
{
return new ItemData<byte>(accessor.ReadByte(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<byte>(0, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<string> ReadString(DeviceAddress address, ushort size)
{
try
{
byte[] bytes = new byte[size];
int result = accessor.ReadArray(FindPosition(address), bytes, 0, bytes.Length);
return new ItemData<string>(Encoding.ASCII.GetString(bytes), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<string>(null, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<float> ReadFloat(DeviceAddress address)
{
try
{
return new ItemData<float>(accessor.ReadSingle(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<float>(0f, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<bool> ReadBit(DeviceAddress address)
{
try
{
return new ItemData<bool>(accessor.ReadBoolean(FindPosition(address)), 0, QUALITIES.QUALITY_GOOD);
}
catch { return new ItemData<bool>(false, 0, QUALITIES.QUALITY_BAD); }
}
public ItemData<object> ReadValue(DeviceAddress address)
{
return this.ReadValueEx(address);
}
public int WriteBytes(DeviceAddress address, byte[] bit)
{
try
{
accessor.WriteArray(FindPosition(address), bit, 0, bit.Length);
return 0;
}
catch { return -1; }
}
public int WriteBit(DeviceAddress address, bool bit)
{
try
{
accessor.Write(FindPosition(address), bit);
return 0;
}
catch { return -1; }
}
public int WriteBits(DeviceAddress address, byte bits)
{
try
{
accessor.Write(FindPosition(address), bits);
return 0;
}
catch { return -1; }
}
public int WriteInt16(DeviceAddress address, short value)
{
try
{
accessor.Write(FindPosition(address), value);
return 0;
}
catch { return -1; }
}
public int WriteUInt16(DeviceAddress address, ushort value)
{
try
{
accessor.Write(FindPosition(address), value);
return 0;
}
catch { return -1; }
}
public int WriteUInt32(DeviceAddress address, uint value)
{
try
{
accessor.Write(FindPosition(address), value);
return 0;
}
catch { return -1; }
}
public int WriteInt32(DeviceAddress address, int value)
{
try
{
accessor.Write(FindPosition(address), value);
return 0;
}
catch { return -1; }
}
public int WriteFloat(DeviceAddress address, float value)
{
try
{
accessor.Write(FindPosition(address), value);
return 0;
}
catch { return -1; }
}
public int WriteString(DeviceAddress address, string str)
{
try
{
return WriteBytes(address, Encoding.ASCII.GetBytes(str));
}
catch { return -1; }
}
public int WriteValue(DeviceAddress address, object value)
{
try
{
return this.WriteValueEx(address, value);
}
catch { return -1; }
}
public int Limit
{
get { return _count; }
}
public FileData[] ReadAll(short groupId)
{
if (mapp == null) return null;
FileData[] hdata = new FileData[_count];
for (int i = 0; i < _count; i++)
{
int pos = 4 + i * 6;
hdata[i].ID = accessor.ReadInt16(pos);
pos = accessor.ReadInt32(pos + 2);
DataType type = (DataType)accessor.ReadByte(pos);
pos++;
byte len = accessor.ReadByte(pos);
pos++;
switch (type)
{
case DataType.BOOL:
hdata[i].Value.Boolean = accessor.ReadBoolean(pos);
break;
case DataType.BYTE:
hdata[i].Value.Byte = accessor.ReadByte(pos);
break;
case DataType.WORD:
hdata[i].Value.Word = accessor.ReadUInt16(pos);
break;
case DataType.SHORT:
hdata[i].Value.Int16 = accessor.ReadInt16(pos);
break;
case DataType.DWORD:
hdata[i].Value.DWord = accessor.ReadUInt32(pos);
break;
case DataType.INT:
hdata[i].Value.Int32 = accessor.ReadInt32(pos);
break;
case DataType.FLOAT:
hdata[i].Value.Single = accessor.ReadSingle(pos);
break;
case DataType.STR:
byte[] bytes = new byte[len];
accessor.ReadArray(pos, bytes, 0, len);
hdata[i].Text = Encoding.ASCII.GetString(bytes);
break;
}
}
return hdata;
}
}
}