@@ -1,6 +1,10 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Hosting;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Import;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
|
||||
@@ -75,6 +79,80 @@ public static class AbLegacyDriverFactoryExtensions
|
||||
return new AbLegacyDriver(options, driverInstanceId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ablegacy-11 / #254 — append RSLogix CSV symbol-export rows to
|
||||
/// <paramref name="options"/> as <see cref="AbLegacyTagDefinition"/> entries bound to
|
||||
/// <paramref name="deviceHostAddress"/>. Returns a new <see cref="AbLegacyDriverOptions"/>
|
||||
/// with the imported tags concatenated onto the existing <c>Tags</c> list — useful both
|
||||
/// at startup-time (server-side bootstrap that wants to seed a device's address space
|
||||
/// from a customer-supplied CSV) and from the CLI (<c>import-rslogix</c> emits the
|
||||
/// resulting JSON fragment for hand-merging into an appsettings file).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The importer is permissive by default — malformed rows are logged and skipped;
|
||||
/// the resulting <see cref="RsLogixImportResult"/> counts surface on
|
||||
/// <paramref name="result"/> for callers that want to assert "we got the row count
|
||||
/// we expected".
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// RSLogix 500's <c>.RSS</c> + RSLogix 5's <c>.RSP</c> binary project files are
|
||||
/// out of scope for v1 — the binary format is proprietary and undocumented; no
|
||||
/// libplctag or community parser exists. Customers must export to text/CSV via
|
||||
/// RSLogix's "Tools → Database → Save" or "Database Export" before pointing the
|
||||
/// importer at the file. See <c>docs/drivers/AbLegacy-RSLogix-Import.md</c>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static AbLegacyDriverOptions AddRsLogixImport(
|
||||
this AbLegacyDriverOptions options,
|
||||
string path,
|
||||
string deviceHostAddress,
|
||||
out RsLogixImportResult result,
|
||||
ImportOptions? importOptions = null,
|
||||
ILogger<RsLogixSymbolImport>? logger = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(path);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(deviceHostAddress);
|
||||
|
||||
using var stream = File.OpenRead(path);
|
||||
var importer = new RsLogixSymbolImport(logger ?? NullLogger<RsLogixSymbolImport>.Instance);
|
||||
result = importer.Parse(stream, deviceHostAddress, importOptions);
|
||||
|
||||
// Concat onto whatever's already on the options — the importer is additive so
|
||||
// hand-edited Tags rows (e.g., system-status fields not surfaced by RSLogix) keep
|
||||
// sitting alongside the bulk-imported symbol rows. Use init-syntax with-expression
|
||||
// so the returned options keeps every other field (Devices, Probe, Timeout, …)
|
||||
// untouched.
|
||||
var merged = new List<AbLegacyTagDefinition>(options.Tags.Count + result.Tags.Count);
|
||||
merged.AddRange(options.Tags);
|
||||
merged.AddRange(result.Tags);
|
||||
return new AbLegacyDriverOptions
|
||||
{
|
||||
Devices = options.Devices,
|
||||
Tags = merged,
|
||||
Probe = options.Probe,
|
||||
Timeout = options.Timeout,
|
||||
Retries = options.Retries,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CLI-friendly overload that returns the <see cref="RsLogixImportResult"/> alongside
|
||||
/// the modified options as a tuple. Mirrors <see cref="AddRsLogixImport"/> but avoids
|
||||
/// the <c>out</c> parameter for call sites that prefer pattern-matched destructuring.
|
||||
/// </summary>
|
||||
public static (AbLegacyDriverOptions Options, RsLogixImportResult Result) AddRsLogixImportWithResult(
|
||||
this AbLegacyDriverOptions options,
|
||||
string path,
|
||||
string deviceHostAddress,
|
||||
ImportOptions? importOptions = null,
|
||||
ILogger<RsLogixSymbolImport>? logger = null)
|
||||
{
|
||||
var updated = options.AddRsLogixImport(path, deviceHostAddress, out var result, importOptions, logger);
|
||||
return (updated, result);
|
||||
}
|
||||
|
||||
private static T ParseEnum<T>(string? raw, string driverInstanceId, string field,
|
||||
string? tagName = null, T? fallback = null) where T : struct, Enum
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user