diff --git a/CHANGELOG.md b/CHANGELOG.md index f2ef5df..ce00fe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,14 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.3.3](https://github.com/rdkcentral/rdk-halif-test-hdmi_cec/compare/1.3.2...1.3.3) + +- gh #61 l1 logic update fix [`#60`](https://github.com/rdkcentral/rdk-halif-test-hdmi_cec/pull/60) + #### [1.3.2](https://github.com/rdkcentral/rdk-halif-test-hdmi_cec/compare/1.3.1...1.3.2) +> 5 November 2024 + - gh #58 Issue fix L1 and L2 [`#59`](https://github.com/rdkcentral/rdk-halif-test-hdmi_cec/pull/59) - gh #41 Support State commands (AddDevice, RemoveDevice, PrintStatus) [`#46`](https://github.com/rdkcentral/rdk-halif-test-hdmi_cec/pull/46) - Fixed #50 : updated activate & added test_helper [`#50`](https://github.com/rdkcentral/rdk-halif-test-hdmi_cec/issues/50) diff --git a/build.sh b/build.sh index 6b77cee..fa44309 100755 --- a/build.sh +++ b/build.sh @@ -28,7 +28,7 @@ NC="\e[39m" # When the major version changes in the ut-core, what that signals is that the testings will have to be upgraded to support that version # Therefore in that case it warns you but doesnt' chnage to that version, which could cause your tests to break. # Change this to upgrade your UT-Core Major versions. Non ABI Changes 1.x.x are supported, between major revisions -UT_PROJECT_MAJOR_VERSION="3." +UT_PROJECT_MAJOR_VERSION="4." # Clone the Unit Test Requirements TEST_REPO=git@github.com:rdkcentral/ut-core.git diff --git a/docs/pages/hdmi-cec-source_L3_Low-level_TestSpec.md b/docs/pages/hdmi-cec-source_L3_Low-level_TestSpec.md new file mode 100644 index 0000000..a3a7589 --- /dev/null +++ b/docs/pages/hdmi-cec-source_L3_Low-level_TestSpec.md @@ -0,0 +1,60 @@ +# HDMICEC Source L3 Low Level Test Specification and Procedure Documentation + +## Table of Contents + +- [Overview](#overview) +- [Acronyms, Terms and Abbreviations](#acronyms-terms-and-abbreviations) +- [References](#references) +- [Level 3 Test cases High Level Overview](#level-3-test-cases-high-level-overview) +- [Level 3 Python Test Cases High Level Overview](#level-3-python-test-cases-high-level-overview) + +## Overview + +This document describes the L3 Low Level Test Specification and Procedure Documentation for the Device Settings Video Port module. + +### Acronyms, Terms and Abbreviations + +- `HAL` \- Hardware Abstraction Layer, may include some common components +- `UT` \- Unit Test(s) +- `OEM` \- Original Equipment Manufacture +- `SoC` \- System on a Chip +- `HDMI`\- High-Definition Multimedia Interface +- `HDCP`\- High-bandwidth Digital Content Protection +- `HDR` \- High Dynamic Range +- `HLG` \- Hybrid Log-Gamma +- `SDR` \- Standard Dynamic Range +- `Y` \- yes supported +- `NA` \- Not Supported + +### References + +- The interface of the test is available here: [Hdmicec HAL header](https://github.com/rdkcentral/rdk-halif-hdmi_cec/blob/main/include/hdmi_cec_driver.h) + +- The Hdmicec Hal Spec document: [Hdmicec HAL Spec](https://github.com/rdkcentral/rdk-halif-hdmi_cec/blob/main/docs/pages/hdmi-cec_halSpec.md) + +## Level 3 Test Cases High Level Overview + +|#|Test-case|Description|HAL APIs| +|-|---------|-----------|--------| +|1|Validate logical address|Connect port, and validate that the connected logical address is 4, 8, or 11.| `HdmiCecOpen()`,`HdmiCecGetLogicalAddress()` | +|2|Connect too many devices|Connect five other source devices to sink device using raft, before connecting the testing device. should return HDMI_CEC_IO_LOGICALADDRESS_UNAVAILABLE as there is not a valid logical address.| `HdmiCecOpen()` | +|3|Rapid connection|Rapidly connect and disconnect HDMI connection in 100ms connection and 100ms disconnection cycle.| `HdmiCecOpen()` | +|4|Connect Physical Address | Enable a sink device connected to the DUT first to get the valid physical address allocated through the HAL function. The physical address should be 1.0.0.0 | `HdmiCecGetPhysicalAddress()` | +|5|Connect Physical Address with switch| EVerify the physical addresses allocated by connecting a source and sink device through an HDMI switch. The physical address should 1.1.0.0 | `HdmiCecGetPhysicalAddress()` | +|6|Reconnect physical address| Connect a sink device to the source device, get the physical address. Disconnect the sink device and attempt to get the physical address again | `HdmiCecGetPhysicalAddress()` | +|7|Transmit to invalid address|Transmit a CEC Command (as per 1.4b HDMI CEC spec) to get the CEC Version for a logical address that doesn't exist after the connected device is disconnected. Result should return HDMI_CEC_IO_SENT_BUT_NOT_ACKD.| `HdmiCecTx()` | +|8|Transmit after disconnection|Transmit a CEC Command (as per 1.4b HDMI CEC spec) to get the CEC Version for supported CEC commands (as per 1.4b HDMI CEC spec) after the connected device is disconnected. Result should return HDMI_CEC_IO_SENT_BUT_NOT_ACKD.| `HdmiCecTx()` | +|9|Transmit while connected|Verify the correct transmission of the supported CEC commands (as per 1.4b HDMI CEC spec) to the connected device and ensure it is acknowledged properly. The result should return HDMI_CEC_IO_SENT_AND_ACKD.| `HdmiCecTx()` | +|10|Transmit to all|Broadcast a supported CEC Command to all the devices connected to the network without any error. The result should return HDMI_CEC_IO_SENT_AND_ACKD| `HdmiCecTx()` | +|11|Transmit to standby.|Transmit a CEC Command (as per 1.4b HDMI CEC spec) to put the connected device into standby mode and await the device's response. Monitoring the behavior of the connected device accordingly. The result should return HDMI_CEC_IO_SENT_AND_ACKD.| `HdmiCecTx()` | +|12|Send command and receive response|Transmit a CEC Command that expects a response (Eg. GetCECVersion) to a connected device and see the response is received correctly. Set the Rx Callback before sending the data. Validate the received CEC Version.| `HdmiCecSetRxCallback()` `HdmiCecTx()` | +|13|Receive command and send response|Transmit a CEC command from the connected devices and consider the Acknowledgement and responses are received correctly from the host device (DUT TV here)| `HdmiCecSetRxCallback()`| +|14|Transmit OSD Command|Transmit an OSD CEC command from the connected devices and consider the Acknowledgement and responses are received correctly from the host device (DUT TV here). Make the OSD String to max length| `HdmiCecSetRxCallback()`| +|15|Transmit OSD Command continuously|Transmit an OSD CEC command from the connected devices continuously for 30 seconds changing the patterns in the payload and considering the Acknowledgement and responses are received correctly from the host device (DUT TV here). Make the OSD String to max length| `HdmiCecSetRxCallback()`| +|16|Transmit logical 0|Set the Logical address to 0 on DUT and make sure that it doesn't receive the messages sent to devices with different logical address.| `HdmiCecSetRxCallback()`| +|17|Hotplug event|Generate a Hotplug event by disconnecting the device connected to the HDMI port of the Source Platform. Validating whether the CEC Transmission (use Polling command) works when the HDMI port is disconnected should result in ACK not being received while the TX still works as expected.| `HdmiCecTx()`| +|18|Hotplug event not-acked|Check the behaviour when a device has been remove from the network which is not directly connected to the TV device. Send a CEC Tx command with acknowledgment using HAL Interface and check the behaviour. The Tx command should succeed, but the message should not be Acknowledged.| `HdmiCecTx()`| +|19|Hardware bus failure|Observe the behaviour when the CEC line is pulled high during the CEC Transmission using a CEC Adaptor that provision to keep the CEC line pulled high |`HdmiCecTx()`| +|20|Hardware bus overload|Overload the CEC bus with too many messages (by connecting more devices in the network) and observe the behaviour. |`HdmiCecTx()`| + +## Level 3 Python Test Cases High Level Overview diff --git a/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSourceHelperClass.py b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSourceHelperClass.py new file mode 100644 index 0000000..3df9fe8 --- /dev/null +++ b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSourceHelperClass.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2024 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 + +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(dir_path, "../../")) +sys.path.append(os.path.join(dir_path, "../")) + +from raft.framework.plugins.ut_raft.configRead import ConfigRead +from raft.framework.plugins.ut_raft.utUserResponse import utUserResponse +from raft.framework.plugins.ut_raft import utHelperClass +from raft.framework.core.logModule import logModule +from classes.hdmiCEC import hdmiCECClass + +class hdmiCECHelperClass(utHelperClass): + + """ + Helper class for managing HDMI CEC tests. + This class extends the `utHelperClass` and provides functionality for preparing + and cleaning up HDMI CEC tests. + """ + + def __init__(self, testName:str, qcId:str, log:logModule=None ): + """ + Initializes the test helper class with test name, setup configuration, and session management. + Args: + testName (str): Name of the test. + qcId (str): Quality Control (QC) ID of the test. + log (logModule, optional): Parent log module instance for logging. Defaults to None. + """ + self.testName = "" + self.moduleName = "hdmicec" + self.rackDevice = "dut" + + # Initialize the base helper class + super().__init__(testName, qcId, log) + + # Open Sessions hal test + self.hal_session = self.dut.getConsoleSession("ssh_hal_test") + + deviceTestSetup = self.cpe.get("test") + + # Create user response Class + self.testUserResponse = utUserResponse() + + # Get path to device profile file + self.moduleConfigProfileFile = os.path.join(dir_path, deviceTestSetup.get("profile")) + + self.targetWorkspace = self.cpe.get("target_directory") + self.targetWorkspace = os.path.join(self.targetWorkspace, self.moduleName) + + self.testCECCommands = os.path.join(dir_path, "hdmiCECTestCommands.yml") + hdmicec = ConfigRead(self.testCECCommands, self.moduleName) + self.cecCommands = hdmicec.fields.get(self.testName) + + def testPrepareFunction(self): + """ + Cleans up the test environment by deinitializing the HDMI CEC instance. + Args: + powerOff (bool, optional): Flag to indicate whether to power off the device. Defaults to True. + Returns: + bool + """ + + # Create the hdmiCEC class + self.testhdmiCEC = hdmiCECClass(self.moduleConfigProfileFile, self.hal_session, self.targetWorkspace) + + return True + + def testEndFunction(self, powerOff=True): + + super().testEndFunction(powerOff) + # Clean up the hdmiCEC instance + del self.testhdmiCEC \ No newline at end of file diff --git a/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSourceTestCommands.yml b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSourceTestCommands.yml new file mode 100644 index 0000000..25509d3 --- /dev/null +++ b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSourceTestCommands.yml @@ -0,0 +1,94 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2024 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. +# * +#* ****************************************************************************** + +hdmicec: + test01_TransmitCECCommands: + - command: "0x82" # Active Soruce + payload: ["0x00", "0x00"] + type: "Broadcast" + - command: "0x90" # "Report power status + payload: ["0x00"] + type: "Direct" + response: null + - command: "0x47" # Give OSD Name + payload: ['0x52', '0x44', '0x4b', '0x20', '0x56', '0x54', '0x53', '0x20', '0x44', '0x65', '0x76', '0x69', '0x63', '0x65'] + type: "Direct" + response: null + test02_ReceiveCECCommands: + - command: "0x04" # Image View on + payload: + type: "Direct" + response: null + - command: "0x85" # Request Active source + payload: + type: "Broadcast" + response: + type: "Broadcast" + command: "0x82" + update_payload: true + payload: ["0x00", "0x00"] + description: "Active Soruce" + - command: "0x91" # Get Menu Language + payload: + type: "Direct" + response: + type: "Broadcast" + command: "0x32" + update_payload: false + payload: ["0x65", "0x6E", "0x67"] + description: "Set Menu Language" + - command: "0x8C" # Give Vendor ID + payload: + type: "Direct" + response: + type: "Broadcast" + command: "0x87" + update_payload: false + payload: ["0x00", "0x00","0x01"] + description: "Device Vendor Id" + - command: "0x8F" # Give power status + payload: + type: "Direct" + response: + type: "Direct" + command: "0x90" + update_payload: false + payload: ["0x00"] + description: "Report power status" + - command: "0x9F" # Get CEC version + payload: + type: "Direct" + response: + type: "Direct" + command: "0x9E" + update_payload: false + payload: ["0x05"] + description: "Device request for CEC version" + - command: "0x46" # Give OSD Name + payload: + type: "Direct" + response: + type: "Direct" + command: "0x47" + update_payload: false + payload: ['0x52', '0x44', '0x4b', '0x20', '0x56', '0x54', '0x53', '0x20', '0x44', '0x65', '0x76', '0x69', '0x63', '0x65'] + description: "Device request OSD name" \ No newline at end of file diff --git a/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_L3_Runall.py b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_L3_Runall.py new file mode 100644 index 0000000..05748ec --- /dev/null +++ b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_L3_Runall.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2024 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 importlib +from pathlib import Path + +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(dir_path)) +sys.path.append(os.path.join(dir_path, "../")) +sys.path.append(os.path.join(dir_path, "../raft")) + +from raft.framework.core.logModule import logModule + +def Runall_L3(): + skipTests = [] + # Summery log for all the tests + hdmiCECSummerLog = logModule("hdmiCEC_Sink", level=logModule.INFO) + + testDirectory = Path(dir_path) + + # Find all test modules in the directory + test_modules = sorted(testDirectory.glob("hdmiCEC_test*.py")) + + # Run each test by dynamically importing and instantiating + for test_module_path in test_modules: + # Construct module name from file name, excluding .py extension + module_name = test_module_path.stem + skip = False + for skipTest in skipTests: + if skipTest in module_name: + skip = True + break + if skip: + continue + try: + # Dynamically import the module + module = importlib.import_module(module_name) + + # Dynamically access the test class from the module + # Assuming each test file has only one class named the same as the module + test_class = getattr(module, module_name) + + # Instantiate and run the test + test_instance = test_class(hdmiCECSummerLog) + test_instance.run(False) + + except (ImportError, AttributeError) as e: + hdmiCECSummerLog.error(f"Failed to import {module_name}: {e}") + +if __name__ == '__main__': + Runall_L3() \ No newline at end of file diff --git a/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test01_TransmitCECCommands.py b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test01_TransmitCECCommands.py new file mode 100644 index 0000000..9810002 --- /dev/null +++ b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test01_TransmitCECCommands.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2024 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 time + +# Append the current and parent directory paths to sys.path for module imports +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(dir_path)) +sys.path.append(os.path.join(dir_path, "../")) + +# Importing helper classes and modules for HDMI-CEC testing and logging +from hdmiCECHelperClass import hdmiCECHelperClass +from raft.framework.core.logModule import logModule + +class hdmiCEC_test01_TransmitCECCommands(hdmiCECHelperClass): + """ + A class for testing HDMI-CEC functionality by transmitting and verifying CEC commands. + """ + def __init__(self, log:logModule=None): + """ + Initializes the test class with test-specific configurations. + Args: + log (logModule): Logging module instance to record test execution. + """ + # Class variables + self.testName = "test01_TransmitCECCommands" + self.qcID = '1' + self.tvLogicalAddress = '0' + self.broadcastAddress = 'f' + + # Initialize the parent class + super().__init__(self.testName, self.qcID, log) + + def testFunction(self): + """ + Main test function for transmitting HDMI-CEC commands and validating responses. + Steps: + 1. Initialize HDMI-CEC module. + 2. Add a logical address to the test device. + 3. Get the logical address of the device. + 4. List all connected CEC devices. + 5. Iterate through devices and send commands to appropriate logical addresses. + 6. Validate transmission and record results. + 7. Clean up by removing logical addresses and terminating the HDMI-CEC module. + Returns: + bool: Final result of the test execution. + """ + + # Initialize the hdmiCEC module + self.testhdmiCEC.initialise() + + # Get the logical Address. + deviceLogicalAddress = self.testhdmiCEC.getLogicalAddress() + + # List all connected CEC devices + self.cecDevices = self.hdmiCECController.listDevices() + + # Final test result + finalResult = True + + self.hdmiCECController.startMonitoring() + + for device in self.cecDevices: + logicalAddress = device["logical address"] + + # Skip sending messages to TV + if logicalAddress == '0' or logicalAddress == 'e': + continue + + for command in self.cecCommands: + result = False + cec = command.get("command") + payload = command.get("payload") + type = command.get("type") + + # Determine the destination logical address + destinationLogicalAddress = logicalAddress + if type == "Broadcast": + destinationLogicalAddress = self.broadcastAddress + + # Transmit the CEC command + self.testhdmiCEC.cecTransmitCmd(destinationLogicalAddress, cec, payload) + + time.sleep(2) + + self.log.stepStart(f'HdmiCecTx Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cec} Payload: {payload}') + + # Validate the transmission + result = self.hdmiCECController.checkTransmitStatus(deviceLogicalAddress, destinationLogicalAddress, cec, payload) + + self.log.stepResult(result, f'HdmiCecTx Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cec} Payload: {payload}') + + finalResult &= result + + self.hdmiCECController.stopMonitoring() + + # Remove the Logical Address + self.testhdmiCEC.removeLogicalAddress() + + # Terminate the hdmiCEC Module + self.testhdmiCEC.terminate() + + return finalResult + +if __name__ == '__main__': + # Configure the summary log file + summerLogName = os.path.splitext(os.path.basename(__file__))[0] + "_summery" + summeryLog = logModule(summerLogName, level=logModule.INFO) + + # Create an instance of the test class and execute the test + test = hdmiCEC_test01_TransmitCECCommands(summeryLog) + test.run(False) \ No newline at end of file diff --git a/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test02_ReceiveCECCommands.py b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test02_ReceiveCECCommands.py new file mode 100644 index 0000000..59da651 --- /dev/null +++ b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test02_ReceiveCECCommands.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2024 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 + +# Append the current and parent directory paths to sys.path for module imports +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(dir_path)) +sys.path.append(os.path.join(dir_path, "../")) + +from hdmiCECHelperClass import hdmiCECHelperClass +from raft.framework.core.logModule import logModule +from raft.framework.plugins.ut_raft.configRead import ConfigRead + +class hdmiCEC_test02_ReceiveCECCommands(hdmiCECHelperClass): + """ + A class for testing HDMI-CEC functionality by sending CEC commands + and verifying the received callback data. + """ + def __init__(self, log:logModule=None): + """ + Initializes the test class with test-specific configurations. + Args: + log (logModule): Logging module instance to record test execution. + """ + # Class variables + self.testName = "test02_ReceiveCECCommands" + self.qcID = '2' + self.tvLogicalAddress = '0' + self.broadcastAddress = 'f' + + # Initialize the parent class + super().__init__(self.testName, self.qcID, log) + + def testVerifyReceivedData(self, callbackData:dict, initiatorLogicalAddress:int, destinationLogicalAddress:int, opCode:str, payload:list): + """ + Verifies the received callback data. + Args: + callbackData(dict): callback data received + initiatorLogicalAddress(int): Initiator logical address + destinationLogicalAddress(int): Destination logical address + opCode (str): opcode sent + payload (str): Payload Sent + Returns: + bool: Final result of the test. + """ + result = False + for received in callbackData["Received"]: + # Check if initiator, destination, and opcode match the expected values + if (received["Initiator"] == initiatorLogicalAddress and + received["Destination"] == destinationLogicalAddress and + received["Opcode"] == opCode): + result = True + # Verify payload if provided + if payload: + for rec, sent in zip(received["Data"][2:], payload): + if rec != sent: + result = False + break + return result + + def testFunction(self): + """ + Main test function to send CEC commands and validate received callback data. + Steps: + 1. Initialize HDMI-CEC module. + 2. Add and retrieve logical address of the device. + 3. Send commands to other devices and validate responses using callback data. + 4. Validate response commands if specified. + 5. Clean up by removing logical addresses and terminating the module. + Returns: + bool: Final result of the test execution. + """ + + # Initialize the hdmiCEC module + self.testhdmiCEC.initialise() + + # Get the logical Address. + deviceLogicalAddress = self.testhdmiCEC.getLogicalAddress() + + # Ensure the logical address is retrieved successfully + if deviceLogicalAddress is None: + self.log.error("Failed to get the device logical address") + return False + + # Retrieve details of the HDMI-CEC adapter + self.cecAdaptor = self.hdmiCECController.adaptorDetails + + if self.cecAdaptor is None: + return False + + # Get the logical address of the HDMI-CEC adapter + cecAdapterLogicalAddress = self.cecAdaptor["logical address"] + + self.hdmiCECController.startMonitoring() + finalResult = True + for command in self.cecCommands: + result = False + cecOpcode = command.get("command") + payload = command.get("payload") + response = command.get("response") + type = command.get("type") + + # Determine the destination logical address + destinationLogicalAddress = deviceLogicalAddress + if type == "Broadcast": + destinationLogicalAddress = self.broadcastAddress + + self.log.stepStart(f'Send Test: {cecAdapterLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cecOpcode} Payload: {payload}') + + self.hdmiCECController.sendMessage(cecAdapterLogicalAddress, destinationLogicalAddress, cecOpcode, payload) + + # Read the callback details and verify the received data + callbackData = self.testhdmiCEC.readCallbackDetails() + result = self.testVerifyReceivedData(callbackData, cecAdapterLogicalAddress, destinationLogicalAddress, cecOpcode, payload) + + finalResult &= result + + self.log.stepResult(result, f'Send Test: {cecAdapterLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cecOpcode} Payload: {payload}') + + # If a response is expected, validate the response + if response: + destinationLogicalAddress = cecAdapterLogicalAddress + if response.get("type") == "Broadcast": + destinationLogicalAddress = self.broadcastAddress + + cecOpcode = response.get("command") + payload = response.get("payload") + + self.log.stepStart(f'Response Test: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cecOpcode} Payload: {payload}') + result = self.hdmiCECController.checkTransmitStatus(deviceLogicalAddress, destinationLogicalAddress, cecOpcode, payload) + self.log.stepResult(result, f'Response Test: {cecAdapterLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cecOpcode} Payload: {payload}') + + finalResult &= result + + self.hdmiCECController.stopMonitoring() + + # Remove the Logical Address + self.testhdmiCEC.removeLogicalAddress() + + # Terminate the hdmiCEC module + self.testhdmiCEC.terminate() + + return finalResult + +if __name__ == '__main__': + # Configure the summary log file + summerLogName = os.path.splitext(os.path.basename(__file__))[0] + "_summery" + summeryLog = logModule(summerLogName, level=logModule.INFO) + + # Create an instance of the test class and execute the test + test = hdmiCEC_test02_ReceiveCECCommands(summeryLog) + test.run(False) \ No newline at end of file diff --git a/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test03_TooManyConnectedDevices.py b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test03_TooManyConnectedDevices.py new file mode 100644 index 0000000..979fcb3 --- /dev/null +++ b/host/tests/hdmiCEC_Source_L3_Tests/hdmiCECSource_test03_TooManyConnectedDevices.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2024 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 + +# Append the current and parent directory paths to sys.path for module imports +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(dir_path)) +sys.path.append(os.path.join(dir_path, "../")) + +from hdmiCECHelperClass import hdmiCECHelperClass +from raft.framework.core.logModule import logModule +from raft.framework.plugins.ut_raft.configRead import ConfigRead + +class hdmiCEC_test02_ReceiveCECCommands(hdmiCECHelperClass): + """ + A class for testing HDMI-CEC functionality by sending CEC commands + and verifying the received callback data. + """ + def __init__(self, log:logModule=None): + """ + Initializes the test class with test-specific configurations. + Args: + log (logModule): Logging module instance to record test execution. + """ + # Class variables + self.testName = "test02_ReceiveCECCommands" + self.qcID = '2' + self.tvLogicalAddress = '0' + self.broadcastAddress = 'f' + + # Initialize the parent class + super().__init__(self.testName, self.qcID, log) + + def testFunction(self): + """ + Main test function to send CEC commands and validate received callback data. + Steps: + 1. Initialize HDMI-CEC module. + 2. Initialization should fail due to no available logical address + Returns: + bool: Final result of the test execution. + """ + + self.log.stepStart(f"Test {self.testName} started") + + # Initialize the hdmiCEC module + self.testhdmiCEC.initialise() + + # Should be something to verify the init failure? + + # Terminate the hdmiCEC module + self.testhdmiCEC.terminate() + + #return finalResult + +if __name__ == '__main__': + # Configure the summary log file + summerLogName = os.path.splitext(os.path.basename(__file__))[0] + "_summery" + summeryLog = logModule(summerLogName, level=logModule.INFO) + + # Create an instance of the test class and execute the test + test = hdmiCEC_test02_ReceiveCECCommands(summeryLog) + test.run(False) \ No newline at end of file diff --git a/profiles/source/source_hdmiCEC.yml b/profiles/source/source_hdmiCEC.yml index 7b8fff6..16ac59b 100644 --- a/profiles/source/source_hdmiCEC.yml +++ b/profiles/source/source_hdmiCEC.yml @@ -4,3 +4,138 @@ hdmicec: features: extendedEnumsSupported: false + + +cec_responses: + - command: "0x00" # Feature Abort + payload: + type: "Direct" + response: + type: "Direct" + command: "0x9E" + update_payload: true + payload: ["0x00", "0x00"] + description: "Feature Abort Reason" + - command: "0x04" # Image View on + payload: + type: "Direct" + response: null + - command: "0x0D" # Text View On + payload: + type: "Direct" + response: null + - command: "0x32" # Set Menu Language + payload: + type: "Broadcast" + response: null + - command: "0x36" # Standby + payload: + type: "Both" + response: null + - command: "0x46" # Give OSD Name + payload: + type: "Direct" + response: + type: "Direct" + command: "0x47" + update_payload: false + payload: ["0x52", "0x44", "0x4b", "0x20", "0x56", "0x54", "0x53", "0x20", "0x44", "0x65", "0x76", "0x69", "0x63", "0x65"] + description: "Device request OSD name" + - command: "0x47" # report OSD Name + payload: + type: "Direct" + response: null + - command: "0x64" # Set OSD String + payload: + type: "Direct" + response: null + - command: "0x82" # Active source + payload: + type: "Broadcast" + response: null + - command: "0x83" # Give Physical Address + payload: + type: "Direct" + response: + type: "Broadcast" + command: "0x84" + update_payload: true + payload: ["0x00", "0x00", "0x00"] + description: "Report Physical Address" + - command: "0x84" # Report Physical address + payload: + type: "Broadcast" + response: null + - command: "0x85" # Request Active source + payload: + type: "Broadcast" + response: + type: "Broadcast" + command: "0x82" + update_payload: true + payload: ["0x00", "0x00"] + description: "Active Soruce" + - command: "0x87" # Device Vendor ID + payload: + type: "Broadcast" + response: null + - command: "0x8C" # Give Vendor ID + payload: + type: "Direct" + response: + type: "Broadcast" + command: "0x87" + update_payload: false + payload: ["0x00", "0x00", "0x01"] + description: "Device Vendor Id" + - command: "0x8F" # Give power status + payload: + type: "Direct" + response: + type: "Direct" + command: "0x90" + update_payload: false + payload: ["0x00"] + description: "Report power status" + - command: "0x90" # Power Status + payload: + type: "Direct" + response: null + - command: "0x91" # Get Menu Language + payload: + type: "Direct" + response: + type: "Broadcast" + command: "0x32" + update_payload: false + payload: ["0x65", "0x6E", "0x67"] + description: "Set Menu Language" + - command: "0x9E" # CEC Version + response: null + - command: "0x9F" # Get CEC version + payload: + type: "Direct" + response: + type: "Direct" + command: "0x9E" + update_payload: false + payload: ["0x05"] + description: "Device request for CEC version" + - command: "0xA7" # Request Latency + payload: + type: "Broadcast" + response: + type: "Broadcast" + command: "0xA8" + update_payload: true + # 100msec video delay ((number of milliseconds/2) + 1) + # 200msec audio delay ((number of milliseconds/2) + 1) + # (Bits 1-0) : Audio Ouput Compensated (0 - N/A, 1 - TV audio output is delay compensated, 2 - TV audio output is NOT delay compensated, 3 - TV audio output is Par delay compensated) + # (Bit 2) : 0 - normal latency, 1 - low latency + # Bit(7-3) : Reserved + payload: ["0x00", "0x00", "0x65", "0x00", "0x33"] + description: "Report Physical Address" + - command: "0xA8" # Report Physical Address + payload: + type: "Broadcast" + response: null \ No newline at end of file diff --git a/src/main.c b/src/main.c index 7a31e9a..a3d3b88 100644 --- a/src/main.c +++ b/src/main.c @@ -72,6 +72,7 @@ extern int register_hdmicec_hal_sink_l2_tests( void ); #ifdef VCOMPONENT extern int register_vcomponent_tests ( char* profile ); extern int test_l3_hdmi_cec_driver_register ( char* pValidationProfilePath ); +extern int test_l3_hdmi_cec_source_driver_register( char* pValidationProfilePath ); #endif int main(int argc, char** argv) @@ -132,6 +133,7 @@ int main(int argc, char** argv) #ifdef VCOMPONENT register_vcomponent_tests(pProfilePath); test_l3_hdmi_cec_driver_register (pValidationProfilePath); + test_l3_hdmi_cec_source_driver_register(pValidationProfilePath); #endif if(strncmp(szReturnedString,"source",UT_KVP_MAX_ELEMENT_SIZE) == 0) { diff --git a/src/test_l3_hdmi_cec_source_driver.c b/src/test_l3_hdmi_cec_source_driver.c new file mode 100644 index 0000000..7c55524 --- /dev/null +++ b/src/test_l3_hdmi_cec_source_driver.c @@ -0,0 +1,692 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply:* +* Copyright 2024 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. +*/ + +/** + * @addtogroup HPK Hardware Porting Kit + * @{ + * + */ + +/** + * @addtogroup HDMI_CEC HDMI CEC Module + * @{ + * + */ + +/** + * @defgroup HDMI_CEC_HALTESTS HDMI CEC HAL Tests + * @{ + * + */ + + +/** + * @defgroup HDMI_CEC_HALTESTS_L3 HDMI CEC HAL Tests L2 File + * @{ + * @parblock + * + * ### L2 Test Cases for HDMI CEC HAL : + * + * + * ## Module's Role + * This module includes Level 3 functional test interfaces. + * This Test Interfaces provides a scope to create a User Test cases for HDMI CEC Source modules that can be either Manual or automated scripts. + * + * **Pre-Conditions:** None@n + * **Dependencies:** None@n + * + * Refer to API Definition specification documentation : [hdmi-cec_halSpec.md](../../docs/pages/hdmi-cec_halSpec.md) + * + * @endparblock + */ + +/** + * @file test_l3_hdmi_cec_source_driver.c + * + */ + +#include +#include +#include +#include +#include +#include "hdmi_cec_driver.h" + +#define TIMEOUT 5 +#define REPLY_TIMEOUT 5 + +#define HDMI_CEC_MAX_PAYLOAD 128 +#define HDMI_CEC_MAX_OSDNAME 15 +#define HDMI_CEC_KVP_SIZE 128 +#define HDMI_CEC_TYPE_SIZE 16 + +#define UT_LOG_MENU_INFO UT_LOG_INFO + +typedef struct +{ + uint8_t cecCommand; // CEC command code + const char* commandName; // Human-readable command name + int32_t dataLength; // Number of data bytes required for the command +} CecCommandMap; + +typedef struct cecResponse +{ + uint8_t cecCommand; //CEC opcode + uint32_t payloadSize; //CEC payload size + uint8_t type[UT_KVP_MAX_ELEMENT_SIZE]; //Type of the opcode Broadcast/ Direct + uint8_t payload[HDMI_CEC_MAX_PAYLOAD]; //CEC Payload +} cecResponse_t; + +CecCommandMap cecCommandTable[] = { + {0x00, "Feature Abort", 2}, + {0x04, "Image View On", 0}, + {0x05, "Tuner Step Increment", 0}, + {0x06, "Tuner Step Decrement", 0}, + {0x07, "Tuner Device Status", 8}, + {0x08, "Give Tuner Device Status", 0}, + {0x09, "Record On", 8}, + {0x0A, "Record Status", 8}, + {0x0B, "Record Off", 0}, + {0x0D, "Text View On", 0}, + {0x0F, "Record TV Screen", 0}, + {0x1A, "Give Deck Status", 0}, + {0x1B, "Deck Status", 1}, + {0x32, "Set Menu Language", 3}, + {0x33, "Clear Analog Timer", 0}, + {0x34, "Set Analog Timer", 8}, + {0x35, "Timer Status", 3}, + {0x36, "Standby", 0}, + {0x41, "Play", 0}, + {0x42, "Deck Control", 1}, + {0x43, "Timer Cleared Status", 1}, + {0x44, "User Control Pressed", 1}, + {0x45, "User Control Released", 0}, + {0x46, "Give OSD Name", 0}, + {0x47, "Set OSD Name", 14}, + {0x64, "Set OSD String", 14}, + {0x67, "Set Timer Program Title", 14}, + {0x70, "System Audio Mode Request", 2}, + {0x71, "Give Audio Status", 0}, + {0x72, "Set System Audio Mode", 1}, + {0x7A, "Report Audio Status", 1}, + {0x7D, "Give System Audio Mode Status", 0}, + {0x7E, "System Audio Mode Status", 1}, + {0x80, "Routing Change", 4}, + {0x81, "Routing Information", 2}, + {0x82, "Active Source", 2}, + {0x83, "Give Physical Address", 0}, + {0x84, "Report Physical Address", 3}, + {0x85, "Request Active Source", 0}, + {0x86, "Set Stream Path", 2}, + {0x87, "Device Vendor ID", 3}, + {0x89, "Vendor Command", 14}, + {0x8A, "Vendor Remote Button Down", 1}, + {0x8B, "Vendor Remote Button Up", 0}, + {0x8C, "Give Device Vendor ID", 0}, + {0x8D, "Menu Request", 1}, + {0x8E, "Menu Status", 1}, + {0x8F, "Give Device Power Status", 0}, + {0x90, "Report Power Status", 1}, + {0x91, "Get Menu Language", 0}, + {0x92, "Select Analog Service", 4}, + {0x93, "Select Digital Service", 4}, + {0x97, "Set Digital Timer", 6}, + {0x99, "Clear Digital Timer", 0}, + {0x9A, "Set Audio Rate", 1}, + {0x9D, "Inactive Source", 2}, + {0x9E, "CEC Version", 1}, + {0x9F, "Get CEC Version", 0}, + {0xA0, "Vendor Command With ID", 17}, + {0xA1, "Clear External Timer", 0}, + {0xA2, "Set External Timer", 9}, + {0xA7, "Request Current Latency", 2}, + {0xA8, "Report Current Latency", 5}, + {0xC0, "Initiate ARC", 0}, + {0xC1, "Report ARC Initiated", 0}, + {0xC2, "Report ARC Terminated", 0}, + {0xC3, "Request ARC Initiation", 0}, + {0xC4, "Request ARC Termination", 0}, + {0xC5, "Terminate ARC", 0}, + {0xFF, "Abort", 0} +}; + +/* cecError_t */ +const static ut_control_keyStringMapping_t cecError_mapTable [] = +{ + {"HDMI_CEC_IO_SUCCESS", (int32_t)HDMI_CEC_IO_SUCCESS}, + {"HDMI_CEC_IO_SENT_AND_ACKD", (int32_t)HDMI_CEC_IO_SENT_AND_ACKD}, + {"HDMI_CEC_IO_SENT_BUT_NOT_ACKD", (int32_t)HDMI_CEC_IO_SENT_BUT_NOT_ACKD}, + {"HDMI_CEC_IO_SENT_FAILED", (int32_t)HDMI_CEC_IO_SENT_FAILED}, + {"HDMI_CEC_IO_NOT_OPENED", (int32_t)HDMI_CEC_IO_NOT_OPENED}, + {"HDMI_CEC_IO_INVALID_ARGUMENT", (int32_t)HDMI_CEC_IO_INVALID_ARGUMENT}, + {"HDMI_CEC_IO_LOGICALADDRESS_UNAVAILABLE", (int32_t)HDMI_CEC_IO_LOGICALADDRESS_UNAVAILABLE}, + {"HDMI_CEC_IO_GENERAL_ERROR", (int32_t)HDMI_CEC_IO_GENERAL_ERROR}, + {"HDMI_CEC_IO_ALREADY_OPEN", (int32_t)HDMI_CEC_IO_ALREADY_OPEN}, + {"HDMI_CEC_IO_ALREADY_REMOVED", (int32_t)HDMI_CEC_IO_ALREADY_REMOVED}, + {"HDMI_CEC_IO_INVALID_OUTPUT", (int32_t)HDMI_CEC_IO_INVALID_OUTPUT}, + {"HDMI_CEC_IO_INVALID_HANDLE", (int32_t)HDMI_CEC_IO_INVALID_HANDLE}, + {"HDMI_CEC_IO_OPERATION_NOT_SUPPORTED", (int32_t)HDMI_CEC_IO_OPERATION_NOT_SUPPORTED}, + {"HDMI_CEC_IO_NOT_ADDED", (int32_t)HDMI_CEC_IO_NOT_ADDED}, + {"HDMI_CEC_IO_MAX", (int32_t)HDMI_CEC_IO_MAX}, + { NULL, -1 } +}; + +static int32_t gTestGroup = 3; +static int32_t gTestID = 1; +static int32_t gHandle = 0; +static int32_t gLogicalAddress = -1; +static uint32_t gPhysicalAddress = -1; +static uint8_t *gPhysicalAddressBytes; +static uint8_t gBroadcastAddress = 0xF; + +/** +* @brief CEC Command with data size mapping function. +* +* This function maps the provided CEC command with the data length required for the CEC Command. +* This will help the test to consider the correct size of the data required for the CEC Command. +* +*/ +static int32_t getCecCommandInfo(uint8_t cecCommand, const char** commandName, int32_t* dataLength) +{ + + int32_t tableSize = sizeof(cecCommandTable) / sizeof(CecCommandMap); + + for (int32_t i = 0; i < tableSize; i++) + { + if (cecCommandTable[i].cecCommand == cecCommand) + { + *commandName = cecCommandTable[i].commandName; + *dataLength = cecCommandTable[i].dataLength; + return 0; // Command found + } + } + + return -1; // Command not found +} + +/** + * @brief This function clears the stdin buffer. + * + * This function clears the stdin buffer. + */ +static void readAndDiscardRestOfLine(FILE *in) +{ + int32_t c; + while ((c = fgetc(in)) != EOF && c != '\n'); +} + +static void readInt(int32_t *value) +{ + scanf("%d", value); + readAndDiscardRestOfLine(stdin); +} + +static void readHex(int32_t *value) +{ + scanf("%x", value); + readAndDiscardRestOfLine(stdin); +} + +static bool getCommandResponse(uint8_t opcode, cecResponse_t *pResponse) +{ + uint32_t numCommands = 0; + char key_string[HDMI_CEC_KVP_SIZE] = {0}; + + memset(pResponse, 0, sizeof(cecResponse_t)); + + numCommands = UT_KVP_PROFILE_GET_LIST_COUNT("hdmicec/cec_responses"); + + for(uint32_t i = 0; i < numCommands; i++) + { + uint8_t command; + uint8_t found; + + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/command" , i); + command = UT_KVP_PROFILE_GET_UINT8(key_string); + + if(command != opcode) + { + continue; + } + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/response/command" , i); + found = ut_kvp_fieldPresent(ut_kvp_profile_getInstance(), key_string); + + if(found) + { + pResponse->cecCommand = UT_KVP_PROFILE_GET_UINT8(key_string); + + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/response/type" , i); + UT_KVP_PROFILE_GET_STRING(key_string, (char*)pResponse->type); + + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/response/payload" , i); + pResponse->payloadSize = UT_KVP_PROFILE_GET_LIST_COUNT(key_string); + + for(uint8_t j = 0; j < pResponse->payloadSize; j++) + { + if((command == 0xA8 || command == 0x84|| command == 0x82) && j < 2) //Needs this devices physical address + { + pResponse->payload[j] = gPhysicalAddressBytes[j]; + continue; + } + else{ + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/response/payload/%d" , i, j); + pResponse->payload[j] = UT_KVP_PROFILE_GET_UINT8(key_string); + + } + + } + return true; + } + } + return false; +} + +static void sendResponse(int32_t handle, uint8_t initiator, uint8_t destination, + uint8_t *buf, int32_t len, cecResponse_t *pCecResponse) +{ + uint8_t prBuffer[HDMI_CEC_MAX_PAYLOAD] = {0}; + uint8_t response[HDMI_CEC_MAX_PAYLOAD] = {0}; + + if (pCecResponse->payloadSize) + { + int32_t result; + const char* commandName; + int32_t expectedDataLength; + + if (!strcmp((char*)pCecResponse->type, "Direct")) + { + response[0] = (destination << 4) | initiator; + } + else + { + //Send braodcast message + response[0] = (gLogicalAddress << 4) | gBroadcastAddress; + } + response[1] = pCecResponse->cecCommand; + + for (int32_t index = 0; index < pCecResponse->payloadSize; index++) + { + response[index + 2] = pCecResponse->payload[index]; + } + + { + uint8_t *temp = prBuffer; + // Log each byte received in the buffer + for (int32_t index = 0; index < pCecResponse->payloadSize + 2; index++) + { + int32_t len = 0; + len = snprintf((char*)temp, HDMI_CEC_MAX_PAYLOAD, "%02X:", response[index]); + temp += len; + } + prBuffer[strlen((char*)prBuffer)-1] = '\0'; + + } + + HdmiCecTx(handle, response, pCecResponse->payloadSize + 2, &result); + + getCecCommandInfo(pCecResponse->cecCommand, &commandName, &expectedDataLength); + + UT_LOG_INFO("Sent Response Opcode: [0x%02X] [%s] Initiator: [%x], Destination: [%x] Data: [%s]\n", + pCecResponse->cecCommand, commandName, destination, initiator, prBuffer); + } +} + +static void onRxDataReceived(int32_t handle, void *callbackData, uint8_t *buf, int32_t len) +{ + UT_LOG_INFO("In %s(IN: handle: [%p], IN: callbackData: [%p], IN: buf: [%p], IN: len: [%d])\n", __FUNCTION__, handle, callbackData, buf, len); + + const char* commandName; + int32_t expectedDataLength; + + if ((handle != 0) && (callbackData != NULL) && (len > 0)) + { + // Parse the command + uint8_t initiator = (buf[0] >> 4) & 0xF; // Extract initiator address + uint8_t destination = buf[0] & 0xF; // Extract destination address + uint8_t opcode; // Command opcode + cecResponse_t cecResponse = {0}; // cec response + uint8_t prBuffer[HDMI_CEC_MAX_PAYLOAD] = {0}; + bool result = false; + + if( len == 1) + { + UT_LOG_INFO("Received Ping message Initiator: [%x], Destination: [%x]", initiator, destination); + goto exit; + } + + opcode = buf[1]; + + if(getCecCommandInfo(opcode, &commandName, &expectedDataLength) != 0) + { + UT_LOG_WARNING("CEC command 0x%02X is not recognized", opcode); + goto exit; + } + + { + uint8_t *temp = prBuffer; + // Log each byte received in the buffer + for (int32_t index = 0; index < len; index++) + { + int32_t len = 0; + len = snprintf((char*)temp, HDMI_CEC_MAX_PAYLOAD, "%02X:", buf[index]); + temp += len; + } + prBuffer[strlen((char*)prBuffer)-1] = '\0'; + } + + UT_LOG_INFO("Received Opcode: [0x%02X] [%s] Initiator: [%x], Destination: [%x] Data: [%s]\n", opcode, commandName, initiator, destination, prBuffer); + + result = getCommandResponse(opcode, &cecResponse); + + UT_LOG_INFO("result: %d\n", result); + + sendResponse(handle, initiator, destination, buf, len, &cecResponse); + } + else + { + // Log specific errors based on failed conditions + if (handle == 0) + { + UT_LOG_ERROR("Error: Invalid handle.\n"); + } + if (callbackData == NULL) + { + UT_LOG_ERROR("Error: Null callback data.\n"); + } + if (len <= 0) + { + UT_LOG_ERROR("Error: Invalid length.\n"); + } + } +exit: + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + + + +/** +* @brief Initialization of the HAL CEC Module +* +* This test provides a scope to open the HAL CEC module and preserve the handle. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 001@n +* +* **Pre-Conditions:** None@n +* +* **Dependencies:** None@n +* +* **User Interaction:** @n +* User or Automation tool should select the Test 1 to before running any test. +* +*/ + +void test_l3_hdmi_cec_source_hal_Init(void) +{ + gTestID = 1; + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; + + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); + + // Step 1: Call HdmiCecOpen() + UT_LOG_INFO("Calling HdmiCecOpen(OUT:handle:[])"); + status = HdmiCecOpen(&gHandle); + UT_LOG_INFO("Result HdmiCecOpen(OUT:handle:[0x%0X]) HDMI_CEC_STATUS:[%s]",gHandle, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + assert(gHandle != 0); + + // Step 2: Register the call back + UT_LOG_INFO("Calling HdmiCecSetRxCallback(IN:handle:[0x%0X], IN:cbfunc:[0x%0X])",gHandle, onRxDataReceived); + status = HdmiCecSetRxCallback(gHandle, onRxDataReceived,(void*)0xABABABAB); + UT_LOG_INFO("Result HdmiCecSetRxCallback(IN:handle:[0x%0X], IN:cbfunc:[0x%0X]) HDMI_CEC_STATUS:[%s]",gHandle,onRxDataReceived, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + UT_LOG_INFO("Calling HdmiCecGetPhysicalAddress(IN:handle:[0x%0X], OUT:physicalAddress:[])", gHandle); + status = HdmiCecGetPhysicalAddress(gHandle, &gPhysicalAddress); + UT_LOG_INFO("Result HdmiCecGetPhysicalAddress(IN:handle:[0x%0X], OUT:physicalAddress:[%d]) HDMI_CEC_STATUS:[%s]", gHandle, gPhysicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + UT_LOG_INFO("Calling HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[])", gHandle); + status = HdmiCecGetLogicalAddress(gHandle, &gLogicalAddress); + UT_LOG_INFO("Result HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[%d]) HDMI_CEC_STATUS:[%s]", gHandle, gLogicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + gPhysicalAddressBytes = (uint8_t*)&gPhysicalAddress; + + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + + +/** +* @brief Test to get the logical address +* +* This test provides a scope to check the assigned logical address of the device. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 002@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be initalized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +* **User Interaction:** @n +* User or Automation tool should select the Test 3 and shall read the Logical address displayed on the console. +* +*/ +void test_l3_hdmi_cec_source_hal_GetLogicalAddress(void) +{ + gTestID = 2; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); + + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; + int32_t logicalAddress = -1; + + UT_LOG_INFO("Calling HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[])", gHandle); + status = HdmiCecGetLogicalAddress(gHandle, &logicalAddress); + UT_LOG_INFO("Result HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[%d]) HDMI_CEC_STATUS:[%s])", gHandle, logicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + +/** +* @brief Test provides a scope to Transmit the CEC Command +* +* This test provides an interface to user/automation tool to transmit a CEC Command. +* Necessary input should be provided to the test. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 003@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be initalized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +* **User Interaction:** @n +* User or Automation tool should select the Test 4 and shall provide the necessary source and destination logical address, +* CEC command, data lenght and data. +* +*/ +void test_l3_hdmi_cec_source_hal_TransmitHdmiCecCommand(void) { + gTestID = 3; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); + + int32_t sourceLogicalAddress = gLogicalAddress; + int32_t destinationLogicalAddress = -1; + uint8_t buf[16] = {0}; + int32_t len = 0, cecCommand = 0; + int32_t result; + const char* commandName; + int32_t expectedDataLength; + + assert(sourceLogicalAddress != -1); + + // Reading inputs from the user or test framework + UT_LOG_MENU_INFO("Enter a valid Destination Logical Address: "); + readHex(&destinationLogicalAddress); + + UT_LOG_MENU_INFO("Enter CEC Command (in hex): "); + readHex(&cecCommand); + + // Validate the CEC command and get the expected data length + if (getCecCommandInfo(cecCommand, &commandName, &expectedDataLength) != 0) + { + // Command not found in the map, prompt the user for additional information + UT_LOG_WARNING("CEC command 0x%02X is not recognized. It might be a vendor-specific command.", cecCommand); + + UT_LOG_MENU_INFO("Enter the number of data bytes for the CEC command:"); + readInt(&expectedDataLength); + commandName = "Vendor Specific Command"; + } + else + { + UT_LOG_INFO("CEC Command: %s (0x%02X), expects %d data byte(s)", commandName, cecCommand, expectedDataLength); + } + + // If the command has data bytes, prompt for them + if (expectedDataLength > 0) + { + for (int32_t i = 0; i < expectedDataLength; i++) + { + int32_t byte_data; + UT_LOG_MENU_INFO("Enter Databyte[%d] (in hex):", i); + readHex(&byte_data); + buf[i + 2] = (uint8_t)byte_data; // +2 to account for the first two bytes + } + } + + // Building the CEC message + buf[0] = (uint8_t)((sourceLogicalAddress << 4) | (destinationLogicalAddress & 0x0F)); + buf[1] = (uint8_t)cecCommand; + len = expectedDataLength + 2; // 1 byte for logical addresses, 1 byte for CEC Command + + // Logging the transmission attempt + UT_LOG_INFO("Calling HdmiCecTx(IN:handle:[0x%0X], IN:buf:[%p], IN:len:[%d], OUT:result:[])", gHandle, buf, len); + int32_t status = HdmiCecTx(gHandle, buf, len, &result); + UT_LOG_INFO("Result HdmiCecTx(IN:handle:[0x%0X], IN:buf:[%p], IN:len:[%d], OUT:result:[%s]) HDMI_CEC_STATUS:[%s]", gHandle, buf, len, UT_Control_GetMapString(cecError_mapTable, result)? UT_Control_GetMapString(cecError_mapTable, result):"HDMI_CEC_IO_SENT_FAILED", UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + +/** +* @brief Test to get the physical address +* +* This test provides a scope to read the physical address of the device. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 004@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be initalized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +* **User Interaction:** @n +* User or Automation tool should select the Test 6 to read the physical address of the device +* device connected in the network. +* +*/ +void test_l3_hdmi_cec_source_hal_GetPhysicalAddress(void) +{ + gTestID = 4; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); + + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; + uint32_t physicalAddress = -1; + + UT_LOG_INFO("Calling HdmiCecGetPhysicalAddress(IN:handle:[0x%0X], OUT:physicalAddress:[])", gHandle); + status = HdmiCecGetPhysicalAddress(gHandle, &physicalAddress); + UT_LOG_INFO("Result HdmiCecGetPhysicalAddress(IN:handle:[0x%0X], OUT:physicalAddress:[%d]) HDMI_CEC_STATUS:[%s]", gHandle, physicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + +/** +* @brief Test to close the HDMI CEC device. +* +* This test provides a scope to close the created HDMI CEC handle. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 05@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be initalized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +* **User Interaction:** @n +* User or Automation tool should select the Test 8 to close the created HDMI CEC handle. +* +*/ +void test_l2_hdmi_cec_source_hal_Close(void) +{ + gTestID = 5; + HDMI_CEC_STATUS status; + + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); + + UT_LOG_INFO("Calling HdmiCecClose(IN:handle:[0x%0X])", gHandle); + status = HdmiCecClose(gHandle); + UT_LOG_INFO("Result HdmiCecClose(IN:handle:[0x%0X]) HDMI_CEC_STATUS:[%s]", gHandle, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + gHandle = 0; + + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + + +static UT_test_suite_t * pSuite = NULL; + +/** + * @brief Register the main tests for this module + * + * @return int - 0 on success, otherwise failure + */ +int test_register_hdmicec_hal_source_l3_tests(void) +{ + // Create the test suite + pSuite = UT_add_suite_withGroupID("[L3 HDMICEC Source ]", NULL, NULL,UT_TESTS_L3); + if (pSuite == NULL) + { + return -1; + } + // List of test function names and strings + + UT_add_test( pSuite, "Init HDMI CEC", test_l3_hdmi_cec_source_hal_Init); + UT_add_test( pSuite, "Get Logical Address", test_l3_hdmi_cec_source_hal_GetLogicalAddress); + UT_add_test( pSuite, "Transmit CEC Command", test_l3_hdmi_cec_source_hal_TransmitHdmiCecCommand); + UT_add_test( pSuite, "Get Physical Address", test_l3_hdmi_cec_source_hal_GetPhysicalAddress); + UT_add_test( pSuite, "Close HDMI CEC", test_l2_hdmi_cec_source_hal_Close); + + return 0; +} + + +/** @} */ // End of HDMI CEC HAL Tests L1 File +/** @} */ // End of HDMI CEC HAL Tests +/** @} */ // End of HDMI CEC Module +/** @} */ // End of HPK diff --git a/src/test_register.c b/src/test_register.c index cc1e55c..49ff760 100644 --- a/src/test_register.c +++ b/src/test_register.c @@ -67,6 +67,9 @@ extern int test_hdmidec_hal_l1_register( void ); extern int test_register_hdmicec_hal_source_l2_tests( void ); extern int test_register_hdmicec_hal_sink_l2_tests( void ); +/*L3 Testing Functions*/ +extern int test_register_hdmicec_hal_source_l3_tests( void ); + int register_hdmicec_hal_l1_tests( void ) { @@ -93,6 +96,14 @@ int register_hdmicec_hal_sink_l2_tests( void ) return registerFailed; } +int register_hdmicec_hal_source_l3_tests( void ) +{ + int registerFailed=0; + + registerFailed |= test_register_hdmicec_hal_source_l3_tests(); + + return registerFailed; +} /** @} */ // End of HDMI CEC HAL Tests Register File /** @} */ // End of HDMI CEC HAL Tests