[M5] mxaccess-asb: F25 step 8 — subscription operations

CreateSubscription / AddMonitoredItems / Publish / DeleteSubscription.
Completes the IASBIDataV2 read-and-subscribe path; remaining ops
(Write/PublishWriteComplete/DeleteMonitoredItems) are mechanical
extensions of the same pattern.

Contracts:
* `MonitoredItemValue` codec (IAsbCustomSerializableType binary
  fast-path: ItemIdentity + RuntimeValue + AsbVariant per
  `AsbContracts.cs:1064-1068`) with array codec (4-byte int32
  count + per-element body, mirrors `WriteArrayToStream` at
  `cs:1095-1103`).

Request builders:
* `build_create_subscription_request_body(max_queue_size,
  sample_interval)` — primitive fields per `cs:215-223`.
* `build_delete_subscription_request_body(subscription_id)` —
  primitive field per `cs:232-237`.
* `build_publish_request_body(subscription_id)` — primitive field
  per `cs:287-292`.
* `build_add_monitored_items_request_body(subscription_id, items,
  require_id)` — minimal MonitoredItem shape (Item +
  SampleInterval + Buffered). Full optional-field set
  (Active/TimeDeadband/ValueDeadband/UserData) deferred to a later
  iteration once a live capture confirms the WCF DataContract
  XML wire form.

Response decoders:
* `decode_create_subscription_response` — single int64
  SubscriptionId field. Decoder accepts Int64Text, Int32Text,
  Zero/One, or numeric-string Chars (covers all WCF binary
  numeric encodings).
* `decode_add_monitored_items_response` — Status array +
  ItemCapabilities-presence flag (mirrors RegisterItemsResponse).
* `decode_publish_response` — Status array + Values
  (MonitoredItemValue) array.

`BodyField::Int64Element` variant added for the primitive
SubscriptionId / MaxQueueSize / SampleInterval fields. `uint64`
helper casts to i64 (covers proven value range; if ulong > i64::MAX
ever appears we'll add UInt64Text to F21's NbfxText enum).

Client wrappers (4 new methods on AsbClient):
* `create_subscription(max_queue_size, sample_interval)`
* `add_monitored_items(subscription_id, items, require_id)`
* `publish(subscription_id)`
* `delete_subscription(subscription_id)`

11 new tests cover:
* MonitoredItemValue round-trip + array round-trip.
* CreateSubscription request body shape (Int64 payloads).
* CreateSubscription response decoder via Int64Text.
* CreateSubscription response decoder via Chars text fallback.
* CreateSubscription response missing-field error.
* AddMonitoredItems body carries SubscriptionId + MonitoredItem
  elements.
* AddMonitoredItems response Status round-trip.
* DeleteSubscription body carries SubscriptionId.
* Publish request body shape.
* Publish response Status + Values round-trip.

Workspace: 691 tests pass (was 680, +11). The asb-subscribe example
can now do create_subscription → add_monitored_items → publish-loop
→ delete_subscription once wire-byte reconciliation against a live
capture confirms the MonitoredItem XML shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-05 12:57:59 -04:00
parent c6570dcd06
commit b543eb1f84
5 changed files with 774 additions and 13 deletions
+12 -6
View File
@@ -17,18 +17,24 @@ pub mod operations;
pub use client::{AsbClient, ClientError, PreambleMode};
pub use contracts::{
ItemIdentity, ItemIdentityType, ItemReferenceType, ItemStatus, decode_item_identity_array,
decode_item_status_array, encode_item_identity_array, encode_item_status_array,
ItemIdentity, ItemIdentityType, ItemReferenceType, ItemStatus, MonitoredItemValue,
decode_item_identity_array, decode_item_status_array, decode_monitored_item_value_array,
encode_item_identity_array, encode_item_status_array, encode_monitored_item_value_array,
};
pub use envelope::{
ConnectionValidator, DecodedEnvelope, EnvelopeError, SoapEnvelope, actions, decode_envelope,
encode_envelope,
};
pub use operations::{
AuthenticationDataBytes, ConnectResponse, OperationError, ReadResponse, RegisterItemsResponse,
UnregisterItemsResponse, build_authenticate_me_request_body, build_connect_request_body,
build_disconnect_request_body, build_keep_alive_request_body, build_read_request_body,
AddMonitoredItemsResponse, AuthenticationDataBytes, ConnectResponse,
CreateSubscriptionResponse, DeleteSubscriptionResponse, MinimalMonitoredItem, OperationError,
PublishResponse, ReadResponse, RegisterItemsResponse, UnregisterItemsResponse,
build_add_monitored_items_request_body, build_authenticate_me_request_body,
build_connect_request_body, build_create_subscription_request_body,
build_delete_subscription_request_body, build_disconnect_request_body,
build_keep_alive_request_body, build_publish_request_body, build_read_request_body,
build_register_items_request_body, build_unregister_items_request_body,
collect_asbidata_payloads, decode_connect_response, decode_read_response,
collect_asbidata_payloads, decode_add_monitored_items_response, decode_connect_response,
decode_create_subscription_response, decode_publish_response, decode_read_response,
decode_register_items_response, decode_unregister_items_response,
};