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, 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