diff --git a/examples/configs/example_rack_config.yml b/examples/configs/example_rack_config.yml index e78f0ff..f7efdaf 100644 --- a/examples/configs/example_rack_config.yml +++ b/examples/configs/example_rack_config.yml @@ -103,10 +103,11 @@ rackConfig: # [ avSyncController: optional] - Specifiec AVSyncController for the slot # supported types: # [type: "SyncOne2", port: "/dev/ttyACM0", extended_mode (optional): true|false, audio_input (optional): "AUTO|EXTERNAL|INTERNAL", speaker_distance (optional): "1.5"] - # [ hdmiAnalyserController: optional ] - Specifies an HDMI Analyser/Generator for the slot # supported types: # [type: "m42h", host: "192.168.0.50", port (optional): 22, user (optional): "qd", passwd (optional): "qd", card (optional): 4 ] + # [type: "manual-hdmi-controller", address: "127.0.0.1", username: "", password: "", port: "7722", sink_control_port: 8085, source_control_port: 8086, device: sink] + # [type: "virtual-hdmi-controller", address: "127.0.0.1", username: "", password: "", port: "7722", sink_control_port: 8085, source_control_port: 8086, device: sink] - pi2: ip: "192.168.99.1" description: "local pi4" diff --git a/framework/core/hdmiAnalyserController.py b/framework/core/hdmiAnalyserController.py index 26ce7a1..660f450 100644 --- a/framework/core/hdmiAnalyserController.py +++ b/framework/core/hdmiAnalyserController.py @@ -31,6 +31,8 @@ from framework.core.logModule import logModule from framework.core.hdmiAnalyserModules.m42h import M42hController +from framework.core.hdmiAnalyserModules.virtualHdmiController import virtualHdmiController +from framework.core.hdmiAnalyserModules.manualHdmiController import manualHdmiController class HDMIAnalyserController(): @@ -43,8 +45,12 @@ class HDMIAnalyserController(): Supported types: ``m42h`` – Teledyne LeCroy Quantumdata M42h 96G Video Analyser/Generator. + ``manual-hdmi-controller`` – SSH-based controller for manual HDMI device + interaction via a control port. + ``virtual-hdmi-controller`` – SSH-based controller for virtual HDMI device + interaction via a control port (used in simulation/test environments). - Rack-config example:: + Rack-config example (m42h):: hdmiAnalyserController: type: "m42h" @@ -53,12 +59,26 @@ class HDMIAnalyserController(): user: "qd" # optional, defaults to "qd" passwd: "qd" # optional, defaults to "qd" card: 4 # optional card number + + Rack-config example (manual-hdmi-controller / virtual-hdmi-controller):: + + hdmiAnalyserController: + type: "manual-hdmi-controller" # or "virtual-hdmi-controller" + address: "192.168.0.51" + port: 22 + username: "admin" + password: "secret" + prompt: "~#" + device: "hdmi" # used to resolve _control_port + source_control_port: 8080 # optional, defaults to 8080 + sink_control_port: 8081 """ def __init__(self, log: logModule, config: dict): self._log = log self.controllerType = config.get("type") self.host = config.get("host") + self.devicetype=config.get("device", "") if self.controllerType == "m42h": self.hdmiAnalyser = M42hController( @@ -68,6 +88,27 @@ def __init__(self, log: logModule, config: dict): passwd=config.get("passwd", "qd"), card=config.get("card"), ) + elif self.controllerType == "manual-hdmi-controller": + #if self.controllerType == "manual-hdmi-controller": + self.hdmiAnalyser = manualHdmiController(self._log, + host=config.get("address", ""), + port=config.get("port", 22), + user=config.get("username", ""), + passwd=config.get("password", ""), + prompt=config.get('prompt', '~#'), + control_port=config.get(f'{self.devicetype}_control_port', 8080), + device=self.devicetype, + ) + elif self.controllerType == "virtual-hdmi-controller": + self.hdmiAnalyser = virtualHdmiController(self._log, + host=config.get("address", ""), + port=config.get("port", 22), + user=config.get("username", ""), + passwd=config.get("password", ""), + prompt=config.get('prompt', '~#'), + control_port=config.get(f'{self.devicetype}_control_port', 8080), + device=self.devicetype, + ) else: raise ValueError( f"Unsupported hdmiAnalyserController type: '{self.controllerType}'" @@ -191,3 +232,207 @@ def set_hdcp_mode(self, mode: str): def snapshot(self) -> dict: self._log.info("Taking analyser snapshot") return self.hdmiAnalyser.snapshot() + + # ── HDMI output ───────────────────────────────────────────────────── + + def sendEDIDRead(self, port: int, data: list): + """ + Send an EDID read event for the HDMI output port. + + Args: + port (int): HDMI output port number. + data (list): EDID data bytes. + + Returns: + bool: True if message/event handled successfully. + """ + return self.hdmiAnalyser.sendEDIDRead(port, data) + + def sendFrameRateChanged(self, port: int): + """ + Send a frame rate changed event for the HDMI output port. + + Args: + port (int): HDMI output port number. + + Returns: + bool: True if message/event handled successfully. + """ + return self.hdmiAnalyser.sendFrameRateChanged(port) + + def setHDCPStatus(self, port: int, status: str, version: str): + """ + Set HDCP status for the HDMI output port. + + Args: + port (int): HDMI output port number. + status (str): HDCP status string. + version (str): HDCP version string. + + Returns: + bool: True if message/event handled successfully. + """ + return self.hdmiAnalyser.setHDCPStatus(port, status, version) + + def setHotplugState(self, port: int, connected: bool, version: str = "VERSION_2_X"): + """ + Set hotplug state for the HDMI output port. + + Args: + port (int): HDMI output port number. + connected (bool): True if connected, False if disconnected. + version (str): HDCP version string. Defaults to "VERSION_2_X". + + Returns: + bool: True if message/event handled successfully. + """ + return self.hdmiAnalyser.setHotplugState(port, connected, version) + + def setHDCPVersion(self, port: int, hdcp_version: str): + """ + Set the HDCP version for the HDMI input port. + + Args: + port (int): HDMI input port number. + hdcp_version (str): HDCP version string. (VERSION_1_X, VERSION_2_X, UNDEFINED) + Returns: + bool: True if HDCP version set successfully. + """ + return self.hdmiAnalyser.setHDCPVersion(port, hdcp_version) + + def validateEdid(self, port: int, expected_edid: list): + """ + Validate the EDID data for the HDMI input port. + + Args: + port (int): HDMI input port number. + expected_edid (list): Expected EDID data bytes. + Returns: + bool: True if EDID data matches expected values. + """ + return self.hdmiAnalyser.validateEdid(port, expected_edid) + + def sendAudioInfoFrame(self, port: int, data: list): + """ + Send an Audio Info Frame message to the HDMI input port. + + Args: + port (int): HDMI input port number. + data (list): Audio info frame data bytes. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.sendAudioInfoFrame(port, data) + + def sendAVIInfoFrame(self, port: int, data: list): + """ + Send an AVI Info Frame message to the HDMI input port. + + Args: + port (int): HDMI input port number. + data (list): AVI info frame data bytes. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.sendAVIInfoFrame(port, data) + + def sendDRMInfoFrame(self, port: int, data: list): + """ + Send a DRM Info Frame message to the HDMI input port. + + Args: + port (int): HDMI input port number. + data (list): DRM info frame data bytes. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.sendDRMInfoFrame(port, data) + + def setSignalStatus(self, port: int, signal_state: str): + """ + Set the signal status for the HDMI input port. + + Args: + port (int): HDMI input port number. + signal_state (str): Signal state string (e.g., 'LOCKED', 'NO_SIGNAL'). + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.setSignalStatus(port, signal_state) + + def sendSPDInfoFrame(self, port: int, data: list): + """ + Send an SPD Info Frame message to the HDMI input port. + + Args: + port (int): HDMI input port number. + data (list): SPD info frame data bytes. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.sendSPDInfoFrame(port, data) + + def sendVSIFInfoFrame(self, port: int, data: list): + """ + Send a Vendor Specific Info Frame message to the HDMI input port. + + Args: + port (int): HDMI input port number. + data (list): Vendor specific info frame data bytes. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.sendVSIFInfoFrame(port, data) + + def SetVIC(self, port: int, vic: str): + """ + Set the Video Identification Code (VIC) for the HDMI input port. + + Args: + port (int): HDMI input port number. + vic (str): Video Identification Code string. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.SetVIC(port, vic) + + def setVRRStatus(self, port: int, vrrActive: bool,M_CONST: bool, fastVActive: bool, frameRate: float): + """ + Abstract method to set the Variable Refresh Rate (VRR) status for the HDMI input port. + + Args: + port (int): HDMI input port number. + vrrActive (bool): VRR enabled status. + M_CONST (bool): M_CONST status. + fastVActive (bool): Fast V Active status. + frameRate (float): Frame rate value. + + Returns: + bool: True if message sent successfully. + """ + return self.hdmiAnalyser.setVRRStatus(port, vrrActive, M_CONST, fastVActive, frameRate) + + def start(self): + """ + Start the HDMI controller. + + Returns: + None + """ + return self.hdmiAnalyser.start() + + def stop(self): + """ + Stop the HDMI controller. + + Returns: + None + """ + return self.hdmiAnalyser.stop() \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_audioinfo_frame.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_audioinfo_frame.yaml new file mode 100644 index 0000000..cc8653e --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_audioinfo_frame.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: audioinfo_frame + description: Sends the audioinfo frame to HDMI input ports + params: + port: 0 + data: [0x84, 0x01, 0x0A, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_aviinfo_frame.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_aviinfo_frame.yaml new file mode 100644 index 0000000..dd053e7 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_aviinfo_frame.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: aviinfo_frame + description: Sends the AV InfoFrame to HDMI input ports + params: + port: 0 + data: [0x82, 0x02, 0x0D, 0x6F, 0x10, 0x18, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_connection_status.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_connection_status.yaml new file mode 100644 index 0000000..a663e83 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_connection_status.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: connection_status + description: Sends the connection status of HDMI input ports. + params: + port: 0 + connected: true \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_drminfo_frame.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_drminfo_frame.yaml new file mode 100644 index 0000000..04a1ff8 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_drminfo_frame.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: drminfo_frame + description: Sends the drminfo frame to HDMI input ports + params: + port: 0 + data: [0x87, 0x01, 0x1A, 0x9A, 0x02, 0x00, 0xE0, 0x03, 0x80, 0x07, 0x38, 0x04, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE8, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_hdcp_status.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_hdcp_status.yaml new file mode 100644 index 0000000..bd66b12 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_hdcp_status.yaml @@ -0,0 +1,30 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: hdcp_status + description: Sends the HDCP status of HDMI input ports. + params: + port: 0 + state: AUTHENTICATED # Possible values: UNKNOWN, UNAUTHENTICATED, + # AUTHENTICATION_IN_PROGRESS, AUTHENTICATION_FAILURE, AUTHENTICATED + version: VERSION_2_X # UNDEFINED, VERSION_1_X, VERSION_2_X \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_signal_status.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_signal_status.yaml new file mode 100644 index 0000000..4e9603e --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_signal_status.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: signal_status + description: Sends the signal status of HDMI input ports. + params: + port: 0 + state: LOCKED # Possible values: UNKNOWN, NO_SIGNAL, UNSTABLE, NOT_SUPPORTED, LOCKED \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_spdinfo_frame.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_spdinfo_frame.yaml new file mode 100644 index 0000000..013cf28 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_spdinfo_frame.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: spdinfo_frame + description: Sends the spdinfo frame to HDMI input ports + params: + port: 0 + data: [0x83, 0x01, 0x19, 0x8E, 0x4F, 0x50, 0x45, 0x4E, 0x41, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x4C, 0x55, 0x52, 0x41, 0x59, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01] \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_vendorspecificinfo_frame.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_vendorspecificinfo_frame.yaml new file mode 100644 index 0000000..27d13fc --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_vendorspecificinfo_frame.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: vsifinfo_frame + description: Sends the vendor specific info frame to HDMI input ports + params: + port: 0 + data: [0x81, 0x01, 0x0D, 0xA7, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_videoformat_change.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_videoformat_change.yaml new file mode 100644 index 0000000..63cca97 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_videoformat_change.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: videoformat_change + description: Sends the video format change to HDMI input ports + params: + port: 0 + format: VIC16_1920_1080_P_60_16_9 # Possible values: refer hdmiinput/VIC.aidl \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmiinput_vrr_status.yaml b/framework/core/hdmiAnalyserModules/commands/hdmiinput_vrr_status.yaml new file mode 100644 index 0000000..8349984 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmiinput_vrr_status.yaml @@ -0,0 +1,31 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmiinput: + command: vrr_status + description: Sends the VRR status of HDMI input ports + params: + port: 0 + vrrActive: true + M_CONST: true + fastVActive: true + frameRate: 120.0 \ No newline at end of file diff --git a/framework/core/hdmiAnalyserModules/commands/hdmioutput_edid_read.yaml b/framework/core/hdmiAnalyserModules/commands/hdmioutput_edid_read.yaml new file mode 100644 index 0000000..54c6d8f --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmioutput_edid_read.yaml @@ -0,0 +1,44 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmioutput: + command: edid_read + description: Sends the EDID read event for HDMI output port. + params: + port: 0 + data: [0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x10,0xAC,0x32,0x42,0x4C,0x4C,0x4C,0x4C, + 0x02,0x19,0x01,0x03,0x80,0x3C,0x22,0x78,0xEA,0x1E,0xC5,0xAE,0x50,0x46,0x91,0x26, + 0x0E,0x50,0x54,0xA5,0x4B,0x00,0x71,0x4F,0x81,0x80,0xA9,0x40,0xB3,0x00,0xD1,0xC0, + 0x01,0x01,0x01,0x01,0x01,0x01,0x04,0x74,0x00,0x30,0xF2,0x70,0x5A,0x80,0xB0,0x58, + 0x8A,0x00,0x50,0x1D,0x74,0x00,0x00,0x1E,0x00,0x00,0x00,0xFF,0x00,0x48,0x44,0x4D, + 0x49,0x32,0x30,0x5F,0x54,0x45,0x53,0x54,0x0A,0x20,0x00,0x00,0x00,0xFC,0x00,0x48, + 0x44,0x4D,0x49,0x20,0x32,0x2E,0x30,0x20,0x44,0x69,0x73,0x70,0x00,0x00,0x00,0xFD, + 0x00,0x38,0x4B,0x1E,0x87,0x1E,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x01,0x9A, + 0x02,0x03,0x3E,0x70,0xE3,0x05,0x03,0x01,0x02,0x03,0x04,0x05,0x90,0x23,0x09,0x07, + 0x07,0x83,0x01,0x00,0x00,0x6D,0x03,0x0C,0x00,0x20,0x00,0xB8,0x3C,0x20,0x00,0x60, + 0x01,0x02,0x03,0x67,0xD8,0x5D,0xC4,0x01,0x3C,0x03,0xE2,0x00,0x0F,0xE3,0x06,0x0D, + 0x01,0x01,0x1D,0x00,0x72,0x51,0xD0,0x1E,0x20,0x6E,0x28,0x55,0x00,0x50,0x1D,0x74, + 0x00,0x00,0x1E,0x02,0x3A,0x80,0x18,0x71,0x38,0x2D,0x40,0x58,0x2C,0x45,0x00,0x50, + 0x1D,0x74,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC1] + diff --git a/framework/core/hdmiAnalyserModules/commands/hdmioutput_frame_rate_changed.yaml b/framework/core/hdmiAnalyserModules/commands/hdmioutput_frame_rate_changed.yaml new file mode 100644 index 0000000..eb37006 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmioutput_frame_rate_changed.yaml @@ -0,0 +1,27 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmioutput: + command: frame_rate_changed + description: Sends the frame rate change event for HDMI output port. + params: + port: 0 diff --git a/framework/core/hdmiAnalyserModules/commands/hdmioutput_hdcp_status.yaml b/framework/core/hdmiAnalyserModules/commands/hdmioutput_hdcp_status.yaml new file mode 100644 index 0000000..cb97b24 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmioutput_hdcp_status.yaml @@ -0,0 +1,29 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmioutput: + command: hdcp_status + description: Sends the HDCP status change event for HDMI output port. + params: + port: 0 + status: AUTHENTICATED + version: VERSION_2_X diff --git a/framework/core/hdmiAnalyserModules/commands/hdmioutput_hotplug_state.yaml b/framework/core/hdmiAnalyserModules/commands/hdmioutput_hotplug_state.yaml new file mode 100644 index 0000000..7097678 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/commands/hdmioutput_hotplug_state.yaml @@ -0,0 +1,28 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#** ****************************************************************************** + +hdmioutput: + command: hotplug_state + description: Sends the hotplug state change event for HDMI output ports. + params: + port: 0 + connected: true diff --git a/framework/core/hdmiAnalyserModules/manualHdmiController.py b/framework/core/hdmiAnalyserModules/manualHdmiController.py new file mode 100644 index 0000000..13242b5 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/manualHdmiController.py @@ -0,0 +1,279 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#* ****************************************************************************** +from .hdmiAnalyserInterface import HDMIAnalyserInterface + +class manualHdmiController(HDMIAnalyserInterface): + def __init__(self, logger, host, user, passwd, port:int=22, prompt:str='~#', control_port:int=8080, device:str=""): + #super().__init__(logger, address, username, password, port, prompt, control_port, device) + self._log = logger + self.address = host + self.username = user + self.password = passwd + self.port = port + self.prompt = prompt + self.control_port = control_port + self.device = device + + def getUserYN(self, query: str = "Please Enter Y or N :") -> bool: + """Prompt the user for a Y/N response and return True for Y, False for N.""" + response = input(query) + while True: + if response in ('y', 'Y'): + return True + elif response in ('n', 'N'): + return False + else: + print("Invalid input. Please enter 'y/Y' for Yes or 'n/N' for No.") + response = input(query) + + def sendEDIDRead(self, port: int, data: list): + return True + + def sendFrameRateChanged(self, port: int): + return True + + def setHDCPVersion(self, port: int, hdcp_version: str): + """ + Set the HDCP version for the HDMI input port. + + Args: + port (int): HDMI input port number. + hdcp_version (str): HDCP version string. (VERSION_1_X, VERSION_2_X, UNDEFINED) + Returns: + bool: True if HDCP version set successfully. + """ + results = self.getUserYN(f"Set HDCP version '{hdcp_version}' for HDMI input port {port}? (Y/N):") + return results + + def validateEdid(self, port: int, expected_edid: list): + """ + Validate the EDID data for the HDMI input port. + + Args: + port (int): HDMI input port number. + expected_edid (list): Expected EDID data bytes. + Returns: + bool: True if EDID data matches expected values. + """ + results = self.getUserYN(f"Validate EDID data for HDMI input port {port} against expected data {expected_edid}? (Y/N):") + return results + + def sendAudioInfoFrame(self, port: int, data: list): + """ + Ask user to manually set Audio Info Frame for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set Audio Info Frame for HDMI input port {port} with data {data}? (Y/N):") + return results + + def sendAVIInfoFrame(self, port: int, data: list): + """ + Ask user to manually set AVI Info Frame for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set AVI Info Frame for HDMI input port {port} with data {data}? (Y/N):") + return results + + def sendDRMInfoFrame(self, port: int, data: list): + """ + Ask user to manually set DRM Info Frame for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set DRM Info Frame for HDMI input port {port} with data {data}? (Y/N):") + return results + + def setHotplugState(self, port: int, connected: bool, version: str): + if connected == False: + result = self.getUserYN(f"UnPlug the HDMI device of HDCP version {version} and press Y:") + else : + result = self.getUserYN(f"Plug the HDMI device of HDCP version {version} and press Y:") + return result + + def setHDCPStatus(self, port: int, status: str, version: str): + """ + Ask user to manually set HDCP status for the HDMI input port and confirm. + """ + if self.device == "source": + results = self.getUserYN(f"Set HDCP status '{status}' (version: {version}) for HDMI input port {port}? (Y/N):") + return results + else: + return True # For sink devices. + + def setSignalStatus(self, port: int, signal_state: str): + """ + Ask user to manually set signal status for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set signal status '{signal_state}' for HDMI input port {port}? (Y/N):") + return results + + def sendSPDInfoFrame(self, port: int, data: list): + """ + Ask user to manually set SPD Info Frame for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set SPD Info Frame for HDMI input port {port} with data {data}? (Y/N):") + return results + + def sendVSIFInfoFrame(self, port: int, data: list): + """ + Ask user to manually set Vendor Specific Info Frame for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set Vendor Specific Info Frame for HDMI input port {port} with data {data}? (Y/N):") + return results + + def SetVIC(self, port: int, vic: str): + """ + Ask user to manually set VIC for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set VIC '{vic}' for HDMI input port {port}? (Y/N):") + return results + + def setVRRStatus(self, port: int, vrrActive: bool, M_CONST: bool, fastVActive: bool, frameRate: float): + """ + Ask user to manually set VRR status for the HDMI input port and confirm. + """ + results = self.getUserYN(f"Set VRR status for HDMI input port {port} with vrrActive={vrrActive}, M_CONST={M_CONST}, fastVActive={fastVActive}, frameRate={frameRate}? (Y/N):") + return results + + def start(self): + """ + Start the manual HDMI controller (stub). + + Returns: + None + """ + pass + + def stop(self): + """ + Stop the manual HDMI controller (stub). + + Returns: + None + """ + pass + + # ── Connection / lifecycle ────────────────────────────────────────── + + def connect(self): + return True + + def disconnect(self): + return True + + # ── Port selection ────────────────────────────────────────────────── + + def select_port(self, port): + return True + + # ── Hot-plug control ──────────────────────────────────────────────── + + def set_hpd(self, state: bool, duration: int = 100): + return True + + # ── Generator (source) operations ─────────────────────────────────── + + def set_video_format(self, format_name: str, colour_space: str = None, + subsampling: str = None, bit_depth: int = None, + vic: int = None): + return True + + def set_hdr_mode(self, mode: str): + # HDR is signalled via the DRM InfoFrame; configure via InfoFrame + # type control. The caller is expected to use configInfoFrame and + # updateFormatParameters for full DRM control. This helper enables + # or disables the HDR InfoFrame packet. + return True + + def set_allm(self, enabled: bool): + # ALLM is signalled via the HDMI Forum VSIF (ALLM bit). + # Toggle the HDMI Forum VS InfoFrame accordingly. + return True + + def set_vrr(self, enabled: bool, base_refresh_rate: int = None): + # VRR is signalled via the Video Timing Extended Metadata (VTEM) + # packet on the generator side. + return True + + def set_avi_content_type(self, content_type: str): + # Content type is part of the AVI InfoFrame (ITC/CN fields). + # Update via format parameters. + pass + + def set_spd_info(self, vendor: str, description: str): + # SPD InfoFrame configuration. + return True + + def start_output(self): + return True + + def stop_output(self): + return True + + # ── EDID operations ───────────────────────────────────────────────── + + def get_edid(self, port: str = "") -> bytes: + # The ATP API does not expose a direct "read-back EDID bytes" + # from the sink side in a simple getter. The EDID read-back + # typically occurs through the compliance test infrastructure. + # Return empty bytes as placeholder. + return b"" + + def set_edid(self, edid_data: str, hp_duration_ms: int = 100): + return True + + + def restore_default_edid(self, port: str = ""): + # Re-apply hot-plug with no custom EDID to revert to built-in EDID. + return True + + # ── Analyser (sink) read-back ─────────────────────────────────────── + + def get_video_status(self) -> dict: + result = {} + return result + + def get_audio_status(self) -> dict: + return {} + + def get_hdcp_status(self) -> dict: + # Attempt to read HDCP for both modes and return whichever is active. + return {} + + def get_link_status(self) -> dict: + return {} + + def get_avi_info(self) -> dict: + return {} + + def get_spd_info(self) -> dict: + return {} + + def get_background_color(self) -> str: + return "" + + # ── HDCP control ──────────────────────────────────────────────────── + + def set_hdcp_mode(self, mode: str): + pass + + # ── Snapshot / combined status ────────────────────────────────────── + + def snapshot(self) -> dict: + return {} diff --git a/framework/core/hdmiAnalyserModules/virtualHdmiController.py b/framework/core/hdmiAnalyserModules/virtualHdmiController.py new file mode 100644 index 0000000..4cf5836 --- /dev/null +++ b/framework/core/hdmiAnalyserModules/virtualHdmiController.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2026 RDK Management +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * +# http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#* ****************************************************************************** +import os +import sys +import yaml +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(dir_path) +#sys.path.append(os.path.join(dir_path, "../../tests/raft/")) + +command_templates_dir = os.path.join(dir_path, 'commands') +EDID_READ_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmioutput_edid_read.yaml') +FRAME_RATE_CHANGED_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmioutput_frame_rate_changed.yaml') +HDMIOUT_HDCP_STATUS_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmioutput_hdcp_status.yaml') +HPD_STATUS_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmioutput_hotplug_state.yaml') + +##### HDMIINPUT ##### +AUDIO_INFOFRAME_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_audioinfo_frame.yaml') +AVI_INFOFRAME_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_aviinfo_frame.yaml') +DRM_INFOFRAME_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_drminfo_frame.yaml') +CONNECTION_STATUS_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_connection_status.yaml') +HDCP_STATUS_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_hdcp_status.yaml') +SIGNAL_STATUS_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_signal_status.yaml') +SPD_INFOFRAME_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_spdinfo_frame.yaml') +VENDOR_SPECIFIC_INFOFRAME_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_vendorspecificinfo_frame.yaml') +VIDEO_FORMAT_CHANGE_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_videoformat_change.yaml') +VRR_STATUS_CMD_TEMPLATE = os.path.join(command_templates_dir, 'hdmiinput_vrr_status.yaml') + +from .hdmiAnalyserInterface import HDMIAnalyserInterface +from framework.core.commandModules.sshConsole import sshConsole +from framework.core.utPlaneController import utPlaneController + +class virtualHdmiController(HDMIAnalyserInterface): + def __init__(self, logger, host, user, passwd, port:int=22, prompt:str='~#', control_port:int=8080, device:str=""): + #super().__init__(logger, host, user, passwd, port, prompt, control_port, device) + self._log = logger + self.address = host + self.username = user + self.password = passwd + self.port = port + self.prompt = prompt + self.control_port = control_port + self.analyserdevice = device + self.session = sshConsole(self._log, self.address, self.username, self.password, port=self.port, prompt=self.prompt) + self.utPlaneController = utPlaneController(self.session, port=self.control_port) + + # ── HDMI output Events ────────────────────────────────────────── + def sendEDIDRead(self, port: int, data: list): + with open(EDID_READ_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmioutput']['params']['port'] = port + msg['hdmioutput']['params']['data'] = data + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + + def sendFrameRateChanged(self, port: int): + with open(FRAME_RATE_CHANGED_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmioutput']['params']['port'] = port + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + + def setHDCPStatus(self, port: int, status: str, version: str): + if self.analyserdevice == "sink": + with open(HDMIOUT_HDCP_STATUS_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmioutput']['params']['port'] = port + msg['hdmioutput']['params']['status'] = status + msg['hdmioutput']['params']['version'] = version + elif self.analyserdevice == "source": + with open(HDCP_STATUS_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['state'] = status + msg['hdmiinput']['params']['version'] = version + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def setHotplugState(self, port: int, connected: bool, version: str): + if self.analyserdevice == "sink": + with open(HPD_STATUS_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmioutput']['params']['port'] = port + msg['hdmioutput']['params']['connected'] = connected + elif self.analyserdevice == "source": + with open(CONNECTION_STATUS_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['connected'] = connected + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + + def sendDRMInfoFrame(self, port: int, data: list): + """ + Send a DRM Info Frame message to the HDMI input port using a YAML template. + """ + with open(DRM_INFOFRAME_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['data'] = data + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def setSignalStatus(self, port: int, signal_state: str): + """ + Set the signal status for the HDMI input port using a YAML template. + """ + with open(SIGNAL_STATUS_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['state'] = signal_state + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def sendSPDInfoFrame(self, port: int, data: list): + """ + Send an SPD Info Frame message to the HDMI input port using a YAML template. + """ + with open(SPD_INFOFRAME_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['data'] = data + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def validateEdid(self, port: int, expected_edid: list): + """ + Validate the EDID data for the HDMI input port. + + Args: + port (int): HDMI input port number. + expected_edid (list): Expected EDID data bytes. + Returns: + bool: True if EDID data matches expected values. + """ + print(f"Validate EDID for HDMI input port {port} with expected data {expected_edid} Done") + return True + + def sendAudioInfoFrame(self, port: int, data: list): + """ + Send an Audio Info Frame message to the HDMI input port using a YAML template. + """ + with open(AUDIO_INFOFRAME_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['data'] = data + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def sendAVIInfoFrame(self, port: int, data: list): + """ + Send an AVI Info Frame message to the HDMI input port using a YAML template. + """ + with open(AVI_INFOFRAME_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['data'] = data + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def sendVSIFInfoFrame(self, port: int, data: list): + """ + Send a Vendor Specific Info Frame message to the HDMI input port using a YAML template. + """ + with open(VENDOR_SPECIFIC_INFOFRAME_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['data'] = data + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def SetVIC(self, port: int, vic: str): + """ + Set the Video Identification Code (VIC) for the HDMI input port using a YAML template. + """ + with open(VIDEO_FORMAT_CHANGE_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['format'] = vic + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def setVRRStatus(self, port: int, vrrActive: bool,M_CONST: bool, fastVActive: bool, frameRate: float): + """ + Set the Variable Refresh Rate (VRR) status for the HDMI input port using a YAML template. + """ + with open(VRR_STATUS_CMD_TEMPLATE, 'r') as f: + msg = yaml.safe_load(f) + msg['hdmiinput']['params']['port'] = port + msg['hdmiinput']['params']['vrrActive'] = vrrActive + msg['hdmiinput']['params']['M_CONST'] = M_CONST + msg['hdmiinput']['params']['fastVActive'] = fastVActive + msg['hdmiinput']['params']['frameRate'] = frameRate + yaml_str = yaml.dump(msg) + return self.utPlaneController.sendMessage(yaml_str) + + def setHDCPVersion(self, port: int, hdcp_version: str): + """ + Set the HDCP version for the HDMI input port. + + Args: + port (int): HDMI input port number. + hdcp_version (str): HDCP version string. (VERSION_1_X, VERSION_2_X, UNDEFINED) + Returns: + bool: True if HDCP version set successfully. + """ + print(f"SetHDCP version '{hdcp_version}' for HDMI input port {port} Done") + return True + + def start(self): + """ + Start the virtual HDMI controller (stub). + + Returns: + None + """ + pass + + def stop(self): + """ + Stop the virtual HDMI controller (stub). + + Returns: + None + """ + pass + + # ── Connection / lifecycle ────────────────────────────────────────── + + def connect(self): + return True + + def disconnect(self): + return True + + # ── Port selection ────────────────────────────────────────────────── + + def select_port(self, port): + return True + + # ── Hot-plug control ──────────────────────────────────────────────── + + def set_hpd(self, state: bool, duration: int = 100): + return True + + # ── Generator (source) operations ─────────────────────────────────── + + def set_video_format(self, format_name: str, colour_space: str = None, + subsampling: str = None, bit_depth: int = None, + vic: int = None): + return True + + def set_hdr_mode(self, mode: str): + # HDR is signalled via the DRM InfoFrame; configure via InfoFrame + # type control. The caller is expected to use configInfoFrame and + # updateFormatParameters for full DRM control. This helper enables + # or disables the HDR InfoFrame packet. + return True + + def set_allm(self, enabled: bool): + # ALLM is signalled via the HDMI Forum VSIF (ALLM bit). + # Toggle the HDMI Forum VS InfoFrame accordingly. + return True + + def set_vrr(self, enabled: bool, base_refresh_rate: int = None): + # VRR is signalled via the Video Timing Extended Metadata (VTEM) + # packet on the generator side. + return True + + def set_avi_content_type(self, content_type: str): + # Content type is part of the AVI InfoFrame (ITC/CN fields). + # Update via format parameters. + pass + + def set_spd_info(self, vendor: str, description: str): + # SPD InfoFrame configuration. + return True + + def start_output(self): + return True + + def stop_output(self): + return True + + # ── EDID operations ───────────────────────────────────────────────── + + def get_edid(self, port: str = "") -> bytes: + # The ATP API does not expose a direct "read-back EDID bytes" + # from the sink side in a simple getter. The EDID read-back + # typically occurs through the compliance test infrastructure. + # Return empty bytes as placeholder. + return b"" + + def set_edid(self, edid_data: str, hp_duration_ms: int = 100): + return True + + def restore_default_edid(self, port: str = ""): + # Re-apply hot-plug with no custom EDID to revert to built-in EDID. + return True + + # ── Analyser (sink) read-back ─────────────────────────────────────── + + def get_video_status(self) -> dict: + result = {} + return result + + def get_audio_status(self) -> dict: + return {} + + def get_hdcp_status(self) -> dict: + # Attempt to read HDCP for both modes and return whichever is active. + return {} + + def get_link_status(self) -> dict: + return {} + + def get_avi_info(self) -> dict: + return {} + + def get_spd_info(self) -> dict: + return {} + + def get_background_color(self) -> str: + return "" + + # ── HDCP control ──────────────────────────────────────────────────── + + def set_hdcp_mode(self, mode: str): + pass + + # ── Snapshot / combined status ────────────────────────────────────── + + def snapshot(self) -> dict: + return {} diff --git a/framework/core/testControl.py b/framework/core/testControl.py index cbe230b..9c53d40 100644 --- a/framework/core/testControl.py +++ b/framework/core/testControl.py @@ -156,6 +156,7 @@ def __init__(self, testName="", qcId="", maxRunTime=TEST_MAX_RUN_TIME, level=log self.powerControl = self.dut.powerControl self.commonRemote = self.dut.remoteController self.hdmiCECController = self.dut.hdmiCECController + self.hdmiAnalyserController = self.dut.hdmiAnalyserController self.utils = utilities(self.log) # For UI tests Initialising Video capture and decode the screen_regions.yml for the platform cpePlatform = self.slotInfo.getPlatform()