from UniTAP.libs.lib_tsi.tsi_io import PortIO from .types import HdmiModeTx, FrlMode, _update_error_counters_tx from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_FRL_STATUS_R, TSI_HDTX_CONTROL_W, TSI_HDTX_STATUS_R, \ TSI_HDTX_SINK_STATUS_R, TSI_HDTX_LANES_ERR_COUNTERS_R, TSI_HDTX_HPD_STATUS_R from ctypes import c_uint32, c_uint64 class StatusTx: """ Class `StatusTx` describes information about HDMI link status on Source (TX - transmitter) side. Contains following info: - Set and get HDMI mode `hdmi_mode`. - Link Error counters `error_counters`. - Video status `video_status`. - Channel lock `channel_lock`. - HPD status `hpd_status`. """ def __init__(self, port_io: PortIO): self.__io = port_io def __read_status(self) -> int: return self.__io.get(TSI_HDTX_STATUS_R, c_uint32)[1] def __frl_status(self) -> FrlMode: return FrlMode(self.__io.get(TSI_HDTX_FRL_STATUS_R, c_uint32)[1] & 0xF) @property def video_status(self) -> bool: """ Returns current video status (video enable or not). Returns: object of bool type """ return (self.__read_status() & 0x2) != 0 @property def error_counters(self) -> list: """ Returns values of current errors on link. Returns: object of list type """ return _update_error_counters_tx(self.__io.get(TSI_HDTX_LANES_ERR_COUNTERS_R, c_uint64)[1]) @property def channel_lock(self) -> list: """ Returns channel lock states of current link. Returns: object of list type """ if self.__frl_status().Mode_Disable or self.hdmi_mode in [HdmiModeTx.HDMI_1_4, HdmiModeTx.HDMI_2_0]: return self.__update_channel_lock(self.__io.get(TSI_HDTX_SINK_STATUS_R, c_uint32)[1], self.hdmi_mode) else: return self.__update_channel_lock(self.__io.get(TSI_HDTX_FRL_STATUS_R, c_uint32)[1], self.hdmi_mode) @property def hpd_status(self) -> bool: """ Returns True if HDP is enabled, False - if not. Returns: object of bool type """ return (self.__io.get(TSI_HDTX_HPD_STATUS_R, c_uint32)[1] & 0x1) != 0 @property def hdmi_mode(self) -> HdmiModeTx: """ Returns current HDMI mode. Returns: object of `HdmiModeTx` type """ return HdmiModeTx((self.__read_status() >> 2) & 0x3) @hdmi_mode.setter def hdmi_mode(self, hdmi_mode: HdmiModeTx): """ Set new HDMI mode. Args: hdmi_mode (HdmiModeTx) """ self.__io.set(TSI_HDTX_CONTROL_W, hdmi_mode.value << 2, c_uint32) @property def available_link_rate(self) -> float: """ Returns available link rate. Returns: object of float type """ gbps = 1000000000 frl_status = self.__frl_status() if frl_status == FrlMode.Mode_Disable: link_rate = 3 * 6 * gbps elif frl_status == FrlMode.Mode_3lanes_3gbps: link_rate = 3 * 3 * gbps elif frl_status == FrlMode.Mode_3lanes_6gbps: link_rate = 3 * 6 * gbps elif frl_status == FrlMode.Mode_4lanes_6gbps: link_rate = 4 * 6 * gbps elif frl_status == FrlMode.Mode_4lanes_8gbps: link_rate = 4 * 8 * gbps elif frl_status == FrlMode.Mode_4lanes_10gbps: link_rate = 4 * 10 * gbps elif frl_status == FrlMode.Mode_4lanes_12gbps: link_rate = 4 * 12 * gbps else: link_rate = 0 return link_rate @staticmethod def __update_channel_lock(value, mode: HdmiModeTx) -> list: if mode != HdmiModeTx.HDMI_2_1: lane_0 = (value & (1 << 6)) != 0 lane_1 = (value & (1 << 7)) != 0 lane_2 = (value & (1 << 8)) != 0 lane_3 = False else: lane_0 = (((value >> 25) & 0xF) >> 0) & 0x1 != 0 lane_1 = (((value >> 25) & 0xF) >> 1) & 0x1 != 0 lane_2 = (((value >> 25) & 0xF) >> 2) & 0x1 != 0 lane_3 = (((value >> 25) & 0xF) >> 3) & 0x1 != 0 return [lane_0, lane_1, lane_2, lane_3] def __str__(self): return f"HDMI Mode: {self.hdmi_mode.name}\n" \ f"Channel Lock:\n{self.channel_lock}\n" \ f"Error Counters:\n{self.error_counters.__str__()}\n"