控制器状态信息管理中心ControllerInformation类

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. 改进建议

  1. 双重检查锁定

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字段初始化

总结

该类的设计亮点:

  • 精细的事件分级:精确控制重置过程的通知时序

  • 高效的数据加载:按需初始化减少启动开销

  • 安全的线程管理:规范化的后台线程生命周期

典型应用于:

  1. 设备状态监控系统

  2. 控制器调试工具

  3. 自动化产线管理系统

通过增加异步支持和更健壮的缓存机制,可进一步提升其在高压环境下的可靠性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值