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