1.1.0版本

This commit is contained in:
xinzhu.yin
2026-04-16 16:51:05 +08:00
commit c157e774e5
333 changed files with 70759 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
from .report_maker import generate_html_report, TestAdditionalInfo, TestResult
from .report_utils import update_configuration, dp21_source_timing_table, detect_warning_message

View File

@@ -0,0 +1,179 @@
import platform
from datetime import datetime
from enum import IntEnum
from .report_template import *
class TestResult(IntEnum):
Unknown = -1
Passed = 0
Failed = 1
Skipped = 2
Aborted = 3
class TestAdditionalInfo:
def __init__(self, dut_model_name: str = "", dut_revision: str = "", dut_serial_number: str = "",
dut_firmware_version: str = "", dut_driver_version: str = "", tested_by: str = "", remarks: str = ""):
self.device_name = str()
self.device_serial_number = str()
self.device_detailed_data = str()
self.device_frontend_version = str()
self.memory_size = str()
self.python_version = platform.python_version()
self.bundle_version = str()
self.dut_model_name = dut_model_name
self.dut_revision = dut_revision
self.dut_serial_number = dut_serial_number
self.dut_firmware_version = dut_firmware_version
self.dut_driver_version = dut_driver_version
self.tested_by = tested_by
self.remarks = remarks
def write_to_file(file_name, text: str):
with open(file_name, 'w', encoding='UTF-8') as file:
file.write(text)
def replace_additional_info(test_additional_info: TestAdditionalInfo):
result = DeviceDescription
result = result.replace("#device_name#", test_additional_info.device_name)
result = result.replace("#detailed_vdata#", test_additional_info.device_detailed_data)
result = result.replace("#frontend_version#", test_additional_info.device_frontend_version)
result = result.replace("#memory_size#", test_additional_info.memory_size)
result = result.replace("#console_app_version#", test_additional_info.python_version)
result = result.replace("#console_bundle_version#", test_additional_info.bundle_version)
result = result.replace("#date_time#", datetime.now().strftime("%d-%m-%Y %H:%M"))
result = result.replace("#model_name#", test_additional_info.dut_model_name)
result = result.replace("#revision#", test_additional_info.dut_revision)
result = result.replace("#serial_number#", test_additional_info.dut_serial_number)
result = result.replace("#firmware_version#", test_additional_info.dut_firmware_version)
result = result.replace("#driver_version#", test_additional_info.dut_driver_version)
result = result.replace("#conducted_by#", test_additional_info.tested_by)
result = result.replace("#remarks#", test_additional_info.remarks)
return result
def generate_html_report(path: str, test_additional_info: TestAdditionalInfo, reports: list):
result = str()
head = ReportHead
head = head.replace("#count#", str((len(reports) + 2)))
body = ReportBody
body = body.replace("#device_description#", replace_additional_info(test_additional_info))
runs = 0
failed = 0
skipped = 0
aborted = 0
dict_result_2 = {TestResult.Failed: "FAILED",
TestResult.Skipped: "SKIPPED",
TestResult.Aborted: "ABORTED",
TestResult.Passed: "PASSED"}
json_config_info = '[' + ",".join(f'"{report.json_config_info}"' for report in reports) + ']'
for item in reports:
runs += 1
if item.test_result == TestResult.Failed:
failed += 1
elif item.test_result == TestResult.Skipped:
skipped += 1
elif item.test_result == TestResult.Aborted:
aborted += 1
head = head.replace("#configInfo#", json_config_info)
result += head
passed = runs - failed - skipped - aborted
body = body.replace("#runs#", str(runs))
body = body.replace("#passed#", str(passed))
body = body.replace("#failed#", str(failed))
body = body.replace("#skipped#", str(skipped))
body = body.replace("#aborted#", str(aborted))
options_list = ""
for i in range(len(reports)):
line = OptionListLine
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_result#", dict_result_2.get(reports[i].test_result))
options_list += line + "\n"
body = body.replace("#optionList#", options_list)
tables = Tables
table_lines = ""
for i in range(len(reports)):
line = TestDescriptionLine
line = line.replace("#handler_number#", str(i + 2))
line = line.replace("#test_name#", reports[i].test_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("#error#", f"{reports[i].error_code}" if reports[i].error_code != 0 else "-")
line = line.replace("#ending#", "2" if i % 2 else "")
test_result = dict_result_2.get(reports[i].test_result)
line = line.replace("#SUCCESS#", test_result if test_result is not None else "PASSED")
table_lines += line + "\n"
tables = tables.replace("#test_description_lines#", table_lines)
def escape_html(log: str) -> str:
res = []
for c in log:
if c == '&':
res.append("&")
elif c == '<':
res.append("&lt;")
elif c == '>':
res.append("&gt;")
elif c == '"':
res.append("&quot;")
elif c == '\'':
res.append("&apos;")
else:
res.append(c)
return ''.join(res)
tables_list = ""
warnings = ""
for i in range(len(reports)):
line = TestTable
line = line.replace("#number#", f"{i + 2}")
line = line.replace("#test_number#", f"{i + 1}")
line = line.replace("#test_group#", reports[i].group_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("#test_delay#", f"{reports[i].test_delay * 1000}")
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:
warnings = "<b>Debug options enabled!</b><br><br>"
line = line.replace("#test_log#", escape_html(reports[i].fw_logs))
tables_list += line + "\n"
body = body.replace("#warning#", warnings)
tables = tables.replace("#test_tables_list#", tables_list)
tables = tables.replace("#warning#", warnings)
result += body
result += tables
footer = ReportFooter
footer = footer.replace("#result#", "PASSED" if failed == 0 else "FAILED")
result += footer
full_name = path if path.lower().find(".html") != -1 else (path + ".html")
write_to_file(full_name, result)

View File

@@ -0,0 +1,153 @@
ReportHead = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" \
"<html><head><title>Unigraf Test Report</title>\n" \
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Windows-1252\">\n" \
"<style>\n" \
"html {scroll-behavior: smooth;}\n" \
" TABLE.DOCUMENT{width: 100%;}\n" \
" P.CONTENTS{font-weight: bold;font-family: \"Arial\";font-size: 11pt;margin-left: 0.3cm;margin-top: 10;margin-bottom: 0.3cm;color: #000000;}\n" \
" P.HEADING{background-color: #BBC3FF;margin-top: 0;margin-bottom: 0.5cm;margin-left: 0cm;font-weight: bold;font-family: \"Arial\";font-size: 16pt;color: #000000;}\n" \
" P.SUBHEADING{background-color: #BBC3FF;margin-top: 1.25cm;margin-bottom: 0.5cm;margin-left: 0.5cm;margin-right: 0;font-weight: bold;font-family: \"Arial\";font-size: 12pt;color: #000000;text-transform: uppercase;}\n" \
" P.GREENSUBHEADING{background-color: #DCFABC;margin-top: 0.5cm;margin-bottom: 0.5cm;margin-left: 0.6cm; margin-right: 0; font-weight: bold;font-family: \"Arial\";font-size: 12pt;color: #000000;}\n" \
" P.BODYTEXT{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 11pt;color: #000000;}\n" \
" P.BODYWARNINGS{margin-top: 0;margin-bottom: 0;margin-left: 1.0cm;font-weight: medium;font-family: \"Arial\";font-size: 14pt;color: #ff0000;}\n" \
" P.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.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: " \
"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_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.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.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" \
"</style>\n" \
"<script type=\"text/javascript\">\n" \
"var base64Content = #configInfo#;\n"\
"window.current_index = 2;\n" \
"window.min_value = 2;\n" \
"window.max_value = #count# - 1;\n" \
"window.onscroll = function() {scrollFunction()};\n" \
"function Hide(iElementIndex) { document.getElementById(\"ID\"+iElementIndex).style.display = 'none'; }\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 ShowAll(iDivCount) { for(var i=0;i<iDivCount;i++) { Show(i); }}\n" \
"function SetIndex(value) { window.current_index = value; }\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 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 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 PreviousTest() { var index = GetIndex(); ListHandler ((index - 1 < window.min_value) ? (window.max_value) : (index - 1)); }\n" \
"function scrollFunction() { let topButton = document.getElementById('topBtn'); if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {topButton.style.display = 'block';} else {topButton.style.display = 'none';} }\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 getText() { var index = GetIndex(); let a = document.getElementById(\"testlist\"); let option = a.options[index]; return option.text.replace('/', '').replace('>', '').replace(':', '') }\n"\
"</script>\n" \
"</head>\n"
OptionListLine = " <option value=\"#number#\"> #test_name# (#test_result#)</option>\n"
TestDescriptionLine = ("<tr><td><p class=\"TABLE_LINKS#ending#\"><a href=\"javascript:ListHandler(#handler_number#)\">"
"#test_group# / #test_name#</a></p></td><td align=\"center\"><p class=\"#SUCCESS#\">"
"&nbsp;#test_result#&nbsp;</p></td><td align=\"center\"><p class=\"ERROR_CODE\">&nbsp;#error#&nbsp;</p></td></tr>\n")
Tables = "<div id=\"ID1\">\n" \
"<p class=\"BODYTEXT\">\n" \
"<p class=\"SUBHEADING\" style=\"margin-left: 0; margin-top: " \
"0;\">&nbsp;&nbsp;&nbsp;Summary of individual test runs</p>\n" \
"<p class=\"BODYWARNINGS\">\n#warning#</p>\n" \
"<table width=\"80%\"><colgroup><col span=\"1\" style=\"width: 85%;\"><col span=\"1\" style=\"width: 10%;\"><col span=\"1\" style=\"width: 5%;\"></colgroup>\n" \
"<tr><th><p class=\"TABLE_HEADERS\">Test name</p></th><th><p class=\"TABLE_HEADERS\" style=\"margin-left: 0;\">Result</p></th><th><p class=\"TABLE_HEADERS\" style=\"margin-left: 0;\">Error</p></th></tr>\n" \
"#test_description_lines#\n" \
"</table>\n" \
"#test_tables_list#\n"
DeviceDescription = "<p class=\"BODYTEXT\">\n" \
"Device: #device_name#\n" \
"<br>Firmware Package: #detailed_vdata#\n" \
"<br>UniTAP: #console_app_version#\n" \
"<br>Software Bundle: #console_bundle_version#\n" \
"<br>Frontend Info: #frontend_version#\n" \
"<br>Device total memory size: #memory_size#\n" \
"<br><br>Report generated: #date_time#<br>\n" \
"</p></p><p class=\"GREENSUBHEADING\">&nbsp;&nbsp;&nbsp;DUT<p class=\"BODYTEXT\">\n" \
"Device/Model name: #model_name#\n" \
"<br>HW Revision: #revision#\n" \
"<br>Serial number: #serial_number#\n" \
"<br>Firmware: #firmware_version#\n" \
"<br>Driver: #driver_version#\n" \
"<br><br>Testing conducted by: #conducted_by#\n" \
"<br><br>Remarks: #remarks#\n" \
"<p class=\"BODYDETAILTEXT\">\n"
TestTable = "<br><br></p></div><div id=\"ID#number#\">\n" \
"<p class=\"SUBHEADING\" style=\"margin-left: 0; margin-top: 0;\">&nbsp;&nbsp;&nbsp;Test Details, Test #test_number#</p>\n" \
"<p class=\"GREENSUBHEADING\">&nbsp;&nbsp;&nbsp;#test_name#</p>\n" \
"<p class=\"BODYWARNINGS\">\n" \
"#warning#</p>\n" \
"<p class=\"BODYTEXT\">\n" \
"Test Set: <b>#test_group#</b><br>\n" \
"Test Result: <b>#result#</b>\n" \
"<br><br><b>Test Settings:</b></p>\n" \
"<p class=\"BODYTEXT\">\n" \
"Delay between tests = #test_delay#ms\n<br>" \
"#test_parameters#\n" \
"</p><p class=\"GREENSUBHEADING\">&nbsp;&nbsp;&nbsp;Test Log</p><pre class=\"TESTBODY\">" \
"#test_log#" \
"\n"
ReportBody = "<body onload='ListHandler(0);'>\n" \
" <button class=\"TOPBUTTON\" onclick=\"TopFunction()\" id=\"topBtn\" title=\"Go to top\">&#8593;</button>\n" \
" <div><p class=\"HEADING\" id=\"top\">&nbsp;&nbsp;Unigraf Test Report</p></div>\n" \
" <div>\n" \
" <table class=\"DOCUMENT\" cellpadding=\"0\" cellspacing=\"0\">\n" \
" <colgroup>\n" \
" <col width=\"200\">\n" \
" <col width=\"*\">\n" \
" </colgroup>\n" \
" <td><p class=\"CONTENTS\">Select item to display</p></td> \n" \
" <td><select id=\"testlist\" onchange=\"ListHandler (document.getElementById ('testlist').value)\" onkeyup=\"ListHandler (document.getElementById ('testlist').value)\"></span>\n" \
" <option value=\"0\">Report Summary</option>\n" \
" <option value=\"1\">Test Summary</option>\n" \
"#optionList#\n" \
" <option value=\"-1\">Show everything</option>\n" \
" </select>\n" \
" </td>\n" \
" </table>\n" \
"<div id=\"top_buttons\" style='margin-left: 12'>\n" \
"<button type=\"button\" onclick=\"PreviousTest()\">Previous</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=\"NextTest()\">Next</button>\n" \
"<br>\n" \
"</div>\n" \
"<br>\n" \
"<div id=\"ID0\">\n" \
"<p class=\"SUBHEADING\" style=\"margin-left: 0; margin-top: 0;\">&nbsp;&nbsp;&nbsp;Report summary</p>\n" \
"<p class=\"GREENSUBHEADING\">&nbsp;&nbsp;&nbsp;Unigraf device\n" \
"#device_description#\n" \
"</p></p></p><p class=\"GREENSUBHEADING\">&nbsp;&nbsp;&nbsp;Test results summary<p class=\"BODYWARNINGS\">\n#warning#</p>\n<p class=\"BODYTEXT\">\n" \
"Total number of test runs: #runs#<br>Passed test runs: #passed#<br>Failed test runs: #failed#<br>Skipped test runs: #skipped#<br>Aborted test runs: #aborted#\n" \
"<br></p></p></div>\n"
ReportFooter = "<br><br></pre></div>\n" \
"<div id=\"bottom_buttons\" style='margin-left: 12'>\n" \
"<button type=\"button\" onclick=\"PreviousTest()\">Previous</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=\"NextTest()\">Next</button>\n" \
"</div>\n" \
"</div>\n" \
" <hr>\n" \
" <p class=\"BODYTEXT\" style=\"text-align: center;\">\n" \
" Unigraf Oy<span style=\"color:#808080;\"> |</span> Piispantilankuja 4 <span style=\"color:#808080;\">|</span> 02240 Espoo <span style=\"color:#808080;\">|</span> Finland <span style=\"color:#808080;\">|</span> +358-9-859 550<br />\n" \
" E-mail: <a href=\"mailto:info@unigraf.fi\">info@unigraf.fi</a><span style=\"color:#808080;\"> " \
"|</span> Web site: <a href=\"http://www.unigraf.fi\">www.unigraf.fi</a>\n" \
" </p>\n" \
"</body>\n" \
"</html>\n"

View File

@@ -0,0 +1,780 @@
import re
from UniTAP.dev.modules.dut_tests.test_utils import TestReportConfigType, make_cf, CMTFormat, CMTBitDepth
def value_from_enumeration_var(_data, _value):
if len(_data.str_presentation) > 0:
return _data.str_presentation[_data.available_values.index(str(_value))]
else:
return _value
def copy_data(data):
_data = {}
for item in data:
if item.config_id_name in ["TSI_DP14_SRCCTS_DUT_CAPS", "TSI_DP14_SRCCTS_DUT_TA",
"TSI_DP14_SRCCTS_DMT_TIMING", "TSI_DP14_SRCCTS_CTA_TIMING",
"TSI_DP14_SRCCTS_CVT_TIMING", "TSI_DP14_SRCCTS_AS_DUT_CAPS",
"TSI_DP20_SRCCTS_DUT_CAPS", "TSI_DP20_SRCCTS_DUT_TA",
"TSI_DP20_SRCCTS_DMT_TIMING", "TSI_DP20_SRCCTS_CTA_TIMING",
"TSI_DP20_SRCCTS_CVT_TIMING", "TSI_DP20_SRCCTS_AS_DUT_CAPS",
"TSI_DP20_SRCCTS_DUT_LINK_RATES", "TSI_DP14_SRCCTS_DUT_DEBUG_CONF",
"TSI_DP20_SRCCTS_DUT_DEBUG_CONF", "TSI_DP20_SINKCTS_DEBUG_CONF"]:
_data.update({item.config_id_name: [item.default_value, item.bit_field_list]})
elif item.enumeration_variants is not None:
_data.update({item.config_id_name: [item.default_value, item.enumeration_variants]})
else:
_data.update({item.config_id_name: item.default_value})
return _data
def detect_warning_message(type_of_test: TestReportConfigType, data):
_data = copy_data(data)
_dict = {TestReportConfigType.Dp1_4_Source: "TSI_DP14_SRCCTS_DUT_DEBUG_CONF",
TestReportConfigType.Dp2_1_Source: "TSI_DP20_SRCCTS_DUT_DEBUG_CONF",
TestReportConfigType.Dp2_1_Sink: "TSI_DP20_SINKCTS_DEBUG_CONF",
TestReportConfigType.Dp2_1_Lttpr: "TSI_DP20_LTTPR_DEBUG_CR_ITERATION_DELAY"}
key = _dict.get(type_of_test)
val = _data.get(key)
if val is not None:
if key in ["TSI_DP14_SRCCTS_DUT_DEBUG_CONF",
"TSI_DP20_SRCCTS_DUT_DEBUG_CONF",
"TSI_DP20_SINKCTS_DEBUG_CONF"] and val[0] != 0:
return True
elif key == "TSI_DP20_LTTPR_DEBUG_CR_ITERATION_DELAY" and int(val[0] != 100):
return True
else:
return False
else:
return False
def update_configuration(type_of_test: TestReportConfigType, data):
configuration = ""
_data = copy_data(data)
if type_of_test == TestReportConfigType.Dp1_4_Source:
val = _data.get("TSI_DP14_SRCCTS_DUT_DEBUG_CONF")
if val is not None and val[0] != 0:
configuration += "<span class=DBG_HIGHLIGHT><br>Debug options:<br>"
for _bit in val[1]:
if val[0] & _bit.mask:
configuration += f" - {_bit.description}<br>"
configuration += "<br>"
configuration += "Test timeout = {}ms<br>".format(_data.get("TSI_DP14_SRCCTS_TIMEOUT"))
configuration += "Long HPD Duration = {}ms<br><br>".format(_data.get("TSI_DP14_SRCCTS_LONG_HPD_PULSE"))
configuration += "DUT capability settings and flags:<br>"
configuration += "- Max lanes = {}<br>".format(_data.get("TSI_DP14_SRCCTS_MAX_LANES")[0])
configuration += "- Max link rate = {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_MAX_LINK_RATE")[1],
_data.get("TSI_DP14_SRCCTS_MAX_LINK_RATE")[0]))
value = _data.get("TSI_DP14_SRCCTS_DUT_CAPS")
dut_caps_value = int(value[0])
for _bit in _data.get("TSI_DP14_SRCCTS_DUT_CAPS")[1]:
if dut_caps_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
configuration += "<br>Test automation flags and settings:<br>"
ta_flags = ["Always ready", "EDID read", "Link Training end", "Active Video"]
ta_flags_value = _data.get("TSI_DP14_SRCCTS_DUT_TA")[0]
for bit in _data.get("TSI_DP14_SRCCTS_DUT_TA")[1]:
if bit.mask & ta_flags_value or bit.enumeration_variants is not None:
if bit.enumeration_variants is not None:
configuration += "- Event indicating DUT ready: {}<br>".format(
ta_flags[(ta_flags_value >> 3) & 0x3])
else:
configuration += "- {}<br>".format(bit.description)
fail_mode = "640 x 480 @ 60Hz 6 BPC"
configuration += "<br>Failsafe timing: {}<br>".format(
fail_mode if int(_data.get("TSI_DP14_SRCCTS_FAILSAFE_MODE")[0]) else "")
configuration += "Max supported timing: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_MAX_RESOLUTION")[1],
_data.get("TSI_DP14_SRCCTS_MAX_RESOLUTION")[0]))
configuration += "<br>Most packed timings, 1 lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_1L_MOST_PACKED")[1],
_data.get("TSI_DP14_SRCCTS_1L_MOST_PACKED")[0]))
configuration += "Most packed timings, 2 lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_2L_MOST_PACKED")[1],
_data.get("TSI_DP14_SRCCTS_2L_MOST_PACKED")[0]))
configuration += "Most packed timings, 4 lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_4L_MOST_PACKED")[1],
_data.get("TSI_DP14_SRCCTS_4L_MOST_PACKED")[0]))
configuration += "<br>Time stamp generation timigns:<br>"
configuration += "RBR, 1 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_1L_RBB")[1],
_data.get("TSI_DP14_SRCCTS_1L_RBB")[0]))
configuration += "RBR, 2 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_2L_RBB")[1],
_data.get("TSI_DP14_SRCCTS_2L_RBB")[0]))
configuration += "RBR, 4 Lane: {}<br><br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_4L_RBB")[1],
_data.get("TSI_DP14_SRCCTS_4L_RBB")[0]))
configuration += "HBR, 1 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_1L_HBR")[1],
_data.get("TSI_DP14_SRCCTS_1L_HBR")[0]))
configuration += "HBR, 2 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_2L_HBR")[1],
_data.get("TSI_DP14_SRCCTS_2L_HBR")[0]))
configuration += "HBR, 4 Lane: {}<br><br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_4L_HBR")[1],
_data.get("TSI_DP14_SRCCTS_4L_HBR")[0]))
configuration += "HBR2, 1 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_1L_HBR2")[1],
_data.get("TSI_DP14_SRCCTS_1L_HBR2")[0]))
configuration += "HBR2, 2 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_2L_HBR2")[1],
_data.get("TSI_DP14_SRCCTS_2L_HBR2")[0]))
configuration += "HBR2, 4 Lane: {}<br><br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_4L_HBR2")[1],
_data.get("TSI_DP14_SRCCTS_4L_HBR2")[0]))
configuration += "HBR3, 1 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_1L_HBR3")[1],
_data.get("TSI_DP14_SRCCTS_1L_HBR3")[0]))
configuration += "HBR3, 2 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_2L_HBR3")[1],
_data.get("TSI_DP14_SRCCTS_2L_HBR3")[0]))
configuration += "HBR3, 4 Lane: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_4L_HBR3")[1],
_data.get("TSI_DP14_SRCCTS_4L_HBR3")[0]))
configuration += "<br>Colorimetry:<br>"
configuration += "- RGB 6 bpc VESA<br>"
for i in range(1, 13):
value = int(_data.get(f"TSI_DP14_SRCCTS_COLOR_MODE_{i}"))
if value == make_cf(CMTFormat.RGB_LEGACY, CMTBitDepth.BPC_8):
configuration += "- RGB 8 bpc VESA<br>"
elif value == make_cf(CMTFormat.RGB_LEGACY, CMTBitDepth.BPC_10):
configuration += "- RGB 10 bpc VESA<br>"
elif value == make_cf(CMTFormat.RGB_CEA, CMTBitDepth.BPC_8):
configuration += "- RGB 8 bpc CTA<br>"
elif value == make_cf(CMTFormat.RGB_CEA, CMTBitDepth.BPC_10):
configuration += "- RGB 10 bpc CTA<br>"
elif value == make_cf(CMTFormat.YCBCR_422_BT601, CMTBitDepth.BPC_8):
configuration += "- YCbCr 4:2:2 8 bpc CTA (ITU.601)<br>"
elif value == make_cf(CMTFormat.YCBCR_422_BT601, CMTBitDepth.BPC_10):
configuration += "- YCbCr 4:2:2 10 bpc CTA (ITU.601)<br>"
elif value == make_cf(CMTFormat.YCBCR_422_BT709, CMTBitDepth.BPC_8):
configuration += "- YCbCr 4:2:2 8 bpc CTA (ITU.709)<br>"
elif value == make_cf(CMTFormat.YCBCR_422_BT709, CMTBitDepth.BPC_10):
configuration += "- YCbCr 4:2:2 10 bpc CTA (ITU.709)<br>"
elif value == make_cf(CMTFormat.YCBCR_444_BT601, CMTBitDepth.BPC_8):
configuration += "- YCbCr 4:4:4 8 bpc CTA (ITU.601)<br>"
elif value == make_cf(CMTFormat.YCBCR_444_BT601, CMTBitDepth.BPC_10):
configuration += "- YCbCr 4:4:4 10 bpc CTA (ITU.601)<br>"
elif value == make_cf(CMTFormat.YCBCR_444_BT709, CMTBitDepth.BPC_8):
configuration += "- YCbCr 4:4:4 8 bpc CTA (ITU.709)<br>"
elif value == make_cf(CMTFormat.YCBCR_444_BT709, CMTBitDepth.BPC_10):
configuration += "- YCbCr 4:4:4 10 bpc CTA (ITU.709)<br>"
configuration += "<br>Audio format:<br>"
configuration += "- Minimum supported sample frequency: {}Hz<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_MIN_SAMPLE_RATE")[1],
_data.get("TSI_DP14_SRCCTS_MIN_SAMPLE_RATE")[0]))
configuration += "- Maximum supported sample frequency: {}Hz<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_MAX_SAMPLE_RATE")[1],
_data.get("TSI_DP14_SRCCTS_MAX_SAMPLE_RATE")[0]))
configuration += "- Audio test pattern: {}<br>". \
format(value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_AUDIO_TEST_PATTERN")[1],
_data.get("TSI_DP14_SRCCTS_AUDIO_TEST_PATTERN")[0]))
configuration += "- Audio sample size: {}<br>". \
format(value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_EDID_SAMPLE_SIZE")[1],
_data.get("TSI_DP14_SRCCTS_EDID_SAMPLE_SIZE")[0]))
ch_alloc_title = ["Minimum channel configuration / Min. sample rate",
"Maximum channel configuration / Min. sample rate",
"Minimum channel configuration / Max. sample rate",
"Maximum channel configuration / Max. sample rate"]
ch_alloc_str = [
"- Front Left + Front Right (2 Channels)",
"- Low Frequency Effect (1 Channel)",
"- Front Center (1 Channel)",
"- Rear Left + Rear Right (2 Channels)",
"- Rear Center (1 Channel)",
"- Front Left Center + Front Right Center (2 Channels)",
"- Rear Left Center + Rear Right Center (2 Channels)",
"- Front Left Wide + Front Right Wide (2 Channels)",
"- Front Left High + Front Right High (2 Channels)",
"- Top Center (1 Channel)",
"- Front Center High (1 Channel)"]
for i in range(len(ch_alloc_title)):
CH_ALLOC_CI = f"TSI_DP14_SRCCTS_CH_ALLOC{i + 1}"
CH_ALLOC_VAL = int(_data.get(CH_ALLOC_CI))
CH_COUNT_CI = f"TSI_DP14_SRCCTS_CHANNELS{i + 1}"
CH_COUNT_VAL = int(_data.get(CH_COUNT_CI))
configuration += "<br>{}:<br>".format(ch_alloc_title[i])
configuration += "- Channel count: {}<br>".format(CH_COUNT_VAL)
for j in range(len(ch_alloc_str)):
if CH_ALLOC_VAL >> j & 1:
configuration += "{}<br>".format(ch_alloc_str[j])
configuration += "<br>DSC Info:<br>"
dsc_version = int(_data.get("TSI_DP14_SRCCTS_DSC_VERSION")[0])
configuration += "- DSC Version: {}.{}<br>".format((dsc_version >> 16) & 0xff, dsc_version & 0xff)
configuration += "- DSC Max. Slices: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_DSC_DUT_MAX_SLICE")[1],
_data.get("TSI_DP14_SRCCTS_DSC_DUT_MAX_SLICE")[0]))
configuration += "<br>DSC Colorimetry:<br>"
configuration += "- RGB 8 bpc VESA<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_1")):
configuration += "- RGB 10 bpc VESA<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_2")):
configuration += "- RGB 12 bpc VESA<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_3")):
configuration += "- YCbCr 4:4:4 8 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_4")):
configuration += "- YCbCr 4:4:4 10 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_5")):
configuration += "- YCbCr 4:4:4 12 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_6")):
configuration += "- YCbCr 4:2:2 8 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_7")):
configuration += "- YCbCr 4:2:2 10 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_8")):
configuration += "- YCbCr 4:2:2 12 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_9")):
configuration += "- YCbCr 4:2:2 Simple 8 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_10")):
configuration += "- YCbCr 4:2:2 Simple 10 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_11")):
configuration += "- YCbCr 4:2:2 Simple 12 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_12")):
configuration += "- YCbCr 4:2:0 Simple 8 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_13")):
configuration += "- YCbCr 4:2:0 Simple 10 bpc CTA (ITU.709)<br>"
if int(_data.get("TSI_DP14_SRCCTS_DSC_COLOR_MODE_14")):
configuration += "- YCbCr 4:2:0 Simple 12 bpc CTA (ITU.709)<br>"
configuration += "<br>DSC resolutions to be tested:<br>"
dsc_timings = ["1920x1080 @ 30Hz", "1920x1080 @ 60Hz", "1920x1080 @ 120Hz", "3840x2160 @ 30Hz",
"3840x2160 @ 60Hz", "3840x2160 @ 120Hz", "5120x2160 @ 30Hz", "5120x2160 @ 60Hz",
"5120x2160 @ 120Hz", "7680x4320 @ 30Hz", "7680x4320 @ 60Hz", "7680x4320 @ 100Hz"]
for item in enumerate(dsc_timings):
if int(_data.get(f"TSI_DP14_SRCCTS_DSC_VMT_{item[0]}_TIMINGS")):
lane_count_link_rate = _data.get(f"TSI_DP14_SRCCTS_DSC_VMT_{item[0]}_LC_LR")
if lane_count_link_rate in [1 << 0, 1 << 1, 1 << 2, 1 << 3]:
n_lanes = "1"
elif lane_count_link_rate in [1 << 4, 1 << 5, 1 << 6, 1 << 7]:
n_lanes = "2"
else:
n_lanes = "4"
if lane_count_link_rate in [1 << 0, 1 << 4, 1 << 8]:
bit_rate = "1.62"
elif lane_count_link_rate in [1 << 1, 1 << 5, 1 << 9]:
bit_rate = "2.7"
elif lane_count_link_rate in [1 << 2, 1 << 6, 1 << 10]:
bit_rate = '5.4'
else:
bit_rate = "8.1"
configuration += "- {} with {} lanes(s) @ {} Gbps<br>".format(item[1], n_lanes, bit_rate)
configuration += "<br>DisplayID test configuration:<br>"
configuration += "- Max HActive = {}<br>".format(_data.get("TSI_DP14_SRCCTS_MAX_STREAM_HACTIVE"))
configuration += "- Max VActive = {}<br>".format(_data.get("TSI_DP14_SRCCTS_MAX_STREAM_VACTIVE"))
configuration += "- Max Pixel Clock (kHz) = {} <br>".format(
_data.get("TSI_DP14_SRCCTS_MAX_STREAM_PIXEL_CLOCK"))
if int(_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[1][15].mask) & int(
_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[0]):
configuration += "<br>DMT Timings:<br>"
dmt_timing_value = int(_data.get("TSI_DP14_SRCCTS_DMT_TIMING")[0])
for _bit in _data.get("TSI_DP14_SRCCTS_DMT_TIMING")[1]:
if dmt_timing_value & int(_bit.mask):
configuration += "- {}<br>".format(_bit.description)
if int(_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[1][16].mask) & int(
_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[0]):
configuration += "<br>CTA Timings:<br>"
cta_timing_value = int(_data.get("TSI_DP14_SRCCTS_CTA_TIMING")[0])
for _bit in _data.get("TSI_DP14_SRCCTS_CTA_TIMING")[1]:
if cta_timing_value & int(_bit.mask):
configuration += "- {}<br>".format(_bit.description)
if (int(_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[1][17].mask) & int(
_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[0])) or \
(int(_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[1][18].mask) &
_data.get("TSI_DP14_SRCCTS_DUT_CAPS")[0]):
configuration += "<br>CVT Timings:<br>"
cvt_timing_value = int(_data.get("TSI_DP14_SRCCTS_CVT_TIMING")[0])
for _bit in _data.get("TSI_DP14_SRCCTS_CVT_TIMING")[1]:
if cvt_timing_value & int(_bit.mask):
configuration += "- {}<br>".format(_bit.description)
configuration += "<br>Audio modes:<br>"
for i in range(8):
audio_mode = int(_data.get(f"TSI_DP14_SRCCTS_TESTED_AUDIO_MODE_{i}"))
audio_type = ["Refer to Stream Header", "L-PCM", "AC-3", "MPEG-1", "MP3", "MPEG2", "AAC LC", "DTS",
"ATRAC", "One Bit Audio", "Enhanced AC-3", "DTS-HD", "MAT", "DST", "WMA Pro",
"Refer to Audio Coding Extension Type (CXT)"]
audio_sampling = ["Refer to Stream Header", "32 kHz", "44.1 kHz (CD)", "48 kHz", "88.2 kHz", "96 kHz",
"176.4 kHz", "192 kHz"]
audio_ch_count = ["Refer to Stream Header", "2 channels", "3 channels", "4 channels", "5 channels",
"6 channels", "7 channels", "8 channels"]
audio_sample_size = ["Refer to Stream Header", "16 bit", "20 bit", "24 bit"]
if audio_mode:
configuration += "- Audio Mode {}: {}, {}, {} @ {}<br>".format(i, audio_type[
audio_mode >> 4 & 0xF],
audio_ch_count[
audio_mode & 0x7],
audio_sample_size[
audio_mode >> 8 & 0x3],
audio_sampling[
audio_mode >> 10 & 0x7])
else:
configuration += f"- Audio Mode {i}: Disabled<br>"
configuration += "<br>AdaptiveSync configuration:<br>"
as_value = _data.get("TSI_DP14_SRCCTS_AS_DUT_CAPS")[0]
for _bit in _data.get("TSI_DP14_SRCCTS_AS_DUT_CAPS")[1]:
if as_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
configuration += "- Adaptive-Sync range minimum refresh rate supported by the Source: {}<br>" \
.format(value_from_enumeration_var(_data.get("TSI_DP14_SRCCTS_AS_RANGE_MIN_RATE")[1],
_data.get("TSI_DP14_SRCCTS_AS_RANGE_MIN_RATE")[0]))
as_timings = ["1920x1080p", "2560x1080p", "2560x1440p", "3840x2160p", "4096x2160p", "5120x2160p",
"7680x4320p", "10240x4320p"]
for item in enumerate(as_timings):
as_value = int(_data.get(f"TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_{item[0]}"))
if as_value:
configuration += "- {} maximum refresh rate: {}Hz<br>".format(item[1], as_value)
else:
configuration += "- {} is not supported<br>".format(item[1])
elif type_of_test == TestReportConfigType.Dp2_1_Source:
val = _data.get("TSI_DP20_SRCCTS_DUT_DEBUG_CONF")
if val is not None and val[0] != 0:
configuration += "<span class=DBG_HIGHLIGHT><br>Debug options:<br>"
for _bit in val[1]:
if val[0] & _bit.mask:
configuration += f" - {_bit.description}<br>"
configuration += "<br>"
configuration += "Test timeout = {}ms<br>".format(_data.get("TSI_DP20_SRCCTS_TIMEOUT"))
configuration += "Long HPD Duration = {}ms<br><br>".format(_data.get("TSI_DP20_SRCCTS_LONG_HPD_PULSE"))
configuration += "DUT capability settings and flags:<br>"
configuration += "- Max lanes = {}<br>".format(_data.get("TSI_DP20_SRCCTS_MAX_LANES")[0])
configuration += "- Max link rate = {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_MAX_LINK_RATE")[1],
_data.get("TSI_DP20_SRCCTS_MAX_LINK_RATE")[0]))
dut_caps_value = _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[0]
for _bit in _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[1]:
if dut_caps_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
dut_link_rates_value = _data.get("TSI_DP20_SRCCTS_DUT_LINK_RATES")[0]
for _bit in _data.get("TSI_DP20_SRCCTS_DUT_LINK_RATES")[1]:
if dut_link_rates_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
configuration += f"- Number of LTTPR devices: {_data.get('TSI_DP20_SRCCTS_LTTPR_DEVICE_COUNT')}<br>"
configuration += "- Number of minimum link bandwidth: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_MAX_LINK_BW_POLICY")[1],
_data.get("TSI_DP20_SRCCTS_MAX_LINK_BW_POLICY")[0]))
configuration += "<br>Settings for Dynamic Refresh Rate with VBlank stretch with MSA_TIMING_PAR_IGNORED:<br>"
configuration += f"- HActive: {_data.get('TSI_DP20_SRCCTS_DRR_HACTIVE')} pixels<br>"
configuration += f"- VActive: {_data.get('TSI_DP20_SRCCTS_DRR_VACTIVE')} lines<br>"
configuration += f"- Pixel Clock: {_data.get('TSI_DP20_SRCCTS_DRR_PIXEL_CLOCK')} kHz<br>"
configuration += f"- Minimum Vertical Refresh Rate: {_data.get('TSI_DP20_SRCCTS_DRR_MIN_VRR')} Hz<br>"
configuration += f"- Maximum Vertical Refresh Rate: {_data.get('TSI_DP20_SRCCTS_DRR_MAX_VRR')} Hz<br>"
configuration += "<br>Test automation flags and settings:<br>"
ta_flags = ["Always ready", "EDID read", "Link Training end", "Active Video"]
ta_flags_value = _data.get("TSI_DP20_SRCCTS_DUT_TA")[0]
for bit in _data.get("TSI_DP20_SRCCTS_DUT_TA")[1]:
if bit.mask & ta_flags_value or bit.enumeration_variants is not None:
if bit.enumeration_variants is not None:
configuration += "- Event indicating DUT ready: {}<br>".format(ta_flags[(ta_flags_value >> 3) & 0x3])
else:
configuration += "- {}<br>".format(bit.description)
configuration += "<br>Audio format:<br>"
configuration += "- Minimum supported sample frequency: {}Hz<br>".format(
value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_MIN_SAMPLE_RATE")[1],
_data.get("TSI_DP20_SRCCTS_MIN_SAMPLE_RATE")[0]))
configuration += "- Maximum supported sample frequency: {}Hz<br>".format(
value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_MAX_SAMPLE_RATE")[1],
_data.get("TSI_DP20_SRCCTS_MAX_SAMPLE_RATE")[0]))
configuration += "- Audio test pattern: {}<br>". \
format(value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_AUDIO_TEST_PATTERN")[1],
_data.get("TSI_DP20_SRCCTS_AUDIO_TEST_PATTERN")[0]))
configuration += "- Audio sample size: {}<br>". \
format(value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_EDID_SAMPLE_SIZE")[1],
_data.get("TSI_DP20_SRCCTS_EDID_SAMPLE_SIZE")[0]))
ch_alloc_title = ["Minimum channel configuration / Min. sample rate",
"Maximum channel configuration / Min. sample rate",
"Minimum channel configuration / Max. sample rate",
"Maximum channel configuration / Max. sample rate"]
ch_alloc_str = [
"- Front Left + Front Right (2 Channels)",
"- Low Frequency Effect (1 Channel)",
"- Front Center (1 Channel)",
"- Rear Left + Rear Right (2 Channels)",
"- Rear Center (1 Channel)",
"- Front Left Center + Front Right Center (2 Channels)",
"- Rear Left Center + Rear Right Center (2 Channels)",
"- Front Left Wide + Front Right Wide (2 Channels)",
"- Front Left High + Front Right High (2 Channels)",
"- Top Center (1 Channel)",
"- Front Center High (1 Channel)"]
for i in range(len(ch_alloc_title)):
CH_ALLOC_CI = f"TSI_DP20_SRCCTS_CH_ALLOC{i + 1}"
CH_ALLOC_VAL = int(_data.get(CH_ALLOC_CI))
CH_COUNT_CI = f"TSI_DP20_SRCCTS_CHANNELS{i + 1}"
CH_COUNT_VAL = int(_data.get(CH_COUNT_CI))
configuration += "<br>{}:<br>".format(ch_alloc_title[i])
configuration += "- Channel count: {}<br>".format(CH_COUNT_VAL)
for j in range(len(ch_alloc_str)):
if CH_ALLOC_VAL >> j & 1:
configuration += "{}<br>".format(ch_alloc_str[j])
configuration += "<br>DSC Info:<br>"
dsc_version = int(_data.get("TSI_DP20_SRCCTS_DSC_VERSION")[0])
configuration += "- DSC Version: {}.{}<br>".format((dsc_version >> 16) & 0xff, dsc_version & 0xff)
configuration += "- DSC Max. Slices: {}<br>".format(
value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_DSC_DUT_MAX_SLICE")[1],
_data.get("TSI_DP20_SRCCTS_DSC_DUT_MAX_SLICE")[0]))
configuration += "<br>DisplayID test configuration:<br>"
configuration += "- Max HActive = {}<br>".format(_data.get("TSI_DP20_SRCCTS_MAX_STREAM_HACTIVE"))
configuration += "- Max VActive = {}<br>".format(_data.get("TSI_DP20_SRCCTS_MAX_STREAM_VACTIVE"))
configuration += "- Max Pixel Clock (kHz) = {} <br>".format(
_data.get("TSI_DP20_SRCCTS_MAX_STREAM_PIXEL_CLOCK"))
if _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[1][17].mask & _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[0]:
configuration += "<br>DMT Timings:<br>"
dmt_timing_value = _data.get("TSI_DP20_SRCCTS_DMT_TIMING")[0]
for _bit in _data.get("TSI_DP20_SRCCTS_DMT_TIMING")[1]:
if dmt_timing_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
if _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[1][18].mask & _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[0]:
configuration += "<br>CTA Timings:<br>"
cta_timing_value = _data.get("TSI_DP20_SRCCTS_CTA_TIMING")[0]
for _bit in _data.get("TSI_DP20_SRCCTS_CTA_TIMING")[1]:
if cta_timing_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
if (_data.get("TSI_DP20_SRCCTS_DUT_CAPS")[1][19].mask & _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[0]) or \
(_data.get("TSI_DP20_SRCCTS_DUT_CAPS")[1][20].mask & _data.get("TSI_DP20_SRCCTS_DUT_CAPS")[0]):
configuration += "<br>CVT Timings:<br>"
cvt_timing_value = _data.get("TSI_DP20_SRCCTS_CVT_TIMING")[0]
for _bit in _data.get("TSI_DP20_SRCCTS_CVT_TIMING")[1]:
if cvt_timing_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
configuration += "<br>Audio modes:<br>"
for i in range(8):
audio_mode = int(_data.get(f"TSI_DP20_SRCCTS_TESTED_AUDIO_MODE_{i}"))
audio_type = ["Refer to Stream Header", "L-PCM", "AC-3", "MPEG-1", "MP3", "MPEG2", "AAC LC", "DTS",
"ATRAC", "One Bit Audio", "Enhanced AC-3", "DTS-HD", "MAT", "DST", "WMA Pro",
"Refer to Audio Coding Extension Type (CXT)"]
audio_sampling = ["Refer to Stream Header", "32 kHz", "44.1 kHz (CD)", "48 kHz", "88.2 kHz", "96 kHz",
"176.4 kHz", "192 kHz"]
audio_ch_count = ["Refer to Stream Header", "2 channels", "3 channels", "4 channels", "5 channels",
"6 channels", "7 channels", "8 channels"]
audio_sample_size = ["Refer to Stream Header", "16 bit", "20 bit", "24 bit"]
if audio_mode:
configuration += "- Audio Mode {}: {}, {}, {} @ {}<br>".format(i, audio_type[
audio_mode >> 4 & 0xF],
audio_ch_count[
audio_mode & 0x7],
audio_sample_size[
audio_mode >> 8 & 0x3],
audio_sampling[
audio_mode >> 10 & 0x7])
else:
configuration += f"- Audio Mode {i}: Disabled<br>"
configuration += "<br>AdaptiveSync configuration:<br>"
as_value = _data.get("TSI_DP20_SRCCTS_AS_DUT_CAPS")[0]
for _bit in _data.get("TSI_DP20_SRCCTS_AS_DUT_CAPS")[1]:
if as_value & _bit.mask:
configuration += "- {}<br>".format(_bit.description)
configuration += "- Adaptive-Sync range minimum refresh rate supported by the Source: {}<br>" \
.format(value_from_enumeration_var(_data.get("TSI_DP20_SRCCTS_AS_RANGE_MIN_RATE")[1],
_data.get("TSI_DP20_SRCCTS_AS_RANGE_MIN_RATE")[0]))
as_timings = ["1920x1080p", "2560x1080p", "2560x1440p", "3840x2160p", "4096x2160p", "5120x2160p",
"7680x4320p", "10240x4320p"]
for item in enumerate(as_timings):
as_value = int(_data.get(f"TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_{item[0]}"))
if as_value:
configuration += "- {} maximum refresh rate: {}Hz<br>".format(item[1], as_value)
else:
configuration += "- {} is not supported<br>".format(item[1])
colorimetry_map = {0: '-', 1: 8, 3: 10, 7: 12, 15: 16}
def add_column_title(include_dsc : bool):
title = "<tr>"
style = 'style="padding: 10px; border: 1px solid black;"'
title_list = [f'<th rowspan="2" {style}>Timing</th>\n',
f'<th colspan="6" {style}>Timing vendors</th>\n',
f'<th colspan="5" {style}>Colorimetry</th>\n']
timing_vendors = ['CTA', 'DMT', 'CVT', 'CVT RB1', 'CVT RB2', 'OVT']
colorimetry = ["RGB", "YCbCr444", "YCbCr422", "YCbCr422Simple", "YCbCr420"] if include_dsc else [ "RGB", "YCbCr444", "YCbCr422", "YCbCr420" ]
for title_item in title_list:
title += title_item
title += "</tr>\n<tr>"
for timing_vendors_item in timing_vendors:
title += f'<th {style}>{timing_vendors_item}</th>'
for colorimetry_item in colorimetry:
title += f'<th {style}>{colorimetry_item}</th>'
title += "</tr>\n"
return title
def add_video_row(timing_info, tim_value):
style = 'align="center";'
row = f'<tr><td align="left">{timing_info}</td>' \
f'<td {style}>{"+" if tim_value & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 1) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 2) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 3) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 4) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 5) & 0x1 else "-"}</td>'
row += f'<td {style}>{colorimetry_map.get((tim_value >> 12) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 16) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 20) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 28) & 0xF)}</td>'
return row
def add_dsc_row(timing_info, tim_value):
style = 'align="center";'
row = f'<tr><td align="left">{timing_info}</td>' \
f'<td {style}>{"+" if tim_value & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 1) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 2) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 3) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 4) & 0x1 else "-"}</td>' \
f'<td {style}>{"+" if (tim_value >> 5) & 0x1 else "-"}</td>'
row += f'<td {style}>{colorimetry_map.get((tim_value >> 12) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 16) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 20) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 24) & 0xF)}</td>' \
f'<td {style}>{colorimetry_map.get((tim_value >> 28) & 0xF)}</td>'
return row
configuration += '<br><table border="1">' + add_column_title(False)
deprecated_video_modes = [ "TSI_DP20_SRCCTS_VMT_1920_1080_144", "TSI_DP20_SRCCTS_VMT_1920_1080_240",
"TSI_DP20_SRCCTS_VMT_3840_2160_30", "TSI_DP20_SRCCTS_VMT_3840_2160_240",
"TSI_DP20_SRCCTS_VMT_5120_2160_120", "TSI_DP20_SRCCTS_VMT_5120_2160_240",
"TSI_DP20_SRCCTS_VMT_7680_4320_120", "TSI_DP20_SRCCTS_VMT_10240_4320_30",
"TSI_DP20_SRCCTS_VMT_10240_4320_60"]
for key in _data.keys():
if key in deprecated_video_modes:
continue
if key.find("TSI_DP20_SRCCTS_VMT_") != -1:
value = _data.get(key)
_, h_active, w_active, rate = re.findall(r'\d+', key)
configuration += add_video_row(f"{h_active}x{w_active} @ {rate}Hz", value)
configuration += "</table><br>"
configuration += '<br><table border="1">' + add_column_title(True)
for key in _data.keys():
if key.find("TSI_DP20_SRCCTS_DSC_VMT_") != -1:
value = _data.get(key)
_, h_active, w_active, rate = re.findall(r'\d+', key)
configuration += add_dsc_row(f"{h_active}x{w_active} @ {rate}Hz", value)
configuration += "</table><br>"
elif type_of_test == TestReportConfigType.Dp1_4_Sink:
configuration = "Test timeout = {}ms<br>".format(_data.get("TSI_DP14_SINKCTS_TIMEOUT"))
if not int(_data.get("TSI_DP14_SINKCTS_DSC_SOURCE")[0]):
configuration += "<br>DSC resolutions to be tested:<br>"
dsc_timings = ["1920x1080 @ 30Hz", "1920x1080 @ 60Hz", "1920x1080 @ 120Hz", "3840x2160 @ 30Hz",
"3840x2160 @ 60Hz", "3840x2160 @ 120Hz", "5120x2160 @ 30Hz", "5120x2160 @ 60Hz",
"5120x2160 @ 120Hz", "7680x4320 @ 30Hz", "7680x4320 @ 60Hz", "7680x4320 @ 100Hz"]
for item in enumerate(dsc_timings):
timing_flags = int(str(_data.get(f"TSI_DP14_SINKCTS_DSC_VM_T_{item[0]}")), 16)
if timing_flags:
configuration += "- {}{}{}{}<br>".format(item[1], " CTA" if timing_flags & 0x1 else "",
" RB1" if timing_flags & 0x2 else "",
" RB2" if timing_flags & 0x4 else "")
else:
configuration += "<br>DSC resolutions to be tested are defined by DUT EDID<br>"
configuration += "<br>Sink DUT supports DSC Simple 422 CRC for {}<br>". \
format(value_from_enumeration_var(_data.get("TSI_DP14_SINKCTS_SUPPORT_444CRC")[1],
_data.get("TSI_DP14_SINKCTS_SUPPORT_444CRC")[0]))
if int(_data.get("TSI_DP14_SINKCTS_VISUAL_TEST_CHECK")[0]):
configuration += "Never skip Display ID test's visual video checks<br>"
else:
configuration += "Skip Display ID test's visual video checks if CRC available and matching<br>"
if not int(_data.get("TSI_DP14_SINKCTS_PACKET_SOURCE")[0]):
configuration += "<br>Most packed resolutions to be tested:<br>"
video_timings = ["CVT 1280 x 800 @ 60p [RB1] 18bpp 99", "DMT 1280 x 768 @ 60p [RB1] 18bpp 95",
"DMT 800 x 600 @ 60.317p 30bpp 93", "DMT 1024 x 768 @ 60p 18bpp 90",
"DMT 1280 x 1024 @ 60p 24bpp 100", "DMT 1280 x 960 @ 60p 24bpp 100",
"DMT 1360 x 768 @ 60p 30bpp 99", "CVT 1280 x 800 @ 60p 30bpp 97",
"DMT 1400 x 1050 @ 60p [RB1] 24bpp 94", "DMT 1280 x 768 @ 60p 30bpp 92",
"CVT 1600 x 1200 @ 60p [RB1] 18bpp 90", "CVT 2048 x 1536 @ 60p [RB1] 24bpp 97",
"DMT 1792 x 1344 @ 60p 24bpp 95", "DMT 1600 x 1200 @ 60p 30bpp 94",
"CTA 1440 x 480 @ 59.94p 24bpp 100", "CTA 1440 x 576 @ 50p 24bpp 100",
"CTA 1920 x 1080 @ 60p 30bpp 86"]
for item in video_timings:
configuration += "- {}<br>".format(item)
else:
configuration += "<br>Most packed resolutions to be tested are defined by DUT EDID<br>"
elif type_of_test == TestReportConfigType.Dp2_1_Sink:
configuration = ""
val = _data.get("TSI_DP20_SINKCTS_DEBUG_CONF")
if val is not None and val[0] != 0:
configuration += "<span class=DBG_HIGHLIGHT><br>Debug options:<br>"
for _bit in val[1]:
if val[0] & _bit.mask:
configuration += f" - {_bit.description}<br>"
configuration += "<br>"
configuration += "Test timeout = {}ms<br>".format(_data.get("TSI_DP20_SINKCTS_TIMEOUT"))
if not int(_data.get("TSI_DP20_SINKCTS_DSC_SOURCE")[0]):
configuration += "<br>DSC resolutions to be tested:<br>"
video_modes_list = [[1920, 1080, 30], [1920, 1080, 60], [1920, 1080, 120], [1920, 1080, 144],
[1920, 1080, 240],
[3840, 2160, 30], [3840, 2160, 60], [3840, 2160, 120], [3840, 2160, 144],
[3840, 2160, 240],
[5120, 2160, 30], [5120, 2160, 60], [5120, 2160, 120], [5120, 2160, 144],
[5120, 2160, 240],
[7680, 4320, 30], [7680, 4320, 60], [7680, 4320, 120], [7680, 4320, 144],
[7680, 4320, 240],
[10240, 4320, 30], [10240, 4320, 60], [10240, 4320, 120], [10240, 4320, 144],
[10240, 4320, 240],
[15360, 8640, 30], [15360, 8640, 60], [15360, 8640, 120], [15360, 8640, 144],
[15360, 8640, 240]]
for vm in video_modes_list:
timing_flag = _data.get(f"TSI_DP20_SINKCTS_VMT_{vm[0]}_{vm[1]}")
bit_n = 0
if vm[2] == 60:
bit_n = 4
elif vm[2] == 120:
bit_n = 8
elif vm[2] == 144:
bit_n = 13
elif vm[2] == 240:
bit_n = 17
if vm[2] in [144, 240]:
rb1_value = (timing_flag >> bit_n) & 0x1
rb2_value = (timing_flag >> (bit_n + 1)) & 0x1
ovt_value = (timing_flag >> (bit_n + 2)) & 0x1
if rb1_value or rb2_value or ovt_value:
configuration += f"- {vm[0]}x{vm[1]} @ {vm[2]}Hz" \
f"{' RB1' if rb1_value else ''}" \
f"{' RB2' if rb2_value else ''}" \
f"{' OVT' if ovt_value else ''}<br>"
else:
cta_value = (timing_flag >> bit_n) & 0x1
rb1_value = (timing_flag >> (bit_n + 1)) & 0x1
rb2_value = (timing_flag >> (bit_n + 2)) & 0x1
if rb1_value or rb2_value or cta_value:
configuration += f"- {vm[0]}x{vm[1]} @ {vm[2]}Hz" \
f"{' CTA' if cta_value else ''}" \
f"{' RB1' if rb1_value else ''}" \
f"{' RB2' if rb2_value else ''}<br>"
else:
configuration += "<br>DSC resolutions to be tested are defined by DUT EDID<br>"
if _data.get("TSI_DP20_SINKCTS_SUPPORT_444CRC")[0] == 0:
configuration += "<br>Sink DUT supports YCbCR 422 CRC for Simple 422 bitstream<br>"
elif _data.get("TSI_DP20_SINKCTS_SUPPORT_444CRC")[0] == 1:
configuration += "<br>Sink DUT supports YCbCR 444 CRC for Simple 422 bitstream<br>"
else:
configuration += "<br><br>"
if int(_data.get("TSI_DP20_SINKCTS_VISUAL_TEST_CHECK")[0]):
configuration += "<br>Skip Display ID test's visual video checks if CRC available and matching<br>"
else:
configuration += "<br>Never skip Display ID test's visual video checks<br>"
return configuration
def dp21_source_timing_table(data) -> str:
_data = copy_data(data)
colorimetry_map = {0: '-', 1: 8, 3: 10, 7: 12, 15: 16}
info = f"Timing {'Timing vendors':>35} {'Colorimetry':>40}\n"
info += f"{'CTA DMT CVT CVT-RB1 CVT-RB2 OVT':>50}"
info += f"{'RGB YCbCr444 YCbCr422 YCbCr422Simple YCbCr420':>50}\n"
def shift(str_length) -> int:
if str_length == 14:
return 7
elif str_length == 15:
return 6
elif str_length == 16:
return 5
elif str_length == 17:
return 4
def support(flag) -> str:
return "+" if flag else "-"
def add_row(timing_info, tim_value):
row = f'{timing_info}' \
f'{support(tim_value & 0x1):>{shift(len(timing_info))}}' \
f'{support((tim_value >> 1) & 0x1):>4}' \
f'{support((tim_value >> 2) & 0x1):>4}' \
f'{support((tim_value >> 3) & 0x1):>6}' \
f'{support((tim_value >> 4) & 0x1):>8}' \
f'{support((tim_value >> 5) & 0x1):>6}'
row += f'{colorimetry_map.get((tim_value >> 12) & 0xF):>8}' \
f'{colorimetry_map.get((tim_value >> 16) & 0xF):>7}' \
f'{colorimetry_map.get((tim_value >> 20) & 0xF):>9}' \
f'{colorimetry_map.get((tim_value >> 24) & 0xF):>12}' \
f'{colorimetry_map.get((tim_value >> 28) & 0xF):>12}\n'
return row
for key in _data.keys():
if key.find("TSI_DP20_SRCCTS_VMT_") != -1:
value = _data.get(key)
_, h_active, w_active, rate = re.findall(r'\d+', key)
info += add_row(f"{h_active}x{w_active} @ {rate}Hz", value)
return info