using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using FlyADBase;
using FObjBase;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace FLY.Thick.Base.Server
{
///
/// 膜位置检测;
/// 通过辊接近开关,或者编码器2;
/// 可以用于2台测厚仪同步主轴位置
///
public class FilmPositionDetect : IFilmPositionDetectService
{
const int MARKNO_SYNC_HIGH = 1;
public event PropertyChangedEventHandler PropertyChanged;
#region 状态
///
/// 线速度 m/min
///
public double FilmVelocity { get; private set; }
///
/// 膜位置, m
///
public double FilmPosition { get; private set; }
///
/// 复位标识,从同步服务器发送过来的
///
public int ResetMark { get; private set; }
#endregion
#region 参数
///
/// 线速度阀值,低于阀值,速度直接变为0
///
public double FilmVThreshold { get; set; } = 2;
///
/// 线速度来源
///
public FilmVSRC FilmVSrc { get; set; } = FilmVSRC.ROUND;
///
/// 线速度:编码器2 mm/pulse
///
public double Encoder2_mmpp { get; set; } = 0.1;
///
/// 线速度:1圈多少mm
///
public double MmOfR { get; set; } = 314;
#endregion
///
/// 纵向光纤传感器检测到 0到1 变化 事件
/// 或
/// sysTime同步信号触发 0到1 变化 事件
///
public event EventHandler SysTimeFilmPosEvent;
///
///
///
double reset_filmPos;
///
/// 复位时,对应的pos2脉冲
///
int reset_pos2;
FlyAD7 flyAd;
///
///
///
///
public void Init(FlyAD7 flyAd)
{
this.flyAd = flyAd;
//------------------------------------------------------------------------------------------------------------------------------------
//线速度------------------------------------------------------------------------------------------------------------------------------
this.flyAd.PropertyChanged += FlyAd_PropertyChanged_EN2;
//------------------------------------------------------------------------------------------------------------------------------------
//辊信号生成线速度-----------------------------------------------------------------------------------------------------------------------------
InitRoundFilmVelocity();
flyAd.IStatusChangedEvent += mFlyAD_IStatusChangedEvent;
//复位
Misc.BindingOperations.SetBinding(this.flyAd, nameof(this.flyAd.IsReady), () =>
{
//刚连接上,复位
ResetMark = 0;
Reset(0);
});
}
private void FlyAd_PropertyChanged_EN2(object sender, PropertyChangedEventArgs e)
{
if (FilmVSrc != FilmVSRC.EN2)
return;
if (e.PropertyName == nameof(flyAd.Speed2))
{
double speed = flyAd.Speed2 * Encoder2_mmpp / 1000.0;// m/s
speed *= 60;//m/min
FilmVelocity = speed;
}
else if (e.PropertyName == nameof(flyAd.Position2))
{
double filmPos = Pos2ToFilmPos(flyAd.Position2);
FilmPosition = filmPos;
}
}
class DateTimeUnit
{
public DateTime dt { get; set; }
public int data;
}
List pos2Pool = new List();
void AddPos2(DateTime time, int pos2)
{
pos2Pool.Add(new DateTimeUnit() { dt = time, data = pos2 });
if (pos2Pool.Last().dt - pos2Pool.First().dt > TimeSpan.FromMinutes(1))
{
pos2Pool.RemoveAt(0);
}
}
bool FindPos2(DateTime time, out int pos2)
{
pos2 = 0;
var unit = pos2Pool.Find(u => u.dt == time);
if (unit == null)
return false;
pos2 = unit.data;
return true;
}
void mFlyAD_IStatusChangedEvent(object sender, IStatusChangedEventArgs e)
{
if (Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_VSign))
{
if (Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_VSign))
{
if (FilmVSrc == FilmVSRC.EN2)//不是用编码器, 纵向光纤也不会安装
{
SysTimeFilmPosEvent?.Invoke(this, new SysTimeFilmPosEventArgs()
{
IsSysTimeSync = false,
SysTime = e.Time,
FilmPos = Pos2ToFilmPos(e.Position2)
});
AddPos2(e.Time, e.Position2);
}
}
}
else if (Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_Sync))
{
if (Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_Sync))
{
if (FilmVSrc == FilmVSRC.EN2)
{
AddPos2(e.Time, e.Position2);
FilmPosition = Pos2ToFilmPos(e.Position2);
}
SysTimeFilmPosEvent?.Invoke(this, new SysTimeFilmPosEventArgs()
{
IsSysTimeSync = true,
SysTime = e.Time,
FilmPos = FilmPosition
});
}
}
}
#region 辊信号生成 线速度
DispatcherTimer round_t;
DateTime dtRound;
int RCnt = 0;
double BaseFilmPosition = 0;
void InitRoundFilmVelocity()
{
round_t = new DispatcherTimer();
round_t.Interval = TimeSpan.FromSeconds(1);
round_t.Tick += new EventHandler(round_t_Tick);
flyAd.IStatusChangedEvent += mFlyAD_IStatusChangedEvent_round;
}
void mFlyAD_IStatusChangedEvent_round(object sender, IStatusChangedEventArgs e)
{
if (FilmVSrc != FilmVSRC.ROUND)
return;
if (!Misc.MyBase.CHECKBIT(e.IChanged, FlyADIODefine.Instance.InNo_Roll))
return;
if (Misc.MyBase.CHECKBIT(e.IStatus, FlyADIODefine.Instance.InNo_Roll))
return;
//1->0
DateTime dt = e.Time;
if (dt <= dtRound)
return;
if (dtRound != DateTime.MinValue)
{
double v = MmOfR / 1000.0 / (dt - dtRound).TotalMinutes;
if (v < 2)//太慢了
{
dt = DateTime.MinValue;
v = 0;
}
FilmVelocity = v;
if (v > 0)
{
RCnt++;
FilmPosition = RCnt * MmOfR / 1000.0 + BaseFilmPosition;
}
}
dtRound = dt;
if (dtRound != DateTime.MinValue)
{
if (!round_t.IsEnabled)
round_t.Start();
}
}
void round_t_Tick(object sender, EventArgs e)
{
if (FilmVSrc != FilmVSRC.ROUND)
{
round_t.Stop();
return;
}
if (dtRound == DateTime.MinValue)
{
round_t.Stop();
return;
}
//1->0
DateTime dt = flyAd.Now;
if (dt <= dtRound)
return;
double v = MmOfR / 1000.0 / (dt - dtRound).TotalMinutes;
if (v < (FilmVelocity - 1))
FilmVelocity = v;
double p1 = RCnt * MmOfR / 1000.0;
double p2 = (dt - dtRound).TotalMinutes * FilmVelocity;
if (p2 > MmOfR / 1000.0)
p2 = MmOfR / 1000.0;
p1 += p2;
if (FilmPosition < p1)
FilmPosition = p1;
if (FilmVelocity <= FilmVThreshold)
{
dtRound = DateTime.MinValue;
FilmVelocity = 0;
round_t.Stop();
return;
}
}
#endregion
///
/// 设置膜位置为某值
///
/// 极片位置m
public void Reset(double filmPos)
{
if (FilmVSrc == FilmVSRC.EN2)
{
reset_pos2 = flyAd.Position2;
reset_filmPos = filmPos;
}
else
{
RCnt = 0;
BaseFilmPosition = filmPos;
}
FilmPosition = filmPos;
}
///
/// 让同步信号输出 1到0 1秒后, 0到1
///
public void SyncSysTime()
{
flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Sync, false);
//1秒后,复位同步信号
PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
() => {
flyAd.SetOutputBit(FlyADIODefine.Instance.OutNo_Sync, true);
},
TimeSpan.FromSeconds(1), true, false, this, MARKNO_SYNC_HIGH, true);
}
///
/// 设置膜位置为某值; 同步服务器调用的
///
/// 极片位置m
/// AD盒sysTime
/// 复位标识
public void Reset(double filmPos, DateTime sysTime, int resetMark)
{
ResetMark = resetMark;
if (FilmVSrc == FilmVSRC.EN2)
{
reset_filmPos = filmPos;
//找回 sysTime 时,对应的flyAd.Position2
if (FindPos2(sysTime, out int pos2))
{
reset_pos2 = pos2;
}
else
{
reset_pos2 = flyAd.Position2;
}
}
else
{
RCnt = 0;
BaseFilmPosition = filmPos;
}
FilmPosition = filmPos;
}
double Pos2ToFilmPos(int pos2)
{
int distance_p = pos2 - reset_pos2;
double distance_m = distance_p * Encoder2_mmpp / 1000.0;
double filmPos = distance_m + reset_filmPos;
if (Math.Abs(distance_p) > 1000000)//不让它太大,不然乘法会溢出
{
//当距离很远,需要复位一下
reset_pos2 = pos2;
reset_filmPos = filmPos;
}
return filmPos;
}
}
}