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