Base TMC Command Design
Overview
The BaseTMCCommand provides a reusable class for implementing Telescope Management Controller (TMC) commands using the Template Method Pattern.
The Design defines a fixed execution workflow while allowing concrete commands to customize specific extension points through hook methods. Common infrastructure concerns such as command invocation, completion tracking, timeout handling, abort handling, and result evaluation are handled by the framework, allowing subclasses to focus only on command-specific business logic.
Design
BaseTMCCommand
│
├── ConfigureCommand
├── AssignResourcesCommand
├── ScanCommand
└── ReleaseResourcesCommand
│
▼
CommandExecutor
│
▼
CommandCompletionTracker
│
▼
CommandContext / CommandRuntimeContext
Command Workflow
execute()
│
▼
pre_process()
│
▼
initialize()
│
▼
prepare_command()
│
▼
build_device_commands()
│
▼
CommandExecutor.execute()
│
├── invoke device command
├── command_invoked_callback() (optional)
└── repeat for remaining devices
│
▼
CommandCompletionTracker.wait_for_command_completion()
│
▼
evaluate_result()
│
▼
handle_exception() (only on exception)
│
▼
cleanup()
│
▼
call_update_task_status()
│
▼
post_process()
Responsibilities
Component |
Responsibility |
|---|---|
BaseTMCCommand |
Define the framework for command execution and provide extension points |
CommandExecutor |
Executes subsystem commands and invokes per-device callbacks |
CommandCompletionTracker |
Waits for command completion, abort, early termination, or timeout |
CommandContext |
Stores runtime state for a single command execution |
CommandRuntimeContext |
Provides shared runtime services and synchronization primitives |
CommandCompletionContext |
Encapsulates completion tracking configuration |
Required Methods
Every concrete command must implement the following methods.
def build_device_commands(self):
pass
def update_task_status(self, **kwargs):
pass
Optional Hooks
The framework provides several hook methods that subclasses may override to customize behaviour.
Hook |
Purpose |
|---|---|
pre_process() |
Execute logic before command initialization |
prepare_command() |
Validate input and prepare command payloads |
command_invoked_callback() |
Execute logic immediately after each device command invocation |
is_state_complete() |
Define additional state-based completion criteria |
should_stop_waiting() |
Stop waiting immediately when command-specific conditions are met |
allowed_result_codes() |
Define acceptable command result codes |
evaluate_result() |
Evaluate overall command outcome |
handle_exception() |
Customize exception mapping |
post_process() |
Execute logic after command completion |
Completion Tracking
The framework creates a default CommandCompletionContext containing:
Completion condition
Command timeout
Completion checker
Abort checker
Subclasses may override create_completion_context() when additional
completion behaviour is required.
Waiting continues until one of the following occurs:
Completion criteria are satisfied.
should_stop_waiting()requests early termination.The command is aborted.
The command times out.
Command Invocation Callback
command_invoked_callback() is invoked immediately after a command has
been successfully invoked on an individual device.
This hook executes once for each device command before the framework continues invoking commands on remaining devices.
Typical use cases include:
Registering device-specific event subscriptions.
Recording command identifiers.
Performing device-specific initialization.
Starting monitoring activities.
Result Evaluation
After completion tracking finishes, the framework evaluates the collected device results.
By default:
Only
ResultCode.OKis considered successful.Commands may override
allowed_result_codes()to treat additional result codes as successful.Commands may override
evaluate_result()to implement command-specific result evaluation.
Command Execution Responsibilities
The framework automatically provides:
Command initialization
Command identifier generation
Adapter lookup
Command invocation
Completion tracking
Early wait termination
Timeout handling
Abort handling
Result evaluation
Exception mapping
Task status update
Cleanup
Best Practices
Keep validation and payload preparation inside
prepare_command().Use
pre_process()only for work that must occur before initialization.Use
command_invoked_callback()for actions that must occur immediately after a device accepts a command.Override
is_state_complete()only when completion depends on subsystem state.Override
should_stop_waiting()when waiting should terminate before completion criteria are met.Override
allowed_result_codes()instead ofevaluate_result()whenever only acceptable result codes differ.Override
evaluate_result()only when command-specific evaluation logic is required.Keep business logic inside subclasses and infrastructure concerns inside the framework.