using System;
namespace AutoFocusTool.Serial
{
///
/// 单舱室马达+光源的语义化控制接口。封装 Protocol+SerialMotor,
/// 给 UI/对焦逻辑直接调。所有动作同步阻塞到下位机回复。
///
/// 重要:移动是开环+固定延时(motorDelay),下位机回复只代表"收到指令",
/// 不代表机械停稳。每次移动后等 MotorDelayMs 再抓图,否则运动模糊。
///
public class HouseMotor : IDisposable
{
private readonly SerialMotor _serial;
/// 电机到位延时(ms),移动后等待机械稳定。真机标定,默认 1500。
public int MotorDelayMs { get; set; } = 1500;
public string PortName => _serial.PortName;
public bool IsOpen => _serial.IsOpen;
public Action Log
{
get => _serial.Log;
set => _serial.Log = value;
}
public HouseMotor(string portName)
{
_serial = new SerialMotor(portName);
}
public bool Open() => _serial.Open();
public void Close() => _serial.Close();
/// 握手,返回下位机自报的 houseSn(失败 -1)。
public int ShakeHands()
{
var r = _serial.Send(Protocol.ShakeHands());
return r == null ? -1 : Protocol.ParseShakeHands(r);
}
/// 读本舱绑定的相机序列号 CCDSN(EEPROM,int)。失败 -1。
public int ReadCCDSN()
{
var r = _serial.Send(Protocol.GetCCDSN());
return r == null ? -1 : Protocol.ParseEepromInt(r);
}
/// 读 EEPROM 灯光亮度(只读)。失败 -1。
public int ReadLightBrightness()
{
var r = _serial.Send(Protocol.ReadLightBrightness());
return r == null ? -1 : Protocol.ParseEepromInt(r);
}
/// 读第 wellNum(1-16) 个well的水平电机位置脉冲(EEPROM)。失败 -1。
public int ReadWellHorizontalPos(int wellNum)
{
var r = _serial.Send(Protocol.ReadWellHorizontalPos(wellNum));
return r == null ? -1 : Protocol.ParseEepromInt(r);
}
///
/// 转动培养皿到第 wellNum(1-16) 个well对准相机:读EEPROM该well位置 → 水平电机绝对运动过去。
/// 返回该well的水平脉冲位置,失败 -1。
///
public int RotateToWell(int wellNum)
{
int pos = ReadWellHorizontalPos(wellNum);
if (pos < 0) { Log?.Invoke($"读well{wellNum}位置失败"); return -1; }
bool ok = HorizontalMoveTo(pos);
Log?.Invoke($"转到well{wellNum} 位置脉冲={pos} {(ok ? "OK" : "失败")}");
return ok ? pos : -1;
}
/// 读第 wellNum(1-16) 个well的Z对焦零点脉冲(EEPROM)。失败 -1。
public int ReadWellFocusZero(int wellNum)
{
var r = _serial.Send(Protocol.ReadWellFocusZero(wellNum));
return r == null ? -1 : Protocol.ParseEepromInt(r);
}
/// 读垂直电机扫描间隔脉冲(每层Z步距,EEPROM)。失败 -1。
public int ReadScanStep()
{
var r = _serial.Send(Protocol.ReadScanStep());
return r == null ? -1 : Protocol.ParseEepromInt(r);
}
// ── 光源 ──
public bool OpenLED() => _serial.Send(Protocol.OpenLED()) != null;
public bool CloseLED() => _serial.Send(Protocol.CloseLED()) != null;
// ── 垂直电机(Z=对焦轴)──
/// Z 复位回零,等待 MotorDelayMs。
public bool VerticalReset()
=> _serial.Send(Protocol.VerticalReset(), MotorDelayMs) != null;
/// Z 绝对运动到指定脉冲,等待 MotorDelayMs 稳定。
public bool VerticalMoveTo(int pulse)
=> _serial.Send(Protocol.VerticalAbsolute(pulse), MotorDelayMs) != null;
/// Z 绝对运动,自定义稳定延时(ms)。扫描小步移动用短延时提速。
public bool VerticalMoveTo(int pulse, int delayMs)
=> _serial.Send(Protocol.VerticalAbsolute(pulse), delayMs) != null;
/// Z 相对正转 pulse 步。
public bool VerticalForward(int pulse)
=> _serial.Send(Protocol.VerticalForward(pulse), MotorDelayMs) != null;
/// Z 相对反转 pulse 步。
public bool VerticalBackward(int pulse)
=> _serial.Send(Protocol.VerticalBackward(pulse), MotorDelayMs) != null;
/// 读 Z 当前位置脉冲。失败 -1。
public int ReadVerticalPosition()
{
var r = _serial.Send(Protocol.ReadVerticalMotor());
return r == null ? -1 : Protocol.ParseMotorPosition(r);
}
// ── 水平电机(皿孔定位)──
public bool HorizontalReset()
=> _serial.Send(Protocol.HorizontalReset(), MotorDelayMs) != null;
public bool HorizontalMoveTo(int pulse)
=> _serial.Send(Protocol.HorizontalAbsolute(pulse), MotorDelayMs) != null;
/// 水平绝对运动,自定义稳定延时(ms)。扫描小步移动用短延时提速。
public bool HorizontalMoveTo(int pulse, int delayMs)
=> _serial.Send(Protocol.HorizontalAbsolute(pulse), delayMs) != null;
public bool HorizontalForward(int pulse)
=> _serial.Send(Protocol.HorizontalForward(pulse), MotorDelayMs) != null;
public bool HorizontalBackward(int pulse)
=> _serial.Send(Protocol.HorizontalBackward(pulse), MotorDelayMs) != null;
public int ReadHorizontalPosition()
{
var r = _serial.Send(Protocol.ReadHorizontalMotor());
return r == null ? -1 : Protocol.ParseMotorPosition(r);
}
public void Dispose() => _serial.Dispose();
}
}