docs(dcl): update protocol and type mapping docs to reflect v2 TypedValue and SDK integration
This commit is contained in:
@@ -60,10 +60,30 @@ Both protocols produce the same value tuple consumed by Instance Actors. Before
|
||||
|
||||
| Concept | ScadaLink Design | LmxProxy Wire Format | Local Type |
|
||||
|---|---|---|---|
|
||||
| Value container | `TagValue(Value, Quality, Timestamp)` | `VtqMessage { Tag, Value, TimestampUtcTicks, Quality }` | `LmxVtq(Value, TimestampUtc, Quality)` — readonly record struct |
|
||||
| Quality | `QualityCode` enum: Good / Bad / Uncertain | String: `"Good"` / `"Uncertain"` / `"Bad"` | `LmxQuality` enum: Good / Uncertain / Bad |
|
||||
| Value container | `TagValue(Value, Quality, Timestamp)` | `VtqMessage { Tag, TypedValue, TimestampUtcTicks, QualityCode }` | `LmxVtq(Value, TimestampUtc, Quality)` — readonly record struct |
|
||||
| Quality | `QualityCode` enum: Good / Bad / Uncertain | `QualityCode` enum (OPC-style byte values) | Mapped via `IsGood()`/`IsUncertain()`/`IsBad()` extensions |
|
||||
| Timestamp | `DateTimeOffset` (UTC) | `int64` (DateTime.Ticks, UTC) | `DateTime` (UTC) |
|
||||
| Value type | `object?` | `string` (parsed by client to double, bool, or string) | `object?` |
|
||||
| Value type | `object?` | `TypedValue` (protobuf oneof: bool, int32, int64, float, double, string, datetime, array) | `object?` (native typed from SDK's `Vtq.Value`) |
|
||||
|
||||
### Value Serialization
|
||||
|
||||
**Inbound (reads/subscriptions)**: The LmxProxy SDK returns `Vtq(object? Value, DateTime Timestamp, Quality Quality)`. The adapter's `NormalizeValue` converts complex types (`ArrayValue`, raw arrays) to display strings before passing them into the ScadaLink system. Scalar types (`bool`, `int`, `double`, `string`, `DateTime`) pass through unchanged.
|
||||
|
||||
**Outbound (writes)**: The adapter's `ToTypedValue` converts `object?` values to the SDK's `TypedValue` for native typed writes:
|
||||
|
||||
| Source Type | TypedValue Variant |
|
||||
|---|---|
|
||||
| `bool` | `BoolValue` |
|
||||
| `int` | `Int32Value` |
|
||||
| `long` | `Int64Value` |
|
||||
| `float` | `FloatValue` |
|
||||
| `double` | `DoubleValue` |
|
||||
| `string` | `StringValue` |
|
||||
| `DateTime` | `DatetimeValue` (UTC ticks) |
|
||||
| `null` | `StringValue` (empty) |
|
||||
| fallback | `StringValue` (`.ToString()`) |
|
||||
|
||||
**Array normalization**: `ValueFormatter.FormatDisplayValue` uses reflection to extract typed array contents from LmxProxy `ArrayValue` objects and formats them as comma-separated strings. This ensures downstream code (Instance Actors, debug views, gRPC streaming) never sees opaque SDK types.
|
||||
|
||||
## Supported Protocols
|
||||
|
||||
@@ -76,10 +96,10 @@ Both protocols produce the same value tuple consumed by Instance Actors. Before
|
||||
|
||||
### LmxProxy (Custom Protocol)
|
||||
|
||||
LmxProxy is a gRPC-based protocol for communicating with LMX data servers. The DCL includes its own proto-generated gRPC client (`RealLmxProxyClient`) — no external SDK dependency.
|
||||
LmxProxy is a gRPC-based protocol for communicating with LMX data servers. The DCL uses the real `ZB.MOM.WW.LmxProxy.Client` SDK library via project reference. `RealLmxProxyClient` is a thin adapter wrapper around the SDK client for testability — it implements a local `ILmxProxyClient` interface while delegating to the SDK. The SDK handles gRPC channel management, retry policies (Polly), keep-alive, and TLS.
|
||||
|
||||
**Transport & Connection**:
|
||||
- gRPC over HTTP/2, using proto-generated client stubs from `scada.proto` (service: `scada.ScadaService`). Pre-generated C# files are checked into `Adapters/LmxProxyGrpc/` to avoid running `protoc` in Docker (ARM64 compatibility).
|
||||
- gRPC over HTTP/2 via the SDK's managed channel.
|
||||
- Default port: **50051**.
|
||||
- Session-based: `Connect` RPC returns a `SessionId` used for all subsequent operations.
|
||||
- Keep-alive: Managed by the LmxProxy server's session timeout. The DCL reconnect cycle handles session loss.
|
||||
@@ -91,16 +111,16 @@ LmxProxy is a gRPC-based protocol for communicating with LMX data servers. The D
|
||||
**Subscriptions**:
|
||||
- Server-streaming gRPC (`Subscribe` RPC returns `stream VtqMessage`).
|
||||
- Configurable sampling interval (default: 0 = on-change).
|
||||
- Wire format: `VtqMessage { tag, value (string), timestamp_utc_ticks (int64), quality (string: "Good"/"Uncertain"/"Bad") }`.
|
||||
- Wire format: `VtqMessage` with `TypedValue` (protobuf oneof) for value, `QualityCode` enum for quality — see [lmxproxy_protocol.md](lmxproxy_protocol.md) for wire details.
|
||||
- Subscription lifetime managed by `CancellationTokenSource` — cancellation stops the streaming RPC.
|
||||
|
||||
**Client Implementation** (`RealLmxProxyClient`):
|
||||
- Uses `Google.Protobuf` + `Grpc.Net.Client` (standard proto-generated stubs, no protobuf-net runtime IL emit).
|
||||
- Thin adapter over the `ZB.MOM.WW.LmxProxy.Client` SDK. Implements `ILmxProxyClient` for testability.
|
||||
- `ILmxProxyClientFactory` creates instances configured with host, port, and API key.
|
||||
- Value conversion: string values from `VtqMessage` are parsed to `double`, `bool`, or left as `string`.
|
||||
- Quality mapping: `"Good"` → `LmxQuality.Good`, `"Uncertain"` → `LmxQuality.Uncertain`, else `LmxQuality.Bad`.
|
||||
- Read values arrive as native typed objects from the SDK's `Vtq.Value` — no string parsing needed.
|
||||
- Quality mapping: SDK's `Quality` enum (OPC-style byte values) mapped to ScadaLink's `QualityCode` via `IsGood()`/`IsUncertain()`/`IsBad()` extension methods.
|
||||
|
||||
**Proto Source**: The `.proto` file originates from the LmxProxy server repository (`lmx/Proxy/Grpc/Protos/scada.proto` in ScadaBridge). The C# stubs are pre-generated and stored at `Adapters/LmxProxyGrpc/`.
|
||||
**Proto Source**: The `.proto` file originates from the LmxProxy server repository (`lmx/Proxy/Grpc/Protos/scada.proto` in ScadaBridge). The SDK provides the generated client stubs.
|
||||
|
||||
**Test Infrastructure**: The `infra/lmxfakeproxy/` project provides a fake LmxProxy server that bridges to the OPC UA test server. It implements the full `scada.ScadaService` proto, enabling end-to-end testing of `RealLmxProxyClient` without a Windows LmxProxy deployment. See [test_infra_lmxfakeproxy.md](../test_infra/test_infra_lmxfakeproxy.md) for setup.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user