using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.ComponentModel; namespace FLY.ModbusModule { public class ServerTCP:INotifyPropertyChanged { PLCRegister mPLCRegs; TCPManager.TCPListen mTCPListen; DateTime lastcommdt= DateTime.MinValue; public DateTime LastCommDT { get { return lastcommdt; } set { if (lastcommdt != value) { lastcommdt = value; NotifyPropertyChanged("LastCommDT"); } } } public ServerTCP(PLCRegister plcRegs):this(plcRegs, 502) { } public ServerTCP(PLCRegister plcRegs, UInt16 port) { mPLCRegs = plcRegs; mTCPListen = new TCPManager.TCPListen(new IPEndPoint(IPAddress.Any, port), ParsePacketInServer); mTCPListen.Enable = true; } /// /// 从异端接收的数据,解释数据 /// /// /// /// int ParsePacketInServer(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) { switch (p.func) { case 0x03: // read holding registers Do_03(conn,p); break; case 0x01: // read coils Do_01(conn, p); break; case 0x10: // write multiple registers Do_10(conn, p); break; case 0x06: // Write single register Do_06(conn, p); break; case 0x05: // Write single coil Do_05(conn, p); break; case 0x0f: // Write mutiple coils Do_0f(conn, p); break; default: Do_Exception(conn, p, 0x01); break; } LastCommDT = DateTime.Now; } #region 处理 /// /// 异常处理 /// /// /// void Do_Exception(TCPManager.TCPConn conn, Pack_Proto p, byte e_code) { byte func = p.func; Misc.MyBase.SIGNBIT( ref func, 7); conn.SendPacket( new Pack_Proto() { tranid = p.tranid, unitid = p.unitid, func = func, buf = new byte[1] { e_code } }.ToBytes()); } #region 功能 /// /// 读多个 COIL /// /// void Do_01(TCPManager.TCPConn conn, Pack_Proto p) { int index = 0; //开始地址 UInt16 start = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; //数量 UInt16 num = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; if ((num < 0x01) || (num > 0x07D0)) { Do_Exception(conn, p, 0x03); return; } if (start + num > mPLCRegs.CoilsCount) { Do_Exception(conn, p, 0x02); return; } bool[] value = new bool[num]; mPLCRegs.GetValue(start, value); List data = new List(); data.Add((byte)(Math.Ceiling(num / 8.0)));//返回的字节数 for (int i = 0,j=0; i < num; i++) { if (j == 0) data.Add(0); if (value[i]) { data[data.Count - 1] = (byte)(data[data.Count - 1] | Misc.MyBase.BIT(i % 8)); } j++; if (j == 8) { j = 0; } } conn.SendPacket( new Pack_Proto(){ tranid = p.tranid, unitid = p.unitid, func = p.func, buf = data.ToArray()}.ToBytes()); } /// /// 读多个REG /// /// void Do_03(TCPManager.TCPConn conn, Pack_Proto p) { int index = 0; //开始地址 UInt16 start = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; //数量 UInt16 num = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; if ((num < 0x01) || (num > 0x007D)) { Do_Exception(conn, p, 0x03); return; } if (start + num > mPLCRegs.RegsCount) { Do_Exception(conn, p, 0x02); return; } UInt16[] value = new UInt16[num]; mPLCRegs.GetValue(start, value); List data = new List(); data.Add((byte)(num * 2)); for (int i = 0; i < num; i++) { data.AddRange(value[i].GetBytes_Big_endian()); } conn.SendPacket( new Pack_Proto() { tranid = p.tranid, unitid = p.unitid, func = p.func, buf = data.ToArray() }.ToBytes()); } /// /// 写单个coil /// /// void Do_05(TCPManager.TCPConn conn, Pack_Proto p) { int index = 0; //开始地址 UInt16 start = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; //数量 UInt16 value = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; if ((value != 0xff00) && (value != 0x0000)) { Do_Exception(conn, p, 0x03); return; } if (start >= mPLCRegs.CoilsCount) { Do_Exception(conn, p, 0x02); return; } bool[] v = new bool[1]; if (value == 0xff00) v[0] = true; else v[0] = false; mPLCRegs.SetValue(start, v); conn.SendPacket(p.ToBytes()); } /// /// 写单个REG /// /// void Do_06(TCPManager.TCPConn conn, Pack_Proto p) { int index = 0; //开始地址 UInt16 start = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; //数量 UInt16 value = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; if (start >= mPLCRegs.RegsCount) Do_Exception(conn, p, 0x02); UInt16[] v = new UInt16[1]; v[0] = value; mPLCRegs.SetValue(start, v); conn.SendPacket(p.ToBytes()); } /// /// 写多个coil /// /// void Do_0f(TCPManager.TCPConn conn, Pack_Proto p) { int index = 0; //开始地址 UInt16 start = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; //数量 UInt16 num = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; if ((num < 0x01) || (num > 0x007D)) { Do_Exception(conn, p, 0x03); return; } if (start + num > mPLCRegs.RegsCount) { Do_Exception(conn, p, 0x02); return; } byte byte_cnt = p.buf[index]; index++; bool[] v = new bool[num]; for (int i = 0,j=0; i < num; i++) { if (Misc.MyBase.CHECKBIT(p.buf[index],j)) v[i] = true; else v[i] = false; j++; if (j == 8) { j = 0; index++; } } mPLCRegs.SetValue(start, v); List data = new List(); data.AddRange(start.GetBytes_Big_endian()); data.AddRange(num.GetBytes_Big_endian()); conn.SendPacket( new Pack_Proto() { tranid = p.tranid, unitid = p.unitid, func = p.func, buf = data.ToArray() }.ToBytes()); } /// /// 写多个REG /// /// void Do_10(TCPManager.TCPConn conn, Pack_Proto p) { int index = 0; //开始地址 UInt16 start = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; //数量 UInt16 num = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; byte byte_cnt = p.buf[index]; index++; if ((num < 0x01) || (num > 0x007D)) { Do_Exception(conn, p, 0x03); return; } if (start + num > mPLCRegs.RegsCount) { Do_Exception(conn, p, 0x02); return; } UInt16[] v = new UInt16[num]; for (int i = 0; i < num; i++) { v[i] = COMMON.ToUInt16_Big_endian(p.buf, index); index += 2; } mPLCRegs.SetValue(start, v); List data = new List(); data.AddRange(start.GetBytes_Big_endian()); data.AddRange(num.GetBytes_Big_endian()); conn.SendPacket( new Pack_Proto() { tranid = p.tranid, unitid = p.unitid, func = p.func, buf = data.ToArray() }.ToBytes()); } #endregion #endregion protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } public event PropertyChangedEventHandler PropertyChanged; } }