public class Controller : INamed<string>, IDisposable
{
private ControllerHandle controllerHandle;
private bool disposed;
private readonly Data data;
private readonly ControllerInformation information;
private readonly ControllerParameters parameters;
private readonly TasksCollection tasks;
private readonly ControlCenter controlCenter;
private readonly TaskSelectionCommands commands;
private readonly ControllerVariableContainer variables;
private readonly LoadedProgramCollection loadedPrograms;
private readonly CallbackRegistrar callbackRegistrar;
private static object mutex = new object();
private static Controller connectedController;
private static SystemConfiguration systemConfiguration;
string INamed<string>.Name => "A3200";
public Data DataCollection => data;
public ControllerInformation Information => information;
public ControllerParameters Parameters => parameters;
public TasksCollection Tasks => tasks;
public ControlCenter ControlCenter => controlCenter;
public TaskSelectionCommands Commands => commands;
public ControllerVariableContainer Variables => variables;
public LoadedProgramCollection LoadedPrograms => loadedPrograms;
internal ControllerHandle Handle => controllerHandle;
internal CallbackRegistrar CallbackRegistrar => callbackRegistrar;
internal int Number => 0;
public static Controller ConnectedController => connectedController;
public static SystemConfiguration Configuration
{
get
{
if (systemConfiguration == null)
{
systemConfiguration = new SystemConfiguration();
}
return systemConfiguration;
}
}
public static bool IsRunning
{
get
{
int pdwInitialized_ = 0;
ExceptionResolver.ResolveThrow(Wrapper.AerSysIsSystemInitialized(ref pdwInitialized_));
return pdwInitialized_ != 1;
}
}
internal Controller(IntPtr controllerHandle)
: this(new ControllerHandle(controllerHandle))
{
}
internal Controller(ControllerHandle controllerHandle)
{
this.controllerHandle = controllerHandle;
information = new ControllerInformation(this);
parameters = new ControllerParameters(this, new ControllerParameterCreator(this));
tasks = new TasksCollection(this);
callbackRegistrar = new CallbackRegistrar(this);
commands = new TaskSelectionCommands(this);
data = new Data(this);
controlCenter = new ControlCenter(this);
variables = new ControllerVariableContainer(this);
loadedPrograms = new LoadedProgramCollection(this);
Information.ControllerResetPre += delegate (object sender, ControllerEventArgs eventArgs)
{
eventArgs.Controller.Parameters.InvalidateCache();
eventArgs.Controller.Information.invalidateCache();
};
}
~Controller()
{
Dispose(disposing: false);
}
public void Reset()
{
if (controllerHandle == null)
{
throw new InvalidOperationException(Resources.ControllerNotConnectedException);
}
InitializationWrapper(controllerHandle.Value, smc: true);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
public void ChangePassword(string oldPassword, string newPassword)
{
if (oldPassword == null)
{
throw new ArgumentNullException("oldPassword");
}
if (newPassword == null)
{
throw new ArgumentNullException("newPassword");
}
ExceptionResolver.ResolveThrow(Wrapper.AerSysSetPassword(controllerHandle.Value, oldPassword, newPassword));
}
protected virtual void Dispose(bool disposing)
{
if (!disposed && disposing)
{
information.stopResetThread();
Wrapper.AerEventWaitCancel(controllerHandle.Value);
controlCenter.UnsubscribeAll();
CallbackRegistrar.ShutDown();
((IDisposable)DataCollection.Poller).Dispose();
controllerHandle.Dispose();
variables.Dispose();
disposed = true;
}
}
public static Controller Connect()
{
Disconnect();
IntPtr phAerCtrl_ = IntPtr.Zero;
int pdwConfigMode_ = 0;
ExceptionResolver.ResolveThrow(Wrapper.AerSysConnect(ref phAerCtrl_, ref pdwConfigMode_));
try
{
_SYS_INIT_INFO pSysInitInfo_ = default(_SYS_INIT_INFO);
Wrapper.AerSysServerIsInitialized(phAerCtrl_, ref pSysInitInfo_);
InitializationWrapper(phAerCtrl_, !pSysInitInfo_.bSmcIsInitialized);
}
catch
{
Wrapper.AerSysDisconnect(phAerCtrl_);
throw;
}
lock (mutex)
{
connectedController = new Controller(phAerCtrl_);
DiagPacketPoller.Threader.ResetInterval();
DiagPacketPoller.Threader.Spooler.InitQueue(1);
TaskStatesPoller.Threader.ResetInterval();
TaskStatesPoller.Threader.Spooler.InitQueue(1);
return connectedController;
}
}
private static void InitializationWrapper(IntPtr handle, bool smc)
{
int pdwInitErrorState_ = 0;
ErrorData peRcWarning_ = default(ErrorData);
StringBuilder stringBuilder = new StringBuilder(4096);
if (smc)
{
ErrorData errorData = Wrapper.AerSysInitialize(handle, null, bResetFieldbus_: true, ref pdwInitErrorState_, ref peRcWarning_, stringBuilder);
string errorMessage = ExceptionResolver.GetErrorMessage(errorData, stringBuilder.ToString());
ExceptionResolver.ResolveThrow(errorData, errorMessage);
}
}
public static void Disconnect()
{
DiagPacketPoller.Threader.StopAll();
TaskStatesPoller.Threader.StopAll();
lock (mutex)
{
if (connectedController != null)
{
connectedController.Dispose();
}
connectedController = null;
DiagPacketPoller.Threader.Spooler.InitQueue(0);
TaskStatesPoller.Threader.Spooler.InitQueue(0);
}
}
}
以下是对 Controller
类的深度解析,从架构设计到实现细节的全面分析:
1. 核心角色
作为 硬件控制系统的中枢管理类,主要职责包括:
-
硬件连接生命周期管理(连接/断开/重置)
-
子系统协调:任务、程序、变量、回调等组件的统一访问入口
-
线程安全的全局状态维护
-
密码保护和资源清理
2. 关键设计模式
(1)单例模式(受限)
private static Controller connectedController;
private static object mutex = new object();
public static Controller Connect() {
lock(mutex) {
if (connectedController == null) {
// 初始化连接...
connectedController = new Controller(phAerCtrl_);
}
return connectedController;
}
}
-
全局唯一性:通过静态字段确保单连接实例
-
线程安全:使用
mutex
保护连接过程
(2)组合模式
-
子系统解耦:各功能模块通过独立类实现
-
统一接口:通过Controller属性暴露子组件
(3)观察者模式
Information.ControllerResetPre += (sender, e) => {
e.Controller.Parameters.InvalidateCache();
// ...
};
-
事件驱动:硬件状态变化通知相关组件
3. 核心组件分析
组件 | 类型 | 功能 |
---|---|---|
TasksCollection | 集合管理 | 所有任务的容器 |
CallbackRegistrar | 事件处理 | 硬件回调注册中心 |
ControllerHandle | 资源封装 | 原生硬件句柄的托管包装 |
DiagPacketPoller | 后台服务 | 诊断数据轮询 |
4. 硬件交互关键流程
(1)连接初始化
(2)资源释放
protected virtual void Dispose(bool disposing) {
if (!disposed) {
// 1. 停止监控线程
information.stopResetThread();
// 2. 取消硬件事件等待
Wrapper.AerEventWaitCancel(handle);
// 3. 释放所有子组件
controlCenter.UnsubscribeAll();
callbackRegistrar.ShutDown();
// 4. 释放原生句柄
controllerHandle.Dispose();
}
}
5. 线程安全设计
机制 | 应用场景 | 实现方式 |
---|---|---|
静态锁 | 全局连接管理 | lock(mutex) 保护 connectedController |
后台轮询 | 状态监控 | DiagPacketPoller 独立线程 |
事件取消 | 资源释放 | AerEventWaitCancel 中断硬件等待 |
6. 典型使用场景
(1)系统初始化
using (var controller = Controller.Connect()) {
controller.Tasks[0].ExecutionMode = TaskExecutionMode.SingleStep;
controller.LoadedPrograms.Add("test.script");
}
(2)异常处理
try {
controller.Reset();
} catch (A3200Exception ex) {
Console.WriteLine($"Reset failed: {ex.ErrorData}");
}
总结
该类的设计优势:
-
清晰的层次结构:通过组合模式分离关注点
-
可靠的资源管理:完善的Dispose模式
-
全局协调能力:统一管理硬件访问和后台服务
适用于需要 精确控制物理设备 的工业自动化场景,典型应用于:
-
CNC机床控制系统
-
机器人运动控制
-
实时数据采集系统
通过引入异步模式和更细粒度的状态监控,可进一步提升其在现代工业4.0系统中的适用性。