Commit cdae5181 authored by 潘栩锋's avatar 潘栩锋 🚴

正在改线程办ModbusMapper

parent a13b615a
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WithThread\ClientTCP.cs" /> <Compile Include="WithThread\ClientTCP.cs" />
<Compile Include="WithThread\IModbusClient.cs" /> <Compile Include="WithThread\IModbusClient.cs" />
<Compile Include="WithThread\ModbusMapper_Client.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Project.FLY.FObjSys\FObjSys\FObjBase.csproj"> <ProjectReference Include="..\..\Project.FLY.FObjSys\FObjSys\FObjBase.csproj">
......
...@@ -97,10 +97,15 @@ namespace FLY.Modbus.WithThread ...@@ -97,10 +97,15 @@ namespace FLY.Modbus.WithThread
bool TranExecute(Pack_Proto request, out Pack_Proto reponse) bool TranExecute(Pack_Proto request, out Pack_Proto reponse)
{ {
reponse = new Pack_Proto(); reponse = new Pack_Proto();
if (!IsConnected)
return false;
lock (this) lock (this)
{ {
if (!IsConnected) if (!IsConnected)
goto _end; return false;
try try
{ {
sock.Send(request.ToBytes()); sock.Send(request.ToBytes());
......
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace FLY.Modbus.WithThread
{
/// <summary>
/// 使用线程版本
/// 支持自定义逻辑
/// </summary>
public class ModbusMapper_Client : ModbusMapper
{
/// <summary>
/// 更新周期,单位ms,
/// </summary>
public int UpdateInterval = 200;
/// <summary>
/// 实际更新间隔
/// </summary>
public TimeSpan ActUpdateInterval { get; protected set; }
private Stopwatch mStopwatch = new Stopwatch();
class RegWrite
{
public PLCAddressArea dataArea;
public int addr;
public object val;
public RegWrite(PLCAddressArea dataArea, int addr, object val)
{
this.dataArea = dataArea;
this.addr = addr;
this.val = val;
}
}
List<RegWrite> rws = new List<RegWrite>();
/// <summary>
/// tcp client
/// </summary>
public ClientTCP mclient;
/// <summary>
///
/// </summary>
/// <param name="clienttcp"></param>
public ModbusMapper_Client(ClientTCP clienttcp)
{
mclient = clienttcp;
FObjBase.PollModule.Current.Poll_Config(OnPoll_update);
mclient.PropertyChanged += Mclient_PropertyChanged;
}
public override string ToString()
{
return mclient.ToString();
}
private void Mclient_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsConnected")
{
if (!mclient.IsConnected)
{
coils.ClearPlanState();
registers.ClearPlanState();
//复位全部状态
isInCommunication = false;
p_doing = null;
isUpdating = false;
curr_area_idx = 0;
// DRMap 的数据 与 下端 属性的数据一致
foreach (RegWrite rw in rws)
{
//更新 本地的 PLC 数据
SetModbusData(rw.dataArea, rw.addr, rw.val);
}
rws.Clear();
mStopwatch.Stop();
}
}
}
void OnPoll_update()
{
if (!mclient.IsConnected)
return;
if (!mStopwatch.IsRunning)
mStopwatch.Restart();
if (mStopwatch.ElapsedMilliseconds >= UpdateInterval)
{
//检查上次更新周期是否完成
if (!isUpdating)
{
isUpdating = true;
ActUpdateInterval = mStopwatch.Elapsed;
mStopwatch.Restart();
}
}
NextPlan();
}
int curr_area_idx = 0;
void NextPlan()
{
if (isInCommunication)//已经在通讯中
return;
if (rws.Count() > 0)
UpdateWriteData();
if (isUpdating)
{
p_doing = mAreaManager[curr_area_idx].GetNextPlan();
if (p_doing != null)
{
p_doing.isDoing = false;
UpdateReadData();
}
else
{
//读完
curr_area_idx++;
if (curr_area_idx >= mAreaManager.Count())
{
isUpdating = false;
//读完一轮了
curr_area_idx = 0;
}
else
{
NextPlan();
}
}
}
}
/// <summary>
/// 读 多个线圈回调
/// </summary>
/// <param name="val"></param>
/// <param name="obj"></param>
void Do_01_callback(bool[] val, object obj)
{
ModbusMapper.Plan p = obj as ModbusMapper.Plan;
p.isDoing = false;
SetModbusData(PLCAddressArea.Coil, p.addr, val);
isInCommunication = false;
NextPlan();
}
/// <summary>
/// 读多个寄存器回调
/// </summary>
/// <param name="val"></param>
/// <param name="obj"></param>
void Do_03_callback(UInt16[] val, object obj)
{
ModbusMapper.Plan p = obj as ModbusMapper.Plan;
p.isDoing = false;
SetModbusData(PLCAddressArea.Register, p.addr, val);
isInCommunication = false;
NextPlan();
}
void Do_0F_callback(object obj)
{
isInCommunication = false;
NextPlan();
}
void Do_10_callback(object obj)
{
isInCommunication = false;
NextPlan();
}
/// <summary>
/// 正在通讯中
/// </summary>
bool isInCommunication = false;
/// <summary>
/// 读更新流程中
/// </summary>
bool isUpdating = false;
/// <summary>
/// 读更新 的计划
/// </summary>
ModbusMapper.Plan p_doing = null;
///// <summary>
/////
///// </summary>
///// <param name="propertyname"></param>
//protected void NotifyPropertyChanged(string propertyname)
//{
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
//}
///// <summary>
/////
///// </summary>
//public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// PC -> PLC
/// 为命名数据赋值,会改变Modbus的寄存器值,并产生通知
/// </summary>
/// <param name="dr">数据映射</param>
/// <param name="val">数据值,不能为空</param>
/// <returns></returns>
public override bool SetNameData(DataToRegs dr, object val)
{
RegWrite rw;
switch (dr.dataArea)
{
case PLCAddressArea.Coil:
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;
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;
}
return false;
}
/// <summary>
/// 更新写命令缓冲区
/// </summary>
void UpdateWriteData()
{
RegWrite rw = rws.First();
switch (rw.dataArea)
{
case PLCAddressArea.Coil:
if (mclient.Do_0F((UInt16)rw.addr, (bool[])(rw.val), Do_0F_callback, null) != ModbusClient_Errno.OK)
return;
SetModbusData(rw.dataArea, rw.addr, rw.val);
break;
case PLCAddressArea.Register:
if (mclient.Do_10((UInt16)rw.addr, (UInt16[])rw.val, Do_10_callback, null) != ModbusClient_Errno.OK)
return;
SetModbusData(rw.dataArea, rw.addr, rw.val);
break;
}
//更新 本地的 PLC 数据
SetModbusData(rw.dataArea, rw.addr, rw.val);
rws.Remove(rw);
isInCommunication = true;
}
void UpdateReadData()
{
switch (p_doing.area)
{
case PLCAddressArea.Coil:
mclient.Do_01((UInt16)p_doing.addr, (UInt16)p_doing.num, Do_01_callback, p_doing);
break;
case PLCAddressArea.Register:
mclient.Do_03((UInt16)p_doing.addr, (UInt16)p_doing.num, Do_03_callback, p_doing);
break;
}
p_doing.isDoing = true;
isInCommunication = true;
}
}
}
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