public class FieldbusVariableContainer
{
private readonly Controller controller;
private const string ElementCountTerminator = ".count";
private PCModbusSlaveConnectionVariableContainer pcModbusSlaveVars;
private INamedConstantCollection<PCModbusMasterConnectionVariableContainer, ModbusMasterConnectionInformation> pcModbusMasterVars;
private INamedConstantCollection<DriveModbusMasterConnectionVariableContainer, DriveModbusMasterConnectionInformation> driveModbusMasterVars;
private INamedConstantCollection<HilscherConnectionVariableContainer, HilscherConnectionInformation> hilscherVars;
public Variable this[string name]
{
get
{
populateVariables(force: false);
if (pcModbusSlaveVars != null)
{
Variable variable = pcModbusSlaveVars[name];
if (variable != null)
{
return variable;
}
}
foreach (HilscherConnectionVariableContainer hilscherVar in hilscherVars)
{
Variable variable2 = hilscherVar[name];
if (variable2 != null)
{
return variable2;
}
}
foreach (DriveModbusMasterConnectionVariableContainer driveModbusMasterVar in driveModbusMasterVars)
{
Variable variable3 = driveModbusMasterVar[name];
if (variable3 != null)
{
return variable3;
}
}
foreach (PCModbusMasterConnectionVariableContainer pcModbusMasterVar in pcModbusMasterVars)
{
Variable variable4 = pcModbusMasterVar[name];
if (variable4 != null)
{
return variable4;
}
}
return null;
}
}
public PCModbusSlaveConnectionVariableContainer PCModbusSlave
{
get
{
populateVariables(force: false);
return pcModbusSlaveVars;
}
}
public INamedConstantCollection<PCModbusMasterConnectionVariableContainer, ModbusMasterConnectionInformation> PCModbusMaster
{
get
{
populateVariables(force: false);
return pcModbusMasterVars;
}
}
public INamedConstantCollection<DriveModbusMasterConnectionVariableContainer, DriveModbusMasterConnectionInformation> DriveModbusMaster
{
get
{
populateVariables(force: false);
return driveModbusMasterVars;
}
}
public INamedConstantCollection<HilscherConnectionVariableContainer, HilscherConnectionInformation> Hilscher
{
get
{
populateVariables(force: false);
return hilscherVars;
}
}
internal FieldbusVariableContainer(Controller c)
{
if (c == null)
{
throw new ArgumentNullException("c");
}
controller = c;
controller.Information.ControllerResettingPre += delegate
{
invalidateCache();
};
}
private void invalidateCache()
{
pcModbusSlaveVars = null;
pcModbusMasterVars = null;
driveModbusMasterVars = null;
hilscherVars = null;
}
private void populateVariables(bool force)
{
if (force)
{
invalidateCache();
}
else if (hilscherVars != null && driveModbusMasterVars != null && pcModbusMasterVars != null)
{
return;
}
Dictionary<int, HilscherConnectionVariableContainer> dictionary = new Dictionary<int, HilscherConnectionVariableContainer>();
Dictionary<int, DriveModbusMasterConnectionVariableContainer> dictionary2 = new Dictionary<int, DriveModbusMasterConnectionVariableContainer>();
Dictionary<int, PCModbusMasterConnectionVariableContainer> dictionary3 = new Dictionary<int, PCModbusMasterConnectionVariableContainer>();
Dictionary<int, PCModbusSlaveConnectionVariableContainer> dictionary4 = new Dictionary<int, PCModbusSlaveConnectionVariableContainer>();
StringBuilder stringBuilder = new StringBuilder(260);
Wrapper.UtilFieldbusGetDefinesFilePath(stringBuilder, stringBuilder.Capacity);
string[] defineNamesFromFile = CoreVariableHelper.GetDefineNamesFromFile(controller, stringBuilder.ToString());
IntPtr phCompiler_ = IntPtr.Zero;
ExceptionResolver.ResolveThrow(Wrapper.AerCompilerOpen(ref phCompiler_));
using (CompilerHandle compilerHandle = new CompilerHandle(phCompiler_))
{
string[] array = defineNamesFromFile;
foreach (string name in array)
{
if (name.EndsWith(".count"))
{
continue;
}
int result = 1;
if (Array.Exists(defineNamesFromFile, (string defineName) => defineName == name + ".count"))
{
StringBuilder stringBuilder2 = new StringBuilder(4096);
ExceptionResolver.ResolveThrow(controller, Wrapper.AerCompilerGetSubstitutionTextForDefine(compilerHandle.Value, name + ".count", stringBuilder2, stringBuilder2.Capacity));
int.TryParse(stringBuilder2.ToString().Trim(), out result);
}
List<Variable> list = new List<Variable>();
if (result > 1)
{
for (int j = 0; j < result; j++)
{
_PTR_DATA pVariableInfo_ = default(_PTR_DATA);
string text = $"{name}[{j}]";
ExceptionResolver.ResolveThrow(controller, Wrapper.AerCompilerParseVariableInfo(compilerHandle.Value, text, ref pVariableInfo_));
list.Add(CoreVariableHelper.CreateFieldbusVariable(controller, text, pVariableInfo_));
}
}
else
{
_PTR_DATA pVariableInfo_2 = default(_PTR_DATA);
ExceptionResolver.ResolveThrow(controller, Wrapper.AerCompilerParseVariableInfo(compilerHandle.Value, name, ref pVariableInfo_2));
list.Add(CoreVariableHelper.CreateFieldbusVariable(controller, name, pVariableInfo_2));
}
Variable firstVar = list[0];
if (list[0] == null)
{
continue;
}
int num = (Array.Exists(CoreVariableHelper.GetHasConnectionContexts(), (VariableContext varContext) => varContext == firstVar.Context) ? firstVar.CoreIdentifier.arrayDimension[0].dwValue : 0);
switch (firstVar.Context)
{
case VariableContext.FieldbusInput:
case VariableContext.FieldbusOutput:
if (!dictionary.ContainsKey(num))
{
_HilscherConnectionInfo pConnInfo_3 = default(_HilscherConnectionInfo);
ExceptionResolver.ResolveThrow(controller, Wrapper.AerFieldbusGetHilscherConnectionInfo(controller.Handle.Value, (short)num, ref pConnInfo_3));
HilscherConnectionInformation connInfo3 = new HilscherConnectionInformation(pConnInfo_3.displayName, pConnInfo_3.id, (FieldbusType)pConnInfo_3.type);
dictionary[num] = new HilscherConnectionVariableContainer(connInfo3);
}
foreach (Variable item in list)
{
dictionary[num].AddVariable(item);
}
break;
case VariableContext.DriveModbusMasterInputWord:
case VariableContext.DriveModbusMasterOutputWord:
case VariableContext.DriveModbusMasterOutputWordStatus:
case VariableContext.DriveModbusMasterInputBit:
case VariableContext.DriveModbusMasterOutputBit:
case VariableContext.DriveModbusMasterOutputBitStatus:
if (!dictionary2.ContainsKey(num))
{
_DriveModbusMasterConnectionInfo pConnInfo_2 = default(_DriveModbusMasterConnectionInfo);
ExceptionResolver.ResolveThrow(controller, Wrapper.AerFieldbusGetDriveModbusMasterConnectionInfo(controller.Handle.Value, (short)num, ref pConnInfo_2));
DriveModbusMasterConnectionInformation connInfo2 = new DriveModbusMasterConnectionInformation(pConnInfo_2.displayName, pConnInfo_2.slaveId, IPAddress.Parse(pConnInfo_2.slaveIp), pConnInfo_2.slavePort, pConnInfo_2.axis);
dictionary2[num] = new DriveModbusMasterConnectionVariableContainer(connInfo2);
}
foreach (Variable item2 in list)
{
dictionary2[num].AddVariable(item2);
}
break;
case VariableContext.ModbusMasterInputWord:
case VariableContext.ModbusMasterOutputWord:
case VariableContext.ModbusMasterOutputWordStatus:
case VariableContext.ModbusMasterInputBit:
case VariableContext.ModbusMasterOutputBit:
case VariableContext.ModbusMasterOutputBitStatus:
if (!dictionary3.ContainsKey(num))
{
_PCModbusMasterConnectionInfo pConnInfo_4 = default(_PCModbusMasterConnectionInfo);
ExceptionResolver.ResolveThrow(controller, Wrapper.AerFieldbusGetPCModbusMasterConnectionInfo(controller.Handle.Value, (short)num, ref pConnInfo_4));
ModbusMasterConnectionInformation connInfo4 = new ModbusMasterConnectionInformation(pConnInfo_4.displayName, pConnInfo_4.slaveId, IPAddress.Parse(pConnInfo_4.slaveIp), pConnInfo_4.slavePort);
dictionary3[num] = new PCModbusMasterConnectionVariableContainer(connInfo4);
}
foreach (Variable item3 in list)
{
dictionary3[num].AddVariable(item3);
}
break;
case VariableContext.ModbusSlaveInputWord:
case VariableContext.ModbusSlaveOutputWord:
case VariableContext.ModbusSlaveInputBit:
case VariableContext.ModbusSlaveOutputBit:
if (!dictionary4.ContainsKey(num))
{
_PCModbusSlaveConnectionInfo pConnInfo_ = default(_PCModbusSlaveConnectionInfo);
ExceptionResolver.ResolveThrow(controller, Wrapper.AerFieldbusGetPCModbusSlaveConnectionInfo(controller.Handle.Value, ref pConnInfo_));
ModbusSlaveConnectionInformation connInfo = new ModbusSlaveConnectionInformation(pConnInfo_.displayName, pConnInfo_.id, pConnInfo_.inputWords, pConnInfo_.outputWords, pConnInfo_.inputBits, pConnInfo_.outputBits);
dictionary4[num] = new PCModbusSlaveConnectionVariableContainer(connInfo);
}
foreach (Variable item4 in list)
{
dictionary4[num].AddVariable(item4);
}
break;
}
}
}
driveModbusMasterVars = new NamedConstantCollection<DriveModbusMasterConnectionVariableContainer, DriveModbusMasterConnectionInformation>(dictValues2Array(dictionary2));
pcModbusMasterVars = new NamedConstantCollection<PCModbusMasterConnectionVariableContainer, ModbusMasterConnectionInformation>(dictValues2Array(dictionary3));
pcModbusSlaveVars = ((dictionary4.Count > 0) ? dictionary4[0] : null);
hilscherVars = new NamedConstantCollection<HilscherConnectionVariableContainer, HilscherConnectionInformation>(dictValues2Array(dictionary));
}
private static TValue[] dictValues2Array<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
return new List<TValue>(dict.Values).ToArray();
}
}
以下是针对 FieldbusVariableContainer 类的专业解析,结合工业通信协议和软件设计模式的深度分析:
1. 核心功能定位
该类是 工业现场总线(Fieldbus)变量的统一管理容器,支持多种工业通信协议:
Modbus TCP Slave/Master(PC端)
Modbus TCP Master(驱动器端)
Hilscher协议(专有工业通信协议)
通过分层架构实现对不同设备通信变量的统一访问。
2. 架构设计
2.1 成员结构
| 成员 | 类型 | 协议类型 | 典型变量示例 |
|---|---|---|---|
pcModbusSlaveVars |
PCModbusSlaveConnectionVariableContainer |
Modbus TCP Slave | "Slave1.InputWord[0]" |
pcModbusMasterVars |
INamedConstantCollection<PCModbusMaster..., ModbusMasterConnInfo> |
Modbus TCP Master | "Master1.OutputBit[2]" |
driveModbusMasterVars |
INamedConstantCollection<DriveModbusMaster..., DriveModbusConnInfo> |
驱动器Modbus Master | "Drive1.InputWord[10]" |
hilscherVars |
INamedConstantCollection<HilscherConnection..., HilscherConnInfo> |
Hilscher协议 | "Hilscher1.Output[3]" |
2.2 核心机制
延迟加载:通过 populateVariables(force: false) 实现按需初始化
缓存管理:控制器复位时自动清空缓存(ControllerResettingPre 事件绑定)
动态解析:从配置文件解析变量定义(defineNamesFromFile)
3. 关键流程解析
3.1 变量初始化流程 (populateVariables)

3.2 变量查找逻辑 (this[name])
// 搜索顺序优先级
1. Modbus Slave变量
2. Hilscher协议变量
3. 驱动器Modbus变量
4. PC Modbus Master变量
4. 协议特定处理
4.1 Modbus TCP 变量
// 典型变量上下文
VariableContext.ModbusSlaveInputWord // 从站输入寄存器
VariableContext.ModbusMasterOutputBit // 主站输出线圈
// 连接信息解析
_PCModbusSlaveConnectionInfo slaveInfo;
Wrapper.AerFieldbusGetPCModbusSlaveConnectionInfo(..., ref slaveInfo);
特点:
区分主/从站模式
支持线圈(Bit)和寄存器(Word)操作
4.2 Hilscher协议变量
_HilscherConnectionInfo hilscherInfo;
Wrapper.AerFieldbusGetHilscherConnectionInfo(..., ref hilscherInfo);
特点:
使用专有连接ID标识设备
支持多种Fieldbus类型(通过FieldbusType枚举)
5. 工业级实现细节
5.1 变量维度处理
if (name.EndsWith(".count")) // 忽略维度定义文件
if (result > 1) // 处理数组型变量
{
for (int j = 0; j < result; j++) {
string text = $"{name}[{j}]"; // 构造带下标的变量名
// 解析每个数组元素...
}
}
作用:支持PLC中常见的数组变量(如 InputWord[0..15])
5.2 编译器集成
using (CompilerHandle compilerHandle = new CompilerHandle(phCompiler_))
{
Wrapper.AerCompilerParseVariableInfo(..., name, ref pVariableInfo_);
}
必要性:依赖编译器解析变量地址映射关系。
5.3 连接信息缓存
Dictionary<int, DriveModbusMasterConnectionVariableContainer> dictionary2 = new ...;
if (!dictionary2.ContainsKey(num))
{
// 首次访问时初始化连接信息
dictionary2[num] = new DriveModbusMasterConnectionVariableContainer(...);
}
优化:避免重复查询硬件连接信息。
6. 典型使用场景
// 获取现场总线容器
var fieldbus = new FieldbusVariableContainer(controller);
// 访问Modbus Slave输入寄存器
double slaveInput = fieldbus["Slave1.InputWord[0]"].Value;
// 批量获取Hilscher变量
foreach (var hilscherVar in fieldbus.Hilscher) {
// 处理每个Hilscher设备变量...
}
// 设置驱动器Modbus输出
fieldbus.DriveModbusMaster[0].OutputWord[1].Value = 100;
7. 设计亮点
协议抽象
统一接口访问不同现场总线协议,上层无需关心底层差异
动态扩展
通过 INamedConstantCollection 支持运行时设备热插拔
工业标准兼容
严格遵循Modbus和Hilscher协议规范
资源安全
using 语句确保编译器句柄释放
8. 改进建议
异步支持:增加 GetVariableAsync 方法适应高并发场景
变量监控:实现 IVariableObserver 接口监听变量变化
协议扩展:通过策略模式方便添加新协议(如PROFINET)
该设计完美体现了工业控制软件对 多协议兼容 和 实时性 的要求,是现场总线通信层的典范实现。


















暂无评论内容