public class ControllerInformation
{
private readonly Controller controller;
private readonly InternalUtilities.KeepRunningContainer resetResettingThreadKeepRunning = new InternalUtilities.KeepRunningContainer();
private readonly Thread resetResettingThread;
private DriveCommunicationType driveCommunicationType;
private NamedMaskedConstantCollection<AxisInfo, string, AxisMask> axes;
private ReadOnlyCollection<DriveInformation> allDrives;
private ReadOnlyCollection<MotionDriveInformation> motionDrives;
private ControllerVersion version;
private readonly InitializationInformation initialization;
public DriveCommunicationType DriveCommunicationType => driveCommunicationType;
public string Name => "A3200";
public INamedMaskedConstantCollection<AxisInfo, string, AxisMask> Axes
{
get
{
if (axes == null)
{
initializeData();
}
return axes;
}
}
public ReadOnlyCollection<DriveInformation> AllDrives
{
get
{
if (allDrives == null)
{
initializeData();
}
return allDrives;
}
}
public ReadOnlyCollection<MotionDriveInformation> MotionDrives
{
get
{
if (motionDrives == null)
{
initializeData();
}
return motionDrives;
}
}
public ControllerVersion Version
{
get
{
if (version == null)
{
initializeData();
}
return version;
}
}
public InitializationInformation Initialization => initialization;
internal event EventHandler<ControllerEventArgs> ControllerResettingPre;
public event EventHandler<ControllerEventArgs> ControllerResetting;
internal event EventHandler<ControllerEventArgs> ControllerResettingPost;
internal event EventHandler<ControllerEventArgs> ControllerResetPre;
public event EventHandler<ControllerEventArgs> ControllerReset;
internal event EventHandler<ControllerEventArgs> ControllerResetPost;
internal ControllerInformation(Controller controller)
{
this.controller = controller;
initialization = new InitializationInformation(controller);
ExceptionResolver.ResolveThrow(Wrapper.AerEventRegister(this.controller.Handle.Value, 1, 0));
ExceptionResolver.ResolveThrow(Wrapper.AerEventRegister(this.controller.Handle.Value, 2, 0));
driveCommunicationType = DriveCommunicationType.NoCard;
ExceptionResolver.ResolveThrow(Wrapper.AerStatusGetDriveCommunicationType(this.controller.Handle.Value, ref driveCommunicationType));
ThreadStart startDelegate = delegate
{
int pdwEventID_ = 0;
int pdwEventNum_ = 0;
bool needToRaiseReset = false;
Action<EventHandler<ControllerEventArgs>> raiseEvent = delegate (EventHandler<ControllerEventArgs> eventToRaise)
{
eventToRaise?.Invoke(this.controller, new ControllerEventArgs(this.controller));
};
Dictionary<int, ThreadStart> dictionary = new Dictionary<int, ThreadStart>
{
[2] = delegate
{
needToRaiseReset = true;
raiseEvent(this.ControllerResettingPre);
raiseEvent(this.ControllerResetting);
raiseEvent(this.ControllerResettingPost);
},
[1] = delegate
{
needToRaiseReset = false;
raiseEvent(this.ControllerResetPre);
raiseEvent(this.ControllerReset);
raiseEvent(this.ControllerResetPost);
}
};
while (resetResettingThreadKeepRunning.KeepRunning)
{
ErrorData errorData = Wrapper.AerEventWait(this.controller.Handle.Value, ref pdwEventID_, ref pdwEventNum_, 100);
if ((errorData.Code != 96 || errorData.Location != 4) && dictionary.ContainsKey(pdwEventID_))
{
dictionary[pdwEventID_]();
}
}
if (needToRaiseReset)
{
dictionary[1]();
}
};
resetResettingThread = new Thread(InternalUtilities.WrapDelegateForCulture(startDelegate));
resetResettingThread.Name = "A3200 Reset/Resetting";
resetResettingThread.IsBackground = true;
resetResettingThread.Start();
}
private void initializeData()
{
int pdwMajor_ = 0;
int pdwMinor_ = 0;
int pdwPatch_ = 0;
int pdwBuild_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerInfoGetSMCVersionEx(controller.Handle.Value, ref pdwMajor_, ref pdwMinor_, ref pdwPatch_, ref pdwBuild_));
Version smcVersion = new Version(pdwMajor_, pdwMinor_, pdwPatch_, pdwBuild_);
version = new ControllerVersion(smcVersion);
AxisInfo[] array = new AxisInfo[32];
for (int i = 0; i < array.Length; i++)
{
int pdwHardwareType_ = 0;
int pdwMajorVersion_ = 0;
int pdwMinorVersion_ = 0;
int pdwPatchVersion_ = 0;
int pdwBuildVersion_ = 0;
int pdwFPGAVersion_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerInfoGetDriveVersion(controller.Handle.Value, i, ref pdwHardwareType_, ref pdwMajorVersion_, ref pdwMinorVersion_, ref pdwPatchVersion_, ref pdwBuildVersion_, ref pdwFPGAVersion_));
array[i] = new AxisInfo(controller, i, pdwFPGAVersion_);
}
axes = new NamedMaskedConstantCollection<AxisInfo, string, AxisMask>(array);
int pNumDrives_ = 0;
ExceptionResolver.ResolveThrow(controller, Wrapper.AerInfoGetNumberDrives(controller.Handle.Value, ref pNumDrives_));
tagAER_DRIVE_INFO[] array2 = new tagAER_DRIVE_INFO[pNumDrives_];
for (int j = 0; j < pNumDrives_; j++)
{
tagAER_DRIVE_INFO pDriveInfo_ = default(tagAER_DRIVE_INFO);
ExceptionResolver.ResolveThrow(Wrapper.AerInfoGetDriveInfo(controller.Handle.Value, j, ref pDriveInfo_));
array2[j] = pDriveInfo_;
}
List<MotionDriveInformation> list = CreateDriveInformation(array2, axes);
motionDrives = list.AsReadOnly();
allDrives = list.ConvertAll((Converter<MotionDriveInformation, DriveInformation>)((MotionDriveInformation driveInfo) => driveInfo)).AsReadOnly();
}
internal static List<MotionDriveInformation> CreateDriveInformation(tagAER_DRIVE_INFO[] aerDriveInfos, INamedMaskedConstantCollection<AxisInfo, string, AxisMask> allAxes)
{
List<MotionDriveInformation> list = new List<MotionDriveInformation>();
for (int i = 0; i < aerDriveInfos.Length; i++)
{
tagAER_DRIVE_INFO tagAER_DRIVE_INFO = aerDriveInfos[i];
if (tagAER_DRIVE_INFO.NodeID == -1)
{
continue;
}
int num = tagAER_DRIVE_INFO.AxisMask;
ComponentType componentType = (ComponentType)tagAER_DRIVE_INFO.HardwareType;
if (componentType == ComponentType.XR3_NoAmplifier || componentType == ComponentType.XR3_XSP3 || componentType == ComponentType.XR3_XSL3 || componentType == ComponentType.XR3_QSL3e)
{
componentType = ComponentType.XR3;
}
if (tagAER_DRIVE_INFO.BackplaneSlot == 0)
{
int num2 = i + 1;
int num3 = 1;
while (num2 < aerDriveInfos.Length && aerDriveInfos[num2].BackplaneSlot == num3)
{
num |= aerDriveInfos[num2].AxisMask;
aerDriveInfos[num2].NodeID = -1;
num2++;
num3++;
}
}
INamedMaskedConstantCollection<AxisInfo, string, AxisMask> namedMaskedConstantCollection = allAxes.Remask((AxisMask)num);
int fpgaVersion = 0;
using (IEnumerator<AxisInfo> enumerator = namedMaskedConstantCollection.GetEnumerator())
{
if (enumerator.MoveNext())
{
fpgaVersion = enumerator.Current.FPGAVersion;
}
}
list.Add(new MotionDriveInformation(namedMaskedConstantCollection, tagAER_DRIVE_INFO.ChannelNumber, componentType, tagAER_DRIVE_INFO.VersionMajor, tagAER_DRIVE_INFO.VersionMinor, tagAER_DRIVE_INFO.VersionPatch, tagAER_DRIVE_INFO.VersionBuild, tagAER_DRIVE_INFO.NodeID, fpgaVersion, tagAER_DRIVE_INFO.IOBoardPresent != 0));
}
return list;
}
internal void invalidateCache()
{
version = null;
axes = null;
allDrives = null;
motionDrives = null;
initialization.invalidateCache();
}
internal void stopResetThread()
{
if (resetResettingThread != null)
{
resetResettingThreadKeepRunning.KeepRunning = false;
resetResettingThread.Join();
}
}
}
以下是针对 ControllerInformation
类的全面分析,结合其设计模式和实现细节:
1. 核心职责
作为 控制器状态信息管理中心,主要功能包括:
-
硬件信息收集:轴/驱动器版本、通信类型等
-
重置事件管理:处理控制器重置前后的状态变更
-
数据缓存与失效:按需加载硬件信息
-
线程安全的事件通知:通过多级事件通知状态变化
2. 关键设计模式
(1)观察者模式(多级事件)
-
精细事件阶段:区分重置前/中/后不同阶段
-
访问控制:公开关键事件,隐藏内部细节
(2)延迟初始化
public INamedMaskedConstantCollection<AxisInfo, string, AxisMask> Axes {
get {
if (axes == null) initializeData(); // 首次访问时加载
return axes;
}
}
(3)后台线程监控
resetResettingThread = new Thread(/* 事件处理循环 */) {
Name = "Acs Reset/Resetting",
IsBackground = true
};
3. 核心组件分析
组件 | 类型 | 功能 |
---|---|---|
KeepRunningContainer | 线程控制 | 安全停止后台线程 |
NamedMaskedConstantCollection | 集合管理 | 带掩码的轴信息集合 |
ControllerVersion | 值对象 | 封装控制器版本信息 |
InitializationInformation | 子系统 | 初始化状态管理 |
4. 关键流程
(1)数据初始化流程
(2)重置事件处理
5. 线程安全设计
机制 | 应用场景 | 实现方式 |
---|---|---|
后台线程 | 事件监控 | 独立线程运行 AerEventWait |
标记控制 | 线程停止 | KeepRunningContainer 布尔标志 |
延迟加载 | 数据缓存 | 通过null检查实现简易同步 |
6. 典型使用场景
(1)监控控制器状态
controller.Information.ControllerReset += (s,e) => {
Console.WriteLine("控制器已重置");
var drives = controller.Information.MotionDrives; // 触发重新初始化
};
(2)获取硬件信息
var axis = controller.Information.Axes["X"];
Console.WriteLine($"X轴FPGA版本: {axis.FPGAVersion}");
7. 改进建议
-
双重检查锁定
private readonly object _initLock = new object();
public INamedMaskedConstantCollection Axes {
get {
if (axes == null) {
lock (_initLock) {
if (axes == null) initializeData();
}
}
return axes;
}
}
异步事件支持
public event AsyncEventHandler<ControllerEventArgs> ControllerResetAsync;
健康检查
public bool IsHealthy {
get {
try {
return Wrapper.AerHealthCheck(handle) == 0;
} catch { return false; }
}
}
DI集成
services.AddSingleton<IControllerInfo>(sp =>
sp.GetRequiredService<Controller>().Information);
8. 异常处理
错误类型 | 处理方式 | 示例 |
---|---|---|
硬件通信错误 | 通过ExceptionResolver 转换 | AerInfoGetDriveVersion 错误 |
线程中断 | KeepRunning 标志检查 | 后台事件循环退出 |
无效访问 | null检查+延迟加载 | axes 字段初始化 |
总结
该类的设计亮点:
-
精细的事件分级:精确控制重置过程的通知时序
-
高效的数据加载:按需初始化减少启动开销
-
安全的线程管理:规范化的后台线程生命周期
典型应用于:
-
设备状态监控系统
-
控制器调试工具
-
自动化产线管理系统
通过增加异步支持和更健壮的缓存机制,可进一步提升其在高压环境下的可靠性。