import copy from UniTAP.common import Timing from typing import Union, List, Optional class TimingManager: """ Class `TimingManager` allows working with all available predefined timings from device. You can get cvt timing by index `get_cvt`, dmt timing by index `get_dmt`, cta timing by index `get_cta`, get list of all timing `get_all` ot search timing by parameters `search`. """ def __init__(self, available_list: List[Timing]): self.__timings = available_list def get_cvt(self, index: int) -> Optional[Timing]: """ Returns cvt `Timing` by index. Args: index (int): CVT timing index Returns: timing (Timing | None) - type `Timing` if search was success, `None` if not. """ return copy.deepcopy(self.__search_by_standard_and_index(Timing.Standard.SD_CVT, index)) def get_dmt(self, index: int) -> Optional[Timing]: """ Returns cvt `Timing` by index. Args: index (int): DMT timing index Returns: timing (Timing | None) - type `Timing` if search was success, `None` if not. """ return copy.deepcopy(self.__search_by_standard_and_index(Timing.Standard.SD_DMT, index)) def get_cta(self, index: int) -> Optional[Timing]: """ Returns cvt `Timing` by index. Args: index (int): CTA timing index Returns: timing (Timing | None) - type `Timing` if search was success, `None` if not. """ return copy.deepcopy(self.__search_by_standard_and_index(Timing.Standard.SD_CTA, index)) def get_all(self) -> List[Timing]: """ Returns list of `Timing` objects. Returns: timing (list[Timing]) """ return copy.deepcopy(self.__timings) def get_by_list_index(self, index: int) -> Optional[Timing]: """ Returns `Timing` objects by index in timings list. Args: index (int) index of timing in list Returns: timing (Timing) """ if index < 0 or index >= len(self.__timings): raise ValueError(f"Incorrect index {index} of timings. Must be between 0 and {len(self.__timings)}") return self.__timings[index] def print_all(self) -> str: """ Print list of `Timing` objects. Returns: str """ return " \n".join(f'# {index} - ' f'{item.standard.name.replace("SD_", "") if item.standard != Timing.Standard.SD_NONE else ""} ' f'{item.hactive}x{item.vactive} @ {item.frame_rate / 1000}Hz' f'{self.__print_timing_id(item)}' for index, item in enumerate(self.__timings)) def search(self, h_active: Optional[int] = None, v_active: Optional[int] = None, f_rate: Optional[int] = None, standard: Optional[Timing.Standard] = None, rb: Optional[Timing.ReduceBlanking] = None) -> Optional[Timing]: """ Search timing by transferred parameters. Args: h_active (int | None): h active resolution of timing v_active (int | None): v active resolution of timing f_rate (int | None): frame rate of timing standard (Standard | None): timing `Standard` rb (ReduceBlanking | None): timing `ReduceBlanking` Returns: timing (Timing | None) - type `Timing` if search was success, `None` if not. """ for timing in self.__timings: if (timing.hactive == h_active or h_active is None) and (timing.vactive == v_active or v_active is None)\ and (f_rate is None or abs(timing.frame_rate - f_rate) <= 500) \ and (timing.standard == standard or standard is None) \ and (timing.reduce_blanking == rb or rb is None): return copy.deepcopy(timing) def __search_by_standard_and_index(self, sd: Timing.Standard, index: int) -> Union[Timing, None]: search_result = [ t for t in self.__timings if t.id == index and t.standard == sd ] return None if len(search_result) == 0 else search_result[0] @staticmethod def __print_timing_id(timing: Timing) -> str: if timing.standard == Timing.Standard.SD_CTA: return f" (VIC {timing.id})" elif timing.standard == Timing.Standard.SD_DMT: return f" (ID {hex(timing.id).replace('0x', '').upper()}h)" \ f"{f' [{timing.reduce_blanking.name}]' if timing.reduce_blanking != Timing.ReduceBlanking.RB_NONE else ''}" elif timing.standard == Timing.Standard.SD_CVT: return f" {f'[{timing.reduce_blanking.name}]' if timing.reduce_blanking != Timing.ReduceBlanking.RB_NONE else ''}" else: return ""