Compare commits

...

52 Commits

Author SHA1 Message Date
xinzhu.yin
4a2fa1daff 更新examples中的sdpg相关,可发送HDR信号 2026-07-08 10:51:07 +08:00
xinzhu.yin
32aaef1c0f 根据新版本调整set_pattern:0~65535 2026-07-07 18:59:44 +08:00
xinzhu.yin
9fa811a9eb 更新UCD-API库及文档 2026-07-02 17:16:18 +08:00
xinzhu.yin
a500751d85 修复UCD连接错误、修改色准计算方式、修改localdiming选择方块 2026-06-24 15:54:58 +08:00
xinzhu.yin
2d8d4119e3 继续优化UI加载速度 2026-06-22 10:52:51 +08:00
xinzhu.yin
92cba114a9 优化UI加载速度 2026-06-22 10:40:39 +08:00
xinzhu.yin
22f8b12690 修改UCD逻辑、添加关闭界面的x 2026-06-22 10:31:19 +08:00
xinzhu.yin
9c15751dd0 将 pattern 切换后的等待时间设置添加到pq_config 2026-06-16 15:56:49 +08:00
xinzhu.yin
3dd383b982 修改UCD连接需要重启错误 2026-06-16 14:31:00 +08:00
xinzhu.yin
dc096a9805 修复UCD调用异常、保存结果按钮异常 2026-06-15 10:58:51 +08:00
xinzhu.yin
c8ad244c45 修改SDR色准dE计算方式 2026-06-12 16:46:30 +08:00
xinzhu.yin
46a97d6ae7 优化ucd调用结构 2026-06-11 16:29:36 +08:00
xinzhu.yin
cc7218411c 重构UCD模块 2026-06-11 15:53:41 +08:00
xinzhu.yin
38222ff002 修改UI细节错误 2026-06-10 11:39:08 +08:00
xinzhu.yin
3206079c63 修复色准结果图偏移 2026-06-09 17:15:54 +08:00
xinzhu.yin
25be4b7f4a 修复日志切换错误 2026-06-09 15:40:44 +08:00
xinzhu.yin
f33984affa 修复LocalDimming测试错误 2026-06-09 15:22:20 +08:00
xinzhu.yin
8916f2fff0 修改SDR色准深色异常、修改保存结果深色模式异常 2026-06-09 11:02:55 +08:00
xinzhu.yin
9ad9cf9aa0 添加手动设置窗口亮度、曲线图生成 2026-06-08 11:39:54 +08:00
xinzhu.yin
e4890d9d8d 添加瞬时峰值测试 2026-06-08 11:14:12 +08:00
xinzhu.yin
febbb28a4c 修改部分UI、修改module中心点设定、添加单独连接 2026-06-08 11:03:10 +08:00
xinzhu.yin
e9a591bf6e 修改深色模式下结果图片显示异常 2026-06-05 16:58:46 +08:00
xinzhu.yin
49d82da8b9 修改Calman灰阶中结果图显示、修改UI主题样式应用 2026-06-04 10:36:15 +08:00
xinzhu.yin
3aa975c4d3 修改calman灰阶点击异常、修改色准结果显示异常 2026-06-02 17:34:46 +08:00
xinzhu.yin
85ac47e8de 修改AI生图接口、修改设备连接UI、修改LocalDimming逻辑和UI 2026-05-29 14:40:39 +08:00
xinzhu.yin
21455f3916 修复日志模块深色显示不正确 2026-05-29 08:32:21 +08:00
xinzhu.yin
4498ec501e 继续优化AI图片列表UI显示 2026-05-28 17:34:51 +08:00
xinzhu.yin
64764524aa 添加Local Dimming图像 2026-05-28 17:02:22 +08:00
xinzhu.yin
c173e2338d 继续优化深色模式显示 2026-05-28 16:41:52 +08:00
xinzhu.yin
cf724d60d7 添加深色模式 2026-05-28 10:50:52 +08:00
xinzhu.yin
f8f2d471e5 屏模组添加colorinfo设置、修改配置项UI样式 2026-05-28 10:20:17 +08:00
xinzhu.yin
c63b9ef615 继续优化色准测试结果显示模块 2026-05-27 16:26:19 +08:00
xinzhu.yin
59c9424218 修改色准测试结果显示 2026-05-27 14:58:44 +08:00
xinzhu.yin
dff4e0df4d 修改引用逻辑、新增Pattern更改界面、新增Calman灰阶界面 2026-05-27 11:26:28 +08:00
xinzhu.yin
a903c17cb3 修复切换config后异常显示pattern问题 2026-05-24 11:37:45 +08:00
xinzhu.yin
29f7d39fe9 删除所有外部旧引用 2026-05-24 11:21:30 +08:00
xinzhu.yin
1b66fff35b 迁移 GUI 调用点 2026-05-24 11:02:37 +08:00
xinzhu.yin
a855ba7157 Merge branch 'master' of http://szmoka.tclking.com:8081/Windows.Python/pqAutomationApp 2026-05-24 10:49:40 +08:00
xinzhu.yin
3ce1574320 新建UCD模块DDD重构文件 2026-05-24 10:49:28 +08:00
23a01be699 Merge branch 'master' of http://thinking.zicp.io:3000/MOKA/pqAutomationApp 2026-05-22 14:15:40 +08:00
7e1136926e 1、实例缺少的库
2、不依赖app_version.py
2026-05-22 14:13:54 +08:00
xinzhu.yin
9b2bc44e17 添加信号格式修改 2026-05-22 11:31:36 +08:00
xinzhu.yin
c42287b7d7 重构pq_config、修改切换面板清空旧逻辑 2026-05-19 11:50:53 +08:00
xinzhu.yin
405b6047b9 色域结果多图保存、更换AI生图服务器接口 2026-05-19 10:06:02 +08:00
xinzhu.yin
d7495734a5 修改色域画图及重绘方式 2026-05-18 15:57:11 +08:00
xinzhu.yin
9371defb6e 添加UCD-API文档 2026-05-13 17:18:50 +08:00
xinzhu.yin
0513f810bd 修改摸底测试功能、修改pattern控制逻辑 2026-05-13 17:17:13 +08:00
xinzhu.yin
9a52e34f2b 添加pantone测试模版文件 2026-05-07 14:12:01 +08:00
xinzhu.yin
3c519dde20 添加Pantone 认证摸底测试面板UI 2026-05-07 11:21:17 +08:00
xinzhu.yin
7bc8fd8557 修改AI生图相关日志信息 2026-04-29 19:10:27 +08:00
xinzhu.yin
afd83448ed 修改日志结构 2026-04-29 16:43:31 +08:00
xinzhu.yin
377bba2a0b 添加AI图像生成接口、修改相关界面 2026-04-29 15:25:58 +08:00
348 changed files with 118839 additions and 5782 deletions

6
.gitignore vendored
View File

@@ -18,8 +18,8 @@ dist/
*.log *.log
*.tmp *.tmp
*.bak *.bak
*.csv /*.csv
*.xlsx /*.xlsx
# IDE files # IDE files
.vscode/ .vscode/
@@ -32,3 +32,5 @@ Desktop.ini
# Local configuration overrides # Local configuration overrides
settings/*.local.json settings/*.local.json
settings/ settings/
log/
results/

View File

@@ -19,6 +19,7 @@ class AudioFormat(IntEnum):
- PCMAudio. - PCMAudio.
""" """
Unknown = -1 Unknown = -1
Compressed = 0x0
L_PCM = 0xFFFF L_PCM = 0xFFFF
@@ -218,7 +219,7 @@ class AudioFrameData:
Args: Args:
sample_format (int) - must be more than 0 sample_format (int) - must be more than 0
""" """
if sample_format <= 0: if sample_format < 0:
raise ValueError(f"Sample format must be more than 0.") raise ValueError(f"Sample format must be more than 0.")
self.__sample_format = AudioFormat(sample_format) self.__sample_format = AudioFormat(sample_format)

View File

@@ -1,6 +1,7 @@
from .ports import DPRX, DPTX, HDRX, HDTX, PDC340 from .ports import DPRX, DPTX, HDRX, HDRX_eARC, HDTX, PDC340
from .modules import MemoryManager, Capturer, DUTTests from .modules import MemoryManager, Capturer, DUTTests
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO, PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortProtocol
from .dev_base_roles import DevBase, DeviceIO
class UCD340: class UCD340:
@@ -9,7 +10,8 @@ class UCD340:
- 'USB-C, DP Alt Mode Reference Sink' `USBCSink` - 'USB-C, DP Alt Mode Reference Sink' `USBCSink`
- 'USB-C, DP Alt Mode Reference Source' `USBCSource`. - 'USB-C, DP Alt Mode Reference Source' `USBCSource`.
""" """
class USBCSink:
class USBCSink(DevBase):
""" """
Class `USBCSink` contains information of available functionality modules for role USB-C Sink (RX - receiver) Class `USBCSink` contains information of available functionality modules for role USB-C Sink (RX - receiver)
role: role:
@@ -17,7 +19,9 @@ class UCD340:
- `DUTTests`. - `DUTTests`.
- `PDC`. - `PDC`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__port_io = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC) self.__port_io = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
self.__dprx = DPRX(self.__port_io, memory_manager, capturer) self.__dprx = DPRX(self.__port_io, memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -63,7 +67,7 @@ class UCD340:
""" """
return list(UCD340.ROLE_DICT.keys())[list(UCD340.ROLE_DICT.values()).index(type(self))] return list(UCD340.ROLE_DICT.keys())[list(UCD340.ROLE_DICT.values()).index(type(self))]
class USBCSource: class USBCSource(DevBase):
""" """
Class `USBCSource` contains information of available functionality modules for role USB-C Source Class `USBCSource` contains information of available functionality modules for role USB-C Source
(TX - transmitter) role: (TX - transmitter) role:
@@ -71,7 +75,9 @@ class UCD340:
- `DUTTests`. - `DUTTests`.
- `PDC`. - `PDC`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__port_io = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC) self.__port_io = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
self.__dptx = DPTX(self.__port_io, memory_manager, capturer) self.__dptx = DPTX(self.__port_io, memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -140,13 +146,16 @@ class UCD323:
- 'HDMI Reference Sink (HDCP 2.3)' `HDMISink` - 'HDMI Reference Sink (HDCP 2.3)' `HDMISink`
- 'HDMI Reference Source (HDCP 2.3)' `HDMISource` - 'HDMI Reference Source (HDCP 2.3)' `HDMISource`
""" """
class DPSink:
class DPSink(DevBase):
""" """
Class `DPSink` contains information of available functionality modules for role DP Sink (RX - receiver) role: Class `DPSink` contains information of available functionality modules for role DP Sink (RX - receiver) role:
- `DPRX`. - `DPRX`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dprx = DPRX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dprx = DPRX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -180,14 +189,16 @@ class UCD323:
""" """
return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))] return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))]
class DPSource: class DPSource(DevBase):
""" """
Class `DPSink` contains information of available functionality modules for role DP Source (TX - transmitter) Class `DPSink` contains information of available functionality modules for role DP Source (TX - transmitter)
role: role:
- `DPTX`. - `DPTX`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dptx = DPTX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dptx = DPTX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -221,19 +232,21 @@ class UCD323:
""" """
return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))] return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))]
class HDMISink: class HDMISink(DevBase):
""" """
Class `HDMISink` contains information of available functionality modules for role HDMI Sink (RX - receiver) Class `HDMISink` contains information of available functionality modules for role HDMI Sink (RX - receiver)
role: role:
- `HDRX`. - `HDRX`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
self.__hdrx = HDRX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer) super().__init__(dev_io)
self.__hdrx = HDRX_eARC(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@property @property
def hdrx(self) -> HDRX: def hdrx(self) -> HDRX_eARC:
""" """
Returns HDMI Sink (RX - receiver) role. Returns HDMI Sink (RX - receiver) role.
@@ -262,14 +275,16 @@ class UCD323:
""" """
return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))] return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))]
class HDMISource: class HDMISource(DevBase):
""" """
Class `HDMISource` contains information of available functionality modules for role HDMI Source Class `HDMISource` contains information of available functionality modules for role HDMI Source
(TX - transmitter) role: (TX - transmitter) role:
- `HDTX`. - `HDTX`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__hdtx = HDTX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer) self.__hdtx = HDTX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -303,11 +318,55 @@ class UCD323:
""" """
return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))] return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))]
class HDMISinkEARC(DevBase):
"""
Class `HDMISink` contains information of available functionality modules for role HDMI Sink (RX - receiver)
role:
- `HDRX`.
- `DUTTests`.
"""
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__hdrx = HDRX_eARC(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io)
@property
def hdrx(self) -> HDRX_eARC:
"""
Returns HDMI Sink (RX - receiver) role.
Returns:
object of HDRX type.
"""
return self.__hdrx
@property
def dut_tests(self) -> DUTTests:
"""
Returns DUT Test module.
Returns:
object of DUTTests type.
"""
return self.__dut_tests
@property
def name(self) -> str:
"""
Returns name of role.
Returns:
object of str type.
"""
return list(UCD323.ROLE_DICT.keys())[list(UCD323.ROLE_DICT.values()).index(type(self))]
ROLE_DICT = { ROLE_DICT = {
"DisplayPort Reference Sink (SST, HDCP 2.3)": DPSink, "DisplayPort Reference Sink (SST, HDCP 2.3)": DPSink,
"DisplayPort Reference Source (SST, HDCP 2.3)": DPSource, "DisplayPort Reference Source (SST, HDCP 2.3)": DPSource,
"HDMI Reference Sink (HDCP 2.3)": HDMISink, "HDMI Reference Sink (HDCP 2.3)": HDMISink,
"HDMI Reference Source (HDCP 2.3)": HDMISource, "HDMI Reference Source (HDCP 2.3)": HDMISource,
"HDMI Reference Sink (eARC)": HDMISinkEARC,
} }
@@ -317,13 +376,16 @@ class UCD301:
- 'DisplayPort Reference Sink (SST, HDCP 2.3)' `DPSink` - 'DisplayPort Reference Sink (SST, HDCP 2.3)' `DPSink`
- 'HDMI Reference Sink (HDCP 2.3)' `HDMISink` - 'HDMI Reference Sink (HDCP 2.3)' `HDMISink`
""" """
class DPSink:
class DPSink(DevBase):
""" """
Class `DPSink` contains information of available functionality modules for role DP Sink (RX - receiver) role: Class `DPSink` contains information of available functionality modules for role DP Sink (RX - receiver) role:
- `DPRX`. - `DPRX`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dprx = DPRX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dprx = DPRX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -357,14 +419,16 @@ class UCD301:
""" """
return list(UCD301.ROLE_DICT.keys())[list(UCD301.ROLE_DICT.values()).index(type(self))] return list(UCD301.ROLE_DICT.keys())[list(UCD301.ROLE_DICT.values()).index(type(self))]
class HDMISink: class HDMISink(DevBase):
""" """
Class `HDMISink` contains information of available functionality modules for role HDMI Sink (RX - receiver) Class `HDMISink` contains information of available functionality modules for role HDMI Sink (RX - receiver)
role: role:
- `HDRX`. - `HDRX`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__hdrx = HDRX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer) self.__hdrx = HDRX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -398,7 +462,7 @@ class UCD301:
""" """
return list(UCD301.ROLE_DICT.keys())[list(UCD301.ROLE_DICT.values()).index(type(self))] return list(UCD301.ROLE_DICT.keys())[list(UCD301.ROLE_DICT.values()).index(type(self))]
class DPSinkHDMISink: class DPSinkHDMISink(DevBase):
""" """
Class `DPSinkHDMISink` contains information of available functionality modules for role DP and HDMI Sink Class `DPSinkHDMISink` contains information of available functionality modules for role DP and HDMI Sink
(RX - receiver) role: (RX - receiver) role:
@@ -408,6 +472,7 @@ class UCD301:
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dprx = DPRX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dprx = DPRX(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__hdrx = HDRX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer) self.__hdrx = HDRX(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)

View File

@@ -1,6 +1,7 @@
from UniTAP.dev.ports import DPRX4xx, DPTX4xx, HDRX4xx, HDTX4xx, PDC424 from UniTAP.dev.ports import DPRX4xx, DPTX4xx, HDRX4xx, HDTX4xx, PDC424
from .modules import MemoryManager, Capturer, DUTTests from .modules import MemoryManager, Capturer, DUTTests
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO, PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortProtocol
from .dev_base_roles import DevBase, DeviceIO
class UCD400: class UCD400:
@@ -8,7 +9,7 @@ class UCD400:
Class `UCD400` describes of device UCD-400. Device has one possible role: Class `UCD400` describes of device UCD-400. Device has one possible role:
- 'DisplayPort Source and Sink' `DPSourceDPSink` - 'DisplayPort Source and Sink' `DPSourceDPSink`
""" """
class DPSourceDPSink: class DPSourceDPSink(DevBase):
""" """
Class `DPSourceDPSink` contains information of available functionality modules for role DP Sink Class `DPSourceDPSink` contains information of available functionality modules for role DP Sink
(RX - receiver) and DP Source (TX - transmitter) roles: (RX - receiver) and DP Source (TX - transmitter) roles:
@@ -17,7 +18,7 @@ class UCD400:
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__() super().__init__(dev_io)
self.__dprx = DPRX4xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dprx = DPRX4xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dptx = DPTX4xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer) self.__dptx = DPTX4xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -72,7 +73,7 @@ class UCD422:
Class `UCD422` describes of device UCD-422. Device has one possible role: Class `UCD422` describes of device UCD-422. Device has one possible role:
- 'HDMI Source and Sink' `HDMISourceHDMISink` - 'HDMI Source and Sink' `HDMISourceHDMISink`
""" """
class HDMISourceHDMISink: class HDMISourceHDMISink(DevBase):
""" """
Class `DPSourceDPSink` contains information of available functionality modules for role HDMI Sink Class `DPSourceDPSink` contains information of available functionality modules for role HDMI Sink
(RX - receiver) and HDMI Source (TX - transmitter) roles: (RX - receiver) and HDMI Source (TX - transmitter) roles:
@@ -81,7 +82,7 @@ class UCD422:
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__() super().__init__(dev_io)
self.__hdrx = HDRX4xx(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer) self.__hdrx = HDRX4xx(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__hdtx = HDTX4xx(dev_io.create_port_io(1, PortProtocol.HDMI), memory_manager, capturer) self.__hdtx = HDTX4xx(dev_io.create_port_io(1, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -136,7 +137,7 @@ class UCD424:
Class `UCD424` describes of device UCD-424. Device has one possible role: Class `UCD424` describes of device UCD-424. Device has one possible role:
- 'USB-C Source and Sink' `USBCSourceUSBCSink`. - 'USB-C Source and Sink' `USBCSourceUSBCSink`.
""" """
class USBCSourceUSBCSink: class USBCSourceUSBCSink(DevBase):
""" """
Class `DPSourceDPSink` contains information of available functionality modules for role HDMI Sink Class `DPSourceDPSink` contains information of available functionality modules for role HDMI Sink
(RX - receiver) and HDMI Source (TX - transmitter) roles: (RX - receiver) and HDMI Source (TX - transmitter) roles:
@@ -146,7 +147,7 @@ class UCD424:
- `PDC`. - `PDC`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__() super().__init__(dev_io)
self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC) self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC) self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC)
self.__dprx = DPRX4xx(self.__port_rx, memory_manager, capturer) self.__dprx = DPRX4xx(self.__port_rx, memory_manager, capturer)
@@ -218,3 +219,237 @@ class UCD424:
ROLE_DICT = { ROLE_DICT = {
"USB-C Source and Sink": USBCSourceUSBCSink "USB-C Source and Sink": USBCSourceUSBCSink
} }
class UCD451:
"""
Class `UCD451` describes of device UCD-451. Device has one possible role:
- 'DP Source' `DPSource`
"""
class DPSource(DevBase):
"""
Class `DPSourceDPSink` contains information of available functionality modules for role
DP Source (TX - transmitter) roles:
- `DPTX4xx`.
- `DUTTests`.
"""
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dptx = DPTX4xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io)
@property
def dptx(self) -> DPTX4xx:
"""
Returns DP Source (TX - transmitter) role.
Returns:
object of DPTX4xx type.
"""
return self.__dptx
@property
def dut_tests(self) -> DUTTests:
"""
Returns DUT Test module.
Returns:
object of DUTTests type.
"""
return self.__dut_tests
@property
def name(self) -> str:
"""
Returns name of role.
Returns:
object of str type.
"""
return list(UCD451.ROLE_DICT.keys())[list(UCD451.ROLE_DICT.values()).index(type(self))]
ROLE_DICT = {
"DisplayPort Source": DPSource
}
class UCD461:
"""
Class `UCD461` describes of device UCD-461. Device has one possible role:
- 'DisplayPort Source and Sink' `DPSourceDPSink`
"""
class DPSourceDPSink(DevBase):
"""
Class `DPSourceDPSink` contains information of available functionality modules for role DP Sink
(RX - receiver) and DP Source (TX - transmitter) roles:
- `DPRX4xx`.
- `DPTX4xx`.
- `DUTTests`.
"""
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dprx = DPRX4xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dptx = DPTX4xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io)
@property
def dprx(self) -> DPRX4xx:
"""
Returns DP Sink (RX - receiver) role.
Returns:
object of DPRX4xx type.
"""
return self.__dprx
@property
def dptx(self) -> DPTX4xx:
"""
Returns DP Source (TX - transmitter) role.
Returns:
object of DPTX4xx type.
"""
return self.__dptx
@property
def dut_tests(self) -> DUTTests:
"""
Returns DUT Test module.
Returns:
object of DUTTests type.
"""
return self.__dut_tests
@property
def name(self) -> str:
"""
Returns name of role.
Returns:
object of str type.
"""
return list(UCD461.ROLE_DICT.keys())[list(UCD461.ROLE_DICT.values()).index(type(self))]
ROLE_DICT = {
"DisplayPort Source and Sink": DPSourceDPSink
}
class UCD452:
"""
Class `UCD452` describes of device UCD-452. Device has one possible role:
- 'HDMI Source' `HDMISource`
"""
class HDMISource(DevBase):
"""
Class `DPSourceDPSink` contains information of available functionality modules for role
HDMI Source (TX - transmitter) roles:
- `HDTX4xx`.
- `DUTTests`.
"""
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__hdtx = HDTX4xx(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io)
@property
def hdtx(self) -> HDTX4xx:
"""
Returns HDMI Source (TX - transmitter) role.
Returns:
object of HDTX4xx type.
"""
return self.__hdtx
@property
def dut_tests(self) -> DUTTests:
"""
Returns DUT Test module.
Returns:
object of DUTTests type.
"""
return self.__dut_tests
@property
def name(self) -> str:
"""
Returns name of role.
Returns:
object of str type.
"""
return list(UCD452.ROLE_DICT.keys())[list(UCD452.ROLE_DICT.values()).index(type(self))]
ROLE_DICT = {
"HDMI Source": HDMISource
}
class UCD462:
"""
Class `UCD462` describes of device UCD-462. Device has one possible role:
- 'HDMI Source and Sink' `HDMISourceHDMISink`
"""
class HDMISourceHDMISink(DevBase):
"""
Class `DPSourceDPSink` contains information of available functionality modules for role HDMI Sink
(RX - receiver) and HDMI Source (TX - transmitter) roles:
- `HDRX4xx`.
- `HDTX4xx`.
- `DUTTests`.
"""
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__hdrx = HDRX4xx(dev_io.create_port_io(0, PortProtocol.HDMI), memory_manager, capturer)
self.__hdtx = HDTX4xx(dev_io.create_port_io(1, PortProtocol.HDMI), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io)
@property
def hdtx(self) -> HDTX4xx:
"""
Returns HDMI Source (TX - transmitter) role.
Returns:
object of HDTX4xx type.
"""
return self.__hdtx
@property
def hdrx(self) -> HDRX4xx:
"""
Returns HDMI Sink (RX - receiver) role.
Returns:
object of HDRX4xx type.
"""
return self.__hdrx
@property
def dut_tests(self) -> DUTTests:
"""
Returns DUT Test module.
Returns:
object of DUTTests type.
"""
return self.__dut_tests
@property
def name(self) -> str:
"""
Returns name of role.
Returns:
object of str type.
"""
return list(UCD462.ROLE_DICT.keys())[list(UCD462.ROLE_DICT.values()).index(type(self))]
ROLE_DICT = {
"HDMI Source and Sink": HDMISourceHDMISink
}

View File

@@ -1,6 +1,7 @@
from UniTAP.dev.ports import DPRX5xx, DPTX5xx, PDC500 from UniTAP.dev.ports import DPRX5xx, DPTX5xx, PDC500
from .modules import MemoryManager, Capturer, DUTTests from .modules import MemoryManager, Capturer, DUTTests
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO, PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortProtocol
from .dev_base_roles import DevBase, DeviceIO
class UCD500: class UCD500:
@@ -11,7 +12,8 @@ class UCD500:
- 'DisplayPort Sink and USB-C, DP Alt Mode Source' `USBCSourceDPSink`. - 'DisplayPort Sink and USB-C, DP Alt Mode Source' `USBCSourceDPSink`.
- 'USB-C, DP Alt Mode Source and Sink' `USBCSourceUSBCSink`. - 'USB-C, DP Alt Mode Source and Sink' `USBCSourceUSBCSink`.
""" """
class DPSourceDPSink:
class DPSourceDPSink(DevBase):
""" """
Class `DPSourceDPSink` contains information of available functionality modules for role DP Sink Class `DPSourceDPSink` contains information of available functionality modules for role DP Sink
(RX - receiver) and DP Source (TX - transmitter) roles: (RX - receiver) and DP Source (TX - transmitter) roles:
@@ -19,7 +21,9 @@ class UCD500:
- `DPTX5xx`. - `DPTX5xx`.
- `DUTTests`. - `DUTTests`.
""" """
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__dprx = DPRX5xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dprx = DPRX5xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dptx = DPTX5xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer) self.__dptx = DPTX5xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dut_tests = DUTTests(dev_io) self.__dut_tests = DUTTests(dev_io)
@@ -64,8 +68,9 @@ class UCD500:
""" """
return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))] return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]
class DPSourceUSBCSink: class DPSourceUSBCSink(DevBase):
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC) self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
self.__dptx = DPTX5xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer) self.__dptx = DPTX5xx(dev_io.create_port_io(1, PortProtocol.DisplayPort), memory_manager, capturer)
self.__dprx = DPRX5xx(self.__port_rx, memory_manager, capturer) self.__dprx = DPRX5xx(self.__port_rx, memory_manager, capturer)
@@ -122,8 +127,9 @@ class UCD500:
""" """
return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))] return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]
class USBCSourceDPSink: class USBCSourceDPSink(DevBase):
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC) self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC)
self.__dptx = DPTX5xx(self.__port_tx, memory_manager, capturer) self.__dptx = DPTX5xx(self.__port_tx, memory_manager, capturer)
self.__dprx = DPRX5xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer) self.__dprx = DPRX5xx(dev_io.create_port_io(0, PortProtocol.DisplayPort), memory_manager, capturer)
@@ -180,8 +186,9 @@ class UCD500:
""" """
return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))] return list(UCD500.ROLE_DICT.keys())[list(UCD500.ROLE_DICT.values()).index(type(self))]
class USBCSourceUSBCSink: class USBCSourceUSBCSink(DevBase):
def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, dev_io: DeviceIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(dev_io)
self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC) self.__port_rx = dev_io.create_port_io(0, PortProtocol.DisplayPortThrowUSBC)
self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC) self.__port_tx = dev_io.create_port_io(1, PortProtocol.DisplayPortThrowUSBC)
self.__dprx = DPRX5xx(self.__port_rx, memory_manager, capturer) self.__dprx = DPRX5xx(self.__port_rx, memory_manager, capturer)

View File

@@ -0,0 +1,28 @@
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO
class DevBase:
"""
Class `DevBase`.
"""
def __init__(self, dev_io: DeviceIO):
self.__dev_io = dev_io
def is_fw_update_available(self) -> bool:
"""
Checks if there is a firmware update available for the current device.
Returns:
object of bool type.
"""
return self.__dev_io.is_fw_update_available()
def get_fw_update_info(self) -> str:
"""
Returns a list of modules to update on the current device and also displays the current version.
Returns:
object of str type.
"""
return self.__dev_io.get_fw_update_info()

View File

@@ -3,7 +3,7 @@ import weakref
from typing import TypeVar, Type, List from typing import TypeVar, Type, List
from .dev_5xx_roles import UCD500 from .dev_5xx_roles import UCD500
from .dev_4xx_roles import UCD400, UCD422, UCD424 from .dev_4xx_roles import UCD400, UCD422, UCD424, UCD451, UCD452, UCD461, UCD462
from .dev_3xx_roles import UCD240, UCD340, UCD323, UCD301 from .dev_3xx_roles import UCD240, UCD340, UCD323, UCD301
from .modules import * from .modules import *
@@ -16,6 +16,11 @@ RoleType = TypeVar("RoleType",
UCD500.USBCSourceUSBCSink, UCD500.USBCSourceUSBCSink,
UCD500.USBCSourceDPSink, UCD500.USBCSourceDPSink,
UCD462.HDMISourceHDMISink,
UCD461.DPSourceDPSink,
UCD452.HDMISource,
UCD451.DPSource,
UCD424.USBCSourceUSBCSink, UCD424.USBCSourceUSBCSink,
UCD422.HDMISourceHDMISink, UCD422.HDMISourceHDMISink,
UCD400.DPSourceDPSink, UCD400.DPSourceDPSink,
@@ -26,6 +31,7 @@ RoleType = TypeVar("RoleType",
UCD323.DPSink, UCD323.DPSink,
UCD323.DPSource, UCD323.DPSource,
UCD323.HDMISink, UCD323.HDMISink,
UCD323.HDMISinkEARC,
UCD323.HDMISource, UCD323.HDMISource,
UCD301.DPSink, UCD301.DPSink,
@@ -36,6 +42,10 @@ RoleType = TypeVar("RoleType",
MODEL_TO_CLASS = { MODEL_TO_CLASS = {
"UCD-500": UCD500, "UCD-500": UCD500,
"UCD-462": UCD462,
"UCD-461": UCD461,
"UCD-452": UCD452,
"UCD-451": UCD451,
"UCD-424": UCD424, "UCD-424": UCD424,
"UCD-422": UCD422, "UCD-422": UCD422,
"UCD-400": UCD400, "UCD-400": UCD400,
@@ -90,9 +100,10 @@ class TSIDevice:
def __define_internal_handler(self, role, role_type): def __define_internal_handler(self, role, role_type):
if role_type in [UCD500.DPSourceUSBCSink, UCD500.DPSourceDPSink, UCD500.USBCSourceUSBCSink, if role_type in [UCD500.DPSourceUSBCSink, UCD500.DPSourceDPSink, UCD500.USBCSourceUSBCSink,
UCD500.USBCSourceDPSink, UCD424.USBCSourceUSBCSink, UCD400.DPSourceDPSink]: UCD500.USBCSourceDPSink, UCD424.USBCSourceUSBCSink, UCD400.DPSourceDPSink,
UCD461.DPSourceDPSink]:
self.opf_handler._set_roles(role.dptx, role.dprx) self.opf_handler._set_roles(role.dptx, role.dprx)
elif role_type in [UCD422.HDMISourceHDMISink]: elif role_type in [UCD422.HDMISourceHDMISink, UCD462.HDMISourceHDMISink]:
self.opf_handler._set_roles(role.hdtx, role.hdrx) self.opf_handler._set_roles(role.hdtx, role.hdrx)
def select_role(self, role_type: Type[RoleType]) -> RoleType: def select_role(self, role_type: Type[RoleType]) -> RoleType:
@@ -152,3 +163,28 @@ class TSIDevice:
@property @property
def _terminal(self) -> Terminal: def _terminal(self) -> Terminal:
return self.__terminal return self.__terminal
def reset(self):
"""
Reset Device NIOS FPGA.
"""
role = self.__io.get_role_type()
if role is None:
logging.error("[UniTAP] Cannot reset device without selected role")
return
if role not in (UCD500.DPSourceUSBCSink,
UCD500.DPSourceDPSink,
UCD500.USBCSourceUSBCSink,
UCD500.USBCSourceDPSink):
logging.error(f"[UniTAP] Reset functionality is not supported for selected role {role}.")
return
self.__io.reset()
def close(self):
"""
Close Device (only with using TSI function `TSIX_DEV_CloseDevice`)
"""
self.__io.close()

View File

@@ -1,8 +1,10 @@
import time import time
from typing import Union from ctypes import c_int, c_uint, c_int32
from typing import Union, List
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO from UniTAP.libs.lib_tsi.tsi_io import DeviceIO
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi_types as ci
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from UniTAP.dev.modules.capturer.statuses import CaptureStatus, AudioCaptureStatus, EventCaptureStatus, \ from UniTAP.dev.modules.capturer.statuses import CaptureStatus, AudioCaptureStatus, EventCaptureStatus, \
VideoCaptureStatus, BulkCaptureStatus VideoCaptureStatus, BulkCaptureStatus
from UniTAP.common import AudioFrameData, VideoFrameDSC, create_from_pps from UniTAP.common import AudioFrameData, VideoFrameDSC, create_from_pps
@@ -12,6 +14,8 @@ from UniTAP.utils import function_scheduler
from UniTAP.dev.ports.modules.capturer.bulk.private_bulk_types import * from UniTAP.dev.ports.modules.capturer.bulk.private_bulk_types import *
from UniTAP.dev.ports.modules.capturer.bulk.bulk_types import * from UniTAP.dev.ports.modules.capturer.bulk.bulk_types import *
from .types import * from .types import *
from UniTAP.utils import tsi_logging as logging
TIMEOUT = 10 TIMEOUT = 10
@@ -84,27 +88,27 @@ class Capturer:
@property @property
def video_capturer_status(self) -> VideoCaptureStatus: def video_capturer_status(self) -> VideoCaptureStatus:
return VideoCaptureStatus(self.__io.get(TSI_VIDCAP_CAPTURE_STATUS_R, c_int)[1]) return VideoCaptureStatus(self.__io.get(p_ci.TSI_VIDCAP_CAPTURE_STATUS_R, c_int)[1])
@property @property
def audio_capturer_status(self) -> AudioCaptureStatus: def audio_capturer_status(self) -> AudioCaptureStatus:
return AudioCaptureStatus(self.__io.get(TSI_R_AUDCAP_STATUS, c_int)[1]) return AudioCaptureStatus(self.__io.get(ci.TSI_R_AUDCAP_STATUS, c_int)[1])
@property @property
def event_capturer_status(self) -> EventCaptureStatus: def event_capturer_status(self) -> EventCaptureStatus:
return EventCaptureStatus(self.__io.get(TSI_EVCAP_CTRL, c_uint32)[1] & 0xFF) return EventCaptureStatus(self.__io.get(ci.TSI_EVCAP_CTRL, c_uint32)[1] & 0xFF)
@property @property
def bulk_capturer_status(self) -> BulkCaptureStatus: def bulk_capturer_status(self) -> BulkCaptureStatus:
return BulkCaptureStatus(self.__io.get(TSI_BULK_CAPTURE_STATUS_R, c_uint32)[1] & 0x3) return BulkCaptureStatus(self.__io.get(ci.TSI_BULK_CAPTURE_STATUS_R, c_uint32)[1] & 0x3)
def start_capture(self, config: CaptureConfig): def start_capture(self, config: CaptureConfig):
self.__mutex.acquire() self.__mutex.acquire()
self.__config.from_int(self.__current_config().to_int() | config.to_int()) self.__config.from_int(self.__current_config().to_int() | config.to_int())
self.__io.set(TSI_CAP_CONFIG, self.__config.to_int()) self.__io.set(ci.TSI_CAP_CONFIG, self.__config.to_int())
if self.__io.set(TSI_W_CAP_COMMAND, 1) == 0: if self.__io.set(ci.TSI_W_CAP_COMMAND, 1) == 0:
self.__status = CaptureStatus.Running self.__status = CaptureStatus.Running
else: else:
self.__status = CaptureStatus.Unknown self.__status = CaptureStatus.Unknown
@@ -115,9 +119,9 @@ class Capturer:
self.__mutex.acquire() self.__mutex.acquire()
self.__config.from_int(self.__current_config().to_int() & ~config.to_int()) self.__config.from_int(self.__current_config().to_int() & ~config.to_int())
self.__io.set(TSI_CAP_CONFIG, self.__config.to_int()) self.__io.set(ci.TSI_CAP_CONFIG, self.__config.to_int())
if self.__io.set(TSI_W_CAP_COMMAND, 2) == 0: if self.__io.set(ci.TSI_W_CAP_COMMAND, 2) == 0:
self.__status = CaptureStatus.Stop self.__status = CaptureStatus.Stop
else: else:
self.__status = CaptureStatus.Unknown self.__status = CaptureStatus.Unknown
@@ -128,22 +132,22 @@ class Capturer:
event = EventData() event = EventData()
if event_count > 0: if event_count > 0:
event_size = self.__io.get(TSI_R_EVCAP_DATA, None, 0)[0] event_size = self.__io.get(ci.TSI_R_EVCAP_DATA, None, 0)[0]
if event_size > 0: if event_size > 0:
event.data = bytearray(self.__io.get(TSI_R_EVCAP_DATA, c_ubyte, event_size)[1]) event.data = bytearray(self.__io.get(ci.TSI_R_EVCAP_DATA, c_ubyte, event_size)[1])
return event return event
def get_buffer_capacity(self, stream_number: int = None): def get_buffer_capacity(self, stream_number: int = None):
if stream_number is not None: if stream_number is not None:
self.__io.set(TSI_DPRX_STREAM_SELECT, stream_number, c_uint32) self.__io.set(ci.TSI_DPRX_STREAM_SELECT, stream_number, c_uint32)
self.__io.set(TSI_DPRX_MSA_COMMAND_W, 2, c_uint32) self.__io.set(ci.TSI_DPRX_MSA_COMMAND_W, 2, c_uint32)
width = self.__io.get(TSI_R_INPUT_WIDTH , c_uint32)[1] width = self.__io.get(ci.TSI_R_INPUT_WIDTH, c_uint32)[1]
height = self.__io.get(TSI_R_INPUT_HEIGHT , c_uint32)[1] height = self.__io.get(ci.TSI_R_INPUT_HEIGHT, c_uint32)[1]
total_memory_bytes = self.__io.get(TSI_MEMORY_SIZE_R, c_uint64)[1] total_memory_bytes = self.__io.get(ci.TSI_MEMORY_SIZE_R, c_uint64)[1]
bpc = self.__io.get(TSI_INPUT_COLOR_DEPTH_R , c_uint32)[1] bpc = self.__io.get(ci.TSI_INPUT_COLOR_DEPTH_R, c_uint32)[1]
color_format = self.__io.get(TSI_INPUT_COLOR_MODE_R , c_uint32)[1] color_format = self.__io.get(ci.TSI_INPUT_COLOR_MODE_R, c_uint32)[1]
bpp = self._get_bits_per_pixel(bpc, color_format) bpp = self._get_bits_per_pixel(bpc, color_format)
line_alignment = 1023 line_alignment = 1023
@@ -186,7 +190,7 @@ class Capturer:
return (value + alignment) & ~alignment return (value + alignment) & ~alignment
def get_available_events_count(self) -> int: def get_available_events_count(self) -> int:
return self.__io.get(TSI_R_EVCAP_COUNT, c_uint32)[1] return self.__io.get(ci.TSI_R_EVCAP_COUNT, c_uint32)[1]
def capture_n_events(self, events_count: int): def capture_n_events(self, events_count: int):
if events_count <= 0: if events_count <= 0:
@@ -215,19 +219,21 @@ class Capturer:
audio_frame = AudioFrameData() audio_frame = AudioFrameData()
audio_frame.channel_count = self.__io.get(TSI_R_AUDCAP_CHANNEL_COUNT, c_int)[1] audio_frame.channel_count = self.__io.get(ci.TSI_AUDCAP_CHANNEL_COUNT_R, c_int)[1]
audio_frame.sample_size = self.__io.get(TSI_R_AUDCAP_SAMPLE_SIZE, c_int)[1] * 8 audio_frame.sample_size = self.__io.get(ci.TSI_AUDCAP_SAMPLE_BITS_SIZE_R, c_int)[1]
audio_frame.sample_rate = self.__io.get(TSI_R_AUDCAP_SAMPLE_RATE, c_int)[1] audio_frame.sample_rate = self.__io.get(ci.TSI_R_AUDCAP_SAMPLE_RATE, c_int)[1]
audio_frame.timestamp = self.__io.get(TSI_R_AUDCAP_TIMESTAMP, c_uint64)[1] audio_frame.timestamp = self.__io.get(ci.TSI_R_AUDCAP_TIMESTAMP, c_uint64)[1]
audio_frame.samples = self.__io.get(TSI_R_AUDCAP_SAMPLE_COUNT, c_int)[1] audio_frame.samples = self.__io.get(ci.TSI_R_AUDCAP_SAMPLE_COUNT, c_int)[1]
audio_frame.frame_counter = self.__io.get(TSI_R_AUDCAP_FRAME_COUNTER, c_int)[1] audio_frame.frame_counter = self.__io.get(ci.TSI_R_AUDCAP_FRAME_COUNTER, c_int)[1]
audio_frame.sample_format = self.__io.get(TSI_R_AUDCAP_SAMPLE_FORMAT, c_int)[1] audio_frame.sample_format = self.__io.get(ci.TSI_R_AUDCAP_SAMPLE_FORMAT, c_int)[1]
min_buff_size = self.__io.get(TSI_R_AUDCAP_MIN_BUFFER_SIZE, c_uint32)[1] min_buff_size = self.__io.get(ci.TSI_R_AUDCAP_MIN_BUFFER_SIZE, c_uint32)[1]
audio_frame.data = self.__io.get(TSI_R_AUDCAP_SAMPLE_DATA, c_uint8, min_buff_size)[1] audio_frame.data = self.__io.get(ci.TSI_R_AUDCAP_SAMPLE_DATA, c_uint8, min_buff_size)[1]
m_sec -= 1000 * len(audio_frame.data) / 2 / audio_frame.channel_count / audio_frame.sample_rate captured_sample_count = len(audio_frame.data) / (audio_frame.sample_size / 8) / audio_frame.channel_count
captured_m_sec_count = int(captured_sample_count * 1000 / audio_frame.sample_rate)
m_sec -= captured_m_sec_count
return audio_frame, m_sec return audio_frame, m_sec
def capture_audio_by_n_frames(self, frames_count: int, timeout: int = None): def capture_audio_by_n_frames(self, frames_count: int, timeout: int = None):
@@ -263,29 +269,32 @@ class Capturer:
raise ValueError(f"Seconds count must be more than 0.") raise ValueError(f"Seconds count must be more than 0.")
buffer = [] buffer = []
time_break = False last_data_time = time.time()
while m_sec > 0:
while m_sec > 0 and not time_break:
captured = 0
start_time = time.time() start_time = time.time()
while captured < 10 and m_sec > 0: while self.audio_capturer_status != AudioCaptureStatus.Running:
status = self.audio_capturer_status if time.time() - start_time > TIMEOUT:
current_time = time.time() logging.error(f"Audio capture device not running for {TIMEOUT} seconds. Aborting.")
if current_time - start_time > TIMEOUT: return buffer
time_break = True logging.debug(f"Audio capture device not running yet: {self.audio_capturer_status}")
break time.sleep(0.5)
if status == AudioCaptureStatus.Stop:
continue
audio_frame, m_sec = self.__capture_audio(m_sec=m_sec) audio_frame, m_sec = self.__capture_audio(m_sec=m_sec)
if len(audio_frame.data) > 0: if len(audio_frame.data) > 0:
captured += 1
buffer.append(audio_frame) buffer.append(audio_frame)
last_data_time = time.time()
else:
if time.time() - last_data_time > TIMEOUT:
logging.error(
f"No audio data captured within {TIMEOUT} seconds. "
f"Interrupting capture process."
)
break
return buffer return buffer
def get_available_video_frame_count(self): def get_available_video_frame_count(self):
return self.__io.get(TSI_VIDCAP_AVAILABLE_FRAME_COUNT, c_int)[1] return self.__io.get(p_ci.TSI_VIDCAP_AVAILABLE_FRAME_COUNT, c_int)[1]
def __check_available_video(self, timeout) -> bool: def __check_available_video(self, timeout) -> bool:
def is_video_available(capturer): def is_video_available(capturer):
@@ -322,27 +331,27 @@ class Capturer:
f"Cannot start to capture video. Current video capture status {self.video_capturer_status.name}") f"Cannot start to capture video. Current video capture status {self.video_capturer_status.name}")
try: try:
result = self.__io.set(TSI_VIDCAP_CAPTURE_NEXT_W, 0) result = self.__io.set(ci.TSI_VIDCAP_CAPTURE_NEXT_W, 0)
if result == TSI_ERROR_DATA_PROTECTION_ENABLED: if result == ci.TSI_ERROR_DATA_PROTECTION_ENABLED:
raise CaptureError("Video data is HDCP protected. Capturing is not available.") raise CaptureError("Video data is HDCP protected. Capturing is not available.")
except AssertionError as e: except AssertionError as e:
raise CaptureError(f"Error: {e}") raise CaptureError(f"Error: {e}")
try: try:
min_buffer_size = self.__io.get(TSI_R_VIDCAP_MIN_BUFFER_SIZE, c_int)[1] min_buffer_size = self.__io.get(ci.TSI_R_VIDCAP_MIN_BUFFER_SIZE, c_int)[1]
if min_buffer_size <= 0: if min_buffer_size <= 0:
raise ValueError("Minimum buffer size must be more than 0") raise ValueError("Minimum buffer size must be more than 0")
except AssertionError as e: except AssertionError as e:
raise CaptureError(f"Error: {e}") raise CaptureError(f"Error: {e}")
try: try:
frame_data = bytearray(self.__io.get(TSI_R_VIDCAP_FRAME_DATA, c_uint8, min_buffer_size)[1]) frame_data = bytearray(self.__io.get(ci.TSI_R_VIDCAP_FRAME_DATA, c_uint8, min_buffer_size)[1])
if len(frame_data) <= 0: if len(frame_data) <= 0:
raise ValueError("Minimum length of captured data must be more than 0") raise ValueError("Minimum length of captured data must be more than 0")
except AssertionError as e: except AssertionError as e:
raise CaptureError(f"Error: {e}") raise CaptureError(f"Error: {e}")
frame_attributes = self.__io.get(TSI_VIDCAP_FRAME_HEADER_R, VideoFrameHeader)[1] frame_attributes = self.__io.get(ci.TSI_VIDCAP_FRAME_HEADER_R, VideoFrameHeader)[1]
if frame_attributes.is_dsc() and len(frame_data) > 128: if frame_attributes.is_dsc() and len(frame_data) > 128:
vf = VideoFrameDSC() vf = VideoFrameDSC()
@@ -397,12 +406,12 @@ class Capturer:
def set_video_stream_number(self, number: int): def set_video_stream_number(self, number: int):
self.__mutex.acquire() self.__mutex.acquire()
self.__io.set(TSI_DPRX_STREAM_SELECT, number, c_uint32) self.__io.set(ci.TSI_DPRX_STREAM_SELECT, number, c_uint32)
self.__mutex.release() self.__mutex.release()
def __current_config(self) -> CaptureConfig: def __current_config(self) -> CaptureConfig:
config = CaptureConfig() config = CaptureConfig()
config.from_int(self.__io.get(TSI_CAP_CONFIG, c_uint)[1]) config.from_int(self.__io.get(ci.TSI_CAP_CONFIG, c_uint)[1])
return config return config
# Capture CRC # Capture CRC
@@ -410,7 +419,7 @@ class Capturer:
if crc_frame_count <= 0: if crc_frame_count <= 0:
raise ValueError(f"Incorrect crc frame count: {crc_frame_count}") raise ValueError(f"Incorrect crc frame count: {crc_frame_count}")
crc_values = self.__io.get(TSI_VIDCAP_SIGNAL_CRC_R, CrcStruct, crc_frame_count)[1] crc_values = self.__io.get(ci.TSI_VIDCAP_SIGNAL_CRC_R, CrcStruct, crc_frame_count)[1]
crc_list = [] crc_list = []
if crc_frame_count == 1: if crc_frame_count == 1:
crc_list = [(crc_values.r, crc_values.g, crc_values.b)] crc_list = [(crc_values.r, crc_values.g, crc_values.b)]
@@ -420,15 +429,15 @@ class Capturer:
# Bulk Capturer # Bulk Capturer
def read_bulk_capture_caps(self) -> CaptureCaps: def read_bulk_capture_caps(self) -> CaptureCaps:
return self.__io.get(TSI_BULK_CAPTURE_CAPS_R, CaptureCaps)[1] return self.__io.get(ci.TSI_BULK_CAPTURE_CAPS_R, CaptureCaps)[1]
def read_bulk_trigger_caps(self) -> int: def read_bulk_trigger_caps(self) -> int:
return self.__io.get(TSI_BULK_TRIGGER_CAPS_R, c_uint32)[1] return self.__io.get(ci.TSI_BULK_TRIGGER_CAPS_R, c_uint32)[1]
def write_bulk_trigger_settings(self, trigger_mask: int, trigger_config: list, trigger_config_ext: list): def write_bulk_trigger_settings(self, trigger_mask: int, trigger_config: list, trigger_config_ext: list):
self.__io.set(TSI_BULK_TRIGGER_MASK_W, trigger_mask, c_uint32) self.__io.set(ci.TSI_BULK_TRIGGER_MASK_W, trigger_mask, c_uint32)
self.__io.set(TSI_BULK_TRIGGER_CONFIGURATION_W, trigger_config, c_uint32, data_count=len(trigger_config)) self.__io.set(ci.TSI_BULK_TRIGGER_CONFIGURATION_W, trigger_config, c_uint32, data_count=len(trigger_config))
self.__io.set(TSI_BULK_TRIGGER_CONFIGURATION_EXT_W, trigger_config_ext, c_uint32, self.__io.set(ci.TSI_BULK_TRIGGER_CONFIGURATION_EXT_W, trigger_config_ext, c_uint32,
data_count=len(trigger_config_ext)) data_count=len(trigger_config_ext))
def write_bulk_size(self, size: int): def write_bulk_size(self, size: int):
@@ -436,56 +445,56 @@ class Capturer:
data.BLOCK = 0 data.BLOCK = 0
data.OFFSET = 0 data.OFFSET = 0
data.SIZE = size data.SIZE = size
self.__io.set(TSI_BULK_CAPTURE_BLOCK, data, SBlock) self.__io.set(ci.TSI_BULK_CAPTURE_BLOCK, data, SBlock)
def write_encoding_type(self, value: EncodingTypeEnum): def write_encoding_type(self, value: EncodingTypeEnum):
self.__io.set(TSI_BULK_CAPTURE_TYPE, value.value, c_uint32) self.__io.set(ci.TSI_BULK_CAPTURE_TYPE, value.value, c_uint32)
def read_encoding_type(self) -> EncodingTypeEnum: def read_encoding_type(self) -> EncodingTypeEnum:
return EncodingTypeEnum(self.__io.get(TSI_BULK_CAPTURE_TYPE, c_uint32)[1]) return EncodingTypeEnum(self.__io.get(ci.TSI_BULK_CAPTURE_TYPE, c_uint32)[1])
def write_lane_count(self, value: LaneCountEnum): def write_lane_count(self, value: LaneCountEnum):
self.__io.set(TSI_BULK_CAPTURE_LANE_COUNT, value.value, c_uint32) self.__io.set(ci.TSI_BULK_CAPTURE_LANE_COUNT, value.value, c_uint32)
def read_lane_count(self) -> LaneCountEnum: def read_lane_count(self) -> LaneCountEnum:
return LaneCountEnum(self.__io.get(TSI_BULK_CAPTURE_LANE_COUNT, c_uint32)[1]) return LaneCountEnum(self.__io.get(ci.TSI_BULK_CAPTURE_LANE_COUNT, c_uint32)[1])
def write_bulk_gpio(self, gpio: bool): def write_bulk_gpio(self, gpio: bool):
self.__io.set(TSI_BULK_CAPTURE_GPIO_W, TSI_BULK_CAPTURE_GPIO_5BIT if gpio else TSI_BULK_CAPTURE_GPIO_OFF, self.__io.set(ci.TSI_BULK_CAPTURE_GPIO_W, ci.TSI_BULK_CAPTURE_GPIO_5BIT if gpio else ci.TSI_BULK_CAPTURE_GPIO_OFF,
c_uint32) c_uint32)
def write_bulk_trigger_position(self, position: int): def write_bulk_trigger_position(self, position: int):
self.__io.set(TSI_BULK_TRIGGER_POS, position) self.__io.set(ci.TSI_BULK_TRIGGER_POS, position)
def start_bulk_capture(self): def start_bulk_capture(self):
self.__mutex.acquire() self.__mutex.acquire()
self.__io.set(TSI_EVCAP_CTRL, 1) self.__io.set(ci.TSI_EVCAP_CTRL, 1)
self.__io.set(TSI_BULK_CAPTURE_CONTROL_W, TSI_BULK_CAPTURE_START) self.__io.set(ci.TSI_BULK_CAPTURE_CONTROL_W, ci.TSI_BULK_CAPTURE_START)
self.__mutex.release() self.__mutex.release()
def stop_bulk_capture(self): def stop_bulk_capture(self):
self.__mutex.acquire() self.__mutex.acquire()
self.__io.set(TSI_EVCAP_CTRL, 0) self.__io.set(ci.TSI_EVCAP_CTRL, 0)
self.__io.set(TSI_BULK_CAPTURE_CONTROL_W, TSI_BULK_CAPTURE_STOP) self.__io.set(ci.TSI_BULK_CAPTURE_CONTROL_W, ci.TSI_BULK_CAPTURE_STOP)
self.__mutex.release() self.__mutex.release()
def start_event_capture(self): def start_event_capture(self):
self.__mutex.acquire() self.__mutex.acquire()
self.__io.set(TSI_EVCAP_CTRL, 1) self.__io.set(ci.TSI_EVCAP_CTRL, 1)
self.__io.set(TSI_EVCAP_EVENT_SRC_EN, UCD_ALL_EVENTS) self.__io.set(ci.TSI_EVCAP_EVENT_SRC_EN, ci.UCD_ALL_EVENTS)
self.__mutex.release() self.__mutex.release()
def stop_event_capture(self): def stop_event_capture(self):
self.__mutex.acquire() self.__mutex.acquire()
self.__io.set(TSI_EVCAP_CTRL, 0) self.__io.set(ci.TSI_EVCAP_CTRL, 0)
self.__mutex.release() self.__mutex.release()
@@ -494,9 +503,9 @@ class Capturer:
value = -1 value = -1
time_waited = time.time() time_waited = time.time()
while value != TSI_BULK_STATUS_IDLE and time.time() - time_waited < max_time_waiting: while value != ci.TSI_BULK_STATUS_IDLE and time.time() - time_waited < max_time_waiting:
self.__io.set(TSI_BULK_CAPTURE_CLEAR_W, 0) self.__io.set(ci.TSI_BULK_CAPTURE_CLEAR_W, 0)
value = self.__io.get(TSI_BULK_CAPTURE_STATUS_R)[1] value = self.__io.get(ci.TSI_BULK_CAPTURE_STATUS_R)[1]
def bulk_capture(self, all_size: int, trigger_enabled: Optional[TriggerVarType]) -> list: def bulk_capture(self, all_size: int, trigger_enabled: Optional[TriggerVarType]) -> list:
buffer = [] buffer = []
@@ -504,16 +513,16 @@ class Capturer:
prev_status = 0 prev_status = 0
last_bulk_capture_time = time.time() last_bulk_capture_time = time.time()
for i in range(iterations): for i in range(iterations):
event_count = self.__io.get(TSI_EVCAP_COUNT_R, c_uint32)[1] event_count = self.__io.get(ci.TSI_EVCAP_COUNT_R, c_uint32)[1]
if event_count > 0: if event_count > 0:
event_number = 0 event_number = 0
prev_timestamp = 0 prev_timestamp = 0
events_captured = 0 events_captured = 0
while event_count > 0 and events_captured < 500: while event_count > 0 and events_captured < 500:
event_size = self.__io.get(TSI_R_EVCAP_DATA, None, 0)[0] event_size = self.__io.get(ci.TSI_R_EVCAP_DATA, None, 0)[0]
if event_size > 0: if event_size > 0:
cap_data = CapturedData() cap_data = CapturedData()
cap_data.data = bytearray(self.__io.get(TSI_R_EVCAP_DATA, c_ubyte, event_size)[1]) cap_data.data = bytearray(self.__io.get(ci.TSI_R_EVCAP_DATA, c_ubyte, event_size)[1])
cap_data.data = cap_data.data[3:] cap_data.data = cap_data.data[3:]
cap_data.type = CapturedDataType.Event cap_data.type = CapturedDataType.Event
cap_data.timestamp = int.from_bytes(bytes=cap_data.data[:8], byteorder='big') cap_data.timestamp = int.from_bytes(bytes=cap_data.data[:8], byteorder='big')
@@ -526,8 +535,8 @@ class Capturer:
events_captured += 1 events_captured += 1
event_count -= 1 event_count -= 1
bulk_status = self.__io.get(TSI_BULK_CAPTURE_STATUS_R, c_int32)[1] bulk_status = self.__io.get(ci.TSI_BULK_CAPTURE_STATUS_R, c_int32)[1]
if bulk_status == TSI_BULK_STATUS_IDLE and prev_status == TSI_BULK_STATUS_TRANSFERRING: if bulk_status == ci.TSI_BULK_STATUS_IDLE and prev_status == ci.TSI_BULK_STATUS_TRANSFERRING:
return buffer return buffer
prev_status = bulk_status prev_status = bulk_status
@@ -538,12 +547,12 @@ class Capturer:
if not self.__check_available_bulk_data(TIMEOUT): if not self.__check_available_bulk_data(TIMEOUT):
return buffer return buffer
self.__io.set(TSI_EVCAP_CTRL, 0) self.__io.set(ci.TSI_EVCAP_CTRL, 0)
cap_data = CapturedData() cap_data = CapturedData()
cap_data.type = CapturedDataType.Bulk cap_data.type = CapturedDataType.Bulk
result, data, _ = self.__io.get(TSI_BULK_CAPTURE_DATA_R, c_ubyte, 1024 * 1024) result, data, _ = self.__io.get(ci.TSI_BULK_CAPTURE_DATA_R, c_ubyte, 1024 * 1024)
cap_data.data = bytearray(data) cap_data.data = bytearray(data)
if result >= TSI_SUCCESS and len(cap_data.data) > 0: if result >= ci.TSI_SUCCESS and len(cap_data.data) > 0:
buffer.append(cap_data) buffer.append(cap_data)
last_bulk_capture_time = time.time() last_bulk_capture_time = time.time()

View File

@@ -1996,40 +1996,6 @@
"minValue": 0, "minValue": 0,
"name": "Maximum refresh rate for supported Adaptive-Sync video timings, in Hz.", "name": "Maximum refresh rate for supported Adaptive-Sync video timings, in Hz.",
"type": 4 "type": 4
},
{
"configId": "0x10e000d",
"defaultValue": "0",
"description": "Reserved for extension.",
"bitList":
[
{"description": "0x10e000d", "defaultValue": "0"},
{"description": "0x10e000f", "defaultValue": "0"},
{"description": "0x10e001c", "defaultValue": "0"},
{"description": "0x10e001d", "defaultValue": "0"},
{"description": "0x10e001e", "defaultValue": "0"},
{"description": "0x10e001f", "defaultValue": "0"},
{"description": "0x10e002f", "defaultValue": "0"},
{"description": "0x10e0030", "defaultValue": "0"},
{"description": "0x10e0031", "defaultValue": "0"},
{"description": "0x10e0032", "defaultValue": "0"},
{"description": "0x10e0033", "defaultValue": "0"},
{"description": "0x10e0034", "defaultValue": "0"},
{"description": "0x10e0035", "defaultValue": "0"},
{"description": "0x10e0036", "defaultValue": "0"},
{"description": "0x10e0037", "defaultValue": "0"},
{"description": "0x10e00b7", "defaultValue": "0"},
{"description": "0x10e00b8", "defaultValue": "0"},
{"description": "0x10e00b9", "defaultValue": "0"},
{"description": "0x10e00ba", "defaultValue": "0"},
{"description": "0x10e00bb", "defaultValue": "0"},
{"description": "0x10e00bc", "defaultValue": "0"},
{"description": "0x10e00bd", "defaultValue": "0"},
{"description": "0x10e00be", "defaultValue": "0"}
],
"flag": 3,
"id": "RESERVED",
"type": 4
} }
], ],
"id": "0x03", "id": "0x03",

View File

@@ -67,20 +67,6 @@
"minValue": 0, "minValue": 0,
"name": "Delay between test cycles, in milliseconds", "name": "Delay between test cycles, in milliseconds",
"type": 4 "type": 4
},
{
"configId": "0x10703",
"defaultValue": "0",
"description": "Reserved for DUT Capabilities flags and DUT Test automation capabilities flags.",
"bitList":
[
{"description": "0x10703", "defaultValue": "0"},
{"description": "0x10704", "defaultValue": "0"}
],
"flag": 3,
"id": "RESERVED",
"name": "Reserved",
"type": 4
} }
], ],
"id": "0x04", "id": "0x04",

View File

@@ -65,7 +65,11 @@
{"mask": "0x01000000", "description": "2x1 tiled display and DisplayID Tiled Display Topology data block supported"}, {"mask": "0x01000000", "description": "2x1 tiled display and DisplayID Tiled Display Topology data block supported"},
{"mask": "0x02000000", "description": "Field sequential stereo and DisplayID Tiled Stereo Display Interface data block supported"}, {"mask": "0x02000000", "description": "Field sequential stereo and DisplayID Tiled Stereo Display Interface data block supported"},
{"mask": "0x04000000", "description": "Stacked frame stereo and DisplayID Tiled Stereo Display Interface data block supported"}, {"mask": "0x04000000", "description": "Stacked frame stereo and DisplayID Tiled Stereo Display Interface data block supported"},
{"mask": "0x08000000", "description": "Dynamic Refresh Rate with VBlank stretch with MSA_TIMING_PAR_IGNORED supported"} {"mask": "0x08000000", "description": "Dynamic Refresh Rate with VBlank stretch with MSA_TIMING_PAR_IGNORED supported"},
{"mask": "0x10000000", "description": "MST transmission supported"},
{"mask": "0x20000000", "description": "MST UP_REQUEST supported"},
{"mask": "0x40000000", "description": "MST RSN_REQUEST supported"},
{"mask": "0x80000000", "description": "MST POWER_UP/DOWN_PHY supported"}
], ],
"flag": 3, "flag": 3,
"id": "TSI_DP20_SRCCTS_DUT_CAPS", "id": "TSI_DP20_SRCCTS_DUT_CAPS",
@@ -211,6 +215,17 @@
"name": "Debug mode configuration.", "name": "Debug mode configuration.",
"type": 12 "type": 12
}, },
{
"configId": "0x119000f",
"defaultValue": "1028",
"description": "Includes: Maximum stream count supported and Maximum daisy chain sink count supported.",
"flag": 3,
"id": "TSI_DP20_SRCCTS_DUT_MST_CAPS",
"maxValue": 2147483647,
"minValue": 0,
"name": "MST source DUT capabilities.",
"type": 4
},
{ {
"configId": "0x1190010", "configId": "0x1190010",
"defaultValue": "32000", "defaultValue": "32000",
@@ -2598,39 +2613,6 @@
"name": "Video mode supported by Source DUT (DP2.1 video & DSC tests)", "name": "Video mode supported by Source DUT (DP2.1 video & DSC tests)",
"type": 4 "type": 4
}, },
{
"configId": "0x119000f",
"defaultValue": "0",
"description": "Reserved for extension.",
"bitList":
[
{"description": "0x119000f", "defaultValue": "0"},
{"description": "0x119001c", "defaultValue": "0"},
{"description": "0x119001d", "defaultValue": "0"},
{"description": "0x119001e", "defaultValue": "0"},
{"description": "0x119001f", "defaultValue": "0"},
{"description": "0x119002f", "defaultValue": "0"},
{"description": "0x1190030", "defaultValue": "0"},
{"description": "0x1190031", "defaultValue": "0"},
{"description": "0x1190032", "defaultValue": "0"},
{"description": "0x1190033", "defaultValue": "0"},
{"description": "0x1190034", "defaultValue": "0"},
{"description": "0x1190035", "defaultValue": "0"},
{"description": "0x1190036", "defaultValue": "0"},
{"description": "0x1190037", "defaultValue": "0"},
{"description": "0x11900b7", "defaultValue": "0"},
{"description": "0x11900b8", "defaultValue": "0"},
{"description": "0x11900b9", "defaultValue": "0"},
{"description": "0x11900ba", "defaultValue": "0"},
{"description": "0x11900bb", "defaultValue": "0"},
{"description": "0x11900bc", "defaultValue": "0"},
{"description": "0x11900bd", "defaultValue": "0"},
{"description": "0x11900be", "defaultValue": "0"}
],
"flag": 3,
"id": "RESERVED",
"type": 4
},
{ {
"configId": "0x11900f4", "configId": "0x11900f4",
"defaultValue": "1920", "defaultValue": "1920",

View File

@@ -132,7 +132,7 @@
], ],
"flag": 1, "flag": 1,
"id": "TSI_HDMI_SNKCTS_DSC_VIDEO_FORMAT", "id": "TSI_HDMI_SNKCTS_DSC_VIDEO_FORMAT",
"name": "DSC Video formats 1.", "name": "DSC Video formats 1",
"type": 12 "type": 12
}, },
{ {
@@ -174,7 +174,7 @@
], ],
"flag": 1, "flag": 1,
"id": "TSI_HDMI_SNKCTS_DSC_VIDEO_FORMAT_2", "id": "TSI_HDMI_SNKCTS_DSC_VIDEO_FORMAT_2",
"name": "DSC Video formats 2.", "name": "DSC Video formats 2",
"type": 12 "type": 12
}, },
{ {
@@ -197,7 +197,7 @@
"id": "TSI_HDMI_SNKCTS_DSC_TOTAL_CHUNK_BYTES", "id": "TSI_HDMI_SNKCTS_DSC_TOTAL_CHUNK_BYTES",
"maxValue": 2147483647, "maxValue": 2147483647,
"minValue": 0, "minValue": 0,
"name": "DSC Max Slices", "name": "DSC TotalChunkKBytes",
"type": 4 "type": 4
} }
], ],

View File

@@ -1,66 +1,8 @@
{ {
"descriptions": [ "descriptions": [
{
"configId": "0x2100",
"defaultValue": "0",
"description": "Does the Sink support Fast Vactive (FVA), also known as Quick Frame Transport (QFT)?",
"flag": 3,
"id": "TSI_HDMI_GAMING_FVA",
"maxValue": 1,
"minValue": 0,
"name": "Sink_Supports_FVA",
"type": 3,
"enumerationVariants": "0 # NO\n1 # YES"
},
{
"configId": "0x2101",
"defaultValue": "1",
"description": "Does the Sink support Variable Refresh Rate (VRR)",
"flag": 3,
"id": "TSI_HDMI_GAMING_VRR",
"maxValue": 1,
"minValue": 0,
"name": "Sink_Supports_VRR",
"type": 3,
"enumerationVariants": "0 # NO\n1 # YES"
},
{
"configId": "0x2102",
"defaultValue": "0",
"description": "Does the Sink support Negative Mvrr values?",
"flag": 3,
"id": "TSI_HDMI_GAMING_NMVRR",
"maxValue": 1,
"minValue": 0,
"name": "Sink_Supports_Negative_MVRR",
"type": 3,
"enumerationVariants": "0 # NO\n1 # YES"
},
{
"configId": "0x2103",
"defaultValue": "40",
"description": "What is the Sinks supported VRR Range? Minimum value.\n",
"flag": 3,
"id": "TSI_HDMI_GAMING_RANGE_MIN",
"maxValue": 480,
"minValue": 20,
"name": "Sink_Supported_VRR_Range VRRMIN",
"type": 4
},
{
"configId": "0x2104",
"defaultValue": "0",
"description": "What is the Sinks supported VRR Range? Maximum value or BRR\n",
"flag": 3,
"id": "TSI_HDMI_GAMING_RANGE_MAX",
"maxValue": 480,
"minValue": 20,
"name": "Sink_Supported_VRR_Range VRRMAX or 0 for BRR",
"type": 4
},
{ {
"configId": "0x2105", "configId": "0x2105",
"defaultValue": "0", "defaultValue": "1",
"description": "Does the Sink implement Auto Low-Latency Mode (ALLM)?", "description": "Does the Sink implement Auto Low-Latency Mode (ALLM)?",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_ALLM", "id": "TSI_HDMI_GAMING_ALLM",
@@ -72,32 +14,28 @@
}, },
{ {
"configId": "0x2106", "configId": "0x2106",
"defaultValue": "0", "defaultValue": "Cinema",
"description": "Which display processing mode is the preferred mode with normal latency?", "description": "Which display processing mode is the preferred mode with normal latency?",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_NLM", "id": "TSI_HDMI_GAMING_NLM",
"maxValue": 2,
"minValue": 0,
"name": "Sink_Preferred_NLM", "name": "Sink_Preferred_NLM",
"type": 4, "type": 2,
"enumerationVariants": "0 # Cinema\n1 # Vivid\n2 # Normal" "maxLength": 256
}, },
{ {
"configId": "0x2107", "configId": "0x2107",
"defaultValue": "0", "defaultValue": "Gaming",
"description": "Which display processing mode is the preferred mode to minimize latency?", "description": "Which display processing mode is the preferred mode to minimize latency?",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_LLM", "id": "TSI_HDMI_GAMING_LLM",
"maxValue": 1,
"minValue": 0,
"name": "Sink_Preferred_LLM", "name": "Sink_Preferred_LLM",
"type": 4, "type": 2,
"enumerationVariants": "0 # Game\n1 # PC" "maxLength": 256
}, },
{ {
"configId": "0x2108", "configId": "0x2108",
"defaultValue": "1", "defaultValue": "1",
"description": "Does the Sink DUT support QMS-VRR?", "description": "Does the Sink supports QMS-VRR?",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_QMS", "id": "TSI_HDMI_GAMING_QMS",
"maxValue": 1, "maxValue": 1,
@@ -107,28 +45,58 @@
"enumerationVariants": "0 # NO\n1 # YES" "enumerationVariants": "0 # NO\n1 # YES"
}, },
{ {
"configId": "0x2109", "configId": "0x2101",
"defaultValue": "97", "defaultValue": "1",
"description": "What is the highest resolution (i.e., width x height) and base refresh rate (BRR) for which all TFRs up to Sink_QMS_Max_TFR_TMDS are supported by the Sink using TMDS?", "description": "Does the Sink supports VRR?",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_VIDEO_TMDS", "id": "TSI_HDMI_GAMING_VRR",
"maxValue": 255, "maxValue": 1,
"minValue": 16, "minValue": 0,
"name": "Sink_QMS_Video_Format_TMDS", "name": "Sink_Supports_VRR",
"type": 4, "type": 3,
"enumerationVariants": "78 # VIC=78; 1920x1080@120\n97 # VIC=97; 3840x2160@60" "enumerationVariants": "0 # NO\n1 # YES"
},
{
"configId": "0x2103",
"defaultValue": "0",
"description": "What is the Sink's supported VRR Range?",
"bitList": [
{
"mask": "0xFFFF",
"description": "VRR min"
},
{
"mask": "0xFFFF0000",
"description": "VRR max (0 for BRR)"
}
],
"flag": 12,
"id": "TSI_HDMI_GAMING_VRR_RANGE",
"name": "Sink_Supported_VRR_Range",
"type": 12
}, },
{ {
"configId": "0x210A", "configId": "0x210A",
"defaultValue": "118", "defaultValue": "0x0003c0043800780",
"description": "What is the highest resolution (i.e., width x height) and base refresh rate (BRR) for which all TFRs up to Sink_QMS_Max_TFR_FRL are supported by the Sink using FRL?", "description": "What is the highest resolution (i.e., width x height) and base refresh rate (BRR) for which all TFRs up to Sink_QMS_Max_TFR_FRL are supported by the Sink using TMDS?",
"flag": 3, "bitList": [
{
"mask": "0xFFFFF",
"description": "Width"
},
{
"mask": "0xFFFFF00000",
"description": "Height"
},
{
"mask": "0xFFFFF0000000000",
"description": "BRR"
}
],
"flag": 12,
"id": "TSI_HDMI_GAMING_VIDEO_FRL", "id": "TSI_HDMI_GAMING_VIDEO_FRL",
"maxValue": 255,
"minValue": 16,
"name": "Sink_QMS_Video_Format_FRL", "name": "Sink_QMS_Video_Format_FRL",
"type": 4, "type": 13
"enumerationVariants": "0 # N/A\n78 # VIC=78; 1920x1080@120\n97 # VIC=97; 3840x2160@60\n118 # VIC=118; 3840x2160@120"
}, },
{ {
"configId": "0x210B", "configId": "0x210B",
@@ -140,11 +108,11 @@
"minValue": 0, "minValue": 0,
"name": "Sink_QMS_Min_TFR", "name": "Sink_QMS_Min_TFR",
"type": 4, "type": 4,
"enumerationVariants": "0 # N/A\n1 # TFR=1; 24/1.001\n2 # TFR=2; 24\n3 # TFR=3; 25\n4 # TFR=4; 30/1.001\n5 # TFR=5; 30\n6 # TFR=6; 48/1.001\n7 # TFR=7; 48\n8 # TFR=8; 50\n9 # TFR=9; 60/1.001\n10 # TFR=10; 60\n11 # TFR=11; 100\n12 # TFR=12; 120/1.001\n13 # TFR=13; 120" "enumerationVariants": "0 # N/A\n1 # 1 - 24/1.001\n2 # 2 - 24\n3 # 3 - 25\n4 # 4 - 30/1.001\n5 # 5 - 30\n6 # 6 - 48/1.001\n7 # 7 - 48\n8 # 8 - 50\n9 # 9 - 60/1.001\n10 # 10 - 60\n11 # 11 - 100\n12 # 12 - 120/1.001\n13 # 13 - 120"
}, },
{ {
"configId": "0x210C", "configId": "0x210C",
"defaultValue": "10", "defaultValue": "6",
"description": "If the Sink DUT supports QMS-VRR, what is the maximum Next_TFR value supported using TMDS? (Refer to the Next_TFR field definition in HDMI 2.1a Table 10-37.)", "description": "If the Sink DUT supports QMS-VRR, what is the maximum Next_TFR value supported using TMDS? (Refer to the Next_TFR field definition in HDMI 2.1a Table 10-37.)",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_MAX_TFR_TMDS", "id": "TSI_HDMI_GAMING_MAX_TFR_TMDS",
@@ -152,11 +120,11 @@
"minValue": 0, "minValue": 0,
"name": "Sink_QMS_Max_TFR_TMDS", "name": "Sink_QMS_Max_TFR_TMDS",
"type": 4, "type": 4,
"enumerationVariants": "0 # N/A\n1 # TFR=1; 24/1.001\n2 # TFR=2; 24\n3 # TFR=3; 25\n4 # TFR=4; 30/1.001\n5 # TFR=5; 30\n6 # TFR=6; 48/1.001\n7 # TFR=7; 48\n8 # TFR=8; 50\n9 # TFR=9; 60/1.001\n10 # TFR=10; 60\n11 # TFR=11; 100\n12 # TFR=12; 120/1.001\n13 # TFR=13; 120" "enumerationVariants": "0 # N/A\n1 # 1 - 24/1.001\n2 # 2 - 24\n3 # 3 - 25\n4 # 4 - 30/1.001\n5 # 5 - 30\n6 # 6 - 48/1.001\n7 # 7 - 48\n8 # 8 - 50\n9 # 9 - 60/1.001\n10 # 10 - 60\n11 # 11 - 100\n12 # 12 - 120/1.001\n13 # 13 - 120"
}, },
{ {
"configId": "0x210D", "configId": "0x210D",
"defaultValue": "13", "defaultValue": "8",
"description": "If the Sink DUT supports QMS-VRR, what is the maximum Next_TFR value supported using FRL? (Refer to the Next_TFR field definition in HDMI 2.1a Table 10-37.)", "description": "If the Sink DUT supports QMS-VRR, what is the maximum Next_TFR value supported using FRL? (Refer to the Next_TFR field definition in HDMI 2.1a Table 10-37.)",
"flag": 3, "flag": 3,
"id": "TSI_HDMI_GAMING_MAX_TFR_FRL", "id": "TSI_HDMI_GAMING_MAX_TFR_FRL",
@@ -164,9 +132,44 @@
"minValue": 0, "minValue": 0,
"name": "Sink_QMS_Max_TFR_FRL", "name": "Sink_QMS_Max_TFR_FRL",
"type": 4, "type": 4,
"enumerationVariants": "0 # N/A\n1 # TFR=1; 24/1.001\n2 # TFR=2; 24\n3 # TFR=3; 25\n4 # TFR=4; 30/1.001\n5 # TFR=5; 30\n6 # TFR=6; 48/1.001\n7 # TFR=7; 48\n8 # TFR=8; 50\n9 # TFR=9; 60/1.001\n10 # TFR=10; 60\n11 # TFR=11; 100\n12 # TFR=12; 120/1.001\n13 # TFR=13; 120" "enumerationVariants": "0 # N/A\n1 # 1 - 24/1.001\n2 # 2 - 24\n3 # 3 - 25\n4 # 4 - 30/1.001\n5 # 5 - 30\n6 # 6 - 48/1.001\n7 # 7 - 48\n8 # 8 - 50\n9 # 9 - 60/1.001\n10 # 10 - 60\n11 # 11 - 100\n12 # 12 - 120/1.001\n13 # 13 - 120"
},
{
"configId": "0x210E",
"defaultValue": "1",
"description": "What is the maximum FRL Rate that the product supports? (Set to 0 if the product does not support FRL reception.)",
"flag": 3,
"id": "TSI_HDMI_GAMING_MAX_FRL",
"maxValue": 6,
"minValue": 0,
"name": "Sink_Max_FRL_Rate",
"type": 4,
"enumerationVariants": "0 # N/A\n1 # 1\n2 # 2\n3 # 3\n4 # 4\n5 # 5\n6 # 6"
},
{
"configId": "0x210F",
"defaultValue": "0x0003c0043800780",
"description": "What is the highest resolution (i.e., width x height) and base refresh rate (BRR) for which all TFRs up to Sink_QMS_Max_TFR_TMDS are supported by the Sink using TMDS?",
"bitList": [
{
"mask": "0xFFFFF",
"description": "Width"
},
{
"mask": "0xFFFFF00000",
"description": "Height"
},
{
"mask": "0xFFFFF0000000000",
"description": "BRR"
}
],
"flag": 12,
"id": "TSI_HDMI_GAMING_VIDEO_TMDS",
"name": "Sink_QMS_Video_Format_TMDS",
"type": 13
} }
], ],
"id": "0x23", "id": "0x23",
"name": "HDMI CTS MOI (VRR-QMS)" "name": "HDMI CTS MOI Gaming Features"
} }

View File

@@ -0,0 +1,197 @@
{
"descriptions": [
{
"configId": "0x01260000",
"defaultValue": "10000",
"description": "Defines timeout for all Timings video tests, in milliseconds. Default setting is 10000ms.\n",
"flag": 3,
"id": "TSI_TIMINGS_TIMEOUT",
"maxValue": 2147483647,
"minValue": 0,
"name": "Test timeout, in milliseconds",
"type": 4
},
{
"configId": "0x01260001",
"defaultValue": "200",
"description": "Total number of frames to be tested. After timings check for total number of frames test will be completed. If total number is equal to 0, then test will be executing up to test timeout. Default setting is 200.\n",
"flag": 3,
"id": "TSI_TIMINGS_FRAMES_TO_TEST",
"maxValue": 2147483647,
"minValue": 0,
"name": "Test duration, in frames",
"type": 4
},
{
"configId": "0x01260002",
"defaultValue": "2",
"description": "Number of bad frames allowed in test. Default setting is 2\n",
"flag": 3,
"id": "TSI_TIMINGS_LIM_FRAME_MISMATCHES",
"maxValue": 2147483647,
"minValue": 0,
"name": "Allowed mismatches, in frames",
"type": 4
},
{
"configId": "0x01260003",
"defaultValue": "24",
"description": "Defines the color depth as bits per pixel. If the input video color depth does not match this setting, the test will fail. Default setting is 24.\n",
"enumerationVariants": "12\n15\n16\n18\n20\n21\n24\n30\n32\n36\n48",
"flag": 3,
"id": "TSI_TIMINGS_REF_COLORDEPTH",
"maxValue": 2147480000,
"minValue": 0,
"name": "Expected color depth, as bits per pixel",
"type": 4
},
{
"configId": "0x01260004",
"defaultValue": "0",
"description": "Defines the required frame rate for timings test, in millihertz. Setting of zero (0) disables the frame-rate requirement. Default setting is 0.\n",
"flag": 3,
"id": "TSI_TIMINGS_REQUIRED_FRAME_RATE",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected frame rate, in millihertz (mHz)",
"type": 4
},
{
"configId": "0x01260005",
"defaultValue": "0",
"description": "Defines the maximum allowed deviation of input frame-rate from the required frame rate (TSI_TIMINGS_REQUIRED_FRAME_RATE), in millihertz. When this setting is non-zero, it defines the range of allowed frame rate as requirements ± tolerance. If the frame-rate requirement is set to zero, this setting has no effect. Default setting is 0 mHz.\n",
"flag": 3,
"id": "TSI_TIMINGS_FRAME_RATE_TOLERANCE",
"maxValue": 2147483647,
"minValue": 0,
"name": "Frame rate tolerance, in millihertz (mHz)",
"type": 4
},
{
"configId": "0x01260006",
"defaultValue": "2200",
"description": "Defined the expected video width, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1920.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_HTOTAL",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected video width, in pixels",
"type": 4
},
{
"configId": "0x01260007",
"defaultValue": "1125",
"description": "Defined the expected total video height, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1080.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_VTOTAL",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected total video height, in pixels",
"type": 4
},
{
"configId": "0x01260008",
"defaultValue": "1920",
"description": "Defined the expected active video width, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1920.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_HACTIVE",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected active video width, in pixels",
"type": 4
},
{
"configId": "0x01260009",
"defaultValue": "1080",
"description": "Defined the expected active video height, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1080.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_VACTIVE",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected active video height, in pixels",
"type": 4
},
{
"configId": "0x0126000a",
"defaultValue": "88",
"description": "Defined the expected horizontal front porch, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1920.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_HFRONT",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected horizontal front porch, in pixels",
"type": 4
},
{
"configId": "0x0126000b",
"defaultValue": "4",
"description": "Defined the expected vertical front porch, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1080.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_VFRONT",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected vertical front porch, in pixels",
"type": 4
},
{
"configId": "0x0126000c",
"defaultValue": "44",
"description": "Defined the expected horizontal sync interval, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1920.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_HSYNC",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected horizontal sync interval, in pixels",
"type": 4
},
{
"configId": "0x0126000d",
"defaultValue": "5",
"description": "Defined the expected vertical sync interval, in pixels. If the video being received does not match this setting, the test will fail. Default setting is 1080.\n",
"flag": 3,
"id": "TSI_TIMINGS_REF_VSYNC",
"maxValue": 2147483647,
"minValue": 0,
"name": "Expected vertical sync interval, in pixels",
"type": 4
},
{
"configId": "0x0126000e",
"defaultValue": "0",
"description": "Data transfer timeout in milliseconds. Default setting is 0.\n",
"flag": 3,
"id": "TSI_TIMINGS_DATA_TRANSFER_TIMEOUT",
"maxValue": 2147483647,
"minValue": 0,
"name": "Data transfer timeout.",
"type": 4
},
{
"configId": "0x01260021",
"defaultValue": "",
"description": "Contains the full path to the folder where failed frames are to be saved without trailing backslash (\\). No default. Failed frame file-name will be “Failed_<#>.ppm”, where <#> is replaced with an auto-incremented number.",
"flag": 3,
"id": "TSI_FAILED_FRAME_TARGET_FOLDER",
"maxLength": 10000,
"name": "Location where the failed frames are to be saved",
"type": 11
},
{
"configId": "0x01260022",
"defaultValue": "0",
"description": "Defines the number of failed frames to be exported from the video test. Default setting is 0. If the setting is 0, no frames are exported.",
"flag": 3,
"id": "TSI_MAX_EXPORT_FAILED",
"maxValue": 2147483647,
"minValue": 0,
"name": "Maximum number of exported frames",
"type": 4
}
],
"id": "0x2d",
"name": "Timings Video Tests",
"shortName": "Timings Video Tests",
"old_names": [
"Timings Video Test Set"
]
}

View File

@@ -0,0 +1,67 @@
{
"descriptions": [
{
"configId": "0x1270000",
"defaultValue": "5000",
"description": "Defines test timeout in milliseconds, default value is 5000ms.",
"flag": 3,
"id": "TSI_DP20_MST_BRANCH_TIMEOUT",
"maxValue": 2147483647,
"minValue": 0,
"name": "Test timeout in milliseconds.",
"reportFormat": "Test timeout = %2ms<br>",
"type": 4
},
{
"configId": "0x1270001",
"defaultValue": "0x00000000",
"description": "Defines the DUT capabilities as flags.",
"bitList":
[
{"mask": "0x00000001", "description": "DUT supports CSN DFP broadcast", "reportFormat": "- DUT is Type-C device<br>"}
],
"flag": 3,
"id": "TSI_DP20_MST_BRANCH_DUT_CAPS",
"name": "DUT Capability flags.",
"reportFormat": "Test DUT capabilities flags:<br>",
"type": 12
},
{
"configId": "0x1270002",
"defaultValue": "0x00000010",
"description": "Defines the numbers of DUT UFP and DFP ports connected to TE.",
"bitList":
[
{"mask": "0x0000000f", "description": "DUT UFP port connected to TE"},
{"mask": "0x000000f0", "description": "DUT DFP port connected to TE"}
],
"flag": 3,
"id": "TSI_DP20_MST_BRANCH_DUT_UFP_DFP_PORTS",
"name": "DUT UFP and DFP ports connected to TE",
"reportFormat": "DUT UFP and DFP ports connected to TE:<br>",
"type": 12
},
{
"configId": "0x1270003",
"defaultValue": "0x00005432",
"description": "Defines the numbers of DUT DFP ports connected to external sinks.",
"bitList":
[
{"mask": "0x0000000f", "description": "DUT DFP port connected to Sink 1"},
{"mask": "0x000000f0", "description": "DUT DFP port connected to Sink 2"},
{"mask": "0x00000f00", "description": "DUT DFP port connected to Sink 3"},
{"mask": "0x0000f000", "description": "DUT DFP port connected to Sink 4"}
],
"flag": 3,
"id": "TSI_DP20_MST_BRANCH_DUT_SINK_PORTS",
"name": "DUT DFP ports connected to external sinks",
"reportFormat": "DUT DFP ports connected to external sinks:<br>",
"type": 12
}
],
"id": "0x2E",
"name": "DP 2.1 MST Branch CTS",
"old_names": [
"DP 2.1 MST Branch CTS"
]
}

View File

@@ -26,6 +26,13 @@ from .hdmi_sink_tests import HdmiSinkDUTTestParam, HdmiTestMode, HdmiFrlRate
from .hdmi_source_tests import HdmiSourceDUTTestParam from .hdmi_source_tests import HdmiSourceDUTTestParam
from .hdmi_sink_continuity_tests import HdmiSinkContinuityDUTTestParam from .hdmi_sink_continuity_tests import HdmiSinkContinuityDUTTestParam
from .hdmi_sink_cable_check_tests import HdmiSinkCableCheckTestParam from .hdmi_sink_cable_check_tests import HdmiSinkCableCheckTestParam
from .hdmi_hdcp_1a_tests import HdmiHdcp1ATestParam
from .hdmi_hdcp_1b_tests import HdmiHdcp1BTestParam
from .hdmi_hdcp_2c_tests import HdmiHdcp2CTestParam
from .hdmi_hdcp_3a_tests import HdmiHdcp3ATestParam
from .hdmi_hdcp_3b_tests import HdmiHdcp3BTestParam
from .hdmi_hdcp_3c_tests import HdmiHdcp3CTestParam
from .dp_2_1_branch_mst import Dp21BranchMSTSourceDUTTestParam
from ..test_group_params_types import Param, get_param_list from ..test_group_params_types import Param, get_param_list
DUTTestParameters = TypeVar("DUTTestParameters", DUTTestParameters = TypeVar("DUTTestParameters",
@@ -53,4 +60,12 @@ DUTTestParameters = TypeVar("DUTTestParameters",
Hdr10TestParam, Hdr10TestParam,
HdmiSinkDUTTestParam, HdmiSinkDUTTestParam,
HdmiSinkContinuityDUTTestParam, HdmiSinkContinuityDUTTestParam,
HdmiSinkCableCheckTestParam) HdmiSinkCableCheckTestParam,
HdmiHdcp1ATestParam,
HdmiHdcp1BTestParam,
HdmiHdcp2CTestParam,
HdmiHdcp3ATestParam,
HdmiHdcp3BTestParam,
HdmiHdcp3CTestParam,
Dp21BranchMSTSourceDUTTestParam
)

View File

@@ -4,6 +4,7 @@ from UniTAP.dev.modules.dut_tests.dut_default_params.dp_source_adaptive_sync_tab
from UniTAP.dev.modules.dut_tests.dut_default_params.dp_2_1_video_modes import Dp21AvailableVideoModes from UniTAP.dev.modules.dut_tests.dut_default_params.dp_2_1_video_modes import Dp21AvailableVideoModes
from UniTAP.dev.modules.dut_tests.dut_default_params.dp_2_1_dsc_video_modes import Dp21AvailableDscVideoModes from UniTAP.dev.modules.dut_tests.dut_default_params.dp_2_1_dsc_video_modes import Dp21AvailableDscVideoModes
from UniTAP.dev.modules.dut_tests.dut_default_params.dp_source_audio_tab import AudioSourceDp21SettingTab from UniTAP.dev.modules.dut_tests.dut_default_params.dp_source_audio_tab import AudioSourceDp21SettingTab
from UniTAP.dev.modules.dut_tests.dut_default_params.dp_2_1_mst import Dp21MstSettingsTab
class Dp21SourceDUTTestParam: class Dp21SourceDUTTestParam:
@@ -13,6 +14,7 @@ class Dp21SourceDUTTestParam:
- Set and get `DisplayIdDp21ConfigTab`. Allows working with parameters from Display ID part `display_id`. - Set and get `DisplayIdDp21ConfigTab`. Allows working with parameters from Display ID part `display_id`.
- Set and get `AdaptiveSyncDp21ConfigTab`. Allows working with parameters from Adaptive-Sync part `adaptive_sync`. - Set and get `AdaptiveSyncDp21ConfigTab`. Allows working with parameters from Adaptive-Sync part `adaptive_sync`.
- Set and get `Dp21AvailableVideoModes`. Allows working with parameters from Video modes part `video_modes`. - Set and get `Dp21AvailableVideoModes`. Allows working with parameters from Video modes part `video_modes`.
- Set and get `Dp21MstSettingsTab`. Allows working with parameters from MST part `mst`.
""" """
def __init__(self, json_obj): def __init__(self, json_obj):
self.__general_tab = GeneralSourceDUTDp21SettingTab(json_obj) self.__general_tab = GeneralSourceDUTDp21SettingTab(json_obj)
@@ -21,6 +23,7 @@ class Dp21SourceDUTTestParam:
self.__adaptive_sync_tab = AdaptiveSyncDp21ConfigTab(json_obj) self.__adaptive_sync_tab = AdaptiveSyncDp21ConfigTab(json_obj)
self.__video_modes = Dp21AvailableVideoModes(json_obj) self.__video_modes = Dp21AvailableVideoModes(json_obj)
self.__dsc_video_modes = Dp21AvailableDscVideoModes(json_obj) self.__dsc_video_modes = Dp21AvailableDscVideoModes(json_obj)
self.__mst_tab = Dp21MstSettingsTab(json_obj)
@property @property
def general(self) -> GeneralSourceDUTDp21SettingTab: def general(self) -> GeneralSourceDUTDp21SettingTab:
@@ -81,3 +84,13 @@ class Dp21SourceDUTTestParam:
object of `Dp21AvailableVideoModes` type object of `Dp21AvailableVideoModes` type
""" """
return self.__dsc_video_modes return self.__dsc_video_modes
@property
def mst(self) -> Dp21MstSettingsTab:
"""
Get object of parameters from Video modes source part.
Returns:
object of `Dp21MstSettingsTab` type
"""
return self.__mst_tab

View File

@@ -0,0 +1,210 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class DutCapsMSTBranchFlags:
"""
Class `DutCapsDp21Flags` defines the DUT capabilities as flags.
Setting:
- DUT CSN DFP broadcast supported flag `support_csn_dfp_broadcast`.
"""
def __init__(self, json_obj):
self.__value = Param(json_obj)
@property
def support_csn_dfp_broadcast(self) -> bool:
"""
Set and get DUT CSN DFP broadcast flag support.
Returns:
object of bool type
"""
return self.__value._get_by_bitmask(0, bool)
@support_csn_dfp_broadcast.setter
def support_csn_dfp_broadcast(self, support_csn_dfp_broadcast: bool):
self.__value._set_by_bitmask(support_csn_dfp_broadcast, 0)
class PortsConnectedToTE:
"""
Class `PortsConnectedToTE` which defines the numbers of DUT UFP and DFP ports connected to TE.
Setting:
- Number of DUT UFP ports connected to TE `ufp_ports`.
- Number of DUT DFP ports connected to TE `dfp_ports`.
"""
def __init__(self, json_obj):
self.__value = Param(json_obj)
@property
def ufp_ports(self) -> int:
"""
Set and get number of DUT UFP ports connected to TE.
Returns:
object of int type
"""
return self.__value._get_by_bitmask(0, int)
@ufp_ports.setter
def ufp_ports(self, ufp_ports: int):
self.__value._set_by_bitmask(ufp_ports, 0)
@property
def dfp_ports(self) -> int:
"""
Set and get number of DUT DFP ports connected to TE.
Returns:
object of int type
"""
return self.__value._get_by_bitmask(1, int)
@dfp_ports.setter
def dfp_ports(self, dfp_ports: int):
self.__value._set_by_bitmask(dfp_ports, 1)
class PortsConnectedToExternalSink:
"""
Class `PortsConnectedToExternalSink` which defines the numbers of DUT DFP ports connected to external sinks.
Setting:
- Number of DUT DFP ports connected to Sink 1 `sink_1`.
- Number of DUT DFP ports connected to Sink 2 `sink_2`.
- Number of DUT DFP ports connected to Sink 3 `sink_3`.
- Number of DUT DFP ports connected to Sink 4 `sink_4`.
"""
def __init__(self, json_obj):
self.__value = Param(json_obj)
@property
def sink_1(self) -> int:
"""
Set and get number of DUT DFP ports connected to Sink 1.
Returns:
object of int type
"""
return self.__value._get_by_bitmask(0, int)
@sink_1.setter
def sink_1(self, ports_to_sink_1: int):
self.__value._set_by_bitmask(ports_to_sink_1, 0)
@property
def sink_2(self) -> int:
"""
Set and get number of DUT DFP ports connected to Sink 2.
Returns:
object of int type
"""
return self.__value._get_by_bitmask(0, int)
@sink_2.setter
def sink_2(self, ports_to_sink_2: int):
self.__value._set_by_bitmask(ports_to_sink_2, 0)
@property
def sink_3(self) -> int:
"""
Set and get number of DUT DFP ports connected to Sink 3.
Returns:
object of int type
"""
return self.__value._get_by_bitmask(0, int)
@sink_3.setter
def sink_3(self, ports_to_sink_3: int):
self.__value._set_by_bitmask(ports_to_sink_3, 0)
@property
def sink_4(self) -> int:
"""
Set and get number of DUT DFP ports connected to Sink 4.
Returns:
object of int type
"""
return self.__value._get_by_bitmask(0, int)
@sink_4.setter
def sink_4(self, ports_to_sink_1: int):
self.__value._set_by_bitmask(ports_to_sink_1, 0)
class Dp21BranchMSTSourceDUTTestParam:
"""
Class `Dp21BranchMSTSourceDUTTestParam` describes requirement parameters for DP 2.1 branch MST tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
- DUT MST Branch capabilities flags `dut_caps_flags` type `DutCapsMSTBranchFlags`.
- DUT UFP and DFP ports connected to TE `ports_connect_to_te` type `PortsConnectedToTE`.
- DUT DFP ports connected to external sinks `ports_connect_to_external_sink` type `PortsConnectedToExternalSink`
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_DP20_MST_BRANCH_TIMEOUT"])
self.__dut_caps_flags = DutCapsMSTBranchFlags(json_obj["TSI_DP20_MST_BRANCH_DUT_CAPS"])
self.__ports_connect_to_te = PortsConnectedToTE(json_obj["TSI_DP20_MST_BRANCH_DUT_UFP_DFP_PORTS"])
self.__ports_connect_to_external_sink = PortsConnectedToExternalSink(json_obj["TSI_DP20_MST_BRANCH_DUT_SINK_PORTS"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout
@property
def dut_caps_flags(self) -> DutCapsMSTBranchFlags:
"""
Set and get DUT capabilities flags.
Returns:
object of `DutCapsMSTBranchFlags` type
"""
return self.__dut_caps_flags
@dut_caps_flags.setter
def dut_caps_flags(self, dut_caps_flags: DutCapsMSTBranchFlags):
self.__dut_caps_flags = dut_caps_flags
@property
def ports_connect_to_te(self) -> PortsConnectedToTE:
"""
Set and get numbers DUT UFP and DFP ports connected to TE.
Returns:
object of `PortsConnectedToTE` type
"""
return self.__ports_connect_to_te
@ports_connect_to_te.setter
def ports_connect_to_te(self, ports_connect_to_te: PortsConnectedToTE):
self.__ports_connect_to_te = ports_connect_to_te
@property
def ports_connect_to_external_sink(self) -> PortsConnectedToExternalSink:
"""
Set and get numbers DUT UFP and DFP ports connected to External Sinks.
Returns:
object of `PortsConnectedToExternalSink` type
"""
return self.__ports_connect_to_external_sink
@ports_connect_to_external_sink.setter
def ports_connect_to_external_sink(self, ports_connect_to_external_sink: PortsConnectedToExternalSink):
self.__ports_connect_to_external_sink = ports_connect_to_external_sink

View File

@@ -276,13 +276,11 @@ class VideoModeInfo:
def __init__(self, json_obj): def __init__(self, json_obj):
self.__value = Param(json_obj) self.__value = Param(json_obj)
self.__standard = VideoModeStandard(self.__value)
self.__colorimetry = ColorimetryModes(self.__value)
@property @property
def standard(self) -> VideoModeStandard: def standard(self) -> VideoModeStandard:
return self.__standard return VideoModeStandard(self.__value)
@property @property
def colorimetry(self) -> ColorimetryModes: def colorimetry(self) -> ColorimetryModes:
return self.__colorimetry return ColorimetryModes(self.__value)

View File

@@ -7,8 +7,6 @@ class Dp21AvailableDscVideoModes:
- Set and get... - Set and get...
""" """
def __init__(self, json_obj): def __init__(self, json_obj):
self.__is_config_changed = False
self.__1920x1080_30hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_1920_1080_30"]) self.__1920x1080_30hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_1920_1080_30"])
self.__1920x1080_60hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_1920_1080_60"]) self.__1920x1080_60hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_1920_1080_60"])
self.__1920x1080_120hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_1920_1080_120"]) self.__1920x1080_120hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_1920_1080_120"])
@@ -30,12 +28,6 @@ class Dp21AvailableDscVideoModes:
self.__10240x4320_30hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_10240_4320_30"]) self.__10240x4320_30hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_10240_4320_30"])
self.__10240x4320_60hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_10240_4320_60"]) self.__10240x4320_60hz = VideoModeInfo(json_obj["TSI_DP20_SRCCTS_DSC_VMT_10240_4320_60"])
def __getattribute__(self, name):
attr = super().__getattribute__(name)
if "vm_" in name or "_all" in name:
self.__is_config_changed = True
return attr
@property @property
def vm_1920x1080_30hz(self) -> VideoModeInfo: def vm_1920x1080_30hz(self) -> VideoModeInfo:
return self.__1920x1080_30hz return self.__1920x1080_30hz

View File

@@ -0,0 +1,46 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class Dp21MstSettingsTab:
"""
Class `Dp21MstSettingsTab` allows working with MST source DUT capabilities.
- Set and get Maximum stream count
- Set and get Maximum daisy chain sink count
"""
def __init__(self, json_obj):
self.__max_stream_count = Param(json_obj["TSI_DP20_SRCCTS_DUT_MST_CAPS"])
self.__max_daisy_chain_sink_count = Param(json_obj["TSI_DP20_SRCCTS_DUT_MST_CAPS"])
@property
def max_stream_count(self) -> int:
"""
Set and get max stream count (1-4).
Returns:
object of int type
"""
return self.__max_stream_count.default_value & 0xFF
@max_stream_count.setter
def max_stream_count(self, max_stream_count: int):
if not (self.__max_stream_count.min_value <= max_stream_count <= self.__max_stream_count.max_value):
raise ValueError(f"Timeout cannot be less than {self.__max_stream_count.min_value} and more than "
f"{self.__max_stream_count.max_value}.")
self.__max_stream_count.direct_set_bits_value(0xFF, max_stream_count, 0)
@property
def max_daisy_chain_sink_count(self) -> int:
"""
Set and get max daisy chain sink count (1-4).
Returns:
object of int type
"""
return (self.__max_daisy_chain_sink_count.default_value >> 8) & 0xFF
@max_daisy_chain_sink_count.setter
def max_daisy_chain_sink_count(self, max_daisy_chain_sink_count: int):
if not (self.__max_stream_count.min_value <= max_daisy_chain_sink_count <= self.__max_stream_count.max_value):
raise ValueError(f"Timeout cannot be less than {self.__max_daisy_chain_sink_count.min_value} and more than "
f"{self.__max_daisy_chain_sink_count.max_value}.")
self.__max_daisy_chain_sink_count.direct_set_bits_value(0xFF00, max_daisy_chain_sink_count, 8)

View File

@@ -114,7 +114,7 @@ class LinkRateDp21(Param):
self._set_by_bitmask(support_13_5Gbps, 2) self._set_by_bitmask(support_13_5Gbps, 2)
class DutCapsDp21Flags(Param): class DutCapsDp21Flags:
""" """
Class `DutCapsDp21Flags` inherited of class`DutCapsFlags` which defines the DUT capabilities as flags and allows Class `DutCapsDp21Flags` inherited of class`DutCapsFlags` which defines the DUT capabilities as flags and allows
setting: setting:
@@ -123,7 +123,7 @@ class DutCapsDp21Flags(Param):
Also has all the `DutCapsFlags` functionality. Also has all the `DutCapsFlags` functionality.
""" """
def __init__(self, json_obj): def __init__(self, json_obj):
super().__init__(json_obj) self.__value = Param(json_obj)
@property @property
def voltage_swing_supported(self) -> bool: def voltage_swing_supported(self) -> bool:
@@ -133,11 +133,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(0, bool) return self.__value._get_by_bitmask(0, bool)
@voltage_swing_supported.setter @voltage_swing_supported.setter
def voltage_swing_supported(self, voltage_swing_supported: bool): def voltage_swing_supported(self, voltage_swing_supported: bool):
self._set_by_bitmask(voltage_swing_supported, 0) self.__value._set_by_bitmask(voltage_swing_supported, 0)
@property @property
def pre_emphasis_supported(self) -> bool: def pre_emphasis_supported(self) -> bool:
@@ -147,11 +147,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(1, bool) return self.__value._get_by_bitmask(1, bool)
@pre_emphasis_supported.setter @pre_emphasis_supported.setter
def pre_emphasis_supported(self, pre_emphasis_supported: bool): def pre_emphasis_supported(self, pre_emphasis_supported: bool):
self._set_by_bitmask(pre_emphasis_supported, 1) self.__value._set_by_bitmask(pre_emphasis_supported, 1)
@property @property
def fixed_timing_dut_supported(self) -> bool: def fixed_timing_dut_supported(self) -> bool:
@@ -161,11 +161,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(2, bool) return self.__value._get_by_bitmask(2, bool)
@fixed_timing_dut_supported.setter @fixed_timing_dut_supported.setter
def fixed_timing_dut_supported(self, fixed_timing_dut_supported: bool): def fixed_timing_dut_supported(self, fixed_timing_dut_supported: bool):
self._set_by_bitmask(fixed_timing_dut_supported, 2) self.__value._set_by_bitmask(fixed_timing_dut_supported, 2)
@property @property
def spread_spectrum_supported(self) -> bool: def spread_spectrum_supported(self) -> bool:
@@ -175,11 +175,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(3, bool) return self.__value._get_by_bitmask(3, bool)
@spread_spectrum_supported.setter @spread_spectrum_supported.setter
def spread_spectrum_supported(self, spread_spectrum_supported: bool): def spread_spectrum_supported(self, spread_spectrum_supported: bool):
self._set_by_bitmask(spread_spectrum_supported, 3) self.__value._set_by_bitmask(spread_spectrum_supported, 3)
@property @property
def change_vf_without_lt_supported(self) -> bool: def change_vf_without_lt_supported(self) -> bool:
@@ -189,11 +189,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(4, bool) return self.__value._get_by_bitmask(4, bool)
@change_vf_without_lt_supported.setter @change_vf_without_lt_supported.setter
def change_vf_without_lt_supported(self, change_vf_without_lt_supported: bool): def change_vf_without_lt_supported(self, change_vf_without_lt_supported: bool):
self._set_by_bitmask(change_vf_without_lt_supported, 4) self.__value._set_by_bitmask(change_vf_without_lt_supported, 4)
@property @property
def e_ddc_protocol_supported(self) -> bool: def e_ddc_protocol_supported(self) -> bool:
@@ -203,11 +203,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(5, bool) return self.__value._get_by_bitmask(5, bool)
@e_ddc_protocol_supported.setter @e_ddc_protocol_supported.setter
def e_ddc_protocol_supported(self, e_ddc_protocol_supported: bool): def e_ddc_protocol_supported(self, e_ddc_protocol_supported: bool):
self._set_by_bitmask(e_ddc_protocol_supported, 5) self.__value._set_by_bitmask(e_ddc_protocol_supported, 5)
@property @property
def audio_transmission_supported(self) -> bool: def audio_transmission_supported(self) -> bool:
@@ -217,11 +217,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(6, bool) return self.__value._get_by_bitmask(6, bool)
@audio_transmission_supported.setter @audio_transmission_supported.setter
def audio_transmission_supported(self, audio_transmission_supported: bool): def audio_transmission_supported(self, audio_transmission_supported: bool):
self._set_by_bitmask(audio_transmission_supported, 6) self.__value._set_by_bitmask(audio_transmission_supported, 6)
@property @property
def dut_is_type_c_device(self) -> bool: def dut_is_type_c_device(self) -> bool:
@@ -231,11 +231,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(7, bool) return self.__value._get_by_bitmask(7, bool)
@dut_is_type_c_device.setter @dut_is_type_c_device.setter
def dut_is_type_c_device(self, dut_is_type_c_device: bool): def dut_is_type_c_device(self, dut_is_type_c_device: bool):
self._set_by_bitmask(dut_is_type_c_device, 7) self.__value._set_by_bitmask(dut_is_type_c_device, 7)
@property @property
def fec_supported(self) -> bool: def fec_supported(self) -> bool:
@@ -245,11 +245,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(8, bool) return self.__value._get_by_bitmask(8, bool)
@fec_supported.setter @fec_supported.setter
def fec_supported(self, fec_supported: bool): def fec_supported(self, fec_supported: bool):
self._set_by_bitmask(fec_supported, 8) self.__value._set_by_bitmask(fec_supported, 8)
@property @property
def fec_disable_sequence_supported(self) -> bool: def fec_disable_sequence_supported(self) -> bool:
@@ -259,11 +259,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(9, bool) return self.__value._get_by_bitmask(9, bool)
@fec_disable_sequence_supported.setter @fec_disable_sequence_supported.setter
def fec_disable_sequence_supported(self, fec_disable_sequence_supported: bool): def fec_disable_sequence_supported(self, fec_disable_sequence_supported: bool):
self._set_by_bitmask(fec_disable_sequence_supported, 9) self.__value._set_by_bitmask(fec_disable_sequence_supported, 9)
@property @property
def audio_without_video_supported(self) -> bool: def audio_without_video_supported(self) -> bool:
@@ -273,11 +273,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(10, bool) return self.__value._get_by_bitmask(10, bool)
@audio_without_video_supported.setter @audio_without_video_supported.setter
def audio_without_video_supported(self, audio_without_video_supported: bool): def audio_without_video_supported(self, audio_without_video_supported: bool):
self._set_by_bitmask(audio_without_video_supported, 10) self.__value._set_by_bitmask(audio_without_video_supported, 10)
@property @property
def dsc_supported(self) -> bool: def dsc_supported(self) -> bool:
@@ -287,11 +287,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(11, bool) return self.__value._get_by_bitmask(11, bool)
@dsc_supported.setter @dsc_supported.setter
def dsc_supported(self, dsc_supported: bool): def dsc_supported(self, dsc_supported: bool):
self._set_by_bitmask(dsc_supported, 11) self.__value._set_by_bitmask(dsc_supported, 11)
@property @property
def dsc_block_prediction_supported(self) -> bool: def dsc_block_prediction_supported(self) -> bool:
@@ -301,11 +301,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(12, bool) return self.__value._get_by_bitmask(12, bool)
@dsc_block_prediction_supported.setter @dsc_block_prediction_supported.setter
def dsc_block_prediction_supported(self, dsc_block_prediction_supported: bool): def dsc_block_prediction_supported(self, dsc_block_prediction_supported: bool):
self._set_by_bitmask(dsc_block_prediction_supported, 12) self.__value._set_by_bitmask(dsc_block_prediction_supported, 12)
@property @property
def max_link_bandwidth_policy_supported(self): def max_link_bandwidth_policy_supported(self):
@@ -315,11 +315,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(13, bool) return self.__value._get_by_bitmask(13, bool)
@max_link_bandwidth_policy_supported.setter @max_link_bandwidth_policy_supported.setter
def max_link_bandwidth_policy_supported(self, max_link_bandwidth_policy_supported: bool): def max_link_bandwidth_policy_supported(self, max_link_bandwidth_policy_supported: bool):
self._set_by_bitmask(max_link_bandwidth_policy_supported, 13) self.__value._set_by_bitmask(max_link_bandwidth_policy_supported, 13)
@property @property
def use_3tap_conversion(self): def use_3tap_conversion(self):
@@ -329,11 +329,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(14, bool) return self.__value._get_by_bitmask(14, bool)
@use_3tap_conversion.setter @use_3tap_conversion.setter
def use_3tap_conversion(self, use_3tap_filter: bool): def use_3tap_conversion(self, use_3tap_filter: bool):
self._set_by_bitmask(use_3tap_filter, 14) self.__value._set_by_bitmask(use_3tap_filter, 14)
@property @property
def usb4_tunnel_presented(self): def usb4_tunnel_presented(self):
@@ -343,11 +343,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(15, bool) return self.__value._get_by_bitmask(15, bool)
@usb4_tunnel_presented.setter @usb4_tunnel_presented.setter
def usb4_tunnel_presented(self, usb4_tunnel_presented: bool): def usb4_tunnel_presented(self, usb4_tunnel_presented: bool):
self._set_by_bitmask(usb4_tunnel_presented, 15) self.__value._set_by_bitmask(usb4_tunnel_presented, 15)
@property @property
def native_display_id_read(self) -> bool: def native_display_id_read(self) -> bool:
@@ -357,11 +357,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(16, bool) return self.__value._get_by_bitmask(16, bool)
@native_display_id_read.setter @native_display_id_read.setter
def native_display_id_read(self, native_display_id_read: bool): def native_display_id_read(self, native_display_id_read: bool):
self._set_by_bitmask(native_display_id_read, 16) self.__value._set_by_bitmask(native_display_id_read, 16)
@property @property
def display_id_vii_supported(self) -> bool: def display_id_vii_supported(self) -> bool:
@@ -371,11 +371,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(17, bool) return self.__value._get_by_bitmask(17, bool)
@display_id_vii_supported.setter @display_id_vii_supported.setter
def display_id_vii_supported(self, display_id_vii_supported: bool): def display_id_vii_supported(self, display_id_vii_supported: bool):
self._set_by_bitmask(display_id_vii_supported, 17) self.__value._set_by_bitmask(display_id_vii_supported, 17)
@property @property
def display_id_viii_supported(self) -> bool: def display_id_viii_supported(self) -> bool:
@@ -385,12 +385,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(18, bool) return self.__value._get_by_bitmask(18, bool)
@display_id_viii_supported.setter @display_id_viii_supported.setter
def display_id_viii_supported(self, display_id_viii_supported: bool): def display_id_viii_supported(self, display_id_viii_supported: bool):
self._set_by_bitmask(display_id_viii_supported, 18) self.__value._set_by_bitmask(display_id_viii_supported, 18)
@property @property
def display_id_ix_supported(self) -> bool: def display_id_ix_supported(self) -> bool:
@@ -400,11 +399,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(19, bool) return self.__value._get_by_bitmask(19, bool)
@display_id_ix_supported.setter @display_id_ix_supported.setter
def display_id_ix_supported(self, display_id_ix_supported: bool): def display_id_ix_supported(self, display_id_ix_supported: bool):
self._set_by_bitmask(display_id_ix_supported, 19) self.__value._set_by_bitmask(display_id_ix_supported, 19)
@property @property
def display_id_x_supported(self) -> bool: def display_id_x_supported(self) -> bool:
@@ -414,11 +413,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(20, bool) return self.__value._get_by_bitmask(20, bool)
@display_id_x_supported.setter @display_id_x_supported.setter
def display_id_x_supported(self, display_id_x_supported: bool): def display_id_x_supported(self, display_id_x_supported: bool):
self._set_by_bitmask(display_id_x_supported, 20) self.__value._set_by_bitmask(display_id_x_supported, 20)
@property @property
def display_id_tiled_display_topology(self) -> bool: def display_id_tiled_display_topology(self) -> bool:
@@ -428,11 +427,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(21, bool) return self.__value._get_by_bitmask(21, bool)
@display_id_tiled_display_topology.setter @display_id_tiled_display_topology.setter
def display_id_tiled_display_topology(self, display_id_tiled_display_topology: bool): def display_id_tiled_display_topology(self, display_id_tiled_display_topology: bool):
self._set_by_bitmask(display_id_tiled_display_topology, 21) self.__value._set_by_bitmask(display_id_tiled_display_topology, 21)
@property @property
def display_id_tiled_stereo_display(self) -> bool: def display_id_tiled_stereo_display(self) -> bool:
@@ -442,11 +441,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(22, bool) return self.__value._get_by_bitmask(22, bool)
@display_id_tiled_stereo_display.setter @display_id_tiled_stereo_display.setter
def display_id_tiled_stereo_display(self, display_id_tiled_stereo_display: bool): def display_id_tiled_stereo_display(self, display_id_tiled_stereo_display: bool):
self._set_by_bitmask(display_id_tiled_stereo_display, 22) self.__value._set_by_bitmask(display_id_tiled_stereo_display, 22)
@property @property
def stacked_frame_stereo_supported(self) -> bool: def stacked_frame_stereo_supported(self) -> bool:
@@ -456,11 +455,11 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(23, bool) return self.__value._get_by_bitmask(23, bool)
@stacked_frame_stereo_supported.setter @stacked_frame_stereo_supported.setter
def stacked_frame_stereo_supported(self, stacked_frame_stereo_supported: bool): def stacked_frame_stereo_supported(self, stacked_frame_stereo_supported: bool):
self._set_by_bitmask(stacked_frame_stereo_supported, 23) self.__value._set_by_bitmask(stacked_frame_stereo_supported, 23)
@property @property
def dynamic_refresh_rate_support(self) -> bool: def dynamic_refresh_rate_support(self) -> bool:
@@ -470,11 +469,67 @@ class DutCapsDp21Flags(Param):
Returns: Returns:
object of bool type object of bool type
""" """
return self._get_by_bitmask(24, bool) return self.__value._get_by_bitmask(24, bool)
@dynamic_refresh_rate_support.setter @dynamic_refresh_rate_support.setter
def dynamic_refresh_rate_support(self, dynamic_refresh_rate_support: bool): def dynamic_refresh_rate_support(self, dynamic_refresh_rate_support: bool):
self._set_by_bitmask(dynamic_refresh_rate_support, 24) self.__value._set_by_bitmask(dynamic_refresh_rate_support, 24)
@property
def mst_transmission_supported(self) -> bool:
"""
Set and get MST transmission supported flag supported.
Returns:
object of bool type
"""
return self.__value._get_by_bitmask(25, bool)
@mst_transmission_supported.setter
def mst_transmission_supported(self, mst_transmission_supported: bool):
self.__value._set_by_bitmask(mst_transmission_supported, 25)
@property
def mst_up_request_supported(self) -> bool:
"""
Set and get MST UP REQUEST supported flag supported.
Returns:
object of bool type
"""
return self.__value._get_by_bitmask(26, bool)
@mst_up_request_supported.setter
def mst_up_request_supported(self, mst_up_request_supported: bool):
self.__value._set_by_bitmask(mst_up_request_supported, 26)
@property
def mst_rsn_request_supported(self) -> bool:
"""
Set and get MST RSN REQUEST supported flag supported.
Returns:
object of bool type
"""
return self.__value._get_by_bitmask(27, bool)
@mst_rsn_request_supported.setter
def mst_rsn_request_supported(self, mst_rsn_request_supported: bool):
self.__value._set_by_bitmask(mst_rsn_request_supported, 27)
@property
def mst_power_up_request_supported(self) -> bool:
"""
Set and get MST POWER_UP DOWN_PHY supported flag supported.
Returns:
object of bool type
"""
return self.__value._get_by_bitmask(28, bool)
@mst_power_up_request_supported.setter
def mst_power_up_request_supported(self, mst_power_up_request_supported: bool):
self.__value._set_by_bitmask(mst_power_up_request_supported, 28)
class DutCapsDp21: class DutCapsDp21:
@@ -487,7 +542,7 @@ class DutCapsDp21:
def __init__(self, json_obj): def __init__(self, json_obj):
self.__max_lanes = Param(json_obj["TSI_DP20_SRCCTS_MAX_LANES"]) self.__max_lanes = Param(json_obj["TSI_DP20_SRCCTS_MAX_LANES"])
self.__max_link_rate = Param(json_obj["TSI_DP20_SRCCTS_MAX_LINK_RATE"]) self.__max_link_rate = Param(json_obj["TSI_DP20_SRCCTS_MAX_LINK_RATE"])
self.__dut_caps_flags = DutCapsDp21Flags(json_obj["TSI_DP20_SRCCTS_DUT_CAPS"]) self.__dut_caps_flags_mst = DutCapsDp21Flags(json_obj["TSI_DP20_SRCCTS_DUT_CAPS"])
@property @property
def max_lanes(self) -> int: def max_lanes(self) -> int:
@@ -529,11 +584,11 @@ class DutCapsDp21:
Returns: Returns:
object of `DutCapsFlags` type object of `DutCapsFlags` type
""" """
return self.__dut_caps_flags return self.__dut_caps_flags_mst
@dut_caps_flags.setter @dut_caps_flags.setter
def dut_caps_flags(self, dut_caps_flags: DutCapsDp21Flags): def dut_caps_flags(self, dut_caps_flags: DutCapsDp21Flags):
self.__dut_caps_flags = dut_caps_flags self.__dut_caps_flags_mst = dut_caps_flags
class DebugOptions: class DebugOptions:
@@ -755,4 +810,3 @@ class GeneralSourceDUTDp21SettingTab:
@debug_options.setter @debug_options.setter
def debug_options(self, debug_config: DebugOptions): def debug_options(self, debug_config: DebugOptions):
self.__debug_options = debug_config self.__debug_options = debug_config

View File

@@ -0,0 +1,27 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class HdmiHdcp1ATestParam:
"""
Class `HdmiHdcp1ATestParam` describes requirement parameters for HDMI HDCP 1A tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_HDMI_HDCP_1A_TIMEOUT"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout

View File

@@ -0,0 +1,27 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class HdmiHdcp1BTestParam:
"""
Class `HdmiHdcp1BTestParam` describes requirement parameters for HDMI HDCP 1B tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_HDMI_HDCP_1B_TIMEOUT"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout

View File

@@ -0,0 +1,60 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
from .hdmi_sink_tests import HdmiFrlRate
class HdmiHdcp2CTestParam:
"""
Class `HdmiHdcp2CTestParam` describes requirement parameters for HDMI HDCP 2C tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
- Set and get `lt_before_test`.
- Set and get `link_rate`.
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_HDMI_HDCP_2C_TIMEOUT"])
self.__lt_before_test = Param(json_obj["TSI_HDMI_HDCP_2C_LT_BEFORE_TEST"])
self.__link_rate = Param(json_obj["TSI_HDMI_HDCP_2C_LINK_RATE"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout
@property
def lt_before_test(self) -> bool:
"""
Set and get flag to do or not link training before starting test
Returns:
object of bool type
"""
return bool(self.__lt_before_test.default_value)
@lt_before_test.setter
def lt_before_test(self, enable: bool):
self.__lt_before_test.default_value = int(enable)
@property
def link_rate(self) -> HdmiFrlRate:
"""
Set and get the Link rate for link training.
Returns:
object of `HdmiFrlRate` type
"""
return HdmiFrlRate(self.__link_rate.default_value)
@link_rate.setter
def link_rate(self, link_rate: HdmiFrlRate):
self.__link_rate.default_value = link_rate.value

View File

@@ -0,0 +1,27 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class HdmiHdcp3ATestParam:
"""
Class `HdmiHdcp3ATestParam` describes requirement parameters for HDMI HDCP 3A tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_HDMI_HDCP_3A_TIMEOUT"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout

View File

@@ -0,0 +1,27 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class HdmiHdcp3BTestParam:
"""
Class `HdmiHdcp3BTestParam` describes requirement parameters for HDMI HDCP 3B tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_HDMI_HDCP_3B_TIMEOUT"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout

View File

@@ -0,0 +1,27 @@
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
class HdmiHdcp3CTestParam:
"""
Class `HdmiHdcp3CTestParam` describes requirement parameters for HDMI HDCP 3C tests:
- Set and get `timeout`. Describes test timeout, in milliseconds.
"""
def __init__(self, json_obj):
self.__timeout = Param(json_obj["TSI_HDMI_HDCP_3C_TIMEOUT"])
@property
def timeout(self) -> int:
"""
Set and get test timeout, in milliseconds.
Returns:
object of int type
"""
return self.__timeout.default_value
@timeout.setter
def timeout(self, timeout: int):
if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
f"{self.__timeout.max_value}.")
self.__timeout.default_value = timeout

View File

@@ -142,45 +142,25 @@ class DUTTests:
- Make report after testing `make_report`. - Make report after testing `make_report`.
- Run test from file `run_from_file` - Not implemented. Will be added later. - Run test from file `run_from_file` - Not implemented. Will be added later.
""" """
__DEFAULT_TEST_PARAMETERS = None
def __init__(self, dev_io: DeviceIO): def __init__(self, dev_io: DeviceIO):
self.__io = dev_io self.__io = dev_io
self.__opf_device = None self.__opf_device = None
self.__results = [] self.__results = []
self.__default_parameters = {}
self.__test_groups = {} self.__test_groups = {}
self.__parser = Parser()
self.__io.set_test_config(0) self.__io.set_test_config(0)
cfp_path = os.path.join(os.path.dirname(__file__), 'cfg')
files = os.listdir(cfp_path)
for file in files:
try:
if not os.path.isfile(os.path.join(cfp_path, file)):
continue
with open(os.path.join(cfp_path, file), encoding='UTF-8') as cfg_json:
json_obj = json.load(cfg_json)
item_group = MergedTestGroups(int(json_obj.get('id'), 16))
group_type = MERGED_GROUP_PARAMS_TYPE.get(item_group, None)
if group_type is None:
continue
group_parameters_dict = {}
for parameter in json_obj.get('descriptions'):
group_parameters_dict[parameter["id"]] = parameter
self.__default_parameters[group_type] = group_type(group_parameters_dict)
except ValueError:
logging.info(
f"[UniTAP] Failed to load {os.path.join(cfp_path, file)}.\n Value {int(json_obj.get('id'), 16)} is missing in MergedTestGroups.")
test_list = self.__io.get_test_list() test_list = self.__io.get_test_list()
for test in test_list: for test in test_list:
test_id = test[0] & 0xFFFF test_id = test[0] & 0xFFFF
try:
group_id = TestGroupId(test[0] >> 16) group_id = TestGroupId(test[0] >> 16)
except BaseException as e:
logging.info(e)
continue
name = test[2] name = test[2]
if test[2].find(' / ') != -1: if test[2].find(' / ') != -1:
@@ -201,6 +181,49 @@ class DUTTests:
self.__test_groups[group_id]._add_new_test(Test(name=test_name, test_id=test_id)) self.__test_groups[group_id]._add_new_test(Test(name=test_name, test_id=test_id))
@staticmethod
def __enumerate_and_get_default_test_parameters():
if DUTTests.__DEFAULT_TEST_PARAMETERS is None:
DUTTests.__DEFAULT_TEST_PARAMETERS = {}
cfp_path = os.path.join(os.path.dirname(__file__), 'cfg')
files = os.listdir(cfp_path)
for file in files:
try:
if not os.path.isfile(os.path.join(cfp_path, file)):
continue
with open(os.path.join(cfp_path, file), encoding='UTF-8') as cfg_json:
json_obj = json.load(cfg_json)
item_group = MergedTestGroups(int(json_obj.get('id'), 16))
group_type = MERGED_GROUP_PARAMS_TYPE.get(item_group, None)
if group_type is None:
continue
group_parameters_dict = {}
for parameter in json_obj.get('descriptions'):
group_parameters_dict[parameter["id"]] = parameter
DUTTests.__DEFAULT_TEST_PARAMETERS[group_type] = group_type(group_parameters_dict)
except ValueError:
logging.info(
f"[UniTAP] Failed to load {os.path.join(cfp_path, file)}.\n Value {int(json_obj.get('id'), 16)} is missing in MergedTestGroups.")
return DUTTests.__DEFAULT_TEST_PARAMETERS
@staticmethod
def __is_dsc_parameters_changed(param: Dp21SourceDUTTestParam):
assert isinstance(param, Dp21SourceDUTTestParam)
result = []
dsc_vm_params = vars(param.dsc_video_modes)
for key in dsc_vm_params:
vm_param_dict = vars(dsc_vm_params[key])
result.append(any(vm_param_dict[param_key].is_modified for param_key in vm_param_dict))
return any(result)
def run(self, group_id: TestGroupId, test_id: int, params: Optional[DUTTestParameters] = None, def run(self, group_id: TestGroupId, test_id: int, params: Optional[DUTTestParameters] = None,
print_fw_logs: bool = True, test_delay: int = 0) -> SubTestResultObject: print_fw_logs: bool = True, test_delay: int = 0) -> SubTestResultObject:
""" """
@@ -234,8 +257,11 @@ class DUTTests:
if params is not None: if params is not None:
params_list = get_param_list(params) params_list = get_param_list(params)
if isinstance(params, Dp21SourceDUTTestParam) and not params.dsc_video_modes._Dp21AvailableDscVideoModes__is_config_changed:
logging.warning("Detected that used didn't change new DSC config. Copy setting from video config.") #
# Backward compatibility with old config
#
if isinstance(params, Dp21SourceDUTTestParam):
dsc_dp2_ci_remapper = { dsc_dp2_ci_remapper = {
"TSI_DP20_SRCCTS_DSC_VMT_1920_1080_30": "TSI_DP20_SRCCTS_VMT_1920_1080_30", "TSI_DP20_SRCCTS_DSC_VMT_1920_1080_30": "TSI_DP20_SRCCTS_VMT_1920_1080_30",
"TSI_DP20_SRCCTS_DSC_VMT_1920_1080_60": "TSI_DP20_SRCCTS_VMT_1920_1080_60", "TSI_DP20_SRCCTS_DSC_VMT_1920_1080_60": "TSI_DP20_SRCCTS_VMT_1920_1080_60",
@@ -259,27 +285,33 @@ class DUTTests:
"TSI_DP20_SRCCTS_DSC_VMT_10240_4320_60": "TSI_DP20_SRCCTS_VMT_10240_4320_60" "TSI_DP20_SRCCTS_DSC_VMT_10240_4320_60": "TSI_DP20_SRCCTS_VMT_10240_4320_60"
} }
if not DUTTests.__is_dsc_parameters_changed(params):
logging.warn("Detected that user didn't change new DSC config. Copy setting from video config.")
for key in dsc_dp2_ci_remapper.keys(): for key in dsc_dp2_ci_remapper.keys():
dst = next((obj for obj in params_list if obj.config_id_name == key), None) dst = next((obj for obj in params_list if obj.config_id_name == key), None)
src = next((obj for obj in params_list if obj.config_id_name == dsc_dp2_ci_remapper[key]), None) src = next((obj for obj in params_list if obj.config_id_name == dsc_dp2_ci_remapper[key]), None)
if dst.default_value != src.default_value: if dst.default_value != src.default_value:
logging.warn(f"DSC Config missmatch detected. Apply workaround: {key}:{hex(dst.default_value)}; {dsc_dp2_ci_remapper[key]}:{hex(src.default_value)}") logging.warn(
f"DSC Config missmatch detected. Apply workaround: {key}:{hex(dst.default_value)}; {dsc_dp2_ci_remapper[key]}:{hex(src.default_value)}")
dst.default_value = src.default_value dst.default_value = src.default_value
else: else:
logging.warn(f"DSC Config modification detected. Skip workaround.") logging.warn(f"DSC Config modification detected. Skip workaround.")
else: else:
params_list = self.__default_parameters[merged_group_id] params_list = DUTTests.__enumerate_and_get_default_test_parameters()[merged_group_id]
for item in params_list: for item in params_list:
if group_id == TestGroupId.AUDIO_TEST and item.config_id_name == "TSI_REF1_FRAME_DATA": if group_id == TestGroupId.AUDIO_TEST and item.config_id_name == "TSI_REF1_FRAME_DATA":
if isinstance(item.default_value, str) and os.path.exists(item.default_value): if isinstance(item.default_value, str) and os.path.exists(item.default_value):
image_data = read_image_file(item.default_value) image_data, file_extension = read_image_file(item.default_value)
if len(image_data) > 0: if len(image_data) > 0:
item.default_value = uicl_image_preparation(image_data, params) # It is assumed that the bin file already contains prepared data,
# otherwise there is no way to determine whether additional conversion is required.
item.default_value = uicl_image_preparation(image_data, params, file_extension == ".bin")
elif isinstance(item, bytearray): elif isinstance(item, bytearray):
# TODO: add 'bytearray' support # TODO: add 'bytearray' support
item.default_value = uicl_image_preparation(item.default_value, params) item.default_value = uicl_image_preparation(item.default_value, params, False)
self.__io.set(item.config_id, item.default_value, dict_types.get(item.value_type), self.__io.set(item.config_id, item.default_value, dict_types.get(item.value_type),
item.data_length) item.data_length)
@@ -320,36 +352,46 @@ class DUTTests:
return copy.deepcopy(self.__results[-1]) return copy.deepcopy(self.__results[-1])
def get_params_from_file(self, path: str) -> Tuple[TestGroupId, int, DUTTestParameters]: @staticmethod
def get_params_from_file(path: str) -> Tuple[TestGroupId, int, DUTTestParameters]:
""" """
Get test parameters from transferred file: td or json (not cdf). Get test parameters from transferred file: td or json (not cdf).
Args: Args:
path ('str') - full path to config file path ('str') - full path to config file
""" """
self.__parser.set_file_name(path) parser = Parser()
group_id = self.__parser.detect_group()
test_id = self.__parser.detect_test() parser.set_file_name(path)
group_id = parser.detect_group()
test_id = parser.detect_test()
group_type = group_params_dict.get(group_id) group_type = group_params_dict.get(group_id)
params = self.__parser.parse(self.get_default_parameters(group_type)) params = parser.parse(DUTTests.get_default_parameters(group_type))
return group_id, test_id, params return group_id, test_id, params
# TODO - add support parsing '.td' (other test groups) file extension # TODO - add support parsing '.td' (other test groups) file extension
def get_params_from_cdf_file(self, path: str) -> DUTTestParameters: @staticmethod
def get_params_from_cdf_file(path: str) -> DUTTestParameters:
""" """
Get test parameters from transferred file: json (cdf). Get test parameters from transferred file: json (cdf).
Args: Args:
path ('str') - full path to config file path ('str') - full path to config file
""" """
self.__parser.set_file_name(path)
group_id = self.__parser.detect_merged_group() parser = Parser()
parser.set_file_name(path)
group_id = parser.detect_merged_group()
group_type = MERGED_GROUP_PARAMS_TYPE.get(group_id) group_type = MERGED_GROUP_PARAMS_TYPE.get(group_id)
params = self.__parser.parse(self.get_default_parameters(group_type)) params = parser.parse(DUTTests.get_default_parameters(group_type))
return params return params
def get_default_parameters(self, group_type: Type[DUTTestParameters]) -> DUTTestParameters: @staticmethod
def get_default_parameters(group_type: Type[DUTTestParameters]) -> DUTTestParameters:
""" """
Get predefined (default) parameters of test group. Get predefined (default) parameters of test group.
@@ -359,9 +401,9 @@ class DUTTests:
Returns: Returns:
object of `DUTTestParameters` type object of `DUTTestParameters` type
""" """
for group_id in self.__default_parameters.keys(): for group_id in DUTTests.__enumerate_and_get_default_test_parameters().keys():
if isinstance(self.__default_parameters.get(group_id), group_type): if isinstance(DUTTests.__enumerate_and_get_default_test_parameters().get(group_id), group_type):
return copy.deepcopy(self.__default_parameters.get(group_id)) return copy.deepcopy(DUTTests.__enumerate_and_get_default_test_parameters().get(group_id))
raise ValueError(f"Group {group_type} is not available.") raise ValueError(f"Group {group_type} is not available.")
def number_tests_in_group(self, group_id: TestGroupId) -> int: def number_tests_in_group(self, group_id: TestGroupId) -> int:

View File

@@ -31,7 +31,17 @@ class MergedTestGroups(IntEnum):
HDRX_DSC_CTS = 0x20, HDRX_DSC_CTS = 0x20,
HDTX_DSC_CTS = 0x21, HDTX_DSC_CTS = 0x21,
HDTX_CONTINUITY = 0x22, HDTX_CONTINUITY = 0x22,
HDTX_CABLE_CHECK = 0x24 HDTX_CABLE_CHECK = 0x24,
HDMI_HDCP_CTS_1A = 0x25,
HDMI_HDCP_CTS_1B = 0x26,
HDMI_HDCP_CTS_2C = 0x27,
HDMI_HDCP_CTS_3A = 0x28,
HDMI_HDCP_CTS_3B = 0x29,
HDMI_HDCP_CTS_3C = 0x2A,
DPRX_128b132b_LL_CTS_DEMO = 0x2B,
DPTX_128b132b_LL_CTS_DEMO = 0x2C,
TIMINGS_VIDEO_TEST = 0x2D,
BRANCH_128b132b_MST_CTS = 0x2E
MERGED_GROUP_PARAMS_TYPE = { MERGED_GROUP_PARAMS_TYPE = {
@@ -60,7 +70,14 @@ MERGED_GROUP_PARAMS_TYPE = {
MergedTestGroups.HDRX_DSC_CTS: HdmiSourceDUTTestParam, MergedTestGroups.HDRX_DSC_CTS: HdmiSourceDUTTestParam,
MergedTestGroups.HDTX_DSC_CTS: HdmiSinkDUTTestParam, MergedTestGroups.HDTX_DSC_CTS: HdmiSinkDUTTestParam,
MergedTestGroups.HDTX_CONTINUITY: HdmiSinkContinuityDUTTestParam, MergedTestGroups.HDTX_CONTINUITY: HdmiSinkContinuityDUTTestParam,
MergedTestGroups.HDTX_CABLE_CHECK: HdmiSinkCableCheckTestParam MergedTestGroups.HDTX_CABLE_CHECK: HdmiSinkCableCheckTestParam,
MergedTestGroups.HDMI_HDCP_CTS_1A: HdmiHdcp1ATestParam,
MergedTestGroups.HDMI_HDCP_CTS_1B: HdmiHdcp1BTestParam,
MergedTestGroups.HDMI_HDCP_CTS_3A: HdmiHdcp3ATestParam,
MergedTestGroups.HDMI_HDCP_CTS_3B: HdmiHdcp3BTestParam,
MergedTestGroups.HDMI_HDCP_CTS_2C: HdmiHdcp2CTestParam,
MergedTestGroups.HDMI_HDCP_CTS_3C: HdmiHdcp3CTestParam,
MergedTestGroups.BRANCH_128b132b_MST_CTS: Dp21BranchMSTSourceDUTTestParam
} }
group_params_dict = { group_params_dict = {
@@ -104,7 +121,25 @@ group_params_dict = {
TestGroupId.HD_RX_DSC_CTS: HdmiSourceDUTTestParam, TestGroupId.HD_RX_DSC_CTS: HdmiSourceDUTTestParam,
TestGroupId.HD_TX_DSC_CTS: HdmiSinkDUTTestParam, TestGroupId.HD_TX_DSC_CTS: HdmiSinkDUTTestParam,
TestGroupId.HD_TX_CONTINUITY: HdmiSinkContinuityDUTTestParam, TestGroupId.HD_TX_CONTINUITY: HdmiSinkContinuityDUTTestParam,
TestGroupId.HD_TX_CABLE_CHECK: HdmiSinkCableCheckTestParam TestGroupId.HD_TX_CABLE_CHECK: HdmiSinkCableCheckTestParam,
TestGroupId.HDMI_HDCP_CTS_1A: HdmiHdcp1ATestParam,
TestGroupId.HDMI_HDCP_CTS_1B: HdmiHdcp1BTestParam,
TestGroupId.HDMI_HDCP_CTS_2C: HdmiHdcp2CTestParam,
TestGroupId.HDMI_HDCP_CTS_3A: HdmiHdcp3ATestParam,
TestGroupId.HDMI_HDCP_CTS_3B: HdmiHdcp3BTestParam,
TestGroupId.HDMI_HDCP_CTS_3C: HdmiHdcp3CTestParam,
TestGroupId.DEMO_DP_2_1_TX_DISPAYID: Dp21SinkTestParam,
TestGroupId.DEMO_DP_2_1_RX_DISPAYID: Dp21SourceDUTTestParam,
TestGroupId.DEMO_DP_2_1_TX_ADAPTIVESYNC: Dp21SinkTestParam,
TestGroupId.DEMO_DP_2_1_RX_ADAPTIVESYNC: Dp21SourceDUTTestParam,
TestGroupId.DEMO_DP_2_1_RX_LL_CTS: Dp21SourceDUTTestParam,
TestGroupId.DEMO_DP_2_1_TX_LL_CTS: Dp21SinkTestParam,
TestGroupId.DEMO_DP_2_1_RX_LTTPR_CTS: Dp21SourceDUTTestParam,
TestGroupId.DEMO_DP_2_1_TX_LTTPR_CTS: Dp21SinkTestParam,
TestGroupId.DEMO_DP_2_1_RX_DSC_CTS: Dp21SourceDUTTestParam,
TestGroupId.DEMO_DP_2_1_TX_DSC_CTS: Dp21SinkTestParam,
TestGroupId.DP_2_1_RX_MST_CTS: Dp21SourceDUTTestParam,
TestGroupId.DP_2_1_BRANCH_MST_CTS: Dp21BranchMSTSourceDUTTestParam
} }
@@ -127,11 +162,17 @@ def test_group_to_merged_group(fw_group: TestGroupId, test_id: int) -> MergedTes
merged_group_id = MergedTestGroups.CRCVideoTest merged_group_id = MergedTestGroups.CRCVideoTest
elif fw_group in [TestGroupId.DP_2_1_RX_LL_CTS, TestGroupId.DP_2_1_RX_DSC_CTS, elif fw_group in [TestGroupId.DP_2_1_RX_LL_CTS, TestGroupId.DP_2_1_RX_DSC_CTS,
TestGroupId.DP_2_1_RX_LTTPR_CTS, TestGroupId.DP_2_1_RX_DISPAYID, TestGroupId.DP_2_1_RX_LTTPR_CTS, TestGroupId.DP_2_1_RX_DISPAYID,
TestGroupId.DP_2_1_RX_ADAPTIVESYNC]: TestGroupId.DP_2_1_RX_ADAPTIVESYNC,
TestGroupId.DEMO_DP_2_1_RX_LL_CTS, TestGroupId.DEMO_DP_2_1_RX_DSC_CTS,
TestGroupId.DEMO_DP_2_1_RX_LTTPR_CTS, TestGroupId.DEMO_DP_2_1_RX_DISPAYID,
TestGroupId.DEMO_DP_2_1_RX_ADAPTIVESYNC, TestGroupId.DP_2_1_RX_MST_CTS]:
merged_group_id = MergedTestGroups.DPRX_128b132b_LL_CTS merged_group_id = MergedTestGroups.DPRX_128b132b_LL_CTS
elif fw_group in [TestGroupId.DP_2_1_TX_LL_CTS, TestGroupId.DP_2_1_TX_DSC_CTS, elif fw_group in [TestGroupId.DP_2_1_TX_LL_CTS, TestGroupId.DP_2_1_TX_DSC_CTS,
TestGroupId.DP_2_1_TX_LTTPR_CTS, TestGroupId.DP_2_1_TX_DISPAYID, TestGroupId.DP_2_1_TX_LTTPR_CTS, TestGroupId.DP_2_1_TX_DISPAYID,
TestGroupId.DP_2_1_TX_ADAPTIVESYNC]: TestGroupId.DP_2_1_TX_ADAPTIVESYNC,
TestGroupId.DEMO_DP_2_1_TX_LL_CTS, TestGroupId.DEMO_DP_2_1_TX_DSC_CTS,
TestGroupId.DEMO_DP_2_1_TX_LTTPR_CTS, TestGroupId.DEMO_DP_2_1_TX_DISPAYID,
TestGroupId.DEMO_DP_2_1_TX_ADAPTIVESYNC]:
merged_group_id = MergedTestGroups.DPTX_128b132b_LL_CTS merged_group_id = MergedTestGroups.DPTX_128b132b_LL_CTS
elif fw_group == TestGroupId.DP_2_1_LTTPR_CTS: elif fw_group == TestGroupId.DP_2_1_LTTPR_CTS:
merged_group_id = MergedTestGroups.LTTPR_128b132b_LL_CTS merged_group_id = MergedTestGroups.LTTPR_128b132b_LL_CTS
@@ -169,6 +210,20 @@ def test_group_to_merged_group(fw_group: TestGroupId, test_id: int) -> MergedTes
merged_group_id = MergedTestGroups.HDTX_CONTINUITY merged_group_id = MergedTestGroups.HDTX_CONTINUITY
elif fw_group == TestGroupId.HD_TX_CABLE_CHECK: elif fw_group == TestGroupId.HD_TX_CABLE_CHECK:
merged_group_id = MergedTestGroups.HDTX_CABLE_CHECK merged_group_id = MergedTestGroups.HDTX_CABLE_CHECK
elif fw_group == TestGroupId.HDMI_HDCP_CTS_1A:
merged_group_id = MergedTestGroups.HDMI_HDCP_CTS_1A
elif fw_group == TestGroupId.HDMI_HDCP_CTS_1B:
merged_group_id = MergedTestGroups.HDMI_HDCP_CTS_1B
elif fw_group == TestGroupId.HDMI_HDCP_CTS_2C:
merged_group_id = MergedTestGroups.HDMI_HDCP_CTS_2C
elif fw_group == TestGroupId.HDMI_HDCP_CTS_3A:
merged_group_id = MergedTestGroups.HDMI_HDCP_CTS_3A
elif fw_group == TestGroupId.HDMI_HDCP_CTS_3B:
merged_group_id = MergedTestGroups.HDMI_HDCP_CTS_3B
elif fw_group == TestGroupId.HDMI_HDCP_CTS_3C:
merged_group_id = MergedTestGroups.HDMI_HDCP_CTS_3C
elif fw_group == TestGroupId.DP_2_1_BRANCH_MST_CTS:
merged_group_id = MergedTestGroups.BRANCH_128b132b_MST_CTS
else: else:
merged_group_id = MergedTestGroups.Unknown merged_group_id = MergedTestGroups.Unknown
return merged_group_id return merged_group_id

View File

@@ -0,0 +1,102 @@
import re
class ReportContentExtractor:
"""
Class `ReportContentExtractor` allows to extract content from test report.
- Extracted EDIDs, DisplayIDs from test report.
"""
__EDID_LINE_PATTERN = re.compile(r"\d{4}.\d{3}.\d{3}:\s+[0-9a-f]{4}:\s+([0-9a-f]{2}\s+)+")
def __init__(self) -> None:
self.__extracting = False
self.__edid_addr = 0
self.__edid_size = 0
self.__edid_ready = False
self.__data = bytearray()
def __start_new_edid(self):
self.__extracting = True
self.__edid_addr = 0
self.__edid_size = 0
self.__edid_ready = False
self.__data = bytearray()
def extract_content_from_report(self, report):
edids = []
for log_line in report.fw_logs.splitlines():
self.__parse_line(log_line)
if self.__edid_ready and self.__edid_size > 0:
edids.append(self.__pop_edid())
return edids
def __parse_line(self, line: str):
if not self.__extracting:
if ("Reference Source reads Sink DUT EDID" in line
or "EDID contents:" in line):
self.__start_new_edid()
return
if len(line) < 18:
return
view = line[18:]
if "I2C AUX WR" in line:
sub_strs = view.split()
if len(sub_strs) <= 3:
return
el = sub_strs[-3]
if "30h" in el:
val = int(sub_strs[-1], 16)
self.__edid_addr = val * 0x100
elif "50h" in el:
val = int(sub_strs[-1], 16)
self.__edid_addr = val
return
if "I2C AUX RD" in line:
sub_strs = view.split()
if len(sub_strs) <= 3:
return
count = int(sub_strs[4])
for i in range(count):
byte_hex = sub_strs[5 + i]
self.__data.append(int(byte_hex, 16))
self.__edid_addr += 1
self.__edid_size = max(self.__edid_size, self.__edid_addr)
return
if self.__EDID_LINE_PATTERN.search(line):
if len(line) < 20:
return
view = line[line.rfind(':') + 1:]
sub_strs = view.split()
for byte_hex in sub_strs:
self.__data.append(int(byte_hex, 16))
self.__edid_addr += 1
self.__edid_size = max(self.__edid_size, self.__edid_addr)
return
self.__edid_ready = True
self.__extracting = False
def __pop_edid(self):
if self.__edid_ready and self.__edid_size > 0:
edid = self.__data[:self.__edid_size].hex()
self.__edid_ready = False
self.__edid_size = 0
self.__data = bytearray()
self.__edid_addr = 0
return edid
return bytearray()

View File

@@ -1,8 +1,10 @@
import os
import platform import platform
from datetime import datetime from datetime import datetime
from enum import IntEnum from enum import IntEnum
from .report_template import * from .report_template import *
from .report_edid_extractor import ReportContentExtractor
class TestResult(IntEnum): class TestResult(IntEnum):
@@ -59,12 +61,48 @@ def replace_additional_info(test_additional_info: TestAdditionalInfo):
return result return result
def to_intel_hex(edid_hex: str) -> str:
data = bytes.fromhex(edid_hex)
lines = []
for offset in range(0, len(data), 16):
chunk = data[offset:offset + 16]
byte_count = len(chunk)
addr_hi = (offset >> 8) & 0xFF
addr_lo = offset & 0xFF
record = [byte_count, addr_hi, addr_lo, 0x00] + list(chunk)
checksum = (~sum(record) + 1) & 0xFF
hex_str = ''.join(f'{b:02X}' for b in record) + f'{checksum:02X}'
lines.append(f':{hex_str}')
lines.append(':00000001FF')
return ('\r\n'.join(lines) + '\r\n').encode('utf-8').hex().upper()
def generate_html_report(path: str, test_additional_info: TestAdditionalInfo, reports: list): def generate_html_report(path: str, test_additional_info: TestAdditionalInfo, reports: list):
result = str() result = str()
head = ReportHead head = ReportHead
head = head.replace("#count#", str((len(reports) + 2))) head = head.replace("#count#", str((len(reports) + 2)))
for index, report in enumerate(reports):
extractor = ReportContentExtractor()
edid_displaid_content = extractor.extract_content_from_report(report)
if edid_displaid_content is None or len(edid_displaid_content) <= 0:
continue
formatted_edids = '["' + '",\n "'.join(edid_displaid_content).upper() + '"]'
formatted_edids_intel_hex = '["' + '",\n "'.join(to_intel_hex(edid) for edid in edid_displaid_content) + '"]'
test_name_formatted = report.test_name.split(' ')[0].replace('.', '_')
if len(edid_displaid_content) > 0:
head = head.replace("#edid_fill#", f"testsEdidData.set({index}, {{name: \"{test_name_formatted}\", data: {formatted_edids}, dataIntelHex: {formatted_edids_intel_hex}}}); \n#edid_fill#")
break
head = head.replace("#edid_fill#", "")
head = head.replace("#jsCode#", report_js)
head = head.replace("#count#", str(len(reports) + 2))
head = head.replace("#fileNamePrefix#", os.path.splitext(os.path.basename(path))[0])
body = ReportBody body = ReportBody
body = body.replace("#device_description#", replace_additional_info(test_additional_info)) body = body.replace("#device_description#", replace_additional_info(test_additional_info))
@@ -105,7 +143,7 @@ def generate_html_report(path: str, test_additional_info: TestAdditionalInfo, re
line = OptionListLine line = OptionListLine
line = line.replace("#number#", str(i + 2)) line = line.replace("#number#", str(i + 2))
line = line.replace("#test_name#", f"{reports[i].group_name} / {reports[i].test_name}") line = line.replace("#test_name#", f"{reports[i].group_name} / {reports[i].test_name}")
line = line.replace("#test_result#", dict_result_2.get(reports[i].test_result)) line = line.replace("#test_result#", dict_result_2.get(reports[i].test_result, "UNKNOWN"))
options_list += line + "\n" options_list += line + "\n"
body = body.replace("#optionList#", options_list) body = body.replace("#optionList#", options_list)
@@ -117,7 +155,7 @@ def generate_html_report(path: str, test_additional_info: TestAdditionalInfo, re
line = line.replace("#handler_number#", str(i + 2)) line = line.replace("#handler_number#", str(i + 2))
line = line.replace("#test_name#", reports[i].test_name) line = line.replace("#test_name#", reports[i].test_name)
line = line.replace("#test_group#", reports[i].group_name) line = line.replace("#test_group#", reports[i].group_name)
line = line.replace("#test_result#", dict_result_2.get(reports[i].test_result)) line = line.replace("#test_result#", dict_result_2.get(reports[i].test_result, "UNKNOWN"))
line = line.replace("#error#", f"{reports[i].error_code}" if reports[i].error_code != 0 else "-") line = line.replace("#error#", f"{reports[i].error_code}" if reports[i].error_code != 0 else "-")
line = line.replace("#ending#", "2" if i % 2 else "") line = line.replace("#ending#", "2" if i % 2 else "")
test_result = dict_result_2.get(reports[i].test_result) test_result = dict_result_2.get(reports[i].test_result)
@@ -153,14 +191,17 @@ def generate_html_report(path: str, test_additional_info: TestAdditionalInfo, re
line = line.replace("#test_number#", f"{i + 1}") line = line.replace("#test_number#", f"{i + 1}")
line = line.replace("#test_group#", reports[i].group_name) line = line.replace("#test_group#", reports[i].group_name)
line = line.replace("#test_name#", reports[i].test_name) line = line.replace("#test_name#", reports[i].test_name)
line = line.replace("#result#", dict_result_2.get(reports[i].test_result)) line = line.replace("#result#", dict_result_2.get(reports[i].test_result, "UNKNOWN"))
line = line.replace("#test_delay#", f"{reports[i].test_delay * 1000}") line = line.replace("#test_delay#", f"{reports[i].test_delay * 1000}")
line = line.replace("#test_parameters#", reports[i].config_info) line = line.replace("#test_parameters#", reports[i].config_info)
line = line.replace("#warning#", "<b>Debug options enabled!</b><br><br>" if reports[i].debug else "")
if reports[i].debug: if "demo" in reports[i].group_name.lower():
warnings = "<b>Demo Report Only - Not valid for DP Logo Certification.</b><br><br>"
elif reports[i].debug:
warnings = "<b>Debug options enabled!</b><br><br>" warnings = "<b>Debug options enabled!</b><br><br>"
line = line.replace("#warning#", warnings)
line = line.replace("#test_log#", escape_html(reports[i].fw_logs)) line = line.replace("#test_log#", escape_html(reports[i].fw_logs))
tables_list += line + "\n" tables_list += line + "\n"

View File

@@ -14,23 +14,29 @@ ReportHead = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\
" PRE.TESTBODY{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Courier New\";font-size: 11pt;color: #000000;}\n" \ " PRE.TESTBODY{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Courier New\";font-size: 11pt;color: #000000;}\n" \
" P.BODYDETAILTEXT{margin-top: 0;margin-bottom: 0;margin-left: 1.4cm;font-weight: medium;font-family: \"Arial\";font-size: 9pt;color: #000000;}\n" \ " P.BODYDETAILTEXT{margin-top: 0;margin-bottom: 0;margin-left: 1.4cm;font-weight: medium;font-family: \"Arial\";font-size: 9pt;color: #000000;}\n" \
" P.CONTENTS SELECT{font-weight: normal;font-family: \"Arial\";font-size: 11pt;width: 98%;margin-top: 0;text-align: left;}\n" \ " P.CONTENTS SELECT{font-weight: normal;font-family: \"Arial\";font-size: 11pt;width: 98%;margin-top: 0;text-align: left;}\n" \
"P.TABLE_HEADERS{background-color: #DCFABC;margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: " \ " P.TABLE_HEADERS{background-color: #DCFABC;margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 12pt;color: #000000;}\n" \
"medium;font-family: \"Arial\";font-size: 12pt;color: #000000;}\n" \
" P.TABLE_LINKS{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 11pt;}\n" \ " P.TABLE_LINKS{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 11pt;}\n" \
" P.TABLE_LINKS2{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 11pt; background-color: #DDDDDD;}\n" \ " P.TABLE_LINKS2{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 11pt; background-color: #DDDDDD;}\n" \
" P.FAILED{margin-top: 0;margin-bottom: 0;background-color: #FFBCBC; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \ " P.FAILED{margin-top: 0;margin-bottom: 0;background-color: #FFBCBC; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \
" P.PASSED{margin-top: 0;margin-bottom: 0;background-color: #BCFFBC; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \ " P.PASSED{margin-top: 0;margin-bottom: 0;background-color: #BCFFBC; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \
" P.SKIPPED{margin-top: 0;margin-bottom: 0;background-color: #BCBCBC; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \ " P.SKIPPED{margin-top: 0;margin-bottom: 0;background-color: #BCBCBC; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \
" P.ERROR_CODE{margin-top: 0;margin-bottom: 0;background-color: #FFFFFF; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \ " P.ERROR_CODE{margin-top: 0;margin-bottom: 0;background-color: #FFFFFF; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \
" P.ABORTED{margin-top: 0;margin-bottom: 0;background-color: #FFFFFF; font-weight: bold;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \
" .TOPBUTTON{display: none; position: fixed; bottom: 20px; right: 30px; z-index: 99; font-size: 18px; border: solid black 1px; outline: none; background-color: #DCFABC; cursor: pointer; padding: 15px; border-radius: 5px;}\n" \ " .TOPBUTTON{display: none; position: fixed; bottom: 20px; right: 30px; z-index: 99; font-size: 18px; border: solid black 1px; outline: none; background-color: #DCFABC; cursor: pointer; padding: 15px; border-radius: 5px;}\n" \
" .DBG_HIGHLIGHT { color: #ff0000;}\n" \
" .flex-container {\n" \
" display: flex;\n" \
" gap: 5px;\n" \
" }\n" \
"</style>\n" \ "</style>\n" \
"<script src=\"https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js\"></script>" \
"<script type=\"text/javascript\">\n" \ "<script type=\"text/javascript\">\n" \
"var base64Content = #configInfo#;\n" \ "var base64Content = #configInfo#;\n" \
"window.current_index = 2;\n" \ "window.current_index = 2;\n" \
"window.min_value = 2;\n" \ "window.min_value = 2;\n" \
"window.max_value = #count# - 1;\n" \ "window.max_value = #count# - 1;\n" \
"window.onscroll = function() {scrollFunction()};\n" \ "window.onscroll = function() {scrollFunction()};\n" \
"let testsEdidData = new Map();\n" \
"#edid_fill#\n\n" \
"function Hide(iElementIndex) { document.getElementById(\"ID\"+iElementIndex).style.display = 'none'; }\n" \ "function Hide(iElementIndex) { document.getElementById(\"ID\"+iElementIndex).style.display = 'none'; }\n" \
"function Show(iElementIndex) { document.getElementById(\"ID\"+iElementIndex).style.display = 'inline'; }\n" \ "function Show(iElementIndex) { document.getElementById(\"ID\"+iElementIndex).style.display = 'inline'; }\n" \
"function HideAll(iDivCount) { for(var i=0;i<iDivCount;i++) { Hide(i); }}\n" \ "function HideAll(iDivCount) { for(var i=0;i<iDivCount;i++) { Hide(i); }}\n" \
@@ -39,7 +45,17 @@ ReportHead = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\
"function GetIndex() { return parseInt(window.current_index, 10); }\n" \ "function GetIndex() { return parseInt(window.current_index, 10); }\n" \
"function HideButtons() { document.getElementById(\"top_buttons\").style.display = 'none'; document.getElementById(\"bottom_buttons\").style.display = 'none'; }\n" \ "function HideButtons() { document.getElementById(\"top_buttons\").style.display = 'none'; document.getElementById(\"bottom_buttons\").style.display = 'none'; }\n" \
"function ShowButtons() { document.getElementById(\"top_buttons\").style.display = 'inline'; document.getElementById(\"bottom_buttons\").style.display = 'inline';} \n" \ "function ShowButtons() { document.getElementById(\"top_buttons\").style.display = 'inline'; document.getElementById(\"bottom_buttons\").style.display = 'inline';} \n" \
"function UpdateButtonsState() { GetIndex() >= window.min_value && window.max_value ? ShowButtons() : HideButtons(); }\n" \ "function ShowHideEdidBtn() {\n" \
" let index = GetIndex();\n" \
" let edidBtnVisibility = 'none';\n" \
" if (index < window.min_value || index > window.max_value) {\n" \
" if (testsEdidData.size > 0) edidBtnVisibility = 'inline';\n }" \
" else if (testsEdidData.has(index)) edidBtnVisibility = 'inline';\n" \
" document.getElementById(\"save_edid_btn\").style.display = edidBtnVisibility;\n" \
" document.getElementById(\"save_edid_intel_hex_btn\").style.display = edidBtnVisibility;\n" \
"}\n" \
"function UpdateButtonsState() { GetIndex() >= window.min_value && window.max_value ? ShowButtons() : HideButtons();\n" \
" ShowHideEdidBtn(); }\n" \
"function ListHandler (iOptionValue) { if(iOptionValue==-1) { ShowAll(#count#); Hide(1); SetIndex(1); UpdateButtonsState(); return; } HideAll(#count#); Show(iOptionValue); SetIndex(iOptionValue > 1 ? iOptionValue : 1); UpdateButtonsState();}\n" \ "function ListHandler (iOptionValue) { if(iOptionValue==-1) { ShowAll(#count#); Hide(1); SetIndex(1); UpdateButtonsState(); return; } HideAll(#count#); Show(iOptionValue); SetIndex(iOptionValue > 1 ? iOptionValue : 1); UpdateButtonsState();}\n" \
"function NextTest() { var index = GetIndex(); ListHandler ((index + 1 > window.max_value) ? (window.min_value) : (index + 1)); }\n" \ "function NextTest() { var index = GetIndex(); ListHandler ((index + 1 > window.max_value) ? (window.min_value) : (index + 1)); }\n" \
"function PreviousTest() { var index = GetIndex(); ListHandler ((index - 1 < window.min_value) ? (window.max_value) : (index - 1)); }\n" \ "function PreviousTest() { var index = GetIndex(); ListHandler ((index - 1 < window.min_value) ? (window.max_value) : (index - 1)); }\n" \
@@ -47,6 +63,7 @@ ReportHead = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\
"function TopFunction() { document.body.scrollTop = 0; document.documentElement.scrollTop = 0;}\n" \ "function TopFunction() { document.body.scrollTop = 0; document.documentElement.scrollTop = 0;}\n" \
"function SaveConfig() { var jsonData = atob(base64Content[GetIndex()-2]); var blob = new Blob([jsonData], { type: 'application/json' }); var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); var currentPageURL = window.location.href; var decodedURL = decodeURIComponent(currentPageURL); link.download = getText() + \".json\"; document.body.appendChild(link); link.click(); document.body.removeChild(link); }\n" \ "function SaveConfig() { var jsonData = atob(base64Content[GetIndex()-2]); var blob = new Blob([jsonData], { type: 'application/json' }); var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); var currentPageURL = window.location.href; var decodedURL = decodeURIComponent(currentPageURL); link.download = getText() + \".json\"; document.body.appendChild(link); link.click(); document.body.removeChild(link); }\n" \
"function getText() { var index = GetIndex(); let a = document.getElementById(\"testlist\"); let option = a.options[index]; return option.text.replace('/', '').replace('>', '').replace(':', '') }\n" \ "function getText() { var index = GetIndex(); let a = document.getElementById(\"testlist\"); let option = a.options[index]; return option.text.replace('/', '').replace('>', '').replace(':', '') }\n" \
"#jsCode#" \
"</script>\n" \ "</script>\n" \
"</head>\n" "</head>\n"
@@ -115,17 +132,23 @@ ReportBody = "<body onload='ListHandler(0);'>\n" \
" <option value=\"0\">Report Summary</option>\n" \ " <option value=\"0\">Report Summary</option>\n" \
" <option value=\"1\">Test Summary</option>\n" \ " <option value=\"1\">Test Summary</option>\n" \
"#optionList#\n" \ "#optionList#\n" \
" <option value=\"-1\">Show everything</option>\n" \ " <option value=\"-1\">Show All</option>\n" \
" </select>\n" \ " </select>\n" \
" </td>\n" \ " </td>\n" \
" </table>\n" \ " </table>\n" \
"<div id=\"top_buttons\" style='margin-left: 12'>\n" \ "<div class='flex-container'>" \
" <div id=\"top_buttons\">\n" \
" <button type=\"button\" onclick=\"PreviousTest()\">Previous</button>\n" \ " <button type=\"button\" onclick=\"PreviousTest()\">Previous</button>\n" \
" <button type=\"button\" onclick=\"ListHandler(1)\">Summary</button>\n" \ " <button type=\"button\" onclick=\"ListHandler(1)\">Summary</button>\n" \
" <button type=\"button\" onclick=\"SaveConfig()\">Save Test Config</button>\n" \ " <button type=\"button\" onclick=\"SaveConfig()\">Save Test Config</button>\n" \
" <button type=\"button\" onclick=\"NextTest()\">Next</button>\n" \ " <button type=\"button\" onclick=\"NextTest()\">Next</button>\n" \
" </div>\n" \
" <div>\n" \
" <button type=\"button\" id=\"save_edid_btn\" onclick=\"SaveEdid()\">Save EDID as bin</button>\n" \
" <button type=\"button\" id=\"save_edid_intel_hex_btn\" onclick=\"SaveEdidIntelHex()\">Save EDID as intel hex</button>\n" \
" <br>\n" \ " <br>\n" \
" </div>\n" \ " </div>\n" \
"</div>\n" \
"<br>\n" \ "<br>\n" \
"<div id=\"ID0\">\n" \ "<div id=\"ID0\">\n" \
"<p class=\"SUBHEADING\" style=\"margin-left: 0; margin-top: 0;\">&nbsp;&nbsp;&nbsp;Report summary</p>\n" \ "<p class=\"SUBHEADING\" style=\"margin-left: 0; margin-top: 0;\">&nbsp;&nbsp;&nbsp;Report summary</p>\n" \
@@ -151,3 +174,134 @@ ReportFooter = "<br><br></pre></div>\n" \
" </p>\n" \ " </p>\n" \
"</body>\n" \ "</body>\n" \
"</html>\n" "</html>\n"
report_js = """
function hexToUint8Array(hex) {
const clean = hex.replace(/\s+/g, '');
const bytes = new Uint8Array(clean.length / 2);
for (let i = 0; i < clean.length; i += 2) {
bytes[i / 2] = parseInt(clean.substr(i, 2), 16);
}
return bytes;
}
function saveBlob(blob, fileName) {
const a = document.createElement('a');
const url = URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
setTimeout(() => {
URL.revokeObjectURL(url);
a.remove();
}, 2000);
}
async function saveZip(files, zipName) {
const zip = new JSZip();
for (const file of files) {
zip.file(file.name, file.data, {
binary: true
});
}
const uint8 = await zip.generateAsync({
type: 'uint8array',
compression: 'STORE'
});
const blob = new Blob([uint8], { type: 'application/zip' });
saveBlob(blob, zipName);
}
async function saveFiles(getFileList, zipName, mimeType) {
const files = getFileList();
if (files.length === 1) {
saveBlob(
new Blob([files[0].data], { type: mimeType }),
files[0].name
);
} else if (files.length > 1) {
await saveZip(files, zipName);
}
}
function getEdidBinFiles() {
let index = GetIndex();
const files = [];
if (index < window.min_value || index > window.max_value) {
for (const [key, value] of testsEdidData) {
for (let i = 0; i < value.data.length; ++i) {
files.push({
name: `#fileNamePrefix#_Test${key}_${value.name}_EDID_${i}.bin`,
data: hexToUint8Array(value.data[i])
});
}
}
} else if (testsEdidData.has(index)) {
const testData = testsEdidData.get(index);
for (let i = 0; i < testData.data.length; ++i) {
files.push({
name: `#fileNamePrefix#_Test_${testData.name}_EDID_${i}.bin`,
data: hexToUint8Array(testData.data[i])
});
}
}
return files;
}
function getEdidIntelHexFiles() {
let index = GetIndex();
const files = [];
if (index < window.min_value || index > window.max_value) {
for (const [key, value] of testsEdidData) {
for (let i = 0; i < value.dataIntelHex.length; ++i) {
files.push({
name: `#fileNamePrefix#_Test${key}_${value.name}_EDID_${i}.hex`,
data: hexToUint8Array(value.dataIntelHex[i])
});
}
}
} else if (testsEdidData.has(index)) {
const testData = testsEdidData.get(index);
for (let i = 0; i < testData.dataIntelHex.length; ++i) {
files.push({
name: `#fileNamePrefix#_Test_${testData.name}_EDID_${i}.hex`,
data: hexToUint8Array(testData.dataIntelHex[i])
});
}
}
return files;
}
async function SaveEdid() {
await saveFiles(
getEdidBinFiles,
'#fileNamePrefix#_EDID_BIN.zip',
'application/octet-stream'
);
}
async function SaveEdidIntelHex() {
await saveFiles(
getEdidIntelHexFiles,
'#fileNamePrefix#_EDID_HEX.zip',
'application/octet-stream'
);
}
"""

View File

@@ -121,6 +121,8 @@ class Param:
self.__process_value(json_obj) self.__process_value(json_obj)
self.__modified = False
def _set_by_bitmask(self, value, bitmask_index): def _set_by_bitmask(self, value, bitmask_index):
if len(self.__bit_field_list) > bitmask_index: if len(self.__bit_field_list) > bitmask_index:
mask = self.__bit_field_list[bitmask_index].mask mask = self.__bit_field_list[bitmask_index].mask
@@ -149,12 +151,17 @@ class Param:
def direct_set_def_value(self, default_value): def direct_set_def_value(self, default_value):
self.__default_value = default_value self.__default_value = default_value
def direct_set_bits_value(self, mask: int, value: int, shift: int = 0):
cleared = self.__default_value & ~mask
self.__default_value = cleared | (value << shift)
@property @property
def default_value(self): def default_value(self):
return self.__default_value return self.__default_value
@default_value.setter @default_value.setter
def default_value(self, default_value): def default_value(self, default_value):
self.__modified = True
if self.__enumeration_variants is not None: if self.__enumeration_variants is not None:
if str(default_value) in self.__enumeration_variants.available_values: if str(default_value) in self.__enumeration_variants.available_values:
self.__default_value = default_value self.__default_value = default_value
@@ -203,6 +210,10 @@ class Param:
else: else:
return 1 return 1
@property
def is_modified(self):
return self.__modified
def __str__(self): def __str__(self):
return f"{self.default_value if self.data_length <= 50 else self.default_value[:50]}" return f"{self.default_value if self.data_length <= 50 else self.default_value[:50]}"
@@ -274,25 +285,28 @@ def param_by_ci_name(json_obj, name: str) -> Param:
return Param({}) return Param({})
def read_image_file(full_filename: str) -> bytearray: def read_image_file(full_filename: str) -> [bytearray, str]:
file_name, file_extension = os.path.splitext(full_filename) file_name, file_extension = os.path.splitext(full_filename)
if file_extension.lower() == '.bin': if file_extension.lower() == '.bin':
with open(full_filename, 'rb') as file: with open(full_filename, 'rb') as file:
image_data = bytearray(file.read()) image_data = bytearray(file.read())
return image_data return image_data, file_extension
elif file_extension.lower() in [".png", '.jpg', ".ppm", '.bmp', '.tif', '.tiff']: elif file_extension.lower() in [".png", '.jpg', ".ppm", '.bmp', '.tif', '.tiff']:
image = Image.open(full_filename) image = Image.open(full_filename)
image = image.convert('RGB') image = image.convert('RGB')
image_data = bytearray(image.tobytes()) image_data = bytearray(image.tobytes())
return image_data return image_data, file_extension
else: else:
return bytearray() return bytearray(), file_extension
def uicl_image_preparation(data: bytearray, params): def uicl_image_preparation(data: bytearray, params, is_prepared):
ref_image = UICL_Image() ref_image = UICL_Image()
ref_param = UICL_ImageParameters() ref_param = UICL_ImageParameters()
if is_prepared:
return list(data)
ref_param.Width = params.image_width ref_param.Width = params.image_width
ref_param.Height = params.image_height ref_param.Height = params.image_height
# VideoPixelTestElementFormat: RGB_16BPC = 20 # VideoPixelTestElementFormat: RGB_16BPC = 20

View File

@@ -58,6 +58,26 @@ class TestGroupId(IntEnum):
HD_TX_DSC_CTS = 0x41 HD_TX_DSC_CTS = 0x41
HD_TX_CONTINUITY = 0x42 HD_TX_CONTINUITY = 0x42
HD_TX_CABLE_CHECK = 0x43 HD_TX_CABLE_CHECK = 0x43
HDMI_HDCP_CTS_1A = 0x44
HDMI_HDCP_CTS_1B = 0x45
HDMI_HDCP_CTS_2C = 0x46
HDMI_HDCP_CTS_3A = 0x47
HDMI_HDCP_CTS_3B = 0x48
HDMI_HDCP_CTS_3C = 0x49
DP_2_1_RX_MST_CTS = 0x4A,
DEMO_DP_2_1_TX_DISPAYID = 0x4B,
DEMO_DP_2_1_RX_DISPAYID = 0x4C,
DEMO_DP_2_1_TX_ADAPTIVESYNC = 0x4D,
DEMO_DP_2_1_RX_ADAPTIVESYNC = 0x4E,
DEMO_DP_2_1_RX_LL_CTS = 0x4F,
DEMO_DP_2_1_TX_LL_CTS = 0x50,
DEMO_DP_2_1_RX_LTTPR_CTS = 0x51,
DEMO_DP_2_1_TX_LTTPR_CTS = 0x52,
DEMO_DP_2_1_RX_DSC_CTS = 0x53,
DEMO_DP_2_1_TX_DSC_CTS = 0x54,
DP_2_1_BRANCH_MST_CTS = 0x55,
HDMI_TIMINGS_TEST_SUIT = 0x59,
DP_TIMINGS_TEST_SUIT = 0x5A,
PIXEL_VIDEO_TEST = 0x3E8 PIXEL_VIDEO_TEST = 0x3E8
HDR10_TEST = -2 HDR10_TEST = -2

View File

@@ -2,9 +2,7 @@ from typing import List
from ctypes import c_uint64, c_uint32, c_uint8 from ctypes import c_uint64, c_uint32, c_uint8
from enum import IntEnum from enum import IntEnum
from UniTAP.libs.lib_tsi.tsi_types import TSI_R_MEMORY_SIZE, TSI_MEMORY_LAYOUT,\ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_MEMORY_BLOCK_INDEX, TSI_MEMORY_RESET_W, TSI_MEMORY_WRITE_W
from UniTAP.libs.lib_tsi.tsi import TSIX_TS_GetConfigItem, TSIX_TS_SetConfigItem
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO from UniTAP.libs.lib_tsi.tsi_io import DeviceIO
@@ -16,31 +14,31 @@ class MemoryManager:
MAX_BLOCK_COUNT = 4 MAX_BLOCK_COUNT = 4
DEFAULT_MEMOTY_ALLOCATION = [534600704, 534600704, 534600704] DEFAULT_MEMOTY_ALLOCATION = [534600704, 534600704, 2048]
RESERVED_MEMORY_BYTES = 8192 * (5120 + 1) * 4 + 0x80000 RESERVED_MEMORY_BYTES = 8192 * (5120 + 1) * 4 + 0x80000
def __init__(self, io: DeviceIO): def __init__(self, io: DeviceIO):
self.__io = io self.__io = io
def get_total_memory(self) -> int: def get_total_memory(self) -> int:
result = self.__io.get(TSI_R_MEMORY_SIZE, c_uint64)[1] result = self.__io.get(ci.TSI_R_MEMORY_SIZE, c_uint64)[1]
return result return result
def set_memory_layout(self, layout: List[int]): def set_memory_layout(self, layout: List[int]):
self.__io.set(TSI_MEMORY_LAYOUT, layout, c_uint64, data_count=len(layout)) self.__io.set(ci.TSI_MEMORY_LAYOUT, layout, c_uint64, data_count=len(layout))
def get_memory_layout(self) -> List[int]: def get_memory_layout(self) -> List[int]:
return self.__io.get(TSI_MEMORY_LAYOUT, c_uint64, self.MAX_BLOCK_COUNT) return list(self.__io.get(ci.TSI_MEMORY_LAYOUT, c_uint64, self.MAX_BLOCK_COUNT)[1])
def set_memory_block_index(self, index: MemoryOwner): def set_memory_block_index(self, index: MemoryOwner):
self.__io.set(TSI_MEMORY_BLOCK_INDEX, index.value) self.__io.set(ci.TSI_MEMORY_BLOCK_INDEX, index.value)
def make_default(self): def make_default(self):
self.__io.set(TSI_MEMORY_LAYOUT, self.DEFAULT_MEMOTY_ALLOCATION, c_uint64, self.__io.set(ci.TSI_MEMORY_LAYOUT, self.DEFAULT_MEMOTY_ALLOCATION, c_uint64,
data_count=len(self.DEFAULT_MEMOTY_ALLOCATION)) data_count=len(self.DEFAULT_MEMOTY_ALLOCATION))
def reset(self): def reset(self):
self.__io.set(TSI_MEMORY_RESET_W, 0) self.__io.set(ci.TSI_MEMORY_RESET_W, 0)
def memory_write(self, data, size): def memory_write(self, data, size):
self.__io.set(TSI_MEMORY_WRITE_W, bytearray(data), data_type=c_uint8, data_count=size) self.__io.set(ci.TSI_MEMORY_WRITE_W, bytearray(data), data_type=c_uint8, data_count=size)

View File

@@ -1,7 +1,7 @@
import platform import platform
import warnings import warnings
from UniTAP.libs.lib_tsi.tsi_types import TSI_OPF_CALLBACK_STRUCT, TSI_OPF_RETURN_CODE_ABORT import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO from UniTAP.libs.lib_tsi.tsi_io import DeviceIO
from UniTAP.utils import tsi_logging as logging from UniTAP.utils import tsi_logging as logging
from .handlers import OpfHandlerBase, OpfHandlerDefault from .handlers import OpfHandlerBase, OpfHandlerDefault
@@ -9,11 +9,11 @@ from .handlers import OpfHandlerBase, OpfHandlerDefault
if platform.system() == 'Windows': if platform.system() == 'Windows':
from ctypes import c_int, POINTER, c_void_p, WINFUNCTYPE from ctypes import c_int, POINTER, c_void_p, WINFUNCTYPE
OPF_CALLBACK_TYPE = WINFUNCTYPE(c_int, POINTER(TSI_OPF_CALLBACK_STRUCT), c_void_p) OPF_CALLBACK_TYPE = WINFUNCTYPE(c_int, POINTER(ci.TSI_OPF_CALLBACK_STRUCT), c_void_p)
else: else:
from ctypes import c_int, POINTER, c_void_p, CFUNCTYPE from ctypes import c_int, POINTER, c_void_p, CFUNCTYPE
OPF_CALLBACK_TYPE = CFUNCTYPE(c_int, POINTER(TSI_OPF_CALLBACK_STRUCT), c_void_p) OPF_CALLBACK_TYPE = CFUNCTYPE(c_int, POINTER(ci.TSI_OPF_CALLBACK_STRUCT), c_void_p)
class OperatorFeedbackHandler: class OperatorFeedbackHandler:
@@ -33,8 +33,8 @@ class OperatorFeedbackHandler:
self.__handler = OpfHandlerDefault() self.__handler = OpfHandlerDefault()
def __get_callback(self): def __get_callback(self):
def ofp_impl(_struct: POINTER(TSI_OPF_CALLBACK_STRUCT), context_ptr: c_void_p): def ofp_impl(_struct: POINTER(ci.TSI_OPF_CALLBACK_STRUCT), context_ptr: c_void_p):
opf_struct: TSI_OPF_CALLBACK_STRUCT = _struct.contents opf_struct: ci.TSI_OPF_CALLBACK_STRUCT = _struct.contents
logging.debug(f"Received OPF dialog with ID: {opf_struct.id()}, Session: {opf_struct.session_id()}.") logging.debug(f"Received OPF dialog with ID: {opf_struct.id()}, Session: {opf_struct.session_id()}.")
try: try:
@@ -46,7 +46,7 @@ class OperatorFeedbackHandler:
opf_struct.parameters()) opf_struct.parameters())
except BaseException as e: except BaseException as e:
warnings.warn(f"OPF Dialog {opf_struct.id()} was aborted due an exception. Exception: {e}") warnings.warn(f"OPF Dialog {opf_struct.id()} was aborted due an exception. Exception: {e}")
return opf_struct.write_opf_result(TSI_OPF_RETURN_CODE_ABORT) return opf_struct.write_opf_result(ci.TSI_OPF_RETURN_CODE_ABORT)
return ofp_impl return ofp_impl

View File

@@ -30,6 +30,9 @@ class OpfHandlerInternal(OpfHandlerBase):
19: OPFFunctions.opf_19_handler, 19: OPFFunctions.opf_19_handler,
20: OPFFunctions.opf_20_handler, 20: OPFFunctions.opf_20_handler,
21: OPFFunctions.opf_21_handler, 21: OPFFunctions.opf_21_handler,
22: OPFFunctions.opf_22_handler,
23: OPFFunctions.opf_23_handler,
24: OPFFunctions.opf_24_handler,
101: OPFFunctions.opf_101_handler, 101: OPFFunctions.opf_101_handler,
102: OPFFunctions.opf_102_handler, 102: OPFFunctions.opf_102_handler,
103: OPFFunctions.opf_103_handler, 103: OPFFunctions.opf_103_handler,
@@ -37,6 +40,7 @@ class OpfHandlerInternal(OpfHandlerBase):
105: OPFFunctions.opf_105_handler, 105: OPFFunctions.opf_105_handler,
106: OPFFunctions.opf_106_handler, 106: OPFFunctions.opf_106_handler,
107: OPFFunctions.opf_107_handler, 107: OPFFunctions.opf_107_handler,
108: OPFFunctions.opf_108_handler,
120: OPFFunctions.opf_120_handler, 120: OPFFunctions.opf_120_handler,
121: OPFFunctions.opf_121_handler, 121: OPFFunctions.opf_121_handler,
122: OPFFunctions.opf_122_handler, 122: OPFFunctions.opf_122_handler,
@@ -47,6 +51,8 @@ class OpfHandlerInternal(OpfHandlerBase):
143: OPFFunctions.opf_143_handler, 143: OPFFunctions.opf_143_handler,
144: OPFFunctions.opf_144_handler, 144: OPFFunctions.opf_144_handler,
145: OPFFunctions.opf_145_handler, 145: OPFFunctions.opf_145_handler,
146: OPFFunctions.opf_146_handler,
147: OPFFunctions.opf_147_handler,
150: OPFFunctions.opf_150_handler, 150: OPFFunctions.opf_150_handler,
161: OPFFunctions.opf_161_handler 161: OPFFunctions.opf_161_handler
} }

View File

@@ -1,4 +1,5 @@
import copy import copy
import math
import re import re
import threading import threading
import time import time
@@ -17,22 +18,19 @@ from UniTAP.utils.function_wrapper import function_scheduler
from UniTAP.libs.lib_dscl.dscl import DSC_TOOLS_FOLDER, DSCL_ExtractPPSFromData, DSCL_Encode, DSCL_Decode from UniTAP.libs.lib_dscl.dscl import DSC_TOOLS_FOLDER, DSCL_ExtractPPSFromData, DSCL_Encode, DSCL_Decode
from UniTAP.libs.lib_dscl.dscl_utils import calculate_slice_size, dscl_image_to_dsc_vf from UniTAP.libs.lib_dscl.dscl_utils import calculate_slice_size, dscl_image_to_dsc_vf
from UniTAP.libs.lib_pdl.pdl import generate_pattern_as_vf, PatternType from UniTAP.libs.lib_pdl.pdl import generate_pattern_as_vf, PatternType
from UniTAP.libs.lib_tsi.tsi_types import TSI_MEMORY_WRITE_W, TSI_MEMORY_BLOCK_INDEX, TSI_MEMORY_LAYOUT, \ import UniTAP.libs.lib_tsi.tsi as tsi
TSI_DP20_SINKCTS_SUPPORT_444CRC, TSI_DP14_SINKCTS_SUPPORT_444CRC
from UniTAP.libs.lib_tsi.tsi_private_types import TSI_DSC_MEMORY_BLOCK, TSI_DSC_DATA_SIZE, \
TSI_DSC_TX_CRC, TSI_DPRX_DSC_TEST_CRC, TSI_SELECT_SUITE
from UniTAP.libs.lib_tsi.tsi import TSIX_TS_SetConfigItem, TSIX_TS_GetConfigItem
from ctypes import c_uint64, c_uint32 from ctypes import c_uint64, c_uint32
from UniTAP.libs.lib_tsi import TSI_OPF_RETURN_CODE_ABORT, TSI_OPF_RETURN_CODE_PASS, \
TSI_OPF_RETURN_CODE_PROCEED, TSI_OPF_RETURN_CODE_FAIL, TSI_OPF_RETURN_CODE_AUTO_CLOSED import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
import UniTAP.libs.lib_tsi.tsi_types as ci
class OPFDialogAnswer(IntEnum): class OPFDialogAnswer(IntEnum):
ABORT = TSI_OPF_RETURN_CODE_ABORT ABORT = ci.TSI_OPF_RETURN_CODE_ABORT
PASS = TSI_OPF_RETURN_CODE_PASS PASS = ci.TSI_OPF_RETURN_CODE_PASS
PROCEED = TSI_OPF_RETURN_CODE_PROCEED PROCEED = ci.TSI_OPF_RETURN_CODE_PROCEED
FAIL = TSI_OPF_RETURN_CODE_FAIL FAIL = ci.TSI_OPF_RETURN_CODE_FAIL
NOTHING = TSI_OPF_RETURN_CODE_AUTO_CLOSED NOTHING = ci.TSI_OPF_RETURN_CODE_AUTO_CLOSED
class OPFFunctions: class OPFFunctions:
@@ -380,7 +378,16 @@ class OPFFunctions:
for i in range(iterations): for i in range(iterations):
vf = capture_frame(dprx) vf = capture_frame(dprx)
vf = video_frame_to_ci(vf, vf.color_info, OPFFunctions.g_vf.data_info)
if OPFFunctions.g_vf is None:
data_info = DataInfo()
data_info.packing = DataInfo.Packing.P_PACKED
data_info.component_order = DataInfo.ComponentOrder.CO_RGB
data_info.alignment = DataInfo.Alignment.A_LSB
else:
data_info = OPFFunctions.g_vf.data_info
vf = video_frame_to_ci(vf, vf.color_info, data_info)
if vf is not None and len(vf.data) > 0: if vf is not None and len(vf.data) > 0:
if OPFFunctions.g_vf is not None: if OPFFunctions.g_vf is not None:
@@ -390,11 +397,88 @@ class OPFFunctions:
else: else:
if OPFFunctions.g_vf.data in vf.data: if OPFFunctions.g_vf.data in vf.data:
return OPFDialogAnswer.PASS return OPFDialogAnswer.PASS
else:
return OPFDialogAnswer.PASS
return OPFDialogAnswer.FAIL return OPFDialogAnswer.FAIL
@staticmethod @staticmethod
def opf_13_handler(dptx, dprx, message: str) -> OPFDialogAnswer: def opf_13_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
return OPFFunctions.opf_pass_handler(dptx, dprx, message) audio_mode = dptx.ag.audio_mode
dptx.ag.setup(audio_mode, UniTAP.AudioPattern.SignalPing, 2000, 100)
if not dptx.ag.apply():
return OPFDialogAnswer.FAIL
dprx.audio_capturer.start(m_sec=10000)
dprx.audio_capturer.stop()
result = dprx.audio_capturer.capture_result
sample_size_bytes = int(math.ceil(result.audio_mode.bits / 8))
samples = {}
for channel in range(result.audio_mode.channel_count):
samples[channel] = []
for frame in result.buffer:
frame: UniTAP.AudioFrameData
sample_per_channel = int(len(frame.data) / sample_size_bytes / result.audio_mode.channel_count)
for sample_index in range(sample_per_channel):
for channel in range(result.audio_mode.channel_count):
sample_offset = (sample_index * sample_size_bytes * result.audio_mode.channel_count) + (
channel * sample_size_bytes)
sample_value = int.from_bytes(frame.data[sample_offset:sample_offset + sample_size_bytes], "little",
signed=True)
samples[channel].append(sample_value)
logging.info(f"Total samples per channel 0: {len(samples[0])}")
def find_next_transition(start_pos: int, sample_list: list):
for pos in range(start_pos + 1, len(sample_list) - 1):
previous_value = sample_list[pos - 1]
current_value = sample_list[pos]
next_value = sample_list[pos + 1]
if previous_value == 0 and current_value == 0 and next_value != 0:
return "burst", pos + 1
elif previous_value != 0 and current_value == 0 and next_value == 0:
return "silence", pos + 1
return None, -1
transition_type, transition_pos = find_next_transition(0, samples[0])
if transition_type is None:
logging.warn("OPF 13: No transitions were found. Audio may be invalid.")
return OPFDialogAnswer.FAIL
#
# Cut beginning of captured data to start exactly with transition.
#
samples[0] = samples[0][transition_pos:]
chunk_info_list = []
transition_pos = 0
while (t_info := find_next_transition(transition_pos, samples[0])) != (None, -1):
chuck_size = t_info[1] - transition_pos + 1
chunk_length_ms = int(chuck_size / result.audio_mode.sample_rate * 1000)
logging.info(f"Chuck size: {chuck_size}")
logging.info(f"Chuck length: {chunk_length_ms}ms")
chunk_info_list.append((t_info[0], chuck_size, chunk_length_ms))
transition_pos = t_info[1]
valid = True
for chunk in chunk_info_list:
if chunk[2] not in range(245, 255):
valid = False
break
logging.info(f"Chunk validation: {'PASS' if valid else 'FAIL'}")
logging.info(f"Chunks: {chunk_info_list}")
return OPFDialogAnswer.PASS if valid else OPFDialogAnswer.FAIL
@staticmethod @staticmethod
def opf_14_handler(dptx, dprx, message: str) -> OPFDialogAnswer: def opf_14_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
@@ -553,10 +637,10 @@ class OPFFunctions:
try: try:
if not OPFFunctions.check_video(dprx): if not OPFFunctions.check_video(dprx):
print('Video is not available.') logging.error('Video is not available.')
return OPFDialogAnswer.ABORT return OPFDialogAnswer.ABORT
except BaseException as e: except BaseException as e:
print(e) logging.error(e)
return OPFDialogAnswer.ABORT return OPFDialogAnswer.ABORT
return OPFDialogAnswer.PROCEED return OPFDialogAnswer.PROCEED
@@ -582,16 +666,10 @@ class OPFFunctions:
def opf_19_handler(dptx, dprx, use_3tap) -> OPFDialogAnswer: def opf_19_handler(dptx, dprx, use_3tap) -> OPFDialogAnswer:
if not OPFFunctions.check_dprx(dprx): if not OPFFunctions.check_dprx(dprx):
return OPFDialogAnswer.ABORT return OPFDialogAnswer.FAIL
# check DSC state # check DSC state
if not dprx.link.capabilities.link_caps_status().dsc: if not dprx.link.capabilities.link_caps_status().dsc:
return OPFDialogAnswer.ABORT
incorrect_crc = [0xFFFF, 0xFFFF, 0xFFFF, 0x1111, 0x1111, 0x1111]
def load_dsc(handle: int, values: list) -> OPFDialogAnswer:
TSIX_TS_SetConfigItem(handle, TSI_DPRX_DSC_TEST_CRC, values, data_count=6)
return OPFDialogAnswer.FAIL return OPFDialogAnswer.FAIL
# TODO: Need to change on public interface. Temporary solution. # TODO: Need to change on public interface. Temporary solution.
@@ -599,19 +677,13 @@ class OPFFunctions:
__getattribute__('_MemoryManager__io'). \ __getattribute__('_MemoryManager__io'). \
__getattribute__('device_handle') __getattribute__('device_handle')
iterations = 5 def upload_dut_and_te_crc(handle: int, values: list) -> OPFDialogAnswer:
if tsi.TSIX_TS_SetConfigItem(handle, p_ci.TSI_DPRX_DSC_TEST_CRC, values, data_count=6) > ci.TSI_SUCCESS:
return OPFDialogAnswer.PROCEED
else:
return OPFDialogAnswer.FAIL
for i in range(iterations): def create_reference_image(video_frame, crc_value: list):
# capture frame
try:
dprx.video_capturer.start(frames_count=1)
vf = dprx.video_capturer.capture_result.buffer[-1]
dprx.video_capturer.stop()
except BaseException:
dprx.video_capturer.stop()
return load_dsc(device_handle, incorrect_crc)
def create_reference_image(video_frame, crc_values: list):
try: try:
pps_info = DSCL_ExtractPPSFromData(video_frame.data) pps_info = DSCL_ExtractPPSFromData(video_frame.data)
except BaseException: except BaseException:
@@ -684,34 +756,46 @@ class OPFFunctions:
reference_image_crc = UICL_CRC16() reference_image_crc = UICL_CRC16()
try: try:
res = UICL_CalculateCRC16(dsc_decoded_uicl_image, reference_image_crc) res = UICL_CalculateCRC16(dsc_decoded_uicl_image, reference_image_crc)
if res < UICL_SUCCESS: if res >= UICL_SUCCESS:
crc_values.extend([0xFFFF, 0xFFFF, 0xFFFF]) crc = [reference_image_crc.R, reference_image_crc.G, reference_image_crc.B]
logging.info(f"TE successfully generated image from DUT's PPS and calculated CRC: {crc}")
crc_value[:] = crc
else: else:
crc_values.extend([reference_image_crc.R, reference_image_crc.G, reference_image_crc.B]) logging.error(f"TE failed to generate image from DUT's PPS without exception with error: {res}")
except BaseException: except BaseException as exc:
return logging.error(f"TE failed to generated image fro DUT's PPS due an exception: {exc}")
def decompress_dsc(video_frame, crc_values: list): def decompress_dsc(video_frame, crc_value: list):
decoded_captured_vf = decode_video_frame(video_frame) decoded_captured_vf = decode_video_frame(video_frame)
uicl_decoded_image_2 = image_from_vf(decoded_captured_vf) uicl_decoded_image_2 = image_from_vf(decoded_captured_vf)
decompressed_image_crc = UICL_CRC16() decompressed_image_crc = UICL_CRC16()
try: try:
res = UICL_CalculateCRC16(uicl_decoded_image_2, decompressed_image_crc) res = UICL_CalculateCRC16(uicl_decoded_image_2, decompressed_image_crc)
if res < UICL_SUCCESS: if res >= UICL_SUCCESS:
crc_values.extend([0x1111, 0x1111, 0x1111]) crc = [decompressed_image_crc.R, decompressed_image_crc.G, decompressed_image_crc.B]
logging.info(f"DUT's DSC CRC successfully calculated: {crc}")
crc_value[:] = crc
else: else:
crc_values.extend([decompressed_image_crc.R, decompressed_image_crc.G, logging.error(f"DUT's DSC CRC calculation failed, without exception: {res}")
decompressed_image_crc.B]) except BaseException as exc:
except BaseException: logging.error(f"Failed to decompress DUT's DSC image due an exception: {exc}")
return
reference_image_crc_values = [] reference_image_crc_values = [0x0BAD, 0x0BAD, 0x0BAD]
decompressed_image_crc_values = [] decompressed_image_crc_values = [0xBAD0, 0xBAD0, 0xBAD0]
max_frames_to_validate = 5
try:
dprx.video_capturer.start()
for frame_idx in range(1, max_frames_to_validate + 1):
try:
logging.info(f"Iteration {frame_idx}. Start frame capturing.")
frame = dprx.video_capturer.pop_element()
thread_create_reference_image = threading.Thread(target=create_reference_image, thread_create_reference_image = threading.Thread(target=create_reference_image,
args=(vf, reference_image_crc_values)) args=(frame, reference_image_crc_values))
thread_decompressed_image = threading.Thread(target=decompress_dsc, thread_decompressed_image = threading.Thread(target=decompress_dsc,
args=(vf, decompressed_image_crc_values)) args=(frame, decompressed_image_crc_values))
thread_create_reference_image.start() thread_create_reference_image.start()
thread_decompressed_image.start() thread_decompressed_image.start()
@@ -719,20 +803,27 @@ class OPFFunctions:
thread_create_reference_image.join() thread_create_reference_image.join()
thread_decompressed_image.join() thread_decompressed_image.join()
if len(reference_image_crc_values) > 0 and len(decompressed_image_crc_values) > 0 and \ if reference_image_crc_values == decompressed_image_crc_values:
((reference_image_crc_values == decompressed_image_crc_values) or logging.info(f"Frame {frame_idx} is OK.")
(reference_image_crc_values != decompressed_image_crc_values and (i == iterations - 1))): break
# Write crc to register else:
load_dsc(device_handle, [decompressed_image_crc_values[0], te_crc_str = [f"0x{value:04X}" for value in reference_image_crc_values]
decompressed_image_crc_values[1], dut_crc_str = [f"0x{value:04X}" for value in decompressed_image_crc_values]
decompressed_image_crc_values[2], logging.info(f"Frame {frame_idx} is NOT OK. "
reference_image_crc_values[0], f"TE CRC: {te_crc_str}. "
reference_image_crc_values[1], f"DUT CRC: {dut_crc_str}.")
reference_image_crc_values[2]])
return OPFDialogAnswer.PROCEED except BaseException as exception:
logging.error(f"Frame {frame_idx} is NOT OK. Exception: {exception}")
return load_dsc(device_handle, incorrect_crc) except BaseException as exc:
logging.error(f"Failed to process OPF 19 due an exception: {exc}")
finally:
dprx.video_capturer.stop()
logging.info(f"Capturing has been stopped.")
combined_crc_list = decompressed_image_crc_values + reference_image_crc_values
logging.info("OPF 19 finished.")
return upload_dut_and_te_crc(device_handle, combined_crc_list)
@staticmethod @staticmethod
def opf_20_handler(dptx, dprx, res_x, res_y, res_frate, res_bpc, col_format, col_range, col_yc, tim_std, def opf_20_handler(dptx, dprx, res_x, res_y, res_frate, res_bpc, col_format, col_range, col_yc, tim_std,
@@ -742,6 +833,14 @@ class OPFFunctions:
logging.info((res_x, res_y, res_frate, res_bpc, col_format, col_range, col_yc, tim_std, pattern_name)) logging.info((res_x, res_y, res_frate, res_bpc, col_format, col_range, col_yc, tim_std, pattern_name))
if res_x == 0 and res_y == 0:
logging.info("Received request to disable PG.")
dptx.pg.set_pattern(pattern=UniTAP.VideoPattern.Disabled)
res = dptx.pg.apply()
logging.info(f"PG perform apply. Success: {res}.")
return UniTAP.OPFDialogAnswer.PASS if res else UniTAP.OPFDialogAnswer.FAIL
if pattern_name is not None: if pattern_name is not None:
if pattern_name == 'No Video': if pattern_name == 'No Video':
pattern_name = VideoPattern.Disabled pattern_name = VideoPattern.Disabled
@@ -823,6 +922,18 @@ class OPFFunctions:
return OPFDialogAnswer.ABORT return OPFDialogAnswer.ABORT
return OPFDialogAnswer.PROCEED return OPFDialogAnswer.PROCEED
@staticmethod
def opf_22_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
return OPFDialogAnswer.PROCEED
@staticmethod
def opf_23_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
return OPFDialogAnswer.PROCEED
@staticmethod
def opf_24_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
return OPFDialogAnswer.PROCEED
@staticmethod @staticmethod
def opf_101_handler(dptx, dprx, message: str) -> OPFDialogAnswer: def opf_101_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
if not OPFFunctions.check_dprx(dprx): if not OPFFunctions.check_dprx(dprx):
@@ -834,7 +945,7 @@ class OPFFunctions:
return UniTAP.OPFDialogAnswer.PASS if len( return UniTAP.OPFDialogAnswer.PASS if len(
dprx.audio_capturer.capture_result.buffer) > 0 else UniTAP.OPFDialogAnswer.FAIL dprx.audio_capturer.capture_result.buffer) > 0 else UniTAP.OPFDialogAnswer.FAIL
except BaseException as e: except BaseException as e:
print(f"Cannot capture audio. Error: {e}") logging.error(f"Cannot capture audio. Error: {e}")
return UniTAP.OPFDialogAnswer.FAIL return UniTAP.OPFDialogAnswer.FAIL
@staticmethod @staticmethod
@@ -926,7 +1037,7 @@ class OPFFunctions:
OPFFunctions.g_h_slice_size = h_slice_size OPFFunctions.g_h_slice_size = h_slice_size
OPFFunctions.g_v_slice_size = v_slice_size OPFFunctions.g_v_slice_size = v_slice_size
res, suite_id = TSIX_TS_GetConfigItem(device_handle, TSI_SELECT_SUITE, c_uint32) res, suite_id = tsi.TSIX_TS_GetConfigItem(device_handle, p_ci.TSI_SELECT_SUITE, c_uint32)
if res > 0: if res > 0:
suite_id = TestGroupId(suite_id) suite_id = TestGroupId(suite_id)
else: else:
@@ -936,10 +1047,12 @@ class OPFFunctions:
try: try:
if suite_id in [TestGroupId.DP_TX_LL_CTS, TestGroupId.DP_TX_LL_CTS_DSC, if suite_id in [TestGroupId.DP_TX_LL_CTS, TestGroupId.DP_TX_LL_CTS_DSC,
TestGroupId.DP_TX_DISPLAYID, TestGroupId.DP_TX_ADAPTIVESYNC]: TestGroupId.DP_TX_DISPLAYID, TestGroupId.DP_TX_ADAPTIVESYNC]:
res, is_simple_as_444 = TSIX_TS_GetConfigItem(device_handle, TSI_DP14_SINKCTS_SUPPORT_444CRC, c_uint32) res, is_simple_as_444 = tsi.TSIX_TS_GetConfigItem(device_handle, ci.TSI_DP14_SINKCTS_SUPPORT_444CRC,
c_uint32)
elif suite_id in [TestGroupId.DP_2_1_TX_LL_CTS, TestGroupId.DP_2_1_TX_DSC_CTS, elif suite_id in [TestGroupId.DP_2_1_TX_LL_CTS, TestGroupId.DP_2_1_TX_DSC_CTS,
TestGroupId.DP_2_1_TX_DISPAYID, TestGroupId.DP_2_1_TX_ADAPTIVESYNC]: TestGroupId.DP_2_1_TX_DISPAYID, TestGroupId.DP_2_1_TX_ADAPTIVESYNC]:
res, is_simple_as_444 = TSIX_TS_GetConfigItem(device_handle, TSI_DP20_SINKCTS_SUPPORT_444CRC, c_uint32) res, is_simple_as_444 = tsi.TSIX_TS_GetConfigItem(device_handle, ci.TSI_DP20_SINKCTS_SUPPORT_444CRC,
c_uint32)
except BaseException as e: except BaseException as e:
pass pass
@@ -964,18 +1077,18 @@ class OPFFunctions:
OPFFunctions.g_vm = copy.deepcopy(encoded_video_frame) OPFFunctions.g_vm = copy.deepcopy(encoded_video_frame)
TSIX_TS_SetConfigItem(device_handle, TSI_MEMORY_LAYOUT, len(encoded_video_frame.data), c_uint64) tsi.TSIX_TS_SetConfigItem(device_handle, ci.TSI_MEMORY_LAYOUT, len(encoded_video_frame.data), c_uint64)
TSIX_TS_SetConfigItem(device_handle, TSI_MEMORY_BLOCK_INDEX, 0, data_size=4) tsi.TSIX_TS_SetConfigItem(device_handle, ci.TSI_MEMORY_BLOCK_INDEX, 0, data_size=4)
TSIX_TS_SetConfigItem(device_handle, TSI_MEMORY_WRITE_W, bytearray(encoded_video_frame.data), tsi.TSIX_TS_SetConfigItem(device_handle, ci.TSI_MEMORY_WRITE_W, bytearray(encoded_video_frame.data),
data_type=c_uint8, data_type=c_uint8,
data_count=len(encoded_video_frame.data)) data_count=len(encoded_video_frame.data))
TSIX_TS_SetConfigItem(device_handle, TSI_DSC_MEMORY_BLOCK, 0) tsi.TSIX_TS_SetConfigItem(device_handle, p_ci.TSI_DSC_MEMORY_BLOCK, 0)
TSIX_TS_SetConfigItem(device_handle, TSI_DSC_DATA_SIZE, len(encoded_video_frame.data)) tsi.TSIX_TS_SetConfigItem(device_handle, p_ci.TSI_DSC_DATA_SIZE, len(encoded_video_frame.data))
decoded_vf = decode_video_frame(encoded_video_frame) decoded_vf = decode_video_frame(encoded_video_frame)
crc0, crc1, crc2 = calculate_crc(decoded_vf) crc0, crc1, crc2 = calculate_crc(decoded_vf)
TSIX_TS_SetConfigItem(device_handle, TSI_DSC_TX_CRC, [crc0, crc1, crc2], data_count=3) tsi.TSIX_TS_SetConfigItem(device_handle, p_ci.TSI_DSC_TX_CRC, [crc0, crc1, crc2], data_count=3)
return OPFDialogAnswer.PROCEED return OPFDialogAnswer.PROCEED
@@ -1020,14 +1133,17 @@ class OPFFunctions:
vf.data[pps_size + slice_size:slice_size * 2]: vf.data[pps_size + slice_size:slice_size * 2]:
return OPFDialogAnswer.PASS return OPFDialogAnswer.PASS
else: else:
print(f"Frame {i + 1}: Image looks good and distortion free for slice #2. It is wrong.") logging.info(
f"Frame {i + 1}: Image looks good and distortion free for slice #2. It is wrong.")
else: else:
print( logging.info(
f"Frame {i + 1}: Image does not look good and distortion free for slice #4. It is wrong.") f"Frame {i + 1}: Image does not look good and distortion free for slice #4. It is wrong.")
else: else:
print(f"Frame {i + 1}: Image does not look good and distortion free for slice #3. It is wrong.") logging.info(
f"Frame {i + 1}: Image does not look good and distortion free for slice #3. It is wrong.")
else: else:
print(f"Frame {i + 1}: Image does not look good and distortion free for slice #1. It is wrong.") logging.info(
f"Frame {i + 1}: Image does not look good and distortion free for slice #1. It is wrong.")
return OPFDialogAnswer.FAIL return OPFDialogAnswer.FAIL
@@ -1043,6 +1159,66 @@ class OPFFunctions:
def opf_107_handler(dptx, dprx, message: str) -> OPFDialogAnswer: def opf_107_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
return OPFFunctions.opf_pass_handler(dptx, dprx, message) return OPFFunctions.opf_pass_handler(dptx, dprx, message)
@staticmethod
def opf_108_handler(dptx, dprx, *args) -> OPFDialogAnswer:
if not OPFFunctions.check_dprx(dprx):
return OPFDialogAnswer.ABORT
if len(args) == 4:
audio_pattern, sample_rate, sample_size, ch_count = args
else:
audio_pattern, sample_rate, sample_size, ch_count = None, None, None, None
logging.info(audio_pattern, sample_rate, sample_size, ch_count)
try:
dprx.audio_capturer.start(10)
dprx.audio_capturer.stop()
if len(dprx.audio_capturer.capture_result.buffer) <= 0:
logging.info("Audio buffer is empty")
return UniTAP.OPFDialogAnswer.FAIL
if audio_pattern is None:
logging.info("Default 108 OPF, check audio availability")
return UniTAP.OPFDialogAnswer.PASS if len(dprx.audio_capturer.capture_result.buffer) > 0 else \
UniTAP.OPFDialogAnswer.FAIL
def check_audio_frame(index, ch_count, sample_freq, sample_size) -> bool:
frame = dprx.audio_capturer.capture_result.buffer[index]
_data = list(frame.data)
length = len(_data)
zero_count = _data.count(0)
is_only_zero = zero_count == length
active_channel_count = OPFFunctions.get_active_channel_count(raw_data=frame.data,
bit_depths=[frame.sample_size],
channel_range=[frame.channel_count],
expected_channels=ch_count
)
logging.info(f"Frame index[{index}]: Len - {length}, Zero count - {zero_count}, "
f"Reference channel count - {ch_count}, Captured active channel count - {active_channel_count}, "
f"Reference sample rate - {sample_freq}, Captured sample rate - {frame.sample_rate}\n")
return not is_only_zero and \
active_channel_count == ch_count and \
frame.sample_rate == sample_freq and \
frame.sample_size == sample_size
buffer_len = len(dprx.audio_capturer.capture_result.buffer)
state = buffer_len > 0 and \
(check_audio_frame(0, ch_count, sample_rate, sample_size) or
check_audio_frame(int(buffer_len / 2), ch_count, sample_rate, sample_size) or
check_audio_frame(buffer_len - 1, ch_count, sample_rate, sample_size))
return UniTAP.OPFDialogAnswer.PASS if state else UniTAP.OPFDialogAnswer.FAIL
except BaseException as e:
logging.error(f"Cannot capture audio. Error: {e}")
return UniTAP.OPFDialogAnswer.FAIL
@staticmethod @staticmethod
def opf_120_handler(dptx, dprx, res_x, res_y, res_frate, res_bpc, color_format) -> OPFDialogAnswer: def opf_120_handler(dptx, dprx, res_x, res_y, res_frate, res_bpc, color_format) -> OPFDialogAnswer:
if not OPFFunctions.check_dprx(dprx): if not OPFFunctions.check_dprx(dprx):
@@ -1256,6 +1432,38 @@ class OPFFunctions:
else: else:
return OPFDialogAnswer.ABORT return OPFDialogAnswer.ABORT
@staticmethod
def opf_146_handler(dptx, dprx, res_x, res_y, rate):
if not OPFFunctions.check_dptx(dptx):
logging.error("DPTX is not initialized")
return OPFDialogAnswer.ABORT
logging.info(res_x, res_y, rate)
return OPFDialogAnswer.PROCEED
@staticmethod
def opf_147_handler(dptx, dprx, rate):
if not OPFFunctions.check_dptx(dptx):
logging.error("DPTX is not initialized")
return OPFDialogAnswer.ABORT
logging.info(f"Refresh rate passed from OPF: {rate}")
dptx.pg.set_as_config(as_config=FixedASParams(refresh_rate=rate,
divide_by_1_001=False,
increase_lines=100,
decrease_lines=100))
res_pg = dptx.pg.apply()
if not res_pg:
logging.info("DPTX pattern is not applied")
return OPFDialogAnswer.ABORT
time.sleep(1)
return OPFDialogAnswer.PROCEED
@staticmethod @staticmethod
def opf_150_handler(dptx, dprx, message: str) -> OPFDialogAnswer: def opf_150_handler(dptx, dprx, message: str) -> OPFDialogAnswer:
return OPFFunctions.opf_pass_handler(dptx, dprx, message) return OPFFunctions.opf_pass_handler(dptx, dprx, message)
@@ -1388,3 +1596,94 @@ class OPFFunctions:
compression_info.is_simple_as_444 = is_simple_as_444 compression_info.is_simple_as_444 = is_simple_as_444
return compression_info return compression_info
@staticmethod
def read_pcm(raw_data, sample_size):
"""
Read raw PCM data from file into a list of int32 values.
Handles 16, 20, and 24-bit samples (little-endian).
"""
if sample_size == 16:
if len(raw_data) % 2 != 0:
raise ValueError("File length not divisible by 2 for 16-bit audio")
result = []
for i in range(0, len(raw_data), 2):
sample = int.from_bytes(raw_data[i:i + 2], byteorder='little', signed=True)
result.append(sample)
return result, 32767
elif sample_size == 20 or sample_size == 24:
if len(raw_data) % 3 != 0:
raise ValueError("File length not divisible by 3 for 24/20-bit audio")
result = []
for i in range(0, len(raw_data), 3):
val = (raw_data[i] |
(raw_data[i + 1] << 8) |
(raw_data[i + 2] << 16))
sign_mask = 1 << 23
val = (val & (sign_mask - 1)) - (val & sign_mask)
result.append(val)
return result, (1 << 23) - 1
else:
raise ValueError(f"Unsupported bit depth: {sample_size}")
@staticmethod
def get_active_channel_count(raw_data, bit_depths: list, channel_range: list, expected_channels: int,
rms_threshold=1e-3, nonzero_frac_threshold=1e-4):
"""
Try multiple bit depths and channel counts, report active channels.
"""
active_count = 0
for bd in bit_depths:
try:
data, dtype_max = OPFFunctions.read_pcm(raw_data, bd)
except Exception as e:
logging.info(f"[{bd}-bit] Error: {e}")
continue
logging.info(f"\n=== Testing bit depth {bd} ===")
for nch in [expected_channels] + [ch for ch in channel_range if ch != expected_channels]:
if len(data) % nch != 0:
logging.info(f"Skipping {nch} channels: data length {len(data)} not divisible by {nch}")
continue
frames = len(data) // nch
arr = []
for f in range(frames):
frame = data[f * nch:(f + 1) * nch]
arr.append(frame)
rms = []
peak = []
nonzero_frac = []
for ch in range(nch):
channel_data = [arr[f][ch] for f in range(frames)]
mean_square = sum(x * x for x in channel_data) / frames
rms.append(mean_square ** 0.5)
peak.append(max(abs(x) for x in channel_data))
nonzero_count = sum(1 for x in channel_data if x != 0)
nonzero_frac.append(nonzero_count / frames)
norm_rms = [r / dtype_max for r in rms]
norm_peak = [p / dtype_max for p in peak]
logging.info(f"\nAssuming {nch} channel(s):")
channel_active_count = 0
for ch in range(nch):
active = (norm_rms[ch] > rms_threshold or
nonzero_frac[ch] > nonzero_frac_threshold)
if active:
channel_active_count += 1
logging.info(f" Ch{ch}: normRMS={norm_rms[ch]:.6f}, "
f"normPeak={norm_peak[ch]:.6f}, "
f"nonzero={nonzero_frac[ch]:.6f}, ACTIVE={active}")
logging.info(f" => Detected {channel_active_count}/{nch} active channels")
if channel_active_count == expected_channels:
active_count = channel_active_count
break
return active_count

View File

@@ -8,7 +8,7 @@ class OPFParametersParser:
return parse_link_training(args[3]) return parse_link_training(args[3])
if opf_id in [2]: if opf_id in [2]:
return parse_video_mode_2(args[3]) return parse_video_mode_2(args[3])
if opf_id in [3, 4, 5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 101, 102, 104, 105, 106, 121, 122, 123, 145, 150, 152, 161]: if opf_id in [3, 4, 5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 22, 23, 24, 101, 102, 104, 105, 106, 121, 122, 123, 145, 150, 152, 161]:
return parse_message(args[1]) return parse_message(args[1])
if opf_id in [6]: if opf_id in [6]:
return parse_video_mode_6(args[1], args[3]) return parse_video_mode_6(args[1], args[3])
@@ -26,6 +26,11 @@ class OPFParametersParser:
return parse_opf_21(args[3]) return parse_opf_21(args[3])
if opf_id in [103]: if opf_id in [103]:
return parse_video_mode_103(args[3]) return parse_video_mode_103(args[3])
if opf_id in [108]:
if len(args) > 3:
return parse_audio_mode_108(args[3])
else:
return parse_message(args[1])
if opf_id in [120]: if opf_id in [120]:
return parse_video_mode_120(args[3]) return parse_video_mode_120(args[3])
if opf_id in [140]: if opf_id in [140]:
@@ -38,6 +43,10 @@ class OPFParametersParser:
return parse_video_mode_143(args[3]) return parse_video_mode_143(args[3])
if opf_id in [144]: if opf_id in [144]:
return parse_video_mode_144(args[3]) return parse_video_mode_144(args[3])
if opf_id in [146]:
return parse_video_mode_146(args[3])
if opf_id in [147]:
return parse_video_mode_147(args[3])
if opf_id in [151]: if opf_id in [151]:
return parse_video_mode_103(args[3]) return parse_video_mode_103(args[3])
else: else:

View File

@@ -1,10 +1,10 @@
import re import re
from typing import List, Optional from typing import List, Optional
from UniTAP.libs.lib_tsi.tsi_types import TSI_OPF_PARAMETER import UniTAP.libs.lib_tsi.tsi_types as ci
def parse_link_training(parameters_list: List[TSI_OPF_PARAMETER]): def parse_link_training(parameters_list: List[ci.TSI_OPF_PARAMETER]):
dp_lanes = 0 dp_lanes = 0
dp_link_rate = 0 dp_link_rate = 0
encoding = None encoding = None
@@ -29,7 +29,7 @@ def parse_link_training(parameters_list: List[TSI_OPF_PARAMETER]):
return int(dp_lanes), float(dp_link_rate), encoding return int(dp_lanes), float(dp_link_rate), encoding
def parse_video_mode_2(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_2(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x = 0 res_x = 0
res_y = 0 res_y = 0
res_frate = 0 res_frate = 0
@@ -48,7 +48,7 @@ def parse_video_mode_2(parameters_list: List[TSI_OPF_PARAMETER]):
return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), tim_std, tim_rb return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), tim_std, tim_rb
def parse_video_mode_6(pattern_request: str, parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_6(pattern_request: str, parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x = 0 res_x = 0
res_y = 0 res_y = 0
res_frate = 0 res_frate = 0
@@ -79,7 +79,7 @@ def parse_video_mode_6(pattern_request: str, parameters_list: List[TSI_OPF_PARAM
res_bpc), timing_standard, col_format, col_range, col_yc, pattern_name res_bpc), timing_standard, col_format, col_range, col_yc, pattern_name
def parse_video_mode_9(parameters_list: List[TSI_OPF_PARAMETER], pattern_request: Optional[str] = None): def parse_video_mode_9(parameters_list: List[ci.TSI_OPF_PARAMETER], pattern_request: Optional[str] = None):
res_x = 0 res_x = 0
res_y = 0 res_y = 0
res_frate = 0 res_frate = 0
@@ -101,7 +101,7 @@ def parse_video_mode_9(parameters_list: List[TSI_OPF_PARAMETER], pattern_request
return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), tim_std, pattern_name return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), tim_std, pattern_name
def parse_opf_10(parameters_list: List[TSI_OPF_PARAMETER]): def parse_opf_10(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x, res_y, res_frate, res_bpc, timing_standard = [0] * 5 res_x, res_y, res_frate, res_bpc, timing_standard = [0] * 5
audio_pattern = '' audio_pattern = ''
@@ -136,7 +136,7 @@ def parse_message(message: str):
return [str(message)] return [str(message)]
def parse_video_mode_19(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_19(parameters_list: List[ci.TSI_OPF_PARAMETER]):
use_3tap = False use_3tap = False
for param in parameters_list: for param in parameters_list:
if param.name == 'Conversion type filter': if param.name == 'Conversion type filter':
@@ -144,7 +144,7 @@ def parse_video_mode_19(parameters_list: List[TSI_OPF_PARAMETER]):
return [use_3tap] return [use_3tap]
def parse_video_mode_18(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_18(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x = 0 res_x = 0
res_y = 0 res_y = 0
res_frate = 0 res_frate = 0
@@ -166,7 +166,7 @@ def parse_video_mode_18(parameters_list: List[TSI_OPF_PARAMETER]):
return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), col_format, col_range, col_yc, tim_std return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), col_format, col_range, col_yc, tim_std
def parse_video_mode_20(parameters_list: List[TSI_OPF_PARAMETER], pattern_request: Optional[str] = None): def parse_video_mode_20(parameters_list: List[ci.TSI_OPF_PARAMETER], pattern_request: Optional[str] = None):
pattern_name = None pattern_name = None
res_x = 0 res_x = 0
res_y = 0 res_y = 0
@@ -186,7 +186,7 @@ def parse_video_mode_20(parameters_list: List[TSI_OPF_PARAMETER], pattern_reques
enable_dsc = False enable_dsc = False
for param in parameters_list: for param in parameters_list:
if param.name == 'Video Mode': if param.name == 'Video Mode' and param.description != "Disable Video":
line = param.description.split("Hz") line = param.description.split("Hz")
res_x, res_y, res_frate = re.findall(r'\d+', line[0]) res_x, res_y, res_frate = re.findall(r'\d+', line[0])
tim_std = re.findall(r'VIC \d+|DMT \w+|UFG \d+|CVT RB\d+|CVT|OVT', line[1]) tim_std = re.findall(r'VIC \d+|DMT \w+|UFG \d+|CVT RB\d+|CVT|OVT', line[1])
@@ -203,7 +203,7 @@ def parse_video_mode_20(parameters_list: List[TSI_OPF_PARAMETER], pattern_reques
pattern_name, enable_dsc pattern_name, enable_dsc
def parse_opf_21(parameters_list: List[TSI_OPF_PARAMETER]): def parse_opf_21(parameters_list: List[ci.TSI_OPF_PARAMETER]):
audio_pattern = '' audio_pattern = ''
ch_count = 0 ch_count = 0
sample_freq = 0 sample_freq = 0
@@ -230,7 +230,7 @@ def parse_opf_21(parameters_list: List[TSI_OPF_PARAMETER]):
ch_info if len(ch_info) > 0 else None) ch_info if len(ch_info) > 0 else None)
def parse_video_mode_103(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_103(parameters_list: List[ci.TSI_OPF_PARAMETER]):
width = 0 width = 0
height = 0 height = 0
res_frate = 60000 res_frate = 60000
@@ -268,7 +268,26 @@ def parse_video_mode_103(parameters_list: List[TSI_OPF_PARAMETER]):
int(h_slice_number), int(buffer_bit_depth), int(v_slice_number), int(dsc_v_major), int(dsc_v_minor) int(h_slice_number), int(buffer_bit_depth), int(v_slice_number), int(dsc_v_major), int(dsc_v_minor)
def parse_video_mode_120(parameters_list: List[TSI_OPF_PARAMETER]): def parse_audio_mode_108(parameters_list: List[ci.TSI_OPF_PARAMETER]):
audio_pattern = ''
ch_count = 0
sample_rate = 0
sample_size = 0
for ind, param in enumerate(parameters_list):
if param.name == 'Audio test pattern':
audio_pattern = param.description
elif param.name == 'Sample rate':
sample_rate, = re.findall(r'\d+', param.description)
elif param.name == 'Sample size':
sample_size, = re.findall(r'\d+', param.description)
elif param.name == 'Channels count':
ch_count, = re.findall(r'\d+', param.description)
return audio_pattern, int(sample_rate), int(sample_size), int(ch_count)
def parse_video_mode_120(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x = 0 res_x = 0
res_y = 0 res_y = 0
res_frate = 0 res_frate = 0
@@ -282,7 +301,7 @@ def parse_video_mode_120(parameters_list: List[TSI_OPF_PARAMETER]):
return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), color_format return int(res_x), int(res_y), int(float(res_frate) * 1000), int(res_bpc), color_format
def parse_video_mode_140(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_140(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x = 0 res_x = 0
res_y = 0 res_y = 0
res_frate = 0 res_frate = 0
@@ -300,7 +319,7 @@ def parse_video_mode_140(parameters_list: List[TSI_OPF_PARAMETER]):
return int(res_x), int(res_y), int(float(res_frate) * 1000), tim_std, tim_std_num return int(res_x), int(res_y), int(float(res_frate) * 1000), tim_std, tim_std_num
def parse_video_mode_141(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_141(parameters_list: List[ci.TSI_OPF_PARAMETER]):
audio_format = '' audio_format = ''
channels = 0 channels = 0
size = 0 size = 0
@@ -313,7 +332,7 @@ def parse_video_mode_141(parameters_list: List[TSI_OPF_PARAMETER]):
return audio_format, int(channels), int(size), int(float(rate) * 1000) return audio_format, int(channels), int(size), int(float(rate) * 1000)
def parse_video_mode_143(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_143(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_frate = 0 res_frate = 0
for param in parameters_list: for param in parameters_list:
@@ -323,5 +342,23 @@ def parse_video_mode_143(parameters_list: List[TSI_OPF_PARAMETER]):
return [int(float(res_frate))] return [int(float(res_frate))]
def parse_video_mode_144(parameters_list: List[TSI_OPF_PARAMETER]): def parse_video_mode_144(parameters_list: List[ci.TSI_OPF_PARAMETER]):
return [parameters_list[0].description] return [parameters_list[0].description]
def parse_video_mode_146(parameters_list: List[ci.TSI_OPF_PARAMETER]):
res_x = 0
res_y = 0
rate = 0
for param in parameters_list:
if param.name == "Resolution":
res_x, res_y = re.findall(r'\d+', param.description)
if param.name == 'Refresh rate':
rate = re.findall(r'\d+', param.description)[0]
return int(res_x), int(res_y), int(float(rate) * 1000)
def parse_video_mode_147(parameters_list: List[ci.TSI_OPF_PARAMETER]):
refresh_rate = 0
for param in parameters_list:
if param.name == 'Refresh rate':
refresh_rate = re.findall(r'\d+', param.description)[0]
return int(refresh_rate)

View File

@@ -1,7 +1,7 @@
import time import time
from UniTAP.libs.lib_tsi.tsi_io import DeviceIO from UniTAP.libs.lib_tsi.tsi_io import DeviceIO
from UniTAP.libs.lib_tsi.tsi import TSI_TERMINAL_RW
from ctypes import c_char from ctypes import c_char
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
class Terminal: class Terminal:
@@ -30,7 +30,7 @@ class Terminal:
def __execute(self, command): def __execute(self, command):
command += '\r' command += '\r'
str_len = (len(command) / 4 + (1 if len(command) % 4 else 0)) * 4 str_len = (len(command) / 4 + (1 if len(command) % 4 else 0)) * 4
self.__io.set(config_id=TSI_TERMINAL_RW, self.__io.set(config_id=p_ci.TSI_TERMINAL_RW,
data=command, data=command,
data_type=c_char, data_type=c_char,
data_count=len(command), data_count=len(command),
@@ -41,7 +41,7 @@ class Terminal:
start = time.time() start = time.time()
result = [] result = []
while time.time() - start < timeout: while time.time() - start < timeout:
result = self.__io.get(TSI_TERMINAL_RW, c_char, 1024)[1] result = self.__io.get(p_ci.TSI_TERMINAL_RW, c_char, 1024)[1]
if result[0] != b'\x00': if result[0] != b'\x00':
break break

View File

@@ -2,6 +2,7 @@ from .dptx5xx import DPTX, DPTX4xx, DPTX5xx
from .dprx5xx import DPRX, DPRX4xx, DPRX5xx from .dprx5xx import DPRX, DPRX4xx, DPRX5xx
from .hdrx4xx import HDRX, HDRX4xx from .hdrx4xx import HDRX, HDRX4xx
from .hdtx4xx import HDTX, HDTX4xx from .hdtx4xx import HDTX, HDTX4xx
from .hdrx_earc import HDRX_eARC
from .pdc_port import PDC340, PDC424, PDC500 from .pdc_port import PDC340, PDC424, PDC500
from .modules import * from .modules import *
import UniTAP.dev.ports.modules.capturer.bulk as bulk import UniTAP.dev.ports.modules.capturer.bulk as bulk

View File

@@ -5,9 +5,7 @@ from .modules.edid.edid import EdidSink
from .modules.hdcp import HdcpSink from .modules.hdcp import HdcpSink
from .modules.capturer.event.event_capturer import EventCapturer, EventFilterDpRx, EventFilterUsbc from .modules.capturer.event.event_capturer import EventCapturer, EventFilterDpRx, EventFilterUsbc
from .modules.link.dp.private_link_rx_types import DPRXHWCaps from .modules.link.dp.private_link_rx_types import DPRXHWCaps
from UniTAP.libs.lib_tsi.tsi_types import TSI_DPRX_HDCP_CAPS_R, TSI_DPRX_HDCP_STATUS_R import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_types import TSI_DPRX_DPCD_BASE_W, TSI_DPRX_DPCD_DATA
from UniTAP.libs.lib_tsi.tsi_types import TSI_PDC_LOG_CONTROL, TSI_DPRX_HW_CAPS_R
from UniTAP.libs.lib_tsi.tsi_io import PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortProtocol
@@ -34,11 +32,11 @@ class DPRX(RX):
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(port_io, memory_manager, capturer) super().__init__(port_io, memory_manager, capturer)
hw_caps = port_io.get(TSI_DPRX_HW_CAPS_R, DPRXHWCaps)[1] hw_caps = port_io.get(ci.TSI_DPRX_HW_CAPS_R, DPRXHWCaps)[1]
self.__dpcd = DPCDRegisters(port_io, TSI_DPRX_DPCD_BASE_W, TSI_DPRX_DPCD_DATA) self.__dpcd = DPCDRegisters(port_io, ci.TSI_DPRX_DPCD_BASE_W, ci.TSI_DPRX_DPCD_DATA)
self.__link = LinkDisplayPortRx(port_io, hw_caps, self.__dpcd) self.__link = LinkDisplayPortRx(port_io, hw_caps, self.__dpcd)
self.__edid = EdidSink(port_io, self.__link.status.mst_stream_count) self.__edid = EdidSink(port_io, self.__link.status.mst_stream_count)
self.__hdcp = HdcpSink(port_io, TSI_DPRX_HDCP_CAPS_R, TSI_DPRX_HDCP_STATUS_R) self.__hdcp = HdcpSink(port_io, ci.TSI_DPRX_HDCP_CAPS_R, ci.TSI_DPRX_HDCP_STATUS_R)
self.__video_capturer = VideoCapturerDP(capturer, hw_caps.mst_stream_count) self.__video_capturer = VideoCapturerDP(capturer, hw_caps.mst_stream_count)
event_filters = [] event_filters = []

View File

@@ -4,6 +4,7 @@ from .modules.capturer.bulk.bulk_capturer import BulkCapturer
from .modules.edid.edid import DisplayIdSink from .modules.edid.edid import DisplayIdSink
from .modules.panel_replay import SinkPanelReplay, SinkPanelSelfRefresh from .modules.panel_replay import SinkPanelReplay, SinkPanelSelfRefresh
from typing import Optional from typing import Optional
import UniTAP.libs.lib_tsi.tsi_types as ci
class DPRX4xx(DPRX): class DPRX4xx(DPRX):
@@ -26,7 +27,7 @@ class DPRX4xx(DPRX):
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(port_io, memory_manager, capturer) super().__init__(port_io, memory_manager, capturer)
hw_caps = port_io.get(TSI_DPRX_HW_CAPS_R, DPRXHWCaps)[1] hw_caps = port_io.get(ci.TSI_DPRX_HW_CAPS_R, DPRXHWCaps)[1]
self.__fec = FecRx(port_io, self.dpcd) self.__fec = FecRx(port_io, self.dpcd)
self.__bulk_capturer = BulkCapturer(capturer, memory_manager) self.__bulk_capturer = BulkCapturer(capturer, memory_manager)
self.__display_id = DisplayIdSink(port_io, hw_caps.mst_stream_count) self.__display_id = DisplayIdSink(port_io, hw_caps.mst_stream_count)

View File

@@ -5,9 +5,7 @@ from .modules.vtg.pg import DpPatternGenerator
from .modules.hdcp import HdcpSource from .modules.hdcp import HdcpSource
from .modules.capturer.event.event_capturer import EventCapturer, EventFilterDpTx, EventFilterUsbc from .modules.capturer.event.event_capturer import EventCapturer, EventFilterDpTx, EventFilterUsbc
from .modules.link.dp.private_link_tx_types import DPTXHWCaps from .modules.link.dp.private_link_tx_types import DPTXHWCaps
from UniTAP.libs.lib_tsi.tsi_types import TSI_DPTX_DPCD_BASE_W, TSI_DPTX_DPCD_DATA import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_types import TSI_DPTX_HDCP_CAPS_R, TSI_DPTX_HDCP_STATUS_R
from UniTAP.libs.lib_tsi.tsi_types import TSI_DPTX_HW_CAPS_R
from UniTAP.libs.lib_tsi.tsi_io import PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortProtocol
@@ -34,12 +32,12 @@ class DPTX(TX):
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(port_io, memory_manager, capturer) super().__init__(port_io, memory_manager, capturer)
hw_caps = port_io.get(TSI_DPTX_HW_CAPS_R, DPTXHWCaps)[1] hw_caps = port_io.get(ci.TSI_DPTX_HW_CAPS_R, DPTXHWCaps)[1]
self.__dpcd = DPCDRegisters(port_io, TSI_DPTX_DPCD_BASE_W, TSI_DPTX_DPCD_DATA) self.__dpcd = DPCDRegisters(port_io, ci.TSI_DPTX_DPCD_BASE_W, ci.TSI_DPTX_DPCD_DATA)
self.__link = LinkDisplayPortTx(port_io, self.__dpcd, hw_caps) self.__link = LinkDisplayPortTx(port_io, self.__dpcd, hw_caps)
self.__pg = DpPatternGenerator(port_io, memory_manager, 0) self.__pg = DpPatternGenerator(port_io, memory_manager, 0)
self.__edid = EdidSource(port_io, self.__link.max_stream_count) self.__edid = EdidSource(port_io, self.__link.max_stream_count)
self.__hdcp = HdcpSource(port_io, TSI_DPTX_HDCP_CAPS_R, TSI_DPTX_HDCP_STATUS_R) self.__hdcp = HdcpSource(port_io, ci.TSI_DPTX_HDCP_CAPS_R, ci.TSI_DPTX_HDCP_STATUS_R)
# event_filters = [e(hw_caps) for e in self.__CHECK_EVENT_FILTER.get(port_io.protocol())] # event_filters = [e(hw_caps) for e in self.__CHECK_EVENT_FILTER.get(port_io.protocol())]
event_filters = [] event_filters = []

View File

@@ -2,6 +2,8 @@ from .dptx import *
from .modules.fec import FecTx, FECCounters, FECErrorType8b10b from .modules.fec import FecTx, FECCounters, FECErrorType8b10b
from .modules.vtg.pg import DpMstPatternGenerator from .modules.vtg.pg import DpMstPatternGenerator
from .modules.edid.edid import DisplayIdSource from .modules.edid.edid import DisplayIdSource
import UniTAP.libs.lib_tsi.tsi_types as ci
class DPTX4xx(DPTX): class DPTX4xx(DPTX):
@@ -21,7 +23,7 @@ class DPTX4xx(DPTX):
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer): def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(port_io, memory_manager, capturer) super().__init__(port_io, memory_manager, capturer)
hw_caps = port_io.get(TSI_DPTX_HW_CAPS_R, DPTXHWCaps)[1] hw_caps = port_io.get(ci.TSI_DPTX_HW_CAPS_R, DPTXHWCaps)[1]
self.__fec = FecTx(port_io, self.dpcd) self.__fec = FecTx(port_io, self.dpcd)
self.__pg = DpMstPatternGenerator(port_io, memory_manager, hw_caps.mst_stream_count) self.__pg = DpMstPatternGenerator(port_io, memory_manager, hw_caps.mst_stream_count)
self.__display_id = DisplayIdSource(port_io, hw_caps.mst_stream_count) self.__display_id = DisplayIdSource(port_io, hw_caps.mst_stream_count)

View File

@@ -4,8 +4,7 @@ from .modules.link.hdmi.link import HdmiLinkRx
from .modules.hdcp import HdcpSink from .modules.hdcp import HdcpSink
from .modules.cec.cec_rx import CecRx from .modules.cec.cec_rx import CecRx
from .modules.capturer.event.event_capturer import EventCapturer, EventFilterHdRx from .modules.capturer.event.event_capturer import EventCapturer, EventFilterHdRx
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDRX_HDCP_CAPS_R, TSI_HDRX_HDCP_STATUS_R import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDRX_LOG_CONTROL
class HDRX(RX): class HDRX(RX):
@@ -30,7 +29,7 @@ class HDRX(RX):
self.__link = HdmiLinkRx(port_io) self.__link = HdmiLinkRx(port_io)
self.__edid = EdidSink(port_io, 1) self.__edid = EdidSink(port_io, 1)
self.__hdcp = HdcpSink(port_io, TSI_HDRX_HDCP_CAPS_R, TSI_HDRX_HDCP_STATUS_R) self.__hdcp = HdcpSink(port_io, ci.TSI_HDRX_HDCP_CAPS_R, ci.TSI_HDRX_HDCP_STATUS_R)
self.__event_capturer = EventCapturer(capturer, port_io.index(), [EventFilterHdRx(0)]) self.__event_capturer = EventCapturer(capturer, port_io.index(), [EventFilterHdRx(0)])
self.__video_capturer = VideoCapturerHDMI(capturer, 1) self.__video_capturer = VideoCapturerHDMI(capturer, 1)
self.__cec = CecRx(port_io) self.__cec = CecRx(port_io)

View File

@@ -0,0 +1,30 @@
from UniTAP.dev.ports.modules.earc.earc_tx import EarcTx
from .hdrx import HDRX, PortIO, MemoryManager, Capturer
class HDRX_eARC(HDRX):
"""
Main class of `HDRX` object.
Inherited from class `RX`.
Class describes capabilities of 300th (3XX) series of HDMI devices in Sink (RX - receiver) role with eARC support.
Attributes:
__earc (EarcTx): object of `EarcTx`.
"""
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, capturer: Capturer):
super().__init__(port_io, memory_manager, capturer)
self.__earc = EarcTx(port_io, memory_manager)
@property
def earc(self) -> EarcTx:
"""
Should be used to control link capabilities on Sink (RX - receiver) role.
Returns:
object of `EarcTx` type.
"""
return self.__earc

View File

@@ -5,8 +5,8 @@ from .modules.vtg.pg import HdmiPatternGenerator
from .modules.hdcp import HdcpSource from .modules.hdcp import HdcpSource
from .modules.capturer.event.event_capturer import EventCapturer, EventFilterHdTx from .modules.capturer.event.event_capturer import EventCapturer, EventFilterHdTx
from .modules.cec.cec_tx import CecTx from .modules.cec.cec_tx import CecTx
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_HDCP_CAPS_R, TSI_HDTX_HDCP_STATUS_R import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_LOG_CONTROL
class HDTX(TX): class HDTX(TX):
@@ -32,7 +32,7 @@ class HDTX(TX):
self.__link = HdmiLinkTx(port_io) self.__link = HdmiLinkTx(port_io)
self.__edid = EdidSource(port_io, 1) self.__edid = EdidSource(port_io, 1)
self.__pg = HdmiPatternGenerator(port_io, memory_manager) self.__pg = HdmiPatternGenerator(port_io, memory_manager)
self.__hdcp = HdcpSource(port_io, TSI_HDTX_HDCP_CAPS_R, TSI_HDTX_HDCP_STATUS_R) self.__hdcp = HdcpSource(port_io, ci.TSI_HDTX_HDCP_CAPS_R, ci.TSI_HDTX_HDCP_STATUS_R)
self.__event_capturer = EventCapturer(capturer, port_io.index(), [EventFilterHdTx(0)]) self.__event_capturer = EventCapturer(capturer, port_io.index(), [EventFilterHdTx(0)])
self.__cec = CecTx(port_io) self.__cec = CecTx(port_io)

View File

@@ -7,5 +7,7 @@ from .hdcp import *
from .capturer import * from .capturer import *
from .edid import * from .edid import *
from .panel_replay import * from .panel_replay import *
from .earc import *
from .packet_generator import *
import UniTAP.dev.ports.modules.cec as cec import UniTAP.dev.ports.modules.cec as cec
import UniTAP.dev.ports.modules.pdc as pdc import UniTAP.dev.ports.modules.pdc as pdc

View File

@@ -1,4 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_types import * from ctypes import c_uint8, c_int, c_int32
import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.utils import function_scheduler from UniTAP.utils import function_scheduler
from .ag_utils import * from .ag_utils import *
from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol
@@ -43,16 +45,16 @@ class AudioGenerator:
self.__memory_manager.make_default() self.__memory_manager.make_default()
self.__memory_manager.set_memory_block_index(MemoryManager.MemoryOwner.MO_AudioGenerator) self.__memory_manager.set_memory_block_index(MemoryManager.MemoryOwner.MO_AudioGenerator)
self.__io.set(TSI_AUDGEN_SIGNAL_BLOCK, MemoryManager.MemoryOwner.MO_AudioGenerator.value) self.__io.set(ci.TSI_AUDGEN_SIGNAL_BLOCK, MemoryManager.MemoryOwner.MO_AudioGenerator.value)
self.__memory_manager.memory_write(data, size) self.__memory_manager.memory_write(data, size)
self.__io.set(TSI_AUDGEN_AUDIO_SIZE, size) self.__io.set(ci.TSI_AUDGEN_AUDIO_SIZE, size)
ag_struct = self.__io.get(TSI_AUDGEN_CONFIG, AudioConfigStructure)[1] ag_struct = self.__io.get(ci.TSI_AUDGEN_CONFIG, AudioConfigStructure)[1]
ag_struct.non_lpcm = 0 ag_struct.non_lpcm = 0
ag_struct.loop = 1 ag_struct.loop = 1
audio_sts = create_audio_sts(audio_mode=audio_mode) audio_sts = create_audio_sts(audio_mode=audio_mode)
self.__io.set(TSI_AUDGEN_CHANNELS_STS, audio_sts, data_type=c_uint8, data_count=len(audio_sts)) self.__io.set(ci.TSI_AUDGEN_CHANNELS_STS, audio_sts, data_type=c_uint8, data_count=len(audio_sts))
if self.__io.protocol() == PortProtocol.HDMI: if self.__io.protocol() == PortProtocol.HDMI:
tp = 0 tp = 0
@@ -63,16 +65,16 @@ class AudioGenerator:
ag_struct.n_selector = 1 ag_struct.n_selector = 1
ag_struct.cts_selector = 1 ag_struct.cts_selector = 1
self.__io.set(TSI_AUDGEN_CONFIG, ag_struct.value()) self.__io.set(ci.TSI_AUDGEN_CONFIG, ag_struct.value())
self.__io.set(TSI_AUDGEN_PACKET_TYPE, tp) self.__io.set(ci.TSI_AUDGEN_PACKET_TYPE, tp)
else: else:
self.__io.set(TSI_AUDGEN_CONFIG, ag_struct.value()) self.__io.set(ci.TSI_AUDGEN_CONFIG, ag_struct.value())
self.__io.set(TSI_AUDGEN_SIGNAL_TYPE, AudioPattern.CustomAudio.value) self.__io.set(ci.TSI_AUDGEN_SIGNAL_TYPE, AudioPattern.CustomAudio.value)
self.__io.set(TSI_AUDGEN_CHANNEL_COUNT, audio_mode.channel_count) self.__io.set(ci.TSI_AUDGEN_CHANNEL_COUNT, audio_mode.channel_count)
self.__io.set(TSI_AUDGEN_SAMPLE_RATE, audio_mode.sample_rate) self.__io.set(ci.TSI_AUDGEN_SAMPLE_RATE, audio_mode.sample_rate)
self.__io.set(TSI_AUDGEN_SAMPLE_SIZE, audio_mode.bits) self.__io.set(ci.TSI_AUDGEN_SAMPLE_SIZE, audio_mode.bits)
elif isinstance(audio_pattern, AudioPattern): elif isinstance(audio_pattern, AudioPattern):
list_sample_rate = [22050, 44100, 88200, 176400, 24000, 48000, 96000, 192000, 32000, 768000] list_sample_rate = [22050, 44100, 88200, 176400, 24000, 48000, 96000, 192000, 32000, 768000]
list_bits = [16, 20, 24] list_bits = [16, 20, 24]
@@ -93,16 +95,16 @@ class AudioGenerator:
if amplitude not in [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]: if amplitude not in [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]:
raise ValueError(f"'Amplitude' must be more than 0") raise ValueError(f"'Amplitude' must be more than 0")
memory_block_no = 2 memory_block_no = 1
self.__memory_manager.make_default() self.__memory_manager.make_default()
self.__io.set(TSI_AUDGEN_SIGNAL_BLOCK, memory_block_no) self.__io.set(ci.TSI_AUDGEN_SIGNAL_BLOCK, memory_block_no)
self.__io.set(TSI_AUDGEN_SIGNAL_TYPE, audio_pattern.value) self.__io.set(ci.TSI_AUDGEN_SIGNAL_TYPE, audio_pattern.value)
self.__io.set(TSI_AUDGEN_CHANNEL_COUNT, audio_mode.channel_count) self.__io.set(ci.TSI_AUDGEN_CHANNEL_COUNT, audio_mode.channel_count)
self.__io.set(TSI_AUDGEN_SAMPLE_RATE, audio_mode.sample_rate) self.__io.set(ci.TSI_AUDGEN_SAMPLE_RATE, audio_mode.sample_rate)
self.__io.set(TSI_AUDGEN_SAMPLE_SIZE, audio_mode.bits) self.__io.set(ci.TSI_AUDGEN_SAMPLE_SIZE, audio_mode.bits)
self.__io.set(TSI_AUDGEN_SIGNAL_FREQ, signal_frequency) self.__io.set(ci.TSI_AUDGEN_SIGNAL_FREQ, signal_frequency)
self.__io.set(TSI_AUDGEN_SIGNAL_VOLUME, amplitude) self.__io.set(ci.TSI_AUDGEN_SIGNAL_VOLUME, amplitude)
else: else:
available_variants = '\n'.join([e.name for e in AudioPattern]) available_variants = '\n'.join([e.name for e in AudioPattern])
raise ValueError(f"Incorrect value of audio pattern - {audio_pattern}\n" raise ValueError(f"Incorrect value of audio pattern - {audio_pattern}\n"
@@ -115,7 +117,7 @@ class AudioGenerator:
Returns: Returns:
object of `bool` type - generation was enabled successfully or not. object of `bool` type - generation was enabled successfully or not.
""" """
self.__io.set(TSI_W_AUDGEN_CONTROL, 1) self.__io.set(ci.TSI_W_AUDGEN_CONTROL, 1)
def is_apply_ag_success(ag: AudioGenerator): def is_apply_ag_success(ag: AudioGenerator):
return ag.status == AGStatus.Running return ag.status == AGStatus.Running
@@ -129,7 +131,7 @@ class AudioGenerator:
Returns: Returns:
object of `bool` type - generation was disabled successfully or not. object of `bool` type - generation was disabled successfully or not.
""" """
return True if self.__io.set(TSI_W_AUDGEN_CONTROL, 0) >= TSI_SUCCESS else False return True if self.__io.set(ci.TSI_W_AUDGEN_CONTROL, 0) >= ci.TSI_SUCCESS else False
@property @property
def status(self) -> AGStatus: def status(self) -> AGStatus:
@@ -139,7 +141,7 @@ class AudioGenerator:
Returns: Returns:
object of `AGStatus` type object of `AGStatus` type
""" """
self.__status = AGStatus(self.__io.get(TSI_AUDGEN_STATUS_R, c_int)[1] & 0x1) self.__status = AGStatus(self.__io.get(ci.TSI_AUDGEN_STATUS_R, c_int)[1] & 0x1)
return self.__status return self.__status
@property @property
@@ -150,7 +152,7 @@ class AudioGenerator:
Returns: Returns:
object of `AudioMode` type object of `AudioMode` type
""" """
self.__audio_mode.sample_rate = self.__io.get(TSI_AUDGEN_SAMPLE_RATE, c_int32)[1] self.__audio_mode.sample_rate = self.__io.get(ci.TSI_AUDGEN_SAMPLE_RATE, c_int32)[1]
self.__audio_mode.bits = self.__io.get(TSI_AUDGEN_SAMPLE_SIZE, c_int32)[1] self.__audio_mode.bits = self.__io.get(ci.TSI_AUDGEN_SAMPLE_SIZE, c_int32)[1]
self.__audio_mode.channel_count = self.__io.get(TSI_AUDGEN_CHANNEL_COUNT, c_int32)[1] self.__audio_mode.channel_count = self.__io.get(ci.TSI_AUDGEN_CHANNEL_COUNT, c_int32)[1]
return self.__audio_mode return self.__audio_mode

View File

@@ -1,10 +1,12 @@
import os.path import os.path
import warnings
import wave import wave
import pickle import pickle
from collections import deque from collections import deque
from ctypes import c_uint32
from _ctypes import sizeof
from UniTAP.common.audio_mode import AudioMode, AudioFileFormat from UniTAP.common.audio_mode import AudioMode, AudioFileFormat
from UniTAP.libs.lib_tsi.tsi import sizeof, c_uint32
def save_to_wave_file(path: str, audio_mode: AudioMode, data: bytearray): def save_to_wave_file(path: str, audio_mode: AudioMode, data: bytearray):

View File

@@ -0,0 +1,158 @@
from ctypes import c_uint8, c_int, c_int32
import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.utils import function_scheduler
from .ag_utils import *
from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol
from UniTAP.dev.modules import MemoryManager
from .types import *
from .private_types import *
from typing import Union
class AudioGeneratorEARC:
"""
Class `AudioGenerator` allows working with generating audio from Source (TX - transmitter). You can configure
audio generator `setup`, apply settings and start generate audio `apply`, stop generate audio `stop_generate`,
read audio generator `status` and get current `audio_mode`.
"""
def __init__(self, port_io: PortIO, memory_manager: MemoryManager):
self.__io = port_io
self.__memory_manager = memory_manager
self.__status = AGStatus.Unknown
self.__audio_mode = AudioMode()
def setup(self, audio_mode: AudioMode = AudioMode(),
audio_pattern: Union[AudioPattern, str] = AudioPattern.SignalSine,
signal_frequency: int = 1000, amplitude: int = 60):
"""
Configure audio generator. Possible two variants of configuration:
- From 'wav' or 'bin' file.
- From `AudioPattern` parameters.
Args:
audio_mode (AudioMode) - object of `AudioMode`
audio_pattern (Union[AudioPattern, str]) - object of `AudioPattern` or path to audio file ('bin' or 'wave')
signal_frequency (int)
amplitude (int)
"""
self.stop_generate()
if isinstance(audio_pattern, str) and check_file_format(audio_pattern) != AudioFileFormat.UNKNOWN:
if check_file_format(audio_pattern) == AudioFileFormat.BIN:
data, _, size = load_from_bin_file(path=audio_pattern)
else:
data, audio_mode, size = load_from_wave_file(path=audio_pattern)
self.__memory_manager.make_default()
self.__memory_manager.set_memory_block_index(MemoryManager.MemoryOwner.MO_AudioGenerator)
self.__io.set(ci.TSI_EARC_AUDGEN_SIGNAL_BLOCK, MemoryManager.MemoryOwner.MO_AudioGenerator.value)
self.__memory_manager.memory_write(data, size)
self.__io.set(ci.TSI_EARC_AUDGEN_AUDIO_SIZE, size)
ag_struct = self.__io.get(ci.TSI_EARC_AUDGEN_CONFIG, AudioConfigStructure)[1]
ag_struct.non_lpcm = 0
ag_struct.loop = 1
audio_sts = create_audio_sts(audio_mode=audio_mode)
self.__io.set(ci.TSI_EARC_AUDGEN_CHANNELS_STS, audio_sts, data_type=c_uint8, data_count=len(audio_sts))
if self.__io.protocol() == PortProtocol.HDMI:
tp = 0
if audio_mode.channel_count == 8 and audio_mode.sample_rate >= 64000:
tp = 3
ag_struct.n_selector = 1
ag_struct.cts_selector = 1
self.__io.set(ci.TSI_EARC_AUDGEN_CONFIG, ag_struct.value())
self.__io.set(ci.TSI_EARC_AUDGEN_PACKET_TYPE, tp)
else:
self.__io.set(ci.TSI_EARC_AUDGEN_CONFIG, ag_struct.value())
self.__io.set(ci.TSI_EARC_AUDGEN_SIGNAL_TYPE, AudioPattern.CustomAudio.value)
self.__io.set(ci.TSI_EARC_AUDGEN_CHANNEL_COUNT, audio_mode.channel_count)
self.__io.set(ci.TSI_EARC_AUDGEN_SAMPLE_RATE, audio_mode.sample_rate)
self.__io.set(ci.TSI_EARC_AUDGEN_SAMPLE_SIZE, audio_mode.bits)
elif isinstance(audio_pattern, AudioPattern):
list_sample_rate = [22050, 44100, 88200, 176400, 24000, 48000, 96000, 192000, 32000, 768000]
list_bits = [16, 20, 24]
audio_pattern = AudioPattern(audio_pattern.value)
if not (1 <= audio_mode.channel_count <= 8):
raise ValueError(f"'Channel count' must be in range: 1 - 8")
if audio_mode.sample_rate not in list_sample_rate:
raise ValueError(f"'Sample rate' must be in list {list_sample_rate}")
if audio_mode.bits not in list_bits:
raise ValueError(f"'Bits' must be in list {list_bits}")
if signal_frequency <= 0:
raise ValueError(f"'Signal frequency' must be more than 0")
if amplitude not in [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]:
raise ValueError(f"'Amplitude' must be more than 0")
memory_block_no = 1
self.__memory_manager.make_default()
self.__io.set(ci.TSI_EARC_AUDGEN_SIGNAL_BLOCK, memory_block_no)
self.__io.set(ci.TSI_EARC_AUDGEN_SIGNAL_TYPE, audio_pattern.value)
self.__io.set(ci.TSI_EARC_AUDGEN_CHANNEL_COUNT, audio_mode.channel_count)
self.__io.set(ci.TSI_EARC_AUDGEN_SAMPLE_RATE, audio_mode.sample_rate)
self.__io.set(ci.TSI_EARC_AUDGEN_SAMPLE_SIZE, audio_mode.bits)
self.__io.set(ci.TSI_EARC_AUDGEN_SIGNAL_FREQ, signal_frequency)
self.__io.set(ci.TSI_EARC_AUDGEN_SIGNAL_VOLUME, amplitude)
else:
available_variants = '\n'.join([e.name for e in AudioPattern])
raise ValueError(f"Incorrect value of audio pattern - {audio_pattern}\n"
f"Available audio patterns: {available_variants}")
def apply(self) -> bool:
"""
Apply settings and start generate audio.
Returns:
object of `bool` type - generation was enabled successfully or not.
"""
self.__io.set(ci.TSI_EARC_AUDGEN_CONTROL_W, 1)
def is_apply_ag_success(ag: AudioGeneratorEARC) -> bool:
return ag.status == AGStatus.Running
return function_scheduler(is_apply_ag_success, self, interval=1, timeout=10)
def stop_generate(self) -> bool:
"""
Stop generate audio.
Returns:
object of `bool` type - generation was disabled successfully or not.
"""
return True if self.__io.set(ci.TSI_EARC_AUDGEN_CONTROL_W, 0) >= ci.TSI_SUCCESS else False
@property
def status(self) -> AGStatus:
"""
Return audio generator status.
Returns:
object of `AGStatus` type
"""
self.__status = AGStatus(self.__io.get(ci.TSI_EARC_AUDGEN_STATUS_R, c_int)[1] & 0x1)
return self.__status
@property
def audio_mode(self) -> AudioMode:
"""
Return current audio mode.
Returns:
object of `AudioMode` type
"""
self.__audio_mode.sample_rate = self.__io.get(ci.TSI_EARC_AUDGEN_SAMPLE_RATE, c_int32)[1]
self.__audio_mode.bits = self.__io.get(ci.TSI_EARC_AUDGEN_SAMPLE_SIZE, c_int32)[1]
self.__audio_mode.channel_count = self.__io.get(ci.TSI_EARC_AUDGEN_CHANNEL_COUNT, c_int32)[1]
return self.__audio_mode

View File

@@ -17,3 +17,12 @@ class AudioConfigStructure(Structure):
def value(self) -> int: def value(self) -> int:
return self.auto_ch_sts | self.use_raw_data << 1 | self.non_lpcm << 2 | self.loop << 3 | \ return self.auto_ch_sts | self.use_raw_data << 1 | self.non_lpcm << 2 | self.loop << 3 | \
self.auto_info_frame << 4 | self.n_selector << 8 | self.cts_selector << 12 self.auto_info_frame << 4 | self.n_selector << 8 | self.cts_selector << 12
class AudioSignalStruct(Structure):
_fields_ = [
('freq', c_uint32, 32),
('volume', c_uint32, 32),
('shift', c_uint32, 32),
('type', c_uint32, 32),
]

View File

@@ -10,7 +10,8 @@ class AudioPattern(IntEnum):
SignalSquare = 2 SignalSquare = 2
CustomAudio = 3 CustomAudio = 3
SignalIncremental = 4 SignalIncremental = 4
Unknown = 5 SignalPing = 5
Unknown = 6
class AGStatus(IntEnum): class AGStatus(IntEnum):

View File

@@ -4,7 +4,7 @@ import copy
from typing import Union, TypeVar, Type, List from typing import Union, TypeVar, Type, List
from UniTAP.libs.lib_tsi.tsi import TSIX_TS_SetPortConfigItem import UniTAP.libs.lib_tsi.tsi as tsi
from UniTAP.dev.modules.capturer.capture import Capturer, CaptureConfig from UniTAP.dev.modules.capturer.capture import Capturer, CaptureConfig
from UniTAP.dev.modules.capturer.statuses import EventCaptureStatus from UniTAP.dev.modules.capturer.statuses import EventCaptureStatus
from .result_event import ResultEventObject from .result_event import ResultEventObject
@@ -98,10 +98,10 @@ class EventCapturer:
self.__event_filter[i] = event_filter self.__event_filter[i] = event_filter
for item in event_filter.additional_filter: for item in event_filter.additional_filter:
TSIX_TS_SetPortConfigItem(self.__device.device_handle, self.__port_id, item.ci_control, item.value, tsi.TSIX_TS_SetPortConfigItem(self.__device.device_handle, self.__port_id, item.ci_control, item.value,
data_count=len(item.value) if isinstance(item.value, list) else 1) data_count=len(item.value) if isinstance(item.value, list) else 1)
TSIX_TS_SetPortConfigItem(self.__device.device_handle, self.__port_id, event_filter._control_ci, tsi.TSIX_TS_SetPortConfigItem(self.__device.device_handle, self.__port_id, event_filter._control_ci,
event_filter.config) event_filter.config)
def clear_capturer_config(self): def clear_capturer_config(self):
@@ -110,7 +110,7 @@ class EventCapturer:
""" """
for item in self.__event_filter: for item in self.__event_filter:
item.clear() item.clear()
TSIX_TS_SetPortConfigItem(self.__device.device_handle, self.__port_id, item._control_ci, 0) tsi.TSIX_TS_SetPortConfigItem(self.__device.device_handle, self.__port_id, item._control_ci, 0)
def start(self, sec=0, n_elements=0): def start(self, sec=0, n_elements=0):
""" """

View File

@@ -1,7 +1,9 @@
from enum import IntEnum
from .event_utils import set_bit_in_vector, search_in_list from .event_utils import set_bit_in_vector, search_in_list
from .private_event_types import AdditionalSDPEventFilter, AdditionalLinkPatternEventFilter, \ from .private_event_types import AdditionalSDPEventFilter, AdditionalLinkPatternEventFilter, \
AdditionalInfoFrameEventFilter, AdditionalVBIDEventFilter, AdditionalMSAEventFilter, AdditionalLSEEventFilter AdditionalInfoFrameEventFilter, AdditionalVBIDEventFilter, AdditionalMSAEventFilter, AdditionalLSEEventFilter
from UniTAP.libs.lib_tsi.tsi_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
import warnings import warnings
@@ -405,7 +407,7 @@ class EventFilterDpRx(EventFilter):
def __init__(self, hw_caps): def __init__(self, hw_caps):
super().__init__(hw_caps) super().__init__(hw_caps)
self._control_ci = TSI_DPRX_LOG_CONTROL self._control_ci = ci.TSI_DPRX_LOG_CONTROL
self.additional_filter = [AdditionalSDPEventFilter()] self.additional_filter = [AdditionalSDPEventFilter()]
if hw_caps.link_pat_log: if hw_caps.link_pat_log:
self.additional_filter.append(AdditionalLinkPatternEventFilter()) self.additional_filter.append(AdditionalLinkPatternEventFilter())
@@ -422,9 +424,9 @@ class EventFilterDpRx(EventFilter):
enable (bool) - enable/disable HDP events enable (bool) - enable/disable HDP events
""" """
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_HPD self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_HPD
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_HPD self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_HPD
def config_aux_events(self, enable: bool): def config_aux_events(self, enable: bool):
""" """
@@ -434,9 +436,9 @@ class EventFilterDpRx(EventFilter):
enable (bool) - enable/disable AUX events enable (bool) - enable/disable AUX events
""" """
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_AUX self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_AUX
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_AUX self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_AUX
def config_sdp_events(self, enable: bool, *args: EventSDP): def config_sdp_events(self, enable: bool, *args: EventSDP):
""" """
@@ -447,9 +449,9 @@ class EventFilterDpRx(EventFilter):
*args (`EventSDP`) - SDP packet types *args (`EventSDP`) - SDP packet types
""" """
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_SDP self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_SDP
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_SDP self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_SDP
if len(args) > 0: if len(args) > 0:
for item in args: for item in args:
@@ -466,9 +468,9 @@ class EventFilterDpRx(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.link_pat_log: if self._hw_caps is not None and self._hw_caps.link_pat_log:
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT
if len(args) > 0: if len(args) > 0:
for item in args: for item in args:
@@ -490,9 +492,9 @@ class EventFilterDpRx(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.vbid_hw_log: if self._hw_caps is not None and self._hw_caps.vbid_hw_log:
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_VBID_HW self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_VBID_HW
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_VBID_HW self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_VBID_HW
if len(args) > 0: if len(args) > 0:
for item in args: for item in args:
@@ -516,9 +518,9 @@ class EventFilterDpRx(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.msa_hw_log: if self._hw_caps is not None and self._hw_caps.msa_hw_log:
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_MSA_HW self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_MSA_HW
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_MSA_HW self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_MSA_HW
if len(args) > 0: if len(args) > 0:
for item in args: for item in args:
@@ -541,9 +543,9 @@ class EventFilterDpRx(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.aux_bw_log: if self._hw_caps is not None and self._hw_caps.aux_bw_log:
if enable: if enable:
self.config |= TSI_DPRX_LOG_CTRL_VALUE_AUX_BW self.config |= ci.TSI_DPRX_LOG_CTRL_VALUE_AUX_BW
else: else:
self.config &= ~TSI_DPRX_LOG_CTRL_VALUE_AUX_BW self.config &= ~ci.TSI_DPRX_LOG_CTRL_VALUE_AUX_BW
else: else:
warnings.warn("HW does not support Aux Bw Logger") warnings.warn("HW does not support Aux Bw Logger")
@@ -556,7 +558,7 @@ class EventFilterDpTx(EventFilter):
def __init__(self, hw_caps): def __init__(self, hw_caps):
super().__init__(hw_caps) super().__init__(hw_caps)
self._control_ci = TSI_DPTX_LOG_CONTROL self._control_ci = ci.TSI_DPTX_LOG_CONTROL
def config_hpd_events(self, enable: bool): def config_hpd_events(self, enable: bool):
""" """
@@ -566,9 +568,9 @@ class EventFilterDpTx(EventFilter):
enable (bool) - enable/disable HDP events enable (bool) - enable/disable HDP events
""" """
if enable: if enable:
self.config |= TSI_DPTX_LOG_CONTROL_VALUE_HPD self.config |= ci.TSI_DPTX_LOG_CONTROL_VALUE_HPD
else: else:
self.config &= ~TSI_DPTX_LOG_CONTROL_VALUE_HPD self.config &= ~ci.TSI_DPTX_LOG_CONTROL_VALUE_HPD
def config_aux_events(self, enable: bool): def config_aux_events(self, enable: bool):
""" """
@@ -578,9 +580,9 @@ class EventFilterDpTx(EventFilter):
enable (bool) - enable/disable AUX events enable (bool) - enable/disable AUX events
""" """
if enable: if enable:
self.config |= TSI_DPTX_LOG_CONTROL_VALUE_AUX self.config |= ci.TSI_DPTX_LOG_CONTROL_VALUE_AUX
else: else:
self.config &= ~TSI_DPTX_LOG_CONTROL_VALUE_AUX self.config &= ~ci.TSI_DPTX_LOG_CONTROL_VALUE_AUX
class EventFilterHdRx(EventFilter): class EventFilterHdRx(EventFilter):
@@ -593,7 +595,7 @@ class EventFilterHdRx(EventFilter):
def __init__(self, hw_caps): def __init__(self, hw_caps):
super().__init__(hw_caps) super().__init__(hw_caps)
self.additional_filter = [AdditionalInfoFrameEventFilter()] self.additional_filter = [AdditionalInfoFrameEventFilter()]
self._control_ci = TSI_HDRX_LOG_CONTROL self._control_ci = ci.TSI_HDRX_LOG_CONTROL
def config_hpd_events(self, enable: bool): def config_hpd_events(self, enable: bool):
""" """
@@ -603,9 +605,9 @@ class EventFilterHdRx(EventFilter):
enable (bool) - enable/disable HPD events enable (bool) - enable/disable HPD events
""" """
if enable: if enable:
self.config |= TSI_HDRX_LOG_CTRL_VALUE_HPD self.config |= ci.TSI_HDRX_LOG_CTRL_VALUE_HPD
else: else:
self.config &= ~TSI_HDRX_LOG_CTRL_VALUE_HPD self.config &= ~ci.TSI_HDRX_LOG_CTRL_VALUE_HPD
def config_packets_events(self, enable: bool, *args: EventInfoFrame): def config_packets_events(self, enable: bool, *args: EventInfoFrame):
""" """
@@ -616,9 +618,9 @@ class EventFilterHdRx(EventFilter):
*args (`EventInfoFrame`) - InfoFrame packet types *args (`EventInfoFrame`) - InfoFrame packet types
""" """
if enable: if enable:
self.config |= TSI_HDRX_LOG_CTRL_VALUE_INFO self.config |= ci.TSI_HDRX_LOG_CTRL_VALUE_INFO
else: else:
self.config &= ~TSI_HDRX_LOG_CTRL_VALUE_INFO self.config &= ~ci.TSI_HDRX_LOG_CTRL_VALUE_INFO
if len(args) > 0: if len(args) > 0:
for item in args: for item in args:
@@ -633,9 +635,9 @@ class EventFilterHdRx(EventFilter):
enable (bool) - enable/disable I2C events enable (bool) - enable/disable I2C events
""" """
if enable: if enable:
self.config |= TSI_HDRX_LOG_CTRL_VALUE_I2C self.config |= ci.TSI_HDRX_LOG_CTRL_VALUE_I2C
else: else:
self.config &= ~TSI_HDRX_LOG_CTRL_VALUE_I2C self.config &= ~ci.TSI_HDRX_LOG_CTRL_VALUE_I2C
def config_cec_events(self, enable: bool): def config_cec_events(self, enable: bool):
""" """
@@ -645,9 +647,9 @@ class EventFilterHdRx(EventFilter):
enable (bool) - enable/disable CEC events enable (bool) - enable/disable CEC events
""" """
if enable: if enable:
self.config |= TSI_HDRX_LOG_CTRL_VALUE_CEC self.config |= ci.TSI_HDRX_LOG_CTRL_VALUE_CEC
else: else:
self.config &= ~TSI_HDRX_LOG_CTRL_VALUE_CEC self.config &= ~ci.TSI_HDRX_LOG_CTRL_VALUE_CEC
class EventFilterHdTx(EventFilter): class EventFilterHdTx(EventFilter):
@@ -659,7 +661,7 @@ class EventFilterHdTx(EventFilter):
def __init__(self, hw_caps): def __init__(self, hw_caps):
super().__init__(hw_caps) super().__init__(hw_caps)
self._control_ci = TSI_HDTX_LOG_CONTROL self._control_ci = ci.TSI_HDTX_LOG_CONTROL
def config_hpd_events(self, enable: bool): def config_hpd_events(self, enable: bool):
""" """
@@ -669,9 +671,9 @@ class EventFilterHdTx(EventFilter):
enable (bool) - enable/disable HPD events enable (bool) - enable/disable HPD events
""" """
if enable: if enable:
self.config |= TSI_HDTX_LOG_CTRL_VALUE_HPD self.config |= ci.TSI_HDTX_LOG_CTRL_VALUE_HPD
else: else:
self.config &= ~TSI_HDTX_LOG_CTRL_VALUE_HPD self.config &= ~ci.TSI_HDTX_LOG_CTRL_VALUE_HPD
def config_i2c_events(self, enable: bool): def config_i2c_events(self, enable: bool):
""" """
@@ -681,9 +683,9 @@ class EventFilterHdTx(EventFilter):
enable (bool) - enable/disable I2C events enable (bool) - enable/disable I2C events
""" """
if enable: if enable:
self.config |= TSI_HDTX_LOG_CTRL_VALUE_I2C self.config |= ci.TSI_HDTX_LOG_CTRL_VALUE_I2C
else: else:
self.config &= ~TSI_HDTX_LOG_CTRL_VALUE_I2C self.config &= ~ci.TSI_HDTX_LOG_CTRL_VALUE_I2C
def config_cec_events(self, enable: bool): def config_cec_events(self, enable: bool):
""" """
@@ -693,9 +695,9 @@ class EventFilterHdTx(EventFilter):
enable (bool) - enable/disable CEC events enable (bool) - enable/disable CEC events
""" """
if enable: if enable:
self.config |= TSI_HDTX_LOG_CTRL_VALUE_CEC self.config |= ci.TSI_HDTX_LOG_CTRL_VALUE_CEC
else: else:
self.config &= ~TSI_HDTX_LOG_CTRL_VALUE_CEC self.config &= ~ci.TSI_HDTX_LOG_CTRL_VALUE_CEC
class EventFilterUsbc(EventFilter): class EventFilterUsbc(EventFilter):
@@ -707,7 +709,7 @@ class EventFilterUsbc(EventFilter):
def __init__(self, hw_caps): def __init__(self, hw_caps):
super().__init__(hw_caps) super().__init__(hw_caps)
self._control_ci = TSI_PDC_LOG_CONTROL self._control_ci = ci.TSI_PDC_LOG_CONTROL
if hw_caps is not None and hw_caps.voltage: if hw_caps is not None and hw_caps.voltage:
self.additional_filter.append(AdditionalLSEEventFilter()) self.additional_filter.append(AdditionalLSEEventFilter())
@@ -719,9 +721,9 @@ class EventFilterUsbc(EventFilter):
enable (bool) - enable/disable PD events enable (bool) - enable/disable PD events
""" """
if enable: if enable:
self.config |= TSI_PDC_LOG_CTRL_VALUE_PD self.config |= ci.TSI_PDC_LOG_CTRL_VALUE_PD
else: else:
self.config &= ~TSI_PDC_LOG_CTRL_VALUE_PD self.config &= ~ci.TSI_PDC_LOG_CTRL_VALUE_PD
def config_voltage_events(self, enable: bool, value: EventLCE): def config_voltage_events(self, enable: bool, value: EventLCE):
""" """
@@ -733,9 +735,9 @@ class EventFilterUsbc(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.voltage: if self._hw_caps is not None and self._hw_caps.voltage:
if enable: if enable:
self.config |= TSI_PDC_LOG_CTRL_VALUE_USBC_VOLTAGE self.config |= ci.TSI_PDC_LOG_CTRL_VALUE_USBC_VOLTAGE
else: else:
self.config &= ~TSI_PDC_LOG_CTRL_VALUE_USBC_VOLTAGE self.config &= ~ci.TSI_PDC_LOG_CTRL_VALUE_USBC_VOLTAGE
for i in enumerate(value.values()): for i in enumerate(value.values()):
self.additional_filter[search_in_list(AdditionalLSEEventFilter, self.additional_filter[search_in_list(AdditionalLSEEventFilter,
@@ -752,9 +754,9 @@ class EventFilterUsbc(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.events: if self._hw_caps is not None and self._hw_caps.events:
if enable: if enable:
self.config |= TSI_PDC_LOG_CTRL_VALUE_USBC_EVENT self.config |= ci.TSI_PDC_LOG_CTRL_VALUE_USBC_EVENT
else: else:
self.config &= ~TSI_PDC_LOG_CTRL_VALUE_USBC_EVENT self.config &= ~ci.TSI_PDC_LOG_CTRL_VALUE_USBC_EVENT
else: else:
warnings.warn("HW does not support 'USB-C' events") warnings.warn("HW does not support 'USB-C' events")
@@ -767,8 +769,8 @@ class EventFilterUsbc(EventFilter):
""" """
if self._hw_caps is not None and self._hw_caps.states: if self._hw_caps is not None and self._hw_caps.states:
if enable: if enable:
self.config |= TSI_PDC_LOG_CTRL_VALUE_USBC_STATE self.config |= ci.TSI_PDC_LOG_CTRL_VALUE_USBC_STATE
else: else:
self.config &= ~TSI_PDC_LOG_CTRL_VALUE_USBC_STATE self.config &= ~ci.TSI_PDC_LOG_CTRL_VALUE_USBC_STATE
else: else:
warnings.warn("HW does not support 'USB-C Port State' events") warnings.warn("HW does not support 'USB-C Port State' events")

View File

@@ -113,7 +113,7 @@ def save_to_bin_file(path: str, events: list, index=None):
def save_to_csv_file(path: str, events: list): def save_to_csv_file(path: str, events: list):
with (open(path, 'w', newline='') as file): with open(path, 'w', newline='') as file:
writer = csv.writer(file, delimiter=';') writer = csv.writer(file, delimiter=';')
writer.writerow(["Source", "Type", "Start", "Brief info", "Full info"]) writer.writerow(["Source", "Type", "Start", "Brief info", "Full info"])
for data in events: for data in events:

View File

@@ -1,5 +1,4 @@
from UniTAP.libs.lib_tsi.tsi_types import TSI_DPRX_LOG_IF_SEL, TSI_HDRX_LOG_IF_SEL, TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT, \ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_DPRX_VBID_LOG_SEL, TSI_DPRX_MSA_LOG_SEL, TSI_PDC_USBC_LOG_THRESH
class AdditionalEventFilter: class AdditionalEventFilter:
@@ -31,7 +30,7 @@ class AdditionalSDPEventFilter(AdditionalEventFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.ci_control = TSI_DPRX_LOG_IF_SEL self.ci_control = ci.TSI_DPRX_LOG_IF_SEL
self.value = [0] * 8 self.value = [0] * 8
@@ -39,7 +38,7 @@ class AdditionalInfoFrameEventFilter(AdditionalEventFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.ci_control = TSI_HDRX_LOG_IF_SEL self.ci_control = ci.TSI_HDRX_LOG_IF_SEL
self.value = [0] * 8 self.value = [0] * 8
@@ -47,7 +46,7 @@ class AdditionalLinkPatternEventFilter(AdditionalEventFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.ci_control = TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT self.ci_control = ci.TSI_DPRX_LOG_CTRL_VALUE_LINK_PAT
self.value = [0] * 3 self.value = [0] * 3
@@ -55,7 +54,7 @@ class AdditionalVBIDEventFilter(AdditionalEventFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.ci_control = TSI_DPRX_VBID_LOG_SEL self.ci_control = ci.TSI_DPRX_VBID_LOG_SEL
self.value = 0 self.value = 0
@@ -63,7 +62,7 @@ class AdditionalMSAEventFilter(AdditionalEventFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.ci_control = TSI_DPRX_MSA_LOG_SEL self.ci_control = ci.TSI_DPRX_MSA_LOG_SEL
self.value = 0 self.value = 0
@@ -71,5 +70,5 @@ class AdditionalLSEEventFilter(AdditionalEventFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.ci_control = TSI_PDC_USBC_LOG_THRESH self.ci_control = ci.TSI_PDC_USBC_LOG_THRESH
self.value = [0] * 5 self.value = [0] * 5

View File

@@ -1,7 +1,7 @@
import warnings import warnings
from UniTAP.dev.modules.capturer.result_object import ResultObject from UniTAP.dev.modules.capturer.result_object import ResultObject
from UniTAP.libs.lib_tsi.tsi import TSIEventParser import UniTAP.libs.lib_tsi.tsi as tsi
from .event_utils import save_to_bin_file, save_to_csv_file, save_to_txt_file, save_to_html_file from .event_utils import save_to_bin_file, save_to_csv_file, save_to_txt_file, save_to_html_file
from .event_types import EventFileFormat from .event_types import EventFileFormat
@@ -96,7 +96,7 @@ class ResultEventObject(ResultObject):
warnings.warn("Buffer size is equal 0.") warnings.warn("Buffer size is equal 0.")
def __parse_buffer(self): def __parse_buffer(self):
with TSIEventParser() as parser: with tsi.TSIEventParser() as parser:
for index, item in enumerate(self.buffer): for index, item in enumerate(self.buffer):
if len(item.data) > 12: if len(item.data) > 12:
res = parser.parse(item.data, to_dict=True) res = parser.parse(item.data, to_dict=True)

View File

@@ -52,6 +52,36 @@ class VideoCapturer:
""" """
return self.__max_stream_number return self.__max_stream_number
def start(self, frames_count: int = 0, sec: int = 0, capture_type: CaptureConfig.Type = CaptureConfig.Type.LIVE):
"""
Start capturing. Possible some variants of capturing:
- Capture with fixed frames count (will be captured fixed frames count and capturing will be stopped).
- Capture with fixed time (capturing will be continued fixed seconds and capturing will be stopped).
- Capture without parameters - Live capturing (for getting frames you need to use functions `pop_element` and
`pop_all_elements`)
All results can be obtained using the function `capture_result`.
Args:
frames_count (int)
sec (int)
type (CaptureConfig.Type)
"""
config = CaptureConfig()
config.video = True
config.type = capture_type
self.__capturer.start_capture(config)
self.capture_result.clear()
self.capture_result.start_capture_time = time.time()
if frames_count > 0:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_frames(frames_count, capture_type))
elif sec > 0:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_sec(sec))
def stop(self): def stop(self):
""" """
Stop capture video. Stop capture video.
@@ -127,8 +157,8 @@ class VideoCapturerDP(VideoCapturer):
super().__init__(capturer, max_stream_number) super().__init__(capturer, max_stream_number)
self.__capturer = capturer self.__capturer = capturer
def start(self, frames_count: int = 0, sec: int = 0, stream_number: int = 0, def start(self, frames_count: int = 0, sec: int = 0, capture_type: CaptureConfig.Type = CaptureConfig.Type.LIVE,
capture_type: CaptureConfig.Type = CaptureConfig.Type.LIVE): stream_number: int = 0):
""" """
Start capturing. Possible some variants of capturing: Start capturing. Possible some variants of capturing:
- Capture with fixed frames count (will be captured fixed frames count and capturing will be stopped). - Capture with fixed frames count (will be captured fixed frames count and capturing will be stopped).
@@ -150,21 +180,7 @@ class VideoCapturerDP(VideoCapturer):
f"{', '.join([str(i) for i in range(self.max_stream_number)])}") f"{', '.join([str(i) for i in range(self.max_stream_number)])}")
self.__capturer.set_video_stream_number(stream_number) self.__capturer.set_video_stream_number(stream_number)
super().start(frames_count, sec, capture_type)
config = CaptureConfig()
config.video = True
config.type = capture_type
self.__capturer.start_capture(config)
self.capture_result.clear()
self.capture_result.start_capture_time = time.time()
if frames_count > 0:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_frames(frames_count, capture_type))
elif sec > 0:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_sec(sec))
def get_buffer_capacity(self, stream_number: int = 0): def get_buffer_capacity(self, stream_number: int = 0):
return self.__capturer.get_buffer_capacity(stream_number) return self.__capturer.get_buffer_capacity(stream_number)
@@ -182,43 +198,5 @@ class VideoCapturerHDMI(VideoCapturer):
super().__init__(capturer, max_stream_number) super().__init__(capturer, max_stream_number)
self.__capturer = capturer self.__capturer = capturer
def start(self, frames_count: int = 0, sec: int = 0, stream_number: int = 0):
"""
Start capturing. Possible some variants of capturing:
- Capture with fixed frames count (will be captured fixed frames count and capturing will be stopped).
- Capture with fixed time (capturing will be continued fixed seconds and capturing will be stopped).
- Capture without parameters - Live capturing (for getting frames you need to use functions `pop_element` and
`pop_all_elements`)
All results can be obtained using the function `capture_result`.
Args:
frames_count (int)
sec (int)
stream_number (int)
"""
if stream_number >= self.max_stream_number:
assert ValueError(f"Incorrect index of stream. Value must be from available options: "
f"{', '.join([str(i) for i in range(self.max_stream_number)])}")
config = CaptureConfig()
config.video = True
config.type = CaptureConfig.Type.LIVE
self.__capturer.start_capture(config)
self.capture_result.clear()
self.capture_result.start_capture_time = time.time()
if frames_count > 0:
if frames_count > 1:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_frames(frames_count))
else:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_frames(frames_count))
elif sec > 0:
self.capture_result.buffer.extend(self.__capturer.capture_video_by_n_sec(sec))
def get_buffer_capacity(self): def get_buffer_capacity(self):
return self.__capturer.get_buffer_capacity() return self.__capturer.get_buffer_capacity()

View File

@@ -1,5 +1,5 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi_types as ci
from .cec_types import * from .cec_types import *
from .cec_private_types import * from .cec_private_types import *
from typing import Union from typing import Union
@@ -29,7 +29,7 @@ class CecRx:
Args: Args:
state (`bool`) state (`bool`)
""" """
self.__io.set(TSI_HDRX_CEC_CONTROL, state, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_CONTROL, state, c_uint32)
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
""" """
@@ -38,7 +38,7 @@ class CecRx:
Returns: Returns:
object of `bool` type object of `bool` type
""" """
return self.__io.get(TSI_HDRX_CEC_CONTROL, c_uint32)[1] & 0x1 == 1 return self.__io.get(ci.TSI_HDRX_CEC_CONTROL, c_uint32)[1] & 0x1 == 1
@property @property
def logical_address(self) -> LogicalAddressEnum: def logical_address(self) -> LogicalAddressEnum:
@@ -48,11 +48,11 @@ class CecRx:
Returns: Returns:
object of `LogicalAddressEnum` type object of `LogicalAddressEnum` type
""" """
return LogicalAddressEnum(self.__io.get(TSI_HDRX_CEC_LOGICAL_ADDRESS, c_uint32)[1]) return LogicalAddressEnum(self.__io.get(ci.TSI_HDRX_CEC_LOGICAL_ADDRESS, c_uint32)[1])
@logical_address.setter @logical_address.setter
def logical_address(self, address: LogicalAddressEnum): def logical_address(self, address: LogicalAddressEnum):
self.__io.set(TSI_HDRX_CEC_LOGICAL_ADDRESS, address.value, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_LOGICAL_ADDRESS, address.value, c_uint32)
@property @property
def destination(self) -> LogicalAddressEnum: def destination(self) -> LogicalAddressEnum:
@@ -62,11 +62,11 @@ class CecRx:
Returns: Returns:
object of `LogicalAddressEnum` type object of `LogicalAddressEnum` type
""" """
return LogicalAddressEnum(self.__io.get(TSI_HDRX_CEC_DESTINATION, c_uint32)[1]) return LogicalAddressEnum(self.__io.get(ci.TSI_HDRX_CEC_DESTINATION, c_uint32)[1])
@destination.setter @destination.setter
def destination(self, address: LogicalAddressEnum): def destination(self, address: LogicalAddressEnum):
self.__io.set(TSI_HDRX_CEC_DESTINATION, address.value, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_DESTINATION, address.value, c_uint32)
@property @property
def phy_address(self) -> int: def phy_address(self) -> int:
@@ -76,11 +76,11 @@ class CecRx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDRX_CEC_PHYSICAL_ADDRESS, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_CEC_PHYSICAL_ADDRESS, c_uint32)[1]
@phy_address.setter @phy_address.setter
def phy_address(self, address: int): def phy_address(self, address: int):
self.__io.set(TSI_HDRX_CEC_PHYSICAL_ADDRESS, address, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_PHYSICAL_ADDRESS, address, c_uint32)
@property @property
def op_code(self) -> int: def op_code(self) -> int:
@@ -90,11 +90,11 @@ class CecRx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDRX_CEC_OP_CODE, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_CEC_OP_CODE, c_uint32)[1]
@op_code.setter @op_code.setter
def op_code(self, code: int): def op_code(self, code: int):
self.__io.set(TSI_HDRX_CEC_OP_CODE, code, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_OP_CODE, code, c_uint32)
@property @property
def op_code_param(self) -> Union[int, list]: def op_code_param(self) -> Union[int, list]:
@@ -104,12 +104,12 @@ class CecRx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDRX_CEC_OP_CODE_PARAM, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_CEC_OP_CODE_PARAM, c_uint32)[1]
@op_code_param.setter @op_code_param.setter
def op_code_param(self, code_param: Union[int, list]): def op_code_param(self, code_param: Union[int, list]):
data_count = len(code_param) if isinstance(code_param, list) else 1 data_count = len(code_param) if isinstance(code_param, list) else 1
self.__io.set(TSI_HDRX_CEC_OP_CODE_PARAM, code_param, c_uint32, data_count=data_count) self.__io.set(ci.TSI_HDRX_CEC_OP_CODE_PARAM, code_param, c_uint32, data_count=data_count)
@property @property
def device_type(self) -> DeviceType: def device_type(self) -> DeviceType:
@@ -119,7 +119,7 @@ class CecRx:
Returns: Returns:
object of `DeviceType` type object of `DeviceType` type
""" """
data = self.__io.get(TSI_HDRX_CEC_DEVICE_TYPE, DeviceTypePrivate)[1] data = self.__io.get(ci.TSI_HDRX_CEC_DEVICE_TYPE, DeviceTypePrivate)[1]
return DeviceType(data.cecSwitch, data.audioSystem, data.pbDevice, data.tuner, data.recDev, data.tv) return DeviceType(data.cecSwitch, data.audioSystem, data.pbDevice, data.tuner, data.recDev, data.tv)
@device_type.setter @device_type.setter
@@ -134,7 +134,7 @@ class CecRx:
value = dev_type & 0xFF value = dev_type & 0xFF
else: else:
raise TypeError(f"Unsupported type: {type(dev_type)}") raise TypeError(f"Unsupported type: {type(dev_type)}")
self.__io.set(TSI_HDRX_CEC_DEVICE_TYPE, value, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_DEVICE_TYPE, value, c_uint32)
@property @property
def status(self) -> CECStatus: def status(self) -> CECStatus:
@@ -144,7 +144,7 @@ class CecRx:
Returns: Returns:
object of `CECStatus` type object of `CECStatus` type
""" """
data = self.__io.get(TSI_HDRX_CEC_STATUS_R, CECStatusPrivate)[1] data = self.__io.get(ci.TSI_HDRX_CEC_STATUS_R, CECStatusPrivate)[1]
return CECStatus(data.bufferOverflowed) return CECStatus(data.bufferOverflowed)
@property @property
@@ -155,7 +155,7 @@ class CecRx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDRX_CEC_RECEIVED_CNT_R, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_CEC_RECEIVED_CNT_R, c_uint32)[1]
@property @property
def data(self) -> list: def data(self) -> list:
@@ -165,8 +165,8 @@ class CecRx:
Returns: Returns:
object of `list` type object of `list` type
""" """
data_size = self.__io.get(TSI_HDRX_CEC_DATA_SIZE_R, c_uint32)[1] data_size = self.__io.get(ci.TSI_HDRX_CEC_DATA_SIZE_R, c_uint32)[1]
return self.__io.get(TSI_HDRX_CEC_DATA_RECIEVED, c_uint32, data_size)[1] return self.__io.get(ci.TSI_HDRX_CEC_DATA_RECIEVED, c_uint32, data_size)[1]
def reset_data(self, command: CecResetDataCommand): def reset_data(self, command: CecResetDataCommand):
""" """
@@ -175,10 +175,10 @@ class CecRx:
Returns: Returns:
object of `CecResetDataCommand` type object of `CecResetDataCommand` type
""" """
self.__io.set(TSI_HDRX_CEC_DATA_RESET_W, command.value, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_DATA_RESET_W, command.value, c_uint32)
def __read_version(self) -> (int, int): def __read_version(self) -> (int, int):
version = self.__io.get(TSI_HDRX_CEC_VERSION_R, CECVersion)[1] version = self.__io.get(ci.TSI_HDRX_CEC_VERSION_R, CECVersion)[1]
return version.minor, version.major return version.minor, version.major
def add_command(self, command: CECCommand = CECCommand()): def add_command(self, command: CECCommand = CECCommand()):
@@ -250,7 +250,7 @@ class CecRx:
self.__send_cec_command() self.__send_cec_command()
def __send_cec_command(self): def __send_cec_command(self):
self.__io.set(TSI_HDRX_CEC_COMMAND, 1, c_uint32) self.__io.set(ci.TSI_HDRX_CEC_COMMAND, 1, c_uint32)
@property @property
def commands(self) -> list: def commands(self) -> list:

View File

@@ -1,5 +1,5 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi_types as ci
from .cec_types import * from .cec_types import *
from .cec_private_types import * from .cec_private_types import *
from typing import Union from typing import Union
@@ -29,7 +29,7 @@ class CecTx:
Args: Args:
state (`bool`) state (`bool`)
""" """
self.__io.set(TSI_HDTX_CEC_CONTROL, state, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_CONTROL, state, c_uint32)
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
""" """
@@ -38,7 +38,7 @@ class CecTx:
Returns: Returns:
object of `bool` type object of `bool` type
""" """
return self.__io.get(TSI_HDTX_CEC_CONTROL, c_uint32)[1] & 0x1 == 1 return self.__io.get(ci.TSI_HDTX_CEC_CONTROL, c_uint32)[1] & 0x1 == 1
@property @property
def logical_address(self) -> LogicalAddressEnum: def logical_address(self) -> LogicalAddressEnum:
@@ -48,11 +48,11 @@ class CecTx:
Returns: Returns:
object of `LogicalAddressEnum` type object of `LogicalAddressEnum` type
""" """
return LogicalAddressEnum(self.__io.get(TSI_HDTX_CEC_LOGICAL_ADDRESS, c_uint32)[1]) return LogicalAddressEnum(self.__io.get(ci.TSI_HDTX_CEC_LOGICAL_ADDRESS, c_uint32)[1])
@logical_address.setter @logical_address.setter
def logical_address(self, address: LogicalAddressEnum): def logical_address(self, address: LogicalAddressEnum):
self.__io.set(TSI_HDTX_CEC_LOGICAL_ADDRESS, address.value, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_LOGICAL_ADDRESS, address.value, c_uint32)
@property @property
def destination(self) -> LogicalAddressEnum: def destination(self) -> LogicalAddressEnum:
@@ -62,11 +62,11 @@ class CecTx:
Returns: Returns:
object of `LogicalAddressEnum` type object of `LogicalAddressEnum` type
""" """
return LogicalAddressEnum(self.__io.get(TSI_HDTX_CEC_DESTINATION, c_uint32)[1]) return LogicalAddressEnum(self.__io.get(ci.TSI_HDTX_CEC_DESTINATION, c_uint32)[1])
@destination.setter @destination.setter
def destination(self, address: LogicalAddressEnum): def destination(self, address: LogicalAddressEnum):
self.__io.set(TSI_HDTX_CEC_DESTINATION, address.value, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_DESTINATION, address.value, c_uint32)
@property @property
def phy_address(self) -> int: def phy_address(self) -> int:
@@ -76,11 +76,11 @@ class CecTx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDTX_CEC_PHYSICAL_ADDRESS, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_CEC_PHYSICAL_ADDRESS, c_uint32)[1]
@phy_address.setter @phy_address.setter
def phy_address(self, address: int): def phy_address(self, address: int):
self.__io.set(TSI_HDTX_CEC_PHYSICAL_ADDRESS, address, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_PHYSICAL_ADDRESS, address, c_uint32)
@property @property
def op_code(self) -> int: def op_code(self) -> int:
@@ -90,11 +90,11 @@ class CecTx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDTX_CEC_OP_CODE, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_CEC_OP_CODE, c_uint32)[1]
@op_code.setter @op_code.setter
def op_code(self, code: int): def op_code(self, code: int):
self.__io.set(TSI_HDTX_CEC_OP_CODE, code, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_OP_CODE, code, c_uint32)
@property @property
def op_code_param(self) -> Union[int, list]: def op_code_param(self) -> Union[int, list]:
@@ -104,12 +104,12 @@ class CecTx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDTX_CEC_OP_CODE_PARAM, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_CEC_OP_CODE_PARAM, c_uint32)[1]
@op_code_param.setter @op_code_param.setter
def op_code_param(self, code_param: Union[int, list]): def op_code_param(self, code_param: Union[int, list]):
data_count = len(code_param) if isinstance(code_param, list) else 1 data_count = len(code_param) if isinstance(code_param, list) else 1
self.__io.set(TSI_HDTX_CEC_OP_CODE_PARAM, code_param, c_uint32, data_count=data_count) self.__io.set(ci.TSI_HDTX_CEC_OP_CODE_PARAM, code_param, c_uint32, data_count=data_count)
@property @property
def device_type(self) -> DeviceType: def device_type(self) -> DeviceType:
@@ -119,7 +119,7 @@ class CecTx:
Returns: Returns:
object of `DeviceType` type object of `DeviceType` type
""" """
data = self.__io.get(TSI_HDTX_CEC_DEVICE_TYPE, DeviceTypePrivate)[1] data = self.__io.get(ci.TSI_HDTX_CEC_DEVICE_TYPE, DeviceTypePrivate)[1]
return DeviceType(data.cecSwitch, data.audioSystem, data.pbDevice, data.tuner, data.recDev, data.tv) return DeviceType(data.cecSwitch, data.audioSystem, data.pbDevice, data.tuner, data.recDev, data.tv)
@device_type.setter @device_type.setter
@@ -134,7 +134,7 @@ class CecTx:
value = dev_type & 0xFF value = dev_type & 0xFF
else: else:
raise TypeError(f"Unsupported type: {type(dev_type)}") raise TypeError(f"Unsupported type: {type(dev_type)}")
self.__io.set(TSI_HDTX_CEC_DEVICE_TYPE, value, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_DEVICE_TYPE, value, c_uint32)
@property @property
def status(self) -> CECStatus: def status(self) -> CECStatus:
@@ -144,7 +144,7 @@ class CecTx:
Returns: Returns:
object of `CECStatus` type object of `CECStatus` type
""" """
data = self.__io.get(TSI_HDTX_CEC_STATUS_R, CECStatusPrivate)[1] data = self.__io.get(ci.TSI_HDTX_CEC_STATUS_R, CECStatusPrivate)[1]
return CECStatus(data.bufferOverflowed) return CECStatus(data.bufferOverflowed)
@property @property
@@ -155,7 +155,7 @@ class CecTx:
Returns: Returns:
object of `int` type object of `int` type
""" """
return self.__io.get(TSI_HDTX_CEC_RECEIVED_CNT_R, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_CEC_RECEIVED_CNT_R, c_uint32)[1]
@property @property
def data(self) -> list: def data(self) -> list:
@@ -165,8 +165,8 @@ class CecTx:
Returns: Returns:
object of `list` type object of `list` type
""" """
data_size = self.__io.get(TSI_HDTX_CEC_DATA_SIZE_R, c_uint32)[1] data_size = self.__io.get(ci.TSI_HDTX_CEC_DATA_SIZE_R, c_uint32)[1]
return self.__io.get(TSI_HDTX_CEC_DATA_RECEIVED_R, c_uint32, data_size)[1] return self.__io.get(ci.TSI_HDTX_CEC_DATA_RECEIVED_R, c_uint32, data_size)[1]
def reset_data(self, command: CecResetDataCommand): def reset_data(self, command: CecResetDataCommand):
""" """
@@ -175,10 +175,10 @@ class CecTx:
Returns: Returns:
object of `CecResetDataCommand` type object of `CecResetDataCommand` type
""" """
self.__io.set(TSI_HDTX_CEC_DATA_RESET_W, command.value, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_DATA_RESET_W, command.value, c_uint32)
def __read_version(self) -> (int, int): def __read_version(self) -> (int, int):
version = self.__io.get(TSI_HDTX_CEC_VERSION_R, CECVersion)[1] version = self.__io.get(ci.TSI_HDTX_CEC_VERSION_R, CECVersion)[1]
return version.minor, version.major return version.minor, version.major
def add_command(self, command: CECCommand = CECCommand()): def add_command(self, command: CECCommand = CECCommand()):
@@ -250,7 +250,7 @@ class CecTx:
self.__send_cec_command() self.__send_cec_command()
def __send_cec_command(self): def __send_cec_command(self):
self.__io.set(TSI_HDTX_CEC_COMMAND, 1, c_uint32) self.__io.set(ci.TSI_HDTX_CEC_COMMAND, 1, c_uint32)
@property @property
def commands(self) -> list: def commands(self) -> list:

View File

@@ -1,8 +1,9 @@
import os import os
from ctypes import c_ubyte
from typing import Union, Tuple from typing import Union, Tuple
from UniTAP.libs.lib_tsi.tsi import *
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_types as ci
class DPCDRegion: class DPCDRegion:
@@ -129,7 +130,7 @@ class DPCDRegisters:
data = bytearray(data) data = bytearray(data)
result = self.__io.set(self.__base_ci, base) result = self.__io.set(self.__base_ci, base)
if result < TSI_SUCCESS: if result < ci.TSI_SUCCESS:
return result return result
result = self.__io.set(self.__data_ci, data, c_ubyte, len(data)) result = self.__io.set(self.__data_ci, data, c_ubyte, len(data))
return result return result

View File

@@ -0,0 +1,2 @@
from .earc_types import EarcMode
from .earc_tx import EarcTx

View File

@@ -0,0 +1,83 @@
from ctypes import c_ubyte
from UniTAP.dev.ports.modules.ag.earc import AudioGeneratorEARC
from UniTAP.dev.modules.memory_manager import MemoryManager
from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
import UniTAP.libs.lib_tsi.tsi_types as ci
from .earc_types import EarcControl, EarcMode, EarcStatus, EarcState, EarcHearthbeatState, EarcRxStatus
class EarcTx:
__MAX_EARC_EDID_SIZE = 128
def __init__(self, port_io: PortIO, memory_manager: MemoryManager) -> None:
self.__io = port_io
self.__earc_ag = AudioGeneratorEARC(port_io, memory_manager)
self.__control = self.__io.get(ci.TSI_HDRX_EARC_CTRL, EarcControl)[1]
def configure(self, mode: EarcMode, latency: int, bypass: bool = False) -> None:
self.__control.mode = mode
self.__control.bypass = bypass
self.__apply_control()
self.__set_audio_latency(latency)
def get_status(self) -> EarcStatus:
"""
Get eARC transmitter status.
Returns:
object of `EarcStatus` type.
"""
return self.__io.get(ci.TSI_HDRX_EARC_STS_R, EarcStatus)[1]
def get_latency(self) -> int:
"""
Get current audio latency for eARC transmitter.
Returns:
object of `int` type.
"""
return self.__io.get(ci.TSI_HDRX_EARC_LATENCY, int)[1]
def get_edid(self) -> bytearray:
"""
Get EDID data from eARC receiver.
Returns:
object of `bytearray` type.
"""
result, edid_data, size = self.__io.get(ci.TSI_HDRX_EARC_EDID_DATA, c_ubyte, self.__MAX_EARC_EDID_SIZE)
if result > 0:
return bytearray(edid_data[:result])
else:
return bytearray()
@property
def ag(self) -> AudioGeneratorEARC:
"""
Get audio generator for eARC transmitter.
Returns:
object of `AudioGeneratorEARC` type.
"""
return self.__earc_ag
def __apply_control(self):
"""
Apply eARC control settings.
"""
self.__io.set(ci.TSI_HDRX_EARC_CTRL, self.__control)
def __set_audio_latency(self, latency: int):
"""
Set audio latency request for eARC transmitter.
Args:
latency (int) - latency value to set
"""
self.__io.set(ci.TSI_HDRX_EARC_LATENCY_REQ, latency)

View File

@@ -0,0 +1,112 @@
from enum import IntEnum
from ctypes import c_uint32, Structure
from UniTAP.utils.bit_ops import get_bitfield, set_bitfield
class EarcMode(IntEnum):
"""
Describes possible eArc modes.
"""
Disabled = 0
eArc = 1
Legacy = 2
eArcNone = 3
class EarcState(IntEnum):
"""
Describes possible eArc states.
"""
H14bARC = 0
IDLE1 = 1
IDLE2 = 2
DISC1 = 3
DISC2 = 4
EARC = 5
def __str__(self) -> str:
return self.name
class EarcHearthbeatState(IntEnum):
"""
Describes possible eArc states.
"""
LOST = 0
SUCCESS = 1
FAIL = 2
def __str__(self) -> str:
return self.name
class EarcRxStatus(IntEnum):
"""
Describes possible eArc RX statuses.
"""
INVALID = 0
STAT_CHNG = 1
CAP_CHNG = 2
EARC_HPD = 4
def __str__(self) -> str:
return self.name
class EarcStatus(Structure):
__EARC_STATE_OFFSET = 0
__EARC_STATE_MASK = 0xF << __EARC_STATE_OFFSET
__EARC_HEARTHBEAT_OFFSET = 4
__EARC_HEARTHBEAT_MASK = 0xF << __EARC_HEARTHBEAT_OFFSET
__EARC_RX_STATUS_OFFSET = 8
__EARC_RX_STATUS_MASK = 0xF << __EARC_RX_STATUS_OFFSET
_fields_ = [
('data', c_uint32, 32)
]
def __init__(self, value: int) -> None:
self.data = value
@property
def earc_state(self) -> EarcState:
return EarcState(get_bitfield(self.data, self.__EARC_STATE_MASK, self.__EARC_STATE_OFFSET))
@property
def earc_hearthbeat(self) -> EarcHearthbeatState:
return EarcHearthbeatState(get_bitfield(self.data, self.__EARC_HEARTHBEAT_MASK, self.__EARC_HEARTHBEAT_OFFSET))
@property
def earc_rx_status(self) -> EarcRxStatus:
return EarcRxStatus(get_bitfield(self.data, self.__EARC_RX_STATUS_MASK, self.__EARC_RX_STATUS_OFFSET))
def __str__(self) -> str:
return f"EarcStatus(state={self.earc_state}, heartbeat={self.earc_hearthbeat}, rx_status={self.earc_rx_status})"
class EarcControl(Structure):
__EARC_MODE_OFFSET = 0
__EARC_MODE_MASK = 0x7 << __EARC_MODE_OFFSET
__EARC_BYPASS_OFFSET = 3
__EARC_BYPASS_MASK = 0x1 << __EARC_BYPASS_OFFSET
_fields_ = [
('data', c_uint32, 32)
]
def __init__(self, value: int) -> None:
self.data = value
@property
def mode(self) -> EarcMode:
return EarcMode(get_bitfield(self.data, self.__EARC_MODE_MASK, self.__EARC_MODE_OFFSET))
@mode.setter
def mode(self, value: EarcMode):
self.data = set_bitfield(self.data, self.__EARC_MODE_MASK, self.__EARC_MODE_OFFSET, value.value)
@property
def bypass(self) -> bool:
return bool(get_bitfield(self.data, self.__EARC_BYPASS_MASK, self.__EARC_BYPASS_OFFSET))
@bypass.setter
def bypass(self, value: bool):
self.data = set_bitfield(self.data, self.__EARC_BYPASS_MASK, self.__EARC_BYPASS_OFFSET, int(value))

View File

@@ -3,10 +3,7 @@ from typing import List
from UniTAP.common import Timing from UniTAP.common import Timing
from UniTAP.libs.lib_tsi.tsi_types import TSI_EDID_SELECT_STREAM, TSI_EDID_TE_INPUT, TSI_EDID_TE_OUTPUT, \ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_EDID_TE_OUTPUT_REMOTE_R, TSI_DID_TE_OUTPUT, TSI_DID_TE_INPUT, TSI_DID_SELECT_STREAM, \
TSI_DID_TE_OUTPUT_REMOTE_R, TSI_DPRX_DISPLAYID_CTRL, TSI_DPTX_DISPLAYID_CTRL, TSI_EDID_DUT_TIMINGS_COUNT, \
TSI_EDID_DUT_TIMINGS_DATA
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.dev.ports.modules.device_constants import MAX_EDID_SIZE from UniTAP.dev.ports.modules.device_constants import MAX_EDID_SIZE
from ctypes import c_ubyte, c_uint32 from ctypes import c_ubyte, c_uint32
@@ -67,12 +64,12 @@ class Edid:
""" """
""" """
timings_count = self._io.get(TSI_EDID_DUT_TIMINGS_COUNT, c_uint32)[1] timings_count = self._io.get(ci.TSI_EDID_DUT_TIMINGS_COUNT, c_uint32)[1]
if timings_count == 0: if timings_count == 0:
return [] return []
timings = self._io.get(TSI_EDID_DUT_TIMINGS_DATA, ParsedTimingStruct, timings_count)[1] timings = self._io.get(ci.TSI_EDID_DUT_TIMINGS_DATA, ParsedTimingStruct, timings_count)[1]
parsed_timings = [] parsed_timings = []
for i in range(timings_count): for i in range(timings_count):
@@ -123,7 +120,7 @@ class EdidSource(Edid):
""" """
def __init__(self, port_io: PortIO, max_stream_count: int): def __init__(self, port_io: PortIO, max_stream_count: int):
super().__init__(port_io, TSI_EDID_TE_OUTPUT, max_stream_count, TSI_EDID_SELECT_STREAM) super().__init__(port_io, ci.TSI_EDID_TE_OUTPUT, max_stream_count, ci.TSI_EDID_SELECT_STREAM)
def read_sbm(self, stream: int): def read_sbm(self, stream: int):
""" """
@@ -137,7 +134,7 @@ class EdidSource(Edid):
""" """
self._select_stream(stream) self._select_stream(stream)
result, edid_data, size = self._io.get(TSI_EDID_TE_OUTPUT_REMOTE_R, c_ubyte, MAX_EDID_SIZE) result, edid_data, size = self._io.get(ci.TSI_EDID_TE_OUTPUT_REMOTE_R, c_ubyte, MAX_EDID_SIZE)
if result > 0: if result > 0:
return bytearray(edid_data[:result]) return bytearray(edid_data[:result])
else: else:
@@ -153,7 +150,7 @@ class EdidSink(Edid):
""" """
def __init__(self, port_io: PortIO, max_stream_count: int): def __init__(self, port_io: PortIO, max_stream_count: int):
super().__init__(port_io, TSI_EDID_TE_INPUT, max_stream_count, TSI_EDID_SELECT_STREAM) super().__init__(port_io, ci.TSI_EDID_TE_INPUT, max_stream_count, ci.TSI_EDID_SELECT_STREAM)
def write_edid(self, data: bytearray, stream: int = 0): def write_edid(self, data: bytearray, stream: int = 0):
""" """
@@ -216,7 +213,7 @@ class DisplayIdSource(Edid):
""" """
def __init__(self, port_io: PortIO, max_stream_count: int): def __init__(self, port_io: PortIO, max_stream_count: int):
super().__init__(port_io, TSI_DID_TE_OUTPUT, max_stream_count, TSI_DID_SELECT_STREAM) super().__init__(port_io, ci.TSI_DID_TE_OUTPUT, max_stream_count, ci.TSI_DID_SELECT_STREAM)
def read_sbm(self, stream: int): def read_sbm(self, stream: int):
""" """
@@ -230,7 +227,7 @@ class DisplayIdSource(Edid):
""" """
self._select_stream(stream) self._select_stream(stream)
result, data, size = self._io.get(TSI_DID_TE_OUTPUT_REMOTE_R, c_ubyte, MAX_EDID_SIZE) result, data, size = self._io.get(ci.TSI_DID_TE_OUTPUT_REMOTE_R, c_ubyte, MAX_EDID_SIZE)
if result > 0: if result > 0:
return bytearray(data[:result]) return bytearray(data[:result])
else: else:
@@ -243,7 +240,7 @@ class DisplayIdSource(Edid):
Args: Args:
mode (`DisplayIDReadMode`) mode (`DisplayIDReadMode`)
""" """
self._io.set(TSI_DPTX_DISPLAYID_CTRL, mode.value, c_uint32) self._io.set(ci.TSI_DPTX_DISPLAYID_CTRL, mode.value, c_uint32)
def get_display_id_mode(self) -> DisplayIDReadMode: def get_display_id_mode(self) -> DisplayIDReadMode:
""" """
@@ -252,7 +249,7 @@ class DisplayIdSource(Edid):
Returns: Returns:
object of `DisplayIDReadMode` type. object of `DisplayIDReadMode` type.
""" """
result = self._io.get(TSI_DPTX_DISPLAYID_CTRL, c_uint32)[1] result = self._io.get(ci.TSI_DPTX_DISPLAYID_CTRL, c_uint32)[1]
return DisplayIDReadMode(result) return DisplayIDReadMode(result)
@@ -265,7 +262,7 @@ class DisplayIdSink(Edid):
""" """
def __init__(self, port_io: PortIO, max_stream_count: int): def __init__(self, port_io: PortIO, max_stream_count: int):
super().__init__(port_io, TSI_DID_TE_INPUT, max_stream_count, TSI_DID_SELECT_STREAM) super().__init__(port_io, ci.TSI_DID_TE_INPUT, max_stream_count, ci.TSI_DID_SELECT_STREAM)
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
""" """
@@ -274,7 +271,7 @@ class DisplayIdSink(Edid):
Returns: Returns:
object of `bool` type. object of `bool` type.
""" """
result = self._io.get(TSI_DPRX_DISPLAYID_CTRL, c_uint32) result = self._io.get(ci.TSI_DPRX_DISPLAYID_CTRL, c_uint32)
status_display_id = ((result[1] & 0x1) != 0) status_display_id = ((result[1] & 0x1) != 0)
return bool(status_display_id) return bool(status_display_id)
@@ -286,7 +283,7 @@ class DisplayIdSink(Edid):
enable (bool) - enable (True) or disable (False) enable (bool) - enable (True) or disable (False)
""" """
val = 0x1 if enable else 0x0 val = 0x1 if enable else 0x0
self._io.set(TSI_DPRX_DISPLAYID_CTRL, val) self._io.set(ci.TSI_DPRX_DISPLAYID_CTRL, val)
def write_display_id(self, data: bytearray): def write_display_id(self, data: bytearray):

View File

@@ -1,4 +1,6 @@
from UniTAP.libs.lib_tsi.tsi import * from ctypes import c_int
import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .fec_shared import FECCounters from .fec_shared import FECCounters
@@ -27,7 +29,7 @@ class FecRx:
Returns: Returns:
object of `bool` type. object of `bool` type.
""" """
result = self.__io.get(TSI_DPRX_FEC_STATUS_R, c_int) result = self.__io.get(ci.TSI_DPRX_FEC_STATUS_R, c_int)
status_fec = ((result[1] & 0x1) != 0) status_fec = ((result[1] & 0x1) != 0)
return bool(status_fec) return bool(status_fec)
@@ -38,7 +40,7 @@ class FecRx:
Returns: Returns:
object of `bool` type. object of `bool` type.
""" """
result = self.__io.get(TSI_DPRX_FEC_CTRL, c_int) result = self.__io.get(ci.TSI_DPRX_FEC_CTRL, c_int)
enabled_fec = (result[1] & 0x1) != 0 enabled_fec = (result[1] & 0x1) != 0
return enabled_fec return enabled_fec
@@ -50,7 +52,7 @@ class FecRx:
enable (bool) - enable (True) or disable (False) enable (bool) - enable (True) or disable (False)
""" """
val = 0x1 if enable else 0x0 val = 0x1 if enable else 0x0
self.__io.set(TSI_DPRX_FEC_CTRL, val) self.__io.set(ci.TSI_DPRX_FEC_CTRL, val)
def aggregate_errors(self, enable: bool): def aggregate_errors(self, enable: bool):
""" """
@@ -59,7 +61,7 @@ class FecRx:
Args: Args:
enable (bool) - enable (True) or disable (False) enable (bool) - enable (True) or disable (False)
""" """
result = self.__io.get(TSI_DPRX_FEC_CONTROL, c_int) result = self.__io.get(ci.TSI_DPRX_FEC_CONTROL, c_int)
val = result[1] val = result[1]
if enable: if enable:
val |= 0x2 val |= 0x2
@@ -67,7 +69,7 @@ class FecRx:
else: else:
val &= ~0x2 val &= ~0x2
self.__aggregate_error = 0 self.__aggregate_error = 0
self.__io.set(TSI_DPRX_FEC_CONTROL, val) self.__io.set(ci.TSI_DPRX_FEC_CONTROL, val)
def get_error_counters(self) -> FECCounters: def get_error_counters(self) -> FECCounters:
""" """
@@ -78,7 +80,7 @@ class FecRx:
object of `FECCounters` type object of `FECCounters` type
""" """
result = FECCounters() result = FECCounters()
lane_count = self.__io.get(TSI_R_DPRX_LINK_LANE_COUNT, c_int)[1] lane_count = self.__io.get(ci.TSI_R_DPRX_LINK_LANE_COUNT, c_int)[1]
if lane_count == 4: if lane_count == 4:
lane_count += 1 if self.__aggregate_error else 0 lane_count += 1 if self.__aggregate_error else 0

View File

@@ -1,5 +1,8 @@
from UniTAP.libs.lib_tsi.tsi import * from ctypes import c_int, c_uint32
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
import UniTAP.libs.lib_tsi.tsi_types as ci
from .fec_shared import FECCounters, FECErrorType8b10b, FECErrorType128b132b from .fec_shared import FECCounters, FECErrorType8b10b, FECErrorType128b132b
from UniTAP.dev.ports.modules.dpcd.dpcd import DPCDRegisters from UniTAP.dev.ports.modules.dpcd.dpcd import DPCDRegisters
@@ -29,7 +32,7 @@ class FecTx:
Returns: Returns:
object of `bool` type. object of `bool` type.
""" """
result = self.__io.get(TSI_DPTX_FEC_STATUS_R, c_int) result = self.__io.get(ci.TSI_DPTX_FEC_STATUS_R, c_int)
status_fec = ((result[1] & 0x1) != 0) status_fec = ((result[1] & 0x1) != 0)
return bool(status_fec) return bool(status_fec)
@@ -40,7 +43,7 @@ class FecTx:
Returns: Returns:
object of `bool` type. object of `bool` type.
""" """
result = self.__io.get(TSI_DPTX_FEC_CTRL, c_int) result = self.__io.get(ci.TSI_DPTX_FEC_CTRL, c_int)
enabled_fec = (result[1] & 0x2) != 0 enabled_fec = (result[1] & 0x2) != 0
return enabled_fec return enabled_fec
@@ -51,10 +54,10 @@ class FecTx:
Args: Args:
enable (bool) - enable (True) or disable (False) enable (bool) - enable (True) or disable (False)
""" """
result = self.__io.get(TSI_DPTX_FEC_CTRL, c_int) result = self.__io.get(ci.TSI_DPTX_FEC_CTRL, c_int)
val = result[1] val = result[1]
val |= 0x8 if enable else 0x10 val |= 0x8 if enable else 0x10
self.__io.set(TSI_DPTX_FEC_CTRL, val) self.__io.set(ci.TSI_DPTX_FEC_CTRL, val)
def enable_intent(self, enable: bool): def enable_intent(self, enable: bool):
""" """
@@ -63,10 +66,10 @@ class FecTx:
Args: Args:
enable (bool) - enable (True) or disable (False) enable (bool) - enable (True) or disable (False)
""" """
result = self.__io.get(TSI_DPTX_FEC_CTRL, c_int) result = self.__io.get(ci.TSI_DPTX_FEC_CTRL, c_int)
val = result[1] val = result[1]
val |= 1 if enable else 4 val |= 1 if enable else 4
self.__io.set(TSI_DPTX_FEC_CTRL, val) self.__io.set(ci.TSI_DPTX_FEC_CTRL, val)
def aggregate_errors(self, enable: bool): def aggregate_errors(self, enable: bool):
""" """
@@ -75,7 +78,7 @@ class FecTx:
Args: Args:
enable (bool) - enable (True) or disable (False) enable (bool) - enable (True) or disable (False)
""" """
result = self.__io.get(TSI_DPTX_FEC_CONTROL, c_int) result = self.__io.get(ci.TSI_DPTX_FEC_CONTROL, c_int)
val = result[1] val = result[1]
if enable: if enable:
val |= 0x40 val |= 0x40
@@ -83,7 +86,7 @@ class FecTx:
else: else:
val &= ~0x40 val &= ~0x40
self.__aggregate_error = 0 self.__aggregate_error = 0
self.__io.set(TSI_DPTX_FEC_CONTROL, val) self.__io.set(ci.TSI_DPTX_FEC_CONTROL, val)
def generate_errors(self, error_type: Union[FECErrorType8b10b, FECErrorType128b132b], lane: list, ms: int = 100): def generate_errors(self, error_type: Union[FECErrorType8b10b, FECErrorType128b132b], lane: list, ms: int = 100):
""" """
@@ -94,8 +97,8 @@ class FecTx:
lane (list) lane (list)
ms (int) - time in m seconds ms (int) - time in m seconds
""" """
result, status = self.__io.get(TSI_DPTX_LINK_MODE_R, c_int) result, status = self.__io.get(ci.TSI_DPTX_LINK_MODE_R, c_int)
resut, hw_caps, size = self.__io.get(TSI_DPTX_HW_CAPS_R, c_uint32, 4) resut, hw_caps, size = self.__io.get(ci.TSI_DPTX_HW_CAPS_R, c_uint32, 4)
if status == 0: if status == 0:
if isinstance(error_type, FECErrorType128b132b): if isinstance(error_type, FECErrorType128b132b):
assert False, "This device doesn't support 128b/132b" if (hw_caps[1] & 0x7) == 0 else "Change link mode!" assert False, "This device doesn't support 128b/132b" if (hw_caps[1] & 0x7) == 0 else "Change link mode!"
@@ -109,24 +112,24 @@ class FecTx:
delay = ms * 100 delay = ms * 100
self.__io.set(TSI_MLEG_CONTROL, 0) self.__io.set(p_ci.TSI_MLEG_CONTROL, 0)
nl = self.__io.get(TSI_R_DPTX_LINK_STATUS_LANE_COUNT, c_uint32)[1] nl = self.__io.get(ci.TSI_R_DPTX_LINK_STATUS_LANE_COUNT, c_uint32)[1]
self.__io.set(TSI_MLEG_SYMBOL_REPLACE_A, 0x00010000) self.__io.set(p_ci.TSI_MLEG_SYMBOL_REPLACE_A, 0x00010000)
self.__io.set(TSI_MLEG_SYMBOL_REPLACE_MASK_A, 0x00010001) self.__io.set(p_ci.TSI_MLEG_SYMBOL_REPLACE_MASK_A, 0x00010001)
self.__io.set(TSI_MLEG_SYMBOL_REPLACE_B, 0x00000001) self.__io.set(p_ci.TSI_MLEG_SYMBOL_REPLACE_B, 0x00000001)
self.__io.set(TSI_MLEG_SYMBOL_REPLACE_MASK_B, 0x00010001) self.__io.set(p_ci.TSI_MLEG_SYMBOL_REPLACE_MASK_B, 0x00010001)
self.__io.set(TSI_MLEG_DELAY_COUNTER, delay) self.__io.set(p_ci.TSI_MLEG_DELAY_COUNTER, delay)
n = lane[0] << 16 n = lane[0] << 16
self.__io.set(TSI_MLEG_LANE0_REPLACE_COUNTERS, n) self.__io.set(p_ci.TSI_MLEG_LANE0_REPLACE_COUNTERS, n)
n = lane[1] << 16 n = lane[1] << 16
self.__io.set(TSI_MLEG_LANE1_REPLACE_COUNTERS, n) self.__io.set(p_ci.TSI_MLEG_LANE1_REPLACE_COUNTERS, n)
n = lane[2] << 16 n = lane[2] << 16
self.__io.set(TSI_MLEG_LANE2_REPLACE_COUNTERS, n) self.__io.set(p_ci.TSI_MLEG_LANE2_REPLACE_COUNTERS, n)
n = lane[3] << 16 n = lane[3] << 16
self.__io.set(TSI_MLEG_LANE3_REPLACE_COUNTERS, n) self.__io.set(p_ci.TSI_MLEG_LANE3_REPLACE_COUNTERS, n)
ctrl = 0 ctrl = 0
ctrl |= (error_type.value << 16) ctrl |= (error_type.value << 16)
@@ -144,7 +147,7 @@ class FecTx:
if lane[3]: if lane[3]:
ctrl |= (1 << 3) ctrl |= (1 << 3)
self.__io.set(TSI_MLEG_CONTROL, ctrl) self.__io.set(p_ci.TSI_MLEG_CONTROL, ctrl)
def get_error_counters(self) -> FECCounters: def get_error_counters(self) -> FECCounters:
""" """
@@ -154,7 +157,7 @@ class FecTx:
object of `FECCounters` type object of `FECCounters` type
""" """
result = FECCounters() result = FECCounters()
lane_count = self.__io.get(TSI_R_DPTX_LINK_STATUS_LANE_COUNT, c_uint32)[1] lane_count = self.__io.get(ci.TSI_R_DPTX_LINK_STATUS_LANE_COUNT, c_uint32)[1]
if lane_count == 4: if lane_count == 4:
lane_count += 1 if self.__aggregate_error else 0 lane_count += 1 if self.__aggregate_error else 0

View File

@@ -1,9 +1,10 @@
import warnings import warnings
from typing import Optional, Union from ctypes import c_int
from typing import Optional, Union, Type
import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol
from .types import * from .types import *
from UniTAP.libs.lib_tsi.tsi import c_int
class HdcpSinkStatus: class HdcpSinkStatus:
@@ -77,7 +78,7 @@ class HdcpSinkStatus:
def __read_status(self, mode: HdcpMode) -> int: def __read_status(self, mode: HdcpMode) -> int:
if mode == HdcpMode.Mode1_4: if mode == HdcpMode.Mode1_4:
return self.__io.get(TSI_HDCP_1X_STATUS_R, c_int)[1] return self.__io.get(ci.TSI_HDCP_1X_STATUS_R, c_int)[1]
else: else:
return self.__io.get(self.__ci_status_control, c_int)[1] return self.__io.get(self.__ci_status_control, c_int)[1]
@@ -164,7 +165,7 @@ class HdcpSinkConfig:
if keys == HdcpSink2XKeys.Production and not self.__caps_2x.production_keys_available: if keys == HdcpSink2XKeys.Production and not self.__caps_2x.production_keys_available:
warnings.warn("Production keys is not hw supported. Please, select another keys.") 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) self.__io.set(ci.TSI_HDCP_1X_COMMAND_W if hdcp_mode == HdcpMode.Mode1_4 else ci.TSI_HDCP_2X_COMMAND_W, keys.value)
def __set_capable(self, value: Optional[bool], hdcp_mode: HdcpMode): def __set_capable(self, value: Optional[bool], hdcp_mode: HdcpMode):
if value is None: if value is None:
@@ -172,9 +173,10 @@ class HdcpSinkConfig:
if not self.__full_check(hdcp_mode): if not self.__full_check(hdcp_mode):
return return
self.__io.set(TSI_HDCP_1X_COMMAND_W if hdcp_mode == HdcpMode.Mode1_4 else TSI_HDCP_2X_COMMAND_W, self.__io.set(ci.TSI_HDCP_1X_COMMAND_W if hdcp_mode == HdcpMode.Mode1_4 else ci.TSI_HDCP_2X_COMMAND_W,
(H1_SINK_SET_CAPABLE if value else H1_SINK_CLEAR_CAPABLE) (ci.H1_SINK_SET_CAPABLE if value else ci.H1_SINK_CLEAR_CAPABLE)
if hdcp_mode == HdcpMode.Mode1_4 else (H2_SINK_SET_CAPABLE if value else H2_SINK_CLEAR_CAPABLE)) if hdcp_mode == HdcpMode.Mode1_4 else (
ci.H2_SINK_SET_CAPABLE if value else ci.H2_SINK_CLEAR_CAPABLE))
def __full_check(self, hdcp_mode: HdcpMode) -> bool: def __full_check(self, hdcp_mode: HdcpMode) -> bool:
if hdcp_mode == HdcpMode.Unknown: if hdcp_mode == HdcpMode.Unknown:
@@ -239,7 +241,7 @@ class HdcpSink:
def __read_hw_caps(self, mode: HdcpMode, ci_caps_control: int = 0) -> int: def __read_hw_caps(self, mode: HdcpMode, ci_caps_control: int = 0) -> int:
if mode == HdcpMode.Mode1_4: if mode == HdcpMode.Mode1_4:
return self.__io.get(TSI_HDCP_1X_STATUS_R, c_int)[1] return self.__io.get(ci.TSI_HDCP_1X_STATUS_R, c_int)[1]
elif mode == HdcpMode.Mode2_3: elif mode == HdcpMode.Mode2_3:
return self.__io.get(ci_caps_control, c_int)[1] return self.__io.get(ci_caps_control, c_int)[1]
else: else:

View File

@@ -1,10 +1,11 @@
import warnings import warnings
from typing import Optional, Union from typing import Optional, Union, Type
from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol from UniTAP.libs.lib_tsi.tsi_io import PortIO, PortProtocol
from .types import * from .types import *
from UniTAP.libs.lib_tsi.tsi_private_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
from ctypes import c_int import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from ctypes import c_int, c_uint32
class HdcpSourceStatus: class HdcpSourceStatus:
@@ -52,10 +53,18 @@ class HdcpSourceStatus:
if self.__caps_1x.hw_supported: if self.__caps_1x.hw_supported:
status_value = self.__read_status(HdcpMode.Mode1_4) status_value = self.__read_status(HdcpMode.Mode1_4)
status = HdcpStatus.Status1x() status = HdcpStatus.Status1x()
if (status_value >> 9) & 1:
status.keys = HdcpSource1XKeys.Test
elif (status_value >> 10) & 1:
status.keys = HdcpSource1XKeys.Production
else:
status.keys = HdcpSource1XKeys.Unload
status.active = (status_value >> 8) & 1 status.active = (status_value >> 8) & 1
status.keys = HdcpSource1XKeys(((status_value >> 9) & 3) + 0x100)
status.capable = ((status_value >> 11) & 1) status.capable = ((status_value >> 11) & 1)
status.authenticated = ((status_value >> 12) & 1) status.authenticated = ((status_value >> 12) & 1)
return status return status
else: else:
warnings.warn(f"Not supported 'HDCP 1.4'") warnings.warn(f"Not supported 'HDCP 1.4'")
@@ -63,9 +72,7 @@ class HdcpSourceStatus:
if self.__caps_2x.hw_supported: if self.__caps_2x.hw_supported:
status_value = self.__read_status(HdcpMode.Mode2_3) status_value = self.__read_status(HdcpMode.Mode2_3)
status = HdcpStatus.StatusTx2x() status = HdcpStatus.StatusTx2x()
if self.__io.protocol() == PortProtocol.HDMI:
status.keys = HdcpSource2XKeys.Production if (status_value >> 9) & 1 else HdcpSource2XKeys.Unload
else:
if (status_value >> 14) & 1: if (status_value >> 14) & 1:
status.keys = HdcpSource2XKeys.TestR1 status.keys = HdcpSource2XKeys.TestR1
elif (status_value >> 15) & 1: elif (status_value >> 15) & 1:
@@ -78,7 +85,7 @@ class HdcpSourceStatus:
status.km_is_stored = (status_value >> 13) & 1 status.km_is_stored = (status_value >> 13) & 1
status.try_authenticate = (status_value >> 18) & 1 status.try_authenticate = (status_value >> 18) & 1
status.try_encrypt = (status_value >> 19) & 1 status.try_encrypt = (status_value >> 19) & 1
status.content_level = self.__io.get(TSI_HDCP_2X_CFG, c_uint32)[1] status.content_level = self.__io.get(p_ci.TSI_HDCP_2X_CFG, c_uint32)[1]
status.active = (status_value >> 8) & 1 status.active = (status_value >> 8) & 1
status.capable = (status_value >> 10) & 1 status.capable = (status_value >> 10) & 1
@@ -90,7 +97,7 @@ class HdcpSourceStatus:
def __read_status(self, mode: HdcpMode): def __read_status(self, mode: HdcpMode):
if mode == HdcpMode.Mode1_4: if mode == HdcpMode.Mode1_4:
return self.__io.get(TSI_HDCP_1X_STATUS_R, c_int)[1] return self.__io.get(ci.TSI_HDCP_1X_STATUS_R, c_int)[1]
elif mode == HdcpMode.Mode2_3: elif mode == HdcpMode.Mode2_3:
return self.__io.get(self.__ci_status_control, c_int)[1] return self.__io.get(self.__ci_status_control, c_int)[1]
else: else:
@@ -172,17 +179,17 @@ class HdcpSourceConfig:
if value is None: if value is None:
return return
if hdcp_mode == HdcpMode.Mode1_4: if hdcp_mode == HdcpMode.Mode1_4:
self.__io.set(TSI_HDCP_1X_COMMAND_W, H1_SOURCE_ENABLE_ENCRYPT if value else H1_SOURCE_DISABLE_ENCRYPT) self.__io.set(ci.TSI_HDCP_1X_COMMAND_W, ci.H1_SOURCE_ENABLE_ENCRYPT if value else ci.H1_SOURCE_DISABLE_ENCRYPT)
elif hdcp_mode == HdcpMode.Mode2_3: elif hdcp_mode == HdcpMode.Mode2_3:
self.__io.set(TSI_HDCP_2X_COMMAND_W, H2_SOURCE_ENABLE_ENCRYPT if value else H2_SOURCE_DISABLE_ENCRYPT) self.__io.set(ci.TSI_HDCP_2X_COMMAND_W, ci.H2_SOURCE_ENABLE_ENCRYPT if value else ci.H2_SOURCE_DISABLE_ENCRYPT)
def __set_authenticate(self, value: Optional[bool], hdcp_mode: HdcpMode): def __set_authenticate(self, value: Optional[bool], hdcp_mode: HdcpMode):
if value is None: if value is None:
return return
if hdcp_mode == HdcpMode.Mode1_4: if hdcp_mode == HdcpMode.Mode1_4:
self.__io.set(TSI_HDCP_1X_COMMAND_W, H1_SOURCE_AUTHENTICATE if value else H1_SOURCE_DE_AUTHENTICATE) self.__io.set(ci.TSI_HDCP_1X_COMMAND_W, ci.H1_SOURCE_AUTHENTICATE if value else ci.H1_SOURCE_DE_AUTHENTICATE)
elif hdcp_mode == HdcpMode.Mode2_3: elif hdcp_mode == HdcpMode.Mode2_3:
self.__io.set(TSI_HDCP_2X_COMMAND_W, H2_SOURCE_AUTHENTICATE if value else H2_SOURCE_DE_AUTHENTICATE) self.__io.set(ci.TSI_HDCP_2X_COMMAND_W, ci.H2_SOURCE_AUTHENTICATE if value else ci.H2_SOURCE_DE_AUTHENTICATE)
def __load_keys(self, keys: Optional[Union[HdcpSource1XKeys, HdcpSource2XKeys]], hdcp_mode: HdcpMode): def __load_keys(self, keys: Optional[Union[HdcpSource1XKeys, HdcpSource2XKeys]], hdcp_mode: HdcpMode):
if keys is None: if keys is None:
@@ -203,7 +210,7 @@ class HdcpSourceConfig:
if keys == HdcpSource2XKeys.Production and not self.__caps_2x.production_keys_available: if keys == HdcpSource2XKeys.Production and not self.__caps_2x.production_keys_available:
warnings.warn("Production keys is not hw supported. Please, select another keys.") 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) self.__io.set(ci.TSI_HDCP_1X_COMMAND_W if hdcp_mode == HdcpMode.Mode1_4 else ci.TSI_HDCP_2X_COMMAND_W, keys.value)
def __full_check(self, hdcp_mode: HdcpMode) -> bool: def __full_check(self, hdcp_mode: HdcpMode) -> bool:
if hdcp_mode == HdcpMode.Unknown: if hdcp_mode == HdcpMode.Unknown:
@@ -231,14 +238,14 @@ class HdcpSourceConfig:
def __set_store_km(self, value: Optional[bool]): def __set_store_km(self, value: Optional[bool]):
if value is None: if value is None:
return return
self.__io.set(TSI_HDCP_2X_COMMAND_W, H2_SOURCE_AUTHENTICATE_STORE_KM if value else H2_SOURCE_CLEAR_STORE_KM) self.__io.set(ci.TSI_HDCP_2X_COMMAND_W, ci.H2_SOURCE_AUTHENTICATE_STORE_KM if value else ci.H2_SOURCE_CLEAR_STORE_KM)
def __set_content_level(self, value: Optional[int]): def __set_content_level(self, value: Optional[int]):
if value is None: if value is None:
return return
if value not in [0, 1]: if value not in [0, 1]:
raise ValueError(f"Incorrect input value of 'Content level' - {value}. Must be from range: 0-1") raise ValueError(f"Incorrect input value of 'Content level' - {value}. Must be from range: 0-1")
self.__io.set(TSI_HDCP_2X_CFG, value) self.__io.set(p_ci.TSI_HDCP_2X_CFG, value)
class HdcpSource: class HdcpSource:
@@ -280,7 +287,7 @@ class HdcpSource:
def __read_hw_caps(self, mode: HdcpMode, ci_caps_control: int = 0) -> int: def __read_hw_caps(self, mode: HdcpMode, ci_caps_control: int = 0) -> int:
if mode == HdcpMode.Mode1_4: if mode == HdcpMode.Mode1_4:
return self.__io.get(TSI_HDCP_1X_STATUS_R, c_int)[1] return self.__io.get(ci.TSI_HDCP_1X_STATUS_R, c_int)[1]
elif mode == HdcpMode.Mode2_3: elif mode == HdcpMode.Mode2_3:
return self.__io.get(ci_caps_control, c_int)[1] return self.__io.get(ci_caps_control, c_int)[1]
else: else:

View File

@@ -1,38 +1,37 @@
from typing import TypeVar from typing import TypeVar
from UniTAP.libs.lib_tsi.tsi_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
from enum import IntEnum from enum import IntEnum
from typing import Type
class HdcpSink1XKeys(IntEnum): class HdcpSink1XKeys(IntEnum):
Unknown = -1 Unknown = -1
Unload = H1_SINK_UNLOAD_KEYS Unload = ci.H1_SINK_UNLOAD_KEYS
Test = H1_SINK_LOAD_TEST_KEYS Test = ci.H1_SINK_LOAD_TEST_KEYS
Production = H1_SINK_LOAD_PROD_KEYS Production = ci.H1_SINK_LOAD_PROD_KEYS
class HdcpSink2XKeys(IntEnum): class HdcpSink2XKeys(IntEnum):
Unknown = -1 Unknown = -1
Unload = H2_SINK_UNLOAD_KEYS Unload = ci.H2_SINK_UNLOAD_KEYS
Production = H2_SINK_LOAD_PROD_KEYS Production = ci.H2_SINK_LOAD_PROD_KEYS
TestR1 = H2_SINK_LOAD_TEST_KEYS_R1 TestR1 = ci.H2_SINK_LOAD_TEST_KEYS_R1
TestR2 = H2_SINK_LOAD_TEST_KEYS_R2 TestR2 = ci.H2_SINK_LOAD_TEST_KEYS_R2
class HdcpSource1XKeys(IntEnum): class HdcpSource1XKeys(IntEnum):
Unknown = -1 Unknown = -1
Unload = H1_SOURCE_UNLOAD_KEYS Unload = ci.H1_SOURCE_UNLOAD_KEYS
Test = H1_SOURCE_LOAD_TEST_KEYS Test = ci.H1_SOURCE_LOAD_TEST_KEYS
Production = H1_SOURCE_LOAD_PROD_KEYS Production = ci.H1_SOURCE_LOAD_PROD_KEYS
class HdcpSource2XKeys(IntEnum): class HdcpSource2XKeys(IntEnum):
Unknown = -1 Unknown = -1
Unload = H2_SOURCE_UNLOAD_KEYS Unload = ci.H2_SOURCE_UNLOAD_KEYS
Production = H2_SOURCE_LOAD_PROD_KEYS Production = ci.H2_SOURCE_LOAD_PROD_KEYS
TestR1 = H2_SOURCE_LOAD_TEST_KEYS_R1 TestR1 = ci.H2_SOURCE_LOAD_TEST_KEYS_R1
TestR2 = H2_SOURCE_LOAD_TEST_KEYS_R2 TestR2 = ci.H2_SOURCE_LOAD_TEST_KEYS_R2
class HdcpMode(IntEnum): class HdcpMode(IntEnum):

View File

@@ -1,6 +1,8 @@
from .link_rx_caps import LinkDisplayPortCaps from .link_rx_caps import LinkDisplayPortCaps
from .link_rx_status import * from .link_rx_status import *
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
import UniTAP.libs.lib_tsi.tsi_types as ci
from .dp_cable_info import DpCableInfo, CableCapabilitiesEnum from .dp_cable_info import DpCableInfo, CableCapabilitiesEnum
from .link_rx_aux_controller import DisplayPortAUXController from .link_rx_aux_controller import DisplayPortAUXController
from UniTAP.dev.ports.modules.dpcd import DPCDRegisters from UniTAP.dev.ports.modules.dpcd import DPCDRegisters
@@ -20,7 +22,7 @@ class LinkDisplayPortRx:
self.__HW_CAPS = hw_caps self.__HW_CAPS = hw_caps
self.__status = LinkDisplayPortStatusSink(port_io, self.__HW_CAPS) self.__status = LinkDisplayPortStatusSink(port_io, self.__HW_CAPS)
self.__capabilities = LinkDisplayPortCaps(port_io, self.__HW_CAPS) self.__capabilities = LinkDisplayPortCaps(port_io, self.__HW_CAPS)
self.__cable_info = DpCableInfo(port_io, TSI_DPRX_CABLE_ATTRIBUTES_R) self.__cable_info = DpCableInfo(port_io, p_ci.TSI_DPRX_CABLE_ATTRIBUTES_R)
self.__aux_controller = DisplayPortAUXController(port_io, dpcd) self.__aux_controller = DisplayPortAUXController(port_io, dpcd)
@property @property
@@ -60,7 +62,7 @@ class LinkDisplayPortRx:
Args: Args:
duration_us (int) duration_us (int)
""" """
self.__io.set(TSI_DPRX_HPD_PULSE_W, duration_us, c_int) self.__io.set(ci.TSI_DPRX_HPD_PULSE_W, duration_us, c_int)
def set_assert_state(self, state: bool): def set_assert_state(self, state: bool):
""" """
@@ -70,7 +72,7 @@ class LinkDisplayPortRx:
state (bool) state (bool)
""" """
val = 0x1 if state else 0x0 val = 0x1 if state else 0x0
self.__io.set(TSI_FORCE_HOT_PLUG_STATE_W, val) self.__io.set(ci.TSI_FORCE_HOT_PLUG_STATE_W, val)
@property @property
def scrambler_seed(self) -> int: def scrambler_seed(self) -> int:
@@ -84,7 +86,7 @@ class LinkDisplayPortRx:
warnings.warn("Scrambler Seed is not supported.") warnings.warn("Scrambler Seed is not supported.")
return 0 return 0
return self.__io.get(TSI_DPRX_SCR_SEED, c_uint32)[1] return self.__io.get(ci.TSI_DPRX_SCR_SEED, c_uint32)[1]
@scrambler_seed.setter @scrambler_seed.setter
def scrambler_seed(self, value: int = 0): def scrambler_seed(self, value: int = 0):
@@ -98,7 +100,7 @@ class LinkDisplayPortRx:
raise ValueError(f"Scrambler seed {value} is not available.") raise ValueError(f"Scrambler seed {value} is not available.")
if self.__HW_CAPS.scrambler_seed: if self.__HW_CAPS.scrambler_seed:
self.__io.set(TSI_DPRX_SCR_SEED, value) self.__io.set(ci.TSI_DPRX_SCR_SEED, value)
else: else:
warnings.warn("Scrambler Seed is not supported.") warnings.warn("Scrambler Seed is not supported.")

View File

@@ -1,7 +1,8 @@
from ctypes import c_uint32, c_int
from typing import Optional from typing import Optional
from UniTAP.libs.lib_tsi import PortIO from UniTAP.libs.lib_tsi import PortIO
from UniTAP.libs.lib_tsi.tsi_private_types import * import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from UniTAP.libs.lib_tsi.tsi_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
from .private_link_rx_types import RoutedLTStatusPrivate from .private_link_rx_types import RoutedLTStatusPrivate
from .link_rx_types import RoutedLTStatus, RoutedLTConfig from .link_rx_types import RoutedLTStatus, RoutedLTConfig
from UniTAP.dev.ports.modules.dpcd import DPCDRegisters from UniTAP.dev.ports.modules.dpcd import DPCDRegisters
@@ -34,7 +35,7 @@ class DisplayPortAUXController:
else: else:
ctrl &= ~0x01 ctrl &= ~0x01
res = self.__io.set(TSI_DPRX_LT_ROUTE_CONTROL_W, ctrl, c_uint32) res = self.__io.set(ci.TSI_DPRX_LT_ROUTE_CONTROL_W, ctrl, c_uint32)
if not res: if not res:
raise Exception("The feature requires a license key and the required license key is not installed.") raise Exception("The feature requires a license key and the required license key is not installed.")
@@ -50,6 +51,7 @@ class DisplayPortAUXController:
max_rate_dp14 = 0 max_rate_dp14 = 0
max_rate_dp20 = 0 max_rate_dp20 = 0
if not config.is_edp_lt:
if config.is128b132b: if config.is128b132b:
if config.link_bw == 1: if config.link_bw == 1:
max_rate_dp20 = 1 max_rate_dp20 = 1
@@ -91,12 +93,21 @@ class DisplayPortAUXController:
if config.is128b132b: if config.is128b132b:
self.__dpcd.write(0x21, 0x01) self.__dpcd.write(0x21, 0x01)
self.__dpcd.write(0x90, 0xff) self.__dpcd.write(0x90, 0xff)
edp_data = [0x00] * 16
self.__dpcd.write(0x10, edp_data)
self.__dpcd.write(0x700, 0x00)
dsc_data = [0x0f, 0x21, 0x03, 0x03, 0xeb, 0x07, 0x01, 0x00, 0x00, 0x1f, 0x0e, 0x11, 0x08, 0x07, 0x00, 0x00] dsc_data = [0x0f, 0x21, 0x03, 0x03, 0xeb, 0x07, 0x01, 0x00, 0x00, 0x1f, 0x0e, 0x11, 0x08, 0x07, 0x00, 0x00]
self.__dpcd.write(0x60, dsc_data) self.__dpcd.write(0x60, dsc_data)
self.__dpcd.write(0x2217, 0x06) self.__dpcd.write(0x2217, 0x06)
else: else:
self.__dpcd.write(0x21, 0x00) self.__dpcd.write(0x21, 0x00)
self.__dpcd.write(0x90, 0x00) self.__dpcd.write(0x90, 0x00)
edp_data = [0x00] * 16
if config.is_edp_lt:
edp_data[0] = config.link_bw & 0xff
edp_data[1] = (config.link_bw >> 8) & 0xff
self.__dpcd.write(0x10, edp_data)
self.__dpcd.write(0x700, config.is_edp_lt and 0x06 or 0x00)
dsc_data = [0x00] * 16 dsc_data = [0x00] * 16
self.__dpcd.write(0x60, dsc_data) self.__dpcd.write(0x60, dsc_data)
self.__dpcd.write(0x2217, 0x00) self.__dpcd.write(0x2217, 0x00)
@@ -200,19 +211,19 @@ class DisplayPortAUXController:
step=routed_lt_status.step) step=routed_lt_status.step)
def __set_routed_lt_config(self, value: int) -> bool: def __set_routed_lt_config(self, value: int) -> bool:
res = self.__io.set(TSI_DPRX_LT_ROUTE_CREATE, value, c_uint32) res = self.__io.set(ci.TSI_DPRX_LT_ROUTE_CREATE, value, c_uint32)
return res >= 0 return res >= 0
def __set_force_cable_status_to_plugged(self, enable: bool): def __set_force_cable_status_to_plugged(self, enable: bool):
val = 0x3C if enable else 0 val = 0x3C if enable else 0
self.__io.set(TSI_DPRX_HPD_FORCE, val, c_int) self.__io.set(ci.TSI_DPRX_HPD_FORCE, val, c_int)
def __read_status(self) -> Optional[RoutedLTStatusPrivate]: def __read_status(self) -> Optional[RoutedLTStatusPrivate]:
res, status = self.__io.get(TSI_DPRX_LT_ROUTE_STATUS_R, RoutedLTStatusPrivate) res, status = self.__io.get(ci.TSI_DPRX_LT_ROUTE_STATUS_R, RoutedLTStatusPrivate)
if res >= 0: if res >= 0:
return status return status
return None return None
def __generate_short_hpd_pulse(self, value: int): def __generate_short_hpd_pulse(self, value: int):
self.__io.set(TSI_DPRX_HPD_PULSE_W, value, c_int) self.__io.set(ci.TSI_DPRX_HPD_PULSE_W, value, c_int)

View File

@@ -1,10 +1,11 @@
import warnings import warnings
from ctypes import c_int, c_uint, c_uint32
from typing import List, Optional, Union, Type from typing import List, Optional, Union, Type
from .link_rx_types import LinkCapabilities, LinkEDPCapabilities, DisplayPortLinkCaps from .link_rx_types import LinkCapabilities, LinkEDPCapabilities, DisplayPortLinkCaps
from .private_link_rx_types import DPRXHWCaps, DPRXLinkControl from .private_link_rx_types import DPRXHWCaps, DPRXLinkControl
from UniTAP.libs.lib_tsi import PortIO from UniTAP.libs.lib_tsi import PortIO
from UniTAP.libs.lib_tsi.tsi_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
class LinkDisplayPortCaps: class LinkDisplayPortCaps:
@@ -27,7 +28,8 @@ class LinkDisplayPortCaps:
if isinstance(capabilities, LinkCapabilities): if isinstance(capabilities, LinkCapabilities):
self.__set_max_lanes(capabilities.max_lane) self.__set_max_lanes(capabilities.max_lane)
self.__set_max_bitrate(capabilities.bit_rate) self.__set_max_bitrate(capabilities.bit_rate)
self.__set_force_cable_status_to_plugged(capabilities.force_cable_status_to_plugged) # TODO: Temporarily disabled for writing value
# self.__set_force_cable_status_to_plugged(capabilities.force_cable_status_to_plugged)
self.__set_dp_link_control(old_dp2_lt=capabilities.old_dp_2_0_lt) self.__set_dp_link_control(old_dp2_lt=capabilities.old_dp_2_0_lt)
self.__set_dp_128_132_bitrates(capabilities.dp_128_132_bitrates) self.__set_dp_128_132_bitrates(capabilities.dp_128_132_bitrates)
self.__set_bitrate_override(10.0, capabilities.override_10g) self.__set_bitrate_override(10.0, capabilities.override_10g)
@@ -86,10 +88,10 @@ class LinkDisplayPortCaps:
return return
if lane_count not in [1, 2, 4]: if lane_count not in [1, 2, 4]:
raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4") raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4")
self.__io.set(TSI_DPRX_MAX_LANES, lane_count, c_int) self.__io.set(ci.TSI_DPRX_MAX_LANES, lane_count, c_int)
def __get_max_lanes(self) -> int: def __get_max_lanes(self) -> int:
return self.__io.get(TSI_DPRX_MAX_LANES)[1] return self.__io.get(ci.TSI_DPRX_MAX_LANES)[1]
def __set_max_bitrate(self, bitrate: Optional[float]): def __set_max_bitrate(self, bitrate: Optional[float]):
if bitrate is None: if bitrate is None:
@@ -97,10 +99,10 @@ class LinkDisplayPortCaps:
bitrate = round(bitrate / 0.27) bitrate = round(bitrate / 0.27)
if bitrate not in [6, 10, 20, 25, 30]: if bitrate not in [6, 10, 20, 25, 30]:
raise ValueError(f"Incorrect bit rate number {bitrate}. Must be from list: 1.62, 2.7, 5.4, 6.75, 8.1") raise ValueError(f"Incorrect bit rate number {bitrate}. Must be from list: 1.62, 2.7, 5.4, 6.75, 8.1")
self.__io.set(TSI_DPRX_MAX_LINK_RATE, bitrate, c_int) self.__io.set(ci.TSI_DPRX_MAX_LINK_RATE, bitrate, c_int)
def __get_max_bitrate(self) -> int: def __get_max_bitrate(self) -> int:
return round(self.__io.get(TSI_DPRX_MAX_LINK_RATE)[1] * 0.27, 2) return round(self.__io.get(ci.TSI_DPRX_MAX_LINK_RATE)[1] * 0.27, 2)
def __set_bitrate_override(self, to_override: float, with_override: Optional[float]): def __set_bitrate_override(self, to_override: float, with_override: Optional[float]):
if with_override is None: if with_override is None:
@@ -109,19 +111,19 @@ class LinkDisplayPortCaps:
if not isinstance(to_override, float) or not isinstance(with_override, float): if not isinstance(to_override, float) or not isinstance(with_override, float):
raise TypeError("DP 128b/132b bitrate override settings must float type!") raise TypeError("DP 128b/132b bitrate override settings must float type!")
list_value = self.__io.get(TSI_DP2RX_CUSTOM_RATE_MAP, c_uint, 3)[1] list_value = self.__io.get(ci.TSI_DP2RX_CUSTOM_RATE_MAP, c_uint, 3)[1]
if with_override not in [2.5, 2.7, 5.0, 5.4]: if with_override not in [2.5, 2.7, 5.0, 5.4]:
raise ValueError(f"Incorrect bit rate number {with_override}. " raise ValueError(f"Incorrect bit rate number {with_override}. "
f"Must be from list: 2.5, 2.7, 5.0, 5.4") f"Must be from list: 2.5, 2.7, 5.0, 5.4")
list_value[0] = int(with_override * 1000000000 / 200000) list_value[0] = int(with_override * 1000000000 / 200000)
self.__io.set(TSI_DP2RX_CUSTOM_RATE_MAP, list_value, c_uint, 3) self.__io.set(ci.TSI_DP2RX_CUSTOM_RATE_MAP, list_value, c_uint, 3)
def __get_bitrate_override(self, to_override: float) -> Optional[float]: def __get_bitrate_override(self, to_override: float) -> Optional[float]:
if not isinstance(to_override, float): if not isinstance(to_override, float):
raise TypeError("DP 128b/132b bitrate override settings must float type!") raise TypeError("DP 128b/132b bitrate override settings must float type!")
override_list = self.__io.get(TSI_DP2RX_CUSTOM_RATE_MAP, c_uint, 3)[1] override_list = self.__io.get(ci.TSI_DP2RX_CUSTOM_RATE_MAP, c_uint, 3)[1]
if override_list.count(0) == len(override_list): if override_list.count(0) == len(override_list):
return None return None
@@ -138,21 +140,21 @@ class LinkDisplayPortCaps:
if edp_aux_preamble is not None: if edp_aux_preamble is not None:
ctrl.edp_aux_preamble = edp_aux_preamble ctrl.edp_aux_preamble = edp_aux_preamble
self.__io.set(TSI_DPRX_LINK_CONTROL, ctrl.value(), c_uint32) self.__io.set(ci.TSI_DPRX_LINK_CONTROL, ctrl.value(), c_uint32)
def __get_dp_link_control(self) -> DPRXLinkControl: def __get_dp_link_control(self) -> DPRXLinkControl:
return self.__io.get(TSI_DPRX_LINK_CONTROL, DPRXLinkControl)[1] return self.__io.get(ci.TSI_DPRX_LINK_CONTROL, DPRXLinkControl)[1]
def __set_dp_128_132_bitrates(self, rates: Optional[List[float]]): def __set_dp_128_132_bitrates(self, rates: Optional[List[float]]):
flags = self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & ~0xc0 flags = self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & ~0xc0
if rates is None: if rates is None:
return return
elif isinstance(rates, list) and len(rates) == 0: elif isinstance(rates, list) and len(rates) == 0:
flags &= ~(1 << 4) flags &= ~(1 << 4)
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
else: else:
flags |= (1 << 4) flags |= (1 << 4)
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
val = 0 val = 0
if 10.0 in rates: if 10.0 in rates:
val |= 0x01 val |= 0x01
@@ -160,12 +162,12 @@ class LinkDisplayPortCaps:
val |= 0x04 val |= 0x04
if 20.0 in rates: if 20.0 in rates:
val |= 0x02 val |= 0x02
self.__io.set(TSI_DP2RX_LINK_RATE_CAPS, val, c_int) self.__io.set(ci.TSI_DP2RX_LINK_RATE_CAPS, val, c_int)
def __get_dp_128_132_bitrates(self) -> Optional[List[float]]: def __get_dp_128_132_bitrates(self) -> Optional[List[float]]:
val = (self.__io.get(TSI_DPRX_LINK_FLAGS)[1] >> 4) & 0x1 val = (self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] >> 4) & 0x1
if val: if val:
rates = self.__io.get(TSI_DP2RX_LINK_RATE_CAPS)[1] rates = self.__io.get(ci.TSI_DP2RX_LINK_RATE_CAPS)[1]
list_rates = [] list_rates = []
if rates & 0x01: if rates & 0x01:
list_rates.append(10.0) list_rates.append(10.0)
@@ -181,47 +183,47 @@ class LinkDisplayPortCaps:
if enable is None: if enable is None:
return return
val = 0x3C if enable else 0 val = 0x3C if enable else 0
self.__io.set(TSI_DPRX_HPD_FORCE, val, c_int) self.__io.set(ci.TSI_DPRX_HPD_FORCE, val, c_int)
def __get_force_cable_status_to_plugged(self) -> bool: def __get_force_cable_status_to_plugged(self) -> bool:
return bool(self.__io.get(TSI_DPRX_HPD_FORCE)[1]) return bool(self.__io.get(ci.TSI_DPRX_HPD_FORCE)[1])
def __set_dsc(self, enable: Optional[bool]): def __set_dsc(self, enable: Optional[bool]):
if enable is None: if enable is None:
return return
val = 0x1 if enable else 0x0 val = 0x1 if enable else 0x0
if self.__caps.dsc: if self.__caps.dsc:
self.__io.set(TSI_DPRX_DSC_CONTROL, val, c_int) self.__io.set(ci.TSI_DPRX_DSC_CONTROL, val, c_int)
def __get_dsc(self) -> Optional[bool]: def __get_dsc(self) -> Optional[bool]:
if self.__io.get(TSI_DPRX_DSC_STATUS_R)[1] & 0x1: if self.__io.get(ci.TSI_DPRX_DSC_STATUS_R)[1] & 0x1:
return bool(self.__io.get(TSI_DPRX_DSC_CONTROL)[1] & 0x1) return bool(self.__io.get(ci.TSI_DPRX_DSC_CONTROL)[1] & 0x1)
def __set_fec(self, enable: Optional[bool]): def __set_fec(self, enable: Optional[bool]):
if enable is None: if enable is None:
return return
val = 0x1 if enable else 0x0 val = 0x1 if enable else 0x0
if self.__caps.fec: if self.__caps.fec:
self.__io.set(TSI_DPRX_FEC_CONTROL, val, c_int) self.__io.set(ci.TSI_DPRX_FEC_CONTROL, val, c_int)
def __get_fec(self) -> Optional[bool]: def __get_fec(self) -> Optional[bool]:
if self.__caps.fec: if self.__caps.fec:
return bool(self.__io.get(TSI_DPRX_FEC_CONTROL)[1] & 0x1) return bool(self.__io.get(ci.TSI_DPRX_FEC_CONTROL)[1] & 0x1)
def __set_mst(self, enable: Optional[bool]): def __set_mst(self, enable: Optional[bool]):
if enable is None: if enable is None:
return return
flags = self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & ~0xc0 flags = self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & ~0xc0
if enable: if enable:
flags |= 1 flags |= 1
else: else:
flags &= ~1 flags &= ~1
if self.__caps.mst: if self.__caps.mst:
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
def __get_mst(self) -> Optional[bool]: def __get_mst(self) -> Optional[bool]:
if self.__caps.mst: if self.__caps.mst:
return bool(self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & 0x1) return bool(self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & 0x1)
def __set_mst_sink_count(self, count: int): def __set_mst_sink_count(self, count: int):
if count is None: if count is None:
@@ -230,73 +232,73 @@ class LinkDisplayPortCaps:
if count > self.__caps.mst_stream_count: if count > self.__caps.mst_stream_count:
warnings.warn(f"Maximum sink count: {self.__caps.mst_stream_count}") warnings.warn(f"Maximum sink count: {self.__caps.mst_stream_count}")
else: else:
self.__io.set(TSI_DPRX_MST_SINK_COUNT, count, c_uint32) self.__io.set(ci.TSI_DPRX_MST_SINK_COUNT, count, c_uint32)
else: else:
warnings.warn("MST or Custom Sink Count are not supported") warnings.warn("MST or Custom Sink Count are not supported")
def __get_mst_sink_count(self) -> int: def __get_mst_sink_count(self) -> int:
if self.__caps.sink_cnt_config and self.__caps.mst: if self.__caps.sink_cnt_config and self.__caps.mst:
return int(self.__io.get(TSI_DPRX_MST_SINK_COUNT)[1]) return int(self.__io.get(ci.TSI_DPRX_MST_SINK_COUNT)[1])
else: else:
return 0 return 0
def __set_tps3(self, enable: Optional[bool]): def __set_tps3(self, enable: Optional[bool]):
if enable is None: if enable is None:
return return
flags = self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & ~0xc0 flags = self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & ~0xc0
if enable: if enable:
flags |= (1 << 1) flags |= (1 << 1)
else: else:
flags &= ~(1 << 1) flags &= ~(1 << 1)
if self.__caps.fec: if self.__caps.fec:
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
def __get_tps3(self) -> Optional[bool]: def __get_tps3(self) -> Optional[bool]:
if self.__caps.fec: if self.__caps.fec:
return bool((self.__io.get(TSI_DPRX_LINK_FLAGS)[1] >> 1) & 0x1) return bool((self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] >> 1) & 0x1)
def __set_tps4(self, enable: Optional[bool]): def __set_tps4(self, enable: Optional[bool]):
if enable is None: if enable is None:
return return
flags = self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & ~0xc0 flags = self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & ~0xc0
if enable: if enable:
flags |= (1 << 2) flags |= (1 << 2)
else: else:
flags &= ~(1 << 2) flags &= ~(1 << 2)
if self.__caps.fec: if self.__caps.fec:
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
def __get_tps4(self) -> Optional[bool]: def __get_tps4(self) -> Optional[bool]:
if self.__caps.fec: if self.__caps.fec:
return bool((self.__io.get(TSI_DPRX_LINK_FLAGS)[1] >> 2) & 0x1) return bool((self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] >> 2) & 0x1)
def __set_ss_sbm(self, enable: bool): def __set_ss_sbm(self, enable: bool):
if enable is None: if enable is None:
return return
if self.__caps.dp2_support_rates: if self.__caps.dp2_support_rates:
flags = self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & ~0xc0 flags = self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & ~0xc0
if enable: if enable:
flags |= (1 << 5) flags |= (1 << 5)
else: else:
flags &= ~(1 << 5) flags &= ~(1 << 5)
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
def __get_ss_sbm(self) -> Optional[bool]: def __get_ss_sbm(self) -> Optional[bool]:
if self.__caps.dp2_support_rates: if self.__caps.dp2_support_rates:
return bool((self.__io.get(TSI_DPRX_LINK_FLAGS)[1] >> 5) & 0x1) return bool((self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] >> 5) & 0x1)
def __set_edp_support(self, enable: bool): def __set_edp_support(self, enable: bool):
if self.__caps.edp: if self.__caps.edp:
flags = self.__io.get(TSI_DPRX_LINK_FLAGS)[1] & ~0xc0 flags = self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] & ~0xc0
if enable: if enable:
flags |= (1 << 3) flags |= (1 << 3)
else: else:
flags &= ~(1 << 3) flags &= ~(1 << 3)
self.__io.set(TSI_DPRX_LINK_FLAGS, flags, c_int) self.__io.set(ci.TSI_DPRX_LINK_FLAGS, flags, c_int)
def __get_edp_support(self) -> Optional[bool]: def __get_edp_support(self) -> Optional[bool]:
if self.__caps.edp: if self.__caps.edp:
return bool((self.__io.get(TSI_DPRX_LINK_FLAGS)[1] >> 3) & 0x1) return bool((self.__io.get(ci.TSI_DPRX_LINK_FLAGS)[1] >> 3) & 0x1)
def __set_edp_sel_rates(self, rates: List[float]): def __set_edp_sel_rates(self, rates: List[float]):
if self.__caps.edp: if self.__caps.edp:
@@ -310,11 +312,11 @@ class LinkDisplayPortCaps:
j += 1 j += 1
rates.sort() rates.sort()
self.__io.set(TSI_DPRX_EDP_SEL_RATES, to_write_list, data_type=c_uint32, data_count=8) self.__io.set(ci.TSI_DPRX_EDP_SEL_RATES, to_write_list, data_type=c_uint32, data_count=8)
def __get_edp_sel_rates(self) -> List[float]: def __get_edp_sel_rates(self) -> List[float]:
if self.__caps.edp: if self.__caps.edp:
rates = self.__io.get(TSI_DPRX_EDP_SEL_RATES, data_type=c_uint32, data_count=8)[1] rates = self.__io.get(ci.TSI_DPRX_EDP_SEL_RATES, data_type=c_uint32, data_count=8)[1]
res_rates = [] res_rates = []
for rate in rates: for rate in rates:
if rate == 0: if rate == 0:
@@ -324,7 +326,7 @@ class LinkDisplayPortCaps:
def __get_edp_caps_rates(self) -> List[float]: def __get_edp_caps_rates(self) -> List[float]:
if self.__caps.edp: if self.__caps.edp:
rates = self.__io.get(TSI_DPRX_EDP_CAPS_RATES_R, data_type=c_uint32, data_count=32)[1] rates = self.__io.get(ci.TSI_DPRX_EDP_CAPS_RATES_R, data_type=c_uint32, data_count=32)[1]
new_rates = [] new_rates = []
for rate in rates: for rate in rates:
if rate > 0: if rate > 0:

View File

@@ -1,11 +1,12 @@
import time import time
import warnings import warnings
from ctypes import c_int, c_uint32, c_uint8, c_uint
from typing import Optional from typing import Optional
from UniTAP.libs.lib_tsi import PortIO from UniTAP.libs.lib_tsi import PortIO
from UniTAP.libs.lib_tsi.tsi_private_types import * import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from UniTAP.libs.lib_tsi.tsi_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
from UniTAP.utils.function_wrapper import function_scheduler from UniTAP.utils.function_wrapper import function_scheduler
from .private_link_rx_types import DPRXHWCaps from .private_link_rx_types import DPRXHWCaps
from .link_status_common import * from .link_status_common import *
@@ -48,7 +49,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of int type object of int type
""" """
res, value = self.__io.get(TSI_DPRX_MST_STATUS_R, c_uint) res, value = self.__io.get(p_ci.TSI_DPRX_MST_STATUS_R, c_uint)
return value >> 8 return value >> 8
@property @property
@@ -59,7 +60,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of int type object of int type
""" """
return self.__io.get(TSI_DPRX_LINK_LANE_COUNT_R, c_int)[1] return self.__io.get(ci.TSI_DPRX_LINK_LANE_COUNT_R, c_int)[1]
@property @property
def link_encoding(self) -> DpLinkEncoding: def link_encoding(self) -> DpLinkEncoding:
@@ -69,7 +70,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of `DpLinkEncoding` type object of `DpLinkEncoding` type
""" """
result, value = self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint) result, value = self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint)
if value >> 20 & 1: if value >> 20 & 1:
return DpLinkEncoding.LE_128b132b return DpLinkEncoding.LE_128b132b
@@ -84,7 +85,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of float type object of float type
""" """
current_link_rate = self.__io.get(TSI_DPRX_LINK_BR_R, c_int)[1] current_link_rate = self.__io.get(ci.TSI_DPRX_LINK_BR_R, c_int)[1]
if self.link_encoding == DpLinkEncoding.LE_8b10b: if self.link_encoding == DpLinkEncoding.LE_8b10b:
return round(current_link_rate * 0.27, 2) return round(current_link_rate * 0.27, 2)
else: else:
@@ -105,7 +106,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool(self.__io.get(TSI_DPRX_HPD_STATUS_R, c_int)[1] & 1) return bool(self.__io.get(ci.TSI_DPRX_HPD_STATUS_R, c_int)[1] & 1)
@property @property
def cable_state(self) -> bool: def cable_state(self) -> bool:
@@ -115,7 +116,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool(self.__io.get(TSI_DPRX_HPD_STATUS_R, c_int)[1] & 4) return bool(self.__io.get(ci.TSI_DPRX_HPD_STATUS_R, c_int)[1] & 4)
@property @property
def enhanced_framing(self) -> bool: def enhanced_framing(self) -> bool:
@@ -125,7 +126,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 17) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 17) & 1)
@property @property
def scrambling_enabled(self) -> bool: def scrambling_enabled(self) -> bool:
@@ -135,7 +136,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 18) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 18) & 1)
@property @property
def dsc_enabled(self) -> Union[bool, None]: def dsc_enabled(self) -> Union[bool, None]:
@@ -146,7 +147,7 @@ class LinkDisplayPortStatusSink:
object of bool|None type object of bool|None type
""" """
if self.__caps.dsc or self.__caps.dsc2: if self.__caps.dsc or self.__caps.dsc2:
return bool((self.__io.get(TSI_DPRX_DSC_STATUS_R)[1] >> 1) & 1) return bool((self.__io.get(ci.TSI_DPRX_DSC_STATUS_R)[1] >> 1) & 1)
else: else:
return None return None
@@ -159,7 +160,7 @@ class LinkDisplayPortStatusSink:
object of bool|None type object of bool|None type
""" """
if self.__caps.fec or self.__caps.fec2: if self.__caps.fec or self.__caps.fec2:
return bool(self.__io.get(TSI_DPRX_FEC_STATUS_R)[1] & 1) return bool(self.__io.get(ci.TSI_DPRX_FEC_STATUS_R)[1] & 1)
else: else:
return None return None
@@ -172,7 +173,7 @@ class LinkDisplayPortStatusSink:
object of bool|None type object of bool|None type
""" """
if self.__caps.mst: if self.__caps.mst:
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 19) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 19) & 1)
else: else:
return None return None
@@ -184,8 +185,8 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool|None type object of bool|None type
""" """
if (self.__io.get(TSI_DPRX_SSC_STATUS_R, c_int)[1] >> 1) & 1: if (self.__io.get(ci.TSI_DPRX_SSC_STATUS_R, c_int)[1] >> 1) & 1:
return bool(self.__io.get(TSI_DPRX_SSC_STATUS_R, c_int)[1] & 1) return bool(self.__io.get(ci.TSI_DPRX_SSC_STATUS_R, c_int)[1] & 1)
else: else:
return None return None
@@ -197,7 +198,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 16) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 16) & 1)
@property @property
def eq_ila(self) -> bool: def eq_ila(self) -> bool:
@@ -207,7 +208,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 30) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 30) & 1)
@property @property
def cds_ila(self) -> bool: def cds_ila(self) -> bool:
@@ -217,7 +218,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 29) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 29) & 1)
@property @property
def lt_fail(self) -> bool: def lt_fail(self) -> bool:
@@ -227,7 +228,7 @@ class LinkDisplayPortStatusSink:
Returns: Returns:
object of bool type object of bool type
""" """
return bool((self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 28) & 1) return bool((self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] >> 28) & 1)
def lane(self, lane_number: int) -> LaneStatus: def lane(self, lane_number: int) -> LaneStatus:
""" """
@@ -242,10 +243,10 @@ class LinkDisplayPortStatusSink:
if not (0 <= lane_number <= 3): if not (0 <= lane_number <= 3):
raise ValueError(f"Incorrect lane number {lane_number}. Available range: 0-{self.lane_count}") raise ValueError(f"Incorrect lane number {lane_number}. Available range: 0-{self.lane_count}")
status = self.__io.get(TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1] status = self.__io.get(ci.TSI_DPRX_LINK_STATUS_FLAGS_R, c_uint32)[1]
voltage_swing = self.__io.get(TSI_DPRX_LINK_VS_R, c_uint32)[1] voltage_swing = self.__io.get(ci.TSI_DPRX_LINK_VS_R, c_uint32)[1]
pre_emphasis = self.__io.get(TSI_DPRX_LINK_PE_R, c_uint32)[1] pre_emphasis = self.__io.get(ci.TSI_DPRX_LINK_PE_R, c_uint32)[1]
_, error_counters = self.__io.get(TSI_DPRX_GET_ERROR_COUNTS_R, c_uint32 * 4) _, error_counters = self.__io.get(ci.TSI_DPRX_GET_ERROR_COUNTS_R, c_uint32 * 4)
lane_status = LaneStatus() lane_status = LaneStatus()
@@ -273,7 +274,7 @@ class LinkDisplayPortStatusSink:
if self.__caps.dp2_support_rates and self.link_encoding == DpLinkEncoding.LE_128b132b: if self.__caps.dp2_support_rates and self.link_encoding == DpLinkEncoding.LE_128b132b:
lane_status.voltage_swing = 0 lane_status.voltage_swing = 0
lane_status.pre_emphasis = 0 lane_status.pre_emphasis = 0
_, ffe_preset = self.__io.get(TSI_DP2RX_LINK_FFE_PRESET_R, c_uint32) _, ffe_preset = self.__io.get(ci.TSI_DP2RX_LINK_FFE_PRESET_R, c_uint32)
lane_status.ffe_preset = (ffe_preset >> (8 * lane_number)) & 0xF lane_status.ffe_preset = (ffe_preset >> (8 * lane_number)) & 0xF
else: else:
lane_status.voltage_swing = (voltage_swing >> (8 * lane_number)) & 0x3 lane_status.voltage_swing = (voltage_swing >> (8 * lane_number)) & 0x3
@@ -297,7 +298,7 @@ class LinkDisplayPortStatusSink:
raise ValueError(f"Selected stream {stream_index} is not available. " raise ValueError(f"Selected stream {stream_index} is not available. "
f"Available stream number: {self.mst_stream_count}") f"Available stream number: {self.mst_stream_count}")
res = self.__io.get(TSI_DPRX_VC_TABLE_R, VCPTable, 4)[1] res = self.__io.get(ci.TSI_DPRX_VC_TABLE_R, VCPTable, 4)[1]
if self.mst_enabled: if self.mst_enabled:
status = VCPStatus() status = VCPStatus()
@@ -316,7 +317,7 @@ class LinkDisplayPortStatusSink:
def __check_video(self) -> bool: def __check_video(self) -> bool:
def is_msa_available(io): def is_msa_available(io):
result, msa_info, size = io.get(TSI_DPRX_MSA_INFO_R, DpMsa, 4) result, msa_info, size = io.get(p_ci.TSI_DPRX_MSA_INFO_R, DpMsa, 4)
return size > 0 return size > 0
return function_scheduler(is_msa_available, self.__io, interval=5, timeout=10) return function_scheduler(is_msa_available, self.__io, interval=5, timeout=10)
@@ -339,7 +340,7 @@ class LinkDisplayPortStatusSink:
time.sleep(1) time.sleep(1)
result, msa_info, size = self.__io.get(TSI_DPRX_MSA_INFO_R, DpMsa, 4) result, msa_info, size = self.__io.get(p_ci.TSI_DPRX_MSA_INFO_R, DpMsa, 4)
if stream_index < size: if stream_index < size:
msa_info_private = MSAInfo(msa_info[stream_index]) msa_info_private = MSAInfo(msa_info[stream_index])
@@ -348,22 +349,22 @@ class LinkDisplayPortStatusSink:
stream_status.mvid = msa_info_private.m_video stream_status.mvid = msa_info_private.m_video
stream_status.nvid = msa_info_private.n_video stream_status.nvid = msa_info_private.n_video
result = self.__io.get(TSI_DPRX_CRC_LOG_R, DpCrc, self.mst_stream_count) result = self.__io.get(ci.TSI_DPRX_CRC_LOG_R, DpCrc, self.mst_stream_count)
if result[0] >= TSI_SUCCESS and self.mst_stream_count > 1: if result[0] >= ci.TSI_SUCCESS and self.mst_stream_count > 1:
stream_status.crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b] stream_status.crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b]
elif result[0] >= TSI_SUCCESS and size == 1: elif result[0] >= ci.TSI_SUCCESS and size == 1:
stream_status.crc = [result[1].r, result[1].g, result[1].b] stream_status.crc = [result[1].r, result[1].g, result[1].b]
result = self.__io.get(TSI_DPRX_DSC_CRC_R, DpCrc, self.mst_stream_count) result = self.__io.get(ci.TSI_DPRX_DSC_CRC_R, DpCrc, self.mst_stream_count)
if result[0] >= TSI_SUCCESS and self.mst_stream_count > 1: if result[0] >= ci.TSI_SUCCESS and self.mst_stream_count > 1:
stream_status.dsc_crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b] stream_status.dsc_crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b]
elif result[0] >= TSI_SUCCESS and size == 1: elif result[0] >= ci.TSI_SUCCESS and size == 1:
stream_status.dsc_crc = [result[1].r, result[1].g, result[1].b] stream_status.dsc_crc = [result[1].r, result[1].g, result[1].b]
if self.__caps.dp2_support_rates: if self.__caps.dp2_support_rates:
res = self.__io.get(TSI_DPRX_SDP_CRC16_CTRL, c_uint32) res = self.__io.get(p_ci.TSI_DPRX_SDP_CRC16_CTRL, c_uint32)
stream_status.sdp_crc16.state = False if res[0] < TSI_SUCCESS else (res[1] & 0x1 == 1) stream_status.sdp_crc16.state = False if res[0] < ci.TSI_SUCCESS else (res[1] & 0x1 == 1)
stream_status.sdp_crc16.errors = self.__io.get(TSI_DPRX_SDP_CRC16_COUNTERS, c_uint8, stream_status.sdp_crc16.errors = self.__io.get(p_ci.TSI_DPRX_SDP_CRC16_COUNTERS, c_uint8,
self.__caps.mst_stream_count)[1][stream_index] self.__caps.mst_stream_count)[1][stream_index]
else: else:
raise ValueError(f"Selected stream {stream_index} is not available. " raise ValueError(f"Selected stream {stream_index} is not available. "
@@ -378,7 +379,7 @@ class LinkDisplayPortStatusSink:
if not self.__caps.dp2_support_rates: if not self.__caps.dp2_support_rates:
warnings.warn("SDP CRC16 is not supported. Cannot reset errors.") warnings.warn("SDP CRC16 is not supported. Cannot reset errors.")
return return
self.__io.set(TSI_DPRX_SDP_CRC16_COUNTERS, 0) self.__io.set(p_ci.TSI_DPRX_SDP_CRC16_COUNTERS, 0)
def __str__(self) -> str: def __str__(self) -> str:
lane_status_str = "" lane_status_str = ""

View File

@@ -78,6 +78,7 @@ class RoutedLTConfig:
def __init__(self): def __init__(self):
self.__is128b132b = False self.__is128b132b = False
self.__is_old_dp20_lt = False self.__is_old_dp20_lt = False
self.__is_edp_lt = False
self.__vs = 0 self.__vs = 0
self.__pe = 0 self.__pe = 0
self.__ffe = 0 self.__ffe = 0
@@ -100,13 +101,21 @@ class RoutedLTConfig:
def is_old_dp20_lt(self, value: bool = False): def is_old_dp20_lt(self, value: bool = False):
self.__is_old_dp20_lt = value self.__is_old_dp20_lt = value
@property
def is_edp_lt(self) -> bool:
return self.__is_edp_lt
@is_edp_lt.setter
def is_edp_lt(self, value: bool = False):
self.__is_edp_lt = value
@property @property
def vs(self) -> int: def vs(self) -> int:
return self.__vs return self.__vs
@vs.setter @vs.setter
def vs(self, value: int): def vs(self, value: int):
if not (0 <= value < 3): if not (0 <= value <= 0x3):
raise ValueError(f"VS cannot be less than 0 and more than 3") raise ValueError(f"VS cannot be less than 0 and more than 3")
self.__vs = value self.__vs = value
@@ -136,8 +145,8 @@ class RoutedLTConfig:
@link_bw.setter @link_bw.setter
def link_bw(self, value: int): def link_bw(self, value: int):
if not (0 <= value <= 0xFF): if not (0 <= value <= 0xFFFF):
raise ValueError(f"link_bw cannot be less than 0 and more than 0xFF") raise ValueError(f"link_bw cannot be less than 0 and more than 0xFFFF")
self.__link_bw = value self.__link_bw = value
@property @property
@@ -151,8 +160,9 @@ class RoutedLTConfig:
self.__lane_count = value self.__lane_count = value
def int_value(self) -> int: def int_value(self) -> int:
val = (self.ffe << 8) if self.is128b132b else ((self.vs << 8) | (self.pe << 10)) val = (self.ffe << 4) if self.is128b132b else ((self.vs << 4) | (self.pe << 6))
return self.is128b132b | (self.__is_old_dp20_lt << 1) | val | (self.link_bw << 16) | (self.lane_count << 24) return self.is128b132b | (self.__is_old_dp20_lt << 1) | (self.__is_edp_lt << 2) | val | \
(self.lane_count << 8) | (self.link_bw << 16)
class RoutedLTStatus: class RoutedLTStatus:

View File

@@ -1,8 +1,12 @@
import warnings
from ctypes import c_uint, c_uint8
from typing import List
from warnings import warn from warnings import warn
from UniTAP.libs.lib_tsi import *
from UniTAP.dev.ports.modules.link.dp.link_status_common import DpLinkTrainingResult from UniTAP.dev.ports.modules.link.dp.link_status_common import DpLinkTrainingResult
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_types as ci
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from UniTAP.utils.function_wrapper import * from UniTAP.utils.function_wrapper import *
from .link_tx_status import LinkDisplayPortStatusSource from .link_tx_status import LinkDisplayPortStatusSource
from .link_tx_config import LinkDisplayPortConfig from .link_tx_config import LinkDisplayPortConfig
@@ -34,7 +38,7 @@ class LinkDisplayPortTx:
self.__status = LinkDisplayPortStatusSource(self.__io, self.__HW_CAPS, dpcd) self.__status = LinkDisplayPortStatusSource(self.__io, self.__HW_CAPS, dpcd)
self.__config = LinkDisplayPortConfig(self.__io, self.__HW_CAPS) self.__config = LinkDisplayPortConfig(self.__io, self.__HW_CAPS)
self.__force_config = LinkDisplayPortForceConfig(self.__io, self.__HW_CAPS) self.__force_config = LinkDisplayPortForceConfig(self.__io, self.__HW_CAPS)
self.__cable_info = DpCableInfo(port_io, TSI_DPTX_CABLE_ATTRIBUTES_R) self.__cable_info = DpCableInfo(port_io, p_ci.TSI_DPTX_CABLE_ATTRIBUTES_R)
@property @property
def status(self) -> LinkDisplayPortStatusSource: def status(self) -> LinkDisplayPortStatusSource:
@@ -86,7 +90,7 @@ class LinkDisplayPortTx:
def is_link_training_success(link: LinkDisplayPortTx): def is_link_training_success(link: LinkDisplayPortTx):
return link.last_lt_result() == DpLinkTrainingResult.LTR_SUCCESS return link.last_lt_result() == DpLinkTrainingResult.LTR_SUCCESS
self.__io.set(TSI_W_DPTX_COMMAND, 1, c_uint32) self.__io.set(ci.TSI_W_DPTX_COMMAND, 1, c_uint32)
return function_scheduler(is_link_training_success, self, interval=0.1, timeout=5) return function_scheduler(is_link_training_success, self, interval=0.1, timeout=5)
@@ -97,7 +101,7 @@ class LinkDisplayPortTx:
Returns: Returns:
object of `DpLinkTrainingResult` type object of `DpLinkTrainingResult` type
""" """
_, value = self.__io.get(TSI_DPTX_LT_RESULT_R, c_uint) _, value = self.__io.get(ci.TSI_DPTX_LT_RESULT_R, c_uint)
return DpLinkTrainingResult(value) return DpLinkTrainingResult(value)
@property @property
@@ -112,7 +116,7 @@ class LinkDisplayPortTx:
warnings.warn("Scrambler Seed is not supported.") warnings.warn("Scrambler Seed is not supported.")
return 0 return 0
return self.__io.get(TSI_DPTX_SCR_SEED, c_uint32)[1] return self.__io.get(ci.TSI_DPTX_SCR_SEED, c_uint32)[1]
@scrambler_seed.setter @scrambler_seed.setter
def scrambler_seed(self, value: int = 0): def scrambler_seed(self, value: int = 0):
@@ -126,7 +130,7 @@ class LinkDisplayPortTx:
warnings.warn("Scrambler Seed is not supported.") warnings.warn("Scrambler Seed is not supported.")
return return
if self.config._read_lt_features().auto_seed is not None and not self.config._read_lt_features().auto_seed: if self.config._read_lt_features().auto_seed is not None and not self.config._read_lt_features().auto_seed:
self.__io.set(TSI_DPTX_SCR_SEED, value, c_uint32) self.__io.set(ci.TSI_DPTX_SCR_SEED, value, c_uint32)
else: else:
warnings.warn("AutoSeed has already enabled. Transferred value will not be written") warnings.warn("AutoSeed has already enabled. Transferred value will not be written")
@@ -160,7 +164,7 @@ class LinkDisplayPortTx:
old_value = self.__get_override_voltage() old_value = self.__get_override_voltage()
old_value &= ~(3 << (stream_index * 8)) old_value &= ~(3 << (stream_index * 8))
old_value |= (value << (stream_index * 8)) old_value |= (value << (stream_index * 8))
self.__io.set(TSI_DPTX_OVERRIDE_VOLTAGE_SWING, old_value, c_uint32) self.__io.set(ci.TSI_DPTX_OVERRIDE_VOLTAGE_SWING, old_value, c_uint32)
def get_override_pre_emp(self, stream_index: int) -> int: def get_override_pre_emp(self, stream_index: int) -> int:
""" """
@@ -192,7 +196,7 @@ class LinkDisplayPortTx:
old_value = self.__get_override_pre_emp() old_value = self.__get_override_pre_emp()
old_value &= ~(3 << (stream_index * 8)) old_value &= ~(3 << (stream_index * 8))
old_value |= (value << (stream_index * 8)) old_value |= (value << (stream_index * 8))
self.__io.set(TSI_DPTX_OVERRIDE_PRE_EMPHASIS, old_value, c_uint32) self.__io.set(ci.TSI_DPTX_OVERRIDE_PRE_EMPHASIS, old_value, c_uint32)
@property @property
def override_ffe_presets(self) -> list: def override_ffe_presets(self) -> list:
@@ -205,7 +209,7 @@ class LinkDisplayPortTx:
if not self.__HW_CAPS.dp2_custom_rates: if not self.__HW_CAPS.dp2_custom_rates:
warnings.warn("FFE presets does not support.") warnings.warn("FFE presets does not support.")
return [] return []
return self.__io.get(TSI_DP2TX_OUT_FFE, c_uint8, 4)[1] return self.__io.get(ci.TSI_DP2TX_OUT_FFE, c_uint8, 4)[1]
@override_ffe_presets.setter @override_ffe_presets.setter
def override_ffe_presets(self, value: List[int]): def override_ffe_presets(self, value: List[int]):
@@ -219,13 +223,13 @@ class LinkDisplayPortTx:
warnings.warn("FFE presets does not support.") warnings.warn("FFE presets does not support.")
return return
new_value = value[0] | (value[0] << 8) | (value[0] << 16) | (value[0] << 32) new_value = value[0] | (value[0] << 8) | (value[0] << 16) | (value[0] << 32)
self.__io.set(TSI_DP2TX_OUT_FFE, new_value) self.__io.set(ci.TSI_DP2TX_OUT_FFE, new_value)
def __get_override_voltage(self) -> int: def __get_override_voltage(self) -> int:
return self.__io.get(TSI_DPTX_OVERRIDE_VOLTAGE_SWING, c_uint32)[1] return self.__io.get(ci.TSI_DPTX_OVERRIDE_VOLTAGE_SWING, c_uint32)[1]
def __get_override_pre_emp(self) -> int: def __get_override_pre_emp(self) -> int:
return self.__io.get(TSI_DPTX_OVERRIDE_PRE_EMPHASIS, c_uint32)[1] return self.__io.get(ci.TSI_DPTX_OVERRIDE_PRE_EMPHASIS, c_uint32)[1]
@property @property
def link_pattern(self) -> DPLinkPattern: def link_pattern(self) -> DPLinkPattern:
@@ -235,7 +239,7 @@ class LinkDisplayPortTx:
Returns: Returns:
object of `DPLinkPattern` type object of `DPLinkPattern` type
""" """
return DPLinkPattern(self.__io.get(TSI_DPTX_OUTPUT_PATTERN, c_uint32)[1]) return DPLinkPattern(self.__io.get(ci.TSI_DPTX_OUTPUT_PATTERN, c_uint32)[1])
def set_link_pattern(self, pattern: DPLinkPattern, additional_param: int = 1): def set_link_pattern(self, pattern: DPLinkPattern, additional_param: int = 1):
""" """
@@ -247,16 +251,16 @@ class LinkDisplayPortTx:
""" """
if not self.__HW_CAPS.dp2_custom_rates and pattern not in [e.value for e in DPLinkPattern]: if not self.__HW_CAPS.dp2_custom_rates and pattern not in [e.value for e in DPLinkPattern]:
raise ValueError(f"Current pattern {pattern.name} is not supported") raise ValueError(f"Current pattern {pattern.name} is not supported")
self.__io.set(TSI_DPTX_OUTPUT_PATTERN, pattern.value, c_uint32) self.__io.set(ci.TSI_DPTX_OUTPUT_PATTERN, pattern.value, c_uint32)
if pattern == DPLinkPattern.LinkSquarePattern: if pattern == DPLinkPattern.LinkSquarePattern:
self.__io.set(TSI_DPTX_SQUARE_PATTERN_NUMBER, additional_param, c_uint32) self.__io.set(ci.TSI_DPTX_SQUARE_PATTERN_NUMBER, additional_param, c_uint32)
def set_force_link_mode(self, link_mode: DPOutLinkMode): def set_force_link_mode(self, link_mode: DPOutLinkMode):
self.__io.set(TSI_DPTX_OUT_LINK_MODE, link_mode.value, c_uint32) self.__io.set(p_ci.TSI_DPTX_OUT_LINK_MODE, link_mode.value, c_uint32)
def get_force_link_mode(self) -> DPOutLinkMode: def get_force_link_mode(self) -> DPOutLinkMode:
return DPOutLinkMode(self.__io.get(TSI_DPTX_OUT_LINK_MODE, c_uint32)[1]) return DPOutLinkMode(self.__io.get(p_ci.TSI_DPTX_OUT_LINK_MODE, c_uint32)[1])
def cable_rx_type(self) -> CableCapabilitiesEnum: def cable_rx_type(self) -> CableCapabilitiesEnum:
""" """

View File

@@ -1,6 +1,9 @@
from typing import Optional, Union, Type from ctypes import c_uint, c_int
from typing import Optional, Union, Type, List
from UniTAP.libs.lib_tsi import PortIO from UniTAP.libs.lib_tsi import PortIO
from UniTAP.libs.lib_tsi.tsi_private_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from .link_tx_types import * from .link_tx_types import *
from .private_link_tx_types import * from .private_link_tx_types import *
from .link_status_common import * from .link_status_common import *
@@ -123,10 +126,10 @@ class LinkDisplayPortConfig:
return link_status return link_status
def _read_lt_features(self) -> LTFeatures: def _read_lt_features(self) -> LTFeatures:
return self.__io.get(TSI_DPTX_LT_FEATURES, LTFeatures)[1] return self.__io.get(ci.TSI_DPTX_LT_FEATURES, LTFeatures)[1]
def __get_post_lt_features(self) -> PostLtFeatures: def __get_post_lt_features(self) -> PostLtFeatures:
return self.__io.get(TSI_DPTX_POST_LT_FEATURES, PostLtFeatures)[1] return self.__io.get(p_ci.TSI_DPTX_POST_LT_FEATURES, PostLtFeatures)[1]
def __set_post_lt_features(self, config: DisplayPortLinkConfig): def __set_post_lt_features(self, config: DisplayPortLinkConfig):
post_lt_features = self.__get_post_lt_features() post_lt_features = self.__get_post_lt_features()
@@ -134,10 +137,10 @@ class LinkDisplayPortConfig:
post_lt_features.force_edid_timings = config.force_edid_timings_after_lt post_lt_features.force_edid_timings = config.force_edid_timings_after_lt
if config.adaptive_sync_auto_enable is not None and self.__caps.adaptive_sync: if config.adaptive_sync_auto_enable is not None and self.__caps.adaptive_sync:
post_lt_features.as_auto_enable = config.adaptive_sync_auto_enable post_lt_features.as_auto_enable = config.adaptive_sync_auto_enable
self.__io.set(TSI_DPTX_POST_LT_FEATURES, post_lt_features.value(), c_uint32) self.__io.set(p_ci.TSI_DPTX_POST_LT_FEATURES, post_lt_features.value(), c_uint32)
def __get_dp2_custom_rates(self) -> list: def __get_dp2_custom_rates(self) -> list:
rates = self.__io.get(TSI_DP2TX_CUSTOM_RATE_CAPS_R, c_uint32, 32)[1] rates = self.__io.get(ci.TSI_DP2TX_CUSTOM_RATE_CAPS_R, c_uint32, 32)[1]
custom_rates = [] custom_rates = []
for i in range(len(rates)): for i in range(len(rates)):
custom_rates.append(float(rates[i]) * 200000 / 1000000000) custom_rates.append(float(rates[i]) * 200000 / 1000000000)
@@ -149,20 +152,20 @@ class LinkDisplayPortConfig:
return return
if lane_count not in [1, 2, 4]: if lane_count not in [1, 2, 4]:
raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4") raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4")
self.__io.set(TSI_DPTX_LINK_CFG_LANES, lane_count, c_uint32) self.__io.set(ci.TSI_DPTX_LINK_CFG_LANES, lane_count, c_uint32)
def __get_lane_count_dp14(self) -> int: def __get_lane_count_dp14(self) -> int:
return self.__io.get(TSI_DPTX_LINK_CFG_LANES)[1] return self.__io.get(ci.TSI_DPTX_LINK_CFG_LANES)[1]
def __set_lane_count_dp21(self, lane_count: Optional[int]): def __set_lane_count_dp21(self, lane_count: Optional[int]):
if lane_count is None: if lane_count is None:
return return
if lane_count not in [1, 2, 4]: if lane_count not in [1, 2, 4]:
raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4") raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4")
self.__io.set(TSI_DP2TX_LT_SLC, lane_count, c_uint32) self.__io.set(ci.TSI_DP2TX_LT_SLC, lane_count, c_uint32)
def __get_lane_count_dp21(self) -> int: def __get_lane_count_dp21(self) -> int:
return self.__io.get(TSI_DP2TX_LT_SLC)[1] return self.__io.get(ci.TSI_DP2TX_LT_SLC)[1]
def __set_bit_rate_14(self, bit_rate: Optional[float]): def __set_bit_rate_14(self, bit_rate: Optional[float]):
if bit_rate is None: if bit_rate is None:
@@ -170,10 +173,10 @@ class LinkDisplayPortConfig:
if int(round(bit_rate / 0.27)) > self.__caps.max_link_rate: if int(round(bit_rate / 0.27)) > self.__caps.max_link_rate:
raise ValueError(f"Following 8b/10b bit rate {bit_rate} is not supported on device. " raise ValueError(f"Following 8b/10b bit rate {bit_rate} is not supported on device. "
f"Max supported link rate {round(self.__caps.max_link_rate * 0.27, 2)}") f"Max supported link rate {round(self.__caps.max_link_rate * 0.27, 2)}")
self.__io.set(TSI_DPTX_LINK_CFG_BIT_RATE, int(round(bit_rate / 0.27)), c_uint32) self.__io.set(ci.TSI_DPTX_LINK_CFG_BIT_RATE, int(round(bit_rate / 0.27)), c_uint32)
def __get_bit_rate_14(self) -> float: def __get_bit_rate_14(self) -> float:
return round(self.__io.get(TSI_DPTX_LINK_CFG_BIT_RATE)[1] * 0.27, 2) return round(self.__io.get(ci.TSI_DPTX_LINK_CFG_BIT_RATE)[1] * 0.27, 2)
def __set_bit_rate_21(self, bit_rate: Optional[Union[float, int]]): def __set_bit_rate_21(self, bit_rate: Optional[Union[float, int]]):
if bit_rate is None: if bit_rate is None:
@@ -182,42 +185,42 @@ class LinkDisplayPortConfig:
if not self.__caps.support_10gbps: if not self.__caps.support_10gbps:
raise ValueError(f"Following bit rate {bit_rate} is not supported on device.") raise ValueError(f"Following bit rate {bit_rate} is not supported on device.")
else: else:
res = self.__io.get(TSI_DP2TX_CUSTOM_RATE_MAP, c_uint32, 3)[1] res = self.__io.get(ci.TSI_DP2TX_CUSTOM_RATE_MAP, c_uint32, 3)[1]
self.__io.set(TSI_DP2TX_CUSTOM_RATE_MAP, (int(bit_rate * 1000000000 / 200000), res[1], res[2]), self.__io.set(ci.TSI_DP2TX_CUSTOM_RATE_MAP, (int(bit_rate * 1000000000 / 200000), res[1], res[2]),
c_uint32, 3) c_uint32, 3)
elif (bit_rate == 10.0 and not self.__caps.support_10gbps) or \ elif (bit_rate == 10.0 and not self.__caps.support_10gbps) or \
(bit_rate == 13.5 and not self.__caps.support_13_5gbps) or \ (bit_rate == 13.5 and not self.__caps.support_13_5gbps) or \
(bit_rate == 20.0 and not self.__caps.support_20gbps): (bit_rate == 20.0 and not self.__caps.support_20gbps):
raise ValueError(f"Following bit rate {bit_rate} is not supported on device.") raise ValueError(f"Following bit rate {bit_rate} is not supported on device.")
self.__io.set(TSI_DP2TX_LT_SBR, DP21_LinkRateRev.get(bit_rate), c_uint32) self.__io.set(ci.TSI_DP2TX_LT_SBR, DP21_LinkRateRev.get(bit_rate), c_uint32)
def __get_bit_rate_21(self) -> float: def __get_bit_rate_21(self) -> float:
return DP21_LinkRate.get(self.__io.get(TSI_DP2TX_LT_SBR)[1]) return DP21_LinkRate.get(self.__io.get(ci.TSI_DP2TX_LT_SBR)[1])
def __support_ssc(self) -> bool: def __support_ssc(self) -> bool:
return (self.__io.get(TSI_DPTX_DOWNSPREAD_STATUS_R, c_uint32)[1] >> 1) & 1 != 0 return (self.__io.get(ci.TSI_DPTX_DOWNSPREAD_STATUS_R, c_uint32)[1] >> 1) & 1 != 0
def __set_config_ssc(self, ssc_conf: Optional[SSCConfig]): def __set_config_ssc(self, ssc_conf: Optional[SSCConfig]):
if ssc_conf is None: if ssc_conf is None:
return return
if not self.__support_ssc(): if not self.__support_ssc():
raise ValueError(f"SSC is not supported on the device.") raise ValueError(f"SSC is not supported on the device.")
self.__io.set(TSI_DPTX_DOWNSPREAD_CONTROL, int(ssc_conf.enabled), c_uint32) self.__io.set(ci.TSI_DPTX_DOWNSPREAD_CONTROL, int(ssc_conf.enabled), c_uint32)
if ssc_conf.enabled: if ssc_conf.enabled:
if not (1 <= ssc_conf.amplitude <= 50): if not (1 <= ssc_conf.amplitude <= 50):
raise ValueError(f"Incorrect amplitude value {ssc_conf.amplitude}. Must be from range: 0.1 - 0.5") raise ValueError(f"Incorrect amplitude value {ssc_conf.amplitude}. Must be from range: 0.1 - 0.5")
self.__io.set(TSI_DPTX_DOWNSPREAD_AMP, ssc_conf.amplitude, c_uint32) self.__io.set(ci.TSI_DPTX_DOWNSPREAD_AMP, ssc_conf.amplitude, c_uint32)
if not (30000 <= ssc_conf.frequency <= 63000): if not (30000 <= ssc_conf.frequency <= 63000):
raise ValueError(f"Incorrect frequency value {ssc_conf.frequency}. Must be from range: 30000 - 63000") raise ValueError(f"Incorrect frequency value {ssc_conf.frequency}. Must be from range: 30000 - 63000")
self.__io.set(TSI_DPTX_DOWNSPREAD_FREQ, ssc_conf.frequency, c_uint32) self.__io.set(ci.TSI_DPTX_DOWNSPREAD_FREQ, ssc_conf.frequency, c_uint32)
def __get_config_ssc(self) -> SSCConfig: def __get_config_ssc(self) -> SSCConfig:
if not self.__support_ssc(): if not self.__support_ssc():
return None return None
ssc_conf = SSCConfig() ssc_conf = SSCConfig()
ssc_conf.enabled = (self.__io.get(TSI_DPTX_DOWNSPREAD_STATUS_R)[1] & 1) != 0 ssc_conf.enabled = (self.__io.get(ci.TSI_DPTX_DOWNSPREAD_STATUS_R)[1] & 1) != 0
ssc_conf.frequency = self.__io.get(TSI_DPTX_DOWNSPREAD_FREQ)[1] ssc_conf.frequency = self.__io.get(ci.TSI_DPTX_DOWNSPREAD_FREQ)[1]
ssc_conf.amplitude = self.__io.get(TSI_DPTX_DOWNSPREAD_AMP)[1] ssc_conf.amplitude = self.__io.get(ci.TSI_DPTX_DOWNSPREAD_AMP)[1]
return ssc_conf return ssc_conf
def __dp2_support_rates(self) -> bool: def __dp2_support_rates(self) -> bool:
@@ -228,7 +231,7 @@ class LinkDisplayPortConfig:
return return
if not self.__dp2_support_rates(): if not self.__dp2_support_rates():
raise ValueError(f"LTTPR is not supported on the device.") raise ValueError(f"LTTPR is not supported on the device.")
self.__io.set(TSI_DPTX_LTTPR_CONTROL, int(enable)) self.__io.set(ci.TSI_DPTX_LTTPR_CONTROL, int(enable))
def __set_lt_features(self, config: Optional[DisplayPortLinkConfig]): def __set_lt_features(self, config: Optional[DisplayPortLinkConfig]):
if config is None: if config is None:
@@ -270,22 +273,22 @@ class LinkDisplayPortConfig:
else: else:
raise TypeError("Incorrect DisplayPortLinkConfig format!") raise TypeError("Incorrect DisplayPortLinkConfig format!")
self.__io.set(TSI_DPTX_LT_FEATURES, res.value(), c_uint32) self.__io.set(ci.TSI_DPTX_LT_FEATURES, res.value(), c_uint32)
def __enable_mst(self, enable: Optional[bool]): def __enable_mst(self, enable: Optional[bool]):
if enable is None: if enable is None:
return return
self.__io.set(TSI_DPTX_COMMAND_W, 3 if enable else 4, c_uint32) self.__io.set(ci.TSI_DPTX_COMMAND_W, 3 if enable else 4, c_uint32)
def __set_mst_channel_count(self, count: Optional[int]): def __set_mst_channel_count(self, count: Optional[int]):
if count is None: if count is None:
return return
if not (0 <= count <= self.__caps.mst_stream_count): if not (0 <= count <= self.__caps.mst_stream_count):
raise ValueError(f"Incorrect stream count {count}. Available stream count {self.__caps.mst_stream_count}") raise ValueError(f"Incorrect stream count {count}. Available stream count {self.__caps.mst_stream_count}")
self.__io.set(TSI_PG_ENABLED_STREAM_COUNT, count, c_uint32) self.__io.set(ci.TSI_PG_ENABLED_STREAM_COUNT, count, c_uint32)
def __link_encoding(self) -> DpLinkEncoding: def __link_encoding(self) -> DpLinkEncoding:
result, value = self.__io.get(TSI_DPTX_LINK_MODE_R, c_uint) result, value = self.__io.get(ci.TSI_DPTX_LINK_MODE_R, c_uint)
if value == 0: if value == 0:
return DpLinkEncoding.LE_8b10b return DpLinkEncoding.LE_8b10b
@@ -293,36 +296,36 @@ class LinkDisplayPortConfig:
return DpLinkEncoding.LE_128b132b return DpLinkEncoding.LE_128b132b
def __mst_enabled(self) -> bool: def __mst_enabled(self) -> bool:
return (self.__io.get(TSI_DPTX_LINK_STATUS_BITS_R)[1] & (1 << 30)) != 0 return (self.__io.get(ci.TSI_DPTX_LINK_STATUS_BITS_R)[1] & (1 << 30)) != 0
def __mst_stream_count(self) -> int: def __mst_stream_count(self) -> int:
result, mst_status = self.__io.get(TSI_DPTX_MST_STATUS_R, c_uint) result, mst_status = self.__io.get(ci.TSI_DPTX_MST_STATUS_R, c_uint)
return (mst_status >> 8) & 0xFF return (mst_status >> 8) & 0xFF
def __lttpr_active(self) -> Optional[bool]: def __lttpr_active(self) -> Optional[bool]:
if self.__link_encoding == DpLinkEncoding.LE_128b132b: if self.__link_encoding == DpLinkEncoding.LE_128b132b:
return (self.__io.get(TSI_DPTX_LTTPR_CONTROL, c_uint32)[1] & 1) != 0 return (self.__io.get(ci.TSI_DPTX_LTTPR_CONTROL, c_uint32)[1] & 1) != 0
else: else:
return None return None
def __check_custom_bit_rate(self) -> float: def __check_custom_bit_rate(self) -> float:
res = self.__io.get(TSI_DP2TX_CUSTOM_RATE_MAP, c_uint32, 3)[1] res = self.__io.get(ci.TSI_DP2TX_CUSTOM_RATE_MAP, c_uint32, 3)[1]
for i in range(3): for i in range(3):
if res[i] != 0: if res[i] != 0:
return res[i] * 200000 / 1000000000 return res[i] * 200000 / 1000000000
return 0 return 0
def __try_fec_after_lt(self, enable: bool): def __try_fec_after_lt(self, enable: bool):
result = self.__io.get(TSI_DPTX_FEC_CTRL, c_int) result = self.__io.get(ci.TSI_DPTX_FEC_CTRL, c_int)
val = result[1] val = result[1]
if enable: if enable:
val |= 0x2 val |= 0x2
else: else:
val &= ~0x2 val &= ~0x2
self.__io.set(TSI_DPTX_FEC_CTRL, val) self.__io.set(ci.TSI_DPTX_FEC_CTRL, val)
def __fec_after_lt_state(self) -> bool: def __fec_after_lt_state(self) -> bool:
return (self.__io.get(TSI_DPTX_FEC_CTRL, c_int)[1] & 0x2) != 0 return (self.__io.get(ci.TSI_DPTX_FEC_CTRL, c_int)[1] & 0x2) != 0
def __sdp_control(self, config: Optional[DisplayPortLinkConfig]): def __sdp_control(self, config: Optional[DisplayPortLinkConfig]):
if config is None: if config is None:
@@ -335,24 +338,24 @@ class LinkDisplayPortConfig:
self.__write_sdp_control(sdp_control) self.__write_sdp_control(sdp_control)
def __write_sdp_control(self, sdp_control: SdpControl): def __write_sdp_control(self, sdp_control: SdpControl):
self.__io.set(TSI_DPTX_SDP_CTRL, sdp_control.value()) self.__io.set(p_ci.TSI_DPTX_SDP_CTRL, sdp_control.value())
def __read_sdp_control(self) -> SdpControl: def __read_sdp_control(self) -> SdpControl:
return self.__io.get(TSI_DPTX_SDP_CTRL, SdpControl)[1] return self.__io.get(p_ci.TSI_DPTX_SDP_CTRL, SdpControl)[1]
def __set_edp_sel_rate(self, rate: float): def __set_edp_sel_rate(self, rate: float):
if self.__caps.edp and rate in self.__get_edp_caps_rates(): if self.__caps.edp and rate in self.__get_edp_caps_rates():
self.__io.set(TSI_DPTX_EDP_LT_SBR, int(rate / 0.0002), c_uint32) self.__io.set(ci.TSI_DPTX_EDP_LT_SBR, int(rate / 0.0002), c_uint32)
elif not self.__caps.edp: elif not self.__caps.edp:
raise ValueError("EDP is not supported.") raise ValueError("EDP is not supported.")
def __get_edp_sel_rate(self) -> int: def __get_edp_sel_rate(self) -> int:
if self.__caps.edp: if self.__caps.edp:
return self.__io.get(TSI_DPTX_EDP_LT_SBR)[1] * 0.0002 return self.__io.get(ci.TSI_DPTX_EDP_LT_SBR)[1] * 0.0002
def __get_edp_caps_rates(self) -> List[float]: def __get_edp_caps_rates(self) -> List[float]:
if self.__caps.edp: if self.__caps.edp:
rates = self.__io.get(TSI_DPTX_EXTRA_DP14_RATES, data_type=c_uint32, data_count=8)[1] rates = self.__io.get(ci.TSI_DPTX_EXTRA_DP14_RATES, data_type=c_uint32, data_count=8)[1]
new_rates = [] new_rates = []
for rate in rates: for rate in rates:
if rate > 0: if rate > 0:

View File

@@ -1,6 +1,6 @@
from typing import Optional, Union, Type from typing import Optional, Union, Type
from UniTAP.libs.lib_tsi import PortIO from UniTAP.libs.lib_tsi import PortIO
from UniTAP.libs.lib_tsi.tsi_private_types import * import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from .link_tx_types import * from .link_tx_types import *
from .private_link_tx_types import * from .private_link_tx_types import *
from .link_status_common import * from .link_status_common import *
@@ -62,25 +62,25 @@ class LinkDisplayPortForceConfig:
(bit_rate == 13.5 and not self.__caps.support_13_5gbps) or \ (bit_rate == 13.5 and not self.__caps.support_13_5gbps) or \
(bit_rate == 20.0 and not self.__caps.support_20gbps): (bit_rate == 20.0 and not self.__caps.support_20gbps):
raise ValueError(f"Following bit rate {bit_rate} is not supported on device.") raise ValueError(f"Following bit rate {bit_rate} is not supported on device.")
self.__io.set(TSI_DP2TX_OUT_BR, DP21_LinkRateRev.get(bit_rate), c_uint32) self.__io.set(p_ci.TSI_DP2TX_OUT_BR, DP21_LinkRateRev.get(bit_rate), c_uint32)
def __force_get_bit_rate(self) -> float: def __force_get_bit_rate(self) -> float:
return DP21_LinkRate.get(self.__io.get(TSI_DP2TX_OUT_BR)[1]) return DP21_LinkRate.get(self.__io.get(p_ci.TSI_DP2TX_OUT_BR)[1])
def __force_set_lane_count(self, lane_count: Optional[int]): def __force_set_lane_count(self, lane_count: Optional[int]):
if lane_count is None: if lane_count is None:
return return
if lane_count not in [1, 2, 4]: if lane_count not in [1, 2, 4]:
raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4") raise ValueError(f"Incorrect lane count number {lane_count}. Must be from list: 1, 2, 4")
self.__io.set(TSI_DP2TX_OUT_LC, lane_count, c_uint32) self.__io.set(p_ci.TSI_DP2TX_OUT_LC, lane_count, c_uint32)
def __force_get_lane_count(self) -> int: def __force_get_lane_count(self) -> int:
return self.__io.get(TSI_DP2TX_OUT_LC)[1] return self.__io.get(p_ci.TSI_DP2TX_OUT_LC)[1]
def __force_set_pattern(self, pattern: Optional[DP128b132bLinkPattern]): def __force_set_pattern(self, pattern: Optional[DP128b132bLinkPattern]):
if pattern is None: if pattern is None:
return return
self.__io.set(TSI_DP2TX_OUT_TEST_PATTERN, pattern.value, c_uint32) self.__io.set(p_ci.TSI_DP2TX_OUT_TEST_PATTERN, pattern.value, c_uint32)
def __force_get_pattern(self) -> DP128b132bLinkPattern: def __force_get_pattern(self) -> DP128b132bLinkPattern:
return DP128b132bLinkPattern(self.__io.get(TSI_DP2TX_OUT_TEST_PATTERN, c_uint32)[1]) return DP128b132bLinkPattern(self.__io.get(p_ci.TSI_DP2TX_OUT_TEST_PATTERN, c_uint32)[1])

View File

@@ -2,8 +2,7 @@ import warnings
from typing import Optional from typing import Optional
from UniTAP.libs.lib_tsi import PortIO from UniTAP.libs.lib_tsi import PortIO
from UniTAP.libs.lib_tsi.tsi_types import * import UniTAP.libs.lib_tsi.tsi_types as ci
from .link_tx_types import *
from .private_link_tx_types import * from .private_link_tx_types import *
from .link_status_common import * from .link_status_common import *
from .private_link_status_common import * from .private_link_status_common import *
@@ -47,7 +46,7 @@ class LinkDisplayPortStatusSource:
Returns: Returns:
object of int type object of int type
""" """
result, mst_status = self.__io.get(TSI_DPTX_MST_STATUS_R, c_uint) result, mst_status = self.__io.get(ci.TSI_DPTX_MST_STATUS_R, c_uint)
return (mst_status >> 8) & 0xFF return (mst_status >> 8) & 0xFF
@property @property
@@ -58,7 +57,7 @@ class LinkDisplayPortStatusSource:
Returns: Returns:
object of DpLinkEncoding type object of DpLinkEncoding type
""" """
result, value = self.__io.get(TSI_DPTX_LINK_MODE_R, c_uint) result, value = self.__io.get(ci.TSI_DPTX_LINK_MODE_R, c_uint)
if value == 0: if value == 0:
return DpLinkEncoding.LE_8b10b return DpLinkEncoding.LE_8b10b
@@ -77,9 +76,9 @@ class LinkDisplayPortStatusSource:
if self.__check_custom_bit_rate() != 0: if self.__check_custom_bit_rate() != 0:
return self.__check_custom_bit_rate() return self.__check_custom_bit_rate()
else: else:
return DP21_LinkRate.get(self.__io.get(TSI_DP2TX_LT_RATE_R, c_uint)[1]) return DP21_LinkRate.get(self.__io.get(ci.TSI_DP2TX_LT_RATE_R, c_uint)[1])
else: else:
return round(self.__io.get(TSI_DPTX_LINK_RATE_R, c_uint)[1] * 0.27, 2) return round(self.__io.get(ci.TSI_DPTX_LINK_RATE_R, c_uint)[1] * 0.27, 2)
@property @property
def lane_count(self) -> int: def lane_count(self) -> int:
@@ -89,7 +88,7 @@ class LinkDisplayPortStatusSource:
Returns: Returns:
object of int type object of int type
""" """
return self.__io.get(TSI_DPTX_LINK_LANE_COUNT_R, c_int)[1] return self.__io.get(ci.TSI_DPTX_LINK_LANE_COUNT_R, c_int)[1]
@property @property
def hpd_asserted(self) -> bool: def hpd_asserted(self) -> bool:
@@ -99,7 +98,7 @@ class LinkDisplayPortStatusSource:
Returns: Returns:
object of bool type object of bool type
""" """
return (self.__io.get(TSI_DPTX_HPD_STATUS_R, c_int)[1] & 1) != 0 return (self.__io.get(ci.TSI_DPTX_HPD_STATUS_R, c_int)[1] & 1) != 0
@property @property
def available_link_rate(self) -> float: def available_link_rate(self) -> float:
@@ -142,8 +141,8 @@ class LinkDisplayPortStatusSource:
raise ValueError(f"Incorrect lane number {lane_number}. Available range: 0-{self.lane_count}") raise ValueError(f"Incorrect lane number {lane_number}. Available range: 0-{self.lane_count}")
status = self.__read_link_status() status = self.__read_link_status()
voltage_swing = self.__io.get(TSI_DPTX_LINK_VOLTAGE_SWING_R, LinkVoltageSwing)[1] voltage_swing = self.__io.get(ci.TSI_DPTX_LINK_VOLTAGE_SWING_R, LinkVoltageSwing)[1]
pre_emphasis = self.__io.get(TSI_DPTX_LINK_PRE_EMPHASIS_R, LinkPreEmphasis)[1] pre_emphasis = self.__io.get(ci.TSI_DPTX_LINK_PRE_EMPHASIS_R, LinkPreEmphasis)[1]
error_counters = self.__dpcd.read(0x210, 8).data error_counters = self.__dpcd.read(0x210, 8).data
lane_status = LaneStatus() lane_status = LaneStatus()
@@ -178,7 +177,7 @@ class LinkDisplayPortStatusSource:
lane_status.error_count = error_counters[6] | ((error_counters[7] & 0x7F) << 8) lane_status.error_count = error_counters[6] | ((error_counters[7] & 0x7F) << 8)
if self.link_encoding == DpLinkEncoding.LE_128b132b: if self.link_encoding == DpLinkEncoding.LE_128b132b:
ffe_preset = self.__io.get(TSI_DP2TX_LT_FFE_PRESET_R, c_uint32)[1] ffe_preset = self.__io.get(ci.TSI_DP2TX_LT_FFE_PRESET_R, c_uint32)[1]
lane_status.ffe_preset = (ffe_preset >> (8 * lane_number)) & 0xFF lane_status.ffe_preset = (ffe_preset >> (8 * lane_number)) & 0xFF
else: else:
lane_status.ffe_preset = 0 lane_status.ffe_preset = 0
@@ -195,7 +194,7 @@ class LinkDisplayPortStatusSource:
object of bool or None type object of bool or None type
""" """
if self.__caps.dsc or self.__caps.dsc2: if self.__caps.dsc or self.__caps.dsc2:
return (self.__io.get(TSI_DPTX_DSC_STATUS_R)[1] & 1) != 0 return (self.__io.get(ci.TSI_DPTX_DSC_STATUS_R)[1] & 1) != 0
else: else:
return None return None
@@ -209,7 +208,7 @@ class LinkDisplayPortStatusSource:
object of bool or None type object of bool or None type
""" """
if self.__caps.mst: if self.__caps.mst:
return (self.__io.get(TSI_DPTX_MST_STATUS_R, c_uint32)[1] & 1) != 0 return (self.__io.get(ci.TSI_DPTX_MST_STATUS_R, c_uint32)[1] & 1) != 0
else: else:
return None return None
@@ -222,7 +221,7 @@ class LinkDisplayPortStatusSource:
Returns: Returns:
object of bool or None type object of bool or None type
""" """
res = self.__io.get(TSI_DPTX_DOWNSPREAD_STATUS_R)[1] res = self.__io.get(ci.TSI_DPTX_DOWNSPREAD_STATUS_R)[1]
if ((res >> 1) & 1) != 0: if ((res >> 1) & 1) != 0:
return (res & 1) != 0 return (res & 1) != 0
else: else:
@@ -238,7 +237,7 @@ class LinkDisplayPortStatusSource:
object of bool or None type object of bool or None type
""" """
if self.__caps.fec or self.__caps.fec2: if self.__caps.fec or self.__caps.fec2:
return (self.__io.get(TSI_DPTX_FEC_STATUS_R)[1] & 1) != 0 return (self.__io.get(ci.TSI_DPTX_FEC_STATUS_R)[1] & 1) != 0
else: else:
return None return None
@@ -272,7 +271,7 @@ class LinkDisplayPortStatusSource:
object of bool or None type object of bool or None type
""" """
if self.link_encoding == DpLinkEncoding.LE_128b132b: if self.link_encoding == DpLinkEncoding.LE_128b132b:
return (self.__io.get(TSI_DPTX_LTTPR_STATUS_R, c_uint32)[1] & 1) != 0 return (self.__io.get(ci.TSI_DPTX_LTTPR_STATUS_R, c_uint32)[1] & 1) != 0
else: else:
return None return None
@@ -327,7 +326,7 @@ class LinkDisplayPortStatusSource:
object of `StreamStatusDP` type object of `StreamStatusDP` type
""" """
stream_status = StreamStatusDP() stream_status = StreamStatusDP()
result, msa_info, size = self.__io.get(TSI_DPTX_MSA_INFO_R, DpMsa, 4) result, msa_info, size = self.__io.get(ci.TSI_DPTX_MSA_INFO_R, DpMsa, 4)
if stream_index < size: if stream_index < size:
msa_info_private = MSAInfo(msa_info[stream_index]) msa_info_private = MSAInfo(msa_info[stream_index])
@@ -336,16 +335,16 @@ class LinkDisplayPortStatusSource:
stream_status.mvid = msa_info_private.m_video stream_status.mvid = msa_info_private.m_video
stream_status.nvid = msa_info_private.n_video stream_status.nvid = msa_info_private.n_video
result = self.__io.get(TSI_DPTX_CRC_R, DpCrc, self.mst_stream_count) result = self.__io.get(ci.TSI_DPTX_CRC_R, DpCrc, self.mst_stream_count)
if result[0] >= TSI_SUCCESS and self.mst_stream_count > 1: if result[0] >= ci.TSI_SUCCESS and self.mst_stream_count > 1:
stream_status.crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b] stream_status.crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b]
elif result[0] >= TSI_SUCCESS and self.mst_stream_count == 1: elif result[0] >= ci.TSI_SUCCESS and self.mst_stream_count == 1:
stream_status.crc = [result[1].r, result[1].g, result[1].b] stream_status.crc = [result[1].r, result[1].g, result[1].b]
result = self.__io.get(TSI_DPTX_DSC_CRC_R, DpCrc, self.mst_stream_count) result = self.__io.get(ci.TSI_DPTX_DSC_CRC_R, DpCrc, self.mst_stream_count)
if result[0] >= TSI_SUCCESS and self.mst_stream_count > 1: if result[0] >= ci.TSI_SUCCESS and self.mst_stream_count > 1:
stream_status.dsc_crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b] stream_status.dsc_crc = [result[1][stream_index].r, result[1][stream_index].g, result[1][stream_index].b]
elif result[0] >= TSI_SUCCESS and self.mst_stream_count == 1: elif result[0] >= ci.TSI_SUCCESS and self.mst_stream_count == 1:
stream_status.dsc_crc = [result[1].r, result[1].g, result[1].b] stream_status.dsc_crc = [result[1].r, result[1].g, result[1].b]
else: else:
raise ValueError(f"Selected stream {stream_index} is not available. " raise ValueError(f"Selected stream {stream_index} is not available. "
@@ -368,7 +367,7 @@ class LinkDisplayPortStatusSource:
raise ValueError(f"Selected stream {stream_index} is not available. " raise ValueError(f"Selected stream {stream_index} is not available. "
f"Available stream number: {self.mst_stream_count}") f"Available stream number: {self.mst_stream_count}")
res = self.__io.get(TSI_DPTX_VCP_TABLE_R, VCPTable, 4)[1] res = self.__io.get(ci.TSI_DPTX_VCP_TABLE_R, VCPTable, 4)[1]
if self.mst_enabled: if self.mst_enabled:
status = VCPStatus() status = VCPStatus()
@@ -389,16 +388,16 @@ class LinkDisplayPortStatusSource:
""" """
Send ACT command. Send ACT command.
""" """
self.__io.set(TSI_DPTX_MST_COMMAND_W, 1, c_uint32) self.__io.set(ci.TSI_DPTX_MST_COMMAND_W, 1, c_uint32)
def __read_lt_features(self) -> LTFeatures: def __read_lt_features(self) -> LTFeatures:
return self.__io.get(TSI_DPTX_LT_FEATURES, LTFeatures)[1] return self.__io.get(ci.TSI_DPTX_LT_FEATURES, LTFeatures)[1]
def __read_link_status(self) -> LinkTxStatus: def __read_link_status(self) -> LinkTxStatus:
return self.__io.get(TSI_DPTX_LINK_STATUS_R, LinkTxStatus)[1] return self.__io.get(ci.TSI_DPTX_LINK_STATUS_R, LinkTxStatus)[1]
def __check_custom_bit_rate(self) -> float: def __check_custom_bit_rate(self) -> float:
res = self.__io.get(TSI_DP2TX_CUSTOM_RATE_MAP, c_uint32, 3)[1] res = self.__io.get(ci.TSI_DP2TX_CUSTOM_RATE_MAP, c_uint32, 3)[1]
for i in range(3): for i in range(3):
if res[i] != 0: if res[i] != 0:
return res[i] * 200000 / 1000000000 return res[i] * 200000 / 1000000000

View File

@@ -1,6 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from enum import IntEnum from enum import IntEnum
from UniTAP.libs.lib_tsi.tsi_types import TSI_ARC_CONTROL_W, TSI_HDRX_ARC_STATUS_R import UniTAP.libs.lib_tsi.tsi_types as ci
from ctypes import c_uint32 from ctypes import c_uint32
@@ -44,10 +44,10 @@ class ArcRx:
self.__single_mode = True self.__single_mode = True
def __read_arc_status(self) -> int: def __read_arc_status(self) -> int:
return self.__io.get(TSI_HDRX_ARC_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_ARC_STATUS_R, c_uint32)[1]
def __write_arc(self, value: int): def __write_arc(self, value: int):
self.__io.set(TSI_ARC_CONTROL_W, value, c_uint32) self.__io.set(ci.TSI_ARC_CONTROL_W, value, c_uint32)
@property @property
def supported(self) -> bool: def supported(self) -> bool:

View File

@@ -1,6 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import FrlMode, LtpLanesPattern, FrlCaps, LtpPattern, _update_frl_values, _update_ltp_pattern_values from .types import FrlMode, LtpLanesPattern, FrlCaps, LtpPattern, _update_frl_values, _update_ltp_pattern_values
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDRX_FRL_CAPABILITY, TSI_HDRX_FRL_PATTERN, TSI_HDRX_LINK_STATUS_R import UniTAP.libs.lib_tsi.tsi_types as ci
from ctypes import c_uint32 from ctypes import c_uint32
@@ -19,16 +19,16 @@ class FrlControlRx:
self.__ltp_additional = LtpLanesPattern() self.__ltp_additional = LtpLanesPattern()
def __read_caps(self) -> int: def __read_caps(self) -> int:
return self.__io.get(TSI_HDRX_FRL_CAPABILITY, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_FRL_CAPABILITY, c_uint32)[1]
def __write_caps(self, value: int): def __write_caps(self, value: int):
self.__io.set(TSI_HDRX_FRL_CAPABILITY, value, c_uint32) self.__io.set(ci.TSI_HDRX_FRL_CAPABILITY, value, c_uint32)
def __read_frl_pattern(self) -> int: def __read_frl_pattern(self) -> int:
return self.__io.get(TSI_HDRX_FRL_PATTERN, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_FRL_PATTERN, c_uint32)[1]
def __write_frl_pattern(self, value: int): def __write_frl_pattern(self, value: int):
self.__io.set(TSI_HDRX_FRL_PATTERN, value, c_uint32) self.__io.set(ci.TSI_HDRX_FRL_PATTERN, value, c_uint32)
@property @property
def frl_mode(self) -> FrlMode: def frl_mode(self) -> FrlMode:
@@ -130,7 +130,7 @@ class FrlControlRx:
""" """
DO re train. DO re train.
""" """
self.__io.set(TSI_HDRX_LINK_STATUS_R, 0x1c0000, c_uint32) self.__io.set(ci.TSI_HDRX_LINK_STATUS_R, 0x1c0000, c_uint32)
def __str__(self): def __str__(self):
return f"FRL Mode: {self.frl_mode.name}\n" \ return f"FRL Mode: {self.frl_mode.name}\n" \

View File

@@ -1,7 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import FrlMode, LtpLanesPattern, FrlCaps, _update_frl_values, _update_ltp_pattern_values from .types import FrlMode, LtpLanesPattern, FrlCaps, _update_frl_values, _update_ltp_pattern_values
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_FRL_CAPABILITY, TSI_HDTX_FRL_PATTERN_R, TSI_HDTX_FRL_TIMERS, \ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_HDTX_SINK_FEATURE_W, TSI_HDTX_FRL_STATUS_R
from ctypes import c_uint32 from ctypes import c_uint32
@@ -197,19 +196,19 @@ class FrlControlTx:
self.__ltp_additional = LtpLanesPattern() self.__ltp_additional = LtpLanesPattern()
def __read_caps(self) -> int: def __read_caps(self) -> int:
return self.__io.get(TSI_HDTX_FRL_CAPABILITY, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_FRL_CAPABILITY, c_uint32)[1]
def __write_caps(self, value: int): def __write_caps(self, value: int):
self.__io.set(TSI_HDTX_FRL_CAPABILITY, value, c_uint32) self.__io.set(ci.TSI_HDTX_FRL_CAPABILITY, value, c_uint32)
def __read_frl_timers(self) -> int: def __read_frl_timers(self) -> int:
return self.__io.get(TSI_HDTX_FRL_TIMERS, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_FRL_TIMERS, c_uint32)[1]
def __write_frl_timers(self, value: int): def __write_frl_timers(self, value: int):
self.__io.set(TSI_HDTX_FRL_TIMERS, value, c_uint32) self.__io.set(ci.TSI_HDTX_FRL_TIMERS, value, c_uint32)
def __read_frl_patterns(self) -> int: def __read_frl_patterns(self) -> int:
return self.__io.get(TSI_HDTX_FRL_PATTERN_R, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_FRL_PATTERN_R, c_uint32)[1]
@property @property
def ltp_pattern(self) -> LtpLanesPattern: def ltp_pattern(self) -> LtpLanesPattern:
@@ -243,7 +242,7 @@ class FrlControlTx:
Returns: Returns:
object of `FrlCaps` type object of `FrlCaps` type
""" """
_update_frl_values(self.__frl_caps, self.__io.get(TSI_HDTX_FRL_STATUS_R, c_uint32)[1]) _update_frl_values(self.__frl_caps, self.__io.get(ci.TSI_HDTX_FRL_STATUS_R, c_uint32)[1])
return self.__frl_caps return self.__frl_caps
@property @property
@@ -345,7 +344,7 @@ class FrlControlTx:
""" """
Do link training. Do link training.
""" """
self.__io.set(TSI_HDTX_SINK_FEATURE_W, 5, c_uint32) self.__io.set(ci.TSI_HDTX_SINK_FEATURE_W, 5, c_uint32)
@staticmethod @staticmethod
def __update_values(ffe_max: FfeMax, value: int): def __update_values(ffe_max: FfeMax, value: int):

View File

@@ -9,7 +9,7 @@ from .status_tx import StatusTx, HdmiModeTx
from .capabilities import HdmiCapabilities from .capabilities import HdmiCapabilities
from .frl_control_tx import FrlControlTx from .frl_control_tx import FrlControlTx
from .frl_caps_rx import FrlControlRx from .frl_caps_rx import FrlControlRx
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_CAPABILITY_R, TSI_HDRX_CAPABILITY_R import UniTAP.libs.lib_tsi.tsi_types as ci
from typing import Optional from typing import Optional
@@ -25,7 +25,7 @@ class HdmiLinkTx:
self.__tmds = TmdsTx(self.__io) self.__tmds = TmdsTx(self.__io)
self.__status = StatusTx(self.__io) self.__status = StatusTx(self.__io)
self.__frl = FrlControlTx(self.__io) self.__frl = FrlControlTx(self.__io)
self.__caps = HdmiCapabilities(TSI_HDTX_CAPABILITY_R, self.__io) self.__caps = HdmiCapabilities(ci.TSI_HDTX_CAPABILITY_R, self.__io)
@property @property
def tmds(self) -> Optional[TmdsTx]: def tmds(self) -> Optional[TmdsTx]:
@@ -96,7 +96,7 @@ class HdmiLinkRx:
self.__status = StatusRx(self.__io) self.__status = StatusRx(self.__io)
self.__frl = FrlControlRx(self.__io) self.__frl = FrlControlRx(self.__io)
self.__arc = ArcRx(self.__io) self.__arc = ArcRx(self.__io)
self.__caps = HdmiCapabilities(TSI_HDRX_CAPABILITY_R, self.__io) self.__caps = HdmiCapabilities(ci.TSI_HDRX_CAPABILITY_R, self.__io)
@property @property
def tmds(self) -> Optional[TmdsRx]: def tmds(self) -> Optional[TmdsRx]:

View File

@@ -2,9 +2,7 @@ import time
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import HdmiModeRx, FrlMode, _update_error_counters_rx from .types import HdmiModeRx, FrlMode, _update_error_counters_rx
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDRX_BEHAVIOR, TSI_HDRX_LANES_ERR_COUNTERS_R, TSI_HDRX_HPD_STATUS_R,\ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_HDRX_FRL_CAPABILITY, TSI_HDRX_LINK_STATUS_R, TSI_HDRX_HPD_CONTROL_W, TSI_HDRX_VIDEO_MODE_R, \
TSI_VIDCAP_SIGNAL_CRC_R, TSI_SUCCESS
from ctypes import c_uint8, c_uint32, c_uint64 from ctypes import c_uint8, c_uint32, c_uint64
from UniTAP.utils.function_wrapper import function_scheduler from UniTAP.utils.function_wrapper import function_scheduler
from .types import _hdmi_vm_info_to_video_mode, HdmiVideoModeInfo from .types import _hdmi_vm_info_to_video_mode, HdmiVideoModeInfo
@@ -25,7 +23,7 @@ class StatusRx:
self.__io = port_io self.__io = port_io
def __frl_status(self) -> FrlMode: def __frl_status(self) -> FrlMode:
return FrlMode(self.__io.get(TSI_HDRX_FRL_CAPABILITY, c_uint32)[1] & 0xF) return FrlMode(self.__io.get(ci.TSI_HDRX_FRL_CAPABILITY, c_uint32)[1] & 0xF)
@property @property
def hdmi_mode(self) -> HdmiModeRx: def hdmi_mode(self) -> HdmiModeRx:
@@ -35,7 +33,7 @@ class StatusRx:
Returns: Returns:
object of `HdmiModeRx` type object of `HdmiModeRx` type
""" """
return HdmiModeRx(self.__io.get(TSI_HDRX_BEHAVIOR, c_uint32)[1]) return HdmiModeRx(self.__io.get(ci.TSI_HDRX_BEHAVIOR, c_uint32)[1])
@hdmi_mode.setter @hdmi_mode.setter
def hdmi_mode(self, hdmi_mode: HdmiModeRx): def hdmi_mode(self, hdmi_mode: HdmiModeRx):
@@ -45,7 +43,7 @@ class StatusRx:
Args: Args:
hdmi_mode (HdmiModeRx) hdmi_mode (HdmiModeRx)
""" """
self.__io.set(TSI_HDRX_BEHAVIOR, hdmi_mode.value, c_uint32) self.__io.set(ci.TSI_HDRX_BEHAVIOR, hdmi_mode.value, c_uint32)
@property @property
def error_counters(self) -> list: def error_counters(self) -> list:
@@ -55,7 +53,7 @@ class StatusRx:
Returns: Returns:
object of list type object of list type
""" """
return _update_error_counters_rx(self.__io.get(TSI_HDRX_LANES_ERR_COUNTERS_R, c_uint64)[1]) return _update_error_counters_rx(self.__io.get(ci.TSI_HDRX_LANES_ERR_COUNTERS_R, c_uint64)[1])
def set_assert_state(self, asserted: bool = True): def set_assert_state(self, asserted: bool = True):
""" """
@@ -64,7 +62,7 @@ class StatusRx:
Args: Args:
asserted (bool) asserted (bool)
""" """
self.__io.set(TSI_HDRX_HPD_CONTROL_W, int(asserted), c_uint32) self.__io.set(ci.TSI_HDRX_HPD_CONTROL_W, int(asserted), c_uint32)
@property @property
def channel_lock(self) -> list: def channel_lock(self) -> list:
@@ -74,7 +72,7 @@ class StatusRx:
Returns: Returns:
object of list type object of list type
""" """
return self.__update_channel_lock(self.__io.get(TSI_HDRX_LINK_STATUS_R, c_uint32)[1], self.hdmi_mode) return self.__update_channel_lock(self.__io.get(ci.TSI_HDRX_LINK_STATUS_R, c_uint32)[1], self.hdmi_mode)
@staticmethod @staticmethod
def __update_channel_lock(value: int, mode: HdmiModeRx) -> list: def __update_channel_lock(value: int, mode: HdmiModeRx) -> list:
@@ -99,11 +97,11 @@ class StatusRx:
Returns: Returns:
object of bool type object of bool type
""" """
return (self.__io.get(TSI_HDRX_HPD_STATUS_R, c_uint32)[1] & 0x1) != 0 return (self.__io.get(ci.TSI_HDRX_HPD_STATUS_R, c_uint32)[1] & 0x1) != 0
def __check_video(self) -> bool: def __check_video(self) -> bool:
def is_msa_available(io): def is_msa_available(io):
result, msa_info, size = io.get(TSI_HDRX_VIDEO_MODE_R, HdmiVideoMode, 4) result, msa_info, size = io.get(ci.TSI_HDRX_VIDEO_MODE_R, HdmiVideoMode, 4)
return result > 0 return result > 0
return function_scheduler(is_msa_available, self.__io, interval=5, timeout=10) return function_scheduler(is_msa_available, self.__io, interval=5, timeout=10)
@@ -125,7 +123,7 @@ class StatusRx:
time.sleep(1) time.sleep(1)
result, hdmi_video_mode_info, size = self.__io.get(TSI_HDRX_VIDEO_MODE_R, HdmiVideoMode, 4) result, hdmi_video_mode_info, size = self.__io.get(ci.TSI_HDRX_VIDEO_MODE_R, HdmiVideoMode, 4)
# TODO - Size temporary will be equal 1 # TODO - Size temporary will be equal 1
size = 1 size = 1
@@ -133,8 +131,8 @@ class StatusRx:
if 0 <= stream_index < size: if 0 <= stream_index < size:
stream_status.video_mode = _hdmi_vm_info_to_video_mode(HdmiVideoModeInfo(hdmi_video_mode_info stream_status.video_mode = _hdmi_vm_info_to_video_mode(HdmiVideoModeInfo(hdmi_video_mode_info
[stream_index])) [stream_index]))
result = self.__io.get(TSI_VIDCAP_SIGNAL_CRC_R, data_type=c_uint8, data_count=6) result = self.__io.get(ci.TSI_VIDCAP_SIGNAL_CRC_R, data_type=c_uint8, data_count=6)
if result[0] >= TSI_SUCCESS: if result[0] >= ci.TSI_SUCCESS:
hdmi_crc = HdmiCrc.from_buffer(bytearray(result[1])) hdmi_crc = HdmiCrc.from_buffer(bytearray(result[1]))
stream_status.crc = [hdmi_crc.r, hdmi_crc.g, hdmi_crc.b] stream_status.crc = [hdmi_crc.r, hdmi_crc.g, hdmi_crc.b]

View File

@@ -1,7 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import HdmiModeTx, FrlMode, _update_error_counters_tx 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, \ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_HDTX_SINK_STATUS_R, TSI_HDTX_LANES_ERR_COUNTERS_R, TSI_HDTX_HPD_STATUS_R
from ctypes import c_uint32, c_uint64 from ctypes import c_uint32, c_uint64
@@ -19,10 +18,10 @@ class StatusTx:
self.__io = port_io self.__io = port_io
def __read_status(self) -> int: def __read_status(self) -> int:
return self.__io.get(TSI_HDTX_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_STATUS_R, c_uint32)[1]
def __frl_status(self) -> FrlMode: def __frl_status(self) -> FrlMode:
return FrlMode(self.__io.get(TSI_HDTX_FRL_STATUS_R, c_uint32)[1] & 0xF) return FrlMode(self.__io.get(ci.TSI_HDTX_FRL_STATUS_R, c_uint32)[1] & 0xF)
@property @property
def video_status(self) -> bool: def video_status(self) -> bool:
@@ -42,7 +41,7 @@ class StatusTx:
Returns: Returns:
object of list type object of list type
""" """
return _update_error_counters_tx(self.__io.get(TSI_HDTX_LANES_ERR_COUNTERS_R, c_uint64)[1]) return _update_error_counters_tx(self.__io.get(ci.TSI_HDTX_LANES_ERR_COUNTERS_R, c_uint64)[1])
@property @property
def channel_lock(self) -> list: def channel_lock(self) -> list:
@@ -53,9 +52,9 @@ class StatusTx:
object of list type object of list type
""" """
if self.__frl_status().Mode_Disable or self.hdmi_mode in [HdmiModeTx.HDMI_1_4, HdmiModeTx.HDMI_2_0]: 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) return self.__update_channel_lock(self.__io.get(ci.TSI_HDTX_SINK_STATUS_R, c_uint32)[1], self.hdmi_mode)
else: else:
return self.__update_channel_lock(self.__io.get(TSI_HDTX_FRL_STATUS_R, c_uint32)[1], self.hdmi_mode) return self.__update_channel_lock(self.__io.get(ci.TSI_HDTX_FRL_STATUS_R, c_uint32)[1], self.hdmi_mode)
@property @property
def hpd_status(self) -> bool: def hpd_status(self) -> bool:
@@ -65,7 +64,7 @@ class StatusTx:
Returns: Returns:
object of bool type object of bool type
""" """
return (self.__io.get(TSI_HDTX_HPD_STATUS_R, c_uint32)[1] & 0x1) != 0 return (self.__io.get(ci.TSI_HDTX_HPD_STATUS_R, c_uint32)[1] & 0x1) != 0
@property @property
def hdmi_mode(self) -> HdmiModeTx: def hdmi_mode(self) -> HdmiModeTx:
@@ -85,7 +84,7 @@ class StatusTx:
Args: Args:
hdmi_mode (HdmiModeTx) hdmi_mode (HdmiModeTx)
""" """
self.__io.set(TSI_HDTX_CONTROL_W, hdmi_mode.value << 2, c_uint32) self.__io.set(ci.TSI_HDTX_CONTROL_W, hdmi_mode.value << 2, c_uint32)
@property @property
def available_link_rate(self) -> float: def available_link_rate(self) -> float:

View File

@@ -1,6 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import LinkMode from .types import LinkMode
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDRX_LINK_STATUS_R import UniTAP.libs.lib_tsi.tsi_types as ci
from ctypes import c_uint32 from ctypes import c_uint32
@@ -17,7 +17,7 @@ class TmdsRx:
self.__input_stream_lock = False self.__input_stream_lock = False
def __read_link_status(self) -> int: def __read_link_status(self) -> int:
return self.__io.get(TSI_HDRX_LINK_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_HDRX_LINK_STATUS_R, c_uint32)[1]
@property @property
def clock_rate(self) -> int: def clock_rate(self) -> int:
@@ -27,7 +27,7 @@ class TmdsRx:
Returns: Returns:
object of int type object of int type
""" """
return 6 if self.__read_link_status() & 0x2 else 3 return 6 if self.__read_link_status() >> 1 & 0x1 else 3
@property @property
def link_mode(self) -> LinkMode: def link_mode(self) -> LinkMode:
@@ -37,7 +37,7 @@ class TmdsRx:
Returns: Returns:
object of `LinkMode` type object of `LinkMode` type
""" """
self.__link_mode = LinkMode(self.__read_link_status() & 0x8) self.__link_mode = LinkMode(self.__read_link_status() >> 3 & 0x1)
return self.__link_mode return self.__link_mode
@property @property
@@ -48,7 +48,7 @@ class TmdsRx:
Returns: Returns:
object of bool type object of bool type
""" """
self.__input_stream_lock = (self.__read_link_status() & 0x4) != 0 self.__input_stream_lock = (self.__read_link_status() >> 2 & 0x1) != 0
return self.__input_stream_lock return self.__input_stream_lock
def __str__(self): def __str__(self):

View File

@@ -2,8 +2,7 @@ import warnings
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .types import ClockRate, LinkMode, ScramblerState from .types import ClockRate, LinkMode, ScramblerState
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_SINK_FEATURE_W, TSI_HDTX_STATUS_R, TSI_HDTX_SINK_STATUS_R, \ import UniTAP.libs.lib_tsi.tsi_types as ci
TSI_HDTX_CONTROL_W
from ctypes import c_uint32 from ctypes import c_uint32
@@ -21,13 +20,13 @@ class TmdsTx:
self.__scrambler = ScramblerState.Unknown self.__scrambler = ScramblerState.Unknown
def __read_sink_status(self) -> int: def __read_sink_status(self) -> int:
return self.__io.get(TSI_HDTX_SINK_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_SINK_STATUS_R, c_uint32)[1]
def __read_hdtx_status(self) -> int: def __read_hdtx_status(self) -> int:
return self.__io.get(TSI_HDTX_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_HDTX_STATUS_R, c_uint32)[1]
def __write_sink_feature(self, value: int): def __write_sink_feature(self, value: int):
self.__io.set(TSI_HDTX_SINK_FEATURE_W, value, c_uint32) self.__io.set(ci.TSI_HDTX_SINK_FEATURE_W, value, c_uint32)
@property @property
def clock_rate(self) -> int: def clock_rate(self) -> int:
@@ -71,7 +70,7 @@ class TmdsTx:
Args: Args:
link_mode (LinkMode) link_mode (LinkMode)
""" """
self.__io.set(TSI_HDTX_CONTROL_W, link_mode.value, c_uint32) self.__io.set(ci.TSI_HDTX_CONTROL_W, link_mode.value, c_uint32)
@property @property
def scrambler(self) -> bool: def scrambler(self) -> bool:

View File

@@ -0,0 +1 @@
from .packet_generator import PacketGenerator

View File

@@ -0,0 +1,92 @@
from ctypes import c_byte
from typing import Union, List, Optional
from UniTAP.libs.lib_tsi import ci, p_ci
from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.dev.modules import MemoryManager
class PacketGenerator:
class Status:
def __init__(self, value: int):
self.enabled = bool(value & 0x1)
self.active = bool(value & 0x2)
self.error = bool(value & 0x4)
self.overflow = bool(value & 0x8)
def __str__(self):
return f"Packet Generator Status: Enabled: {self.enabled}; Active: {self.active}; Error: {self.error}; Overflow: {self.overflow};"
"""
Main class `PacketGenerator` allows working with PG functionality on the device: set different types of pattern
`set_pattern`, set different video modes `set_vm`, set additional parameters for some patterns `set_pattern_params`,
get information about current video mode on stream `get_stream_video_mode`, `apply` all transferred setting,
`reset` settings and read pattern generator `status`.
"""
def __init__(self, port_io: PortIO, memory_manager: MemoryManager):
self.__io = port_io
self.__memory_manager = memory_manager
self.__packets = []
def reset(self):
"""
Reset static packet generator settings to default values.
"""
self.stop()
self.__packets = []
def start(self):
"""
Start packet generator with current settings.
"""
self.stop()
self.__upload_data()
if self.__io.set(ci.TSI_PACKETGEN_CONTROL_W, 1) < ci.TSI_SUCCESS:
raise Exception("Failed to start packet generator")
def stop(self):
"""
Stop packet generator.
"""
self.__io.set(ci.TSI_PACKETGEN_CONTROL_W, 2)
def status(self) -> Status:
"""
Get current status of packet generator.
Returns:
Status - current status of packet generator
"""
return PacketGenerator.Status(self.__io.get(ci.TSI_PACKETGEN_STATUS_R)[1])
def add_packet(self, raw_packet_data: bytearray):
self.__packets.append(raw_packet_data)
def load_packet(self, file_path: str):
with open(file_path, "rb") as f:
packet_data = f.read()
self.__packets.append(bytearray(packet_data))
def __upload_data(self):
mem_layout = self.__memory_manager.get_memory_layout()
if len(mem_layout) <= MemoryManager.MemoryOwner.MO_Events.value or mem_layout[MemoryManager.MemoryOwner.MO_Events.value] == 0:
self.__memory_manager.make_default()
if self.__io.set(ci.TSI_PACKETGEN_PACKETS_NUMBER, len(self.__packets)) < ci.TSI_SUCCESS:
raise Exception("Failed to set packets number for packet generator")
for index, packet in enumerate(self.__packets):
if self.__io.set(ci.TSI_PACKETGEN_PACKET_DATA, packet, data_type=c_byte, data_count=len(packet)) < ci.TSI_SUCCESS:
raise Exception(f"Failed to set packet data for packet {index} in packet generator")
if self.__io.set(ci.TSI_PACKETGEN_MEM_BLOCK, int(MemoryManager.MemoryOwner.MO_Events)) < ci.TSI_SUCCESS:
raise Exception("Failed to set memory block for packet generator")

View File

@@ -1,5 +1,6 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi_types as ci
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from .pr_private_types import * from .pr_private_types import *
from .pr_status import PanelReplayStatus from .pr_status import PanelReplayStatus
from .pr_config import PanelReplayConfig from .pr_config import PanelReplayConfig
@@ -68,6 +69,6 @@ class PanelReplay:
self.__write_pr_control(PrControl.EnableSelectiveUpdate) self.__write_pr_control(PrControl.EnableSelectiveUpdate)
def __write_pr_control(self, command: PrControl): def __write_pr_control(self, command: PrControl):
self.__io.set(TSI_PG_STREAM_SELECT, 0) self.__io.set(ci.TSI_PG_STREAM_SELECT, 0)
self.__io.set(TSI_PG_PR_CTRL_W, command.value) self.__io.set(p_ci.TSI_PG_PR_CTRL_W, command.value)

View File

@@ -1,5 +1,7 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi as tsi
import UniTAP.libs.lib_tsi.tsi_types as ci
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
from .pr_types import * from .pr_types import *
from .pr_private_types import * from .pr_private_types import *
@@ -35,7 +37,7 @@ class PanelReplayConfig:
""" """
caps = self.pr_caps caps = self.pr_caps
self.__io.set(TSI_PG_STREAM_SELECT, 0) self.__io.set(ci.TSI_PG_STREAM_SELECT, 0)
pr_config, _ = self.__read_config() pr_config, _ = self.__read_config()
pr_config.early_transport = config.flags.early_transport if caps.pr_flags().early_transport else 0 pr_config.early_transport = config.flags.early_transport if caps.pr_flags().early_transport else 0
@@ -60,7 +62,7 @@ class PanelReplayConfig:
region = RegionConfig(0) region = RegionConfig(0)
region.value = item region.value = item
data.extend(region.value) data.extend(region.value)
self.__io.set(TSI_PG_PR_CFG, data, data_count=len(data)) self.__io.set(p_ci.TSI_PG_PR_CFG, data, data_count=len(data))
def get(self) -> PrSettings: def get(self) -> PrSettings:
""" """
@@ -114,8 +116,8 @@ class PanelReplayConfig:
def __read_config(self): def __read_config(self):
caps = self.pr_caps caps = self.pr_caps
self.__io.set(TSI_PG_STREAM_SELECT, 0) self.__io.set(ci.TSI_PG_STREAM_SELECT, 0)
result = self.__io.get(TSI_PG_PR_CFG, c_uint32, caps.calculate_size())[1] result = self.__io.get(p_ci.TSI_PG_PR_CFG, c_uint32, caps.calculate_size())[1]
if not isinstance(result, list): if not isinstance(result, list):
result = [0] result = [0]
pr_config = PrConfig(result[0]) pr_config = PrConfig(result[0])
@@ -128,5 +130,5 @@ class PanelReplayConfig:
return pr_config, pr_regions return pr_config, pr_regions
def __read_caps(self) -> PRCaps: def __read_caps(self) -> PRCaps:
self.__io.set(TSI_PG_STREAM_SELECT, 0) self.__io.set(ci.TSI_PG_STREAM_SELECT, 0)
return self.__io.get(TSI_PG_PR_CAPS_R, PRCaps)[1] return self.__io.get(p_ci.TSI_PG_PR_CAPS_R, PRCaps)[1]

View File

@@ -1,7 +1,9 @@
from ctypes import c_int, c_uint32
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .pr_sink_private_types import SinkPanelReplayCapsStruct, SinkPanelSelfRefreshCapsStruct from .pr_sink_private_types import SinkPanelReplayCapsStruct, SinkPanelSelfRefreshCapsStruct
from .pr_sink_types import PRCapsFlags, PrGranularityCaps, SuYGranularity, PSRCapsFlags, PSRCaps, PSRSetupTime from .pr_sink_types import PRCapsFlags, PrGranularityCaps, SuYGranularity, PSRCapsFlags, PSRCaps, PSRSetupTime
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi_types as ci
from typing import Tuple from typing import Tuple
@@ -27,7 +29,7 @@ class SinkPanelReplayCaps:
(flags.y_gran_extended_supported << 14) | (flags.link_off_supported << 15)) (flags.y_gran_extended_supported << 14) | (flags.link_off_supported << 15))
self.__write([flags_value, x_granularity.value, y_granularity.value, granularity.combined_value()]) self.__write([flags_value, x_granularity.value, y_granularity.value, granularity.combined_value()])
self.__io.set(TSI_DPRX_HPD_PULSE_W, 500000, c_int) self.__io.set(ci.TSI_DPRX_HPD_PULSE_W, 500000, c_int)
def get(self) -> Tuple[PRCapsFlags, PrGranularityCaps, PrGranularityCaps, SuYGranularity]: def get(self) -> Tuple[PRCapsFlags, PrGranularityCaps, PrGranularityCaps, SuYGranularity]:
caps = self.__read() caps = self.__read()
@@ -65,10 +67,10 @@ class SinkPanelReplayCaps:
return flags, x_granularity, y_granularity, granularity return flags, x_granularity, y_granularity, granularity
def __read(self) -> SinkPanelReplayCapsStruct: def __read(self) -> SinkPanelReplayCapsStruct:
return self.__io.get(TSI_DPRX_PR_CAPS, SinkPanelReplayCapsStruct)[1] return self.__io.get(ci.TSI_DPRX_PR_CAPS, SinkPanelReplayCapsStruct)[1]
def __write(self, data: list): def __write(self, data: list):
self.__io.set(TSI_DPRX_PR_CAPS, data, data_type=c_uint32, data_count=len(data)) self.__io.set(ci.TSI_DPRX_PR_CAPS, data, data_type=c_uint32, data_count=len(data))
class SinkPanelSelfRefreshCaps: class SinkPanelSelfRefreshCaps:
@@ -105,7 +107,7 @@ class SinkPanelSelfRefreshCaps:
return flags, x_granularity, y_granularity return flags, x_granularity, y_granularity
def __read(self) -> SinkPanelSelfRefreshCapsStruct: def __read(self) -> SinkPanelSelfRefreshCapsStruct:
return self.__io.get(TSI_DPRX_PSR_CAPS, SinkPanelSelfRefreshCapsStruct)[1] return self.__io.get(ci.TSI_DPRX_PSR_CAPS, SinkPanelSelfRefreshCapsStruct)[1]
def __write(self, data: list): def __write(self, data: list):
self.__io.set(TSI_DPRX_PSR_CAPS, data, data_type=c_uint32, data_count=len(data)) self.__io.set(ci.TSI_DPRX_PSR_CAPS, data, data_type=c_uint32, data_count=len(data))

View File

@@ -1,7 +1,8 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_types as ci
from .pr_sink_private_types import SinkPanelSelfRefreshStatusStruct, SinkPanelReplayStatusStruct from .pr_sink_private_types import SinkPanelSelfRefreshStatusStruct, SinkPanelReplayStatusStruct
from .pr_sink_types import (SinkPRStatusFlags, SelfStatus, FrameStatus, SinkPSRStatusFlags, PRSSelfRefreshStatus) from .pr_sink_types import (SinkPRStatusFlags, SelfStatus, FrameStatus, SinkPSRStatusFlags, PRSSelfRefreshStatus)
from UniTAP.libs.lib_tsi.tsi import * import UniTAP.libs.lib_tsi.tsi as tsi
class SinkPanelReplayStatus: class SinkPanelReplayStatus:
@@ -31,7 +32,7 @@ class SinkPanelReplayStatus:
def __read(self) -> SinkPanelReplayStatusStruct: def __read(self) -> SinkPanelReplayStatusStruct:
return self.__io.get(TSI_DPRX_PR_STATUS, SinkPanelReplayStatusStruct)[1] return self.__io.get(ci.TSI_DPRX_PR_STATUS, SinkPanelReplayStatusStruct)[1]
class SinkPanelSelfRefreshStatus: class SinkPanelSelfRefreshStatus:
@@ -59,4 +60,4 @@ class SinkPanelSelfRefreshStatus:
self_refresh=PRSSelfRefreshStatus(pr_flags.self_refresh)) self_refresh=PRSSelfRefreshStatus(pr_flags.self_refresh))
def __read(self) -> SinkPanelSelfRefreshStatusStruct: def __read(self) -> SinkPanelSelfRefreshStatusStruct:
return self.__io.get(TSI_DPRX_PSR_STATUS, SinkPanelSelfRefreshStatusStruct)[1] return self.__io.get(ci.TSI_DPRX_PSR_STATUS, SinkPanelSelfRefreshStatusStruct)[1]

View File

@@ -1,6 +1,7 @@
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
import UniTAP.libs.lib_tsi.tsi_types as ci
from .pr_private_types import * from .pr_private_types import *
from UniTAP.libs.lib_tsi.tsi import *
from .pr_types import * from .pr_types import *
@@ -43,6 +44,6 @@ class PanelReplayStatus:
return PRError(self.__read().error) return PRError(self.__read().error)
def __read(self) -> PrStatus: def __read(self) -> PrStatus:
self.__io.set(TSI_PG_STREAM_SELECT, 0) self.__io.set(ci.TSI_PG_STREAM_SELECT, 0)
return self.__io.get(TSI_PG_PR_STATUS_R, PrStatus)[1] return self.__io.get(p_ci.TSI_PG_PR_STATUS_R, PrStatus)[1]

View File

@@ -237,6 +237,12 @@ class PdcControls500(PdcControlsBase):
super().__init__(pdc_io) super().__init__(pdc_io)
self.__io = pdc_io self.__io = pdc_io
def reset(self):
"""
Reset device.
"""
self.__io.write_hw_command(HWControlCommand.ResetPDController)
def reconnect(self) -> bool: def reconnect(self) -> bool:
""" """
Reconnect device. Reconnect device.

View File

@@ -1,5 +1,8 @@
from ctypes import c_uint32
from UniTAP.libs.lib_tsi.tsi_io import PortIO from UniTAP.libs.lib_tsi.tsi_io import PortIO
from UniTAP.libs.lib_tsi.tsi_private_types import * import UniTAP.libs.lib_tsi.tsi_private_types as p_ci
import UniTAP.libs.lib_tsi.tsi_types as ci
from .pdc_private_dpam_types import DPAMCaps, DPAMState, DPAMCommand, DPAMConfig, DPAMDiscModes, DPAMRecv from .pdc_private_dpam_types import DPAMCaps, DPAMState, DPAMCommand, DPAMConfig, DPAMDiscModes, DPAMRecv
from .pdc_private_types import HWControlCommand, HWStatus, HWCaps, PDCStatus, PDCControlCommand, PDCState, PDCCaps, \ from .pdc_private_types import HWControlCommand, HWStatus, HWCaps, PDCStatus, PDCControlCommand, PDCState, PDCCaps, \
PDCContractInfo PDCContractInfo
@@ -13,103 +16,103 @@ class PDCPortIO:
self.write_adc_control() self.write_adc_control()
def write_dpam_caps(self, caps: DPAMCaps): def write_dpam_caps(self, caps: DPAMCaps):
self.__io.set(TSI_PDC_DPAM_CAPS, caps.value(), c_uint32) self.__io.set(ci.TSI_PDC_DPAM_CAPS, caps.value(), c_uint32)
def read_dpam_caps(self) -> DPAMCaps: def read_dpam_caps(self) -> DPAMCaps:
return self.__io.get(TSI_PDC_DPAM_CAPS, DPAMCaps)[1] return self.__io.get(ci.TSI_PDC_DPAM_CAPS, DPAMCaps)[1]
def read_dpam_caps2(self) -> bool: def read_dpam_caps2(self) -> bool:
return (self.__io.get(TSI_PDC_DPAM_CAPS2, c_uint32)[1] & 0x1) != 0 return (self.__io.get(ci.TSI_PDC_DPAM_CAPS2, c_uint32)[1] & 0x1) != 0
def read_dpam_state(self) -> DPAMState: def read_dpam_state(self) -> DPAMState:
return self.__io.get(TSI_PDC_DPAM_STATE_R, DPAMState)[1] return self.__io.get(ci.TSI_PDC_DPAM_STATE_R, DPAMState)[1]
def write_dpam_control(self, command: DPAMCommand): def write_dpam_control(self, command: DPAMCommand):
self.__io.set(TSI_PDC_DPAM_CONTROL_W, command.value, c_uint32) self.__io.set(ci.TSI_PDC_DPAM_CONTROL_W, command.value, c_uint32)
def read_dpam_config(self) -> DPAMConfig: def read_dpam_config(self) -> DPAMConfig:
return self.__io.get(TSI_PDC_DPAM_CONFIG_R, DPAMConfig)[1] return self.__io.get(p_ci.TSI_PDC_DPAM_CONFIG_R, DPAMConfig)[1]
def read_dpam_disc_modes(self) -> DPAMDiscModes: def read_dpam_disc_modes(self) -> DPAMDiscModes:
return self.__io.get(TSI_PDC_DPAM_DISC_MODES_R, DPAMDiscModes)[1] return self.__io.get(ci.TSI_PDC_DPAM_DISC_MODES_R, DPAMDiscModes)[1]
def read_dpam_recv(self) -> DPAMRecv: def read_dpam_recv(self) -> DPAMRecv:
return self.__io.get(TSI_PDC_DPAM_RECV_STS_R, DPAMRecv)[1] return self.__io.get(ci.TSI_PDC_DPAM_RECV_STS_R, DPAMRecv)[1]
def write_hw_command(self, command: HWControlCommand): def write_hw_command(self, command: HWControlCommand):
self.__io.set(TSI_PDC_HW_CONTROL_W, command.value, c_uint32) self.__io.set(ci.TSI_PDC_HW_CONTROL_W, command.value, c_uint32)
def read_hw_status(self) -> HWStatus: def read_hw_status(self) -> HWStatus:
return self.__io.get(TSI_PDC_HW_STATUS_R, HWStatus)[1] return self.__io.get(ci.TSI_PDC_HW_STATUS_R, HWStatus)[1]
def read_hw_caps(self) -> HWCaps: def read_hw_caps(self) -> HWCaps:
return self.__io.get(TSI_PDC_HW_CAPS_R, HWCaps)[1] return self.__io.get(p_ci.TSI_PDC_HW_CAPS_R, HWCaps)[1]
def read_pdc_status(self) -> PDCStatus: def read_pdc_status(self) -> PDCStatus:
return self.__io.get(TSI_PDC_STATUS_R, PDCStatus)[1] return self.__io.get(ci.TSI_PDC_STATUS_R, PDCStatus)[1]
def write_pdc_command(self, command: PDCControlCommand): def write_pdc_command(self, command: PDCControlCommand):
self.__io.set(TSI_PDC_CONTROL, command.value, c_uint32) self.__io.set(ci.TSI_PDC_CONTROL, command.value, c_uint32)
def read_pdc_state(self) -> PDCState: def read_pdc_state(self) -> PDCState:
return self.__io.get(TSI_PDC_STATE, PDCState)[1] return self.__io.get(ci.TSI_PDC_STATE, PDCState)[1]
def read_pdc_caps(self) -> PDCCaps: def read_pdc_caps(self) -> PDCCaps:
return self.__io.get(TSI_PDC_CAPS, PDCCaps)[1] return self.__io.get(ci.TSI_PDC_CAPS, PDCCaps)[1]
def write_pdc_contract_control(self, caps: PDCContractInfo): def write_pdc_contract_control(self, caps: PDCContractInfo):
self.__io.set(TSI_USBC_PWR_CONTRACT_CONTROL, caps.value(), c_uint32) self.__io.set(ci.TSI_USBC_PWR_CONTRACT_CONTROL, caps.value(), c_uint32)
def read_pdc_contract_control(self) -> PDCContractInfo: def read_pdc_contract_control(self) -> PDCContractInfo:
return self.__io.get(TSI_USBC_PWR_CONTRACT_CONTROL, PDCContractInfo)[1] return self.__io.get(ci.TSI_USBC_PWR_CONTRACT_CONTROL, PDCContractInfo)[1]
def read_local_spr_source_pdo(self) -> list: def read_local_spr_source_pdo(self) -> list:
return self.__io.get(TSI_USBC_PWR_LOCAL_SOURCE_PDO, PdoUnion, self.read_hw_caps().pdo_count)[1] return self.__io.get(ci.TSI_USBC_PWR_LOCAL_SOURCE_PDO, PdoUnion, self.read_hw_caps().pdo_count)[1]
def write_local_spr_source_pdo(self, data: list): def write_local_spr_source_pdo(self, data: list):
self.__io.set(TSI_USBC_PWR_LOCAL_SOURCE_PDO, data, c_uint32, len(data)) self.__io.set(ci.TSI_USBC_PWR_LOCAL_SOURCE_PDO, data, c_uint32, len(data))
def read_local_spr_sink_pdo(self) -> list: def read_local_spr_sink_pdo(self) -> list:
return self.__io.get(TSI_USBC_PWR_LOCAL_SINK_PDO, PdoUnion, self.read_hw_caps().pdo_count)[1] return self.__io.get(ci.TSI_USBC_PWR_LOCAL_SINK_PDO, PdoUnion, self.read_hw_caps().pdo_count)[1]
def write_local_spr_sink_pdo(self, data: list): def write_local_spr_sink_pdo(self, data: list):
self.__io.set(TSI_USBC_PWR_LOCAL_SINK_PDO, data, c_uint32, len(data)) self.__io.set(ci.TSI_USBC_PWR_LOCAL_SINK_PDO, data, c_uint32, len(data))
def read_tx_id_vdo_count(self) -> int: def read_tx_id_vdo_count(self) -> int:
return self.__io.get(TSI_PDC_TX_ID_VDO_CNT, c_uint32)[1] return self.__io.get(p_ci.TSI_PDC_TX_ID_VDO_CNT, c_uint32)[1]
def read_tx_id_vdo(self) -> list: def read_tx_id_vdo(self) -> list:
return self.__io.get(TSI_PDC_TX_ID_VDO, c_uint32, self.read_tx_id_vdo_count())[1] return self.__io.get(p_ci.TSI_PDC_TX_ID_VDO, c_uint32, self.read_tx_id_vdo_count())[1]
def write_tx_id_vdo(self, data: list): def write_tx_id_vdo(self, data: list):
self.__io.set(TSI_PDC_TX_ID_VDO, data, c_uint32, len(data)) self.__io.set(p_ci.TSI_PDC_TX_ID_VDO, data, c_uint32, len(data))
def read_contract_data(self) -> list: def read_contract_data(self) -> list:
return self.__io.get(TSI_PDC_CONTRACT_DATA, c_uint32, 4)[1] return self.__io.get(p_ci.TSI_PDC_CONTRACT_DATA, c_uint32, 4)[1]
def write_contract_data(self, data: list): def write_contract_data(self, data: list):
self.__io.set(TSI_PDC_CONTRACT_DATA, data, c_uint32, len(data)) self.__io.set(p_ci.TSI_PDC_CONTRACT_DATA, data, c_uint32, len(data))
def read_power_contract_select(self) -> int: def read_power_contract_select(self) -> int:
return self.__io.get(TSI_USBC_PWR_CONTRACT_SELECT, c_uint32)[1] return self.__io.get(ci.TSI_USBC_PWR_CONTRACT_SELECT, c_uint32)[1]
def write_power_contract_select(self, index: int): def write_power_contract_select(self, index: int):
self.__io.set(TSI_USBC_PWR_CONTRACT_SELECT, index, c_uint32) self.__io.set(ci.TSI_USBC_PWR_CONTRACT_SELECT, index, c_uint32)
def read_resistance(self) -> int: def read_resistance(self) -> int:
return self.__io.get(TSI_USBC_RESISTANCE_CONTROL, c_uint32)[1] return self.__io.get(ci.TSI_USBC_RESISTANCE_CONTROL, c_uint32)[1]
def write_resistance(self, resistance: int): def write_resistance(self, resistance: int):
self.__io.set(TSI_USBC_RESISTANCE_CONTROL, resistance, c_uint32) self.__io.set(ci.TSI_USBC_RESISTANCE_CONTROL, resistance, c_uint32)
def read_adc_vbus_status(self) -> list: def read_adc_vbus_status(self) -> list:
return self.__io.get(TSI_ADC_VBUS_VOLTAGE_R, c_uint32, TSI_ADC_BLOCK_SIZE_WORDS)[1] return self.__io.get(ci.TSI_ADC_VBUS_VOLTAGE_R, c_uint32, ci.TSI_ADC_BLOCK_SIZE_WORDS)[1]
def read_internal_resistance(self) -> int: def read_internal_resistance(self) -> int:
return self.__io.get(TSI_USBC_INT_RESISTANCE_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_USBC_INT_RESISTANCE_STATUS_R, c_uint32)[1]
def read_external_resistance(self) -> int: def read_external_resistance(self) -> int:
return self.__io.get(TSI_USBC_EXT_RESISTANCE_STATUS_R, c_uint32)[1] return self.__io.get(ci.TSI_USBC_EXT_RESISTANCE_STATUS_R, c_uint32)[1]
def write_adc_control(self): def write_adc_control(self):
self.__io.set(TSI_W_USBC_ADC_CTRL, 1, c_uint32) self.__io.set(ci.TSI_W_USBC_ADC_CTRL, 1, c_uint32)

Some files were not shown because too many files have changed in this diff Show More