diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..51fc070 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "args": [ "--config", "example_rack_config.yml", + "--deviceConfig", "deviceConfig.yml"], + "console": "integratedTerminal" + }, + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "stopAtEntry": false, + "externalConsole": false, + "cwd": "${workspaceFolder}", + "program": "${workspaceFolder}/bin/hal_test", + "environment": [ {"name": "LD_LIBRARY_PATH", "value":"${workspaceFolder}/bin/"} ], + "args": [ "-l", "${workspaceFolder}/logs/", "-p", "${workspaceFolder}/profiles/sink/Sink_AudioSettings.yaml" ], + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} diff --git a/Makefile b/Makefile index 3bf2882..4b2fd2e 100644 --- a/Makefile +++ b/Makefile @@ -81,9 +81,9 @@ export HAL_LIB_DIR build: $(SETUP_SKELETON_LIBS) echo "SETUP_SKELETON_LIBS $(SETUP_SKELETON_LIBS)" @echo UT [$@] - make -C ./ut-core framework - make -C ./ut-core test - + make -C ./ut-core TARGET=${TARGET} + rm -rf $(BIN_DIR)/lib$(HAL_LIB).so + rm -rf $(ROOT_DIR)/libs/lib$(HAL_LIB).so #Build against the real library leads to the SOC library dependency also.SOC lib dependency cannot be specified in the ut Makefile, since it is supposed to be common across may platforms. So in order to over come this situation, creating a template skelton library with empty templates so that the template library wont have any other Soc dependency. And in the real platform mount copy bind with the actual library will work fine. skeleton: echo $(CC) 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-L3-Low-Level_TestSpec.md b/docs/pages/hdmi-cec-L3-Low-Level_TestSpec.md new file mode 100644 index 0000000..df6d41d --- /dev/null +++ b/docs/pages/hdmi-cec-L3-Low-Level_TestSpec.md @@ -0,0 +1,97 @@ +# HDMI CEC L3 Test Document + +## Table of Contents + +- [Acronyms, Terms and Abbreviations](#acronyms-terms-and-abbreviations) +- [Overview](#overview) +- [References](#references) +- [Level 3 Test Procedure](#level-3-test-cases-high-level-overview) +- [Level 3 Python Test](#level-3-python-test-cases-high-level-overview) + +## Overview + +This document describes the L3 Test Procedure for the HDMI CEC module. + +## Acronyms, Terms and Abbreviations + +- `CEC` - Consumer Electronics Control +- `HAL` - Hardware Abstraction layer +- `HDMI` - High Definition Multimedia Interface +- `API` - Application Program Interface +- `SoC` - System on Chip +- `DUT` - Device Under Test +- `LA` - Logical Address +- `PA` - Physical Address + +## References + +- CEC Adaptor: [Pulse Eight](https://www.pulse-eight.com/p/104/usb-hdmi-cec-adapter) +- `HAL` interface file: [hdmi_cec_driver.h](https://github.com/rdkcentral/rdk-halif-hdmi_cec/blob/1.3.9/include/hdmi_cec_driver.h) + +## Level 3 Test Cases High Level Overview + +|#|Test-case|Description|HAL APIs|Source|Sink| +|-|---------|-----------|--------|------|----| +|1|Transmit CEC Commands|Send predefined `CEC` commands from the DUT and verify if the command is successfully transmitted using the CEC adapter| `HdmiCecTx()`|`Y`|`Y`| +|2|Receive CEC commands|Send predefined `CEC` commands from the CEC adapter, verify if the `DUT` successfully receives the command, and check the response through call-backs.| `HdmiCecTx()`|`Y`|`Y`| + +## Level 3 Python Test Cases High Level Overview + +The class diagram below illustrates the flow of HDMI CEC Python test cases: + +```mermaid +--- +title: HDMI-CEC - Python Class Flow +--- +classDiagram + testControl <|-- ut_raft : inherits + class ut_raft{ + } + ut_raft <|-- hdmiCECHelperClass : inherits + hdmiCECHelperClass <|-- L3_TestClasses : inherits + L3_TestClasses ..> hdmiCEC : uses + note for testControl "uses rackConfig.yml and deviceConfig.yml" + note for hdmiCEC "uses platformProfile.yml" + note for L3_TestClasses "uses hdmiCECTestCommands.yml" + note for ut_raft "suite Navigator uses testSuite.yml" +``` + +- **testControl** + - Test Control Module for running rack Testing. This module configures the `DUT` based on the rack configuration file provided to the test. + - This class is defined in `RAFT` framework. For more details refer [RAFT](https://github.com/rdkcentral/python_raft/blob/1.2.0/README.md) +- **ut_raft** + - Python based testing framework for writing engineering tests. + - It provides common functionalities like menu navigation, configuration reader, reading user response etc. + - For more details [ut-raft](https://github.com/rdkcentral/ut-raft/tree/2.0.0) +- **hdmiCEC** + - This is test helper class which communicates with the `L3` C/C++ test running on the `DUT` through menu +- **L3_TestClasses** + - These are the L3 test case classes + - Each class covers the each test use-case defined in [L3 Test use-cases](#level-3-test-cases-high-level-overview) table + +### YAML File Inputs + +- **rackConfig.yaml** + - Identifies the rack configuration and platform used + - References platform-specific config from `deviceConfig.yaml` + - For more details refer [RAFT](https://github.com/rdkcentral/python_raft/blob/1.2.0/README.md) and [example_rack_config.yml](https://github.com/rdkcentral/python_raft/blob/1.2.0/examples/configs/example_rack_config.yml) + +- **deviceConfig.yaml** + - Specifies overall configuration for the platform + - Can be overridden by: + - Changing locally .yaml file directory + - Using --deviceConfig command line switch + - For more details refer [RAFT](https://github.com/rdkcentral/python_raft/blob/1.2.0/README.md) and [example_device_config.yml](https://github.com/rdkcentral/python_raft/blob/1.2.0/examples/configs/example_device_config.yml) + +- **componentProfile.yaml/platformProfile.yaml** + - Contains component-specific configurations + - Contains platform wide configuration broken down into separate components + - Example configuration file [sink_hdmiCEC](../../profiles/sink/sink_hdmiCEC.yml) + +- **hdmiCECTestCommands.yaml** + - This configuration file contains the list of `CEC` commands. + - Example configuration file [hdmiCECTestCommands.yml](../../host/tests/hdmiCEC_L3_Tests/hdmiCECTestCommands.yml) + +- **testConfig.yaml** + - This configuration file contains the list of menu items for C/C++ L3 test running on `DUT` + - Example configuration file [hdmiCEC_testConfig.yml](../../host/tests/classes/hdmiCEC_testConfig.yml) diff --git a/docs/pages/hdmi-cec-L3_TestProcedure.md b/docs/pages/hdmi-cec-L3_TestProcedure.md new file mode 100644 index 0000000..4139937 --- /dev/null +++ b/docs/pages/hdmi-cec-L3_TestProcedure.md @@ -0,0 +1,193 @@ +# dsAudio HAL L3 Python Test Procedure + +## Table of Contents + +- [Acronyms, Terms and Abbreviations](#acronyms-terms-and-abbreviations) +- [Setting Up Test Environment](#setting-up-test-environment) +- [Streams Required](#streams-required) +- [Test Cases](#test-cases) + - [dsAudio_L3_Runall_Sink.py](#dsaudio_l3_runall_sinkpy) + - [dsAudio_L3_Runall_Source.py](#dsaudio_l3_runall_sourcepy) + - [dsaudio_test01_enabledisableandverifyaudioportstatus.py](#dsaudio_test01_enabledisableandverifyaudioportstatuspy) + +## Acronyms, Terms and Abbreviations + +- `HAL` - Hardware Abstraction Layer +- `L3` - Level 3 Testing +- `DUT` - Device Under Test +- `RAFT` - Rapid Automation Framework for Testing +- `YAML` - YAML Ain't Markup Language +- `HDMI` - High Definition Multimedia Interface +- `API` - Application Program Interface +- `SoC` - System on Chip +- `DUT` - Device Under Test +- `LA` - Logical Address +- `PA` - Physical Address + +## Setting Up Test Environment + +To execute `HAL` `L3` Python test cases, need a Python environment. Follow these steps mentioned in [HPK Public Documentation](https://github.com/rdkcentral/rdk-hpk-documentation/blob/main/README.md) + +### Update Configuration Files + +#### Rack Configuration File + +Example Rack configuration File: [example_rack_config.yml](../../../ut/host/tests/configs/example_rack_config.yml) + +For more details refer [RAFT](https://github.com/rdkcentral/python_raft/blob/1.0.0/README.md) and [example_rack_config.yml](https://github.com/rdkcentral/python_raft/blob/1.0.0/examples/configs/example_rack_config.yml) + +In this file, update the configuration to define the console sessions for the `DUT` and the outbound settings: + +|Console Session|Description| +|---------------|-----------| +|default|Downloads the streams required for test cases| +|ssh_hal_test|Executes the `HAL` binary for the test case| + +```yaml +rackConfig: + - dut: + ip: "XXX.XXX.XXX.XXX" # IP Address of the device + description: "stb device under test" + platform: "stb" + consoles: + - default: + type: "ssh" + port: 10022 + username: "root" + ip: "XXX.XXX.XXX" # IP address of the device + password: ' ' + - ssh_hal_test: + type: "ssh" + port: 10022 + username: "root" + ip: "XXX.XXX.XXX" # IP address of the device + password: ' ' + outbound: + download_url: "http://localhost:8000/" # download location for the CPE device + httpProxy: # Local Proxy if required + workspaceDirectory: './logs/workspace' # Local working directory +``` + +#### Device Configuration File + +Example Device configuration File: [deviceConfig.yml](../../../ut/host/tests/configs/deviceConfig.yml) + +For more details refer [RAFT](https://github.com/rdkcentral/python_raft/blob/1.0.0/README.md) and [example_device_config.yml](https://github.com/rdkcentral/python_raft/blob/1.0.0/examples/configs/example_device_config.yml) + +Update below fileds in the device configuration file: + +- Set the path for `target_directory` where `HAL` binaries will be copied onto the device. +- Specify the device profile path in `test/profile` +- Ensure the `platform` should match with the `DUT` `platform` in [Rack Configuration](#rack-configuration-file) + +```yaml +deviceConfig: + cpe1: + platform: "tv" + model: "uk" + soc_vendor: "soc" + target_directory: "/tmp/" # Target Directory on device + prompt: "" + test: + profile: "../../../profiles/sink/sink_hdmiCEC.yml" +``` + +#### Test Configuration + +Example Test Setup configuration File: [hdmiCEC_testConfig.yml](../../../ut/host/tests/classes/hdmiCEC_testConfig.yml) + +Execute command to run te HAL binary was provided in this file. + +```yaml +hdmicec: + description: "hdmi CEC testing profile / menu system for UT" + test: + artifacts: + #List of artifacts folders, test class copies the content of folder to the target device workspace + - "../../../bin/" + # exectute command, this will appended with the target device workspace path + execute: "run.sh" + type: UT-C # C (UT-C Cunit) / C++ (UT-G (g++ ut-core gtest backend)) +``` + +## Run Test Cases + +Once the environment is set up, you can execute the test cases with the following command + +```bash +python --config /ut/host/tests/configs/example_rack_config.yml --deviceConfig /ut/host/tests/configs/deviceConfig.yml +``` + +## Test Cases + +### dsAudio_L3_Runall_Sink.py + +This python file runs all the tests supported by `sink` devices + +```bash +python dsAudio_L3_Runall_Sink.py --config /ut/host/tests/configs/example_rack_config.yml --deviceConfig /ut/host/tests/configs/deviceConfig.yml +``` + +### dsAudio_L3_Runall_Source.py + +This python file runs all the tests supported by `source` devices + +```bash +python dsAudio_L3_Runall_Source.py --config /ut/host/tests/configs/example_rack_config.yml --deviceConfig /ut/host/tests/configs/deviceConfig.yml +``` + +### dsAudio_test01_EnableDisableAndVerifyAudioPortStatus.py + +#### Platform Support - test01 + +- Source +- Sink + +#### User Input Required - test01 + +**Yes**: User interaction is necessary to confirm audio playback status (This will be automated later). + +#### Acceptance Criteria - test01 + +Play **Stream #1** and confirm that audio is heard through the supported ports. + +#### Expected Results - test01 + +The test enables the specified audio ports, plays the audio stream, and subsequently disables the ports + +Success Criteria + +- User should hear audio through the enabled port during playback +- User should not hear any audio when the port is disabled. + +#### Test Steps - test01 + +- Initiate the Test: + + - Select and execute the Python file: **`dsAudio_test01_EnableDisableAndVerifyAudioPortStatus.py`** + - The test will automatically download all required artifacts and streams, copying them to the designated target directory before commencing execution. + +- Audio Playback Verification: + + The test will play the designated audio stream and prompt the user with the following: + + - Question: "Is audio playing on the enabled audio port? (Y/N)" + - Press **Y** if audio is heard (this will mark the step as PASS). + - Press **N** if no audio is heard (this will mark the step as FAIL). + +- Audio Status Confirmation (Port Disabled): + + After confirming audio playback, the test will disable the audio port and prompt the user again: + + - Question: "Is audio playing when the port is disabled? (Y/N)" + - Press **N** if no audio is heard (this will mark the step as PASS). + - Press **Y** if audio is heard (this will mark the step as FAIL). + +- Repeat for All Ports: + + The test will iterate through all available audio ports, enabling/disabling each one and collecting user feedback accordingly. + +- Test Conclusion: + + Upon receiving user responses for all ports, the test will conclude and present a final result: PASS or FAIL based on the user inputs throughout the test execution. + diff --git a/host/.lastlogin b/host/.lastlogin new file mode 100644 index 0000000..e69de29 diff --git a/host/activate_venv.sh b/host/activate_venv.sh new file mode 100644 index 0000000..d911224 --- /dev/null +++ b/host/activate_venv.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2023 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. +# * +#* ****************************************************************************** +MY_PATH="$(realpath ${BASH_SOURCE[0]})" +MY_DIR="$(dirname ${MY_PATH})" +VENV_DIR="${MY_DIR}/python_venv" # Default virtual environment directory name + +# Check if the script is sourced +if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then + source "$VENV_DIR"/bin/activate + echo "Virtual environment '$VENV_DIR' activated." +else + echo "The script must be sourced. 'source ./activate_venv.sh' or '. ./activate_venv.sh'" + echo "Once activated you can deactivate with 'deactivate' command" +fi + diff --git a/host/install.sh b/host/install.sh new file mode 100755 index 0000000..fefb72d --- /dev/null +++ b/host/install.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2023 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. +# * +#* ****************************************************************************** +MY_PATH="$(realpath ${BASH_SOURCE[0]})" +MY_DIR="$(dirname ${MY_PATH})" +TESTS_DIR="${MY_DIR}/tests" +RAFT_DIR="${TESTS_DIR}/raft" +PLUGINS_FRAMEWORK_DIR="${RAFT_DIR}/framework/plugins" +VENV_NAME="python_venv" +VENV_DIR="${MY_DIR}/${VENV_NAME}" # Default virtual environment directory name + +mkdir -p ${TESTS_DIR} + +NO_COLOR="\e[0m" +RED="\e[0;31m" +CYAN="\e[0;36m" +YELLOW="\e[1;33m" +GREEN="\e[0;32m" +RED_BOLD="\e[1;31m" +BLUE_BOLD="\e[1;34m" +YELLOW_BOLD="\e[1;33m" + +set -e # return on errors + +function DUMP_VAR() +{ + local var_name="$1" + local var_content="${!var_name}" + echo -e ${CYAN}$var_name:[${var_content}]${NO_COLOR} +} +function ECHO() +{ + echo -e "$*" +} + +function DEBUG() +{ + # if set -x is in use debug messages are useless as whole stript will be shown + if [[ "$-" =~ "x" ]]; then + return + fi + if [[ "${DEBUG_FLAG}" == "1" ]];then + ECHO "${BLUE_BOLD}DEBUG: ${CYAN}$*${NO_COLOR}" > /dev/stderr + fi +} + +function INFO() +{ + ECHO "${GREEN}$*${NO_COLOR}" +} + +function WARNING() +{ + ECHO "${YELLOW_BOLD}Warning: ${YELLOW}$*${NO_COLOR}" > /dev/stderr +} + +function ERROR() +{ + ECHO "${RED_BOLD}ERROR: ${RED}$*${NO_COLOR}" + exit 1 +} + +function install_pip_requirements() +{ + local requirements_file="$1" + + if [ ! -f ${requirements_file} ]; then + WARNING "No ${requirements_file} found" + return # Exit the function if the file exists + fi + + INFO "install_pip_requirements( ${requirements_file} ):" + if pip install -r "$requirements_file" >/dev/null 2>&1; then + INFO "pip install completed" + else + ERROR "process_and_update_sha(): pip install failed." + return 1 # Exit the function with error code + fi +} + +function clone_repo() +{ + # Requirment it to clone only if not present. + local repo_url="$1" + local path="$2" + local version="$3" + local message="$4" + + if [[ -z "${repo_url}" ]]; then + ERROR "clone_repo:A url for a repository must be passed to the clone repo function" + fi + if [[ -z "${version}" ]]; then + ERROR "clone_repo:Version not specified" + fi + if [[ ! -z "${path}" ]]; then + if [[ ! -d "${path}" ]]; then + INFO "git clone ${repo_url} @ ${version} ${CYAN}${message}${NO_COLOR}" + git clone ${repo_url} "${path}" > /dev/null 2>&1 + cd ${path} + #INFO "git checkout ${version}" + git checkout ${version} > /dev/null 2>&1 + cd - > /dev/null + fi + fi +} + +function setup_and_enable_venv() +{ + # Check if virtual environment directory exists, create if not + if [[ ! -d "$VENV_DIR" ]]; then + ECHO "Creating Virtual environment ${YELLOW}'$VENV_NAME'${NO_COLOR}" + python3 -m venv "$VENV_DIR" + ECHO "Virtual environment created." + fi + + # Request that the user re-run this script from the vendor + # Check if already inside a virtual environment + if [[ ! -n "$VIRTUAL_ENV" ]]; then + # Activate virtual environment + ECHO "please source & re-run ${YELLOW}install.sh${NO_COLOR} to ensure setup:" + ECHO ${YELLOW}"source ./activate_venv.sh"${NO_COLOR} + exit 1 # Exit the function if already in a venv + fi + + if [ -f "${VENV_DIR}/.installed" ]; then + return + fi + + # Upgrade pip + #python3 -m pip install --upgrade pip + #echo "pip upgraded within the virtual environment." + + touch ${VENV_DIR}/.installed +} + + +## Setup and start venv +setup_and_enable_venv + +### Clone required repos ### +# Setup raft +clone_repo git@github.com:rdkcentral/python_raft.git "${RAFT_DIR}" "1.2.0" "in ./raft" +install_pip_requirements "${RAFT_DIR}"/requirements.txt + +# Setup ut-raft +clone_repo git@github.com:rdkcentral/ut-raft.git "${PLUGINS_FRAMEWORK_DIR}/ut_raft" 2.0.0 "in ./raft/framework/plugins" +install_pip_requirements "${PLUGINS_FRAMEWORK_DIR}"/ut_raft/requirements.txt + +## Install your own sub git repo's in here as required +# +INFO "Install Complete" diff --git a/host/tests/classes/hdmiCEC.py b/host/tests/classes/hdmiCEC.py new file mode 100644 index 0000000..4ee318d --- /dev/null +++ b/host/tests/classes/hdmiCEC.py @@ -0,0 +1,358 @@ +#!/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 re +import os +import sys + +# Add parent directory to the system path for module imports +dir_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(dir_path, "../")) + +from raft.framework.plugins.ut_raft.configRead import ConfigRead +from raft.framework.plugins.ut_raft.utSuiteNavigator import UTSuiteNavigatorClass +from raft.framework.plugins.ut_raft.interactiveShell import InteractiveShell +from raft.framework.plugins.ut_raft.utBaseUtils import utBaseUtils + +class hdmiCECClass(): + """ + HDMI CEC Class. + + Provides functionalities for initializing, configuring, and controlling + HDMI CEC (Consumer Electronics Control) operations in the test environment. + """ + + def __init__(self, moduleConfigProfileFile:str, session=None, targetWorkspace:str="/tmp"): + """ + Initialize the HDMI CEC Class with configuration settings. + + Args: + moduleConfigProfileFile (str): Path to the profile configuration file for the HDMI CEC module. + session: Optional session object for managing interactions with the device. + targetWorkspace (str, optional): Target workspace directory on the device. Defaults to "/tmp". + + Returns: + None + """ + self.moduleName = "hdmicec" + self.testConfigFile = os.path.join(dir_path, "hdmiCEC_testConfig.yml") + self.testSuite = "L3 HDMICEC Functions" + + # Prepare the profile file on the target workspace + self.moduleConfigProfile = ConfigRead( moduleConfigProfileFile , self.moduleName) + profileOnTarget = os.path.join(targetWorkspace, os.path.basename(moduleConfigProfileFile)) + self.testConfig = ConfigRead(self.testConfigFile, self.moduleName) + self.testConfig.test.execute = os.path.join(targetWorkspace, self.testConfig.test.execute) + f" -p {profileOnTarget}" + self.utMenu = UTSuiteNavigatorClass(self.testConfig, None, session) + self.testSession = session + self.utils = utBaseUtils() + + # Copy required artifacts to the target workspace + for artifact in self.testConfig.test.artifacts: + filesPath = os.path.join(dir_path, artifact) + self.utils.rsync(self.testSession, filesPath, targetWorkspace) + + # Copy the profile configuration to the target workspace + self.utils.scpCopy(self.testSession, moduleConfigProfileFile, targetWorkspace) + + # Start the user interface menu + self.utMenu.start() + + def searchPattern(self, haystack, pattern): + """ + Searches for the first occurrence of a specified pattern in the provided string. + + Args: + haystack (str): The string to be searched. + pattern (str): The regular expression pattern to search for. + + Returns: + str: The first capturing group of the match if found; otherwise, None. + + Notes: + - The pattern should contain at least one capturing group (parentheses). + - If no match is found, None is returned. + """ + match = re.search(pattern, haystack) + if match: + return match.group(1) + return None + + def initialise(self): + """ + Initializes the HDMI CEC module for sink. + + Args: + None. + + Returns: + None + """ + result = self.utMenu.select( self.testSuite, "Init HDMI CEC") + + def terminate(self): + """ + Terminates the hdmi cec module + + Args: + None + + Returns: + None + """ + result = self.utMenu.select(self.testSuite, "Close HDMI CEC") + + def addLogicalAddress(self, logicalAddress:str='0'): + """ + Add a logical address for the device. + + Args: + logicalAddress (str, optional): Logical address of the device. Defaults to '0'. Value ranges from '0' - 'f' + + Returns: + None + """ + promptWithAnswers = [ + { + "query_type": "direct", + "query": "Enter Logical Address:", + "input": logicalAddress + } + ] + result = self.utMenu.select(self.testSuite, "Add Logical Address", promptWithAnswers) + + def removeLogicalAddress(self): + """ + Remove the logical address of the device. + + Args: + None + + Returns: + None + """ + result = self.utMenu.select(self.testSuite, "Remove Logical Address") + + def getLogicalAddress(self): + """ + Get the logical address of the device. + + Args: + None. + + Returns: + str: Logical address of the device. Value ranges from '0' - 'f' + """ + result = self.utMenu.select( self.testSuite, "Get Logical Address") + connectionStatusPattern = r"Result HdmiCecGetLogicalAddress\(IN:handle:\[0x[0-9A-F]+\], OUT:logicalAddress:\[([0-9A-Fa-f]+)\]\)" + logicalAddress = self.searchPattern(result, connectionStatusPattern) + + return logicalAddress + + def getPhysicalAddress(self): + """ + Get the physical address of the device. + + Args: + None. + + Returns: + str: Physical Address of the DUT. + """ + result = self.utMenu.select( self.testSuite, "Get Phyiscal Address") + + addressBytes = None + pattern = r"Result HdmiCecGetPhysicalAddress\(IN:handle:.*OUT:physicalAddress:\[([\da-fA-F]\.[\da-fA-F]\.[\da-fA-F]\.[\da-fA-F])\]" + physicalAddress = self.searchPattern(result, pattern) + if physicalAddress: + parts = physicalAddress.split(".") + high_byte = hex(int(parts[0], 16) << 4 | int(parts[1], 16)) + low_byte = hex(int(parts[2], 16) << 4 | int(parts[3], 16)) + addressBytes = [high_byte, low_byte] + + return addressBytes + + def cecTransmitCmd(self, destLogicalAddress:str, cecCommand:str, cecData:list=None): + """ + Transmit or broadcast a CEC command to a specified destination. + + Args: + destLogicalAddress (str): Destination logical address. + cecCommand (str): CEC command in hexadecimal. + cecData (list, optional): List of data bytes to include in the transmission. + + Returns: + None + """ + + promptWithAnswers = [ + { + "query_type": "direct", + "query": "Enter a valid Destination Logical Address:", + "input": destLogicalAddress + }, + { + "query_type": "direct", + "query": "Enter CEC Command (in hex):", + "input": cecCommand + }, + ] + + if cecData: + for byte in cecData: + promptWithAnswers.append( + { + "query_type": "direct", + "query": "Enter Databyte", + "input": str(byte) + }) + + result = self.utMenu.select( self.testSuite, "Transmit CEC Command",promptWithAnswers) + + pattern = r"Result HdmiCecTx\(.*OUT:result:\[(.*?)\]\).*HDMI_CEC_STATUS:\[(.*?)\]" + + txStatus = self.searchPattern(result, pattern) + + status = False + if txStatus == "HDMI_CEC_IO_SENT_AND_ACKD" or txStatus == "HDMI_CEC_IO_SENT_BUT_NOT_ACKD": + status = True + + return status + + def readCallbackDetails (self): + """ + Parses the callback logs from the device. + + Args: + None. + + Returns: + dict: A dictionary with two keys: + - "Received": A list of dictionaries containing details about received opcodes. + - "Response": A list of dictionaries containing details about sent response opcodes. + Each dictionary contains the following keys: + - "Opcode" (str): The opcode value in hexadecimal. + - "Description" (str): A textual description of the opcode. + - "Initiator" (str): The initiator address in hexadecimal. + - "Destination" (str): The destination address in hexadecimal. + - "Data" (list): The data associated with the opcode. + """ + result = {"Received": [], "Response": []} + + callbackLogs = self.testSession.read_all() + + received_pattern = re.compile( + r"Received Opcode: \[([^\]]+)\] \[([^\]]+)\] Initiator: \[([^\]]+)\], Destination: \[([^\]]+)\] Data: \[(.*?)\]" + ) + sent_pattern = re.compile( + r"Sent Response Opcode: \[([^\]]+)\] \[([^\]]+)\] Initiator: \[([^\]]+)\], Destination: \[([^\]]+)\] Data: \[(.*?)\]" + ) + + def parse_data_field(data_field): + # Split the data field into an array of hex values + return ["0x" + value.strip() for value in data_field.split(":")] + + for match in received_pattern.finditer(callbackLogs): + opcode, description, initiator, destination, data = match.groups() + result["Received"].append({ + "Opcode": opcode, + "Description": description, + "Initiator": initiator, + "Destination": destination, + "Data": parse_data_field(data) + }) + + for match in sent_pattern.finditer(callbackLogs): + opcode, description, initiator, destination, data = match.groups() + result["Response"].append({ + "Opcode": opcode, + "Description": description, + "Initiator": initiator, + "Destination": destination, + "Data": parse_data_field(data) + }) + + return result + + def getDeviceType(self): + """ + Retrieves the type of the audio device. + + Args: + None. + + Returns: + str: The type of device: + - "sink" - sink device. + - "source" - source device. + - None if the device type is unknown or unsupported. + """ + type = self.moduleConfigProfile.fields.get("type") + + return type + + def __del__(self): + """ + Cleans up and de-initializes the hdmi cec helper by stopping the test menu. + + Args: + None. + + Returns: + None + """ + self.utMenu.stop() + +# Test and example usage code +if __name__ == '__main__': + + shell = InteractiveShell() + shell.open() + + platformProfile = dir_path + "/../../../profiles/sink/sink_hdmiCEC.yaml" + + # test the class assuming that it's optional + test = hdmiCECClass(platformProfile, shell) + + # Initialize the hdmiCEC module + test.initialise() + + # Add the logical Address. For now 0 only. + test.addLogicalAddress(0) + + # Get Physical Address + physicalAddress = test.getPhysicalAddress() + + # Broadcast 0x85 cec command + test.cecTransmitCmd('f', '0x85') + + # Transmitt 0x04 cec command to '1' + test.cecTransmitCmd('1', '0x85') + + # Read the callback details + result = test.readCallbackDetails() + + # Close the device + test.terminate() + + shell.close() diff --git a/host/tests/classes/hdmiCEC_testConfig.yml b/host/tests/classes/hdmiCEC_testConfig.yml new file mode 100644 index 0000000..18ed34e --- /dev/null +++ b/host/tests/classes/hdmiCEC_testConfig.yml @@ -0,0 +1,65 @@ +#** ***************************************************************************** +# * +# * 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: + description: "hdmi CEC testing profile / menu system for UT" + test: + artifacts: + #List of artifacts folders, test class copies the content of folder to the target device workspace + - "../../../bin/" + # exectute command, this will appended with the target device workspace path + execute: "run.sh" + type: UT-C # C (UT-C Cunit) / C++ (UT-G (g++ ut-core gtest backend)) + suites: + 0: + name: "L1 hdmicec" + tests: + - "open_Positive" + - "open_negative" + - "close_Positive" + - "close_negative" + - "getPhysicalAddress_Positive" + - "getPhysicalAddress_negative" + - "setRxCallback_Positive" + - "setRxCallback_negative" + - "addLogicalAddress_Positive" + - "addLogicalAddress_negative" + - "removeLogicalAddress_Positive" + - "removeLogicalAddress_negative" + 1: + name: "L2 hdmicec - Sink" + tests: + - "L2_GetDefaultLogicalAddress_Sink" + - "L2_AddAndGetLogicalAddress_Sink" + - "L2_RemoveLogicalAddress_Sink" + - "L2_BroadcastHdmiCecCommand_Sink" + - "L2_VerifyPhysicalAddress_Sink" + - "L2_TransmitCECCommand_Sink" + 2: + name: "L3 HDMICEC Functions" + tests: + - "Init HDMI CEC" + - "Add Logical Address" + - "Get Logical Address" + - "Transmit CEC Command" + - "Get Phyiscal Address" + - "Remove Logical Address" + - "Close HDMI CEC" diff --git a/host/tests/configs/deviceConfig.yml b/host/tests/configs/deviceConfig.yml new file mode 100644 index 0000000..91046a1 --- /dev/null +++ b/host/tests/configs/deviceConfig.yml @@ -0,0 +1,40 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2023 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. +# * +#* ****************************************************************************** + +# The information defined in this config is consistent across all devices of a type. + +deviceConfig: + cpe1: + platform: "element" + model: "uk" + soc_vendor: "amlogic" + target_directory: "/tmp/" # Target Directory on device + prompt: "" # Prompt string on console + test: + profile: "../../../profiles/sink/sink_hdmiCEC.yml" + cpe2: + platform: "test" + model: "test" + vendor: "test" + target_directory: "/tmp" + profile: "" + test: diff --git a/host/tests/configs/example_rack_config.yml b/host/tests/configs/example_rack_config.yml new file mode 100644 index 0000000..910b483 --- /dev/null +++ b/host/tests/configs/example_rack_config.yml @@ -0,0 +1,91 @@ +#** ***************************************************************************** +# * +# * If not stated otherwise in this file or this component's LICENSE file the +# * following copyright and licenses apply: +# * +# * Copyright 2023 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. +# * +#* ****************************************************************************** + +# This config file creates your environment, defaults are setup internally unless otherwise overridden. +# you will need at least 1 rack and 1 slot to operate. +# each module e.g. console options, will be off by default unless otherwise stated + +# Depreciated +# slotx: address: IP of device while running locally, replaced with slotx: ip +# slotx: deviceConsole: IP of device while running locally, replaced with slotx: devices + +# This example is taken from https://github.com/rdkcentral/python_raft/blob/master/examples/configs/example_rack_config.yml +# For information on python_raft please refer to : https://github.com/rdkcentral/python_raft/blob/master/README.md + +# Data that is global to all tests. +globalConfig: + includes: + # [ includes: ] + # [ deviceConfig: "required.yml file" ] + deviceConfig: "example_device_config.yml" + local: + log: # log for each slot + directory: "./logs" + delimiter: "/" + +# Define racks, their slots and the devices in them. These are not always physical racks and slots. +rackConfig: + rack1: + name: "rack1" + description: "example config at my desk" + slot1: + # [ name: "required", description: "optional"] + name: "slot1" + devices: + # [ devices: ] + # [ type: "serial": port: "COM7" baudRate: "(default)115200" dataBits: "optional(8)" stopBits: "optional(1)" parity: "optional(None)" FlowControl: "optional(None)" ] + # [ type: "ssh": port: 22 username: "test" password: "test" ] + # [ type: "telnet": port: 23 username: "test" password: "test" ] + - dut: + ip: "127.0.0.1" + description: "element" + platform: "element" + consoles: + - default: + type: "ssh" + port: 22 + username: "root" + ip: "127.0.0.1" + password: ' ' + - ssh_player: + type: "ssh" + port: 22 + username: "root" + ip: "127.0.0.1" + password: ' ' + - ssh_hal_test: + type: "ssh" + port: 22 + username: "root" + ip: "127.0.0.1" + password: ' ' + outbound: + download_url: "http://localhost:8000/" # download location for the CPE device + httpProxy: # Local Proxy if required + workspaceDirectory: './logs/workspace' # Local working directory + hdmiCECController: + type: remote-cec-client + vendor: "Pulse Eight" + adaptor: /dev/ttyACM0 # Adaptor device entry + address: "127.0.0.1" # Needs to be be filled out with IP address + username: "root" # Needs to be filled out with login username + password: ' ' # Needs to be filled out with login password diff --git a/host/tests/hdmiCEC_L3_Tests/hdmiCECHelperClass.py b/host/tests/hdmiCEC_L3_Tests/hdmiCECHelperClass.py new file mode 100755 index 0000000..db1fc0d --- /dev/null +++ b/host/tests/hdmiCEC_L3_Tests/hdmiCECHelperClass.py @@ -0,0 +1,103 @@ +#!/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) + self.testLogicalAddress = hdmicec.logicalAddress + + 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) + self.deviceType = self.testhdmiCEC.getDeviceType() + + return True + + def testEndFunction(self, powerOff=True): + + super().testEndFunction(powerOff) + # Clean up the hdmiCEC instance + del self.testhdmiCEC + diff --git a/host/tests/hdmiCEC_L3_Tests/hdmiCECTestCommands.yml b/host/tests/hdmiCEC_L3_Tests/hdmiCECTestCommands.yml new file mode 100644 index 0000000..ba480e4 --- /dev/null +++ b/host/tests/hdmiCEC_L3_Tests/hdmiCECTestCommands.yml @@ -0,0 +1,95 @@ +#** ***************************************************************************** +# * +# * 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: + logicalAddress: '0' + 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" diff --git a/host/tests/hdmiCEC_L3_Tests/hdmiCEC_L3_Runall.py b/host/tests/hdmiCEC_L3_Tests/hdmiCEC_L3_Runall.py new file mode 100644 index 0000000..6fc77e7 --- /dev/null +++ b/host/tests/hdmiCEC_L3_Tests/hdmiCEC_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", 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_L3_Tests/hdmiCEC_test01_TransmitCECCommands.py b/host/tests/hdmiCEC_L3_Tests/hdmiCEC_test01_TransmitCECCommands.py new file mode 100755 index 0000000..4bbb2f7 --- /dev/null +++ b/host/tests/hdmiCEC_L3_Tests/hdmiCEC_test01_TransmitCECCommands.py @@ -0,0 +1,152 @@ +#!/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.broadcastAddress = 'f' + + # Initialize the parent class + super().__init__(self.testName, self.qcID, log) + + def testVerifyTxResults(self, txResult:str, rxResult:bool): + """ + Verifies the tx and rx results. + + Args: + txResult(str): tx result + rxResult(bool): rx result + Returns: + bool: Final result of the test. + """ + + return rxResult + + 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() + + # Add the logical Address. + self.testhdmiCEC.addLogicalAddress(self.testLogicalAddress) + + # Get the logical Address. + deviceLogicalAddress = self.testhdmiCEC.getLogicalAddress() + + # List all connected CEC devices + self.cecDevices = self.hdmiCECController.listDevices() + + # Final test result + finalResult = True + + for device in self.cecDevices: + logicalAddress = device["logical address"] + + # Skip sending messages to TV + if logicalAddress == deviceLogicalAddress: + continue + + for command in self.cecCommands: + 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 + + self.log.stepStart(f'HdmiCecTx Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cec} Payload: {payload}') + + # Transmit the CEC command + txResults = self.testhdmiCEC.cecTransmitCmd(destinationLogicalAddress, cec, payload) + + self.log.stepResult(txResults, f'HdmiCecTx Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cec} Payload: {payload}') + + finalResult &= txResults + + time.sleep(2) + + self.log.stepStart(f'HdmiCecTx Receive Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cec} Payload: {payload}') + # Validate the transmission + rxResult = self.hdmiCECController.checkMessageReceived(deviceLogicalAddress, destinationLogicalAddress, cec, payload=payload) + + self.log.stepResult(rxResult, f'HdmiCecTx Receive Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cec} Payload: {payload}') + + finalResult &= rxResult + + # 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) diff --git a/host/tests/hdmiCEC_L3_Tests/hdmiCEC_test02_ReceiveCECCommands.py b/host/tests/hdmiCEC_L3_Tests/hdmiCEC_test02_ReceiveCECCommands.py new file mode 100644 index 0000000..7566811 --- /dev/null +++ b/host/tests/hdmiCEC_L3_Tests/hdmiCEC_test02_ReceiveCECCommands.py @@ -0,0 +1,188 @@ +#!/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, "../")) + +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.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() + + # Add the logical Address. + self.testhdmiCEC.addLogicalAddress(self.testLogicalAddress) + + # Get the logical Address. + deviceLogicalAddress = self.testhdmiCEC.getLogicalAddress() + + # Get Physical Address + devicePhysicalAddress = self.testhdmiCEC.getPhysicalAddress() + + # Ensure the logical address is retrieved successfully + if deviceLogicalAddress is None: + self.log.error("Failed to get the device logical address") + return False + + # List all connected CEC devices + self.cecDevices = self.hdmiCECController.listDevices() + + finalResult = True + + for device in self.cecDevices: + logicalAddress = device["logical address"] + + # Skip sending messages to TV + if logicalAddress == deviceLogicalAddress: + continue + + cecAdapterLogicalAddress = logicalAddress + + 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: Source: {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: Source: {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") + if response.get("update_payload"): + payload[0] = devicePhysicalAddress[0] + payload[1] = devicePhysicalAddress[1] + + self.log.stepStart(f'Response Test: Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cecOpcode} Payload: {payload}') + result = self.hdmiCECController.checkMessageReceived(deviceLogicalAddress, destinationLogicalAddress, cecOpcode, payload=payload) + self.log.stepResult(result, f'Response Test: Source: {deviceLogicalAddress} Destination: {destinationLogicalAddress} CEC OPCode: {cecOpcode} Payload: {payload}') + + finalResult &= result + + # 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) diff --git a/profiles/sink/sink_hdmiCEC.yml b/profiles/sink/sink_hdmiCEC.yml index 323bf59..b4a6d9a 100644 --- a/profiles/sink/sink_hdmiCEC.yml +++ b/profiles/sink/sink_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 + diff --git a/profiles/source/source_hdmiCEC.yml b/profiles/source/source_hdmiCEC.yml index 7b8fff6..67b4790 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 + diff --git a/src/main.c b/src/main.c index 7170e87..5c18bb2 100644 --- a/src/main.c +++ b/src/main.c @@ -70,6 +70,8 @@ extern int register_hdmicec_hal_source_l1_tests( void ); extern int register_hdmicec_hal_sink_l1_tests( void ); extern int register_hdmicec_hal_source_l2_tests( void ); extern int register_hdmicec_hal_sink_l2_tests( void ); +extern int register_hdmicec_hal_sink_l3_tests( void ); + #ifdef VCOMPONENT extern int register_vcomponent_tests ( char* profile ); @@ -111,35 +113,20 @@ int main(int argc, char** argv) } optind = 1; //Reset argv[] element pointer for further processing #endif - + /* Register tests as required, then call the UT-main to support switches and triggering */ UT_init( argc, argv ); - status = ut_kvp_getStringField(ut_kvp_profile_getInstance(), "hdmicec/type", szReturnedString, UT_KVP_MAX_ELEMENT_SIZE); - if (status == UT_KVP_STATUS_SUCCESS ) { - UT_LOG_DEBUG("Device Type: %s", szReturnedString); - } - else { - UT_LOG_ERROR("Failed to get the platform Device Type"); - return -1; - } - register_hdmicec_hal_common_l1_tests(); #ifdef VCOMPONENT register_vcomponent_tests(pProfilePath); test_l3_hdmi_cec_driver_register (pValidationProfilePath); #endif - - if(strncmp(szReturnedString,"source",UT_KVP_MAX_ELEMENT_SIZE) == 0) { - register_hdmicec_hal_source_l1_tests (); - register_hdmicec_hal_source_l2_tests (); - } - - if(strncmp(szReturnedString,"sink",UT_KVP_MAX_ELEMENT_SIZE) == 0) { - register_hdmicec_hal_sink_l1_tests (); - register_hdmicec_hal_sink_l2_tests (); - } - + register_hdmicec_hal_source_l1_tests (); + register_hdmicec_hal_source_l2_tests (); + register_hdmicec_hal_sink_l1_tests (); + register_hdmicec_hal_sink_l2_tests (); + register_hdmicec_hal_sink_l3_tests (); UT_run_tests(); #ifdef VCOMPONENT diff --git a/src/test_l3_hdmi_cec_driver.c b/src/test_l3_hdmi_cec_driver.c index 51a7bcb..68105f2 100644 --- a/src/test_l3_hdmi_cec_driver.c +++ b/src/test_l3_hdmi_cec_driver.c @@ -1,536 +1,809 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2023 RDK Management +/* +* 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 +* 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 +* 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. +* 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 + * @{ + * + */ /** -* @file TODO: test_l3_hdmi_cec_driver.c -* @page module_name TODO: Required field, name of the main module -* @subpage sub_page_name TODO: Add a function group if relevant -* -* ## Module's Role -* TODO: Explain the module's role in the system in general -* This is to ensure that the API meets the operational requirements of the module across all vendors. -* -* **Pre-Conditions:** TODO: Add pre-conditions if any@n -* **Dependencies:** TODO: Add dependencies if any@n -* -* Ref to API Definition specification documentation :[hdmi-cec_halSpec.md](../../docs/pages/hdmi-cec_halSpec.md) -*/ + * @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 Sink 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 + */ -#include -#include -#include -#include -#include -#include +/** + * @file test_l3_hdmi_cec_driver.c + * + */ +#include #include #include #include +#include #include "hdmi_cec_driver.h" -#define DEFAULT_LOGICAL_ADDRESS_PANEL 0 - -#define MAX_WAIT_TIME_SECS 30 -#define MAX_DATA_SIZE 64 - -#define CEC_IMAGE_VIEW_ON 0x04 -#define CEC_TEXT_VIEW_ON 0x0D -#define CEC_STANDBY 0x36 -#define CEC_SET_OSD_NAME 0x49 -#define CEC_ACTIVE_SOURCE 0x82 -#define CEC_REQUEST_ACTIVE_SOURCE 0x85 -#define CEC_INACTIVE_SOURCE 0x9D -#define CEC_COMMAND_UNKNOWN 0x00 - -#define CMD_IMAGE_VIEW_ON "ImageViewOn" -#define CMD_TEXT_VIEW_ON "TextViewOn" -#define CMD_STANDBY "StandBy" -#define CMD_ACTIVE_SOURCE "ActiveSource" -#define CMD_REQUEST_ACTIVE_SOURCE "RequestActiveSource" -#define CMD_INACTIVE_SOURCE "InactiveSource" -#define CMD_SET_OSD_NAME "SetOSDName" - -#define VP_PREFIX "hdmicec/" -#define CMD_DATA_OSD_NAME "/osd_name" -#define VP_RESULT_INITIATOR "/result/initiator" -#define VP_RESULT_DESTINATION "/result/destination" -#define VP_RESULT_OPCODE "/result/opcode" -#define VP_RESULT_PARAMETER_SIZE "/result/parameters/size" -#define VP_RESULT_PARAMETER_DATA "/result/parameters/data/" - -#define COUNT(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#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 HDMI_CEC_DEVICE_TYPE_SIZE 8 + +#define UT_LOG_MENU_INFO UT_LOG_INFO typedef struct { - char* str; - int val; -} strVal_t; - -const static strVal_t gOpCode [] = { - { CMD_IMAGE_VIEW_ON, CEC_IMAGE_VIEW_ON }, - { CMD_TEXT_VIEW_ON, CEC_TEXT_VIEW_ON }, - { CMD_SET_OSD_NAME, CEC_SET_OSD_NAME }, - { CMD_STANDBY , CEC_STANDBY }, - { CMD_ACTIVE_SOURCE, CEC_ACTIVE_SOURCE }, - { CMD_REQUEST_ACTIVE_SOURCE, CEC_REQUEST_ACTIVE_SOURCE }, - { CMD_INACTIVE_SOURCE, CEC_INACTIVE_SOURCE } -}; + 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 + bool updatePhysicalAddress; +} 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} +}; -static UT_test_suite_t * pSuite = NULL; -static int gTestGroup = 1; -static int gTestID = 1; +/* 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 uint8_t gExpectedCecCommand = CEC_COMMAND_UNKNOWN; //Set teach test before waiting for trigger -static sem_t gSemCallbackReceived; -static uint8_t gCommandValidated = CEC_COMMAND_UNKNOWN; //Set by receive callback after test validation is successful +typedef enum HDMI_CEC_DEVICE_TYPE_t +{ + SINK = 0, + SOURCE = 1 +}HDMI_CEC_DEVICE_TYPE; + +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; +static HDMI_CEC_DEVICE_TYPE gDeviceType = SINK; +/** +* @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) +{ -static ut_kvp_instance_t *gValidationProfileInstance = NULL; + int32_t tableSize = sizeof(cecCommandTable) / sizeof(CecCommandMap); -int GetOpCode(const strVal_t *map, int length, char* str) -{ - int result = -1; - - if(map == NULL || length <= 0 || str == NULL) - { - return result; - } - - for (int i = 0; i < length; ++i) - { - if (!strcmp(str, map[i].str)) + for (int32_t i = 0; i < tableSize; i++) { - result = map[i].val; - break; + if (cecCommandTable[i].cecCommand == cecCommand) + { + *commandName = cecCommandTable[i].commandName; + *dataLength = cecCommandTable[i].dataLength; + return 0; // Command found + } } - } - return result; -} -char* GetOpCodeString(const strVal_t *map, int length, int val) -{ - char* result = NULL; - - if(map == NULL || length <= 0) - { - return NULL; - } - - for (int i = 0; i < length; ++i) - { - if (val == (int)map[i].val) - { - result = map[i].str; - break; - } - } - return result; + return -1; // Command not found } - /** - * @brief hdmicec receive message callback - * - * @param handle Hdmi device handle - * @param callbackData callback data passed - * @param buf receive message buffer passed - * @param len receive message buffer length + * @brief This function clears the stdin buffer. + * + * This function clears the stdin buffer. */ -void ReceiveCallback(int handle, void *callbackData, unsigned char *buf, int len) +static void readAndDiscardRestOfLine(FILE *in) { - uint8_t src, dest, opcode; - uint8_t expected_src, expected_dest, expected_opcode; - uint8_t physical_address[4]; - char* expected_command = NULL; - ut_kvp_instance_t *vp_instance; - char szReturnedString[UT_KVP_MAX_ELEMENT_SIZE]; - char field_name[UT_KVP_MAX_ELEMENT_SIZE]; - uint8_t parameter_data[UT_KVP_MAX_ELEMENT_SIZE]; - uint8_t parameter_size = 0; - int length = 0, field_len = 0; - - UT_LOG ("\nBuffer generated: %x length: %d\n",buf, len); - if((handle!=0) && (callbackData !=NULL) && (len>0)) - { - vp_instance = (ut_kvp_instance_t *)callbackData; + int32_t c; + while ((c = fgetc(in)) != EOF && c != '\n'); +} - UT_LOG("\nCall back data generated is \n"); - for (int index=0; index < len; index++) - { - UT_LOG("buf at index : %d is %x", index, buf[index]); - } +static void readInt(int32_t *value) +{ + scanf("%d", value); + readAndDiscardRestOfLine(stdin); +} - src = (buf[0] & 0xF0) >> 4; - dest = buf[0] & 0x0F; - opcode = buf[1]; +static void readHex(int32_t *value) +{ + scanf("%x", value); + readAndDiscardRestOfLine(stdin); +} - expected_command = GetOpCodeString(gOpCode, COUNT(gOpCode), gExpectedCecCommand); - strcpy(field_name, VP_PREFIX); - strcpy(field_name + strlen(VP_PREFIX), expected_command); - length = strlen(field_name); +static bool getCommandResponse(uint8_t opcode, cecResponse_t *pResponse) +{ + uint32_t numCommands = 0; + char key_string[HDMI_CEC_KVP_SIZE] = {0}; - strcpy(field_name + length, VP_RESULT_INITIATOR); - expected_src = ut_kvp_getUInt8Field (vp_instance, field_name); + memset(pResponse, 0, sizeof(cecResponse_t)); - strcpy(field_name + length, VP_RESULT_DESTINATION); - expected_dest = ut_kvp_getUInt8Field (vp_instance, field_name); + numCommands = UT_KVP_PROFILE_GET_LIST_COUNT("hdmicec/cec_responses"); - strcpy(field_name + length, VP_RESULT_OPCODE); - expected_opcode = ut_kvp_getUInt8Field (vp_instance, field_name); + for(uint32_t i = 0; i < numCommands; i++) + { + uint8_t command; + uint8_t found; - strcpy(field_name + length, VP_RESULT_PARAMETER_SIZE); - parameter_size = ut_kvp_getUInt8Field (vp_instance, field_name); - field_len = strlen(field_name); - strcpy(field_name + length, VP_RESULT_PARAMETER_DATA); + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/command" , i); + command = UT_KVP_PROFILE_GET_UINT8(key_string); - for (int i = 0; i < parameter_size; ++i) + if(command != opcode) { - int num_len = snprintf( NULL, 0, "%d", i ); - snprintf( field_name + field_len + 1 , num_len + 1, "%d", i ); - parameter_data[i] = ut_kvp_getUInt8Field (vp_instance, field_name); - UT_LOG("Expected Parameter data at [%d]: 0x%02x",i,parameter_data[i]); + 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); - UT_LOG("\nExpected Command[%s] Src[%d] Dest[%d] \n", (GetOpCodeString(gOpCode, COUNT(gOpCode), gExpectedCecCommand)),expected_src, expected_dest); - UT_LOG("\nCommand[%s] triggered Src[%d] Dest[%d] \n", (GetOpCodeString(gOpCode, COUNT(gOpCode), opcode)),src, dest); - - switch (opcode) + if(found) { - case CEC_ACTIVE_SOURCE: - case CEC_INACTIVE_SOURCE: - { - UT_LOG("\nPhysicalAddress[%d.%d.%d.%d]\n",(buf[2] >> 4) & 0x0F, buf[2] & 0x0F, (buf[3] >> 4) & 0xF0, buf[3] & 0x0F); - } - break; - case CEC_SET_OSD_NAME: + 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, 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++) { - char str[len - 1]; - memcpy(str, &buf[2], len-2); - str[len-2] = '\0'; - UT_LOG("\nosd_name[%s]\n", str); + 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); } - break; - } - //Lets see if this the opcode that was expected. If it is not test will timeout - if(gExpectedCecCommand == opcode) - { - //Lets validate the addresses and opcode - if(src == expected_src && dest == expected_dest && opcode == expected_opcode) + + snprintf(key_string, HDMI_CEC_KVP_SIZE, "hdmicec/cec_responses/%d/response/update_payload" , i); + pResponse->updatePhysicalAddress = UT_KVP_PROFILE_GET_BOOL(key_string); + + if (pResponse->updatePhysicalAddress) { - UT_LOG("\nParameter size[%d] received size[%d]\n", parameter_size, len - 2); - //Expected parameter size should be equal to length of cec buffer received minus 2 (Address, opcode bytes) - gCommandValidated = gExpectedCecCommand; - if(parameter_size > 0) - { - if((parameter_size != (len - 2)) || (memcmp(parameter_data, &buf[2], parameter_size) != 0)) - { - gCommandValidated = CEC_COMMAND_UNKNOWN; - } - } + pResponse->payload[0] = (((uint8_t)gPhysicalAddressBytes[3] << 4) & 0xF0) | (gPhysicalAddressBytes[2] & 0x0F); + pResponse->payload[1] = (((uint8_t)gPhysicalAddressBytes[1] << 4) & 0xF0) | (gPhysicalAddressBytes[0] & 0x0F); } - //Even if the validation fails, signal the test as the opcode is same. - sem_post(&gSemCallbackReceived); + + return true; } } - else + 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) { - if (handle == 0) { - UT_FAIL("Error: Invalid handle.\n"); + int32_t result; + const char* commandName; + int32_t expectedDataLength; + + if (!strcmp(pCecResponse->type, "Direct")) + { + response[0] = (destination << 4) | initiator; } - if (callbackData == NULL) { - UT_FAIL("Error: Null callback data.\n"); + else + { + //Send braodcast message + response[0] = (gLogicalAddress << 4) | gBroadcastAddress; } - if (len <= 0) { - UT_FAIL("Error: Invalid length.\n"); + 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(temp, HDMI_CEC_MAX_PAYLOAD, "%02X:", response[index]); + temp += len; + } + prBuffer[strlen(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); } } -/** - * @brief callback to get the async send message status - * - * @param handle Hdmi device handle - * @param callbackData callback data passed - * @param result async send status - */ -void TransmitCallback(int handle, void *callbackData, int result) +static void onRxDataReceived(int32_t handle, void *callbackData, uint8_t *buf, int32_t len) { - if((handle!=0) && (callbackData !=NULL)) { - //UT_ASSERT_TRUE_FATAL( (unsigned long long)callbackData== (unsigned long long)0xDEADBEEF); - UT_LOG ("\ncallbackData returned: %x result: %d\n",callbackData, result); - } -} + 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; -int TimedWaitForCallback(uint32_t timeOutSeconds) -{ - int s, result = -1; - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += timeOutSeconds; - while ((s = sem_timedwait(&gSemCallbackReceived, &ts)) == -1 && errno == EINTR) + if ((handle != 0) && (callbackData != NULL) && (len > 0)) { - continue; /* Restart if interrupted by handler */ - } + // 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; + } - /* Check what happened */ - if (s == -1) - { - if (errno == ETIMEDOUT) + opcode = buf[1]; + + if(getCecCommandInfo(opcode, &commandName, &expectedDataLength) != 0) { - result = 1; + 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(temp, HDMI_CEC_MAX_PAYLOAD, "%02X:", buf[index]); + temp += len; + } + prBuffer[strlen(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); + + sendResponse(handle, initiator, destination, buf, len, &cecResponse); } else { - result = 0; + // 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"); + } } - return result; +exit: + UT_LOG_INFO("Out %s\n", __FUNCTION__); } - /** -* HdmiCecOpen() Positive -* HdmiCec -* +* @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 +* */ -void test_l3_sink_image_view_on (void) +void test_l3_hdmi_cec_hal_Init(void) { - int result; - int handle = 0; gTestID = 1; + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; + int32_t getLogicalAddress = -1; + + 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); + + gPhysicalAddressBytes = (uint8_t*)&gPhysicalAddress; + + 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:[%01x.%01x.%01x.%01x]) HDMI_CEC_STATUS:[%s]", gHandle, + gPhysicalAddressBytes[3], gPhysicalAddressBytes[2], gPhysicalAddressBytes[1], gPhysicalAddressBytes[0], + UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + + if (gDeviceType == SOURCE) + { + UT_LOG_INFO("Calling HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[])", gHandle); + status = HdmiCecGetLogicalAddress(gHandle, &getLogicalAddress); + UT_LOG_INFO("Result HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[%x]) HDMI_CEC_STATUS:[%s])", gHandle, getLogicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); - UT_LOG("\n In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecOpen( &handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("open failed"); } + gLogicalAddress = getLogicalAddress; + } - result = HdmiCecSetRxCallback(handle, ReceiveCallback, (void*)gValidationProfileInstance); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetRxCallback failed"); } + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} + +/** +* @brief This test provides a scope to add the sink logical address. Usually it shall be zero. +* +* This test case provides a scope to add the available sink logical address +* to a Device under test. +* +* Note: +* This applies only for the Sink Devices. +* Source devices will get the logical address during CEC open. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 002@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be intialized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +*/ +void test_l3_hdmi_cec_hal_AddLogicalAddress(void) +{ + gTestID = 2; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecSetTxCallback( handle, TransmitCallback, (void*)0xDEADBEEF ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetTxCallback failed"); } + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; - result = HdmiCecAddLogicalAddress( handle, DEFAULT_LOGICAL_ADDRESS_PANEL ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecAddLogicalAddress failed"); } + int32_t logicalAddress = -1; + int32_t getLogicalAddress = -1; - gExpectedCecCommand = CEC_IMAGE_VIEW_ON; - gCommandValidated = CEC_COMMAND_UNKNOWN; + UT_LOG_MENU_INFO("Enter Logical Address:"); + readHex(&logicalAddress); - UT_LOG ("\nTrigger ImageViewOn\n"); - result = TimedWaitForCallback(MAX_WAIT_TIME_SECS); - if(result != 0) - { - UT_FAIL("Failed to receive ImageViewOn"); - } - if(gCommandValidated != gExpectedCecCommand) + if (gDeviceType == SOURCE) { - UT_FAIL("Test Validation of ImageViewOn failed"); + UT_LOG_ERROR("Source Device doesn't support add logical Address"); + UT_LOG_INFO("Out %s\n", __FUNCTION__); + return; } - result = HdmiCecClose( handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("close failed"); } -} - -void test_l3_sink_text_view_on (void) -{ - int result; - int handle = 0; - gTestID = 1; + /* Check that logical address should be valid one */ + UT_LOG_INFO("Calling HdmiCecAddLogicalAddress(IN:handle:[0x%0X], IN:logicalAddress:[%x]", gHandle, logicalAddress); + status = HdmiCecAddLogicalAddress(gHandle, logicalAddress); + UT_LOG_INFO("Result HdmiCecAddLogicalAddress (IN:handle:[0x%0X], IN:logicalAddress:[%x]) HDMI_CEC_STATUS[%s]",gHandle,logicalAddress,UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); - UT_LOG("\n In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecOpen( &handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("open failed"); } + UT_LOG_INFO("Calling HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[])", gHandle); + status = HdmiCecGetLogicalAddress(gHandle, &getLogicalAddress); + UT_LOG_INFO("Result HdmiCecGetLogicalAddress(IN:handle:[0x%0X], OUT:logicalAddress:[%x]) HDMI_CEC_STATUS:[%s])", gHandle, getLogicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + assert(logicalAddress == getLogicalAddress); - result = HdmiCecSetRxCallback(handle, ReceiveCallback, (void*)gValidationProfileInstance); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetRxCallback failed"); } + gLogicalAddress = getLogicalAddress; - result = HdmiCecSetTxCallback( handle, TransmitCallback, (void*)0xDEADBEEF ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetTxCallback failed"); } + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} - result = HdmiCecAddLogicalAddress( handle, DEFAULT_LOGICAL_ADDRESS_PANEL ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecAddLogicalAddress failed"); } +/** +* @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:** 003@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be intialized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +*/ +void test_l3_hdmi_cec_hal_GetLogicalAddress(void) +{ + gTestID = 3; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - gExpectedCecCommand = CEC_TEXT_VIEW_ON; - gCommandValidated = CEC_COMMAND_UNKNOWN; + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; + int32_t logicalAddress = -1; - UT_LOG ("\nTrigger TextViewOn\n"); - result = TimedWaitForCallback(MAX_WAIT_TIME_SECS); - if(result != 0) - { - UT_FAIL("Failed to receive TextViewOn"); - } - if(gCommandValidated != gExpectedCecCommand) - { - UT_FAIL("Test Validation of TextViewOn failed"); - } - result = HdmiCecClose( handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("close failed"); } + 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:[%x]) HDMI_CEC_STATUS:[%s])", gHandle, logicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); + assert(logicalAddress >= 0 && logicalAddress <= 15); + gLogicalAddress = logicalAddress; + UT_LOG_INFO("Out %s\n", __FUNCTION__); } -void test_l3_sink_active_source (void) -{ - int result; - int handle = 0; - gTestID = 1; +/** +* @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:** 004@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be intialized through Test 1 before calling this test. +* Logical Address should be added through Test 2 before calling this test. +* +* **Dependencies:** None@n +* +*/ +void test_l3_hdmi_cec_hal_TransmitHdmiCecCommand(void) { + gTestID = 4; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - UT_LOG("\n In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecOpen( &handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("open failed"); } + 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; - result = HdmiCecSetRxCallback(handle, ReceiveCallback, (void*)gValidationProfileInstance); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetRxCallback failed"); } + assert(sourceLogicalAddress != -1); - result = HdmiCecSetTxCallback( handle, TransmitCallback, (void*)0xDEADBEEF ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetTxCallback failed"); } + // Reading inputs from the user or test framework + UT_LOG_MENU_INFO("Enter a valid Destination Logical Address: "); + readHex(&destinationLogicalAddress); - result = HdmiCecAddLogicalAddress( handle, DEFAULT_LOGICAL_ADDRESS_PANEL ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecAddLogicalAddress failed"); } + UT_LOG_MENU_INFO("Enter CEC Command (in hex): "); + readHex(&cecCommand); - gExpectedCecCommand = CEC_ACTIVE_SOURCE; - gCommandValidated = CEC_COMMAND_UNKNOWN; + // 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 ("\nTrigger ActiveSource\n"); - result = TimedWaitForCallback(MAX_WAIT_TIME_SECS); - if(result != 0) + UT_LOG_MENU_INFO("Enter the number of data bytes for the CEC command:"); + readInt(&expectedDataLength); + commandName = "Vendor Specific Command"; + } + else { - UT_FAIL("Failed to receive ActiveSource"); + UT_LOG_INFO("CEC Command: %s (0x%02X), expects %d data byte(s)", commandName, cecCommand, expectedDataLength); } - if(gCommandValidated != gExpectedCecCommand) + + // If the command has data bytes, prompt for them + if (expectedDataLength > 0) { - UT_FAIL("Test Validation of ActiveSource failed"); + 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 + } } - result = HdmiCecClose( handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("close failed"); } + // 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 || status == HDMI_CEC_IO_SENT_AND_ACKD || status == HDMI_CEC_IO_SENT_BUT_NOT_ACKD ); + + UT_LOG_INFO("Out %s\n", __FUNCTION__); } -void test_l3_sink_inactive_source (void) +/** +* @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:** 005@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be intialized through Test 1 before calling this test. +* +* **Dependencies:** None@n +* +*/ +void test_l3_hdmi_cec_hal_GetPhysicalAddress(void) { - int result; - int handle = 0; - gTestID = 1; + gTestID = 5; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - UT_LOG("\n In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecOpen( &handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("open failed"); } + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; - result = HdmiCecSetRxCallback(handle, ReceiveCallback, (void*)gValidationProfileInstance); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetRxCallback failed"); } + 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:[%01x.%01x.%01x.%01x]) HDMI_CEC_STATUS:[%s]", gHandle, + gPhysicalAddressBytes[3], gPhysicalAddressBytes[2], gPhysicalAddressBytes[1], gPhysicalAddressBytes[0], + UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); - result = HdmiCecSetTxCallback( handle, TransmitCallback, (void*)0xDEADBEEF ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetTxCallback failed"); } + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} - result = HdmiCecAddLogicalAddress( handle, DEFAULT_LOGICAL_ADDRESS_PANEL ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecAddLogicalAddress failed"); } +/** +* @brief Test to Remove logical address +* +* This test provides a scope to remove the logical address of the device. HAL API to set +* to default logical addres 0xF once the logical address is removed. +* +* **Test Group ID:** 03@n +* +* **Test Case ID:** 006@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be intialized through Test 1 before calling this test. +* +* **Dependencies:** None@n +*/ +void test_l3_hdmi_cec_hal_RemoveLogicalAddress(void) +{ + gTestID = 6; + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - gExpectedCecCommand = CEC_INACTIVE_SOURCE; - gCommandValidated = CEC_COMMAND_UNKNOWN; + HDMI_CEC_STATUS status = HDMI_CEC_IO_SUCCESS; + int32_t logicalAddress = gLogicalAddress; + int32_t getLogicalAddress = 0; - UT_LOG ("\nTrigger InactiveSource\n"); - result = TimedWaitForCallback(MAX_WAIT_TIME_SECS); - if(result != 0) - { - UT_FAIL("Failed to receive InactiveSource"); - } - if(gCommandValidated != gExpectedCecCommand) + if (gDeviceType == SOURCE) { - UT_FAIL("Test Validation of InactiveSource failed"); + UT_LOG_ERROR("Source Device doesn't support remove logical Address"); + UT_LOG_INFO("Out %s\n", __FUNCTION__); + return; } - result = HdmiCecClose( handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("close failed"); } -} + assert(logicalAddress != -1); -void test_l3_sink_set_osd_name (void) -{ - int result; - int handle = 0; - gTestID = 1; + UT_LOG_INFO("Calling HdmiCecRemoveLogicalAddress(IN:handle:[0x%0X], IN:logicalAddress:[%d])", gHandle, logicalAddress); + status = HdmiCecRemoveLogicalAddress(gHandle, logicalAddress); + UT_LOG_INFO("Result HdmiCecRemoveLogicalAddress(IN:handle:[0x%0X], IN:logicalAddress:[%d]) HDMI_CEC_STATUS:[%s])", gHandle, logicalAddress, UT_Control_GetMapString(cecError_mapTable,status)); + assert(status == HDMI_CEC_IO_SUCCESS); - UT_LOG("\n In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecOpen( &handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("open failed"); } + gLogicalAddress = -1; - result = HdmiCecSetRxCallback(handle, ReceiveCallback, (void*)gValidationProfileInstance); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetRxCallback failed"); } + 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:** 007@n +* +* **Pre-Conditions:** @n +* HDMI-CEC Module should be intialized through Test 1 before calling this test. +* +* **Dependencies:** None@n +*/ +void test_l3_hdmi_cec_hal_Close(void) +{ + gTestID = 7; + HDMI_CEC_STATUS status; - result = HdmiCecSetTxCallback( handle, TransmitCallback, (void*)0xDEADBEEF ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecSetTxCallback failed"); } + UT_LOG_INFO("In %s [%02d%03d]\n", __FUNCTION__, gTestGroup, gTestID); - result = HdmiCecAddLogicalAddress( handle, DEFAULT_LOGICAL_ADDRESS_PANEL ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL("HdmiCecAddLogicalAddress failed"); } + 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; - gExpectedCecCommand = CEC_SET_OSD_NAME; - gCommandValidated = CEC_COMMAND_UNKNOWN; + UT_LOG_INFO("Out %s\n", __FUNCTION__); +} - UT_LOG ("\nTrigger SetOSDName\n"); - result = TimedWaitForCallback(MAX_WAIT_TIME_SECS); - if(result != 0) - { - UT_FAIL("Failed to receive SetOSDName"); - } - if(gCommandValidated != gExpectedCecCommand) - { - UT_FAIL("Test Validation of SetOSDName failed"); - } - result = HdmiCecClose( handle ); - if (HDMI_CEC_IO_SUCCESS != result) { UT_FAIL_FATAL("close failed"); } +static UT_test_suite_t * pSuite = NULL; -} /** - * @brief Register the main test(s) for this module + * @brief Register the main tests for this module * - * @return int - 0 on success, otherwise failure + * @return int32_t - 0 on success, otherwise failure */ -int test_l3_hdmi_cec_driver_register ( char* validation_profile ) +int32_t test_register_hdmicec_hal_sink_l3_tests(void) { ut_kvp_status_t status; - if(validation_profile == NULL) + char deviceType[HDMI_CEC_DEVICE_TYPE_SIZE] = {0}; + + // Create the test suite + pSuite = UT_add_suite("[L3 HDMICEC Functions] ", NULL, NULL); + if (pSuite == NULL) { - UT_FAIL("validation_profile NULL"); return -1; } - gValidationProfileInstance = ut_kvp_createInstance(); - assert(gValidationProfileInstance != NULL); - status = ut_kvp_open(gValidationProfileInstance, validation_profile); - if(status != UT_KVP_STATUS_SUCCESS) + status = ut_kvp_getStringField(ut_kvp_profile_getInstance(), "hdmicec/type", deviceType, HDMI_CEC_DEVICE_TYPE_SIZE); + + if (status == UT_KVP_STATUS_SUCCESS ) { - UT_LOG_ERROR("ut_kvp_open: status: %d", status); - assert(status == UT_KVP_STATUS_SUCCESS); + if (!strncmp(deviceType, "source", HDMI_CEC_DEVICE_TYPE_SIZE)) + { + gDeviceType = SOURCE; + } + else if(!strncmp(deviceType, "sink", HDMI_CEC_DEVICE_TYPE_SIZE)) + { + gDeviceType = SINK; + } + else + { + UT_LOG_ERROR("Invalid platform type: %s", deviceType); + return -1; + } + } + else { + UT_LOG_ERROR("Failed to get the platform type"); return -1; } - /* add a suite to the registry */ - pSuite = UT_add_suite( "[L3 hdmi_cec_driver]", NULL, NULL ); - if ( NULL == pSuite ) - { - return -1; - } - - sem_init(&gSemCallbackReceived, 0, 0); - UT_add_test( pSuite, "test_l3_sink_image_view_on" ,test_l3_sink_image_view_on ); - UT_add_test( pSuite, "test_l3_sink_text_view_on" ,test_l3_sink_text_view_on ); - UT_add_test( pSuite, "test_l3_sink_active_source" ,test_l3_sink_active_source); - UT_add_test( pSuite, "test_l3_sink_inactive_source" ,test_l3_sink_inactive_source ); - UT_add_test( pSuite, "test_l3_sink_set_osd_name" ,test_l3_sink_set_osd_name ); - - return 0; -} + // List of test function names and strings + UT_add_test( pSuite, "Init HDMI CEC", test_l3_hdmi_cec_hal_Init); + UT_add_test( pSuite, "Add Logical Address", test_l3_hdmi_cec_hal_AddLogicalAddress); + UT_add_test( pSuite, "Get Logical Address", test_l3_hdmi_cec_hal_GetLogicalAddress); + UT_add_test( pSuite, "Transmit CEC Command", test_l3_hdmi_cec_hal_TransmitHdmiCecCommand); + UT_add_test( pSuite, "Get Phyiscal Address", test_l3_hdmi_cec_hal_GetPhysicalAddress); + UT_add_test( pSuite, "Remove Logical Address", test_l3_hdmi_cec_hal_RemoveLogicalAddress); + UT_add_test( pSuite, "Close HDMI CEC", test_l3_hdmi_cec_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 fbdf048..7722b05 100644 --- a/src/test_register.c +++ b/src/test_register.c @@ -66,7 +66,7 @@ extern int test_hdmidec_hal_l1_register_sink_tests( void ); extern int test_hdmidec_hal_l1_register_source_tests( void ); extern int test_register_hdmicec_hal_source_l2_tests( void ); extern int test_register_hdmicec_hal_sink_l2_tests( void ); - +extern int test_register_hdmicec_hal_sink_l3_tests(void); int register_hdmicec_hal_common_l1_tests( void ) { @@ -110,6 +110,16 @@ int register_hdmicec_hal_sink_l2_tests( void ) return registerFailed; } +int register_hdmicec_hal_sink_l3_tests( void ) +{ + int registerFailed=0; + + registerFailed |= test_register_hdmicec_hal_sink_l3_tests(); + + return registerFailed; +} + + /** @} */ // End of HDMI CEC HAL Tests Register File /** @} */ // End of HDMI CEC HAL Tests /** @} */ // End of HDMI CEC Module