1.1.0版本
This commit is contained in:
246
UniTAP/dev/ports/modules/hdcp/hdcp_rx.py
Normal file
246
UniTAP/dev/ports/modules/hdcp/hdcp_rx.py
Normal file
@@ -0,0 +1,246 @@
|
||||
import warnings
|
||||
from typing import Optional, Union
|
||||
|
||||
from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol
|
||||
from .types import *
|
||||
from UniTAP.libs.lib_tsi.tsi import c_int
|
||||
|
||||
|
||||
class HdcpSinkStatus:
|
||||
|
||||
"""
|
||||
|
||||
Class `HdcpSinkStatus` contains information about HDCP 1.4 and 2.3 statuses.
|
||||
If you want to get object of one the status, use function `get`.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, port_io: PortIO, ci_status_control: int, caps_1x: HdcpHwSinkCaps, caps_2x: HdcpHwSinkCaps):
|
||||
super().__init__()
|
||||
self.__io = port_io
|
||||
self.__ci_status_control = ci_status_control
|
||||
self.__caps_1x = caps_1x
|
||||
self.__caps_2x = caps_2x
|
||||
|
||||
def get(self, hdcp_mode: Type[HdcpStatusType]) -> HdcpStatusType:
|
||||
"""
|
||||
|
||||
Returns one of possible HDCP Status Type:
|
||||
- Status1x (HDCP 1.4).
|
||||
- StatusRx2x (HDCP 2.3).
|
||||
|
||||
Object contains info about:
|
||||
- HDCP keys (HdcpSink1XKeys if HDCP type 1.4; HdcpSink2XKeys if HDCP type 2.3).
|
||||
- Active state (True or False).
|
||||
- Authenticated state (True or False).
|
||||
- Capable state (True or False).
|
||||
|
||||
Returns:
|
||||
object of `HdcpStatusType` (`Status1x` or `StatusRx2x`)
|
||||
"""
|
||||
if hdcp_mode not in [HdcpStatus.Status1x, HdcpStatus.StatusRx2x]:
|
||||
raise TypeError(f"Wrong type HDCP status, provided type {hdcp_mode}")
|
||||
|
||||
if hdcp_mode == HdcpStatus.Status1x:
|
||||
if self.__caps_1x.hw_supported:
|
||||
status_value = self.__read_status(HdcpMode.Mode1_4)
|
||||
status = HdcpStatus.Status1x()
|
||||
status.active = status_value & 1
|
||||
status.keys = HdcpSink1XKeys((status_value >> 1) & 3)
|
||||
status.capable = ((status_value >> 3) & 1)
|
||||
status.authenticated = ((status_value >> 4) & 1)
|
||||
return status
|
||||
else:
|
||||
warnings.warn(f"Not supported 'HDCP 1.4'")
|
||||
elif hdcp_mode == HdcpStatus.StatusRx2x:
|
||||
if self.__caps_2x.hw_supported:
|
||||
status_value = self.__read_status(HdcpMode.Mode2_3)
|
||||
status = HdcpStatus.StatusRx2x()
|
||||
if self.__io.protocol() == PortProtocol.HDMI:
|
||||
status.keys = HdcpSink2XKeys.Production if (status_value >> 9) & 1 else HdcpSink2XKeys.Unload
|
||||
else:
|
||||
if (status_value >> 11) & 1:
|
||||
status.keys = HdcpSink2XKeys.TestR1
|
||||
elif (status_value >> 13) & 1:
|
||||
status.keys = HdcpSink2XKeys.TestR2
|
||||
elif (status_value >> 9) & 1:
|
||||
status.keys = HdcpSink2XKeys.Production
|
||||
else:
|
||||
status.keys = HdcpSink2XKeys.Unload
|
||||
|
||||
status.active = (status_value >> 8) & 1
|
||||
status.capable = (status_value >> 10) & 1
|
||||
status.authenticated = (status_value >> 12) & 1
|
||||
return status
|
||||
else:
|
||||
warnings.warn(f"Not supported 'HDCP 2.3'")
|
||||
|
||||
def __read_status(self, mode: HdcpMode) -> int:
|
||||
if mode == HdcpMode.Mode1_4:
|
||||
return self.__io.get(TSI_HDCP_1X_STATUS_R, c_int)[1]
|
||||
else:
|
||||
return self.__io.get(self.__ci_status_control, c_int)[1]
|
||||
|
||||
|
||||
class HdcpSinkConfig:
|
||||
|
||||
"""
|
||||
Class `HdcpSinkConfig` contains information about HDCP 1.4 and 2.3 configurations.
|
||||
If you want to set configuration, use function `set`.
|
||||
If you want to get current config, use function `get`.
|
||||
"""
|
||||
|
||||
def __init__(self, port_io: PortIO, caps_1x: HdcpHwSinkCaps, caps_2x: HdcpHwSinkCaps, status: HdcpSinkStatus):
|
||||
self.__io = port_io
|
||||
self.__caps_1x = caps_1x
|
||||
self.__caps_2x = caps_2x
|
||||
self.__status = status
|
||||
|
||||
def set(self, config: HdcpRxConfigType):
|
||||
"""
|
||||
|
||||
This function is used to set the HDCP on Sink (RX - receiver) side.
|
||||
Possible to load HDCP keys and enable/disable HDCP.
|
||||
|
||||
Args:
|
||||
config (HdcpRxConfigType) - one of the available HDCP config type: Config1x (HDCP 1.4), Config2x (HDCP 2.3)
|
||||
"""
|
||||
if isinstance(config, HdcpRxConfig.Config1x):
|
||||
if self.__caps_1x.hw_supported:
|
||||
self.__load_keys(config.keys, HdcpMode.Mode1_4)
|
||||
self.__set_capable(config.capable, HdcpMode.Mode1_4)
|
||||
else:
|
||||
warnings.warn(f"Not supported 'HDCP 1.4'")
|
||||
elif isinstance(config, HdcpRxConfig.Config2x):
|
||||
if self.__caps_2x.hw_supported:
|
||||
self.__load_keys(config.keys, HdcpMode.Mode2_3)
|
||||
self.__set_capable(config.capable, HdcpMode.Mode2_3)
|
||||
else:
|
||||
warnings.warn(f"Not supported 'HDCP 2.3'")
|
||||
|
||||
def get(self, hdcp_mode: Type[HdcpRxConfigType]) -> HdcpRxConfigType:
|
||||
"""
|
||||
|
||||
This function is used to get current HDCP configuration on Sink (RX - receiver) side.
|
||||
|
||||
Returns:
|
||||
object of HdcpRxConfigType - one of the available HDCP config type: Config1x (HDCP 1.4), Config2x (HDCP 2.3)
|
||||
"""
|
||||
if hdcp_mode == HdcpRxConfig.Config1x:
|
||||
if self.__caps_1x.hw_supported:
|
||||
config = HdcpRxConfig.Config1x()
|
||||
status = self.__status.get(HdcpStatus.Status1x)
|
||||
config.keys = status.keys
|
||||
config.capable = status.capable
|
||||
return config
|
||||
else:
|
||||
warnings.warn(f"Not supported 'HDCP 1.4'")
|
||||
elif hdcp_mode == HdcpRxConfig.Config2x:
|
||||
if self.__caps_2x.hw_supported:
|
||||
config = HdcpRxConfig.Config2x()
|
||||
status = self.__status.get(HdcpStatus.StatusRx2x)
|
||||
config.keys = status.keys
|
||||
config.capable = status.capable
|
||||
return config
|
||||
else:
|
||||
warnings.warn(f"Not supported 'HDCP 2.3'")
|
||||
|
||||
def __load_keys(self, keys: Optional[Union[HdcpSink1XKeys, HdcpSink2XKeys]], hdcp_mode: HdcpMode):
|
||||
if keys is None:
|
||||
return
|
||||
if not self.__full_check(hdcp_mode):
|
||||
return
|
||||
|
||||
if hdcp_mode == HdcpMode.Mode1_4 and not isinstance(keys, HdcpSink1XKeys):
|
||||
raise TypeError("Was selected HDCP 1.4 mode. Need to use 'HdcpSink1XKeys' type.")
|
||||
elif hdcp_mode == HdcpMode.Mode1_4 and isinstance(keys, HdcpSink1XKeys):
|
||||
if keys == HdcpSink1XKeys.Production and not self.__caps_1x.production_keys_available:
|
||||
warnings.warn("Production keys is not hw supported. Please, select another keys.")
|
||||
elif keys == HdcpSink1XKeys.Test and not self.__caps_1x.test_keys_available:
|
||||
warnings.warn("Test keys is not hw supported. Please, select another keys.")
|
||||
elif hdcp_mode == HdcpMode.Mode2_3 and not isinstance(keys, HdcpSink2XKeys):
|
||||
raise TypeError("Was selected HDCP 2.3 mode. Need to use 'HdcpSink2XKeys' type.")
|
||||
elif hdcp_mode == HdcpMode.Mode2_3 and isinstance(keys, HdcpSink2XKeys):
|
||||
if keys == HdcpSink2XKeys.Production and not self.__caps_2x.production_keys_available:
|
||||
warnings.warn("Production keys is not hw supported. Please, select another keys.")
|
||||
|
||||
self.__io.set(TSI_HDCP_1X_COMMAND_W if hdcp_mode == HdcpMode.Mode1_4 else TSI_HDCP_2X_COMMAND_W, keys.value)
|
||||
|
||||
def __set_capable(self, value: Optional[bool], hdcp_mode: HdcpMode):
|
||||
if value is None:
|
||||
return
|
||||
if not self.__full_check(hdcp_mode):
|
||||
return
|
||||
|
||||
self.__io.set(TSI_HDCP_1X_COMMAND_W if hdcp_mode == HdcpMode.Mode1_4 else TSI_HDCP_2X_COMMAND_W,
|
||||
(H1_SINK_SET_CAPABLE if value else H1_SINK_CLEAR_CAPABLE)
|
||||
if hdcp_mode == HdcpMode.Mode1_4 else (H2_SINK_SET_CAPABLE if value else H2_SINK_CLEAR_CAPABLE))
|
||||
|
||||
def __full_check(self, hdcp_mode: HdcpMode) -> bool:
|
||||
if hdcp_mode == HdcpMode.Unknown:
|
||||
warnings.warn(f"Did not select HDCP mode. Please, select it from available variants: "
|
||||
f"{'HDCP 1.4 ' if self.__caps_1x.hw_supported else ''}"
|
||||
f"{'HDCP 2.3 ' if self.__caps_2x.hw_supported else ''}")
|
||||
return False
|
||||
|
||||
if not self.__availability_mode_check(hdcp_mode):
|
||||
warnings.warn(f"Selected HDCP mode is not HW supported. Please, select it from available variants: "
|
||||
f"{'HDCP 1.4 ' if self.__caps_1x.hw_supported else ''}"
|
||||
f"{'HDCP 2.3 ' if self.__caps_2x.hw_supported else ''}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __availability_mode_check(self, hdcp_mode: HdcpMode) -> bool:
|
||||
if hdcp_mode == HdcpMode.Mode1_4 and self.__caps_1x.hw_supported:
|
||||
return True
|
||||
elif hdcp_mode == HdcpMode.Mode2_3 and self.__caps_2x.hw_supported:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class HdcpSink:
|
||||
|
||||
"""
|
||||
Main class contains info of HDCP on Sink (RX - receiver) side.
|
||||
If you need to configurate HDCP, use `config` for getting object responsible for the configuration.
|
||||
If you need to read HDCP status, use `status` for getting object responsible for the reading current status.
|
||||
"""
|
||||
|
||||
def __init__(self, port_io: PortIO, ci_caps_control: int, ci_status_control: int):
|
||||
self.__io = port_io
|
||||
self.__hw_caps_1x = HdcpHwSinkCaps(self.__read_hw_caps(HdcpMode.Mode1_4), HdcpMode.Mode1_4)
|
||||
self.__hw_caps_2x = HdcpHwSinkCaps(self.__read_hw_caps(HdcpMode.Mode2_3, ci_caps_control), HdcpMode.Mode2_3)
|
||||
self.__status = HdcpSinkStatus(port_io, ci_status_control, self.__hw_caps_1x, self.__hw_caps_2x)
|
||||
self.__config = HdcpSinkConfig(port_io, self.__hw_caps_1x, self.__hw_caps_2x, self.__status)
|
||||
|
||||
@property
|
||||
def config(self) -> HdcpSinkConfig:
|
||||
"""
|
||||
|
||||
Should be used to configure HDCP on Sink (RX - receiver) role.
|
||||
|
||||
Returns:
|
||||
object of `HdcpSinkConfig`.
|
||||
"""
|
||||
return self.__config
|
||||
|
||||
@property
|
||||
def status(self) -> HdcpSinkStatus:
|
||||
"""
|
||||
|
||||
Should be used to read HDCP current status on Sink (RX - receiver) role.
|
||||
|
||||
Returns:
|
||||
object of `HdcpSinkStatus`.
|
||||
"""
|
||||
return self.__status
|
||||
|
||||
def __read_hw_caps(self, mode: HdcpMode, ci_caps_control: int = 0) -> int:
|
||||
if mode == HdcpMode.Mode1_4:
|
||||
return self.__io.get(TSI_HDCP_1X_STATUS_R, c_int)[1]
|
||||
elif mode == HdcpMode.Mode2_3:
|
||||
return self.__io.get(ci_caps_control, c_int)[1]
|
||||
else:
|
||||
return 0
|
||||
Reference in New Issue
Block a user