using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Threading;
using FlyADBase;
namespace Flyad7_WPF
{
public class AutoSync : INotifyPropertyChanged, Misc.ISaveToXml
{
IFlyADClient mFlyAD;
const int OutIdxOfVSensor = 1;
///
/// 在边界等待的时间,s
///
const int ExtraTime = 2;
///
/// 开始等待时间
///
const int StartWaitTime = 60;
///
/// 温修消耗时间,s
///
public int ConsumeOfSampleBackw { get; set; }
///
/// 样品消耗时间,s
///
public int ConsumeOfSampleForw { get; set; }
///
/// 扫描消耗时间,s
///
public int ConsumeOfScan { get; set; }
///
/// 等待grid完成耗时,s
///
public int ConsumeOfGrid { get; set; }
///
/// 温修主轴脉冲消耗
///
public int Pos2ConsumeOfSampleBackw { get; protected set; }
///
/// 样品主轴脉冲消耗
///
public int Pos2ConsumeOfSampleForw { get; protected set; }
///
/// 扫描单次 主轴脉冲消耗
///
public int Pos2ConsumeOfScan { get; set; }
///
/// 等待下次扫描 主轴脉冲消耗
///
public int Pos2ConsumeOfWaitNextScan { get; set; }
public int SampleInterval { get; set; }
///
/// 扫描宽度,单位脉冲
///
public int ScanWidth { get; set; }
///
/// 扫描开始位置,单位脉冲
///
public int ScanBegin { get; set; }
public Misc.Range SamplePos_Backw = new Misc.Range();
public Misc.Range SamplePos_Forw = new Misc.Range();
public UInt32 Velocity { get; set; }
public UInt32 VSample { get; set; }
double VDistanceWithHeaderInUsed;
public double DistanceWithHeader { get; set; } = 0.486;
public int sampleCount { get; set; }
public int last_pos2 { get; set; }
///
/// pos1 脉冲比例, 如 Velocity = 8000, 所以 Speed1 = Velocity*pos1_scale
///
public double Pos1Scale { get; set; } = 0.25;
///
/// 主轴脉冲 mm/脉冲
///
public double Mmpp2 { get; set; } = 0.326;
///
/// 当前线速度
///
public double CurrFilmVelocity { get; set; }
///
/// 当前速度
///
public double CurrVelocity { get; set; }
///
/// 电机脉冲 mm/脉冲
///
public double Mmpp1 { get; set; } = 0.16;
///
/// m/min
///
public double FilmVelocity { get; set; }
public AutoSync(FlyAD7 flyad)
{
ScanBegin = 484;
ScanWidth = 4000;
SamplePos_Backw.Begin = 67 - 50;
SamplePos_Backw.End = 67 + 50;
SamplePos_Forw.Begin = 5200 - 50;
SamplePos_Forw.End = 5200 + 50;
Velocity = 2000;// 8000;
VSample = 1000;// 3000;
FilmVelocity = 18;//m/min
SampleInterval = 10;
Pos1Scale = 0.25;
ConsumeOfSampleBackw = 6;
ConsumeOfSampleForw = 6;
ConsumeOfScan = 8;
ConsumeOfGrid = 3;
Load();
Init(flyad);
}
void Init(IFlyADClient flyad)
{
mFlyAD = flyad;
Misc.BindingOperations.SetBinding(mFlyAD, new string[] { "Ratio02", "Ratio01" },
delegate()
{
Pos1Scale = (double)mFlyAD.Ratio02 / mFlyAD.Ratio01;
});
Misc.BindingOperations.SetBinding(mFlyAD, "Speed2",
delegate()
{
CurrFilmVelocity = (mFlyAD.Speed2 * Mmpp2 * 60) / 1000.0;
});
Misc.BindingOperations.SetBinding(mFlyAD, "Speed",
delegate()
{
CurrVelocity = (mFlyAD.Speed * Mmpp1 * 60) / 1000.0;
});
TestInit();
}
void GM_SyncScan_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "DistanceWithHeader") //滞后,应该增大
{
double d = DistanceWithHeader - VDistanceWithHeaderInUsed;
d *= 1000.0;
d = -d;
int offset = (int)(d / Mmpp2);
mFlyAD.SetPos2Offset(offset);//提前
VDistanceWithHeaderInUsed = DistanceWithHeader;
}
}
void mFlyAD_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Marker")
{
for (int i = 0; i < syncOrderList.Count(); i++)
{
if (syncOrderList[i].Marker == mFlyAD.Marker)
{
//当前正在运作此同步指令
//在它之前的,肯定运行完了,删除
syncOrderList.RemoveRange(0, i);
OnPoll_SyncOrder();
break;
}
}
}
else if (e.PropertyName == "IsSync")
{
if (!mFlyAD.IsSync)
{
Stop();
}
}
}
public void Start()
{
//清空同步指令
syncOrderList.Clear();
mFlyAD.SyncPos2Clear();
mFlyAD.PropertyChanged += mFlyAD_PropertyChanged;
//InitSyncParam();
mFlyAD.Pos1LCShift = -ScanBegin;
//ScanWidth = syncparam.ScanWidth;
double wait_mm = StartWaitTime * FilmVelocity / 60 * 1000.0;
int pos2 = (int)((-DistanceWithHeader * 1000 - wait_mm) / Mmpp2);
int pos2at01 = (int)((-DistanceWithHeader * 1000) / Mmpp2);
last_pos2 = 0;
sampleCount = 0;
//当前last_pos2 >= pos2
LastOrder = new SyncOrder() { Order = SyncOrder.OrderType.Init };
OnPoll_SyncOrder();
mFlyAD.SyncBegin(pos2);
mFlyAD.SyncPos2Clear();
mFlyAD.SetPos2At01(pos2at01, true);
//设置纵向边界信号为0
ClearVSensor();
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += (s, e) =>
{
((DispatcherTimer)s).Stop();
SetVSensor();
};
timer.Interval = TimeSpan.FromSeconds(0.5);
timer.Start();
}
public void Stop()
{
mFlyAD.SyncEnd();
//mFlyAD.SyncClear();
mFlyAD.PropertyChanged -= mFlyAD_PropertyChanged;
}
public void InitSyncParam()
{
double speed1 = Velocity * Pos1Scale;// pos1 pps
double speed2 = FilmVelocity * 1000 / 60 / Mmpp2; //pos2 pps
//反向取样时间
double consumeTOfTemp = ConsumeOfSampleForw;
Pos2ConsumeOfSampleBackw = (int)(speed2 * consumeTOfTemp);
//正向取样时间
double consumeTOfSample = consumeTOfTemp;
Pos2ConsumeOfSampleForw = (int)(speed2 * consumeTOfSample);
//单次扫描时间
double consumeTOfScan;
consumeTOfScan = ConsumeOfScan;
Pos2ConsumeOfScan = (int)(speed2 * consumeTOfScan);
//在边界等1秒
Pos2ConsumeOfWaitNextScan = (int)(speed2 * (ConsumeOfGrid + 1));
//mFlyAD.SyncEnd();
mFlyAD.SyncClear();
}
#region 测试模式
///
/// 当前线速度
///
public int TestInterval { get; set; } = 60;
///
/// 当前线速度
///
public int TestCnt { get; set; }
public enum TEST_STATE
{
IDLE,
INIT,
START,
POLL,
END,
ERROR
}
public TEST_STATE TestState { get; set; } = TEST_STATE.IDLE;
DispatcherTimer timer = new DispatcherTimer();
void TestInit()
{
TestState = TEST_STATE.INIT;
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += new EventHandler(timer_Tick);
mFlyAD.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "IsConnected")
{
if (mFlyAD.IsConnected == false)
{
TestState = TEST_STATE.ERROR;
timer.Stop();
}
}
};
}
public void StartTest()
{
if (!timer.IsEnabled)
{
TestState = TEST_STATE.INIT;
timer.Start();
}
}
public void StopTest()
{
TestState = TEST_STATE.IDLE;
timer.Stop();
}
void timer_Tick(object sender, EventArgs e)
{
switch (TestState)
{
case TEST_STATE.INIT:
InitSyncParam();
TestState = TEST_STATE.START;
break;
case TEST_STATE.START:
Start();
TestState = TEST_STATE.POLL;
TestCnt = 0;
break;
case TEST_STATE.POLL:
{
TestCnt++;
if (TestCnt >= TestInterval)
{
TestState = TEST_STATE.END;
}
}break;
case TEST_STATE.END:
Stop();
TestState = TEST_STATE.INIT;
break;
}
}
#endregion
///
/// 令虚拟边界传感器 输出1 (OUT1,输出1 ,OUT1 接 机头 与 机尾 AD卡的同步信号)
///
public void SetVSensor()
{
mFlyAD.SetOutput(
(UInt16)Misc.MyBase.BIT(OutIdxOfVSensor - 1),
(UInt16)Misc.MyBase.BIT(OutIdxOfVSensor - 1));
}
///
/// 令虚拟边界传感器 输出0 (OUT1,输出0 ,OUT1 接 机头 与 机尾 AD卡的同步信号)
///
public void ClearVSensor()
{
mFlyAD.SetOutput(
(UInt16)Misc.MyBase.BIT(OutIdxOfVSensor - 1),
(UInt16)~Misc.MyBase.BIT(OutIdxOfVSensor - 1));
}
#region 同步指令管理
///
/// 它就是flyad7 当中的同步指令列表
/// 每收到grid后面带的 marker,就要判断是 哪句order,做哪件事情
///
public List syncOrderList = new List();
private SyncOrder lastorder;
[PropertyChanged.DoNotCheckEquality]
public SyncOrder LastOrder { get; set; }
public struct SyncOrder
{
///
/// 都是从 ScanRangeLC.Begin 开始运行的
/// -----样品取样 & 归0周期:
/// 1.归0,
/// 2.反向取样
/// 3.正向扫描
/// 4.正向取样
/// 5.反向扫描
/// ------正常周期:
/// 1.正向扫描
/// 2.反向扫描
///
public enum OrderType
{
Init,//刚开始,下一条就是First
///
/// 老板说,要同步扫描前,必须有一条 SyncRunTo 或 SyncRunToLC
///
First,
///
/// 【归零】,SyncOrigin()
///
Origin,
///
/// 反向到 【反向样品】结束位,SyncRunTo(SamplePos_Backw.End)
///
SampleBackw_ready,
///
/// 【反向样品】取样,SyncRunTo(SamplePos_Backw.Begin)
///
SampleBackw,
///
/// 【反向样品】完成后,正向回到边界,SyncRunToLC(ScanRangeLC.Begin)
///
SampleBackw_complete,
///
/// 【正向扫描】, SyncRunAtLC(pos2_begin,pos2_end, ScanRangeLC.End)
///
ScanForw,
///
/// 【正向扫描】等待grid完成,SyncWait(ms)
///
ScanForw_waitGridComplete,
///
/// 正向到 【正向样品】开始位,SyncRunTo(SamplePos_Forw.Begin)
///
SampleForw_ready,
///
/// 【正向样品】取样,SyncRunTo(SamplePos_Forw.End)
///
SampleForw,
///
/// 【正向样品】完成后,反向回到边界,SyncRunToLC(ScanRangeLC.End)
///
SampleForw_complete,
///
/// 【反向扫描】, SyncRunAtLC(pos2_begin,pos2_end, ScanRangeLC.Begin)
///
ScanBackw,
///
/// 【反向扫描】等待grid完成,SyncWait(ms)
///
ScanBackw_waitGridComplete,
}
public OrderType Order;
///
/// 主轴脉冲
///
public Int32 Marker;
public override string ToString()
{
return Order.ToString() + "|" + Marker.ToString();
}
}
bool IsSample()
{
if ((sampleCount >= SampleInterval) && (SampleInterval > 0))
return true;
return false;
}
///
/// 每次调用创造1条同步指令!!!!
///
public void CreateSyncOrder()
{
SyncOrder order = new SyncOrder();
switch (LastOrder.Order)
{
case SyncOrder.OrderType.Init:
{
order.Order = SyncOrder.OrderType.First;
} break;
case SyncOrder.OrderType.ScanBackw:
{
order.Order = SyncOrder.OrderType.ScanBackw_waitGridComplete;
} break;
case SyncOrder.OrderType.First:
case SyncOrder.OrderType.ScanBackw_waitGridComplete:
{
if (sampleCount < SampleInterval)
sampleCount++;
if (IsSample())
order.Order = SyncOrder.OrderType.Origin;
else
order.Order = SyncOrder.OrderType.ScanForw;
}break;
case SyncOrder.OrderType.ScanForw:
{
order.Order = SyncOrder.OrderType.ScanForw_waitGridComplete;
}break;
case SyncOrder.OrderType.ScanForw_waitGridComplete:
{
if (IsSample())
{
sampleCount = 0;
order.Order = SyncOrder.OrderType.SampleForw_ready;
}
else
order.Order = SyncOrder.OrderType.ScanBackw;
}break;
case SyncOrder.OrderType.Origin:
order.Order = SyncOrder.OrderType.SampleBackw_ready;
break;
case SyncOrder.OrderType.SampleBackw_ready:
order.Order = SyncOrder.OrderType.SampleBackw;
break;
case SyncOrder.OrderType.SampleBackw:
order.Order = SyncOrder.OrderType.SampleBackw_complete;
break;
case SyncOrder.OrderType.SampleBackw_complete:
order.Order = SyncOrder.OrderType.ScanForw;
break;
case SyncOrder.OrderType.SampleForw_ready:
order.Order = SyncOrder.OrderType.SampleForw;
break;
case SyncOrder.OrderType.SampleForw:
order.Order = SyncOrder.OrderType.SampleForw_complete;
break;
case SyncOrder.OrderType.SampleForw_complete:
order.Order = SyncOrder.OrderType.ScanBackw;
break;
}
DoOrder(ref order);
syncOrderList.Add(order);
LastOrder = order;
}
void DoOrder(ref SyncOrder order)
{
switch (order.Order)
{
case SyncOrder.OrderType.First:
{
order.Marker = last_pos2;
mFlyAD.SyncRunAtLC(
last_pos2,
last_pos2 + Pos2ConsumeOfScan,
0,
true,
order.Marker);
last_pos2 += Pos2ConsumeOfScan;
} break;
case SyncOrder.OrderType.Origin:
{
order.Marker = last_pos2;
mFlyAD.SyncOrigin(order.Marker);
} break;
case SyncOrder.OrderType.SampleBackw_ready:
{
order.Marker = last_pos2 + 1;
mFlyAD.SyncRunTo(SamplePos_Backw.End,
Velocity,
false,
order.Marker);
} break;
case SyncOrder.OrderType.SampleBackw:
{
order.Marker = (last_pos2 + 2);
mFlyAD.SyncRunTo(SamplePos_Backw.Begin,
VSample,
true,
order.Marker);
} break;
case SyncOrder.OrderType.SampleBackw_complete:
{
order.Marker = (last_pos2 + 3);
mFlyAD.SyncRunToLC(0,
Velocity,
false,
order.Marker);
last_pos2 += Pos2ConsumeOfSampleBackw;
} break;
case SyncOrder.OrderType.ScanBackw:
{
order.Marker = last_pos2;
mFlyAD.SyncRunAtLC(
last_pos2,
last_pos2 + Pos2ConsumeOfScan,
0,
true,
order.Marker);
last_pos2 += Pos2ConsumeOfScan;
} break;
case SyncOrder.OrderType.ScanBackw_waitGridComplete:
{
order.Marker = last_pos2;
mFlyAD.SyncRunAtLC(
last_pos2,
last_pos2 + Pos2ConsumeOfWaitNextScan,
0,
false,
order.Marker);
last_pos2 += Pos2ConsumeOfWaitNextScan;
}break;
case SyncOrder.OrderType.SampleForw_ready:
{
order.Marker = last_pos2;
mFlyAD.SyncRunTo(SamplePos_Forw.Begin,
Velocity,
false,
order.Marker);
} break;
case SyncOrder.OrderType.SampleForw:
{
order.Marker = (last_pos2 + 1);
mFlyAD.SyncRunTo(SamplePos_Forw.End,
VSample,
true,
order.Marker);
} break;
case SyncOrder.OrderType.SampleForw_complete:
{
order.Marker = (last_pos2 + 2);
mFlyAD.SyncRunToLC(ScanWidth - 1,
Velocity,
false,
order.Marker);
last_pos2 += Pos2ConsumeOfSampleForw;
} break;
case SyncOrder.OrderType.ScanForw:
{
order.Marker = last_pos2;
mFlyAD.SyncRunAtLC(
last_pos2,
last_pos2 + Pos2ConsumeOfScan,
ScanWidth - 1,
true,
order.Marker);
last_pos2 += Pos2ConsumeOfScan;
} break;
case SyncOrder.OrderType.ScanForw_waitGridComplete:
{
order.Marker = last_pos2;
mFlyAD.SyncRunAtLC(
last_pos2,
last_pos2 + Pos2ConsumeOfWaitNextScan,
ScanWidth - 1,
false,
order.Marker);
last_pos2 += Pos2ConsumeOfWaitNextScan;
}break;
}
}
///
/// 保证列表有10条以上,少于10条,每次添加10条
///
void OnPoll_SyncOrder()
{
if (syncOrderList.Count() < 6)
{
for (int i = 0; i < 6; i++)
CreateSyncOrder();
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
public void Save()
{
Misc.SaveToXmlHepler.Save("autosync.xml", this);
}
public void Load()
{
Misc.SaveToXmlHepler.Load("autosync.xml", this);
}
public string[] GetSavePropertyNames()
{
return new string[]{
"ScanBegin",
"ScanWidth",
"Mmpp1",
"Mmpp2",
"SamplePos_Backw",
"SamplePos_Backw",
"SamplePos_Forw",
"SamplePos_Forw",
"Velocity",
"VSample",
"FilmVelocity",
"SampleInterval",
"TestInterval",
"ConsumeOfSampleBackw",
"ConsumeOfSampleForw",
"ConsumeOfScan",
"ConsumeOfGrid"
};
}
}
}