Merge b626-ablegacy-focas (batch #626+)
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -67,6 +67,9 @@ pieces for driver-side routing (e.g. deciding a bit needs read-modify-write):
|
||||
| `ST9:0` | String file (82-byte fixed-length) |
|
||||
| `T4:0.ACC` / `C5:0.PRE` | Timer / counter sub-element |
|
||||
| `I:0/0` / `O:1/2` / `S:1` | Input / output / status system files (no file number) |
|
||||
| `I:017/07` | **PLC-5 only:** `I:`/`O:` word and bit indices are **octal** (#244); a digit 8/9 is a parse error |
|
||||
| `RTC:0.HR` / `HSC:0.ACC` | **MicroLogix only:** function files RTC, HSC, DLS, MMI, PTO, PWM, STI, EII, IOS, BHI (#245) |
|
||||
| `N7:[N7:0]` / `N[N7:0]:5` | Indirect (index word read from the PLC) — parsed, **not supported at runtime** (#247) |
|
||||
|
||||
`AbLegacyDataType` covers the corresponding PCCC types: `Bit`, `Int` (N), `Long`
|
||||
(L), `Float` (F), `AnalogInt` (A), `String` (ST), and the `TimerElement` /
|
||||
@@ -85,6 +88,42 @@ this is an inherent limitation of any software-level RMW. Input-image (`I`) bit
|
||||
writes are forwarded to the PLC as-is; the device drives the input image from
|
||||
physical inputs and may reject the write.
|
||||
|
||||
### Family-specific address forms (#244 / #245 / #247)
|
||||
|
||||
`AbLegacyAddress.TryParse(text, family)` is family-aware; the driver passes the device's `PlcFamily`
|
||||
(the one-argument overload is the family-neutral grammar: decimal, no function files).
|
||||
|
||||
- **PLC-5 octal I/O (#244).** RSLogix 5 shows `I:`/`O:` word and bit indices in octal, so `I:017/07` is word 15,
|
||||
bit 7 and `I:017/17` is bit 15. Only `I`/`O` on PLC-5 (`OctalIoAddressing` on the family profile) — SLC,
|
||||
MicroLogix and Logix-PCCC stay decimal, and PLC-5 `N`/`B`/... files stay decimal. The record stores decimal and
|
||||
`ToLibplctagName()` **emits decimal**, so the libplctag `name=` string and the string the native transport
|
||||
re-parses carry identical numbers. This is not a double conversion: libplctag's `pccc.c`
|
||||
(`parse_pccc_elem_num` / `parse_pccc_bit_num`) parses decimal numerals only (a FIXME there says octal is
|
||||
unsupported), so the driver must convert. Pinned by `Plc5_io_indices_are_octal` (`I:017/17` -> `I:15/15`).
|
||||
The connectivity-probe address is normalised the same way.
|
||||
- ⚠️ **Behaviour change / migration.** Before this change a PLC-5 `I:`/`O:` address was passed to libplctag as
|
||||
written, i.e. read as **decimal**. An address copied from RSLogix in octal (e.g. `I:017`) therefore read the
|
||||
wrong word, and an authored decimal such as `I:1/12` now means bit 10 (octal 12). A previously "working"
|
||||
address containing the digits 8 or 9 (`I:018`, `O:1/9`) is no longer valid on PLC-5. Re-author any PLC-5
|
||||
I/O tags in RSLogix octal. Such a tag is refused (see below), never silently misread.
|
||||
- **A malformed / family-invalid address** (also: a function-file letter off MicroLogix) reads and writes
|
||||
`BadNodeIdUnknown` for that tag only, creates no runtime, leaves driver health alone, and logs **one**
|
||||
Warning per tag. The same check (`AbLegacyAddress.Validate`) runs in the AdminUI tag editor (family-independent:
|
||||
rejects only what *no* family accepts) and the deploy gate (`EquipmentTagConfigInspector`, using the device's
|
||||
`DeviceConfig.PlcFamily`, absent = SLC 500, unrecognised = unknown) — so `I:018` on a PLC-5 device warns at
|
||||
deploy (an error under `TagConfigValidationMode.Error`), and the editor is never stricter than the gate.
|
||||
- **MicroLogix function files (#245).** `RTC`, `HSC`, `DLS`, `MMI`, `PTO`, `PWM`, `STI`, `EII`, `IOS`, `BHI`
|
||||
(single fixed instance — no file number — with a `.SUBELEMENT`; no bit index) parse on MicroLogix devices only.
|
||||
`AbLegacyFunctionFile.SubElementType` carries the sub-element catalogue (flags → Boolean, words → Int32; unknown
|
||||
members default to Int32). ⚠️ **Wire-unverified on both transports:** there is no capture and no simulator
|
||||
coverage; the libplctag path passes the name through and the native transport has no file-type code for them, so
|
||||
it refuses the tag as `Unsupported` (`BadNotSupported` to the client; see Wire evidence).
|
||||
- **Indirect addressing (#247).** `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).
|
||||
**Runtime resolution is not implemented** (it needs a pre-read of the index word and per-resolved-address
|
||||
runtimes): reads and writes of an indirect tag answer `BadNotSupported` before any runtime is created, on both
|
||||
transports.
|
||||
|
||||
## Configuration
|
||||
|
||||
`AbLegacyDriverOptions` (`Driver.AbLegacy.Contracts/AbLegacyDriverOptions.cs`)
|
||||
@@ -172,6 +211,7 @@ Everything below is against the `ab_server` simulator; no real PCCC controller h
|
||||
| N-file write (`N7:5`) | capture `slc500-write-n7` + native `AbLegacyReadSmokeTests` write/read round trip (SLC 500) |
|
||||
| F-file read (`F8`) | one capture, `slc500-read-f8` (codec parity only; no native F write on a wire) |
|
||||
| S (incl. the default probe `S:0`), B, T, C, R, L, ST, A, O, I | **none** — encoded from the PCCC file-type table |
|
||||
| MicroLogix function files (RTC/HSC/...), PLC-5 octal I/O, indirect addressing | **none** — parsed only; native refuses function files and indirect names as Unsupported |
|
||||
| T/C/R sub-elements (`.PRE`/`.ACC`/`.LEN`/`.POS`), 6-byte T/C/R element layout | **none** |
|
||||
|
||||
### Native known gaps
|
||||
|
||||
@@ -91,6 +91,10 @@ on.
|
||||
| `MACRO:500` | Custom macro variable | System / user macro variable number |
|
||||
| `FIXED:Identity/SeriesNumber` | Fixed-tree field | A path into the [fixed node tree](#fixed-node-tree) — read-only |
|
||||
|
||||
PMC letters are series-gated by `FocasCapabilityMatrix.PmcLetters`; the 16i accepts `X Y F G R D` (F/G are
|
||||
the CNC-to-PMC / PMC-to-CNC handshake groups its ladders use, #265 — reads only, FOCAS stays read-only), while
|
||||
`M C E A K T` remain 0i-F / 30i-family.
|
||||
|
||||
The first three name a location the driver asks the CNC for on demand.
|
||||
`FIXED:` does not: it names a field of the per-device fixed-tree snapshot the
|
||||
driver's own poll loop already maintains, so a `FIXED:` read issues no wire
|
||||
|
||||
Reference in New Issue
Block a user