Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
91ce762
Added Template Instantiator
michal-kurowski-n7s Dec 5, 2025
88edd66
Added names to SystemObjectTypes
michal-kurowski-n7s Dec 5, 2025
9e741d9
Working proof of concept
michal-kurowski-n7s Dec 5, 2025
50be974
Merge branch 'main' into feature-mbep#313-template-instantiation
michal-kurowski-n7s Dec 8, 2025
9e663c0
Added parsing of requirement IDs
michal-kurowski-n7s Dec 8, 2025
aa3f4c9
Ignore output of examples
michal-kurowski-n7s Dec 8, 2025
d271cc8
Added example of generating traces
michal-kurowski-n7s Dec 8, 2025
4de0a3f
Improved trace example
michal-kurowski-n7s Dec 8, 2025
f5ef5f8
Added placeholders for the templates
michal-kurowski-n7s Dec 8, 2025
4ecc204
Merge fix
michal-kurowski-n7s Dec 8, 2025
384b7ca
Added DV example
michal-kurowski-n7s Dec 8, 2025
59166c0
Added ECSS-like requirement trace matrices
michal-kurowski-n7s Dec 8, 2025
01a440d
Aspects of each component POC
michal-kurowski-n7s Dec 8, 2025
34a463d
Merge branch 'main' into feature-mbep#313-template-instantiation
michal-kurowski-n7s Dec 9, 2025
dd826ce
Updated template instantiation tests with DV
michal-kurowski-n7s Dec 9, 2025
1465314
Added demo-project
michal-kurowski-n7s Dec 9, 2025
131e8b9
Improved traceability template
michal-kurowski-n7s Dec 9, 2025
bec6423
Added missing languages in IV parsing
michal-kurowski-n7s Dec 9, 2025
ab854d6
Added custom value support
michal-kurowski-n7s Dec 9, 2025
dd16df9
Added dynamic architecture template and improved interface data model
michal-kurowski-n7s Dec 10, 2025
ec4e51a
Added initial version of internal_inferfaces_design template
michal-kurowski-n7s Dec 10, 2025
0140511
Fixed existing tests
michal-kurowski-n7s Dec 10, 2025
f5c99e3
Added test for value instantiation
michal-kurowski-n7s Dec 10, 2025
16f2b14
Fixed filtering of container functions
michal-kurowski-n7s Dec 10, 2025
83929d8
Added interfaces context template
michal-kurowski-n7s Dec 11, 2025
2504eac
Added static architecture template
michal-kurowski-n7s Dec 11, 2025
a8ebd19
Added overall architecture template
michal-kurowski-n7s Dec 11, 2025
f2c01bd
Improved System Objects example
michal-kurowski-n7s Dec 11, 2025
82b6730
Review fixes
michal-kurowski-n7s Dec 11, 2025
99f23b9
Refactored CLI
michal-kurowski-n7s Dec 11, 2025
6212c6f
Review fixes
michal-kurowski-n7s Dec 11, 2025
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Output in examples
examples/output/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ PYTHON ?= python3
all: check-format check

install:
pipx install .
pipx install --force .

check:
$(MAKE) -C tests check
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<%
## Data Initialization
# Get all functions

funcs = []
def get_function_children(func):
result = []
if func.nested_functions:
for nested in func.nested_functions:
result.append(nested)
result.extend(get_function_children(nested))
return result

for func in interface_view.functions:
funcs.append(func)
funcs.extend(get_function_children(func))

funcs.sort(key=lambda f: f.name.lower())

# Get functions deployed to the target partition
target_partition_name = values["TARGET"]

deployed_funcs = []
target_partition = None
target_node = None
for node in deployment_view.nodes:
for partition in node.partitions:
if partition.name == target_partition_name:
target_node = node
target_partition = partition

deployed_func_names = [f.name for f in target_partition.functions]
for fun in funcs:
if fun.name in deployed_func_names:
deployed_funcs.append(fun)

# Only leaf functions are deployed, so a correction for parents must be applied
for func in funcs:
if func.nested_functions:
for nested in func.nested_functions:
if nested in deployed_funcs and not func in deployed_funcs:
deployed_funcs.append(func)
deployed_func_names.append(func.name)

# Get used implementations
languages = set()
for func in deployed_funcs:
languages.add(func.language)

%>

The software architecture of ${target_partition_name} consists of ${len(deployed_funcs)} functions deployed onto ${target_node.name} node.
The functions use the following implementation technologies: ${",".join([l.value for l in languages])}.
The top-level components are as follows:
% for func in interface_view.functions:
<%
if not func.name in deployed_func_names:
continue
is_composite = func.nested_functions and len(func.nested_functions) > 0
implementation_text = "[COMPOSITE] " if is_composite else func.language.value
%>

- ${func.name} [${implementation_text}] - ${func.comment}
% endfor
## Print the level 2 functions
% for func in interface_view.functions:
<%
if not func.nested_functions or len(func.nested_functions) == 0:
continue
%>

Function ${func.name} is a composite, containing the following sub-functions:
% for nested in func.nested_functions:
<%
is_composite = nested.nested_functions and len(nested.nested_functions) > 0
implementation_text = "[COMPOSITE] " if is_composite else nested.language.value
%>

- ${nested.name} [${implementation_text}] - ${nested.comment}
% endfor

% endfor
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<%
## Data Initialization
# Get all functions

funcs = []
def get_function_children(func):
result = []
if func.nested_functions:
for nested in func.nested_functions:
result.append(nested)
result.extend(get_function_children(nested))
return result

for func in interface_view.functions:
funcs.append(func)
funcs.extend(get_function_children(func))

funcs.sort(key=lambda f: f.name.lower())

# Get functions deployed to the target partition
target_partition_name = values["TARGET"]

deployed_funcs = []
target_partition = None
for node in deployment_view.nodes:
for partition in node.partitions:
if partition.name == target_partition_name:
target_partition = partition

deployed_func_names = [f.name for f in target_partition.functions]
for fun in funcs:
if fun.name in deployed_func_names:
deployed_funcs.append(fun)

# Get all threads
threads = []
for func in deployed_funcs:
for pi in func.provided_interfaces:
if pi.kind.value == "Sporadic" or pi.kind.value == "Cyclic":
threads.append((func, pi))

%>


The list below summarizes all threads of the user components.
% for (func, pi) in threads:

${"##"} [${pi.kind.value}] ${func.name}::${pi.name}

- Description: ${pi.comment}

- Stack size: ${pi.stack_size}

% if pi.kind.value == "Sporadic":
- Queue size: ${pi.queue_size}

% endif
- Priority: ${pi.priority}

% if pi.kind.value == "Cyclic":
- Period: ${pi.period}

- Dispatch offset : ${pi.dispatch_offset}
%endif

% if pi.wcet is not None and pi.wcet != 0:
- WCET: ${pi.wcet}

%endif
% if pi.miat is not None and pi.miat != 0:
- MIAT: ${pi.miat}

% endif
% endfor
165 changes: 165 additions & 0 deletions data/ecss-template/ecss-e-st-40c_4_4_interfaces_context.tmplt
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<%
## Data Initialization
# Get all functions

def find_by_name(all, name):
for f in all:
if f.name == name:
return f
return None

funcs = []
def get_function_children(func):
result = []
if func.nested_functions:
for nested in func.nested_functions:
result.append(nested)
result.extend(get_function_children(nested))
return result

for func in interface_view.functions:
funcs.append(func)
funcs.extend(get_function_children(func))

funcs.sort(key=lambda f: f.name.lower())

# Get functions deployed to the target partition
target_partition_name = values["TARGET"]

deployed_funcs = []
target_partition = None
for node in deployment_view.nodes:
for partition in node.partitions:
if partition.name == target_partition_name:
target_partition = partition

deployed_func_names = [f.name for f in target_partition.functions]
for fun in funcs:
if fun.name in deployed_func_names:
deployed_funcs.append(fun)

# Only leaf functions are deployed, so a correction for parents must be applied
for func in funcs:
if func.nested_functions:
for nested in func.nested_functions:
if nested in deployed_funcs and not func in deployed_funcs:
deployed_funcs.append(func)
deployed_func_names.append(func.name)

# Find and crossreference all connections
def get_function_connections(func):
result = []
if func.nested_connections:
result.extend(func.nested_connections)
if func.nested_functions:
for nested in func.nested_functions:
result.extend(get_function_connections(nested))
return result

connections = []
connections.extend(interface_view.connections)
for func in interface_view.functions:
connections.extend(get_function_connections(func))

external_connections = []

for connection in connections:
if connection.source is None or connection.source.function_name is None:
continue
if connection.target is None or connection.target.function_name is None:
continue
target_inside = connection.target.function_name in deployed_func_names
source_inside = connection.source.function_name in deployed_func_names
if (target_inside and not source_inside) or (not target_inside and source_inside):
external_connections.append(connection)

iface_source_map = {}
iface_target_map = {}

for connection in external_connections:
meta = {}
meta["connection"] = connection
meta["source_function"] = find_by_name(funcs, connection.source.function_name)
if meta["source_function"] is None:
print(f"Source function {connection.source.function_name} not found")
continue
meta["source_iface"] = find_by_name(meta["source_function"].provided_interfaces + meta["source_function"].required_interfaces, connection.source.iface_name)
meta["target_function"] = find_by_name(funcs, connection.target.function_name)
if meta["target_function"] is None:
print(f"Target function {connection.target.function_name} not found")
continue
meta["target_iface"] = find_by_name(meta["target_function"].provided_interfaces + meta["target_function"].required_interfaces, connection.source.iface_name)
source_handle = f"{meta["source_function"].name}__{meta["source_iface"].name}"
target_handle = f"{meta["target_function"].name}__{meta["target_iface"].name}"
if not source_handle in iface_source_map.keys():
iface_source_map[source_handle] = []
iface_source_map[source_handle].append((meta["target_function"], meta["target_iface"]))
if not target_handle in iface_target_map.keys():
iface_target_map[target_handle] = []
iface_target_map[target_handle].append((meta["source_function"], meta["source_iface"]))

%>

The list below summarizes all external interfaces.

% for func in deployed_funcs:
% for iface in func.provided_interfaces + func.required_interfaces:
<%
iface_handle = f"{func.name}__{iface.name}"
if not iface_handle in iface_source_map and not iface_handle in iface_target_map:
continue
%>
${"#"} \
% if iface in func.provided_interfaces:
[PROVIDED] \
% else:
[REQUIRED] \
% endif
[${iface.kind.value}] ${func.name}::${iface.name}

- Description: ${iface.comment}

% if iface.kind.value != "Cyclic":
- Parameters:
% for param in iface.input_parameters + iface.output_parameters:

- \
% if param in iface.input_parameters:
[IN] \
% else:
[OUT] \
% endif
${param.name} ${param.type} (with ${param.encoding.value} encoding)
% endfor
% endif

% if iface_handle in iface_source_map:
- Connects to:
% for (other_function, other_iface) in iface_source_map[iface_handle]:

- ${other_function.name}::${other_iface.name}
% endfor
% endif

% if iface_handle in iface_target_map:
- Is connected from:
% for (other_function, other_iface) in iface_target_map[iface_handle]:

- ${other_function.name}::${other_iface.name}
% endfor
% endif

% endfor
% endfor

The list below summarizes all external connections:
% for connection in external_connections:
<%
if connection.source is None or connection.source.function_name is None:
continue
if connection.target is None or connection.target.function_name is None:
continue
%> \

- Connection from ${connection.source.function_name}::${connection.source.iface_name} to ${connection.target.function_name}::${connection.target.iface_name}
% endfor
Loading