fix(ablegacy): indirect element index up to 999 on PLC-5; clear IndirectLastName on dispose
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -121,7 +121,7 @@ physical inputs and may reject the write.
|
||||
- **Indirect addressing (#247 parse, #646 runtime).** `N7:[N7:0]` (word from another address) and `N[N7:0]:5` (file
|
||||
from another address) parse, one level deep (the inner address must be direct, and carries the family's octal rule).
|
||||
At runtime the driver reads the inner address first (same runtime factory, so libplctag and Native alike), requires
|
||||
an integer in range (word/element `0..255`, file `0..999`), composes the concrete address and runs the normal
|
||||
an integer in range (word/element `0..255`, or `0..999` on PLC-5/LogixPccc; file `0..999`), composes the concrete address and runs the normal
|
||||
read/write path against it. **The index is re-read on every read/write - never cached** - and the previous
|
||||
resolution's handle is released when the index moves. A bad index (negative, too large, float/string source) is
|
||||
`BadOutOfRange` for that tag only (no health impact); an inner-read failure propagates its own status (a wire
|
||||
|
||||
@@ -862,6 +862,9 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
/// <summary>Largest word/element index an indirect source may yield (PCCC element offset is one byte).</summary>
|
||||
private const int MaxIndirectElement = AbLegacyArray.MaxElements - 1;
|
||||
|
||||
/// <summary>PLC-5 data files hold up to 1000 words (extended PCCC offset), unlike SLC/MicroLogix (256).</summary>
|
||||
private const int MaxIndirectElementPlc5 = 999;
|
||||
|
||||
/// <summary>Largest data-file number an indirect source may yield (PLC-5 allows up to 999).</summary>
|
||||
private const int MaxIndirectFile = 999;
|
||||
|
||||
@@ -877,6 +880,8 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
{
|
||||
var fileNumber = parsed.FileNumber;
|
||||
var word = parsed.WordNumber;
|
||||
var maxElement = device.Options.PlcFamily is AbLegacyPlcFamily.Plc5 or AbLegacyPlcFamily.LogixPccc
|
||||
? MaxIndirectElementPlc5 : MaxIndirectElement;
|
||||
|
||||
if (parsed.IndirectFileSource is { } fileSrc)
|
||||
{
|
||||
@@ -890,7 +895,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
{
|
||||
var r = await ReadIndexAsync(device, wordSrc, ct).ConfigureAwait(false);
|
||||
if (r.Status != 0) return new IndirectResolution(null, r.Status, r.TransportFault);
|
||||
if (r.Value is < 0 or > MaxIndirectElement)
|
||||
if (r.Value < 0 || r.Value > maxElement)
|
||||
return new IndirectResolution(null, AbLegacyStatusMapper.BadOutOfRange, false);
|
||||
word = (int)r.Value!;
|
||||
}
|
||||
@@ -1329,6 +1334,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
|
||||
Runtimes.Clear();
|
||||
foreach (var r in ParentRuntimes.Values) r.Dispose();
|
||||
ParentRuntimes.Clear();
|
||||
IndirectLastName.Clear();
|
||||
// Dispose + clear the per-parent RMW gates and the per-runtime/creation locks so
|
||||
// ReinitializeAsync cycles don't orphan their SemaphoreSlim instances (each leaks a
|
||||
// wait handle once contended).
|
||||
|
||||
Reference in New Issue
Block a user