Access Data via Symbol Loader
Some ADS Devices (e.g. the TwinCAT PLC) provide symbolic information for download. That means all visible Symbols and DataTypes can be retrieved from the target system. While this need an extra effort to upload and hold the data, this feature helps to remove the dependency of the code/configuration running on the target device.
E.g. because the symbolic information can now be browsed and determined during runtime, the application can be written without knowing what's running on the target system. Even more having the Symbol information cached, the access of the process image data will be easier because the datasize and access (instance path) is stored in the symbol.
Dependent how it is parametrized, the symbol loader can work with 'ANY_TYPES' (marshallable Primitive types, Value marshalling with ANYTYPE concept) or full dynamic symbols (Automatic dynamic marshalling of values).
Example
Accessing symbolic data by preloaded Symbolic information (asynchronous)
using (AdsClient client = new AdsClient())
{
CancellationToken cancel = CancellationToken.None;
uint valueToRead = 0;
uint valueToWrite = 42;
client.Connect(AmsNetId.Local, 851);
// Load all Symbols + DataTypes
ISymbolLoader loader = SymbolLoaderFactory.Create(client, SymbolLoaderSettings.Default);
ResultSymbols resultSymbols = await loader.GetSymbolsAsync(cancel);
if (resultSymbols.Succeeded)
{
Symbol symbol = (Symbol)resultSymbols.Symbols["MAIN.nCounter"];
// Works for ALL Primitive 'ANY TYPES' Symbols
ResultWriteAccess resultWrite = await symbol.WriteValueAsync(valueToWrite, cancel);
ResultReadValueAccess resultRead = await symbol.ReadValueAsync(cancel);
if (resultRead.Succeeded)
valueToRead = (uint)resultRead.Value;
// Simple filtering of Symbols
Regex filterExpression = new Regex(pattern: @"^MAIN.*"); // Everything that starts with "MAIN"
// FilterFunction that filters for the InstancePath
Func<ISymbol, bool> filter = s => filterExpression.IsMatch(s.InstancePath);
SymbolIterator iterator = new SymbolIterator(symbols: resultSymbols.Symbols, recurse: true, selector: filter);
foreach (ISymbol filteredSymbol in iterator)
{
Console.WriteLine(filteredSymbol.InstancePath);
}
}
}
Accessing symbolic data by preloaded Symbolic information (synchronous)
using (AdsClient client = new AdsClient())
{
uint valueToRead = 0;
uint valueToWrite = 42;
client.Connect(AmsNetId.Local, 851);
// Load all Symbols + DataTypes
ISymbolLoader loader = SymbolLoaderFactory.Create(client, SymbolLoaderSettings.Default);
Symbol symbol = (Symbol)loader.Symbols["MAIN.nCounter"];
// Works for ALL Primitive 'ANY TYPES' Symbols
symbol.WriteValue(valueToWrite);
valueToRead = (uint)symbol.ReadValue();
// Simple filtering of Symbols
Regex filterExpression = new Regex(pattern: @"^MAIN.*"); // Everything that starts with "MAIN"
// FilterFunction that filters for the InstancePath
Func<ISymbol, bool> filter = s => filterExpression.IsMatch(s.InstancePath);
SymbolIterator iterator = new SymbolIterator(symbols: loader.Symbols, recurse: true, selector: filter);
foreach (ISymbol filteredSymbol in iterator)
{
Console.WriteLine(filteredSymbol.InstancePath);
}
}