mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-21 17:16:16 +08:00
fix/encoder-stack-depth-json-flake
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
dbee7b9988 |
Robotics client: fill the engineering units and ranges of the axis values and the load mass, and the gear ratio (#4661)
# Description Follow-up to #4619. It was prepared stacked on #4619 and is now one commit on top of master, with #4619's review changes in place. `AxisSnapshot.Engineering`, `LoadSnapshot.MassEngineering` and `GearSnapshot.GearRatio` are part of the snapshot contracts and documented in `docs/Robotics.md` (the URML capability manifest takes the joint limits from them), but `RoboticsClient` never set them: every axis came back without units or limits, every load without the unit of its mass and every gear without its ratio. OPC 40010-1 declares `ActualPosition` (mandatory), `ActualSpeed` and `ActualAcceleration` (optional) below the axis's DI `ParameterSet`, and the load's `Mass`, as `AnalogUnitType` variables with a mandatory `EngineeringUnits` and an optional `EURange` property, and `GearRatio` as a mandatory `RationalNumber` variable of the gear. The client now reads them: - **Axis:** `ReadAxisAsync`, and with it `ReadSystemAsync`, resolves the `EngineeringUnits` and `EURange` of the three axis values with one TranslateBrowsePathsToNodeIds and reads them with one Read per axis (none when nothing resolves) into `PositionUnit`, `SpeedUnit`, `AccelerationUnit` and `Limits.Position/Speed/Acceleration`. - **Load:** `Mass` is resolved and read together with its `EngineeringUnits` and `EURange` (`MassEngineering`), replacing the separate resolve and read. - **Gear:** `GearRatio` is read in the same request as `Pitch`. - Loads and gears cost no extra request. - A property the server does not publish, whose read fails or whose value has a bad status stays `null`. The structures go through the existing `ToStructure<T>`, which checks `StatusCode.IsGood` as for `MotorTemperatureEngineering`. The rest of the snapshot is still returned. - Because `Mass` and `Pitch` are now part of that request, a failed `Mass` or `Pitch` read keeps the server's status in the `DataValue`, like the axis values and `MotorTemperature`. Before, `Session.ReadValueAsync` threw and failed the whole snapshot read. The public API does not change. ## Changes - `src/Opc.Ua.Robotics.Client/RoboticsClient.Topology.cs`: - new `ReadAxisEngineeringAsync`, called from `ReadAxisAsync`; - `ReadLoadAsync` and `ReadGearAsync` use the existing `ReadChildrenAsync`. - `docs/Robotics.md`: - describes the members and their null cases; - adds them to the values that carry no NodeId; - names `AxisSnapshot.Engineering` instead of the non-existent `AxisSnapshot.Limits` in the URML section. ## Tests - **New, unit** (`Opc.Ua.Robotics.Tests`, `RoboticsClientFacadeTests`): - `EngineeringValuesAndTheGearRatioComeFromTheVariablesTheyDescribe`: the values are checked against same-named decoys below the axis and a `GearRatio` in namespace 0. - `AbsentOrUnreadableEngineeringValuesAndGearRatiosStayNull`: a missing `EURange`, a load without engineering properties, a failing unit read and a failing ratio read. - `BadQualityEngineeringValuesAndGearRatiosReadAsNoStructure`: a range, a unit and a ratio with a bad status read as `null`. - `AFailedMassOrPitchReadKeepsTheStatusAndTheSnapshot`. - `AnAxisWithoutAParameterSetHasNoEngineeringValues`. - **New, end-to-end** (`RoboticsClientServerE2eTests.EngineeringValuesAndGearRatiosAreReadAsync`): - the test cell now publishes a unit and range for `ActualSpeed`, a unit without a range for `ActualAcceleration`, a range for the flange load's mass and a tool load with a mass only; - the test reads the units, ranges and gear ratios back through `ReadSystemAsync` and `ReadAxisAsync`. - **Fail without the fix:** with `src/Opc.Ua.Robotics.Client` from master, five of the six new tests fail. Four get `null` units, ranges or ratios. `AFailedMassOrPitchReadKeepsTheStatusAndTheSnapshot` fails with `ServiceResultException` `Bad_NodeIdUnknown`. `AnAxisWithoutAParameterSetHasNoEngineeringValues` passes there by design: it pins that an axis without a `ParameterSet` still reads without error. - `Opc.Ua.Robotics.Tests` passed 661/661 on net10.0 and 601/601 on net8.0 (macOS). - `Opc.Ua.Robotics.Client` builds for net48, net8.0, net9.0 and net10.0 with 0 warnings. - `dotnet format` (whitespace, style, analyzers) on the changed files: nothing on the changed lines beyond the `IDE0002` info that the existing `RoboticsSessionHarness.Ua(Opc.Ua.BrowseNames.…)` calls in the same test class also get. - Changed lines covered: 52/52 (100 %). - Fork CI (full matrix incl. macOS) and CodeQL: [CI run 37147764118](https://github.com/biancode/UA-.NETStandard/actions/runs/37147764118) and [CodeQL run 37147766527](https://github.com/biancode/UA-.NETStandard/actions/runs/37147766527). CodeQL is green; CI is green except `Opc.Ua.Interop.Tests` (`LegacyClientExtendedCheckAsync("ComplexTypes")` / `LoadAndDecodeLegacyComplexTypesAsync`), which is flaky on master since #4630 (details in #4617), and except one Windows run of `StartIsIdempotentAndDisposeStopsListenerAsync` in `Opc.Ua.Redundancy.Kubernetes.Tests` (HttpListener prefix already registered), which this change does not touch either. ## Notes for review - `ReadAxisAsync` costs one TranslateBrowsePathsToNodeIds and at most one Read more per axis. The other snapshots keep their request count. - `AxisSnapshot.Engineering`, `LoadSnapshot.MassEngineering` and `GearSnapshot.GearRatio` are read once and carry no NodeId, like `MotorTemperatureEngineering`. ## Related Issues - Fixes #4660 - Follows up #4619 ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. (Affected suite on net10.0 and net8.0 locally on macOS; .NET Framework is covered by the fork CI's Windows net48 legs.) - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. Co-authored-by: Marc Schier <marcschier@users.noreply.github.com> |
||
|
|
c801ac1d64 |
Robotics client: expose value NodeIds, operation states and the missing identification and motor fields (#4619)
# Description A Robotics snapshot returns the values it read, but not the variables they came from. A client that shows a snapshot and wants live updates has to resolve every value again before it can subscribe. This PR adds that information to the snapshots, along with the operation state and the DI and motor fields the contracts did not cover. Every addition is an init property with a default; no existing member changes. - **Value NodeIds:** every snapshot value comes with the NodeId of its variable, or `NodeId.Null` when the server does not publish it: - `AxisStateSnapshot.ActualPositionId`/`ActualSpeedId`/`ActualAccelerationId` - `MotionDeviceSnapshot.SpeedOverrideId`, `LoadSnapshot.MassId`, `GearSnapshot.PitchId`, `TaskModuleSnapshot.IsReferencedId` - `SafetyStateSnapshot.EmergencyStopId`/`OperationalModeId`/`ProtectiveStopId`, `SafetyFunctionSnapshot.ActiveId`/`EnabledId` - `TaskControlSnapshot.ExecutionModeId`/`TaskProgramLoadedId`/`TaskProgramNameId` Each id comes from the path resolution the value read already does, so it costs no extra request. - **Operation state:** `ControllerSnapshot.SystemOperationId`. `ControllerSnapshot` and `TaskControlSnapshot` add `CurrentStateId`, the `CurrentState` variable of the SystemOperationStateMachine or TaskControlStateMachine, and `CurrentState`, the `RoboticsOperationState` it named when read. `CurrentState` is `null` when the state machine is absent, its read fails, or it names a state other than Idle, Ready or Executing; the rest of the snapshot is still returned. - **Identification:** `RoboticsComponentIdentification.HardwareRevision`, `SoftwareRevision`, `ManufacturerUri`, `ProductInstanceUri` (DI properties). - **Motor:** `MotorSnapshot.MotorTemperature` with `MotorTemperatureEngineering` (EngineeringUnits, EURange), `BrakeReleased` and `EffectiveLoadRate`, each with its NodeId. They are read from the motor's DI `ParameterSet` with one TranslateBrowsePathsToNodeIds and one Read per motor. - The reads use the path helpers from #4609 and the generated proxies; the per-node structure is unchanged. `docs/Robotics.md` describes the new members with an example. Tests: - **`RoboticsClientServerE2eTests`** (hosted server over opc.tcp). The fixture now publishes the identification revisions and URIs, the motor's unit, range and load rate, the gear pitch, and a SystemOperation that starts in Ready. The new tests: - compare the ids with the server's own nodes, and check that reading each id returns the snapshot value; - subscribe to an `ActualPositionId` and receive changing values; - follow the task control's `CurrentState` through LoadByName and UnloadProgram; - read the identification and motor fields. - **`RoboticsClientFacadeTests`:** check the ids against the ParameterSet children next to same-named decoys, read `CurrentState` alongside its `Id` child, and cover an unknown state, a failing CurrentState read, and a controller and task control without operations. - On the base branch, the new tests do not compile because the members are missing. Local results: - `UA.slnx` Release builds on all target frameworks with no new warnings. - `Opc.Ua.Robotics.Tests`: 650/650 on net10.0 and 590/590 on net8.0. - Changed-line coverage against #4609: 100 % (168/168, `check-coverage.ps1`). - Fork CI (full matrix incl. macOS) and CodeQL on the current head (`3dbb91392`, with master merged in): green — [CI run 36976259619](https://github.com/biancode/UA-.NETStandard/actions/runs/36976259619) (189 jobs), [CodeQL run 36976262134](https://github.com/biancode/UA-.NETStandard/actions/runs/36976262134). ## Related Issues - Fixes #4618 ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. (Affected suites on net10.0 and net8.0 locally on macOS; .NET Framework via the fork CI's Windows legs.) - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Marc Schier <marcschier@users.noreply.github.com> |
||
|
|
f20d94fcac |
Robotics: resolve client reads with namespaces and ParameterSet; call ResetToProgramStart on the ReadySubstateMachine (#4609)
# Description `Opc.Ua.Robotics.Client` read almost nothing from a real OPC 40010-1 server. Every member was looked up with a namespace-0 browse name, and process values were looked for directly below the component instead of below the DI `ParameterSet`. #4569 made motors, gears and drives resolve; the values, identification and enumerations of every snapshot still came back empty, and the Observe methods tried to monitor `NodeId.Null`. Separately, `ResetToProgramStartAsync` called the method on the `Ready` state, which has no such method. This is the minimal fix on the current structure; the generated proxies, the per-node reads, the motor and gear lookup by type and the IsDrivenBy drive lookup with its de-duplication stay as they are. The public API is unchanged. - **Reads:** the resolve helpers take a `QualifiedName[]` path built from the session's namespace table — DI browse names for identification properties, Robotics browse names for members of the component, and `DI:ParameterSet/<Robotics name>` for process values (ActualPosition/Speed/Acceleration, SpeedOverride, EmergencyStop, OperationalMode, ProtectiveStop, ExecutionMode, TaskProgramLoaded, TaskProgramName). A namespace the server does not publish makes the path not resolve instead of matching namespace 0. - **Observe methods:** `ObserveAxisAsync` and `ObserveSafetyAsync` subscribe only to values that resolve, and end when none do. - **ResetToProgramStart:** called on the TaskControlStateMachine's `ReadySubstateMachine`; if it is missing, the call fails with Bad_NotFound. - `docs/Robotics.md` describes how the snapshot reads map to the OPC 40010-1 layout. Tests: - `RoboticsClientServerE2eTests` (new, all target frameworks): a six-axis cell built with the Robotics builders and hosted over opc.tcp. It checks the `ReadSystemAsync` values, that `ObserveAxisAsync` delivers changing positions, and that the server's `ResetToProgramStart` handler runs. All three fail on master. - `RoboticsClientFacadeTests`: the scripted session now matches browse paths by the full QualifiedName, lays nodes out as the NodeSet does, and adds namespace-0 and wrong-level decoys; two new tests check the object ResetToProgramStart is called on and the Bad_NotFound case. Local results on the branch: `UA.slnx` Release builds on all target frameworks with no new warnings; `Opc.Ua.Robotics.Tests` 641/641 on net10.0 and 581/581 on net8.0; changed-line coverage 97.9 % (`check-coverage.ps1`). Fork CI (full matrix incl. macOS) and CodeQL: green — [CI run 36755707494](https://github.com/biancode/UA-.NETStandard/actions/runs/36755707494) (189 jobs incl. macOS), [CodeQL run 36755711056](https://github.com/biancode/UA-.NETStandard/actions/runs/36755711056). Possible follow-ups, not part of this PR: reading the topology level by level in batches (one TranslateBrowsePathsToNodeIds, Browse and Read per level) and filling the axis engineering units and limits, the load mass unit and range, and `GearRatio`, which the snapshot contracts define but the client does not read yet. ## Related Issues - Fixes #4608 ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. (Affected suites on net10.0 and net8.0 locally on macOS; .NET Framework is covered by the fork CI's Windows net48 legs.) - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |