using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.ComponentModel; using Misc; namespace FLY.Modbus { public class ClientTCP:IModbusClient, INotifyPropertyChanged { private int maxConCurrTrans = 1; /// /// 最大同时处理交易数 /// public int MaxConCurrTrans { set { maxConCurrTrans = value; } get { return maxConCurrTrans; } } /// /// 当前交易数 /// public int ConCurrTrans { get { return Transactions.Count(); } } TCPManager.TCPCConn mTCPCConn; /// /// 错误事件 /// public event Action ErrorEvent; /// /// 连接成功? /// public bool IsConnected { get { return mTCPCConn.IsConnected; } } /// /// 标识,modbus tcp的参数 /// public byte UnitID = 1; /// /// /// /// public ClientTCP(IPAddress ip):this(new IPEndPoint(ip,502)) { } /// /// /// /// public ClientTCP(IPEndPoint ep):this(ep,1) { } public override string ToString() { return mTCPCConn.RemoteEP.ToString(); } /// /// /// /// /// public ClientTCP(IPEndPoint ep,byte unitid) { mTCPCConn = new TCPManager.TCPCConn(ep, ParsePacketInClient); mTCPCConn.Enable = true; mTCPCConn.ConnectEvent += new Action(mTCPCConn_ConnectEvent); MaxConCurrTrans = 1; UnitID = unitid; } void mTCPCConn_ConnectEvent(TCPManager.TCPConn obj) { //清空全部tranid Transactions.Clear(); NotifyPropertyChanged("IsConnected"); } /// /// 从异端接收的数据,解释数据 /// /// /// /// int ParsePacketInClient(TCPManager.TCPConn conn, byte[] inBuf) { //格式—————————————— //MBAP //域 长度 描述 //事务标识符 2byte MODBUS请求/响应的识别码 //协议标识符 2byte 0=MODBUS协议 //——长度— 2byte 以下字节的数量 //单元标识符 1byte 串行链路或其它总线过来的识别码 //PDU //功能码—— 1byte //数据 nbyte int startIndex=0; do { Pack_Proto p = new Pack_Proto(); int rlen; if (!p.TryParse(inBuf, startIndex, inBuf.Length, out rlen)) { //处理失败 return startIndex; } ParsePacket(conn, p); startIndex += rlen; } while (startIndex < inBuf.Length); return startIndex; } void ParsePacket(TCPManager.TCPConn conn, Pack_Proto p) { if (Misc.MyBase.CHECKBIT(p.func, 7)) { //出错!!! if (ErrorEvent != null) ErrorEvent(p); //根据tranid 找回 Transaction Transactions.RemoveAll(_t => _t.tranid == p.tranid); } //if (p.func == 0x01 || p.func == 0x03) { //根据tranid 找回 Transaction var tlist = from _t in Transactions where _t.tranid == p.tranid select _t; if (tlist.Count() > 0) { Transaction t = tlist.First(); t.ParsePacket(p); //if( (p.func == 0x05) || (p.func==0x01)) // Misc.Log.LogMessage("ReadCoilsAction", 0, "Receive Transid = {0} func= {1}",t.tranid, p.func); Transactions.RemoveAll(_t => _t.tranid == p.tranid); } } } class Transaction { public UInt16 tranid; public object AsyncDelegate; public object AsyncState; public Action ParsePacket; } List Transactions = new List(); UInt16 tranid = 12; UInt16 GetFreeTranID() { tranid++; return tranid; } /// /// 读多个 COIL /// /// /// /// /// /// public ModbusClient_Errno Do_01(UInt16 addr, UInt16 cnt, Action AsyncDelegate, object AsyncState) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); data.AddRange(cnt.GetBytes_Big_endian()); Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = AsyncDelegate; t.AsyncState = AsyncState; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x01) { //有问题!!!触发异常事件 return; } List blist = new List(); int byte_len = p.buf[0]; int index = 1; for (int i = 0; i < byte_len; i++) { for (int j = 0; j < 8; j++) { if (Misc.MyBase.CHECKBIT(p.buf[index], j)) blist.Add(true); else blist.Add(false); if (blist.Count() >= cnt) { //完成 i = byte_len; break; } } index++; } Transactions.Remove(t); //Misc.Log.LogMessage("ReadCoilsAction", 0, "Receive Coils Transid = "+p.tranid.ToString()); ((Action)t.AsyncDelegate)(blist.ToArray(), t.AsyncState); }); Transactions.Add(t); //Misc.Log.LogMessage("ReadCoilsAction", 0, "Send Coils Transid = " + t.tranid.ToString()); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x01, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// 读多个REG /// /// /// /// /// /// public ModbusClient_Errno Do_03(UInt16 addr, UInt16 cnt, Action AsyncDelegate, object AsyncState) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); data.AddRange(cnt.GetBytes_Big_endian()); Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = AsyncDelegate; t.AsyncState = AsyncState; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x03) { //有问题!!!触发异常事件 return; } List blist = new List(); int index = 1; while(index)t.AsyncDelegate)(blist.ToArray(), t.AsyncState); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x03, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// Write Single Coil /// /// /// /// public ModbusClient_Errno Do_05(UInt16 addr, bool dat) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); if (dat) data.Add(0xff); else data.Add(0); data.Add(0); Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = null; t.AsyncState = null; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x05) { //有问题!!!触发异常事件 return; } Transactions.Remove(t); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x05, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// Write Single Coil,带返回 /// /// /// /// /// /// public ModbusClient_Errno Do_05(UInt16 addr, bool dat, Action AsyncDelegate, object AsyncState) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); if (dat) data.Add(0xff); else data.Add(0); data.Add(0); Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = AsyncDelegate; t.AsyncState = AsyncState; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x05) { //有问题!!!触发异常事件 return; } Transactions.Remove(t); ((Action)t.AsyncDelegate)(t.AsyncState); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x05, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// 写多个coil /// /// /// /// public ModbusClient_Errno Do_0F(UInt16 addr, bool[] datas) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); data.AddRange(((UInt16)datas.Count()).GetBytes_Big_endian()); data.Add((byte)(Math.Ceiling(datas.Count() / 8.0))); byte b = 0; int j=0; for (int i = 0; i < datas.Count(); i++) { if (datas[i]) Misc.MyBase.SIGNBIT(ref b, j); j++; if (j == 8) { data.Add(b); b = 0; j = 0; } } if (j != 0) data.Add(b); Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = null; t.AsyncState = null; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x10) { //有问题!!!触发异常事件 return; } Transactions.Remove(t); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x0F, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// 写多个coil,带返回 /// /// /// /// /// /// public ModbusClient_Errno Do_0F(UInt16 addr, bool[] datas, Action AsyncDelegate, object AsyncState) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); data.AddRange(((UInt16)datas.Count()).GetBytes_Big_endian()); data.Add((byte)(Math.Ceiling(datas.Count() / 8.0))); byte b = 0; int j = 0; for (int i = 0; i < datas.Count(); i++) { if (datas[i]) Misc.MyBase.SIGNBIT(ref b, j); j++; if (j == 8) { data.Add(b); b = 0; j = 0; } } if (j != 0) data.Add(b); Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = AsyncDelegate; t.AsyncState = AsyncState; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x0f) { //有问题!!!触发异常事件 return; } Transactions.Remove(t); ((Action)t.AsyncDelegate)(t.AsyncState); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x0F, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// 写多个REG /// /// /// /// public ModbusClient_Errno Do_10(UInt16 addr, UInt16[] datas) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); data.AddRange(((UInt16)datas.Count()).GetBytes_Big_endian()); data.Add((byte)(datas.Count() * 2)); for (int i = 0; i < datas.Count(); i++) { data.AddRange(datas[i].GetBytes_Big_endian()); } Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = null; t.AsyncState = null; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x10) { //有问题!!!触发异常事件 return; } Transactions.Remove(t); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x10, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// 写多个REG,带返回 /// /// /// /// /// /// public ModbusClient_Errno Do_10(UInt16 addr, UInt16[] datas, Action AsyncDelegate, object AsyncState) { if (Transactions.Count() >= MaxConCurrTrans) return ModbusClient_Errno.TOO_MUCH_TRANS; List data = new List(); data.AddRange(addr.GetBytes_Big_endian()); data.AddRange(((UInt16)datas.Count()).GetBytes_Big_endian()); data.Add((byte)(datas.Count() * 2)); for (int i = 0; i < datas.Count(); i++) { data.AddRange(datas[i].GetBytes_Big_endian()); } Transaction t = new Transaction(); t.tranid = GetFreeTranID(); t.AsyncDelegate = AsyncDelegate; t.AsyncState = AsyncState; t.ParsePacket = new Action(delegate(Pack_Proto p) { if (p.func != 0x10) { //有问题!!!触发异常事件 return; } Transactions.Remove(t); ((Action)t.AsyncDelegate)( t.AsyncState); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = UnitID, func = 0x10, buf = data.ToArray() }.ToBytes()); return ModbusClient_Errno.OK; } /// /// /// /// protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } /// /// /// public event PropertyChangedEventHandler PropertyChanged; } }