using FLY.OBJComponents.IService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using FLY.Modbus;
using System.Windows.Threading;
namespace FLY.OBJComponents.Server
{
///
/// 属性更新计划
///
public class PLCProxySystem : IPLCProxySystemService, IPropertyOpt
{
class Plan
{
///
/// 唯一ID
///
public long ID;
///
/// 上一次喂的时间
///
public DateTime FeedTime;
///
/// plc
///
public List mappers = new List();
}
List planIDs = new List();
public List DRMap = new List();
public List PLCs = new List();
public Dictionary ObjNames { get; } = new Dictionary();
///
/// 与PLC连接成功
///
public bool IsConnectedWithPLC { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
public PLCProxySystem()
{
}
public void Init()
{
foreach (var plc in PLCs)
{
plc.NameDataChanged += plc_NameDataChanged;
}
Misc.BindingOperations.SetBinding(PLCs[0].Client, "IsConnected", () =>
{
IsConnectedWithPLC = PLCs[0].Client.IsConnected;
//if (!IsConnectedWithPLC)
// ClearPlan();
});
foreach (var obj in ObjNames.Values)
{
obj.PropertyChanged += Obj_PropertyChanged;
}
FObjBase.PollModule.Current.Poll_Config(FObjBase.PollModule.POLL_CONFIG.ADD,
OnPoll_plans, TimeSpan.FromSeconds(1));
//启动!!!!
foreach (var plc in PLCs)
plc.Start();
//PLCs[0].Start();
}
private void Obj_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (isShield)
return;
List drs = DRMap;
DataToRegs dr = drs.Find((_dr) => { return (_dr.propertyName == e.PropertyName) && (_dr.owner == sender); });
if (dr == null)
return;//不会刷新PLC
//向PLC写入数据,mRegs每次只能写入一个,它有列表保存功能。
//SetNameData可以执行很多次,不过它只能一个个发。
dr.mapper.SetNameData(dr, Misc.PropertiesManager.GetValue(sender, e.PropertyName));
}
bool isShield = false;
void plc_NameDataChanged(object sender, DataToRegs dr)// NameDataChangedEventArgs e)
{
//var plc = sender as Modbus.WithThread.ModbusMapper_Client;
//object value = plc.GetNameData(e.Owener, e.PropertyName);
//这是从PLC 更新过来的,不需要向PLC写入
FObjBase.PollModule.Current.Dispatcher.Invoke(new SetValueHandler((owner, propertyname, value) =>
{
isShield = true;
Misc.PropertiesManager.SetValue(dr.owner, dr.propertyName, dr.value);
isShield = false;
}), dr.owner, dr.propertyName, dr.value);
}
delegate void SetValueHandler(object owner, string propertyname, object value);
///
/// 设置更新计划
///
/// 对象名称
///
/// 计划的编号,应该全局唯一,建议使用时间ticks
public void SetPlan(string objname, IEnumerable propertynames, long planID)
{
Plan plan = planIDs.Find(p => p.ID == planID);
if (plan == null)
{
plan = new Plan() { ID = planID, FeedTime = DateTime.Now };
planIDs.Add(plan);
}
else
{
plan.FeedTime = DateTime.Now;
}
List drs = DRMap;
foreach (string propertyname in propertynames)
{
if (!ObjNames.ContainsKey(objname))
continue;
DataToRegs dr = drs.Find((_dr) => { return (_dr.propertyName == propertyname && _dr.owner == ObjNames[objname]); });
if (dr == null)
{
continue;
//throw new Exception($"PLCProxySystem.SetPlan 不能找到 {objname}.{propertyname}");
}
dr.mapper.PlanAdd(planID, dr);
if (!plan.mappers.Contains(dr.mapper))
plan.mappers.Add(dr.mapper);
}
foreach (var mapper in plan.mappers)
{
mapper.PlanMake();
}
}
long freeplanid = 1;
long GetFreePlanID()
{
long planid = freeplanid;
freeplanid++;
if (freeplanid == 0)
freeplanid = 1;
return planid;
}
///
/// 设置更新计划
///
/// 对象名称
///
/// 计划的编号,应该全局唯一,建议使用时间ticks
public void SetPlan(string objname, IEnumerable propertynames, SetPlanReponseHandler reponseHandler, object context)
{
long planID = GetFreePlanID();
SetPlan(objname, propertynames, planID);
reponseHandler(planID, context);
}
///
/// 更新计划持续,如果不喂狗,20s后停止更新数据
///
/// 计划的编号
public void FeedPlan(long planID)
{
Plan plan = planIDs.Find(p => p.ID == planID);
if (plan != null)
{
plan.FeedTime = DateTime.Now;
}
}
///
/// 主动删除某个计划
///
///
public void RemovePlan(long planID)
{
ClearPlan((plan) => (plan.ID == planID));
}
///
/// 清除 非0 全部计划
///
void ClearPlan()
{
//if (planIDs.Count() > 0)
//{
// foreach (var plc in PLCs)
// {
// plc.PlanClear();
// plc.PlanMake();
// }
// planIDs.Clear();
//}
ClearPlan((plan) => (plan.ID != 0));
}
void ClearPlan(Func condition)
{
if (planIDs.Count() > 0)
{
var _remove =
from plan in planIDs
where condition(plan)
select plan;
if (_remove.Count() > 0)
{
List remove = new List(_remove);
List mappers = new List();
foreach (var plan in remove)
{
planIDs.Remove(plan);
foreach (var mapper in plan.mappers)
{
mapper.PlanRemove(plan.ID);
if (!mappers.Contains(mapper))
mappers.Add(mapper);
}
}
foreach (var mapper in mappers)
{
mapper.PlanMake();
}
}
}
}
///
/// 1s 一次,看出哪个令牌过期
///
void OnPoll_plans()
{
DateTime now = DateTime.Now;
ClearPlan((plan) => (plan.ID != 0) && (now - plan.FeedTime) > TimeSpan.FromMinutes(2));
}
public string[] GetSyncPropNames()
{
return new string[] { "IsConnectedWithPLC" };
}
public string[] GetNoSyncPropNames()
{
return null;
}
}
}