b95941cb50
在 CNC 编排层补齐 P0 硬件控制能力,使检测编排可覆盖设备测试与校准流程。 位置节点硬件状态还原(核心): - SavePositionNode 新增可选探测器采集参数快照,兼容旧 .xp 文件 - 执行到位后按序还原射线源电压/电流与探测器参数(先电压后电流) - 射线未开弹窗提醒并暂停;还原失败弹窗提示并暂停不继续;服务不可用降级跳过 - 新增 ICncInteractionService 封装弹窗交互,便于单元测试 四类硬件动作节点: - 射线源控制:开/关/设参/暖机/训机,安全时序 + 稳定等待 - 探测器校正:暗场/增益/坏像素/自动 - 安全门控制:开门/关门,复用内置联锁 - 几何设置:按 FDD 或放大倍率反算定位 模型、编辑器与工具栏接线: - CncNodeType 追加四枚举值 + 四类节点 record + 多态判别符 + 值域校验 - 编辑器新增插入命令、类型判定、图标与工具栏入口 - IDetectorService 预留当前采集参数读取接口(暂返回 null,待硬件层完善) 系统设置: - 新增数据存储根目录与日志目录配置及浏览按钮 - 修复保存时重复打开配置文件导致的配置冲突异常 测试: - 新增 33 个单元测试,覆盖序列化往返、旧文件兼容、节点分派/降级/失败、 位置还原全路径与混合程序执行
271 lines
10 KiB
C#
271 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text.Json.Serialization;
|
||
|
||
namespace XplorePlane.Models
|
||
{
|
||
// ── CNC 节点类型枚举 | CNC Node Type Enumeration ──────────────────
|
||
|
||
/// <summary>CNC 节点类型 | CNC node type</summary>
|
||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||
public enum CncNodeType
|
||
{
|
||
ReferencePoint,
|
||
SaveNodeWithImage,
|
||
SaveNode,
|
||
SavePosition,
|
||
InspectionModule,
|
||
InspectionMarker,
|
||
PauseDialog,
|
||
WaitDelay,
|
||
CompleteProgram,
|
||
Reset,
|
||
// ── 硬件控制节点(P0)| Hardware control nodes ──
|
||
RaySourceControl,
|
||
DetectorCorrection,
|
||
DoorControl,
|
||
Geometry
|
||
}
|
||
|
||
// ── CNC 节点基类与派生类型 | CNC Node Base & Derived Types ────────
|
||
|
||
/// <summary>
|
||
/// CNC 节点抽象基类(不可变)| CNC node abstract base (immutable)
|
||
/// 使用 System.Text.Json 多态序列化 | Uses System.Text.Json polymorphic serialization
|
||
/// </summary>
|
||
[JsonDerivedType(typeof(ReferencePointNode), "ReferencePoint")]
|
||
[JsonDerivedType(typeof(SaveNodeWithImageNode), "SaveNodeWithImage")]
|
||
[JsonDerivedType(typeof(SaveNodeNode), "SaveNode")]
|
||
[JsonDerivedType(typeof(SavePositionNode), "SavePosition")]
|
||
[JsonDerivedType(typeof(InspectionModuleNode), "InspectionModule")]
|
||
[JsonDerivedType(typeof(InspectionMarkerNode), "InspectionMarker")]
|
||
[JsonDerivedType(typeof(PauseDialogNode), "PauseDialog")]
|
||
[JsonDerivedType(typeof(WaitDelayNode), "WaitDelay")]
|
||
[JsonDerivedType(typeof(CompleteProgramNode), "CompleteProgram")]
|
||
[JsonDerivedType(typeof(ResetNode), "Reset")]
|
||
[JsonDerivedType(typeof(RaySourceControlNode), "RaySourceControl")]
|
||
[JsonDerivedType(typeof(DetectorCorrectionNode), "DetectorCorrection")]
|
||
[JsonDerivedType(typeof(DoorControlNode), "DoorControl")]
|
||
[JsonDerivedType(typeof(GeometryNode), "Geometry")]
|
||
public abstract record CncNode(
|
||
Guid Id,
|
||
int Index,
|
||
CncNodeType NodeType,
|
||
string Name);
|
||
|
||
/// <summary>参考点节点 | Reference point node</summary>
|
||
public record ReferencePointNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
double StageX,
|
||
double StageY,
|
||
double SourceZ,
|
||
double DetectorZ,
|
||
double DetectorSwing,
|
||
double FDD,
|
||
bool IsRayOn,
|
||
double Voltage,
|
||
double Current,
|
||
double StageRotation = 0,
|
||
double FixtureRotation = 0,
|
||
double FOD = 0,
|
||
double Magnification = 0) : CncNode(Id, Index, CncNodeType.ReferencePoint, Name);
|
||
|
||
/// <summary>保存节点(含图像)| Save node with image</summary>
|
||
public record SaveNodeWithImageNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
MotionState MotionState,
|
||
RaySourceState RaySourceState,
|
||
DetectorState DetectorState,
|
||
string ImageFileName) : CncNode(Id, Index, CncNodeType.SaveNodeWithImage, Name);
|
||
|
||
/// <summary>保存节点(不含图像)| Save node without image</summary>
|
||
public record SaveNodeNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
MotionState MotionState,
|
||
RaySourceState RaySourceState,
|
||
DetectorState DetectorState) : CncNode(Id, Index, CncNodeType.SaveNode, Name);
|
||
|
||
/// <summary>保存位置节点 | Save position node</summary>
|
||
public record SavePositionNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
MotionState MotionState,
|
||
RaySourceState RaySourceState = null,
|
||
bool SaveImage = false,
|
||
string ManualImagePath = "",
|
||
DetectorAcquisitionSnapshot DetectorAcq = null) : CncNode(Id, Index, CncNodeType.SavePosition, Name);
|
||
|
||
/// <summary>检测模块节点 | Inspection module node</summary>
|
||
public record InspectionModuleNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
PipelineModel Pipeline) : CncNode(Id, Index, CncNodeType.InspectionModule, Name);
|
||
|
||
/// <summary>检测标记节点 | Inspection marker node</summary>
|
||
public record InspectionMarkerNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
string MarkerType,
|
||
double MarkerX,
|
||
double MarkerY) : CncNode(Id, Index, CncNodeType.InspectionMarker, Name);
|
||
|
||
/// <summary>停顿对话框节点 | Pause dialog node</summary>
|
||
public record PauseDialogNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
string DialogTitle,
|
||
string DialogMessage) : CncNode(Id, Index, CncNodeType.PauseDialog, Name);
|
||
|
||
/// <summary>等待延时节点 | Wait delay node</summary>
|
||
public record WaitDelayNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
int DelayMilliseconds) : CncNode(Id, Index, CncNodeType.WaitDelay, Name);
|
||
|
||
/// <summary>完成程序节点 | Complete program node</summary>
|
||
public record CompleteProgramNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name) : CncNode(Id, Index, CncNodeType.CompleteProgram, Name);
|
||
|
||
/// <summary>复位节点:执行时调用运动层接口将各轴回到复位/原点位置 | Reset node: invokes the motion-layer interface to home/reset axes during execution</summary>
|
||
public record ResetNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name) : CncNode(Id, Index, CncNodeType.Reset, Name);
|
||
|
||
// ── 硬件控制节点(P0)| Hardware Control Nodes ────────────────────
|
||
|
||
/// <summary>探测器可下发采集参数快照(用于位置节点还原)| Detector down-loadable acquisition parameters snapshot (for position node restore)</summary>
|
||
public record DetectorAcquisitionSnapshot(
|
||
int BinningIndex,
|
||
int Pga,
|
||
decimal FrameRate);
|
||
|
||
/// <summary>射线源动作 | X-ray source action</summary>
|
||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||
public enum RaySourceAction
|
||
{
|
||
/// <summary>开射线 | Turn on X-ray</summary>
|
||
TurnOn,
|
||
/// <summary>关射线 | Turn off X-ray</summary>
|
||
TurnOff,
|
||
/// <summary>设置参数(电压+电流,不改变开关状态)| Set voltage/current without changing on/off state</summary>
|
||
SetParameters,
|
||
/// <summary>暖机 | Warm-up</summary>
|
||
WarmUp,
|
||
/// <summary>训机 | Training</summary>
|
||
Training
|
||
}
|
||
|
||
/// <summary>射线源控制节点 | X-ray source control node</summary>
|
||
public record RaySourceControlNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
RaySourceAction Action,
|
||
double Voltage, // 电压(kV)| Voltage (kV)
|
||
double Current, // 电流(μA)| Current (μA)
|
||
bool WaitForStable = true,
|
||
int StableTimeoutMs = 10000) : CncNode(Id, Index, CncNodeType.RaySourceControl, Name);
|
||
|
||
/// <summary>探测器校正类型 | Detector correction type</summary>
|
||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||
public enum DetectorCorrectionType
|
||
{
|
||
/// <summary>暗场校正 | Dark field correction</summary>
|
||
Dark,
|
||
/// <summary>增益(亮场)校正 | Gain (bright field) correction</summary>
|
||
Gain,
|
||
/// <summary>坏像素校正 | Bad pixel correction</summary>
|
||
BadPixel,
|
||
/// <summary>自动校正(暗场+增益+坏像素)| Auto correction (dark + gain + bad pixel)</summary>
|
||
Auto
|
||
}
|
||
|
||
/// <summary>探测器校正节点 | Detector correction node</summary>
|
||
public record DetectorCorrectionNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
DetectorCorrectionType CorrectionType,
|
||
int FrameCount = 10) : CncNode(Id, Index, CncNodeType.DetectorCorrection, Name);
|
||
|
||
/// <summary>安全门动作 | Safety door action</summary>
|
||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||
public enum DoorAction
|
||
{
|
||
/// <summary>开门 | Open door</summary>
|
||
Open,
|
||
/// <summary>关门 | Close door</summary>
|
||
Close
|
||
}
|
||
|
||
/// <summary>安全门控制节点 | Safety door control node</summary>
|
||
public record DoorControlNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
DoorAction Action,
|
||
bool WaitForComplete = true,
|
||
int TimeoutMs = 15000) : CncNode(Id, Index, CncNodeType.DoorControl, Name);
|
||
|
||
/// <summary>几何设置模式 | Geometry setup mode</summary>
|
||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||
public enum GeometryMode
|
||
{
|
||
/// <summary>由 FOD + FDD 反算 | Inverse from FOD + FDD</summary>
|
||
ByFdd,
|
||
/// <summary>由 FOD + 放大倍率反算 | Inverse from FOD + magnification</summary>
|
||
ByMagnification
|
||
}
|
||
|
||
/// <summary>几何设置节点 | Geometry setup node</summary>
|
||
public record GeometryNode(
|
||
Guid Id,
|
||
int Index,
|
||
string Name,
|
||
GeometryMode Mode,
|
||
double Fod, // 焦点-物体距离(mm)| Focus-object distance (mm)
|
||
double Fdd = 0, // 焦点-探测器距离(mm)| Focus-detector distance (mm)
|
||
double Magnification = 0,
|
||
bool WaitForSettled = true) : CncNode(Id, Index, CncNodeType.Geometry, Name);
|
||
|
||
// ── CNC 程序 | CNC Program ────────────────────────────────────────
|
||
|
||
/// <summary>CNC 程序(不可变)| CNC program (immutable)</summary>
|
||
public record CncProgram(
|
||
Guid Id,
|
||
string Name,
|
||
DateTime CreatedAt,
|
||
DateTime UpdatedAt,
|
||
IReadOnlyList<CncNode> Nodes
|
||
);
|
||
|
||
// ── 节点执行状态 | Node Execution State ──────────────────────────
|
||
|
||
/// <summary>节点执行状态枚举 | Node execution state enumeration</summary>
|
||
public enum NodeExecutionState
|
||
{
|
||
/// <summary>未执行(默认)| Not yet executed (default)</summary>
|
||
Idle,
|
||
/// <summary>正在执行 | Currently executing</summary>
|
||
Running,
|
||
/// <summary>执行成功 | Execution succeeded</summary>
|
||
Succeeded,
|
||
/// <summary>执行失败 | Execution failed</summary>
|
||
Failed
|
||
}
|
||
}
|