d5a87c74679fc568c45187375df0031d2b610501
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
dfd027ebca |
Task #146 — Modbus addressing: align type codes with Wonderware DASMBTCP + Ignition
Web verification (2026-04-25) against current vendor docs surfaced concrete grammar conflicts in the v1 suffix grammar shipped in #137. Hard cutover before the Admin UI rolls out widely so users don't paste `:I` from a Wonderware spreadsheet and silently get wrong-typed reads. Sources: - Wonderware DASMBTCP user guide https://cdn.logic-control.com/media/DASMBTCP.pdf - Ignition Modbus addressing (8.1) https://www.docs.inductiveautomation.com/docs/8.1/ignition-modules/opc-ua/opc-ua-drivers/modbus/modbus-addressing Type-code changes: | Code | Pre-#146 | Post-#146 | Vendor reference | |--------|----------|------------|------------------------------| | `:S` | (n/a) | Int16 | Wonderware DASMBTCP `S` | | `:US` | (n/a) | UInt16 | Ignition `HRUS` | | `:I` | Int16 | **Int32** | Wonderware `I` + Ignition `HRI` | | `:UI` | UInt16 | **UInt32** | Ignition `HRUI` | | `:I_64` | (n/a) | Int64 | Ignition `HRI_64` | | `:UI_64` | (n/a) | UInt64 | Ignition `HRUI_64` | | `:BCD_32`| (n/a) | BCD32 | Ignition `HRBCD_32` | Codes REMOVED (no clear vendor precedent + conflict with the new mapping): `:DI`, `:L`, `:UDI`, `:UL`, `:LI`, `:ULI`, `:LBCD`. Pre-#146 configs that use them get an "Unknown type code" diagnostic at parse time so users get a fast surface-level error rather than silent wrong-typed reads. Codes UNCHANGED (already vendor-aligned): `:BOOL`, `:F`, `:D`, `:BCD`, `:STR<n>`. Modicon 5/6-digit + mnemonic regions (HR/IR/C/DI) + bit suffix `.N` are also unchanged. Defaults: - Coils / DiscreteInputs → `BOOL` (unchanged) - HoldingRegisters / InputRegisters with no explicit type → Int16 (matches Ignition's bare `HR` default) Byte-order mnemonics (`:ABCD` / `:CDAB` / `:BADC` / `:DCBA`) are kept but documented as OtOpcUa-specific — they aren't in any major vendor's per-tag address string. Ignition uses a `-R` suffix per prefix; Wonderware configures word-order at the topic level. Tests: - 12 Type_Codes_Parse rows updated to assert the new mappings. - New Removed_Aliases_Are_Rejected (×7) confirms each pre-#146 alias now fails fast with "Unknown type code". - Worked_Example_Int16_Array uses the new `:S` code. - New Worked_Example_Int32_Array_Via_I_Code documents the `:I = Int32` vendor-alignment intent so a future "fix" doesn't accidentally regress. - Unknown_Type_Code_Rejected_With_Catalog updated to match the new error message ("Valid: BOOL, S, US, I, ..."). Docs: - docs/v2/modbus-addressing.md — table replaced with the post-#146 codes, each row cites its Wonderware / Ignition reference. New "Codes removed in #146" subsection documents the cutover. - docs/Driver.Modbus.Cli.md — example grammar list updated; explicit type-code reminder appended. 114 addressing tests + 231 driver tests still green. Solution build clean. |
||
|
|
4cf0b4eb73 |
Task #144 — Modbus family-native parser branch (DL205 / MELSEC)
Promotes DirectLogicAddress + MelsecAddress from "utility helpers an engineer calls manually" to "first-class branch of ModbusAddressParser." Users can now paste DL205-native (V2000, Y0, C100, X17, SP10) and MELSEC-native (D100, M50, X20 hex/octal, Y0) addresses directly into TagConfig and the parser handles the PLC-native → Modbus PDU translation. Changes: - Both helper files moved into the shared Driver.Modbus.Addressing assembly (same namespace, zero-churn for callers). Required because the parser needs to call them and the dependency direction is parser→helpers, not the other way. - New ModbusFamily enum (Generic / DL205 / MELSEC) on ModbusDriverOptions.Family. Generic preserves pre-#144 behaviour exactly. - ModbusDriverOptions.MelsecSubFamily picks the X/Y notation (Q_L_iQR hex vs F_iQF octal). Default Q_L_iQR. - ModbusAddressParser.Parse now takes optional family + sub-family hints. When non-Generic, family-native parsing runs FIRST; on miss falls back to Modicon / mnemonic. Cross-family ambiguity (C100 = Modicon coil under Generic, DL205 control relay under DL205) is unambiguous within one driver instance. - Suffix grammar composes with native addresses: V2000:F:CDAB:5 parses end-to-end as DL205 V-memory at PDU 1024 + Float32 + word-swap + array of 5. - Bit suffix composes too: V2000.7 parses as bit 7 of HR[1024]. - Factory DTO fields Family / MelsecSubFamily flow through to BuildTag so the JSON binding can drive everything per-driver. Tests: 16 new ModbusFamilyParserTests covering DL205 V/Y/C/X/SP, MELSEC D/M/X/Y, sub-family hex-vs-octal disambiguation, cross-family C100 ambiguity, fallback to Modicon when native misses, and grammar composition with bit/ byte-order/array modifiers. Existing 91 parser tests still green; 220 driver tests still green. Caveat: bank-base offsets for MELSEC X/Y/M default to 0 in the grammar string. Sites with non-zero "Modbus Device Assignment Parameter" bases must use the structured tag form to override — addressed in the docs refresh (#138). |
||
|
|
850b816873 |
Task #137 — Modbus per-tag suffix grammar (type / bit / byte-order / array)
Adds the full Wonderware/Kepware/Ignition-style address suffix grammar so users paste tag spreadsheets without per-tag manual translation: <region><offset>[.<bit>][:<type>[<len>]][:<order>][:<count>] Examples that now parse end-to-end: 40001 HoldingRegisters[0], Int16 400001 same, 6-digit form 40001.5 bit 5 of HR[0] 40001:F Float32 (HR[0..1]) 40001:F:CDAB word-swapped Float32 40001:STR20 20-char ASCII string HR1:DI Int32 via mnemonic region C100 Coils[99] (mnemonic) 40001:F:5 Float32[5] array (3-field shorthand) 40001:I:CDAB:10 Int16[10] word-swapped (4-field strict) Driver-side plumbing: - ModbusAddressParser + ParsedModbusAddress in the shared Addressing assembly. 91 parser tests (every grammar variant + malformed shapes). - ModbusDataType / ModbusByteOrder moved to shared (with the same namespace so callers compile unchanged). ModbusByteOrder gains ByteSwap (BADC) and FullReverse (DCBA) alongside the existing BigEndian (ABCD) and WordSwap (CDAB). - NormalizeWordOrder extended to honor all four orders for both 4-byte and 8-byte values. Old WordSwap behavior preserved bit-for-bit. - ModbusTagDefinition gains optional ArrayCount. - ReadOneAsync / WriteOneAsync handle array fan-out: one FC03/04 read covers N consecutive register-typed elements, decoded into a typed array (short[], float[], etc.). Coil arrays use FC01 reads + FC15 writes (FakeTransport in tests gains FC15 support to match). - DriverAttributeInfo IsArray / ArrayDim flow from ArrayCount so the OPC UA address space surfaces ValueRank=1 + ArrayDimensions to clients. - ModbusDriverFactoryExtensions gains AddressString DTO field. When present, the parser drives Region/Address/DataType/ByteOrder/Bit/ StringLength/ArrayCount; structured fields (Writable, WriteIdempotent, StringByteOrder) still come from the DTO. Existing structured tag rows keep working unchanged. Tests: 91 parser unit tests (Driver.Modbus.Addressing.Tests, all green) + 204 driver tests including new ModbusByteOrderTests (BADC/DCBA roundtrips across Int32/Float32/Float64) and ModbusArrayTests (Int16[5], Float32[3] CDAB, Coil[10], length-mismatch error, IsArray/ArrayDim discovery). Solution-wide build clean. Caveat: grammar names (type codes, byte-order mnemonics, the :count shorthand) were synthesized from training-era vendor docs. Verify against current Kepware Modbus Ethernet Driver Help and Ignition Modbus Addressing manuals before freezing for production deployments — naming may need a back-compat layer if vendor wording has shifted. |
||
|
|
501d8f494b |
Task #136 — Modicon address-string parser (5/6-digit) + shared addressing assembly
Foundation for the Modbus addressing-grammar work tracked in #137-#145. Adds ModbusModiconAddress.Parse / TryParse that turns classic Modicon strings (40001 / 400001 / 30001 / 00001 / 10001) into (Region, ushort PduOffset). Also extracts ModbusRegion to a new Driver.Modbus.Addressing assembly so the Admin UI (#145) can reference the addressing surface without taking a dep on the wire driver. The new assembly intentionally extends the same ZB.MOM.WW.OtOpcUa.Driver.Modbus namespace as the driver — callers see the type as if it lived in one place; only the project layout changes. No existing call site needed editing (zero-churn move). Behaviour: - Single leading digit selects region (0=Coils, 1=DiscreteInputs, 3=InputRegisters, 4=HoldingRegisters). - 5-digit form: trailing 4 digits are 1-based register, supports 1..9999. - 6-digit form: trailing 5 digits are 1-based register, supports 1..65536 (full PDU address space). - Strict 5-or-6 length check; whitespace trimmed; clear FormatException diagnostics for every malformed shape (wrong length, non-digit body, illegal leading digit, register zero, register overflow). 29/29 new unit tests pass. Full Driver.Modbus suite (182 tests) and the solution-wide build still green after the ModbusRegion move. |