public class FieldbusMappings
{
internal const string FieldbusConfigurationSectionName = "FieldbusMap";
private readonly XmlElement fieldbusElement;
private readonly XmlNamespaceManager nsManager;
private readonly HilscherConnectionCollection hilscherConnMappings = new HilscherConnectionCollection();
private readonly FieldbusConnectionCollection<PCModbusMasterConnectionMappings, ModbusMasterConnectionInformation, PCModbusMasterMapping> pcModbusMasterMappings = new FieldbusConnectionCollection<PCModbusMasterConnectionMappings, ModbusMasterConnectionInformation, PCModbusMasterMapping>();
private PCModbusSlaveConnectionMappings pcModbusSlaveMappings;
private readonly DriveModbusMasterConnectionCollection driveModbusMasterMappings = new DriveModbusMasterConnectionCollection();
public INamedCollection<HilscherConnectionMappings, HilscherConnectionInformation> Hilscher => hilscherConnMappings;
public INamedCollection<PCModbusMasterConnectionMappings, ModbusMasterConnectionInformation> PCModbusMaster => pcModbusMasterMappings;
public PCModbusSlaveConnectionMappings PCModbusSlave
{
get
{
return pcModbusSlaveMappings;
}
set
{
if (pcModbusSlaveMappings == null && value == null)
{
return;
}
PCModbusSlaveConnectionMappings pCModbusSlaveConnectionMappings = pcModbusSlaveMappings;
try
{
pcModbusSlaveMappings = null;
if (value != null)
{
foreach (PCModbusSlaveMapping item in value)
{
nameValidatingHandler(this, new FieldbusMappingNameValidatingEventArgs(item.Name));
}
}
}
catch (InvalidOperationException ex)
{
pcModbusSlaveMappings = pCModbusSlaveConnectionMappings;
throw ex;
}
pcModbusSlaveMappings = value;
if (pCModbusSlaveConnectionMappings != null)
{
pCModbusSlaveConnectionMappings.ConfigurationChanged -= configurationChangedHandler;
pCModbusSlaveConnectionMappings.NameValidating -= nameValidatingHandler;
}
if (value != null)
{
pcModbusSlaveMappings.ConfigurationChanged += configurationChangedHandler;
pcModbusSlaveMappings.NameValidating += nameValidatingHandler;
}
configurationChangedHandler(this, new FieldbusMappingChangedEventArgs());
}
}
public INamedCollection<DriveModbusMasterConnectionMappings, DriveModbusMasterConnectionInformation> DriveModbusMaster => driveModbusMasterMappings;
internal static VariableType[] FieldbusVariableTypes => new VariableType[21]
{
VariableType.Bit,
VariableType.Bool,
VariableType.Byte,
VariableType.DInt,
VariableType.Double,
VariableType.DWord,
VariableType.Int,
VariableType.Int16,
VariableType.Int32,
VariableType.Int8,
VariableType.LReal,
VariableType.Real,
VariableType.Single,
VariableType.SInt,
VariableType.UDInt,
VariableType.UInt,
VariableType.UInt16,
VariableType.UInt32,
VariableType.UInt8,
VariableType.USInt,
VariableType.Word
};
internal FieldbusMappings(ParameterFile paramFile, XmlDocument paramFileXmlDoc, XmlNamespaceManager nsManager)
{
this.nsManager = nsManager;
XmlElement xmlElement = paramFile.UserDataSections["FieldbusMap"];
if (xmlElement == null)
{
xmlElement = paramFileXmlDoc.CreateElement("FieldbusMap", "http://www.aerotech.com/xsd/Controller/Parameters/2009/");
paramFile.UserDataSections["FieldbusMap"] = xmlElement;
}
fieldbusElement = xmlElement;
initHilscher();
initDriveModbusMaster();
initPcModbusMaster();
initPcModbusSlave();
}
private void initHilscher()
{
hilscherConnMappings.NameValidating += nameValidatingHandler;
foreach (XmlElement item in fieldbusElement.SelectNodes("p:HilscherCard", nsManager))
{
HilscherConnectionInformation hilscherConnectionInformation = new HilscherConnectionInformation();
((IParameterFileStorable)hilscherConnectionInformation).FromXml(item);
HilscherConnectionMappings hilscherConnectionMappings = new HilscherConnectionMappings(hilscherConnectionInformation);
foreach (XmlNode childNode in item.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
HilscherMapping hilscherMapping = new HilscherMapping();
((IParameterFileStorable)hilscherMapping).FromXml((XmlElement)childNode);
hilscherConnectionMappings.Add(hilscherMapping);
}
}
hilscherConnMappings.Add(hilscherConnectionMappings);
}
hilscherConnMappings.ConfigurationChanged += configurationChangedHandler;
}
private void initPcModbusMaster()
{
pcModbusMasterMappings.NameValidating += nameValidatingHandler;
foreach (XmlElement item in fieldbusElement.SelectNodes("p:PcModbusMaster", nsManager))
{
ModbusMasterConnectionInformation modbusMasterConnectionInformation = new ModbusMasterConnectionInformation();
((IParameterFileStorable)modbusMasterConnectionInformation).FromXml(item);
PCModbusMasterConnectionMappings pCModbusMasterConnectionMappings = new PCModbusMasterConnectionMappings(modbusMasterConnectionInformation);
foreach (XmlNode childNode in item.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
PCModbusMasterMapping pCModbusMasterMapping = new PCModbusMasterMapping();
((IParameterFileStorable)pCModbusMasterMapping).FromXml((XmlElement)childNode);
pCModbusMasterConnectionMappings.Add(pCModbusMasterMapping);
}
}
pcModbusMasterMappings.Add(pCModbusMasterConnectionMappings);
}
pcModbusMasterMappings.ConfigurationChanged += configurationChangedHandler;
}
private void initPcModbusSlave()
{
XmlElement xmlElement = (XmlElement)fieldbusElement.SelectSingleNode("p:PcModbusSlave", nsManager);
if (xmlElement == null)
{
return;
}
ModbusSlaveConnectionInformation modbusSlaveConnectionInformation = new ModbusSlaveConnectionInformation();
((IParameterFileStorable)modbusSlaveConnectionInformation).FromXml(xmlElement);
PCModbusSlaveConnectionMappings pCModbusSlaveConnectionMappings = new PCModbusSlaveConnectionMappings(modbusSlaveConnectionInformation);
foreach (XmlNode childNode in xmlElement.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
PCModbusSlaveMapping pCModbusSlaveMapping = new PCModbusSlaveMapping();
((IParameterFileStorable)pCModbusSlaveMapping).FromXml((XmlElement)childNode);
pCModbusSlaveConnectionMappings.Add(pCModbusSlaveMapping);
}
}
pcModbusSlaveMappings = pCModbusSlaveConnectionMappings;
pcModbusSlaveMappings.ConfigurationChanged += configurationChangedHandler;
pcModbusSlaveMappings.NameValidating += nameValidatingHandler;
}
private void initDriveModbusMaster()
{
driveModbusMasterMappings.NameValidating += nameValidatingHandler;
foreach (XmlElement item in fieldbusElement.SelectNodes("p:DriveModbusMaster", nsManager))
{
DriveModbusMasterConnectionInformation driveModbusMasterConnectionInformation = new DriveModbusMasterConnectionInformation();
((IParameterFileStorable)driveModbusMasterConnectionInformation).FromXml(item);
DriveModbusMasterConnectionMappings driveModbusMasterConnectionMappings = new DriveModbusMasterConnectionMappings(driveModbusMasterConnectionInformation);
foreach (XmlNode childNode in item.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
DriveModbusMasterMapping driveModbusMasterMapping = new DriveModbusMasterMapping();
((IParameterFileStorable)driveModbusMasterMapping).FromXml((XmlElement)childNode);
driveModbusMasterConnectionMappings.Add(driveModbusMasterMapping);
}
}
driveModbusMasterMappings.Add(driveModbusMasterConnectionMappings);
}
driveModbusMasterMappings.ConfigurationChanged += configurationChangedHandler;
}
private void configurationChangedHandler(object sender, FieldbusMappingChangedEventArgs e)
{
fieldbusElement.RemoveAll();
foreach (HilscherConnectionMappings hilscherConnMapping in hilscherConnMappings)
{
fieldbusElement.AppendChild(((IParameterFileStorable)hilscherConnMapping).ToXml(fieldbusElement.OwnerDocument));
}
foreach (PCModbusMasterConnectionMappings pcModbusMasterMapping in pcModbusMasterMappings)
{
fieldbusElement.AppendChild(((IParameterFileStorable)pcModbusMasterMapping).ToXml(fieldbusElement.OwnerDocument));
}
foreach (DriveModbusMasterConnectionMappings driveModbusMasterMapping in driveModbusMasterMappings)
{
fieldbusElement.AppendChild(((IParameterFileStorable)driveModbusMasterMapping).ToXml(fieldbusElement.OwnerDocument));
}
if (pcModbusSlaveMappings != null)
{
fieldbusElement.AppendChild(((IParameterFileStorable)pcModbusSlaveMappings).ToXml(fieldbusElement.OwnerDocument));
}
}
private void nameValidatingHandler(object sender, FieldbusMappingNameValidatingEventArgs e)
{
if (CheckNameExists(e.Name))
{
throw new InvalidOperationException(string.Format(Resources.FieldbusMappingNameInvalid, e.Name));
}
}
internal bool CheckNameExists(string name)
{
IntPtr phCompiler_ = IntPtr.Zero;
ExceptionResolver.ResolveThrow(Wrapper.AerCompilerOpen(ref phCompiler_));
string pszVarName_ = "$" + name;
_PTR_DATA pVariableInfo_ = default(_PTR_DATA);
using (CompilerHandle compilerHandle = new CompilerHandle(phCompiler_))
{
ExceptionResolver.ResolveThrow(Wrapper.AerCompilerParseVariableInfo(compilerHandle.Value, pszVarName_, ref pVariableInfo_));
}
PtrType ptrType = (PtrType)pVariableInfo_.ptrType;
if (!isFieldbusPtrType(ptrType) && ptrType != PtrType.DBL_PROGRAM_VAR)
{
return true;
}
foreach (HilscherConnectionMappings item in Hilscher)
{
if (item[name] != null)
{
return true;
}
}
foreach (DriveModbusMasterConnectionMappings item2 in DriveModbusMaster)
{
if (item2[name] != null)
{
return true;
}
}
foreach (PCModbusMasterConnectionMappings item3 in PCModbusMaster)
{
if (item3[name] != null)
{
return true;
}
}
if (PCModbusSlave != null && PCModbusSlave[name] != null)
{
return true;
}
return false;
}
private static bool isFieldbusPtrType(PtrType type)
{
#if CSHARP8_OR_ABOVE
return type switch
{
PtrType.FieldbusInput => true,
PtrType.FieldbusOutput => true,
PtrType.ModbusMasterInputBits => true,
PtrType.ModbusMasterInputWords => true,
PtrType.ModbusMasterOutputBits => true,
PtrType.ModbusMasterOutputBitsStatus => true,
PtrType.ModbusMasterOutputWords => true,
PtrType.ModbusMasterOutputWordsStatus => true,
PtrType.ModbusSlaveInputBits => true,
PtrType.ModbusSlaveInputWords => true,
PtrType.ModbusSlaveOutputBits => true,
PtrType.ModbusSlaveOutputWords => true,
PtrType.DriveModbusMasterInputBits => true,
PtrType.DriveModbusMasterInputWords => true,
PtrType.DriveModbusMasterOutputBits => true,
PtrType.DriveModbusMasterOutputBitsStatus => true,
PtrType.DriveModbusMasterOutputWords => true,
PtrType.DriveModbusMasterOutputWordsStatus => true,
_ => false,
};
#else
switch (type)
{
case PtrType.FieldbusInput:
case PtrType.FieldbusOutput:
case PtrType.ModbusMasterInputBits:
case PtrType.ModbusMasterInputWords:
case PtrType.ModbusMasterOutputBits:
case PtrType.ModbusMasterOutputBitsStatus:
case PtrType.ModbusMasterOutputWords:
case PtrType.ModbusMasterOutputWordsStatus:
case PtrType.ModbusSlaveInputBits:
case PtrType.ModbusSlaveInputWords:
case PtrType.ModbusSlaveOutputBits:
case PtrType.ModbusSlaveOutputWords:
case PtrType.DriveModbusMasterInputBits:
case PtrType.DriveModbusMasterInputWords:
case PtrType.DriveModbusMasterOutputBits:
case PtrType.DriveModbusMasterOutputBitsStatus:
case PtrType.DriveModbusMasterOutputWords:
case PtrType.DriveModbusMasterOutputWordsStatus:
return true;
default:
return false;
}
#endif
}
}
1. 类概述
FieldbusMappings
类用于管理现场总线(Fieldbus)的配置映射,包括:
-
Hilscher 卡通信配置
-
PC Modbus 主站/从站配置
-
驱动器 Modbus 主站配置
通过 XML 文件存储和加载配置,支持动态验证和事件通知。
2. 核心成员
(1) 字段与属性
-
配置节名称
FieldbusConfigurationSectionName
定义 XML 中存储配置的节点名(FieldbusMap
)。 -
XML 相关
-
fieldbusElement
:根 XML 节点 -
nsManager
:XML 命名空间管理器
-
-
连接映射集合
-
hilscherConnMappings
:Hilscher 卡连接配置 -
pcModbusMasterMappings
:PC Modbus 主站配置 -
pcModbusSlaveMappings
:PC Modbus 从站配置(可空) -
driveModbusMasterMappings
:驱动器 Modbus 主站配置
-
-
公开属性
通过INamedCollection
接口暴露集合,如Hilscher
、PCModbusMaster
等。
(2) 事件与委托
-
ConfigurationChanged
当配置变更时触发,重新序列化所有配置到 XML。 -
NameValidating
验证名称是否重复或非法(通过CheckNameExists
方法)。
3. 关键方法解析
(1) 初始化方法
-
构造函数
从ParameterFile
加载或创建FieldbusMap
XML 节点,并调用各子初始化方法:
initHilscher(); // 初始化 Hilscher 配置
initPcModbusMaster(); // 初始化 PC Modbus 主站
initPcModbusSlave(); // 初始化 PC Modbus 从站
initDriveModbusMaster(); // 初始化驱动器 Modbus 主站
-
子初始化逻辑
每个方法:-
从 XML 读取配置(如
SelectNodes("p:HilscherCard")
)。 -
反序列化为对象(如
hilscherConnectionInformation.FromXml
)。 -
添加到集合并绑定事件(如
NameValidating
)。
-
(2) 配置持久化
-
configurationChangedHandler
当配置变更时,清空 XML 并重新写入所有映射:
fieldbusElement.RemoveAll();
foreach (var mapping in collections) {
fieldbusElement.AppendChild(mapping.ToXml());
}
(3) 名称验证
-
CheckNameExists
检查名称是否已存在或冲突:-
通过
AerCompilerParseVariableInfo
检查变量类型是否合法(需为现场总线类型或程序变量)。 -
遍历所有集合(Hilscher、Modbus 等)检查重复名称。
-
-
isFieldbusPtrType
判断指针类型是否属于现场总线(如ModbusMasterInputBits
),使用 C# 8.0 switch 表达式或 传统 switch 语句(通过#if
条件编译适配不同版本)。
4. 辅助功能
-
类型支持
FieldbusVariableTypes
定义了支持的变量类型(如Bit
、Bool
、Int32
等)。 -
异常处理
-
名称重复时抛出
InvalidOperationException
。 -
PC Modbus 从站设置时回滚变更(
try-catch
保证原子性)。
-
5. 设计模式与技巧
-
观察者模式
通过事件(ConfigurationChanged
、NameValidating
)通知状态变更。 -
泛型与接口
使用INamedCollection<T>
统一管理不同类型的映射集合。 -
条件编译
适配不同 C# 版本的语法(如#if CSHARP8_OR_ABOVE
)。 -
XML 序列化
通过IParameterFileStorable
接口实现配置的持久化。
6. 典型流程
-
加载配置
名称验证: