Skip to content

Implement Modes (target mode management) endpoints #204

@bburda

Description

@bburda

Summary

Modes represent entity states - things like "diagnostic session level" or "security access level" - that may be prerequisites for accessing certain resources or executing certain operations. For example, a component might require diagnostic_session=EXTENDED before allowing certain calibration operations.

Clients can list available modes, read their current values, and change them.


Proposed solution

1. GET /api/v1/{entity-path}/modes

List all modes defined for an entity.

Applies to entity types: Components, Apps

Path parameters:

Parameter Type Required Description
{entity-path} URL segment Yes e.g., components/engine_ecu

Response 200 OK:

{
  "items": [
    {
      "id": "diagnostic_session",
      "name": "Diagnostic Session",
      "href": "/api/v1/components/engine_ecu/modes/diagnostic_session"
    },
    {
      "id": "access_level",
      "name": "Security Access Level",
      "href": "/api/v1/components/engine_ecu/modes/access_level"
    }
  ]
}

Each item is a ModeReference:

Field Type Required Description
id string Yes Mode identifier
name string Yes Human-readable mode name
translation_id string No Translation key for localization
href string Yes URI to read/set this mode

2. GET /api/v1/{entity-path}/modes/{mode-id}

Read the current value of a mode, including its JSON Schema (enum of allowed values).

Path parameters:

Parameter Type Required Description
{entity-path} URL segment Yes e.g., components/engine_ecu
{mode-id} string Yes Mode identifier

Response 200 OK:

{
  "name": "Diagnostic Session",
  "value": "DEFAULT",
  "schema": {
    "type": "string",
    "enum": ["DEFAULT", "EXTENDED", "PROGRAMMING"]
  }
}
Field Type Required Description
name string Yes Mode name
value string Yes Current mode value
schema object Yes JSON Schema describing allowed values. Usually { "type": "string", "enum": [...] }

Error responses:

Status Error Code When
404 resource-not-found Mode doesn't exist on this entity

3. PUT /api/v1/{entity-path}/modes/{mode-id}

Change the current mode value. Optionally set an expiration timer after which the mode reverts to its default value.

Path parameters:

Parameter Type Required Description
{entity-path} URL segment Yes e.g., components/engine_ecu
{mode-id} string Yes Mode identifier

Request body:

{
  "value": "EXTENDED",
  "mode_expiration": 1200
}
Field Type Required Description
value string Yes Target mode value (must be one of the values in the mode's schema enum)
mode_expiration integer No Seconds until auto-revert to default. If omitted, mode stays until explicitly changed or server restarts.

Response 200 OK: Returns the updated mode (same format as GET).

Error responses:

Status Error Code When
400 invalid-parameter Value not in allowed enum, invalid expiration
404 resource-not-found Mode doesn't exist
500 internal-error Entity returned an error when changing mode

Hint-based Mode Control (request header)

Instead of making separate SET mode calls, any API request can include modes via the x-sovd-mode header:

POST /api/v1/apps/temp_sensor/operations/calibrate/executions HTTP/1.1
x-sovd-mode: diagnostic_session;EXTENDED,access_level;UNLOCKED

Header format: x-sovd-mode: {mode-id};{value}[,{mode-id};{value}]*

The server sets the requested modes before executing the main request. This avoids separate mode-setting round-trips.

Behavior:

  • If mode setting fails, the main request is not executed and a 400 error is returned
  • Modes set via hint header follow the same validation as PUT /modes/{id}
  • If mode_expiration is needed, use the explicit PUT endpoint instead

Additional context

ROS 2 mapping

Modes can be implemented via:

  1. ROS 2 node parameters - mode values stored as parameters on the entity's node (e.g., diagnostic_session parameter with string enum)
  2. Gateway-managed state - the gateway tracks mode values internally, applying them as prerequisites before forwarding requests

For initial implementation, gateway-managed state is simpler:

  • Store mode definitions per entity (from manifest)
  • Track current values in memory
  • Reset to defaults on server restart

Mode definitions

Modes should be declarable in the manifest YAML:

components:
  engine_ecu:
    modes:
      - id: diagnostic_session
        name: "Diagnostic Session"
        default: "DEFAULT"
        values: ["DEFAULT", "EXTENDED", "PROGRAMMING"]
      - id: access_level
        name: "Security Access Level"
        default: "LOCKED"
        values: ["LOCKED", "UNLOCKED"]

Mode expiration

  • Use a ROS 2 timer per active expiration
  • On expiry: revert mode to its default value
  • Cancel timer if mode is changed again before expiry

Mode prerequisites

The capability description (OpenAPI extensions) defines which modes must be set before an operation can execute:

  • x-sovd-required-modes: { "diagnostic_session": "EXTENDED" } on an operation means the diagnostic_session mode must be EXTENDED before that operation can run
  • The operation handler should check mode prerequisites and return 400 if not met

Route registration

srv->Get((api_path("/components") + R"(/([^/]+)/modes$)"), handler);
srv->Get((api_path("/components") + R"(/([^/]+)/modes/([^/]+)$)"), handler);
srv->Put((api_path("/components") + R"(/([^/]+)/modes/([^/]+)$)"), handler);
// Same for /apps/

Tests

  • Unit test: list modes returns manifest-defined modes
  • Unit test: get mode returns current value and schema
  • Unit test: set mode → value changes → 200
  • Unit test: set invalid enum value → 400
  • Unit test: mode expiration auto-reverts
  • Unit test: nonexistent mode → 404
  • Unit test: x-sovd-mode header parsed and applied

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions