using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.ComponentModel; namespace FLY.ModbusModule { public class ClientTCP:IModbusClient, INotifyPropertyChanged { TCPManager.TCPCConn mTCPCConn; public event Action<Pack_Proto> ErrorEvent; public bool IsConnected { get { return mTCPCConn.IsConnected; } } public ClientTCP(IPAddress ip) { mTCPCConn = new TCPManager.TCPCConn(new IPEndPoint(ip, 502), ParsePacketInClient); mTCPCConn.Enable = true; mTCPCConn.ConnectEvent += new Action<TCPManager.TCPConn>(mTCPCConn_ConnectEvent); } void mTCPCConn_ConnectEvent(TCPManager.TCPConn obj) { //清空全部tranid Transactions.Clear(); NotifyPropertyChanged("IsConnected"); } /// <summary> /// 从异端接收的数据,解释数据 /// </summary> /// <param name="packet"></param> /// <param name="conn"></param> /// <returns></returns> 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, 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); Transactions.RemoveAll(_t => _t.tranid == p.tranid); } } } class Transaction { public UInt16 tranid; public object AsyncDelegate; public object AsyncState; public Action<Pack_Proto> ParsePacket; } List<Transaction> Transactions = new List<Transaction>(); UInt16 tranid = 12; UInt16 GetFreeTranID() { tranid++; return tranid; } /// <summary> /// 读多个 COIL /// </summary> /// <param name="addr"></param> public void Do_01(UInt16 addr, UInt16 cnt, Action<bool[],object> AsyncDelegate, object AsyncState) { List<byte> data = new List<byte>(); 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<Pack_Proto>(delegate(Pack_Proto p) { if (p.func != 0x01) { //有问题!!!触发异常事件 return; } List<bool> blist = new List<bool>(); 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; } } } ((Action<bool[], object>)t.AsyncDelegate)(blist.ToArray(), t.AsyncState); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = 0, func = 0x01, buf = data.ToArray() }.ToBytes()); } /// <summary> /// 读多个REG /// </summary> /// <param name="addr"></param> public void Do_03(UInt16 addr, UInt16 cnt, Action<UInt16[], object> AsyncDelegate, object AsyncState) { List<byte> data = new List<byte>(); 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<Pack_Proto>(delegate(Pack_Proto p) { if (p.func != 0x03) { //有问题!!!触发异常事件 return; } List<UInt16> blist = new List<UInt16>(); int index = 1; while(index<p.buf.Count()) { blist.Add(COMMON.ToUInt16_Big_endian(p.buf, index)); index += 2; } ((Action<UInt16[], object>)t.AsyncDelegate)(blist.ToArray(), t.AsyncState); }); Transactions.Add(t); mTCPCConn.SendPacket( new Pack_Proto() { tranid = t.tranid, unitid = 0, func = 0x03, buf = data.ToArray() }.ToBytes()); } /// <summary> /// 写多个coil /// </summary> /// <param name="addr"></param> public void Do_0F(UInt16 addr, bool[] datas) { List<byte> data = new List<byte>(); 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); mTCPCConn.SendPacket( new Pack_Proto() { tranid = GetFreeTranID(), unitid = 0, func = 0x0F, buf = data.ToArray() }.ToBytes()); } /// <summary> /// 写多个REG /// </summary> /// <param name="addr"></param> public void Do_10(UInt16 addr, UInt16[] datas) { List<byte> data = new List<byte>(); 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()); } mTCPCConn.SendPacket( new Pack_Proto() { tranid = GetFreeTranID(), unitid = 0, func = 0x10, buf = data.ToArray() }.ToBytes()); } protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } public event PropertyChangedEventHandler PropertyChanged; } }