Files
lmxopcua/docs/drivers/AbLegacy-RSLogix-Import.md
2026-04-26 04:13:13 -04:00

6.9 KiB

AB Legacy — RSLogix symbol & data-table import

ablegacy-11 / #254 — bulk-import RSLogix 500 / 5 symbol exports into the AB Legacy driver. Saves operators from hand-typing every N7:0 / F8:12 / B3:0/5 row of a several-hundred-tag PLC into appsettings.json.

Supported formats — v1

Format Status Notes
.CSV "Database Export" supported Header columns Symbol,Address,Description,DataType,Scope; quoted fields, doubled-quote escapes, comment lines (; / #) all honoured
.SLC text export supported RSLogix 500's "Save As Text" emits the same column shape — point the importer at the file directly
.RSS (RSLogix 500 binary project) out of scope Proprietary; no parser ships in libplctag or any community project. Export to CSV first
.RSP (RSLogix 5 binary project) out of scope Same as .RSS

The binary .RSS / .RSP non-goal isn't a "we don't have time" decision — Rockwell's binary format is undocumented + tied to RSLogix's internal page layout, and the only known parsers are commercial IDE plugins. v1 ships with text/CSV only and a clean abstraction (IRsLogixImporter) so a binary parser can slot in later without reshaping the call sites.

CSV column reference

Column Required Notes
Symbol yes OPC UA tag name. RSLogix symbols are already stable; the importer uses them verbatim
Address yes PCCC address. File letter implies DataType (see below); the importer's resolution wins over the CSV's DataType column
Description no Parsed but currently unused — AbLegacyTagDefinition has no Description field at the v2 schema layer (see #248). Held in the column contract for future schema bumps
DataType no RSLogix-supplied (INT / REAL / BOOL / TIMER / …). Ignored at import time; the importer derives the type from the file letter
Scope no Global (default when blank) or Local:N for ladder-file-N-scoped tags. Acts as a filter when --scope is set on the CLI

File-letter → AbLegacyDataType mapping

Letter Example Maps to Notes
N N7:0 Int (signed 16-bit)
F F8:0 Float (32-bit IEEE-754)
B B3:0/0 Bit Bit-within-word also forces Bit when BitIndex is set
L L9:0 Long (signed 32-bit) SLC 5/05+ only
ST ST10:0 String 82-byte fixed-length + length word
T T4:0.ACC TimerElement Sub-element implied by .ACC / .PRE / .EN / .DN
C C5:0.ACC CounterElement
R R6:0.LEN ControlElement
A A14:0 AnalogInt Older hardware
I / O / S I:0/0 Int (or Bit with bit suffix) I/O + status files
PD / MG / PLS / BT PD9:0 PidElement etc. Family-gated; PD/MG common on SLC500 + PLC-5; PLS/BT PLC-5 only
RTC / HSC / DLS / … RTC:0.YR MicroLogixFunctionFile MicroLogix 1100 / 1400 only

A bit suffix (/N) on any file letter forces Bit, regardless of the file letter's normal classification — N7:0/3 parses as Bit, not Int.

Scope filter

The Scope column distinguishes program-scoped tags (Local:1, Local:2, …) from globals. RSLogix exports usually mix both. The CLI's --scope flag (and ImportOptions.ScopeFilter at the API level) keeps only the rows whose Scope value matches case-insensitively; rows with no Scope column count as Global.

# Import only the Global symbols
otopcua-ablegacy-cli import-rslogix `
    --file plc-export.csv `
    --device ab://192.168.1.20/1,0 `
    --scope Global

# Import only the file-2 program-scope tags
otopcua-ablegacy-cli import-rslogix `
    --file plc-export.csv `
    --device ab://192.168.1.20/1,0 `
    --scope Local:2

CLI subcommand — import-rslogix

otopcua-ablegacy-cli import-rslogix --help
Flag Default Purpose
-f / --file required Path to the CSV export
-d / --device required Canonical AB Legacy gateway URI every imported tag binds to
--emit appsettings-fragment appsettings-fragment (JSON) or summary (one-line counter)
-o / --output stdout Optional path; when set the JSON fragment is written there + summary line goes to stdout
--scope none Optional Scope filter (case-insensitive)
--max-rows unlimited Defensive cap on rows imported
--strict off Fail-fast on the first malformed row (default permissive: skip + log)

appsettings-fragment output shape

The default --emit appsettings-fragment mode writes a JSON object whose Tags array is shaped like the AbLegacyDriverConfigDto.Tags array — paste straight into the driver-instance config under Drivers/<instance>/Config/Tags.

{
  "Tags": [
    {
      "Name": "MotorSpeed",
      "DeviceHostAddress": "ab://192.168.1.20/1,0",
      "Address": "N7:0",
      "DataType": "Int",
      "Writable": true
    },
    
  ]
}

Summary line

--emit summary writes a single line:

Imported 142 tag(s), skipped 3, errors 0.

Skipped covers Scope-filter rejections + missing-required-field rows; errors covers rows whose Address failed to parse as a PCCC address.

API surface — IRsLogixImporter + AddRsLogixImport

For server-side / bootstrap use-cases the importer is also reachable via:

using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Import;

var options = new AbLegacyDriverOptions
{
    Devices = [new AbLegacyDeviceOptions("ab://192.168.1.20/1,0")],
};

// Append imported tags onto an existing options object.
var updated = options.AddRsLogixImport(
    path: @"C:\plc\plc-export.csv",
    deviceHostAddress: "ab://192.168.1.20/1,0",
    out var result);

// result.ParsedCount / SkippedCount / ErrorCount surface the import telemetry.
Console.WriteLine($"Imported {result.ParsedCount} tags");

For a hand-managed importer instance (e.g. supplying a custom ILogger) call new RsLogixSymbolImport(logger).Parse(stream, deviceHostAddress, opts) directly.

Operational notes

  • The importer is additiveAddRsLogixImport concatenates onto the existing Tags list rather than replacing it. Hand-rolled tags (system-status variables, computed fields the operator added by hand) survive a re-import.
  • Re-imports are not idempotent today — calling AddRsLogixImport twice will produce duplicate tag rows. Operators are expected to either start from a clean options object or de-duplicate themselves; a future schema rev may add a replace=true switch.
  • Description metadata is dropped on the floor — see the column reference above. When #248 lands a Description field on AbLegacyTagDefinition the importer will start populating it without further changes to the CSV contract.