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;
}
}