using FLY.Modbus; using PropertyChanged; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; namespace FLY.FeedbackRenZiJia.Server { public class PLCLink : IPLCLink { /// /// 一次读取的数据量 /// const int MaxRegsOfOneRead = 50; const int MaxCoilsOfOneRead = 100; //D200 4x201 通道数量 //D201 4x202 设置值 更新 //D202 4x203 当前值 更新 //不用 //D400 4x401 设置值 160个 //D600 4x601 当前值 160个 //不用 //M3 0x4 风环开关 //M4 0x5 检测电流 public FLY.Modbus.WithThread.ClientTCP mclient; /// /// 更新周期,单位ms, /// public int UpdateInterval = 100; /// /// 实际更新间隔 /// public TimeSpan ActUpdateInterval { get; private set; } /// /// 加热通道数 /// [DoNotCheckEquality] public UInt16 ChannelCnt { get; set; } /// /// 加热量更新 /// [DoNotCheckEquality] public UInt16 HeatUpdate { get; set; } /// /// 当前电流 有没? /// public bool HasElectricity { get; private set; } /// /// 风机是否启动? /// public bool HasFan { get; private set; } /// /// 加热量更新 读 /// public UInt16 HeatUpdate_R { get; private set; } public int Errno { get; set; } = -1; public event PropertyChangedEventHandler PropertyChanged; /// /// 工作中 /// public bool IsRunning { get; private set; } /// /// 异常次数 /// public int ErrorCnt { get; private set; } CancellationTokenSource cts; public PLCLink(IPEndPoint ep) { mclient = new Modbus.WithThread.ClientTCP(ep); this.PropertyChanged += PLCLink_PropertyChanged; } 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 rws = new List(); private void PLCLink_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "ChannelCnt") { //D200 4x201 通道数量 RegWrite regWrite = new RegWrite(PLCAddressArea.Register, 200, new UInt16[] { ChannelCnt }); lock (rws) { rws.Add(regWrite); } } else if (e.PropertyName == "HeatUpdate") { //D201 4x202 设置值 更新 RegWrite regWrite = new RegWrite(PLCAddressArea.Register, 201, new UInt16[] { HeatUpdate }); lock (rws) { rws.Add(regWrite); } } } public void Start() { lock (this) { if (IsRunning) return; IsRunning = true; cts = new CancellationTokenSource(); Task.Factory.StartNew(OnPoll_update, cts.Token); } } public void Stop() { lock (this) { if (!IsRunning) return; cts.Cancel(); mclient.Close(); } } void OnPoll_update() { Stopwatch stopwatch = new Stopwatch(); _connect: while (true) { if (cts.IsCancellationRequested) goto _end; bool isconnected = mclient.Connect(); if (cts.IsCancellationRequested) goto _end; if (isconnected) break; else Thread.Sleep(1000); } lock (rws) { rws.Clear(); } stopwatch.Restart(); while (true) { if (cts.IsCancellationRequested) goto _end; if (stopwatch.ElapsedMilliseconds >= UpdateInterval) { //检查上次更新周期是否完成 ActUpdateInterval = stopwatch.Elapsed; stopwatch.Restart(); if (!UpdateReadData()) { if (cts.IsCancellationRequested)//可能是外部强制关闭 goto _end; goto _error;//连接断开,终止更新线程 } } //输出写入数据 if (!UpdateWriteData()) { if (cts.IsCancellationRequested)//可能是外部强制关闭 goto _end; goto _error;//连接断开,终止更新线程 } Errno = 0; Thread.Sleep(30); } _error: Errno = -1; ErrorCnt++; goto _connect; _end: mclient.Close(); Errno = -1; IsRunning = false; } bool UpdateReadData() { //M3 0x4 风环开关 //M4 0x5 检测电流 if (!mclient.Do_01(3, 2, out IEnumerable values)) return false; HasFan = values.ElementAt(0); HasElectricity = values.ElementAt(1); //D201 4x202 设置值 更新 if (!mclient.Do_03(201, 1, out IEnumerable values2)) return false; HeatUpdate_R = values2.ElementAt(0); return true; } bool UpdateWriteData() { while (true) { RegWrite rw; lock (rws) { if (rws.Count() == 0) break; rw = rws.First(); rws.RemoveAt(0); } switch (rw.dataArea) { case PLCAddressArea.Register: if (!mclient.Do_10((UInt16)rw.addr, (IEnumerable)rw.val)) return false; break; } } return true; } /// /// 设置加热量 /// /// public void SetHeat(IEnumerable values) { UInt16[] buf = values.ToArray(); List writes = new List(); //D400 4x401 设置值 160个 int addr = 400; int cnt = buf.Count(); int offset = 0; //每次最多 MaxRegsOfOneRead while (true) { int cnt1 = cnt; if (cnt1 > MaxRegsOfOneRead) cnt1 = MaxRegsOfOneRead; UInt16[] buf1 = new UInt16[cnt1]; Array.Copy(buf, offset, buf1, 0, cnt1); RegWrite rw = new RegWrite(PLCAddressArea.Register, addr+offset, buf1); writes.Add(rw); offset += cnt1; cnt -= cnt1; if (cnt == 0) { break; } } lock (rws) { rws.AddRange(writes); } } } }