Commit 7924757b authored by 潘栩锋's avatar 潘栩锋 🚴

修改中

parent cdae5181
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLY.Modbus
{
public abstract class AreaManagerBase
{
protected List<Plan> plan = new List<Plan>();
protected int currIndex = 0;
/// <summary>
/// 获取下一个plan,返回下一个plan,若已经到了最后一个,则在开始
/// 下一个之前,返回一个null
/// </summary>
/// <returns></returns>
public Plan GetNextPlan()
{
int cnt = plan.Count();
if (cnt <= 0) return null;
if (currIndex >= cnt)
{
currIndex = 0;
return null;
}
Plan p = plan.ElementAt(currIndex);
currIndex += 1;
return p;
}
/// <summary>
/// 清除doing状态
/// </summary>
public void ClearPlanState()
{
foreach (Plan p in plan)
{
p.isDoing = false;
}
currIndex = 0;
}
}
public abstract class AreaManager<T> : AreaManagerBase
where T : PLCRegObj, new()
{
/// <summary>
/// 一个property 对应 N个 PLC寄存器;
/// 地址必须是从小到大排列,不能有重叠
/// </summary>
public List<T> regs = new List<T>();
protected PLCAddressArea area;
protected int currIndex = 0;
protected int maxOfOneRead = 50;
public AreaManager(PLCAddressArea area, int maxOfOneRead)
{
this.area = area;
this.maxOfOneRead = maxOfOneRead;
}
/// <summary>
/// 根据DataToRegs列表构建数组
/// </summary>
public virtual void BuildArray(List<DataToRegs> DRmap)
{
List<DataToRegs> drs = DRmap.FindAll((c) =>
{
return c.dataArea == area;
});
// 分配寄存器存储空间
regs.Clear();
foreach (DataToRegs dr in drs)
{
T r = new T();
r.Init(dr);
regs.Add(r);
}
regs.Sort((r1, r2) =>
{
if (r1.dr.addr < r2.dr.addr)
return -1;
else if (r1.dr.addr > r2.dr.addr)
return 1;
else
return 0;
});
}
/// <summary>
/// 根据当前regs的配置指定读寄存器的计划
/// </summary>
public abstract void MakePlan();
}
/// <summary>
/// 每次向PLC读取寄存器的任务
/// </summary>
public class Plan
{
/// <summary>
/// coil or register
/// </summary>
public PLCAddressArea area;
/// <summary>
/// 地址
/// </summary>
public int addr;
/// <summary>
/// 数量
/// </summary>
public int num;
/// <summary>
/// 是否正在读取
/// </summary>
public bool isDoing;
/// <summary>
///
/// </summary>
/// <param name="area"></param>
/// <param name="addr"></param>
/// <param name="num"></param>
public Plan(PLCAddressArea area, int addr, int num)
{
this.area = area;
this.addr = addr;
this.num = num;
}
}
public abstract class PLCRegObj
{
/// <summary>
/// 该寄存器所属的 property
/// </summary>
public DataToRegs dr;
/// <summary>
/// 最后一个寄存器地址
/// </summary>
public int EndAddr;
public PLCRegObj()
{
}
public virtual void Init(DataToRegs dr)
{
this.dr = dr;
EndAddr = dr.addr;
}
public override string ToString()
{
return dr.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLY.Modbus
{
/// <summary>
/// PLC中的继电器对象, 与 Regs 对应
/// </summary>
public class Coil : PLCRegObj
{
/// <summary>
/// Coil的值
/// </summary>
public bool value;
}
/// <summary>
/// property 与 PLC继电器 更新操作,与 RegsData 对应
/// </summary>
public class CoilData : AreaManager<Coil>
{
public CoilData(PLCAddressArea area, int maxOfOneRead) : base(area, maxOfOneRead)
{
}
/// <summary>
/// 根据当前regs的配置指定读寄存器的计划
/// </summary>
public override void MakePlan()
{
//this.maxOfOneRead = maxOfOneRead;
if (regs == null)
{
throw new Exception("还没有执行 BuildArray()");
}
plan.Clear();
int addr = -1;
int num = 0;
for (int i = 0; i < regs.Count(); i++)
{
if (!regs[i].dr.isNeedUpdate)
continue;
if (addr == -1)
{
addr = regs[i].dr.addr;
num = 1;
}
else
{
int n = regs[i].dr.addr - addr + 1;
if (n <= maxOfOneRead)
{
num = n;
}
else
{
plan.Add(new Plan(area, addr, num));
addr = -1;
i--;
}
}
}
if (addr != -1)
{
plan.Add(new Plan(area, addr, num));
addr = -1;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLY.Modbus
{
/// <summary>
/// 数据映射的类
/// </summary>
public class DataToRegs
{
/// <summary>
/// 所属的plc
/// </summary>
public ModbusMapper mapper;
/// <summary>
/// 对应 PLC寄存器区 coil or register
/// </summary>
public PLCAddressArea dataArea;
/// <summary>
/// PLC 首地址
/// </summary>
public int addr;
/// <summary>
/// value 的C#类型 float,int16,int32
/// </summary>
public REG_TYPE type;
/// <summary>
/// 放大倍数, value * scale 才是属性的值
/// </summary>
public double scale;
/// <summary>
/// object
/// </summary>
public object owner;
/// <summary>
/// object 的 property 名称, 只能是 数字类型都是double, 剩下就是 bool
/// </summary>
public string propertyName;
/// <summary>
/// property 的值, 没有缩小. 只有 double 与 bool
/// </summary>
public object value;
/// <summary>
/// 需要从PLC读取数据更新
/// </summary>
public bool isNeedUpdate = false;
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="dataArea"></param>
/// <param name="addr"></param>
/// <param name="type"></param>
/// <param name="scale"></param>
/// <param name="owner"></param>
/// <param name="propertyname"></param>
public DataToRegs(ModbusMapper mapper, PLCAddressArea dataArea, int addr, REG_TYPE type, double scale, object owner, string propertyname)
{
this.mapper = mapper;
this.dataArea = dataArea;
this.addr = addr;
this.type = type;
this.scale = scale;
this.owner = owner;
this.propertyName = string.Copy(propertyname);
}
/// <summary>
/// C# 类型数据 转 PLC寄存器
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public bool[] ToBools(object value)
{
bool b = (bool)value;
return new bool[] { b };
}
/// <summary>
/// C# 类型数据 转 PLC寄存器, 会/scale
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public ushort[] ToRegs(object value)
{
return RegTypeConverter.ToRegs(value, type, scale);
}
public override string ToString()
{
return propertyName + " [" + ((int)dataArea).ToString() + "](" + addr + ")";
}
}
}
......@@ -47,7 +47,12 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AreaManager.cs" />
<Compile Include="CoilData.cs" />
<Compile Include="RegisterData.cs" />
<Compile Include="RegTypeConverter.cs" />
<Compile Include="ClientTCP.cs" />
<Compile Include="DataToRegs.cs" />
<Compile Include="ModbusMapper_Client.cs" />
<Compile Include="IModbusClient.cs" />
<Compile Include="IModbusRegister.cs" />
......
......@@ -241,7 +241,7 @@ namespace FLY.Modbus
/// <param name="dr">数据映射</param>
/// <param name="val">数据值,不能为空</param>
/// <returns></returns>
public override bool SetNameData(DataToRegs dr, object val)
public override void SetNameData(DataToRegs dr, object val)
{
RegWrite rw;
switch (dr.dataArea)
......@@ -250,14 +250,13 @@ namespace FLY.Modbus
rw = rws.Find((c) => { return (c.addr == dr.addr) && (c.dataArea == PLCAddressArea.Coil); });
if (rw != null) rws.Remove(rw);
rws.Add(new RegWrite(dr.dataArea, dr.addr, dr.ToBools(val)));
return true;
break;
case PLCAddressArea.Register:
rw = rws.Find((c) => { return (c.addr == dr.addr) && (c.dataArea == PLCAddressArea.Register); });
if (rw != null) rws.Remove(rw);
rws.Add(new RegWrite(dr.dataArea, dr.addr, dr.ToRegs(val)));
return true;
break;
}
return false;
}
/// <summary>
/// 更新写命令缓冲区
......@@ -298,6 +297,80 @@ namespace FLY.Modbus
p_doing.isDoing = true;
isInCommunication = true;
}
#region 寄存器读取更新计划
Dictionary<object, List<DataToRegs>> plans = new Dictionary<object, List<DataToRegs>>();
/// <summary>
/// 登记寄存器更新计划
/// </summary>
/// <param name="owner"></param>
/// <param name="propertyName"></param>
public void PlanAdd(object key, DataToRegs dr)
{
if (plans.ContainsKey(key))
{
if (!plans[key].Contains(dr))
plans[key].Add(dr);
}
else
{
plans.Add(key, new List<DataToRegs>());
plans[key].Add(dr);
}
}
/// <summary>
/// 删除寄存器更新计划
/// </summary>
/// <param name="key"></param>
public void PlanRemove(object key)
{
plans.Remove(key);
}
/// <summary>
/// 删除全部寄存器更新计划
/// </summary>
public void PlanClear()
{
plans.Clear();
}
/// <summary>
/// 需要被更新的 寄存器数量
/// </summary>
public int DRNeedUpdateCnt { get; private set; }
/// <summary>
/// 总寄存器数量
/// </summary>
public int DRCnt { get; private set; }
/// <summary>
/// 创建寄存器更新计划
/// </summary>
public void PlanMake()
{
foreach (DataToRegs dr in DRmap)
{
dr.isNeedUpdate = false;
}
foreach (KeyValuePair<object, List<DataToRegs>> kv in plans)
{
foreach (DataToRegs dr in kv.Value)
{
dr.isNeedUpdate = true;
}
}
DRNeedUpdateCnt = DRmap.Count((dr) => dr.isNeedUpdate);
DRCnt = DRmap.Count;
//TODO, 应该提前做!!!!
registers.BuildArray(DRmap);
coils.BuildArray(DRmap);
registers.MakePlan();
coils.MakePlan();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLY.Modbus
{
/// <summary>
/// PLC寄存器 与 C# 类型数据 转换, 不含bool
/// </summary>
public class RegTypeConverter
{
/// <summary>
/// PLC寄存器 转 C# 类型数据
/// </summary>
/// <param name="data">PLC 寄存器数据</param>
/// <param name="type">PLC 数据类型</param>
/// <param name="scale">PLC数据放大倍数</param>
/// <returns></returns>
public static object ToObject(ushort[] data, REG_TYPE type, double scale)
{
switch (type)
{
//case REG_TYPE.BOOL:
// {
// return data[0] != 0 ? true : false;
// }
case REG_TYPE.INT16:
{
float v = (Int16)data[0];
v = (float)(v * scale);
return v;
}
case REG_TYPE.UINT16:
{
float v = (UInt16)data[0];
v = (float)(v * scale);
return v;
}
case REG_TYPE.UINT32:
{
float v = (UInt32)(data[0] | (data[1] << 16));
v = (float)(v * scale);
return v;
}
case REG_TYPE.INT32:
{
float v = (Int32)(data[0] | (data[1] << 16));
v = (float)(v * scale);
return v;
}
case REG_TYPE.FLOAT:
{
byte[] dat = new byte[] { (byte)data[0], (byte)(data[0] >> 8), (byte)data[1], (byte)(data[1] >> 8) };
float v = BitConverter.ToSingle(dat, 0);
if ((v > 1000000) || (v < -1000000))
v = 0;
v = (float)(v * scale);
return v;
}
default:
{
throw new Exception("ToObject type=" + type + "不支持的类型");
}
}
}
/// <summary>
/// C# 类型数据 转 PLC寄存器
/// </summary>
/// <param name="value">C#中数值 只能是 float or bool</param>
/// <param name="type">PLC 数据类型</param>
/// <param name="scale">PLC数据放大倍数</param>
/// <returns></returns>
public static ushort[] ToRegs(object value, REG_TYPE type, double scale)
{
byte[] bs;
//if (type == REG_TYPE.BOOL)
//{
// bool v = (bool)value;
// if (v)
// {
// return new ushort[1] { 1 };
// }
// else
// {
// return new ushort[1] { 0 };
// }
//}
float f = (float)value;
f = (float)(f / scale);
switch (type)
{
case REG_TYPE.INT16:
{
short v = (short)f;
return new ushort[] { (ushort)v };
}
case REG_TYPE.UINT16:
{
ushort v = (ushort)f;
return new ushort[] { v };
}
case REG_TYPE.FLOAT:
{
float v = (float)f;
bs = BitConverter.GetBytes(v);
return new ushort[] {
(ushort)((bs[1] << 8) | bs[0]),
(ushort)((bs[3] << 8) | bs[2]) };
}
break;
case REG_TYPE.INT32:
{
Int32 v = (Int32)f;
bs = BitConverter.GetBytes(v);
return new ushort[] {
(ushort)((bs[1] << 8) | bs[0]),
(ushort)((bs[3] << 8) | bs[2]) };
}
case REG_TYPE.UINT32:
{
UInt32 v = (UInt32)f;
bs = BitConverter.GetBytes(v);
return new ushort[] {
(ushort)((bs[1] << 8) | bs[0]),
(ushort)((bs[3] << 8) | bs[2]) };
}
}
return null;
}
}
/// <summary>
/// C# 类型枚举
/// </summary>
public enum REG_TYPE
{
/// <summary>
/// 出错
/// </summary>
Unknown = 0,
/// <summary>
/// float
/// </summary>
FLOAT = 1,
/// <summary>
/// uint16
/// </summary>
UINT16 = 2,
/// <summary>
/// int16
/// </summary>
INT16 = 3,
/// <summary>
/// uint32
/// </summary>
UINT32 = 4,
/// <summary>
/// int32
/// </summary>
INT32 = 5,
/// <summary>
/// bool
/// </summary>
BOOL = 6,
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLY.Modbus
{
/// <summary>
/// PLC中的寄存器对象
/// </summary>
public class Register : PLCRegObj
{
/// <summary>
/// 寄存器当前值
/// </summary>
public UInt16[] value;
/// <summary>
/// 寄存器值是否改变
/// </summary>
public bool changed;
public override void Init(DataToRegs dr)
{
base.Init(dr);
value = new UInt16[ModbusMapper.RegSize(dr.type)];
EndAddr = dr.addr + value.Count() - 1;
}
}
/// <summary>
/// property 与 PLC寄存器 更新操作
/// </summary>
public class RegisterData : AreaManager<Register>
{
/// <summary>
///
/// </summary>
public RegisterData(PLCAddressArea area, int maxOfOneRead) : base(area, maxOfOneRead)
{
}
/// <summary>
/// 根据当前regs的配置指定读寄存器的计划
/// </summary>
public override void MakePlan()
{
if (regs == null)
{
throw new Exception("还没有执行 BuildArray()");
}
plan.Clear();
int addr = -1;
int num = 0;
for (int i = 0; i < regs.Count(); i++)
{
if (!regs[i].dr.isNeedUpdate)
continue;
if (addr == -1)
{
addr = regs[i].dr.addr;
num = regs[i].value.Count();
if (num > maxOfOneRead)
{
//一片区域已经大于 最大读取寄存器数,分拆
while (num > maxOfOneRead)
{
plan.Add(new Plan(area, addr, maxOfOneRead));
addr += maxOfOneRead;
num -= maxOfOneRead;
}
if (num > 0)
plan.Add(new Plan(area, addr, num));
addr = -1;
}
}
else
{
int n = regs[i].dr.addr + regs[i].value.Count() - 1 - addr + 1;
if (n <= maxOfOneRead)
{
num = n;
}
else
{
plan.Add(new Plan(area, addr, num));
addr = -1;
i--;
}
}
}
if (addr != -1)
{
plan.Add(new Plan(area, addr, num));
addr = -1;
}
}
}
}
......@@ -29,6 +29,15 @@ namespace FLY.Modbus.WithThread
/// 连接成功
/// </summary>
public bool IsConnected { get; set; }
/// <summary>
/// 最大一次读取写入寄存器 的数量
/// </summary>
//public int MaxRegLen { get; set; } = 120;
/// <summary>
/// 最大一次读取写入线圈 的数量
/// </summary>
//public int MaxCoilLen { get; set; } = 1900;
/// <summary>
/// 标识,modbus tcp的参数
/// </summary>
......@@ -177,12 +186,12 @@ namespace FLY.Modbus.WithThread
/// <param name="cnt"></param>
/// <param name="values"></param>
/// <returns></returns>
public bool Do_01(ushort addr, ushort cnt, out IEnumerable<bool> values)
public bool Do_01(int addr, int cnt, out IEnumerable<bool> values)
{
values = null;
List<byte> data = new List<byte>();
data.AddRange(addr.GetBytes_Big_endian());
data.AddRange(cnt.GetBytes_Big_endian());
data.AddRange(((UInt16)addr).GetBytes_Big_endian());
data.AddRange(((UInt16)cnt).GetBytes_Big_endian());
Pack_Proto request = new Pack_Proto()
......@@ -234,12 +243,12 @@ namespace FLY.Modbus.WithThread
/// <param name="cnt"></param>
/// <param name="values"></param>
/// <returns></returns>
public bool Do_03(ushort addr, ushort cnt, out IEnumerable<ushort> values)
public bool Do_03(int addr, int cnt, out IEnumerable<ushort> values)
{
values = null;
List<byte> data = new List<byte>();
data.AddRange(addr.GetBytes_Big_endian());
data.AddRange(cnt.GetBytes_Big_endian());
data.AddRange(((UInt16)addr).GetBytes_Big_endian());
data.AddRange(((UInt16)cnt).GetBytes_Big_endian());
Pack_Proto request = new Pack_Proto()
{
......@@ -276,10 +285,10 @@ namespace FLY.Modbus.WithThread
/// <param name="addr"></param>
/// <param name="dat"></param>
/// <returns></returns>
public bool Do_05(ushort addr, bool dat)
public bool Do_05(int addr, bool dat)
{
List<byte> data = new List<byte>();
data.AddRange(addr.GetBytes_Big_endian());
data.AddRange(((UInt16)addr).GetBytes_Big_endian());
if (dat)
data.Add(0xff);
else
......@@ -312,10 +321,10 @@ namespace FLY.Modbus.WithThread
/// <param name="addr"></param>
/// <param name="datas"></param>
/// <returns></returns>
public bool Do_0F(ushort addr, IEnumerable<bool> datas)
public bool Do_0F(int addr, IEnumerable<bool> datas)
{
List<byte> data = new List<byte>();
data.AddRange(addr.GetBytes_Big_endian());
data.AddRange(((UInt16)addr).GetBytes_Big_endian());
data.AddRange(((UInt16)datas.Count()).GetBytes_Big_endian());
data.Add((byte)(Math.Ceiling(datas.Count() / 8.0)));
......@@ -356,10 +365,10 @@ namespace FLY.Modbus.WithThread
return true;
}
public bool Do_10(ushort addr, IEnumerable<ushort> datas)
public bool Do_10(int addr, IEnumerable<ushort> datas)
{
List<byte> data = new List<byte>();
data.AddRange(addr.GetBytes_Big_endian());
data.AddRange(((UInt16)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++)
......
......@@ -23,7 +23,7 @@ namespace FLY.Modbus.WithThread
/// <param name="cnt"></param>
/// <param name="values"></param>
/// <returns></returns>
bool Do_01(UInt16 addr, UInt16 cnt, out IEnumerable<bool> values);
bool Do_01(int addr, int cnt, out IEnumerable<bool> values);
/// <summary>
......@@ -33,7 +33,7 @@ namespace FLY.Modbus.WithThread
/// <param name="cnt"></param>
/// <param name="values"></param>
/// <returns></returns>
bool Do_03(UInt16 addr, UInt16 cnt, out IEnumerable<UInt16> values);
bool Do_03(int addr, int cnt, out IEnumerable<UInt16> values);
/// <summary>
/// Write Single Coil
......@@ -41,7 +41,7 @@ namespace FLY.Modbus.WithThread
/// <param name="addr"></param>
/// <param name="data"></param>
/// <returns></returns>
bool Do_05(UInt16 addr, bool data);
bool Do_05(int addr, bool data);
/// <summary>
......@@ -50,7 +50,7 @@ namespace FLY.Modbus.WithThread
/// <param name="addr"></param>
/// <param name="datas"></param>
/// <returns></returns>
bool Do_0F(UInt16 addr, IEnumerable<bool> datas);
bool Do_0F(int addr, IEnumerable<bool> datas);
/// <summary>
......@@ -59,6 +59,6 @@ namespace FLY.Modbus.WithThread
/// <param name="addr"></param>
/// <param name="datas"></param>
/// <returns></returns>
bool Do_10(UInt16 addr, IEnumerable<UInt16> datas);
bool Do_10(int addr, IEnumerable<UInt16> datas);
}
}
......@@ -29,7 +29,7 @@ namespace FLY.OBJComponents.Server
public List<ModbusMapper> mappers = new List<ModbusMapper>();
}
List<Plan> planIDs = new List<Plan>();
public List<ModbusMapper.DataToRegs> DRMap = new List<ModbusMapper.DataToRegs>();
public List<DataToRegs> DRMap = new List<DataToRegs>();
public List<ModbusMapper_Client> PLCs = new List<ModbusMapper_Client>();
public Dictionary<string, INotifyPropertyChanged> ObjNames { get; } = new Dictionary<string, INotifyPropertyChanged>();
......@@ -75,9 +75,9 @@ namespace FLY.OBJComponents.Server
{
if (isShield)
return;
List<ModbusMapper.DataToRegs> drs = DRMap;
List<DataToRegs> drs = DRMap;
ModbusMapper.DataToRegs dr = drs.Find((_dr) => { return (_dr.propertyName == e.PropertyName) && (_dr.owner == sender); });
DataToRegs dr = drs.Find((_dr) => { return (_dr.propertyName == e.PropertyName) && (_dr.owner == sender); });
if (dr == null)
return;//不会刷新PLC
......@@ -122,10 +122,10 @@ namespace FLY.OBJComponents.Server
List<ModbusMapper.DataToRegs> drs = DRMap;
List<DataToRegs> drs = DRMap;
foreach (string propertyname in propertynames)
{
ModbusMapper.DataToRegs dr = drs.Find((_dr) => { return (_dr.propertyName == propertyname && _dr.owner == ObjNames[objname]); });
DataToRegs dr = drs.Find((_dr) => { return (_dr.propertyName == propertyname && _dr.owner == ObjNames[objname]); });
if (dr == null)
continue;
dr.mapper.PlanAdd(planID, dr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment