Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ConfigurationDeskMCP/sources/models/hardware_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

class AddHardwarePlatformInput(BaseModel):
ip_addresses: List[str] = Field(
description="Address(es) of the platform to register, e.g. ['192.0.2.10']. VEOS is NOT a platform - do not use this for VEOS."
description="Address(es) of the platform to register, e.g. ['192.0.2.10']. VEOS is not a real-time hardware platform - do not use this for VEOS."
)
platform_type: str = Field(
default="SCALEXIO",
description="Platform type: 'SCALEXIO', 'MicroAutoBox III', or 'MicroLabBox II'. VEOS is NOT a platform - use add_application_processing_unit / generate_bus_containers instead.",
description="Platform type: 'SCALEXIO', 'MicroAutoBox III', or 'MicroLabBox II'. VEOS is not a real-time hardware platform - use add_processing_unit_application / generate_bus_containers instead.",
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,21 @@ def bus_manager_restbus_simulation(
For .slx/.mdl also call `analyze_models`; .sic/.bsc are already analyzed.
Then `add_model_to_signal_chain` to expose the model ports.

## Step 6 — Provide scheduling
A processing unit must exist. For real hardware, register it with
`add_hardware_platform`; for VEOS/offline, call `add_application_processing_unit`.
Then `create_application_process` (auto-assigned to "{bus_config_name}").
## Step 6 — Create the application process and assign the model
When creating an application process, a Processing Unit Application should be
automatically created if one does not already exist. If exactly one Processing Unit
Application exists, the Application Process should be added to it.

Assign the behavior model from Step 5 by calling
`create_preconfigured_application_process` with the model's name (use `list_models` to
get the exact name of "{model_path}"). This creates an application process pre-configured
for that model — its runnable function is placed in the process's default task.

Then assign the bus configuration to that application process with
`assign_bus_config_to_application_process` (bus_config_name="{bus_config_name}").

For a model-less restbus process instead, call `create_application_process` — it
auto-assigns to "{bus_config_name}".

## Step 7 — Connect the ports
Call `auto_connect_matching_io_function_blocks_to_model_ports` to wire matching
Expand Down
29 changes: 18 additions & 11 deletions ConfigurationDeskMCP/sources/prompts/individual_setup_prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ def create_application_process(
{_ENSURE_RUNNING}

## Prerequisite
A ProcessingUnitApplication must exist: register a hardware platform
(`add_hardware_platform`) or, for VEOS/no-hardware, call `add_application_processing_unit`.
A ProcessingUnitApplication is mandatory regardless of the target (real-time
hardware or BSC/VEOS). If none exists yet, call `add_processing_unit_application`.

## Step 1 — Create the process (default periodic task)
Call `create_application_process` with name="{process_name}". This sets
Expand Down Expand Up @@ -386,7 +386,7 @@ def build_application(

@mcp.prompt(
name="register_hardware",
description="Single task: provide the hardware topology — register a SCALEXIO/MicroAutoBox III/MicroLabBox II platform, import an .htfx file, or add a VEOS processing unit",
description="Single task: provide the hardware topology — register and scan a SCALEXIO/MicroAutoBox III/MicroLabBox II platform or import an .htfx file for a real-time application. A non-empty hardware topology is NOT necessary to generate bus simulation containers (BSC)",
)
def register_hardware(
platform_type: str = "SCALEXIO",
Expand All @@ -396,23 +396,30 @@ def register_hardware(
# Register Hardware

Goal: provide the hardware topology that bus and I/O function blocks are assigned to.
NOTE: a hardware topology is required to build and download a real-time application
for SCALEXIO, MicroAutoBox III, or MicroLabBox II. It describes the components of a
specific hardware system, such as channel types and slot numbers.

GENERAL REMARK: a non-empty hardware topology — created for example by registering
and scanning hardware — is NOT necessary to generate bus simulation containers (BSC).
When BSC output is the only deliverable, skip this prompt entirely and use
`generate_bus_containers`. Working without a hardware topology means bus
configurations are not assigned to application processes via real-time hardware
access, so assign them manually instead.

{_ENSURE_RUNNING}

## Choose an approach (ASK the user which applies)

### Option A — Physical platform
### Option A — Register and scan a physical platform
Call `add_hardware_platform` with ip_addresses=["{platform_ip}"], platform_type="{platform_type}".
Valid types: "SCALEXIO", "MicroAutoBox III", "MicroLabBox II".
Returns the unique platform name used by later hardware operations.
Returns the unique platform name used by later hardware operations. Scanning the
registered platform creates a matching hardware topology.

### Option B — Import a topology file
Call `import_hardware_topology` with path="C:/HW/topology.htfx".

### Option C — VEOS / no hardware
Call `add_application_processing_unit`. VEOS is NOT a platform — do NOT call
`add_hardware_platform` for it. The deliverable is the generated BSC.

## Verify / maintain
- `list_platforms` — confirm the registered hardware and its I/O boards.
- `refresh_platforms` — refresh platform information.
Expand Down Expand Up @@ -477,7 +484,7 @@ def assign_bus_hardware(
## Prerequisite
- A bus configuration with assigned ECUs (see `create_bus_configuration`).
- Hardware present: `add_hardware_platform` / `import_hardware_topology`, or
`add_application_processing_unit` for VEOS (then skip channel assignment).
`add_processing_unit_application` for VEOS (then skip channel assignment).

## Step 1 — Inspect what needs hardware
Call `list_bus_access_requests` — each cluster/part generates one request to assign.
Expand Down Expand Up @@ -571,7 +578,7 @@ def inspect_configuration() -> str:
Call `get_application_status` — project name, project root, and active application.

## Configuration tree
Call `list_configuration` — executable applications, processing units, tasks, events.
Call `list_configuration` — executable applications, processing unit applications, application processes, tasks, events.

## Inventory
- `list_applications` — applications in the project.
Expand Down
4 changes: 2 additions & 2 deletions ConfigurationDeskMCP/sources/resources/domain_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
## Hardware Platforms
SCALEXIO, MicroAutoBox III, and MicroLabBox II platforms are registered by
address and scanned to create the hardware topology. Use `list_platforms` to see
registered hardware. VEOS is NOT a platform — use `add_application_processing_unit`.
registered hardware. VEOS is not a real-time hardware platform.
"""

_TOOL_CATEGORIES = """\
Expand Down Expand Up @@ -597,7 +597,7 @@
- `SCALEXIO`
- `MicroAutoBox III`
- `MicroLabBox II`
(VEOS is NOT a platform — use `add_application_processing_unit`.)
(VEOS is not a real-time hardware platform.)

## `bus_type` (create_io_function_block)
- `CAN`
Expand Down
4 changes: 2 additions & 2 deletions ConfigurationDeskMCP/sources/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ async def _lifespan(server: FastMCP) -> Any: # type: ignore[type-arg]
13. Hardware topology → ASK USER which approach:
- `add_hardware_platform` → register SCALEXIO, MicroAutoBox III, or MicroLabBox II hardware (needs address from user)
- `import_hardware_topology` → import .htfx file (needs file path from user)
- `add_application_processing_unit` → no physical hardware / VEOS workflow
- VEOS does NOT need platform registration. Use generate_bus_containers for BSC files.
- `add_processing_unit_application` → no physical hardware / VEOS workflow
- VEOS is not a real-time hardware platform; use generate_bus_containers to produce the BSC files it consumes.
14. `create_io_function_block` → create CAN/LIN/Ethernet I/O block
15. `set_io_function_block_property` → set BaudRate
16. `assign_bus_access` → link bus access requests to function block
Expand Down
33 changes: 33 additions & 0 deletions ConfigurationDeskMCP/sources/services/app_management_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,36 @@ async def list_applications() -> str:
except Exception as e:
logger.exception("Error listing applications")
return error_response(str(e), transient=False)


async def add_processing_unit_application() -> str:
"""Add a processing unit application to the executable application.

An executable application has one or more processing unit applications (PUA);
each PUA is executed on one processing unit (PU) and hosts one or more
application processes (AP). Add one explicitly when no registered hardware or
imported topology already provides one — typically a no-hardware or VEOS build.
"""
try:
conn = await _get_live_connection()
result = await dispatch(app_management_com.add_processing_unit_application, conn)
pua_created = result.get("processing_unit_application_created", False)
if not pua_created:
return error_response(
f"ProcessingUnitApplication could not be added: "
f"{result.get('processing_unit_application_detail', '')}. "
"You may need to add it manually in ConfigurationDesk.",
transient=False,
)
return success_response(
message=(
"ProcessingUnitApplication added. "
"For VEOS: use generate_bus_containers to produce BSC files."
),
verified=True,
)
except BridgeError as exc:
return tool_error_result(exc)
except Exception as e:
logger.exception("Error adding processing unit application")
return error_response(str(e), transient=False)
6 changes: 3 additions & 3 deletions ConfigurationDeskMCP/sources/services/bus_access_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ async def auto_assign_channel_set(function_block_name: str, bus_type: str = "CAN
f"Function block '{function_block_name}' not found. "
f"Verify it exists with list_io_function_block_properties. "
f"If the block is LIN, pass bus_type='LIN'. "
f"Also ensure a hardware topology exists via add_application_processing_unit or add_hardware_platform."
f"Also ensure a hardware topology exists (add_hardware_platform or import_hardware_topology), or add a processing unit application (add_processing_unit_application) for a no-hardware build."
),
)
return error_response(detail, transient=False)
Expand Down Expand Up @@ -390,7 +390,7 @@ async def create_preconfigured_application_process(model_name: str) -> str:
next_action=(
"Pre-configured application process creation failed. "
"Verify the model exists in the topology and a ProcessingUnitApplication "
"is available (registered hardware or `add_application_processing_unit`). "
"is available (registered hardware or `add_processing_unit_application`). "
"Do NOT retry with the same parameters."
),
)
Expand All @@ -406,7 +406,7 @@ async def create_preconfigured_application_process(model_name: str) -> str:
"No new application process became observable after the pre-configured creation call.",
transient=False,
next_action=(
"Verify a ProcessingUnitApplication exists (use `add_application_processing_unit` "
"Verify a ProcessingUnitApplication exists (use `add_processing_unit_application` "
"for VEOS workflows, or register hardware). Then call `create_application_process` "
"as the manual fallback."
),
Expand Down
31 changes: 1 addition & 30 deletions ConfigurationDeskMCP/sources/services/hardware_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def add_hardware_platform(ip_addresses: list[str], platform_type: str = "S
transient=False,
retryable=False,
next_action=(
"VEOS is not a hardware platform. For VEOS workflows: "
"VEOS is not a real-time hardware platform and cannot be registered in ConfigurationDesk. For VEOS workflows: "
"1) Use generate_bus_containers to create BSC files, "
"2) Import BSC files into VEOS. "
"For SCALEXIO: ensure hardware is powered on and reachable."
Expand Down Expand Up @@ -160,32 +160,3 @@ async def add_hardware_element(element_type: str) -> str:
except Exception as e:
logger.exception("Error adding hardware element")
return error_response(str(e), transient=False)


async def add_application_processing_unit() -> str:
"""Add a ProcessingUnitApplication to the application configuration.

Used for VEOS-targeted or no-hardware workflows.
"""
try:
conn = get_connection()
result = await dispatch(hardware_com.add_application_processing_unit, conn)
pu_created = result.get("processing_unit_created", False)
if not pu_created:
return error_response(
f"ProcessingUnitApplication could not be added: {result.get('processing_unit_detail', '')}. "
"You may need to add it manually in ConfigurationDesk.",
transient=False,
)
return success_response(
message=(
"ProcessingUnitApplication added. "
"For VEOS: use generate_bus_containers to produce BSC files."
),
verified=True,
)
except BridgeError as exc:
return tool_error_result(exc)
except Exception as e:
logger.exception("Error adding application processing unit")
return error_response(str(e), transient=False)
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async def create_application_process(
"No new application process became observable after the creation call.",
transient=False,
next_action=(
"Verify a ProcessingUnitApplication exists (use `add_application_processing_unit` "
"Verify a ProcessingUnitApplication exists (use `add_processing_unit_application` "
"for VEOS workflows or register a hardware platform), then retry."
),
)
Expand Down
24 changes: 24 additions & 0 deletions ConfigurationDeskMCP/sources/tools/app_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
RemoveApplicationInput,
)
from sources.server.app import mcp
from sources.server.preconditions import with_preconditions
from sources.services import app_management_service as svc


Expand Down Expand Up @@ -69,3 +70,26 @@ async def remove_application(input: RemoveApplicationInput) -> str:
)
async def list_applications() -> str:
return await svc.list_applications()


@mcp.tool(
name="add_processing_unit_application",
description=(
"Add a processing unit application to the executable application. "
"An executable application has one or more processing unit applications (PUA); "
"each PUA is executed on one processing unit (PU) and hosts one or more "
"application processes (AP). Add one explicitly when no "
"registered hardware or imported topology already provides one — typically a "
"no-hardware or VEOS build. VEOS is not a real-time hardware platform; "
"it consumes generated Bus Simulation Containers (BSC)."
),
annotations={
"readOnlyHint": False,
"destructiveHint": False,
"idempotentHint": True,
"openWorldHint": False,
},
)
@with_preconditions("connection", "project", "application")
async def add_processing_unit_application() -> str:
return await svc.add_processing_unit_application()
2 changes: 1 addition & 1 deletion ConfigurationDeskMCP/sources/tools/bus_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ async def auto_connect_matching_io_function_blocks_to_model_ports() -> str:
"Create a pre-configured application process for one specific model. "
"Calls Algorithms.CreatePreConfiguredApplicationProcessAutomatically([model], None). "
"A new ProcessingUnitApplication is created automatically when no Parent is supplied "
"(VEOS workflows: ensure `add_application_processing_unit` was called first). "
"(VEOS workflows: ensure `add_processing_unit_application` was called first). "
"For all-models behavior, prefer create_application_process or pass `model_names` to it."
),
annotations={
Expand Down
3 changes: 2 additions & 1 deletion ConfigurationDeskMCP/sources/tools/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
name="list_configuration",
description=(
"List the application configuration tree "
+ "(executable applications, processing units, tasks, events). "
+ "(executable applications, processing unit applications, application processes, "
+ "tasks, events). "
+ "Results are paginated; call again with next_offset to retrieve later pages."
),
annotations={
Expand Down
26 changes: 2 additions & 24 deletions ConfigurationDeskMCP/sources/tools/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
"BEFORE calling this tool, ASK the user which hardware approach they want: "
"1) Provide address of SCALEXIO, MicroAutoBox III, or MicroLabBox II hardware → use this tool, "
"2) Import an .htfx topology file → use import_hardware_topology, "
"3) Create empty topology (VEOS/no hardware) → use add_application_processing_unit. "
"VEOS is NOT a platform - never call this for VEOS. "
"VEOS is not a real-time hardware platform - never call this for VEOS. "
"Returns the unique platform name for subsequent hardware operations."
),
annotations={
Expand All @@ -38,7 +37,7 @@ async def add_hardware_platform(
platform_type: Annotated[
str,
Field(
description="Platform type: 'SCALEXIO', 'MicroAutoBox III', or 'MicroLabBox II'. VEOS is not a platform.",
description="Platform type: 'SCALEXIO', 'MicroAutoBox III', or 'MicroLabBox II'. VEOS is not a real-time hardware platform.",
),
] = "SCALEXIO",
) -> str:
Expand Down Expand Up @@ -167,24 +166,3 @@ async def add_hardware_element(
],
) -> str:
return await svc.add_hardware_element(element_type)


@mcp.tool(
name="add_application_processing_unit",
description=(
"Add a ProcessingUnitApplication to the application configuration. "
"Use this for VEOS-targeted or no-hardware workflows where the project needs "
"an application processing unit to host I/O function blocks and application processes. "
"VEOS does NOT use registered hardware platforms; it consumes generated Bus "
"Simulation Containers (BSC)."
),
annotations={
"readOnlyHint": False,
"destructiveHint": False,
"idempotentHint": True,
"openWorldHint": False,
},
)
@with_preconditions("connection", "project", "application")
async def add_application_processing_unit() -> str:
return await svc.add_application_processing_unit()
2 changes: 1 addition & 1 deletion ConfigurationDeskMCP/sources/tools/model_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ async def analyze_models() -> str:
"Pass `bus_config_names` to scope the assignment to specific configurations, or pass an "
"empty list `[]` to skip assignment entirely. "
"PRECONDITION: a ProcessingUnitApplication must exist (register a hardware platform or call "
"`add_application_processing_unit` for VEOS workflows)."
"`add_processing_unit_application` for VEOS workflows)."
),
annotations={
"readOnlyHint": False,
Expand Down
6 changes: 3 additions & 3 deletions ConfigurationDeskMCP/tests/_fake_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ def _create_preconfigured_application_process(model_name, *args):
"hardware_items": [etype or "Element"],
"verified": True,
},
"add_application_processing_unit": {
"processing_unit_created": True,
"processing_unit_detail": "created",
"add_processing_unit_application": {
"processing_unit_application_created": True,
"processing_unit_application_detail": "created",
},
"import_hardware_topology": {"verified": True, "hardware_items": ["SCALEXIO_Rack"]},
"scan_hardware": {"verified": True, "hardware_items": ["SCALEXIO_Rack"]},
Expand Down
5 changes: 5 additions & 0 deletions ConfigurationDeskMCP/tests/domains/test_app_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"activate_application",
"remove_application",
"list_applications",
"add_processing_unit_application",
)


Expand All @@ -28,3 +29,7 @@ def test_remove_application(fake_bridge):

def test_list_applications(fake_bridge):
run_ok(appmgmt_svc.list_applications())


def test_add_processing_unit_application(fake_bridge):
run_ok(appmgmt_svc.add_processing_unit_application())
Loading