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.
743 lines
24 KiB
743 lines
24 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Text;
|
|
using DataService;
|
|
|
|
namespace DDEDriver
|
|
{
|
|
[Description("DDE 通讯协议")]
|
|
public class DDEReader : IDriver
|
|
{
|
|
//DDE用常量定义#region DDE用常量定义
|
|
/**/
|
|
/// <summary>
|
|
/// ///////////////////////////////////////////////////////////////////////////
|
|
/// /***** conversation states (usState) *****/
|
|
/**/
|
|
/// </summary>
|
|
private int dwDDEInst; // DDE Instance value
|
|
private IntPtr hconvCurrent;
|
|
//private bool bAutoConnect;
|
|
|
|
//public string LinkDesc;
|
|
private DdeCallback _Callback;
|
|
|
|
short _id;
|
|
public string LinkName;
|
|
|
|
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; }
|
|
}
|
|
|
|
string _topic;
|
|
public string Topic
|
|
{
|
|
get
|
|
{
|
|
return _topic;
|
|
}
|
|
set
|
|
{
|
|
_topic = value;
|
|
}
|
|
}
|
|
|
|
internal bool _connected;
|
|
public bool IsClosed
|
|
{
|
|
get { return !_connected; }
|
|
}
|
|
|
|
int _timeOut;
|
|
public int TimeOut
|
|
{
|
|
get { return _timeOut; }
|
|
set { _timeOut = value; }
|
|
}
|
|
|
|
List<IGroup> _groups = new List<IGroup>(3);
|
|
public IEnumerable<IGroup> Groups
|
|
{
|
|
get { return _groups; }
|
|
}
|
|
|
|
IDataServer _parent;
|
|
public IDataServer Parent
|
|
{
|
|
get { return _parent; }
|
|
}
|
|
|
|
public DDEValueChangeEventHandler DDEValueChange;
|
|
|
|
public DDEReader(IDataServer parent, short id, string name, string server, int timeOut = 2000, string topic = null, string spare2 = null)
|
|
{
|
|
_id = id;
|
|
_parent = parent;
|
|
_name = name;
|
|
_server = server;
|
|
_timeOut = timeOut;
|
|
_topic = topic;
|
|
LinkName = _server + "|" + _topic;
|
|
_Callback = DdeClientCallback;
|
|
}
|
|
|
|
public unsafe bool Connect()
|
|
{
|
|
IntPtr hConv, hszService, hszTopic;
|
|
|
|
if (dwDDEInst != 0)
|
|
{
|
|
Ddeml.DdeUninitialize(dwDDEInst);
|
|
dwDDEInst = 0;
|
|
}
|
|
if (hconvCurrent != IntPtr.Zero)
|
|
{
|
|
Ddeml.DdeDisconnect(hconvCurrent);
|
|
hconvCurrent = IntPtr.Zero;
|
|
};
|
|
//如果是第一次,则什么也不做
|
|
Ddeml.DdeInitialize(ref dwDDEInst, _Callback, 0x3f000, 0);
|
|
// Connect to the server
|
|
hszTopic = Ddeml.DdeCreateStringHandle(dwDDEInst, _topic, Ddeml.CP_WINANSI);
|
|
hszService = Ddeml.DdeCreateStringHandle(dwDDEInst, _server, Ddeml.CP_WINANSI);
|
|
CONVCONTEXT cc = new CONVCONTEXT();
|
|
cc.cb = sizeof(CONVCONTEXT);
|
|
hConv = Ddeml.DdeConnect(dwDDEInst, hszService, hszTopic, ref cc);
|
|
//int DdeErrcode = Win32.DdeGetLastError(dwDDEInst);
|
|
|
|
Ddeml.DdeFreeStringHandle(dwDDEInst, hszTopic);
|
|
Ddeml.DdeFreeStringHandle(dwDDEInst, hszService);
|
|
|
|
if (hConv != IntPtr.Zero)
|
|
{
|
|
if (hconvCurrent != IntPtr.Zero)
|
|
{
|
|
Ddeml.DdeDisconnect(hconvCurrent);
|
|
}
|
|
hconvCurrent = hConv;
|
|
_connected = true;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
_connected = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private IntPtr DdeClientCallback(int uType, ConversionFormat uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, uint dwData1, uint dwData2)
|
|
{
|
|
int dwLength = 0;
|
|
//DateTime time = DateTime.Now;
|
|
unsafe
|
|
{
|
|
switch (uType)
|
|
{
|
|
case Ddeml.XTYP_ADVDATA:
|
|
try
|
|
{
|
|
sbyte* pData = (sbyte*)Ddeml.DdeAccessData(hData, ref dwLength);
|
|
if (pData != null)
|
|
{
|
|
sbyte* pSZ = stackalloc sbyte[0xFF];
|
|
Ddeml.DdeQueryString(dwDDEInst, hsz2, pSZ, 0xFF, Ddeml.CP_WINANSI);
|
|
if (DDEValueChange != null)
|
|
DDEValueChange(this, new DDEValueChangeEventArgs(new string(pSZ).ToUpper(), new string(pData, 0, dwLength)));
|
|
}
|
|
}
|
|
catch { }
|
|
finally
|
|
{
|
|
if (hData != IntPtr.Zero) Ddeml.DdeUnaccessData(hData);
|
|
}
|
|
break;
|
|
case Ddeml.XTYP_DISCONNECT:
|
|
if (OnError != null)
|
|
OnError(this, new IOErrorEventArgs("XTYP_DISCONNECT"));
|
|
_connected = false;
|
|
break;
|
|
case Ddeml.XTYP_XACT_COMPLETE:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return new IntPtr(Ddeml.DDE_FACK);
|
|
}
|
|
|
|
//与Server建立Hoot连接
|
|
public unsafe bool TransactItem(string name)
|
|
{
|
|
IntPtr hszItem, hDDEData;
|
|
int dwResult = 0;
|
|
if (string.IsNullOrEmpty(name)) return false;
|
|
if (hconvCurrent != IntPtr.Zero)
|
|
{
|
|
hszItem = Ddeml.DdeCreateStringHandle(dwDDEInst, name, Ddeml.CP_WINANSI);
|
|
|
|
hDDEData = Ddeml.DdeClientTransaction(null,
|
|
0,
|
|
hconvCurrent,
|
|
hszItem,
|
|
ConversionFormat.TEXT,//CF_TEXT,
|
|
Ddeml.XTYP_ADVSTART,
|
|
Ddeml.TIMEOUT_ASYNC, // ms timeout
|
|
ref dwResult);
|
|
|
|
Ddeml.DdeFreeStringHandle(dwDDEInst, hszItem);
|
|
|
|
if (hDDEData != IntPtr.Zero)
|
|
{
|
|
try
|
|
{
|
|
int dwLength = 0;
|
|
sbyte* pData = (sbyte*)Ddeml.DdeAccessData(hDDEData, ref dwLength);
|
|
if ((pData != null) && (dwLength != 0))
|
|
{
|
|
if (DDEValueChange != null)
|
|
DDEValueChange(this, new DDEValueChangeEventArgs(name, new string(pData, 0, dwLength)));
|
|
}
|
|
}
|
|
catch { }
|
|
finally
|
|
{
|
|
Ddeml.DdeUnaccessData(hDDEData);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
public int Execute(string command)
|
|
{
|
|
int res = 0;
|
|
byte[] data = Encoding.ASCII.GetBytes(command);
|
|
Ddeml.DdeClientTransaction(data, data.Length, hconvCurrent, IntPtr.Zero, ConversionFormat.NONE, Ddeml.XTYP_EXECUTE, _timeOut, ref res);
|
|
return res;
|
|
}
|
|
|
|
//必须设置item.ItemName和item.ItemValue后调用
|
|
public int Poke(string name, string value)
|
|
{
|
|
IntPtr hszItem, hDDEData;
|
|
int dwResult = 0;
|
|
if (string.IsNullOrEmpty(name)) return -2;
|
|
if (hconvCurrent != IntPtr.Zero)
|
|
{
|
|
hszItem = Ddeml.DdeCreateStringHandle(dwDDEInst, name, Ddeml.CP_WINANSI);
|
|
if (!string.IsNullOrEmpty(name))
|
|
{
|
|
//int errcode=Win32.DdeGetLastError(dwDDEInst);
|
|
byte[] ByteArray = Encoding.ASCII.GetBytes(value);
|
|
IntPtr hd = Ddeml.DdeCreateDataHandle(dwDDEInst, ByteArray, ByteArray.Length, 0, hszItem, ConversionFormat.TEXT, 0);
|
|
hDDEData = Ddeml.DdeClientTransaction(
|
|
ByteArray, ByteArray.Length,
|
|
hconvCurrent, hszItem,
|
|
ConversionFormat.TEXT,//CF_TEXT,
|
|
Ddeml.XTYP_POKE,
|
|
Ddeml.TIMEOUT_ASYNC, // ms timeout
|
|
ref dwResult);
|
|
Ddeml.DdeFreeStringHandle(dwDDEInst, hszItem);
|
|
|
|
if (hDDEData != IntPtr.Zero)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// [10/24/2003]
|
|
//主动请求Item的值
|
|
public unsafe string Request(string name)
|
|
{
|
|
IntPtr hszItem, hDDEData;
|
|
int dwResult = 0;
|
|
int dwLength = 0;
|
|
if (name != null && hconvCurrent != IntPtr.Zero)
|
|
{
|
|
hszItem = Ddeml.DdeCreateStringHandle(dwDDEInst, name, Ddeml.CP_WINANSI);
|
|
|
|
hDDEData = Ddeml.DdeClientTransaction(null,
|
|
0,
|
|
hconvCurrent,
|
|
hszItem,
|
|
ConversionFormat.TEXT,//CF_TEXT,
|
|
(int)Ddeml.XTYP_REQUEST,
|
|
5000, // ms timeout
|
|
ref dwResult);
|
|
Ddeml.DdeFreeStringHandle(dwDDEInst, hszItem);
|
|
|
|
if (hDDEData != IntPtr.Zero)
|
|
{
|
|
sbyte* pData = (sbyte*)Ddeml.DdeAccessData(hDDEData, ref dwLength);
|
|
{
|
|
if ((pData != null) && (dwLength != 0))
|
|
{
|
|
return new string(pData, 0, dwLength);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
|
|
{
|
|
if (_groups.Count > 0)
|
|
return null;
|
|
DDEGroup grp = new DDEGroup(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();
|
|
Ddeml.DdeDisconnect(hconvCurrent);
|
|
}
|
|
|
|
public event IOErrorEventHandler OnError;
|
|
}
|
|
|
|
public class DDEGroup : IGroup
|
|
{
|
|
bool _isActive;
|
|
public bool IsActive
|
|
{
|
|
get
|
|
{
|
|
return _isActive;
|
|
}
|
|
set
|
|
{
|
|
_isActive = value;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
DDEReader _plcReader;
|
|
public IDriver Parent
|
|
{
|
|
get
|
|
{
|
|
return _plcReader;
|
|
}
|
|
}
|
|
|
|
|
|
List<short> _changedList;
|
|
public List<short> ChangedList
|
|
{
|
|
get
|
|
{
|
|
return _changedList;
|
|
}
|
|
}
|
|
|
|
|
|
List<ITag> _items;
|
|
public IEnumerable<ITag> Items
|
|
{
|
|
get { return _items; }
|
|
}
|
|
|
|
IDataServer _server;
|
|
public IDataServer Server
|
|
{
|
|
get
|
|
{
|
|
return _server;
|
|
}
|
|
}
|
|
|
|
Dictionary<short, string> _mapping;
|
|
|
|
public DDEGroup(short id, string address, int updateRate, bool active, DDEReader plcReader)
|
|
{
|
|
this._id = id;
|
|
this._updateRate = updateRate;
|
|
this._isActive = active;
|
|
this._plcReader = plcReader;
|
|
this._name = address;
|
|
this._server = _plcReader.Parent;
|
|
this._changedList = new List<short>(100);
|
|
plcReader.DDEValueChange += new DDEValueChangeEventHandler(plcReader_DDEValueChange);
|
|
}
|
|
|
|
void plcReader_DDEValueChange(object sender, DDEValueChangeEventArgs e)
|
|
{
|
|
string name = e.Name;
|
|
string data = e.Data;
|
|
ITag tag = _server[name];
|
|
if (tag != null)
|
|
{
|
|
Storage value = Storage.Empty;
|
|
switch (tag.Address.VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
value.Boolean = bool.Parse(data);
|
|
break;
|
|
case DataType.BYTE:
|
|
value.Byte = byte.Parse(data);
|
|
break;
|
|
case DataType.WORD:
|
|
case DataType.SHORT:
|
|
value.Int16 = short.Parse(data);
|
|
break;
|
|
case DataType.INT:
|
|
value.Int32 = int.Parse(data);
|
|
break;
|
|
case DataType.STR:
|
|
var stag = tag as StringTag;
|
|
if (stag != null)
|
|
{
|
|
stag.String = data;
|
|
}
|
|
break;
|
|
}
|
|
tag.Update(value, DateTime.Now, QUALITIES.QUALITY_GOOD);
|
|
if (DataChange != null)
|
|
DataChange(this, new DataChangeEventArgs(1, new HistoryData[]{
|
|
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,tag.Value,tag.TimeStamp)}));
|
|
}
|
|
}
|
|
|
|
|
|
public bool AddItems(IList<TagMetaData> items)
|
|
{
|
|
int count = items.Count;
|
|
if (_items == null)
|
|
{
|
|
_items = new List<ITag>(count);
|
|
_mapping = new Dictionary<short, string>(count);
|
|
}
|
|
lock (_server.SyncRoot)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
ITag dataItem = null;
|
|
TagMetaData meta = items[i];
|
|
if (meta.GroupID == this._id)
|
|
{
|
|
DeviceAddress addr = new DeviceAddress { Start = meta.ID, DataSize = meta.Size, VarType = 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.DWORD:
|
|
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;
|
|
}
|
|
if (dataItem != null)
|
|
{
|
|
//dataItem.Active = meta.Active;
|
|
_items.Add(dataItem);
|
|
_plcReader.TransactItem(meta.Name);
|
|
_mapping.Add(meta.ID, meta.Address);
|
|
_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());
|
|
_mapping.Remove(item.ID);
|
|
_items.Remove(item);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool SetActiveState(bool active, params short[] items)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public ITag FindItemByAddress(DeviceAddress addr)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public ITag GetItemByID(short id)
|
|
{
|
|
return _server[id];
|
|
}
|
|
|
|
public HistoryData[] BatchRead(DataSource source, bool isSync, params ITag[] itemArray)
|
|
{
|
|
return ExtMethods.BatchRead(source, itemArray);
|
|
}
|
|
|
|
public int BatchWrite(SortedDictionary<ITag, object> items, bool isSync = true)
|
|
{
|
|
int rev = ExtMethods.BatchWrite(items);
|
|
if (DataChange != null && rev >= 0)
|
|
{
|
|
int len = items.Count;
|
|
HistoryData[] data = new HistoryData[len];
|
|
int i = 0;
|
|
foreach (var item in items)
|
|
{
|
|
ITag tag = item.Key;
|
|
data[i].ID = tag.ID;
|
|
data[i].TimeStamp = tag.TimeStamp;
|
|
data[i].Quality = tag.Quality;
|
|
//data[i].Value = item.Value.ToStorge();
|
|
i++;
|
|
}
|
|
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
|
|
{
|
|
deleg.BeginInvoke(this, new DataChangeEventArgs(1, data), null, null);
|
|
}
|
|
}
|
|
return rev;
|
|
}
|
|
|
|
public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<int>(0, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<int>(int.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<short>(0, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<short>(short.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<uint> ReadUInt32(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<uint>(0, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<uint>(uint.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<ushort> ReadUInt16(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<ushort>(0, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<ushort>(ushort.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<byte>(0, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<byte>(byte.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<float>(0, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<float>(float.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<bool>(false, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<bool>(bool.Parse(data), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
|
|
{
|
|
string data = _plcReader.Request(_mapping[(short)address.Start]);
|
|
return string.IsNullOrEmpty(data) ? new ItemData<string>(null, 0, QUALITIES.QUALITY_BAD) :
|
|
new ItemData<string>(data, 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
|
|
public int WriteInt32(DeviceAddress address, int value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public int WriteInt16(DeviceAddress address, short value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public int WriteUInt32(DeviceAddress address, uint value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public int WriteUInt16(DeviceAddress address, ushort value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public int WriteFloat(DeviceAddress address, float value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public int WriteString(DeviceAddress address, string value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value);
|
|
}
|
|
|
|
public int WriteBit(DeviceAddress address, bool value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public int WriteBits(DeviceAddress address, byte value)
|
|
{
|
|
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
|
|
}
|
|
|
|
public event DataChangeEventHandler DataChange;
|
|
|
|
public void Dispose()
|
|
{
|
|
_plcReader.DDEValueChange -= new DDEValueChangeEventHandler(plcReader_DDEValueChange);
|
|
_items.Clear();
|
|
_mapping.Clear();
|
|
_items = null;
|
|
_mapping = null;
|
|
}
|
|
}
|
|
|
|
public delegate void DDEValueChangeEventHandler(object sender, DDEValueChangeEventArgs e);
|
|
|
|
public class DDEValueChangeEventArgs : EventArgs
|
|
{
|
|
public DDEValueChangeEventArgs(string name, string data)
|
|
{
|
|
this.Name = name;
|
|
this.Data = data;
|
|
}
|
|
|
|
public string Name;
|
|
public string Data;
|
|
}
|
|
}
|
|
|