65c1d746a7
We don't transfer git history since it may contain proprietary data that we cannot have in an open sources version. Change-Id: I9586124c1720db69a76b9390e208e9f0ba3b86d4
228 lines
8.4 KiB
Python
228 lines
8.4 KiB
Python
# Copyright 2024 Volvo Car Corporation
|
|
# Licensed under Apache 2.0.
|
|
|
|
"""Module to generate AllSystemInfo.mat for compatibility purposes with DocGen."""
|
|
|
|
import os
|
|
from copy import deepcopy
|
|
from numpy import array
|
|
from scipy.io import savemat
|
|
from pybuild.signal_interfaces import SignalInterfaces
|
|
from pybuild.unit_configs import UnitConfigs
|
|
from pybuild.lib.helper_functions import merge_dicts
|
|
from pybuild.problem_logger import ProblemLogger
|
|
|
|
|
|
def _get_signals_by_type(signal_conf, signal_type):
|
|
"""Get signals by type ('missing', 'unused', 'inconsistent_defs' or 'multiple_defs').
|
|
|
|
Args:
|
|
signal_conf (dict): Configuration from SignalInterfaces with the following format
|
|
{
|
|
"missing": {"signal_name" : ["VED4_GENIII", "VEP4_GENIII"]}
|
|
"unused": {}
|
|
"multiple_defs": {}
|
|
"inconsistent_defs": {}
|
|
}
|
|
|
|
Returns:
|
|
dict: with the following format
|
|
{
|
|
"signal_name" : {'VarStatus' : 'Not Used', 'SignalType' : "signal_type"}
|
|
}
|
|
|
|
"""
|
|
result = {}
|
|
for signal_name in signal_conf[signal_type].keys():
|
|
signal = {signal_name: {'VarStatus': 'Not Used', 'SignalType': signal_type}}
|
|
result.update(signal)
|
|
return result
|
|
|
|
|
|
class GenAllSystemInfo(ProblemLogger):
|
|
"""Class to generate AllSystemInfo.mat for compatibility purposes with DocGen."""
|
|
|
|
_signal_types = ['missing', 'unused']
|
|
|
|
def __init__(self, signal_if, unit_cfg):
|
|
"""Class to generate a matlab struct AllSystemInfo for compatibility with the old document generation.
|
|
|
|
Args:
|
|
signal_if: an initialized SignalInterfaces object to access signal configurations
|
|
"""
|
|
if not isinstance(signal_if, SignalInterfaces):
|
|
raise TypeError
|
|
if not isinstance(unit_cfg, UnitConfigs):
|
|
raise TypeError
|
|
self.signal_if = signal_if
|
|
self.unit_cfg = unit_cfg
|
|
self._signals_without_source = {}
|
|
self._core_ids = {}
|
|
self._file_info = {}
|
|
self._dids = {}
|
|
|
|
def __repr__(self):
|
|
"""Get string representation of object."""
|
|
return f'if: {self.signal_if}\n uc: {self.unit_cfg}'
|
|
|
|
def build(self):
|
|
"""Build AllSystemInfo.mat for docgen compatibility."""
|
|
self.info('******************************************************')
|
|
self.info('%s - Getting signals without source', __name__)
|
|
signals_tmp = self.get_signals_without_source()
|
|
for signal_name, signal_data in signals_tmp.items():
|
|
if '.' in signal_name:
|
|
struct_name = signal_name.split('.')[0]
|
|
if struct_name not in self._signals_without_source:
|
|
self.info(
|
|
f'{__name__} - Found struct signal: {signal_name}, adding struct name only ({struct_name}). '
|
|
'Remaining members will be ignored.'
|
|
)
|
|
self._signals_without_source[struct_name] = signal_data
|
|
else:
|
|
self._signals_without_source[signal_name] = signal_data
|
|
|
|
self.info('%s - Getting CoreIDs', __name__)
|
|
self._core_ids = self.get_core_ids()
|
|
|
|
self.info('%s - Generating FileInfo', __name__)
|
|
self._file_info = self._gen_dummy_file_info()
|
|
|
|
self.info('%s - Getting DIDs', __name__)
|
|
self._dids = self.get_dids()
|
|
|
|
output_path = os.path.abspath(os.path.join('Models', 'CodeGenTmp'))
|
|
self.info('%s - Creating CodeGenTmp directory', __name__)
|
|
self.create_codegen_tmp_dir(output_path)
|
|
|
|
self.info('%s - Building AllSystemInfo', __name__)
|
|
self._build_all_system_info(output_path)
|
|
|
|
def create_codegen_tmp_dir(self, path):
|
|
"""Create CodeGenTmp directory if it does not exist.
|
|
|
|
Args:
|
|
path (str): directory to create.
|
|
"""
|
|
if not os.path.isdir(path):
|
|
os.mkdir(path)
|
|
else:
|
|
self.info('%s - Directory already exist at %s', __name__, path)
|
|
|
|
def _build_all_system_info(self, path):
|
|
"""Build AllSystemInfo.mat for DocGen compatibility.
|
|
|
|
Args:
|
|
path (str): directory path to place the output file.
|
|
"""
|
|
absolute_path = os.path.abspath(os.path.join(path, 'AllSystemInfo.mat'))
|
|
all_system_info = {
|
|
'SystemData': self._signals_without_source,
|
|
'CoreIDs': self._core_ids,
|
|
'FileInfo': self._file_info,
|
|
'DIDs': self._dids
|
|
}
|
|
|
|
all_system_info_scipy = {'AllSystemInfo': all_system_info}
|
|
savemat(absolute_path, all_system_info_scipy, long_field_names=True, do_compression=True)
|
|
self.info('%s - AllSystemInfo placed at %s', __name__, absolute_path)
|
|
|
|
def get_core_ids(self):
|
|
"""Get core IDs for specified project.
|
|
|
|
Returns:
|
|
dict: DID as a dict with the following format
|
|
{
|
|
"unit name" : {}
|
|
}
|
|
|
|
"""
|
|
result = {}
|
|
unit_configs = self.unit_cfg.get_per_unit_cfg()
|
|
for unit, configs in unit_configs.items():
|
|
result[unit] = deepcopy(configs['core'])
|
|
for unit, configs in result.items():
|
|
for core_id, core_id_dict in configs.items():
|
|
for identifier, data_dict in core_id_dict.items():
|
|
for tl_field, tl_data in data_dict.items():
|
|
# Turn lists into numpy.array, required to get matlab cell arrays instead of char arrays.
|
|
# char arrays make DocGen crash.
|
|
if isinstance(tl_data, list):
|
|
configs[core_id][identifier][tl_field] = array(tl_data, dtype=object)
|
|
else:
|
|
configs[core_id][identifier][tl_field] = tl_data
|
|
return result
|
|
|
|
def get_dids(self):
|
|
"""Get DIDs for specified project.
|
|
|
|
Returns:
|
|
dict: DID as a dict with the following format
|
|
{
|
|
"unit name" : {}
|
|
}
|
|
|
|
"""
|
|
result = {}
|
|
unit_configs = self.unit_cfg.get_per_unit_cfg()
|
|
for unit, configs in unit_configs.items():
|
|
dids_list = []
|
|
for signal_values in configs['dids'].values():
|
|
signal_values_allsysteminfo_keys = {
|
|
'sig_name': signal_values['name'],
|
|
'sig_desc': signal_values['description'],
|
|
'blk_name': signal_values['handle'],
|
|
'data_type': signal_values['type'],
|
|
'unit': signal_values['unit'],
|
|
'lsb': signal_values['lsb'],
|
|
'offset': signal_values['offset']
|
|
}
|
|
dids_list.append(signal_values_allsysteminfo_keys)
|
|
result.update({unit: dids_list})
|
|
|
|
return result
|
|
|
|
def _gen_dummy_file_info(self):
|
|
"""Generate dummy FileInfo struct for compatibility purposes."""
|
|
result = {}
|
|
for key in self._core_ids:
|
|
result.update({key: ''})
|
|
return result
|
|
|
|
def get_signals_without_source(self):
|
|
"""Get missing and unused signals from project configuration.
|
|
|
|
Returns:
|
|
dict: result with the following format
|
|
{
|
|
"signal_name" : "signal_type"
|
|
}
|
|
|
|
"""
|
|
prj_conf = self.signal_if.check_config()
|
|
result = self._get_external_signals(prj_conf)
|
|
temp_signals = self._get_internal_signals(prj_conf)
|
|
result = merge_dicts(result, temp_signals, merge_recursively=True)
|
|
return result
|
|
|
|
def _get_external_signals(self, prj_conf):
|
|
signals_conf = prj_conf['sigs']['ext']
|
|
return self._get_signals_by_types(signals_conf)
|
|
|
|
def _get_internal_signals(self, prj_conf):
|
|
result = {}
|
|
signals_conf = prj_conf['sigs']['int']
|
|
for sig_conf in signals_conf.values():
|
|
temp_signals = self._get_signals_by_types(sig_conf)
|
|
result = merge_dicts(result, temp_signals, merge_recursively=True)
|
|
return result
|
|
|
|
def _get_signals_by_types(self, signal_conf):
|
|
"""Get signals by multiple types and merge them into one dictionary, see _get_signals_by_type() for docs."""
|
|
result = {}
|
|
for signal_type in self._signal_types:
|
|
temp_signals = _get_signals_by_type(signal_conf, signal_type)
|
|
if temp_signals:
|
|
result = merge_dicts(result, temp_signals, merge_recursively=True)
|
|
return result
|