# Copyright 2024 Volvo Car Corporation # Licensed under Apache 2.0. """Module containing classes for the signal interfaces report.""" from collections import defaultdict from powertrain_build.html_report import HtmlReport class SigIfHtmlReport(HtmlReport): """Signal interface html report. Inherits class :doc:`HtmlReport `. """ __intro = """

Table of contents

  1. Introduction
  2. Detailed signal information
  3. Signal index

Introduction

This documents lists the signal interfaces.

""" __table_unused = """ """ __table_detailed_sig_desc = """
Variable Configurations
""" __table_detailed_sig_desc_ext = """
Unit Type Class Min Max Lsb Offset Configs
""" __table_detailed_sig_def = """
Unit Type Init Value Min Max Config Doc
""" __table_detailed_sig_cons = """
Defined in unit in projects
""" def __init__(self, build_cfg, unit_cfg, sig_if): """Initialize class instance. Args: build_cfg (BuildProjConfig): holds all the build configs unit_cfg (UnitConfigs): object holding all unit interfaces sig_if (SignalInterfaces): object holding signal interface information """ super().__init__('Signal interface report') self._build_cfg = build_cfg self._unit_cfg = unit_cfg self._sig_if = sig_if self._format_unit_data() def _gen_sigs_details(self): """Generate detailed signal information.""" out = '

Detailed Signal Information

\n' for signal in sorted(self._if.keys()): out += self._gen_sig_details(signal) return out def _gen_sig_details(self, signal): """Generate detailed signal information.""" out = f'

{signal}

\n' unit = tuple(self._if[signal]['def'].keys())[0] # ugly! use the first defining unit. # Check that it is a unit, and not from the inteface definition if unit[:2] == 'Vc': sig_def = defaultdict(lambda: '-', self._unit_cfg.get_per_unit_cfg()[unit]['outports'][signal]) out += f'

{sig_def["description"]}

' out += self.__table_detailed_sig_desc out += ' \n' out += f' \n' out += f' \n' out += f' \n' out += f' \n' out += f' \n' out += f' \n' out += f' \n' out += f' \n' out += ' \n' out += ' \n' out += '
Consumed by units in projects
{sig_def["unit"]}{sig_def["type"]}{sig_def["class"]}{sig_def["min"]}{sig_def["max"]}{sig_def["lsb"]}{sig_def["offset"]}{sig_def["configs"]}
\n

\n' else: sig_def = defaultdict(lambda: '-', self._sig_if.get_raw_io_cnfg()[unit][signal]) out += f'

{sig_def["description"]}

' out += self.__table_detailed_sig_desc_ext out += ' \n' out += f' {sig_def["unit"]}\n' out += f' {sig_def["type"]}\n' out += f' {sig_def["init"]}\n' out += f' {sig_def["min"]}\n' out += f' {sig_def["max"]}\n' out += f' {unit}\n' out += ' \n' out += ' \n' out += ' \n

\n' out += self.__table_detailed_sig_def for unit, prjs in self._if[signal]['def'].items(): out += ' \n' out += f' {unit}\n' out += f' {prjs}\n' out += ' \n' out += ' \n' out += ' \n' if 'consumers' in self._if[signal]: out += '

\n' out += self.__table_detailed_sig_cons for units, prjs in self._if[signal]['consumers'].items(): out += ' \n' out += f' {units}\n' out += f' {prjs}\n' out += ' \n' out += ' \n' out += ' \n' return out def _format_unit_data(self): """Format data per unit.""" self._if = {} prj_name = self._build_cfg.get_prj_config() # internal signals prj_cfg = self._unit_cfg.get_per_cfg_unit_cfg() ext_out_prj = self._sig_if.get_external_outputs() if 'outports' in prj_cfg: for sig, data in prj_cfg['outports'].items(): prod_unit = list(data.keys())[0] self._if.setdefault(sig, {}).setdefault('def', {}).setdefault(prod_unit, []).append(prj_name) cons_units = [] for sig_type, osig in ext_out_prj.items(): if sig in osig: cons_units = [sig_type] break if sig in prj_cfg['inports']: cons_units.extend(list(prj_cfg['inports'][sig].keys())) if cons_units: (self._if[sig].setdefault('consumers', {}) .setdefault(tuple(sorted(cons_units)), []) .append(prj_name)) # external signals prj_cfg = self._unit_cfg.get_per_cfg_unit_cfg() ext_in_prj = self._sig_if.get_external_inputs() for sig_type, osig in ext_in_prj.items(): for sig, data in osig.items(): self._if.setdefault(sig, {}).setdefault('def', {}).setdefault(sig_type, []).append(prj_name) if 'inports' in prj_cfg and sig in prj_cfg['inports']: (self._if[sig].setdefault('consumers', {}) .setdefault(tuple(sorted(prj_cfg['inports'][sig].keys())), []) .append(prj_name)) def _gen_signal_toc(self): """Generate a signal TOC for the unit with signal inconsistencies. Hyperlinks to more in depth signal information. """ out = '

Signal index

\n' for signal in sorted(self._if.keys()): out += f'
{signal}
\n' return out def gen_contents(self): """Generate report contents from the signal interfaces data. Overrides HtmlReport.gen_contents() """ html = [] html += self.__intro html += self._gen_sigs_details() html += self._gen_signal_toc() return ''.join(html)