using System;
using System.Collections.Generic;
using System.Threading;
namespace TeamAAS.Motion
{
///
/// 仿真运动卡:无硬件环境下的全功能实现(联调/演示/单元测试用)。
/// 轴位置按指令速度渐变逼近目标(后台定时器推进),IO 点内存模拟。
/// 品牌适配器(雷赛/固高/IMC60G)实现 IMotionCard 时可直接参照本类的状态机结构。
///
public class SimulatedMotionCard : TeamAAS.Global.Devices.IMotionCard
{
private readonly MotionDeviceConfig _cfg;
private readonly object _sync = new object();
private readonly double[] _pos;
private readonly double[] _target;
private readonly double[] _vel;
private readonly bool[] _moving;
private readonly bool[] _homed;
private readonly bool[] _enabled;
public string Name => _cfg.Name;
public int AxisCount => _cfg.AxisCount;
public bool IsConnected { get; private set; }
public SimulatedMotionCard(MotionDeviceConfig cfg)
{
_cfg = cfg ?? new MotionDeviceConfig();
int n = Math.Max(1, _cfg.AxisCount);
_pos = new double[n];
_target = new double[n];
_vel = new double[n];
_moving = new bool[n];
_homed = new bool[n];
_enabled = new bool[n];
// 后台轮询推进仿真轴运动(50ms 周期)
var t = new System.Threading.Timer(Tick, null, 50, 50);
}
private void Tick(object state)
{
lock (_sync)
{
for (int i = 0; i < _pos.Length; i++)
{
if (!_moving[i]) continue;
double step = _vel[i] * 0.05; // 50ms 周期
double diff = _target[i] - _pos[i];
if (Math.Abs(diff) <= step) { _pos[i] = _target[i]; _moving[i] = false; }
else _pos[i] += Math.Sign(diff) * step;
}
}
}
public bool Open() { IsConnected = true; return true; }
public void Close() { IsConnected = false; }
public bool SetEnable(int axis, bool enable)
{
ApplyAxis(ref axis);
lock (_sync) { _enabled[axis] = enable; }
return true;
}
public bool Home(int axis, int mode = 0)
{
ApplyAxis(ref axis);
lock (_sync) { _pos[axis] = 0; _target[axis] = 0; _moving[axis] = false; _homed[axis] = true; }
return true;
}
public bool IsHomed(int axis) { lock (_sync) { return _homed[ClampAxis(axis)]; } }
public bool MoveAbsolute(int axis, double position, double velocity)
{
ApplyAxis(ref axis);
lock (_sync) { _target[axis] = position; _vel[axis] = Math.Abs(velocity) <= 0 ? 1 : Math.Abs(velocity); _moving[axis] = true; }
return true;
}
public bool MoveRelative(int axis, double distance, double velocity)
{
lock (_sync) { return MoveAbsolute(axis, _pos[ClampAxis(axis)] + distance, velocity); }
}
public bool JogStart(int axis, int direction, double velocity)
{
ApplyAxis(ref axis);
lock (_sync) { _target[axis] = direction >= 0 ? double.MaxValue : double.MinValue; _vel[axis] = Math.Abs(velocity) <= 0 ? 1 : Math.Abs(velocity); _moving[axis] = true; }
return true;
}
public bool JogStop(int axis)
{
lock (_sync) { int i = ClampAxis(axis); _target[i] = _pos[i]; _moving[i] = false; }
return true;
}
public bool Stop(int axis = -1)
{
lock (_sync)
{
for (int i = 0; i < _pos.Length; i++)
{
if (axis >= 0 && i != axis) continue;
_target[i] = _pos[i]; _moving[i] = false;
}
}
return true;
}
public TeamAAS.Global.Devices.AxisStatus GetAxisStatus(int axis)
{
int i = ClampAxis(axis);
lock (_sync)
{
return new TeamAAS.Global.Devices.AxisStatus
{
Index = i,
Name = $"轴{i}",
Position = _pos[i],
Velocity = _moving[i] ? _vel[i] : 0,
IsMoving = _moving[i],
IsHomed = _homed[i],
IsEnabled = _enabled[i],
};
}
}
public List GetAllAxisStatus()
{
var list = new List();
for (int i = 0; i < AxisCount; i++) list.Add(GetAxisStatus(i));
return list;
}
private int ClampAxis(int axis) => Math.Max(0, Math.Min(axis < 0 ? 0 : axis, _pos.Length - 1));
private void ApplyAxis(ref int axis)
{
if (axis < 0) axis = 0;
if (axis >= _pos.Length) axis = _pos.Length - 1;
}
}
/// 仿真 IO 卡(16进/16出,内存模拟,批量接口齐全)。
public class SimulatedIOCard : TeamAAS.Global.Devices.IIOCard
{
private readonly MotionDeviceConfig _cfg;
private readonly bool[] _inputs;
private readonly bool[] _outputs;
public string Name => _cfg.Name;
public int InputCount => _inputs.Length;
public int OutputCount => _outputs.Length;
public bool IsConnected { get; private set; }
public SimulatedIOCard(MotionDeviceConfig cfg)
{
_cfg = cfg ?? new MotionDeviceConfig();
_inputs = new bool[Math.Max(1, _cfg.InputCount)];
_outputs = new bool[Math.Max(1, _cfg.OutputCount)];
}
public bool Open() { IsConnected = true; return true; }
public void Close() { IsConnected = false; }
public bool[] ReadAllInputs()
{
lock (_inputs) { return (bool[])_inputs.Clone(); }
}
public bool[] ReadAllOutputs()
{
lock (_outputs) { return (bool[])_outputs.Clone(); }
}
public bool WriteOutput(int index, bool value)
{
if (index < 0 || index >= _outputs.Length) return false;
lock (_outputs) { _outputs[index] = value; }
return true;
}
public bool WriteOutputs(bool[] values)
{
if (values == null) return false;
lock (_outputs)
{
int n = Math.Min(values.Length, _outputs.Length);
for (int i = 0; i < n; i++) _outputs[i] = values[i];
}
return true;
}
}
}