UACM Service

The Usage and Condition Monitoring (UACM) Service (gva-uacm) is the register-side runtime that watches subsystem characteristics, faults, and usage counters across the platform, rolls that data up into a per-resource health status, and drives automatic maintenance scheduling. It implements the Def Stan 23-009 Usage and Condition Monitoring Service Specification (UCMS) v1.0.

Overview

The UACM Service handles:

  • Subscribing to characteristic values, faults, and usage/expiry counters published by LRUs (subsystems) across the platform
  • Evaluating threshold-based, periodic, and change-based monitoring requirements against those values
  • Rolling active threshold exceedances up into a per-resource RED/GREEN health status (Monitored_Resource.A_healthStatus)
  • Deriving Fault_Events from resource-published Fault_Code samples
  • Automatically transitioning Maintenance_Actions to Due when a linked usage counter or fault goes active
  • Bulk-logging a named bundle of characteristics (Collection_Data_Set_Definition) whenever the requirement or fault that references it activates
  • Persisting characteristic, fault, and usage history to PostgreSQL/PostGIS
  • Standing in for simple LRUs that do not publish their own specifications via a bridge/policy JSON layer
  • Responding to operator commands (IBIT start/stop, Maintenance_Action lifecycle, manual failure reports, comment/remove) via the GVA Command Response Protocol (CRP)

The service is a headless daemon backed by PostgreSQL/PostGIS. All inter-process traffic is DDS; every DDS interaction is defined by an IDL contract in the shipped Reference Model.

Roles on the wire

graph LR subgraph "LRUs (subsystems)" LRU1[Engine LRU] LRU2[Turret LRU] end subgraph "UACM Service" SVC[gva-uacm] DB[(PostGIS
monitored_events)] end subgraph "HMI tier" HMI[gva-hmi] end LRU1 -->|supplyCharacteristicValue| SVC LRU1 -->|Fault_Code| SVC LRU1 -->|Characteristic_Usage / Expiry_Date_Usage| SVC LRU1 -.->|"Monitored_Resource_Specification
(optional, R-role)"| SVC SVC --> DB SVC -->|Monitored_Resource
A_healthStatus RAG| HMI SVC -->|Threshold_Exceedance_Event| HMI SVC -->|Fault_Event| HMI SVC -->|Maintenance_Action| HMI HMI -->|IBIT start/stop
Maintenance_Action commands| SVC SVC -->|Command Response| HMI

Ownership:

Actor Publishes Subscribes
LRU (R-role) supplyCharacteristicValue, Fault_Code, Characteristic_Usage, Expiry_Date_Usage, optionally its own specifications Command topics addressed to it
UACM Service Monitored_Resource, Threshold_Exceedance_Event, Fault_Event, Maintenance_Action, Collection_Data_Set_Definition, CRP responses Characteristic values, Fault_Code, usage/expiry topics, monitoring-requirement topics, operator commands
HMI (O-role) IBIT start/stop, Maintenance_Action lifecycle commands, manual failure reports Monitored_Resource, Threshold_Exceedance_Event, Fault_Event, Maintenance_Action

The UACM Service is the sole publisher of Monitored_Resource and Fault_Event — LRUs never publish either directly. LRUs publish the raw facts (Fault_Code, characteristic values); the service derives the platform-facing state from them.

RAG rollup

Monitored_Resource.A_healthStatus is the platform's single per-resource health indicator (T_RAGType). It is LRU-authoritative: the service mirrors the value the resource itself reports on Resource_With_Monitoring.A_healthStatus — every resource must publish Resource_With_Monitoring at a minimum (§4.1.2), and it is documented as "Instanciated by the resource itself", i.e. the LRU's own self-assessed health, not something the service computes.

sequenceDiagram participant LRU as Resource (LRU) participant Service as UACM Service participant HMI LRU->>Service: Resource_With_Monitoring (A_healthStatus = Red) Service->>HMI: Monitored_Resource (A_healthStatus = Red) LRU->>Service: Resource_With_Monitoring (A_healthStatus = Green) Service->>HMI: Monitored_Resource (A_healthStatus = Green)
  • The service never derives or overrides this value — whatever the LRU's most recent Resource_With_Monitoring sample reports is what gets republished on Monitored_Resource.
  • Threshold exceedances (Threshold_Exceedance_Event) are evaluated and published/disposed exactly as before, and remain visible on Monitored_Resource.A_thresholdExceedanceEvents_sourceID — but they no longer influence A_healthStatus. A resource can have active exceedances and still report Green (if the LRU's own BIT considers itself healthy), and vice versa; that disagreement is itself meaningful information for a crew station to surface, not a bug.
  • Def Stan 23-009 UCMS v1.0 defines no algorithm for aggregating multiple exceedances into one RAG value — this remains a model-wide gap (still true, see the citation trail in the developer-facing behaviour-model doc). The LRU-authoritative approach sidesteps that gap rather than resolving it: the service simply never needs to aggregate anything.

Monitored_Resource is published TRANSIENT_LOCAL, so a late-joining subscriber always receives the resource's current health status on start-up. A subscriber that needs to observe a transient RED excursion — as opposed to just the resource's steady-state colour — should already be matched and subscribed before the exceedance occurs, rather than relying on catching it after the fact.

Maintenance action auto-Due

Maintenance_Action.A_state (Not_Due / Due / Blocked / Complete) is normally driven by explicit operator commands (complete, blocked, setComment, remove). In addition, the service automatically promotes a Maintenance_Action to Due via two trigger paths, configured per action in uacm_specifications.json:

  • Usage exceedance — a Characteristic_Usage or Expiry_Date_Usage linked to the action (usageExceededMaintenanceActionResourceId / ...InstanceId) enters the Exceeded state.
  • Fault activation — a Fault_Code linked to the action (dueFaultCodeResourceId / ...InstanceId) goes active.

Either trigger creates the Maintenance_Action in Due state if none exists yet for that action ID, or flips an existing Not_Due instance to Due. Blocked and Complete remain purely operator-driven — the auto-trigger never overrides an action an operator has already actioned.

Collection Data Set bulk-logging

A Collection_Data_Set_Definition names a bundle of characteristics that should be logged together whenever a linked requirement or fault activates — for example, capturing every related engine parameter (pressure, temperature, RPM) the moment any one of them trips a threshold, rather than relying on each characteristic's own independent logging schedule.

Two link points drive this:

  • Threshold_Based_Monitoring_Requirement.A_additionalMonitorDataSet_sourceID — bulk-log the named data set when this requirement activates.
  • Fault_Event_Specification.A_collectionDataSet_sourceID — bulk-log the named data set when this fault event activates.

On activation, the service writes every characteristic named by the linked data set to PostgreSQL using its most recently supplied value — including characteristics that are not otherwise configured to persist their own values (persistValue: false). Configure data sets under collectionDataSetDefinitions[] in uacm_specifications.json:

{
  "collectionDataSetDefinitions": [
    {
      "resourceId": 80001,
      "instanceId": 1,
      "dataCollectionName": "DATA_SET::engineHealthSnapshot",
      "characteristics": [
        { "resourceId": 3001, "instanceId": 1 },
        { "resourceId": 3002, "instanceId": 1 }
      ]
    }
  ]
}

Monitoring requirements and logging cadence

Three requirement types govern how often a characteristic is logged to PostgreSQL, and can combine on a single characteristic:

Requirement Active when Logging behaviour
Threshold_Based_Monitoring_Requirement Value is exceeding a configured Min/Max threshold (subject to sample or time hysteresis) Logs at loggingIntervalMsWhileExceeded while active
Periodic_Monitoring_Requirement Always Logs at a fixed A_loggingInterval
Change_Based_Monitoring_Requirement Always Logs immediately on every value change, independent of any interval

When more than one interval-bearing requirement is active on the same characteristic, the service logs at the smallest currently-active interval among them — not the tick rate of any single requirement. A characteristic with an active change-based requirement is logged on every change in addition to whatever interval schedule also applies.

Hysteresis (§5.4.16)

An LRU may supply A_sampleHysteresis (attackSamples/releaseSamples) and/or A_timeHysteresis (attackDuration/releaseDuration) directly on its Threshold_Based_Monitoring_Requirement — both are @optional wire fields. When present, the wire-supplied values are authoritative and override anything configured locally in uacm_specifications.json for that requirement; time-based hysteresis takes priority over sample-based when a requirement configures both. A requirement that supplies neither field falls back to any hysteresis configured for it locally, defaulting to an immediate 1-sample attack/release if nothing is configured either way.

Built-in tests (IBIT / PBIT / CBIT)

A_generatingBitType (Power_Up / Continuous / Interruptive) is a mandatory field on every Fault_Code_Specification — every fault an LRU declares is expected to originate from one of these three built-in test categories.

  • IBIT (Interruptive) has a full wire lifecycle: the service tracks Not_RunRunningPassed/Failed/Interrupted in response to startTest/stopTest commands and the resource's own published result.
  • PBIT (Power-up) is self-reported by the resource as a boolean, A_pbitComplete, on its Resource_With_Monitoring publication at power-on. The service does not aggregate individual resources' PBIT flags into its own platform-wide status.
  • CBIT (Continuous) has no dedicated topic. A resource's own continuous self-test result is expected to be modelled as an ordinary monitored characteristic, or surfaced indirectly via a tagged Fault_Code.

See examples/sdk/uacm-faults for a driver that demonstrates all three --bit-type values plus --pbit-complete/--no-pbit-complete.

Bridge Role and Policy Layer

UCMS Spec v1.0 defines three ways the "bridge" role can be implemented (§2.5.4–§2.5.7): as part of the UACM service, as part of the resource itself, or as a separate entity. gva-uacm supports all three via a three-role model on its internal specification register.

The three roles

Role Meaning Wire behaviour
SR_ROLE The service owns this specification (Def Stan 23-009 §5.8 — "service as resource"). Published on the wire at boot with TRANSIENT_LOCAL durability.
BRIDGE_FALLBACK The service acts as a surrogate for a simple LRU that does not publish its own specification (§7.2.1 / GVA_UCMR_003). Every entry must declare a human-readable rationale. Held for a grace window (default 5 000 ms) then published — unless the R-role LRU claims authority on the wire first, in which case the surrogate publish is suppressed.
WIRE_LEARNED Promoted at runtime when the service receives a Monitored_Resource_Specification or Fault_Event_Specification from an external LRU that matches a BRIDGE_FALLBACK key. Nothing published — the service defers to the LRU's own wire authority.

JSON schema (nested — preferred)

{
  "policy": {
    // grace window before BRIDGE_FALLBACK entries are synthesised on
    // the wire; wire-authority ingest during this window promotes the
    // entry to WIRE_LEARNED and the surrogate publish is skipped.
    "bridgeGraceMs": 5000
  },
  "platformWithMonitoring": {
    // SR_ROLE — the service owns these specifications.
    "monitoredResourceSpecifications":       [ ... ],
    "faultEventSpecifications":              [ ... ],
    "monitoredCharacteristicSpecifications": [ ... ]
  },
  "fallbacks": {
    // BRIDGE_FALLBACK — surrogates for simple LRUs. Each entry MUST
    // carry a non-empty `rationale` explaining why the service is
    // publishing on behalf of the LRU.
    "monitoredResourceSpecifications":       [ ... ],
    "faultEventSpecifications":              [ ... ],
    "monitoredCharacteristicSpecifications": [ ... ]
  },
  "collectionDataSetDefinitions": [
    // See "Collection Data Set bulk-logging" above.
  ],
  "overrides": [
    // Patch derived Fault_Event output on emit — e.g. correct a typo
    // in an LRU-shipped faultDescription without patching the LRU
    // firmware. Matches on (kind, resourceId, instanceId).
    {
      "match": { "kind": "faultEvent", "resourceId": 8001, "instanceId": 1 },
      "patch": { "faultDescription": "Corrected description" },
      "rationale": "Typo in LRU firmware — corrected pending next release"
    }
  ],
  "disabled": [
    // Short-circuit derived output entirely — no publish, no PostGIS
    // row. Matches on (kind, resourceId, instanceId).
    {
      "match": { "kind": "faultEvent", "resourceId": 8002, "instanceId": 1 },
      "rationale": "Disabled on this vehicle configuration"
    }
  ]
}

Example BRIDGE_FALLBACK entry:

{
  "resourceId": 59001,
  "instanceId": 1,
  "faultEventIdentifier": "FAULT_EVENT::ENGINE_TEMP_SENSOR_FAULT",
  "faultDescription": "Engine temperature sensor malfunction",
  "faultCodeIdentifier": "FAULT_CODE::E001",
  "monitoredEntityResourceId": 1001,
  "monitoredEntityInstanceId": 1,
  "rationale": "Simple temperature sensor — no on-board R-role support"
}

CLI flags

Flag Purpose
-d, --domain <N> DDS domain ID (defaults to the build-time domain ID).
-c, --config <path> Path to the specifications JSON (see Configuration file location for the default search order).
--bridge-grace-ms <N> Override policy.bridgeGraceMs from JSON. 0 publishes fallbacks immediately (useful for tests).
--strict-conformance Reject any BRIDGE_FALLBACK entry whose rationale is empty. Fails the load rather than silently accepting a non-attributable surrogate. Recommended for production.

Boot logs make the role decisions auditable:

  • [UACM][BRIDGE] N fallback spec(s) will be synthesised in Xms if no LRU claims authority
  • [UACM][BRIDGE] synthesised FAULT_EVENT::… (rid=… iid=…) — <rationale>
  • [UACM][BRIDGE] suppressed surrogate publish of FAULT_EVENT::… — LRU published first
  • [UACM][BRIDGE] grace elapsed: N synthesised, M suppressed by wire authority
  • [UACM][POLICY] override registered kind=faultEvent (rid=… iid=…) — <rationale>
  • [UACM][POLICY] suppress registered kind=faultEvent (rid=… iid=…) — <rationale>
  • [UACM][POLICY] suppressing all Fault_Event activity for FAULT_EVENT::… (rid=… iid=…)
  • [UACM][STRICT] rejecting BRIDGE_FALLBACK … : missing 'rationale' (only under --strict-conformance)

Legacy flat schema (deprecated)

For back-compatibility, the pre-existing flat schema still loads:

{
  "monitoredResourceSpecifications":       [ ... ],
  "faultEventSpecifications":              [ ... ],
  "monitoredCharacteristicSpecifications": [ ... ]
}

Every entry is treated as SR_ROLE; there is no bridge/policy layer. A [UACM][DEPRECATION] uacm_specifications.json uses the flat legacy schema … notice is written to stderr on load. New deployments should use the nested form.

Configuration file location

Resolution order (highest to lowest precedence):

  1. -c/--config=<path> on the command line.
  2. /etc/gva/uacm/uacm_specifications.local.json — operator override. Never shipped by the package, so it is never overwritten on upgrade. Use this to customise the specification/policy file without editing the package-owned default in place.
  3. /etc/gva/uacm/uacm_specifications.json — the packaged default, installed by the gva-uacm-service package. Overwritten unconditionally on every upgrade.
  4. Dev-tree fallbacks — only relevant when running an unpacked build out of build/bin without installing.

If none of the search paths resolve, the service logs a warning and continues with an empty specification set — every monitored resource, characteristic, and fault is then learned entirely from what LRUs publish over DDS.

Database maintenance CLI

Two one-shot recovery actions are exposed on the gva-uacm binary. Both perform the requested action at startup, then the service continues normal boot; there is no separate one-shot systemd unit.

Destructive — no confirmation prompt

Both --db-truncate and --db-clear execute their delete the moment the process starts. There is no --yes interlock and no "are you sure?" prompt. The flag alone is the confirmation.

Never wire either flag into the ExecStart= line of the systemd unit — you will silently wipe UACM history on every reboot. These flags are for interactive operator use only.

Flag Deletes Preserves Effect on running fleet
--db-truncate[-days N] (default 90) monitored_events older than the cutoff, and CLEARED fault_events (plus their fault_state_history rows) older than the cutoff — the same retention sweep documented for deleteOldEvents()/deleteOldClearedFaults() Every active/inactive (non-cleared) fault; geofences/geofence_events/fault_specifications; the schema and indexes None — this is routine retention housekeeping, equivalent to what a cron-scheduled call to the repository methods would do
--db-clear Every row from every UACM-managed table (monitored_events, geofences, geofence_events, fault_specifications, fault_events, fault_state_history) Schema, indexes Full factory reset. UACM re-learns everything from uacm_specifications.json and the DDS wire on the next boot

--db-truncate and --db-clear are mutually exclusive; passing both together aborts with exit code 2 before any rows are touched. A failed database connection aborts with exit code 4; a failed delete aborts with exit code 5 — in both cases no partial action is left running and the service does not proceed to normal boot.

Typical use cases:

  • Routine retention: on a long-running vehicle, --db-truncate (optionally with --db-truncate-days tuned to site policy) keeps monitored_events from growing unbounded while leaving active fault history intact.
  • Dev / test: after a load-test run generates millions of simulated characteristic samples, --db-truncate --db-truncate-days 0 clears everything accumulated so far without needing a full reset.
  • Factory refurbishment: on a returned vehicle, --db-clear gives a completely empty UACM database — every monitored resource, characteristic and fault re-populates from the specification file and wire traffic on the next boot.

Both actions log every row count they delete to journald. Example:

[gva-uacm] --db-truncate: purging events/faults older than 20 day(s)…
[gva-uacm] --db-truncate complete: 1911875 event row(s) + 0 fault row(s) deleted.
Continuing normal service boot.

For per-row surgery (delete a specific fault or event without touching anything else) there is no operator-facing DDS command — use the repository's targeted query/delete methods directly if a bespoke cleanup is required.

Deployment

The UACM service ships as gva-uacm (systemd unit gva-uacm.service). Ordering:

  1. postgresql.service
  2. gva-db-init-service postinst (provisions roles/databases via gva-db-init.sh, once, at install/upgrade)
  3. gva-registry.service
  4. gva-uacm.service

Common environment overrides (see the shipped gva-uacm.env.example, installed to /etc/default/gva-uacm):

Variable Purpose
UACM_DB_HOST / UACM_DB_PORT PostgreSQL connection (default localhost:5432)
UACM_DB_NAME Database name (default uacm_db)
UACM_DB_USER / UACM_DB_PASSWORD PostgreSQL credentials — must match gva-db-init's provisioned role
UACM_DB_SCHEMA Schema name (default uacm)

Troubleshooting

Monitored_Resource.A_healthStatus never turns RED

  • Confirm the characteristic actually has a Threshold_Based_Monitoring_Requirement configured (either in uacm_specifications.json or published on the wire by the LRU) and that the sample/time hysteresis (attackSamples/attackDuration) has actually been met by the values supplied.
  • Use astutedds-discovery-dump -d <domain> to confirm the LRU and service participants see each other and the QoS on Monitored_Characteristic__supplyCharacteristicValue matches.
  • A subscriber started after an exceedance has already cleared will only ever see the resource's current (GREEN) state. Start your subscriber before driving the exceedance if you need to observe RED.

Maintenance_Action never transitions to Due automatically

  • Confirm the action is linked via usageExceededMaintenanceActionResourceId/ ...InstanceId or dueFaultCodeResourceId/...InstanceId in uacm_specifications.json — auto-Due is opt-in per action, not global.
  • Confirm the linked usage counter or fault has actually reached its Exceeded/active state, not just changed value.

Collection Data Set rows are missing for one characteristic

  • Confirm the characteristic has been supplied at least once (supplyCharacteristicValue) before the linked requirement or fault activates — the bulk-log path only writes the last-known cached value; a characteristic with no cached sample yet is silently skipped.

An LRU's specification is never picked up, only the bridge fallback

  • Check the LRU actually published its specification on the matching (resourceId, instanceId) key before the bridge grace window (policy.bridgeGraceMs, default 5000 ms) elapsed.
  • Increase --bridge-grace-ms if the LRU is a slow starter, or set it to 0 in test environments where the bridge fallback should never win a race.

SDK examples

Every wire-level behaviour on this page is covered by a raw-DDS SDK example under /usr/share/ldm-sdk/examples/ (installed by the ldm-sdk-examples package). See the SDK — UACM Examples reference page for the per-example index and build instructions.

Specification references

  • Def Stan 23-009 Usage and Condition Monitoring Service Specification v1.0 — §4.1.2 / GVA_UCMR_002 (R-role preamble), §5.4.13–§5.4.19 (monitoring requirements, threshold exceedance, logging cadence), §5.4.21 / GVA_UCMS_025 and §5.5.8 / GVA_UCMS_029 (Collection_Data_Set bulk-logging), §5.5.9–§5.5.10 / GVA_UCMS_030 and §5.6.8–§5.6.9 / GVA_UCMS_038 (Maintenance_Action auto-Due), §5.5 (Fault_Event derivation), §6 / GVA_UCMR_004 (IBIT), §7.2.1 / GVA_UCMR_003 (bridge role).
  • Def Stan 23-009 Command Response Protocol — IBIT start/stop, Maintenance_Action lifecycle, and manual-failure-report commands + CRP responses.
  • RAG rollup is LRU-authoritative (mirrors Resource_With_Monitoring. A_healthStatus verbatim), not a service-derived aggregation — the reference model does not define an aggregation algorithm, so the service does not attempt one. PBIT/CBIT aggregation likewise remains unspecified by the reference model.