using FObjBase;
using Misc;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace FlyADBase
{
public partial class FlyAD7 : IFlyADClientAdv
{
NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
///
/// 通过脉冲计算速度,不使用AD盒的输出
///
public bool IsCalSpeed { get; set; } = true;
///
/// grid数据平滑
///
public int GridSmooth { get; set; }
///
/// 机架总长
///
public int PosLen { get; set; } = 8900;
///
/// 使用独立的脉冲最大最小值
///
public bool HasPosMaxMin { get; set; }
///
/// 最小脉冲,默认是0
///
public int PosMin { get; set; } = 0;
///
/// 最大脉冲,默认于PosLen 一样
///
public int PosMax { get; set; } = 8900;
#region 备份参数
public MOTORTYPE Backup_MotorType { get; set; } = MOTORTYPE.SERVO;
public UInt16 Backup_PosOfGrid { get; set; } = 10;
public UInt16 Backup_Ratio01 { get; set; } = 4;
public UInt16 Backup_Ratio02 { get; set; } = 1;
public Int16 Backup_PosOffset { get; set; } = 0;
public UInt32 Backup_JogVelocity { get; set; } = 300;
#endregion
public int GridLen => PosLen / PosOfGrid;
///
/// Speed1 = Velocity * Speed1Scale
///
public double Speed1Scale => (double)Ratio02 / Ratio01;
///
/// 动作完成
///
public bool IsFinish { get; set; }
class CalSpeed
{
DateTime last_now;
DateTime pos1_changed_time;
DateTime pos2_changed_time;
DateTime last_pos1_changed_time;
DateTime last_pos2_changed_time;
int last_pos1;
int last_pos2;
int pos1;
int pos2;
public bool Cal(DateTime now, out int speed1, out int speed2)
{
speed1 = 0;
speed2 = 0;
if (last_now == DateTime.MinValue && now != DateTime.MinValue)
{
last_now = now;
last_pos1_changed_time = pos1_changed_time;
last_pos2_changed_time = pos2_changed_time;
last_pos1 = pos1;
last_pos2 = pos2;
return false;
}
if (now - last_now < TimeSpan.FromSeconds(1))
return false;
if (pos1_changed_time != last_pos1_changed_time && last_pos1_changed_time != DateTime.MinValue)
{
speed1 = (int)((pos1 - last_pos1) / (pos1_changed_time - last_pos1_changed_time).TotalSeconds);
}
else
{
//停了
}
if (pos2_changed_time != last_pos2_changed_time && last_pos2_changed_time != DateTime.MinValue)
{
speed2 = (int)((pos2 - last_pos2) / (pos2_changed_time - last_pos2_changed_time).TotalSeconds);
}
else
{
//停了
}
last_now = now;
last_pos1_changed_time = pos1_changed_time;
last_pos2_changed_time = pos2_changed_time;
last_pos1 = pos1;
last_pos2 = pos2;
return true;
}
public void SetPos1(DateTime changedTime, int pos)
{
pos1_changed_time = changedTime;
pos1 = pos;
}
public void SetPos2(DateTime changedTime, int pos)
{
pos2_changed_time = changedTime;
pos2 = pos;
}
public void Reset()
{
last_now = DateTime.MinValue;
pos1_changed_time = DateTime.MinValue;
pos1 = 0;
last_pos1_changed_time = DateTime.MinValue;
last_pos1 = 0;
pos2_changed_time = DateTime.MinValue;
pos2 = 0;
last_pos2_changed_time = DateTime.MinValue;
last_pos2 = 0;
}
}
CalSpeed calSpeed = new CalSpeed();
void constructor2()
{
fGrid.SetSize(PosLen / PosOfGrid);
mTimeGridAdvHelper.Init();
this.PropertyChanged += FlyAD7_PropertyChanged1;
//更新线速度
PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
() =>
{
if (IsCalSpeed)
{
if (calSpeed.Cal(Now, out int speed1, out int speed2))
{
Speed = speed1;
Speed2 = speed2;
}
}
}, TimeSpan.FromSeconds(1));
}
private void FlyAD7_PropertyChanged1(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(DriveStatus))
{
switch (DriveStatus)
{
case DRIVE_MAN_STATUS.STOP_MANUAL:
case DRIVE_MAN_STATUS.STOP:
case DRIVE_MAN_STATUS.LIMIT:
IsFinish = true;
break;
case DRIVE_MAN_STATUS.RUNNING:
IsFinish = false;
break;
}
}
else if ((e.PropertyName == nameof(PosLen)) ||
(e.PropertyName == nameof(PosOfGrid)))
{
fGrid.SetSize(PosLen / PosOfGrid);
}
else if (e.PropertyName == nameof(Marker))
{
//if (DriveOrder == DRIVE_MAN_ORDER.SYNC)
{
//同步运行中
//检测与哪个指令一致,
//该指令置为 Doing, 前面的全部置为 Finish,并且删除
for (int i = 0; i < SyncOrders.Count(); i++)
{
if (SyncOrders[i].Marker == Marker)
{
SyncOrders[i].State = SyncOrderState.Doing;
for (int j = 0; j < i; j++)
{
SyncOrders[0].State = SyncOrderState.Finish;
SyncOrders.RemoveAt(0);
}
}
}
}
}
}
void Init2()
{
mTimeGridAdvHelper.Clear();
}
///
/// Runto(0), 不同于 Backward
///
public void RuntoMin()
{
if (HasPosMaxMin)
Runto(PosMin);
else
Runto(0);
}
///
/// Runto(PosLen), 不同于 Forward
///
public void RuntoMax()
{
if (HasPosMaxMin)
Runto(PosMax);
else
Runto(PosLen);
}
///
/// 设置输出
///
///
///
public void SetOutputBit(int index, bool is1)
{
if (index > 15)//4)
return;
if (index < 0)
return;
if (is1)
{
SetOutput(
(UInt16)Misc.MyBase.BIT(index),
(UInt16)Misc.MyBase.BIT(index));
}
else
{
SetOutput(
(UInt16)Misc.MyBase.BIT(index),
(UInt16)~Misc.MyBase.BIT(index));
}
}
///
/// 正反转 grid数据 缓存区
///
class SGrid
{
public const int GRID_MAX_SIZE = 1000;
int size;
public int[][] data = new int[2][];//data[0]=forword, data[1]=backward
public SGrid()
{
//清空所有数据
SetSize(GRID_MAX_SIZE);
}
public void SetSize(int size)
{
this.size = size;
data[0] = new int[size];
data[1] = new int[size];
Clear();
}
public void Clear()
{
//清空所有数据
for (int i = 0; i < size; i++)
{
data[0][i] = Misc.MyBase.NULL_VALUE;
data[1][i] = Misc.MyBase.NULL_VALUE;
}
}
}
SGrid fGrid = new SGrid();
///
/// 从正反缓存区, 获取grid数据
///
/// 方向, 只有 正,反
/// grid 开始位置
/// grid 长度
/// grid 数据
public void GetGrid(Misc.DIRECTION direction, int grid_start, int grid_len, out int[] dat)
{
int index = 0;
if (direction == Misc.DIRECTION.BACKWARD)
index = 1;
dat = new int[grid_len];
for (int i = 0; i < dat.Length; i++)
{
int grid_num = grid_start + i;
if (grid_num >= fGrid.data[index].Length)
break;
if (GridSmooth > 0)
{
int sum = 0;
int cnt = 0;
for (int j = 0; j < (GridSmooth * 2 + 1); j++)
{
int idx = grid_num - GridSmooth + j;
if (idx < 0)
continue;
if (idx >= fGrid.data[index].Length)
break;
if (Misc.MyBase.ISVALIDATA(fGrid.data[index][idx]))
{
sum += fGrid.data[index][idx];
cnt++;
}
}
if (cnt > 0)
dat[i] = sum / cnt;
else
dat[i] = Misc.MyBase.NULL_VALUE;
}
else
{
dat[i] = fGrid.data[index][grid_num];
}
}
CorrectADs?.Invoke(direction, grid_start, dat);
return;
}
///
/// 从正反缓存区, 获取全部grid数据
///
/// 方向, 只有 正,反
/// grid 数据
public void GetGrid(Misc.DIRECTION direction, out int[] dat)
{
GetGrid(direction, 0, fGrid.data[0].Length, out dat);
}
///
/// 机架修正
///
public CorrectADsHandler CorrectADs { get; set; }
#region 滞后处理
//一共有1.AD数据池(由timegrid提供) 1min
//2.pos数据池(pos推送提供) 1min
//4.当接收的grid事件数据。它有 (direction, grid_start,grid_len, systick )
//systick 就是结束的时间点。 当AD数据池出现了这个时间点
//pos数据池向前找。 pos 在 grid_start*posOfGrid 范围的数据。
//找到开始的systick 后,整合3个数据池的数据。
//5.最后代替 grid 推送出去。
///
/// ad滞后修正 单位ms
///
public int ADLag { get; set; }
public event TimeGridAdv2EventHandler TimeGridAdv2Event;
public TimeGridAdvHelper mTimeGridAdvHelper = new TimeGridAdvHelper();
#endregion
void advGetPos1AD1(int ad)
{
mTimeGridAdvHelper.AddPos_Default(Now, Position);
if (CorrectADs != null)
{
ad = CorrectAD(Position / PosOfGrid, ad);
}
AD = ad;
}
void advGetPos2()
{
mTimeGridAdvHelper.AddPos2_Default(Now, Position2);
}
void advGetIo()
{
mTimeGridAdvHelper.AddIStatus_Default(Now, IStatus);
}
void advGetState()
{
mTimeGridAdvHelper.AddDriveStatus_Default(Now, DriveOrder, DriveStatus, Marker);
}
void advPushPos1()
{
mTimeGridAdvHelper.AddPos(Now, Position);
}
void advPushPos2()
{
mTimeGridAdvHelper.AddPos2(Now, Position2);
}
void advPushIo()
{
mTimeGridAdvHelper.AddIStatus(Now, IStatus, Position, Position2);
}
void advPushAd(int ad)
{
if (CorrectADs != null)
ad = CorrectAD(Position / PosOfGrid, ad);
AD = ad;
}
public TimeGridAdv2EventArgs GetTimeGridAdv2Event(DateTime beginTime) {
//获取ad列表
var adList = mTimeGridAdvHelper.GetAD(beginTime);
if (adList.Count() == 0)
return null;
DateTime endTime = mTimeGridAdvHelper.NewestTime;
int adCnt = adList.Count();
//获取pos
var posList = mTimeGridAdvHelper.GetPos(mTimeGridAdvHelper.NewestTime, adList.Count());
Misc.DIRECTION direction;
//判断运动方向
if (posList.Last() > posList.First())
{
//正向
direction = DIRECTION.FORWARD;
}
else
{
direction = DIRECTION.BACKWARD;
}
//机架修正
if (CorrectADs != null)
{
for (int i = 0; i < adList.Count(); i++)
{
adList[i] = CorrectAD(posList[i] / PosOfGrid, adList[i]);
}
}
TimeGridAdv2EventArgs eventArgs = new TimeGridAdv2EventArgs();
eventArgs.Direction = direction;
eventArgs.EndTime = endTime;
eventArgs.AdList = adList;
eventArgs.PosList = posList;
return eventArgs;
}
void advPushTimeGrid(DateTime end_dt, int[] datas)
{
#region 高级 timegrid
//TODO
mTimeGridAdvHelper.AddAD(end_dt - TimeSpan.FromMilliseconds(ADLag), datas);
if (IsTimeToPushTimeGridAdv) {
IsTimeToPushTimeGridAdv = false;
if (TimeGridAdv2Event != null)
{
//触发全部高级版的 timegrid
bool ret = mTimeGridAdvHelper.GetLastRunningTime(out DateTime beginTime, out DateTime endTime, out int marker, out DRIVE_MAN_ORDER order);
if (ret)
{
//获取ad列表
var adList = mTimeGridAdvHelper.GetAD(beginTime, endTime, out DateTime reponse_endTime);
int adCnt = adList.Count();
if (adCnt == 0)
return;
//获取pos
var posList = mTimeGridAdvHelper.GetPos(reponse_endTime, adList.Count());
Misc.DIRECTION direction;
//判断运动方向
if (posList.Last() > posList.First())
{
//正向
direction = DIRECTION.FORWARD;
}
else {
direction = DIRECTION.BACKWARD;
}
//机架修正
if (CorrectADs != null)
{
for(int i=0;i
/// 动作指令完成,准备推送 timegridadv 事件
///
public bool IsTimeToPushTimeGridAdv = false;
void advPushStatus()
{
mTimeGridAdvHelper.AddDriveStatus(Now, DriveOrder, DriveStatus, Marker);
if (DriveStatus != DRIVE_MAN_STATUS.RUNNING)
{
//检测 mTimeGridAdvHelper.AdPool 的 systick 是否 大于等于 Now
if (mTimeGridAdvHelper.NewestTime >= Now)
{
IsTimeToPushTimeGridAdv = false;
}
else {
//通知 mTimeGridAdvHelper 下次触发 timegridadv
IsTimeToPushTimeGridAdv = true;
}
}
}
void advPushGrid(DateTime dt, int marker, DIRECTION direction, int grid_start, int[] data)
{
int index = (direction == Misc.DIRECTION.BACKWARD) ? 1 : 0;
if (grid_start >= fGrid.data[index].Length)
return;
int grid_end = data.Length + grid_start - 1;
if (grid_end >= fGrid.data[index].Length)
grid_end = fGrid.data[index].Length - 1;
int len = grid_end - grid_start + 1;
Array.Copy(data, 0, fGrid.data[index], grid_start, len);
//清空其它数据
for (int i = 0; i < grid_start; i++)
{
fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
}
for (int i = (grid_end + 1); i < fGrid.data[index].Length; i++)
{
fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
}
if (GridEvent != null)
{
CorrectADs?.Invoke(direction, grid_start, data);
}
}
void advPushMiniGrid(DIRECTION direction, int grid_start, int[] data)
{
int index = (direction == Misc.DIRECTION.BACKWARD) ? 1 : 0;
if (grid_start >= fGrid.data[index].Length)
return;
int grid_end = data.Length + grid_start - 1;
if (grid_end >= fGrid.data[index].Length)
grid_end = fGrid.data[index].Length - 1;
int len = grid_end - grid_start + 1;
Array.Copy(data, 0, fGrid.data[index], grid_start, len);
//清空后面的数据
if (direction == Misc.DIRECTION.BACKWARD)
{
for (int i = 0; i < grid_start; i++)
{
fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
}
}
else
{
for (int i = (grid_end + 1); i < fGrid.data[index].Length; i++)
{
fGrid.data[index][i] = Misc.MyBase.NULL_VALUE;
}
}
CorrectADs?.Invoke(direction, grid_start, data);
}
int CorrectAD(int grid, int ad)
{
int[] d = new int[1];
d[0] = ad;
CorrectADs(Misc.DIRECTION.FIX, grid, d);
return d[0];
}
}
}