Auto: ablegacy-3 — sub-element bit semantics

Closes #246
This commit is contained in:
Joseph Doherty
2026-04-25 13:41:52 -04:00
parent 07235d3b66
commit c89f5bb3b9
6 changed files with 350 additions and 5 deletions

View File

@@ -141,7 +141,12 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
}
var parsed = AbLegacyAddress.TryParse(def.Address, device.Options.PlcFamily);
var value = runtime.DecodeValue(def.DataType, parsed?.BitIndex);
// Timer/Counter/Control status bits route through GetBit at the parent-word
// address — translate the .DN/.EN/etc. sub-element to its standard bit position
// and pass it down to the runtime as a synthetic bitIndex.
var decodeBit = parsed?.BitIndex
?? AbLegacyDataTypeExtensions.StatusBitIndex(def.DataType, parsed?.SubElement);
var value = runtime.DecodeValue(def.DataType, decodeBit);
results[i] = new DataValueSnapshot(value, AbLegacyStatusMapper.Good, now, now);
_health = new DriverHealth(DriverState.Healthy, now, null);
}
@@ -188,6 +193,15 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
{
var parsed = AbLegacyAddress.TryParse(def.Address, device.Options.PlcFamily);
// Timer/Counter/Control PLC-set status bits (DN, TT, OV, UN, FD, ER, EM, UL,
// IN) are read-only — the PLC sets them; any client write would be silently
// overwritten on the next scan. Reject up front with BadNotWritable.
if (AbLegacyDataTypeExtensions.IsPlcSetStatusBit(def.DataType, parsed?.SubElement))
{
results[i] = new WriteResult(AbLegacyStatusMapper.BadNotWritable);
continue;
}
// PCCC bit-within-word writes — task #181 pass 2. RMW against a parallel
// parent-word runtime (strip the /N bit suffix). Per-parent-word lock serialises
// concurrent bit writers. Applies to N-file bit-in-word (N7:0/3) + B-file bits
@@ -247,12 +261,19 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
string.Equals(t.DeviceHostAddress, device.HostAddress, StringComparison.OrdinalIgnoreCase));
foreach (var tag in tagsForDevice)
{
var parsed = AbLegacyAddress.TryParse(tag.Address, device.PlcFamily);
// Timer/Counter/Control sub-elements (.DN/.EN/.TT/.PRE/.ACC/etc.) refine the
// base element's Int32 to Boolean for status bits and Int32 for word members.
var effectiveType = AbLegacyDataTypeExtensions.EffectiveDriverDataType(
tag.DataType, parsed?.SubElement);
var plcSetBit = AbLegacyDataTypeExtensions.IsPlcSetStatusBit(
tag.DataType, parsed?.SubElement);
deviceFolder.Variable(tag.Name, tag.Name, new DriverAttributeInfo(
FullName: tag.Name,
DriverDataType: tag.DataType.ToDriverDataType(),
DriverDataType: effectiveType,
IsArray: false,
ArrayDim: null,
SecurityClass: tag.Writable
SecurityClass: tag.Writable && !plcSetBit
? SecurityClassification.Operate
: SecurityClassification.ViewOnly,
IsHistorized: false,