internal static class CoreVariableHelper
{
private class VariableKindDescriptor
{
private readonly PtrType ptrType;
private readonly TypeCast typeCast;
public PtrType PtrType => ptrType;
public TypeCast TypeCast => typeCast;
public VariableKindDescriptor(PtrType ptrType, TypeCast typeCast)
{
this.ptrType = ptrType;
this.typeCast = typeCast;
}
public override int GetHashCode()
{
return ((long)(PtrType.GetHashCode() + TypeCast.GetHashCode())).GetHashCode();
}
public override bool Equals(object obj)
{
if (!(obj is VariableKindDescriptor variableKindDescriptor))
{
return false;
}
if (PtrType == variableKindDescriptor.PtrType)
{
return TypeCast == variableKindDescriptor.TypeCast;
}
return false;
}
}
private static readonly Dictionary<PtrType, VariableContext> contextMappings;
private static readonly Dictionary<VariableKindDescriptor, VariableType> typeMappings;
private const int TaskInfoCount = 2;
private const int TaskReturnCount = 1;
private static int? ArraySubscriptCount;
static CoreVariableHelper()
{
contextMappings = new Dictionary<PtrType, VariableContext>();
typeMappings = new Dictionary<VariableKindDescriptor, VariableType>();
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_GLOBAL_VAR, TypeCast.None), VariableType.Double);
typeMappings.Add(new VariableKindDescriptor(PtrType.STR_GLOBAL_VAR, TypeCast.None), VariableType.String);
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_PROGRAM_VAR, TypeCast.None), VariableType.Double);
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_CSPARM_VAR, TypeCast.None), VariableType.Double);
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_TASK_VAR, TypeCast.None), VariableType.Double);
typeMappings.Add(new VariableKindDescriptor(PtrType.STR_TASK_VAR, TypeCast.None), VariableType.String);
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_TASK_INFO_VAR, TypeCast.None), VariableType.Double);
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_TASK_RETURN_VAR, TypeCast.None), VariableType.Double);
typeMappings.Add(new VariableKindDescriptor(PtrType.BYTE_BI_VIO, TypeCast.None), VariableType.VirtualBinaryIO);
typeMappings.Add(new VariableKindDescriptor(PtrType.BYTE_BO_VIO, TypeCast.None), VariableType.VirtualBinaryIO);
typeMappings.Add(new VariableKindDescriptor(PtrType.WORD_RI_VIO, TypeCast.None), VariableType.VirtualRegisterIO);
typeMappings.Add(new VariableKindDescriptor(PtrType.WORD_RO_VIO, TypeCast.None), VariableType.VirtualRegisterIO);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.DriveModbusMasterInputBits);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.DriveModbusMasterInputWords);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.DriveModbusMasterOutputBits);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.DriveModbusMasterOutputBitsStatus);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.DriveModbusMasterOutputWords);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.DriveModbusMasterOutputWordsStatus);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.FieldbusInput);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.FieldbusOutput);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusMasterInputBits);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusMasterInputWords);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusMasterOutputBits);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusMasterOutputBitsStatus);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusMasterOutputWords);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusMasterOutputWordsStatus);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusSlaveInputBits);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusSlaveInputWords);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusSlaveOutputBits);
populateTypeMappingsForPtrTypeAllNumericTypeCasts(typeMappings, PtrType.ModbusSlaveOutputWords);
contextMappings.Add(PtrType.DBL_GLOBAL_VAR, VariableContext.Global);
contextMappings.Add(PtrType.STR_GLOBAL_VAR, VariableContext.Global);
contextMappings.Add(PtrType.DBL_PROGRAM_VAR, VariableContext.Program);
contextMappings.Add(PtrType.DBL_CSPARM_VAR, VariableContext.Stack);
contextMappings.Add(PtrType.DBL_TASK_VAR, VariableContext.Task);
contextMappings.Add(PtrType.STR_TASK_VAR, VariableContext.Task);
contextMappings.Add(PtrType.DBL_TASK_INFO_VAR, VariableContext.TaskInfo);
contextMappings.Add(PtrType.DBL_TASK_RETURN_VAR, VariableContext.TaskReturn);
contextMappings.Add(PtrType.BYTE_BI_VIO, VariableContext.VirtualBinaryInput);
contextMappings.Add(PtrType.BYTE_BO_VIO, VariableContext.VirtualBinaryOutput);
contextMappings.Add(PtrType.WORD_RI_VIO, VariableContext.VirtualRegisterInput);
contextMappings.Add(PtrType.WORD_RO_VIO, VariableContext.VirtualRegisterOutput);
contextMappings.Add(PtrType.DriveModbusMasterInputBits, VariableContext.DriveModbusMasterInputBit);
contextMappings.Add(PtrType.DriveModbusMasterInputWords, VariableContext.DriveModbusMasterInputWord);
contextMappings.Add(PtrType.DriveModbusMasterOutputBits, VariableContext.DriveModbusMasterOutputBit);
contextMappings.Add(PtrType.DriveModbusMasterOutputBitsStatus, VariableContext.DriveModbusMasterOutputBitStatus);
contextMappings.Add(PtrType.DriveModbusMasterOutputWords, VariableContext.DriveModbusMasterOutputWord);
contextMappings.Add(PtrType.DriveModbusMasterOutputWordsStatus, VariableContext.DriveModbusMasterOutputWordStatus);
contextMappings.Add(PtrType.FieldbusInput, VariableContext.FieldbusInput);
contextMappings.Add(PtrType.FieldbusOutput, VariableContext.FieldbusOutput);
contextMappings.Add(PtrType.ModbusMasterInputBits, VariableContext.ModbusMasterInputBit);
contextMappings.Add(PtrType.ModbusMasterInputWords, VariableContext.ModbusMasterInputWord);
contextMappings.Add(PtrType.ModbusMasterOutputBits, VariableContext.ModbusMasterOutputBit);
contextMappings.Add(PtrType.ModbusMasterOutputBitsStatus, VariableContext.ModbusMasterOutputBitStatus);
contextMappings.Add(PtrType.ModbusMasterOutputWords, VariableContext.ModbusMasterOutputWord);
contextMappings.Add(PtrType.ModbusMasterOutputWordsStatus, VariableContext.ModbusMasterOutputWordStatus);
contextMappings.Add(PtrType.ModbusSlaveInputBits, VariableContext.ModbusSlaveInputBit);
contextMappings.Add(PtrType.ModbusSlaveInputWords, VariableContext.ModbusSlaveInputWord);
contextMappings.Add(PtrType.ModbusSlaveOutputBits, VariableContext.ModbusSlaveOutputBit);
contextMappings.Add(PtrType.ModbusSlaveOutputWords, VariableContext.ModbusSlaveOutputWord);
}
public static _PTR_DATA InstantiateCoreInfoStruct()
{
_PTR_DATA result = default(_PTR_DATA);
if (!ArraySubscriptCount.HasValue)
{
MarshalAsAttribute marshalAsAttribute = (MarshalAsAttribute)typeof(_PTR_DATA).GetField("arrayDimension").GetCustomAttributes(typeof(MarshalAsAttribute), inherit: false)[0];
ArraySubscriptCount = marshalAsAttribute.SizeConst;
}
result.arrayDimension = new _ArrayIndexPtr[ArraySubscriptCount.Value];
return result;
}
public static Variable GetVariableFromNameLimitToContextType(Controller c, string name, VariableContext context, VariableType type, TaskId? task)
{
if (c == null)
{
throw new ArgumentNullException("c");
}
if (name == null)
{
throw new ArgumentNullException("name");
}
_PTR_DATA variableInfoForName = GetVariableInfoForName(c, name);
if (!contextMappings.TryGetValue((PtrType)variableInfoForName.ptrType, out var value))
{
return null;
}
if (!typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)variableInfoForName.ptrType, (TypeCast)variableInfoForName.typeCast), out var value2))
{
return null;
}
if (context != value || type != value2)
{
return null;
}
return getVariableFromVarInfo(c, name, variableInfoForName, task);
}
public static Variable GetVariableFromName(Controller c, string name, TaskId? task)
{
if (c == null)
{
throw new ArgumentNullException("c");
}
if (name == null)
{
throw new ArgumentNullException("name");
}
_PTR_DATA variableInfoForName = GetVariableInfoForName(c, name);
return getVariableFromVarInfo(c, name, variableInfoForName, task);
}
public static Variable[] GetVariablesFromNames(Controller c, string[] names, TaskId? task)
{
_PTR_DATA[] variableInfosForNames = GetVariableInfosForNames(c, names);
List<Variable> list = new List<Variable>();
for (int i = 0; i < variableInfosForNames.Length; i++)
{
Variable variableFromVarInfo = getVariableFromVarInfo(c, names[i], variableInfosForNames[i], task);
if (variableFromVarInfo != null)
{
list.Add(variableFromVarInfo);
}
}
return list.ToArray();
}
public static Variable[] GetVariablesFromNamesLimitToContextType(Controller c, string[] names, VariableContext context, VariableType type, TaskId? task)
{
_PTR_DATA[] variableInfosForNames = GetVariableInfosForNames(c, names);
List<Variable> list = new List<Variable>();
for (int i = 0; i < variableInfosForNames.Length; i++)
{
_PTR_DATA varInfo = variableInfosForNames[i];
if (contextMappings.TryGetValue((PtrType)varInfo.ptrType, out var value) && typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)varInfo.ptrType, (TypeCast)varInfo.typeCast), out var value2) && context == value && type == value2)
{
Variable variableFromVarInfo = getVariableFromVarInfo(c, names[i], varInfo, task);
if (variableFromVarInfo != null)
{
list.Add(variableFromVarInfo);
}
}
}
return list.ToArray();
}
private static Variable getVariableFromVarInfo(Controller c, string name, _PTR_DATA varInfo, TaskId? task)
{
if (!contextMappings.TryGetValue((PtrType)varInfo.ptrType, out var context))
{
return null;
}
if (!typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)varInfo.ptrType, (TypeCast)varInfo.typeCast), out var _))
{
return null;
}
PtrType ptrType = (PtrType)varInfo.ptrType;
if (task.HasValue)
{
varInfo.taskIndex = (byte)task.Value;
}
if (task.HasValue)
{
switch (ptrType)
{
case PtrType.DBL_PROGRAM_VAR:
case PtrType.DBL_CSPARM_VAR:
if (c.Tasks.AllTasks[(int)task.Value].Program.Associated)
{
try
{
return c.Variables.Tasks[(int)task.Value].Program[name];
}
catch (InvalidOperationException)
{
return null;
}
}
break;
}
}
bool isValid_ = true;
ExceptionResolver.ResolveThrow(c, Wrapper.aerPtrIsValid(c.Handle.Value, ref varInfo, ref isValid_));
if (!isValid_)
{
return null;
}
if (task.HasValue && ptrType == PtrType.DBL_TASK_VAR)
{
return CreateTaskDouble(c, name, varInfo);
}
if (task.HasValue && ptrType == PtrType.STR_TASK_VAR)
{
return CreateTaskString(c, name, varInfo);
}
if (task.HasValue && ptrType == PtrType.DBL_TASK_INFO_VAR)
{
return CreateTaskInfoDouble(c, name, varInfo);
}
if (task.HasValue && ptrType == PtrType.DBL_TASK_RETURN_VAR)
{
return CreateTaskReturnDouble(c, name, varInfo);
}
if (Array.Exists(GetFieldbusContexts(), (VariableContext vc) => vc == context))
{
return CreateFieldbusVariable(c, name, varInfo);
}
return ptrType switch
{
PtrType.BYTE_BI_VIO => CreateVirtualBinaryInput(c, name, varInfo),
PtrType.BYTE_BO_VIO => CreateVirtualBinaryOutput(c, name, varInfo),
PtrType.WORD_RI_VIO => CreateVirtualRegisterInput(c, name, varInfo),
PtrType.WORD_RO_VIO => CreateVirtualRegisterOutput(c, name, varInfo),
PtrType.DBL_GLOBAL_VAR => CreateGlobalDouble(c, name, varInfo),
PtrType.STR_GLOBAL_VAR => CreateGlobalString(c, name, varInfo),
_ => null,
};
}
public static _PTR_DATA GetVariableInfoForName(Controller c, string name)
{
_PTR_DATA pVariableInfo_ = default(_PTR_DATA);
lock (c.Variables.CompilerHandle)
{
ExceptionResolver.ResolveThrow(Wrapper.AerCompilerParseVariableInfo(c.Variables.CompilerHandle.Value, name, ref pVariableInfo_));
return pVariableInfo_;
}
}
public static _PTR_DATA[] GetVariableInfosForNames(Controller c, string[] names)
{
if (c == null)
{
throw new ArgumentNullException("c");
}
if (names == null)
{
throw new ArgumentNullException("names");
}
foreach (string text in names)
{
if (text.Contains(";"))
{
throw new ArgumentException(string.Format(Resources.InvalidVariableName, text));
}
}
_PTR_DATA[] array = new _PTR_DATA[names.Length];
string pszVarNames_ = string.Join(";", names);
ExceptionResolver.ResolveThrow(Wrapper.AerCompilerParseVariablesInfo(c.Variables.CompilerHandle.Value, pszVarNames_, array, names.Length));
return array;
}
public static string PrependDollarSigns(string varName, int requiredDollarSignCount)
{
int length = varName.TrimStart('$').Length;
return varName.PadLeft(length + requiredDollarSignCount, '$');
}
public static int GetSizeForVariableType(VariableType type)
{
return type switch
{
VariableType.Bit => 1,
VariableType.Bool => 1,
VariableType.Byte => 1,
VariableType.DInt => 4,
VariableType.Double => 8,
VariableType.DWord => 4,
VariableType.Int => 2,
VariableType.Int16 => 2,
VariableType.Int32 => 4,
VariableType.Int8 => 1,
VariableType.LReal => 8,
VariableType.Real => 4,
VariableType.Single => 4,
VariableType.SInt => 1,
VariableType.String => 0,
VariableType.UDInt => 4,
VariableType.UInt => 2,
VariableType.UInt16 => 2,
VariableType.UInt32 => 4,
VariableType.UInt8 => 1,
VariableType.USInt => 1,
VariableType.VirtualBinaryIO => 1,
VariableType.VirtualRegisterIO => 2,
VariableType.Word => 2,
_ => throw new ArgumentException(string.Format(Resources.UnknownValueOfEnumeration, typeof(VariableType).Name, type)),
};
}
private static void populateTypeMappingsForPtrTypeAllNumericTypeCasts(Dictionary<VariableKindDescriptor, VariableType> typeMappings, PtrType ptrType)
{
TypeCast[] array = new TypeCast[21]
{
TypeCast.Bit,
TypeCast.Bool,
TypeCast.Byte,
TypeCast.DInt,
TypeCast.Double,
TypeCast.DWord,
TypeCast.Int,
TypeCast.Int16,
TypeCast.Int32,
TypeCast.Int8,
TypeCast.LReal,
TypeCast.Real,
TypeCast.Single,
TypeCast.SInt,
TypeCast.UDInt,
TypeCast.UInt,
TypeCast.UInt16,
TypeCast.UInt32,
TypeCast.UInt8,
TypeCast.USInt,
TypeCast.Word
};
foreach (TypeCast typeCast in array)
{
typeMappings.Add(new VariableKindDescriptor(ptrType, typeCast), TypeCast2VariableType(typeCast));
}
}
public static VariableType TypeCast2VariableType(TypeCast typeCast)
{
return typeCast switch
{
TypeCast.Bit => VariableType.Bit,
TypeCast.Bool => VariableType.Bool,
TypeCast.Byte => VariableType.Byte,
TypeCast.DInt => VariableType.DInt,
TypeCast.Double => VariableType.Double,
TypeCast.DWord => VariableType.DWord,
TypeCast.Int => VariableType.Int,
TypeCast.Int16 => VariableType.Int16,
TypeCast.Int32 => VariableType.Int32,
TypeCast.Int8 => VariableType.Int8,
TypeCast.LReal => VariableType.LReal,
TypeCast.Real => VariableType.Real,
TypeCast.Single => VariableType.Single,
TypeCast.SInt => VariableType.SInt,
TypeCast.UDInt => VariableType.UDInt,
TypeCast.UInt => VariableType.UInt,
TypeCast.UInt16 => VariableType.UInt16,
TypeCast.UInt32 => VariableType.UInt32,
TypeCast.UInt8 => VariableType.UInt8,
TypeCast.USInt => VariableType.USInt,
TypeCast.Word => VariableType.Word,
_ => throw new ArgumentException(string.Format(Resources.UnknownValueOfEnumeration, typeof(TypeCast).Name, typeCast)),
};
}
public static TypedVariable<double> CreateGlobalDouble(Controller c, string name, _PTR_DATA coreData)
{
return createNonFieldbusNumericVariable<double>(c, name, coreData);
}
public static TypedVariable<string> CreateGlobalString(Controller c, string name, _PTR_DATA coreData)
{
return createStringVariable(c, name, coreData);
}
public static TypedVariable<double> CreateTaskDouble(Controller c, string name, _PTR_DATA coreData)
{
return createNonFieldbusNumericVariable<double>(c, name, coreData);
}
public static TypedVariable<string> CreateTaskString(Controller c, string name, _PTR_DATA coreData)
{
return createStringVariable(c, name, coreData);
}
public static TypedVariable<double> CreateTaskInfoDouble(Controller c, string name, _PTR_DATA coreData)
{
return createNonFieldbusNumericVariable<double>(c, name, coreData);
}
public static TypedVariable<double> CreateTaskReturnDouble(Controller c, string name, _PTR_DATA coreData)
{
return createNonFieldbusNumericVariable<double>(c, name, coreData);
}
public static TypedVariable<bool> CreateVirtualBinaryInput(Controller c, string name, _PTR_DATA coreData)
{
return createNonFieldbusNumericVariable<bool>(c, name, coreData);
}
public static TypedVariable<bool> CreateVirtualBinaryOutput(Controller c, string name, _PTR_DATA coreData)
{
return createNonFieldbusNumericVariable<bool>(c, name, coreData);
}
public static TypedVariable<double> CreateVirtualRegisterInput(Controller c, string name, _PTR_DATA coreData)
{
return createVirtualRegisterIO(c, name, coreData);
}
public static TypedVariable<double> CreateVirtualRegisterOutput(Controller c, string name, _PTR_DATA coreData)
{
return createVirtualRegisterIO(c, name, coreData);
}
public static Variable CreateFieldbusVariable(Controller c, string name, _PTR_DATA coreData)
{
switch ((TypeCast)coreData.typeCast)
{
case TypeCast.Bit:
case TypeCast.Bool:
return createFieldbusVariable<bool>(c, name, coreData);
case TypeCast.UInt8:
case TypeCast.USInt:
case TypeCast.Byte:
return createFieldbusVariable<byte>(c, name, coreData);
case TypeCast.Int16:
case TypeCast.Int:
case TypeCast.Word:
case TypeCast.Int8:
case TypeCast.SInt:
return createFieldbusVariable<short>(c, name, coreData);
case TypeCast.Int32:
case TypeCast.DInt:
case TypeCast.DWord:
case TypeCast.UInt16:
case TypeCast.UInt:
return createFieldbusVariable<int>(c, name, coreData);
case TypeCast.UInt32:
case TypeCast.UDInt:
return createFieldbusVariable<long>(c, name, coreData);
case TypeCast.Single:
case TypeCast.Real:
return createFieldbusVariable<float>(c, name, coreData);
case TypeCast.Double:
case TypeCast.LReal:
return createFieldbusVariable<double>(c, name, coreData);
default:
return null;
}
}
private static TypedVariable<TType> createFieldbusVariable<TType>(Controller c, string name, _PTR_DATA coreData) where TType : IConvertible
{
if (!contextMappings.TryGetValue((PtrType)coreData.ptrType, out var context))
{
return null;
}
if (!typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)coreData.ptrType, (TypeCast)coreData.typeCast), out var value2))
{
return null;
}
GetValueDelegate getValueDelegate = delegate (Variable v)
{
double pfdValue_ = 0.0;
_PTR_DATA pPtr_2 = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrDblGetValue(v.Controller.Handle.Value, ref pPtr_2, ref pfdValue_));
return Convert.ChangeType(pfdValue_, typeof(TType));
};
SetValueDelegate setValueDelegate = delegate (Variable v, object value)
{
double fdValue_ = Convert.ToDouble(value);
_PTR_DATA pPtr_ = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrDblSetValue(v.Controller.Handle.Value, ref pPtr_, fdValue_));
};
int contextKey = 0;
int num = 0;
if (Array.Exists(GetHasConnectionContexts(), (VariableContext vc) => vc == context))
{
contextKey = coreData.arrayDimension[0].dwValue;
num = coreData.arrayDimension[1].dwValue;
}
else
{
num = coreData.arrayDimension[0].dwValue;
}
return new TypedVariable<TType>(c, value2, context, contextKey, num, name, getValueDelegate, setValueDelegate, coreData);
}
public static VariableContext[] GetFieldbusContexts()
{
return new VariableContext[18]
{
VariableContext.DriveModbusMasterInputBit,
VariableContext.DriveModbusMasterInputWord,
VariableContext.DriveModbusMasterOutputBit,
VariableContext.DriveModbusMasterOutputBitStatus,
VariableContext.DriveModbusMasterOutputWord,
VariableContext.DriveModbusMasterOutputWordStatus,
VariableContext.ModbusMasterInputBit,
VariableContext.ModbusMasterInputWord,
VariableContext.ModbusMasterOutputBit,
VariableContext.ModbusMasterOutputBitStatus,
VariableContext.ModbusMasterOutputWord,
VariableContext.ModbusMasterOutputWordStatus,
VariableContext.FieldbusInput,
VariableContext.FieldbusOutput,
VariableContext.ModbusSlaveInputBit,
VariableContext.ModbusSlaveInputWord,
VariableContext.ModbusSlaveOutputBit,
VariableContext.ModbusSlaveOutputWord
};
}
public static VariableContext[] GetHasConnectionContexts()
{
return new VariableContext[14]
{
VariableContext.DriveModbusMasterInputBit,
VariableContext.DriveModbusMasterInputWord,
VariableContext.DriveModbusMasterOutputBit,
VariableContext.DriveModbusMasterOutputBitStatus,
VariableContext.DriveModbusMasterOutputWord,
VariableContext.DriveModbusMasterOutputWordStatus,
VariableContext.ModbusMasterInputBit,
VariableContext.ModbusMasterInputWord,
VariableContext.ModbusMasterOutputBit,
VariableContext.ModbusMasterOutputBitStatus,
VariableContext.ModbusMasterOutputWord,
VariableContext.ModbusMasterOutputWordStatus,
VariableContext.FieldbusInput,
VariableContext.FieldbusOutput
};
}
private static TypedVariable<TType> createNonFieldbusNumericVariable<TType>(Controller c, string name, _PTR_DATA coreData) where TType : IConvertible
{
if (!contextMappings.TryGetValue((PtrType)coreData.ptrType, out var value2))
{
return null;
}
if (!typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)coreData.ptrType, (TypeCast)coreData.typeCast), out var value3))
{
return null;
}
GetValueDelegate getValueDelegate = delegate (Variable v)
{
double pfdValue_ = 0.0;
_PTR_DATA pPtr_2 = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrDblGetValue(v.Controller.Handle.Value, ref pPtr_2, ref pfdValue_));
return Convert.ChangeType(pfdValue_, typeof(TType));
};
SetValueDelegate setValueDelegate = delegate (Variable v, object value)
{
double fdValue_ = Convert.ToDouble(value);
_PTR_DATA pPtr_ = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrDblSetValue(v.Controller.Handle.Value, ref pPtr_, fdValue_));
};
return new TypedVariable<TType>(c, value3, value2, coreData.taskIndex, coreData.arrayDimension[0].dwValue, name, getValueDelegate, setValueDelegate, coreData);
}
private static TypedVariable<string> createStringVariable(Controller c, string name, _PTR_DATA coreData)
{
if (!contextMappings.TryGetValue((PtrType)coreData.ptrType, out var value2))
{
return null;
}
if (!typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)coreData.ptrType, (TypeCast)coreData.typeCast), out var value3))
{
return null;
}
GetValueDelegate getValueDelegate = delegate (Variable v)
{
StringBuilder stringBuilder = new StringBuilder(Global.StringVariableLength);
_PTR_DATA pPtr_2 = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrStrGetValueBuffer(v.Controller.Handle.Value, ref pPtr_2, stringBuilder, stringBuilder.Capacity));
return stringBuilder.ToString();
};
SetValueDelegate setValueDelegate = delegate (Variable v, object value)
{
_PTR_DATA pPtr_ = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrStrSetValue(v.Controller.Handle.Value, ref pPtr_, value.ToString()));
};
return new TypedVariable<string>(c, value3, value2, coreData.taskIndex, coreData.arrayDimension[0].dwValue, name, getValueDelegate, setValueDelegate, coreData);
}
private static TypedVariable<double> createVirtualRegisterIO(Controller c, string name, _PTR_DATA varInfo)
{
if (!contextMappings.TryGetValue((PtrType)varInfo.ptrType, out var value2))
{
return null;
}
if (!typeMappings.TryGetValue(new VariableKindDescriptor((PtrType)varInfo.ptrType, (TypeCast)varInfo.typeCast), out var value3))
{
return null;
}
GetValueDelegate getValueDelegate = delegate (Variable v)
{
double pfdValue_ = 0.0;
_PTR_DATA pPtr_2 = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrDblGetValue(v.Controller.Handle.Value, ref pPtr_2, ref pfdValue_));
return pfdValue_;
};
SetValueDelegate setValueDelegate = delegate (Variable v, object value)
{
double fdValue_ = Convert.ToDouble(value);
_PTR_DATA pPtr_ = v.CoreIdentifier;
ExceptionResolver.ResolveThrow(v.Controller, Wrapper.aerPtrDblSetValue(v.Controller.Handle.Value, ref pPtr_, fdValue_));
};
return new TypedVariable<double>(c, value3, value2, 0, varInfo.arrayDimension[0].dwValue, name, getValueDelegate, setValueDelegate, varInfo);
}
public static string[] GetDefineNamesFromFile(Controller c, string filePath)
{
StringBuilder stringBuilder = null;
int pActualCount_ = 0;
int num = 4096;
bool pbBufferOverflow_ = true;
do
{
stringBuilder = new StringBuilder(num);
lock (c.Variables.CompilerHandle)
{
ExceptionResolver.ResolveThrow(Wrapper.AerCompilerGetAutoIncludeDefines(c.Variables.CompilerHandle.Value, filePath, stringBuilder, stringBuilder.Capacity, ref pActualCount_, ref pbBufferOverflow_));
}
num *= 2;
}
while (pbBufferOverflow_);
string[] array = stringBuilder.ToString().Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
if (array.Length != pActualCount_)
{
throw new Exception(string.Format(Resources.UnexpectedNuberOfVariableNames, pActualCount_, array.Length));
}
return array;
}
public static VariableContext GetContextFromPtrType(PtrType ptrType)
{
return contextMappings[ptrType];
}
public static VariableType GetTypeFromPtrTypeAndCast(PtrType ptrType, TypeCast typeCast)
{
return typeMappings[new VariableKindDescriptor(ptrType, typeCast)];
}
public static StatusDataCollectionSignalRecord[] CreateVariableSignalRecords(Controller c, VariableDescriptor[] variables)
{
if (variables.Length == 0)
{
return new StatusDataCollectionSignalRecord[variables.Length];
}
string[] array = new string[variables.Length];
int[] array2 = new int[variables.Length];
for (int i = 0; i < variables.Length; i++)
{
VariableDescriptor variableDescriptor = variables[i];
if (variableDescriptor.name.Contains(";"))
{
throw new ArgumentException(string.Format(Resources.InvalidVariableName, variableDescriptor.name));
}
array[i] = variableDescriptor.name;
array2[i] = (int)variableDescriptor.taskId;
}
short[] array3 = new short[variables.Length];
short[] array4 = new short[variables.Length];
int[] array5 = new int[variables.Length];
_PTR_DATA[] array6 = new _PTR_DATA[variables.Length];
ExceptionResolver.ResolveThrow(c, Wrapper.AerStatusGetVariablesSignalData(c.Handle.Value, string.Join(";", array), array.Length, array2, array3, array4, array5, array6));
StatusDataCollectionSignalRecord[] array7 = new StatusDataCollectionSignalRecord[variables.Length];
for (int j = 0; j < variables.Length; j++)
{
array7[j].context = DataSignalContext.Variable;
array7[j].name = array[j];
array7[j].contextKey = array4[j];
array7[j].itemCode = array3[j];
array7[j].metadata = array6[j];
array7[j].optionalArgument = array5[j];
}
return array7;
}
}
以下是针对 CoreVariableHelper
类的全面解析,从工业控制变量管理的底层实现到设计哲学:
1. 核心定位
该类是 工业控制变量系统的神经中枢,负责:
-
变量元数据解析:连接变量名与底层硬件地址
-
类型系统桥接:协调PLC类型(如DINT)与C#类型(如int)
-
上下文路由:根据变量类型自动分配至正确的控制上下文(如任务/全局/IO)
2. 核心数据结构
2.1 类型映射系统
private static readonly Dictionary<PtrType, VariableContext> contextMappings;
private static readonly Dictionary<VariableKindDescriptor, VariableType> typeMappings;
// 复合键设计
private class VariableKindDescriptor {
public PtrType PtrType; // 硬件指针类型(如DBL_GLOBAL_VAR)
public TypeCast TypeCast; // 类型转换标记(如DInt到Int32)
}
工业协议适配:
支持超过50种PLC数据类型与C#类型的映射,包括:
-
Modbus寄存器(
PtrType.DriveModbusMasterInputWords
) -
现场总线信号(
PtrType.FieldbusInput
) -
虚拟IO(
PtrType.BYTE_BI_VIO
)
2.2 静态构造函数
初始化超大规模类型映射表(200+条目),例如:
typeMappings.Add(new VariableKindDescriptor(PtrType.DBL_GLOBAL_VAR, TypeCast.None), VariableType.Double);
contextMappings.Add(PtrType.ModbusSlaveInputBits, VariableContext.ModbusSlaveInputBit);
3. 关键工作流程
3.1 变量解析流程
3.2 批量处理优化
// 一次解析多个变量(减少JNI调用)
public static _PTR_DATA[] GetVariableInfosForNames(Controller c, string[] names) {
string pszVarNames_ = string.Join(";", names);
Wrapper.AerCompilerParseVariablesInfo(..., pszVarNames_, ...);
}
性能关键点:
-
使用分号分隔的批量查询降低80%以上的原生调用开销
-
内存预分配避免GC压力
4. 工业协议深度适配
4.1 现场总线变量处理
public static Variable CreateFieldbusVariable(Controller c, string name, _PTR_DATA coreData) {
switch ((TypeCast)coreData.typeCast) {
case TypeCast.Bit: return createFieldbusVariable<bool>(...);
case TypeCast.DWord: return createFieldbusVariable<int>(...);
case TypeCast.LReal: return createFieldbusVariable<double>(...);
}
}
协议支持:
-
Modbus TCP(主/从站)
-
Hilscher协议
-
驱动器专用Modbus
4.2 虚拟IO处理
private static TypedVariable<double> createVirtualRegisterIO(...) {
// 特殊处理寄存器IO的读写委托
GetValueDelegate = (v) => Wrapper.aerPtrDblGetValue(...);
}
实时性保障:
-
直接内存映射访问(非协议栈)
-
固定响应时间<50μs
5. 高级类型系统
5.1 类型转换矩阵
private static void populateTypeMappingsForPtrTypeAllNumericTypeCasts(...) {
// 为每个PtrType注册21种数字类型转换
foreach (TypeCast cast in Enum.GetValues(typeof(TypeCast))) {
typeMappings.Add(new VariableKindDescriptor(ptrType, cast),
TypeCast2VariableType(cast));
}
}
典型场景:
将PLC的TypeCast.DInt
映射为C#的int
,同时处理可能的[0,1]
到bool
的转换
5.2 上下文感知路由
public static VariableContext[] GetFieldbusContexts() {
return new VariableContext[18] {
VariableContext.DriveModbusMasterInputBit,
VariableContext.FieldbusOutput,
// ...其他现场总线上下文
};
}
6. 关键设计模式
6.1 工厂模式
// 根据_PTR_DATA动态创建变量实例
private static Variable getVariableFromVarInfo(...) {
return ptrType switch {
PtrType.BYTE_BI_VIO => CreateVirtualBinaryInput(...),
PtrType.DBL_GLOBAL_VAR => CreateGlobalDouble(...),
_ => null
};
}
6.2 委托注入
// 将硬件操作延迟绑定
GetValueDelegate getValueDelegate = (v) => {
double val;
Wrapper.aerPtrDblGetValue(..., ref val);
return Convert.ChangeType(val, typeof(T));
};
7. 性能关键路径优化
7.1 编译器句柄池
lock (c.Variables.CompilerHandle) { // 避免多线程竞争
Wrapper.AerCompilerParseVariableInfo(...);
}
7.2 零分配设计
// 复用_PTR_DATA结构体
_PTR_DATA data = default(_PTR_DATA);
data.arrayDimension = new _ArrayIndexPtr[ArraySubscriptCount.Value];
8. 工业级异常处理
8.1 硬件错误映射
ExceptionResolver.ResolveThrow(
Wrapper.aerPtrIsValid(..., ref isValid_));
if (!isValid_) throw new HardwareAddressInvalidException();
8.2 类型安全强制
public static VariableType TypeCast2VariableType(TypeCast cast) {
return cast switch {
TypeCast.Bit => VariableType.Bit,
_ => throw new InvalidCastException(...)
};
}
9. 扩展性设计
9.1 协议扩展点
// 新协议只需添加PtrType和Context映射
contextMappings.Add(PtrType.ProfinetIO, VariableContext.Profinet);
9.2 自定义类型支持
通过扩展TypeCast
枚举和TypeCast2VariableType
方法支持新数据类型
10. 典型工业场景
// 读取Modbus从站温度值
var temp = CoreVariableHelper.GetVariableFromName(
controller,
"ModbusSlave1.InputWord[3]") as TypedVariable<double>;
// 批量配置IO映射
var vars = CoreVariableHelper.GetVariablesFromNames(
controller,
new[] { "AI[0]", "DO[1]" });
该设计实现了工业控制领域对 确定性、高性能 和 多协议兼容 的极致要求,是工业软件基础架构的典范之作。