diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ecc80d1..7a145496 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,19 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.0.4](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.3...1.0.4) + +- RDKEMW-1061: RDK-E Add COMRPC [`#29`](https://github.com/rdkcentral/entservices-inputoutput/pull/29) +- Merge pull request #27 from rdkcentral/feature/RDKEMW-1061-RDK-E-Add-… [`#28`](https://github.com/rdkcentral/entservices-inputoutput/pull/28) +- RDKEMW-1061: RDK-E Add COMRPC [`#27`](https://github.com/rdkcentral/entservices-inputoutput/pull/27) +- Merge tag '1.0.3' into develop [`9d73332`](https://github.com/rdkcentral/entservices-inputoutput/commit/9d7333267973f791c7183192c7fce499cbc26efc) + #### [1.0.3](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.2...1.0.3) +> 3 March 2025 + - RDKEMW-1691 : Revert Unsupported plugin changes [`#13`](https://github.com/rdkcentral/entservices-inputoutput/pull/13) +- RDKEMW-1691 - Changelog updates for 1.0.3 [`bdbe8c0`](https://github.com/rdkcentral/entservices-inputoutput/commit/bdbe8c0e9572f79e390106242ca7b84880a208ad) - Merge tag '1.0.2' into develop [`00db359`](https://github.com/rdkcentral/entservices-inputoutput/commit/00db359737a5db24230be599bbe5f3b0345b9673) #### [1.0.2](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.1...1.0.2) diff --git a/HdmiCecSource/CMakeLists.txt b/HdmiCecSource/CMakeLists.txt index efaa3a15..6a60b721 100644 --- a/HdmiCecSource/CMakeLists.txt +++ b/HdmiCecSource/CMakeLists.txt @@ -14,37 +14,72 @@ # 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. + set(PLUGIN_NAME HdmiCecSource) set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) +set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) set(PLUGIN_HDMICECSOURCE_STARTUPORDER "" CACHE STRING "To configure startup order of HdmiCecSource plugin") + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + set_source_files_properties(HdmiCecSource.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") +set_source_files_properties(HdmiCecSourceImplementation.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) +find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED HdmiCecSource.cpp Module.cpp) - set_target_properties(${MODULE_NAME} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES) +target_include_directories(${MODULE_NAME} PRIVATE ${IARMBUS_INCLUDE_DIRS} ../helpers) + +target_link_libraries(${MODULE_NAME} + PRIVATE + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions + ${IARMBUS_LIBRARIES}) + +install(TARGETS ${MODULE_NAME} + DESTINATION lib/${STORAGE_DIRECTORY}/plugins) + +add_library(${PLUGIN_IMPLEMENTATION} SHARED + HdmiCecSourceImplementation.cpp + Module.cpp) + +set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + find_package(DS) find_package(IARMBus) find_package(CEC) -target_include_directories(${MODULE_NAME} PRIVATE ${IARMBUS_INCLUDE_DIRS} ../helpers) -target_include_directories(${MODULE_NAME} PRIVATE ${CEC_INCLUDE_DIRS}) -target_include_directories(${MODULE_NAME} PRIVATE ${DS_INCLUDE_DIRS}) -target_link_libraries(${MODULE_NAME} PUBLIC ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${IARMBUS_LIBRARIES} ${CEC_LIBRARIES} ${DS_LIBRARIES} ) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS} ../helpers) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${CEC_INCLUDE_DIRS}) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${DS_INCLUDE_DIRS}) + + +target_link_libraries(${PLUGIN_IMPLEMENTATION} PUBLIC ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${IARMBUS_LIBRARIES} ${CEC_LIBRARIES} ${DS_LIBRARIES} ) + +target_link_libraries(${PLUGIN_IMPLEMENTATION} + PRIVATE + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins) if (NOT RDK_SERVICES_L1_TEST) - target_compile_options(${MODULE_NAME} PRIVATE -Wno-error=deprecated) + target_compile_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wno-error=deprecated) endif () -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) + +install(TARGETS ${PLUGIN_IMPLEMENTATION} + DESTINATION lib/${STORAGE_DIRECTORY}/plugins) write_config(${PLUGIN_NAME}) diff --git a/HdmiCecSource/HdmiCecSource.conf.in b/HdmiCecSource/HdmiCecSource.conf.in index eae4e67c..1dae4b85 100644 --- a/HdmiCecSource/HdmiCecSource.conf.in +++ b/HdmiCecSource/HdmiCecSource.conf.in @@ -2,3 +2,10 @@ precondition = ["Platform"] callsign = "org.rdk.HdmiCecSource" autostart = "false" startuporder = "@PLUGIN_HDMICECSOURCE_STARTUPORDER@" + +configuration = JSON() +rootobject = JSON() + +rootobject.add("mode", "@PLUGIN_HDMICECSOURCE_MODE@") +rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") +configuration.add("root", rootobject) \ No newline at end of file diff --git a/HdmiCecSource/HdmiCecSource.config b/HdmiCecSource/HdmiCecSource.config index 4d2d2006..787e151a 100644 --- a/HdmiCecSource/HdmiCecSource.config +++ b/HdmiCecSource/HdmiCecSource.config @@ -5,3 +5,13 @@ set (callsign "org.rdk.HdmiCecSource") if(PLUGIN_HDMICECSOURCE_STARTUPORDER) set (startuporder ${PLUGIN_HDMICECSOURCE_STARTUPORDER}) endif() + + +map() + key(root) + map() + kv(mode ${PLUGIN_HDMICECSOURCE_MODE}) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() +end() +ans(configuration) diff --git a/HdmiCecSource/HdmiCecSource.cpp b/HdmiCecSource/HdmiCecSource.cpp index f0ba0f98..68b38a9a 100644 --- a/HdmiCecSource/HdmiCecSource.cpp +++ b/HdmiCecSource/HdmiCecSource.cpp @@ -19,80 +19,15 @@ #include "HdmiCecSource.h" - -#include "ccec/Connection.hpp" -#include "ccec/CECFrame.hpp" -#include "ccec/MessageEncoder.hpp" -#include "host.hpp" -#include "ccec/host/RDK.hpp" - -#include "dsMgr.h" -#include "dsDisplay.h" -#include "videoOutputPort.hpp" -#include "manager.hpp" -#include "websocket/URL.h" - #include "UtilsIarm.h" #include "UtilsJsonRpc.h" #include "UtilssyncPersistFile.h" #include "UtilsSearchRDKProfile.h" -#define HDMICECSOURCE_METHOD_SET_ENABLED "setEnabled" -#define HDMICECSOURCE_METHOD_GET_ENABLED "getEnabled" -#define HDMICECSOURCE_METHOD_OTP_SET_ENABLED "setOTPEnabled" -#define HDMICECSOURCE_METHOD_OTP_GET_ENABLED "getOTPEnabled" -#define HDMICECSOURCE_METHOD_SET_OSD_NAME "setOSDName" -#define HDMICECSOURCE_METHOD_GET_OSD_NAME "getOSDName" -#define HDMICECSOURCE_METHOD_SET_VENDOR_ID "setVendorId" -#define HDMICECSOURCE_METHOD_GET_VENDOR_ID "getVendorId" -#define HDMICECSOURCE_METHOD_PERFORM_OTP_ACTION "performOTPAction" -#define HDMICECSOURCE_METHOD_SEND_STANDBY_MESSAGE "sendStandbyMessage" -#define HDMICECSOURCE_METHOD_GET_ACTIVE_SOURCE_STATUS "getActiveSourceStatus" -#define HDMICECSOURCE_METHOD_SEND_KEY_PRESS "sendKeyPressEvent" -#define HDMICEC_EVENT_ON_DEVICES_CHANGED "onDevicesChanged" -#define HDMICEC_EVENT_ON_HDMI_HOT_PLUG "onHdmiHotPlug" -#define HDMICEC_EVENT_ON_STANDBY_MSG_RECEIVED "standbyMessageReceived" -#define HDMICEC_EVENT_ON_KEYPRESS_MSG_RECEIVED "onKeyPressEvent" -#define HDMICEC_EVENT_ON_KEYRELEASE_MSG_RECEIVED "onKeyReleaseEvent" -#define DEV_TYPE_TUNER 1 -#define HDMI_HOT_PLUG_EVENT_CONNECTED 0 -#define ABORT_REASON_ID 4 - #define API_VERSION_NUMBER_MAJOR 1 #define API_VERSION_NUMBER_MINOR 0 #define API_VERSION_NUMBER_PATCH 8 -enum { - HDMICECSOURCE_EVENT_DEVICE_ADDED=0, - HDMICECSOURCE_EVENT_DEVICE_REMOVED, - HDMICECSOURCE_EVENT_DEVICE_INFO_UPDATED, - HDMICECSOURCE_EVENT_ACTIVE_SOURCE_STATUS_UPDATED, -}; - -static const char *eventString[] = { - "onDeviceAdded", - "onDeviceRemoved", - "onDeviceInfoUpdated", - "onActiveSourceStatusUpdated" -}; - -#define CEC_SETTING_ENABLED_FILE "/opt/persistent/ds/cecData_2.json" -#define CEC_SETTING_ENABLED "cecEnabled" -#define CEC_SETTING_OTP_ENABLED "cecOTPEnabled" -#define CEC_SETTING_OSD_NAME "cecOSDName" -#define CEC_SETTING_VENDOR_ID "cecVendorId" - -static std::vector defaultVendorId = {0x00,0x19,0xFB}; -static VendorID appVendorId = {defaultVendorId.at(0),defaultVendorId.at(1),defaultVendorId.at(2)}; -static VendorID lgVendorId = {0x00,0xE0,0x91}; -static PhysicalAddress physical_addr = {0x0F,0x0F,0x0F,0x0F}; -static LogicalAddress logicalAddress = 0xF; -static OSDName osdName = "TV Box"; -static int32_t powerState = 1; -static PowerStatus tvPowerState = 1; -static bool isDeviceActiveSource = false; -static bool isLGTvConnected = false; - using namespace WPEFramework; @@ -116,307 +51,9 @@ namespace WPEFramework { SERVICE_REGISTRATION(HdmiCecSource, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - HdmiCecSource* HdmiCecSource::_instance = nullptr; - static int libcecInitStatus = 0; - -//=========================================== HdmiCecSourceFrameListener ========================================= - void HdmiCecSourceFrameListener::notify(const CECFrame &in) const { - const uint8_t *buf = NULL; - char strBuffer[512] = {0}; - size_t len = 0; - - in.getBuffer(&buf, &len); - for (unsigned int i = 0; i < len; i++) { - snprintf(strBuffer + (i*3) , sizeof(strBuffer) - (i*3), "%02X ",(uint8_t) *(buf + i)); - } - LOGINFO(" >>>>> Received CEC Frame: :%s \n",strBuffer); - - MessageDecoder(processor).decode(in); - } - -//=========================================== HdmiCecSourceProcessor ========================================= - void HdmiCecSourceProcessor::process (const ActiveSource &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); - if(msg.physicalAddress.toString() == physical_addr.toString()) - isDeviceActiveSource = true; - else - isDeviceActiveSource = false; - LOGINFO("ActiveSource isDeviceActiveSource status :%d \n", isDeviceActiveSource); - HdmiCecSource::_instance->sendActiveSourceEvent(); - HdmiCecSource::_instance->addDevice(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const InActiveSource &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: InActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); - } - void HdmiCecSourceProcessor::process (const ImageViewOn &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ImageViewOn \n"); - HdmiCecSource::_instance->addDevice(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const TextViewOn &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: TextViewOn\n"); - HdmiCecSource::_instance->addDevice(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const RequestActiveSource &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: RequestActiveSource\n"); - if(isDeviceActiveSource) - { - LOGINFO("sending ActiveSource\n"); - try - { - conn.sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(ActiveSource(physical_addr))); - } - catch(...) - { - LOGWARN("Exception while sending ActiveSource"); - } - } - } - void HdmiCecSourceProcessor::process (const Standby &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: Standby from %s\n", header.from.toString().c_str()); - HdmiCecSource::_instance->SendStandbyMsgEvent(header.from.toInt()); - - } - void HdmiCecSourceProcessor::process (const GetCECVersion &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GetCECVersion sending CECVersion response \n"); - try - { - conn.sendTo(header.from, MessageEncoder().encode(CECVersion(Version::V_1_4))); - } - catch(...) - { - LOGWARN("Exception while sending CECVersion "); - } - } - void HdmiCecSourceProcessor::process (const CECVersion &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: CECVersion Version : %s \n",msg.version.toString().c_str()); - HdmiCecSource::_instance->addDevice(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const SetMenuLanguage &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetMenuLanguage Language : %s \n",msg.language.toString().c_str()); - } - void HdmiCecSourceProcessor::process (const GiveOSDName &msg, const Header &header) - { - printHeader(header); - if (!(header.from == LogicalAddress(LogicalAddress::UNREGISTERED))) - { - LOGINFO("Command: GiveOSDName sending SetOSDName : %s\n",osdName.toString().c_str()); - try - { - conn.sendTo(header.from, MessageEncoder().encode(SetOSDName(osdName))); - } - catch(...) - { - LOGWARN("Exception while sending SetOSDName"); - } - } - } - void HdmiCecSourceProcessor::process (const GivePhysicalAddress &msg, const Header &header) - { - LOGINFO("Command: GivePhysicalAddress\n"); - try - { - LOGINFO(" sending ReportPhysicalAddress response physical_addr :%s logicalAddress :%x \n",physical_addr.toString().c_str(), logicalAddress.toInt()); - conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(ReportPhysicalAddress(physical_addr,logicalAddress.toInt()))); - } - catch(...) - { - LOGWARN("Exception while sending ReportPhysicalAddress "); - } - } - void HdmiCecSourceProcessor::process (const GiveDeviceVendorID &msg, const Header &header) - { - printHeader(header); - try - { - LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n",(isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); - if(isLGTvConnected) - conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(lgVendorId))); - else - conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); - } - catch(...) - { - LOGWARN("Exception while sending DeviceVendorID"); - } - - } - void HdmiCecSourceProcessor::process (const SetOSDString &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetOSDString OSDString : %s\n",msg.osdString.toString().c_str()); - } - void HdmiCecSourceProcessor::process (const SetOSDName &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetOSDName OSDName : %s\n",msg.osdName.toString().c_str()); - if (HdmiCecSource::_instance) { - bool isOSDNameUpdated = HdmiCecSource::_instance->deviceList[header.from.toInt()].update(msg.osdName); - if (isOSDNameUpdated) - HdmiCecSource::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } else { - LOGWARN("Exception HdmiCecSource::_instance NULL"); - } - } - void HdmiCecSourceProcessor::process (const RoutingChange &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: RoutingChange From : %s To: %s \n",msg.from.toString().c_str(),msg.to.toString().c_str()); - if(msg.to.toString() == physical_addr.toString()) - isDeviceActiveSource = true; - else - isDeviceActiveSource = false; - LOGINFO("physical_addr : %s isDeviceActiveSource :%d \n",physical_addr.toString().c_str(),isDeviceActiveSource); - HdmiCecSource::_instance->sendActiveSourceEvent(); - } - void HdmiCecSourceProcessor::process (const RoutingInformation &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: RoutingInformation Routing Information to Sink : %s\n",msg.toSink.toString().c_str()); - if(msg.toSink.toString() == physical_addr.toString()) - isDeviceActiveSource = true; - else - isDeviceActiveSource = false; - LOGINFO("physical_addr : %s isDeviceActiveSource :%d \n",physical_addr.toString().c_str(),isDeviceActiveSource); - HdmiCecSource::_instance->sendActiveSourceEvent(); - } - void HdmiCecSourceProcessor::process (const SetStreamPath &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetStreamPath Set Stream Path to Sink : %s\n",msg.toSink.toString().c_str()); - if(msg.toSink.toString() == physical_addr.toString()) - isDeviceActiveSource = true; - else - isDeviceActiveSource = false; - LOGINFO("physical_addr : %s isDeviceActiveSource :%d \n",physical_addr.toString().c_str(),isDeviceActiveSource); - HdmiCecSource::_instance->sendActiveSourceEvent(); - - } - void HdmiCecSourceProcessor::process (const GetMenuLanguage &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GetMenuLanguage\n"); - } - void HdmiCecSourceProcessor::process (const ReportPhysicalAddress &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ReportPhysicalAddress\n"); - HdmiCecSource::_instance->addDevice(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const DeviceVendorID &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: DeviceVendorID VendorID : %s\n",msg.vendorId.toString().c_str()); - if (HdmiCecSource::_instance){ - bool isVendorIdUpdated = HdmiCecSource::_instance->deviceList[header.from.toInt()].update(msg.vendorId); - if (isVendorIdUpdated) - HdmiCecSource::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } - else { - LOGWARN("Exception HdmiCecSource::_instance NULL"); - } - - } - void HdmiCecSourceProcessor::process (const GiveDevicePowerStatus &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GiveDevicePowerStatus sending powerState :%d \n",powerState); - try - { - conn.sendTo(header.from, MessageEncoder().encode(ReportPowerStatus(PowerStatus(powerState)))); - } - catch(...) - { - LOGWARN("Exception while sending ReportPowerStatus"); - } - } - void HdmiCecSourceProcessor::process (const ReportPowerStatus &msg, const Header &header) - { - printHeader(header); - if ((header.from == LogicalAddress(LogicalAddress::TV))) - tvPowerState = msg.status; - LOGINFO("Command: ReportPowerStatus TV Power Status from:%s status : %s \n",header.from.toString().c_str(),msg.status.toString().c_str()); - HdmiCecSource::_instance->addDevice(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const UserControlPressed &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: UserControlPressed message received from:%s command : %d \n",header.from.toString().c_str(),msg.uiCommand.toInt()); - HdmiCecSource::_instance->SendKeyPressMsgEvent(header.from.toInt(),msg.uiCommand.toInt()); - } - void HdmiCecSourceProcessor::process (const UserControlReleased &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: UserControlReleased message received from:%s \n",header.from.toString().c_str()); - HdmiCecSource::_instance->SendKeyReleaseMsgEvent(header.from.toInt()); - } - void HdmiCecSourceProcessor::process (const FeatureAbort &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: FeatureAbort\n"); - } - void HdmiCecSourceProcessor::process (const Abort &msg, const Header &header) - { - printHeader(header); - if (!(header.from == LogicalAddress(LogicalAddress::BROADCAST))) - { - LOGINFO("Command: Abort, sending FeatureAbort"); - try - { - conn.sendTo(header.from, MessageEncoder().encode(FeatureAbort(OpCode(msg.opCode()),AbortReason(ABORT_REASON_ID)))); - } - catch(...) - { - LOGWARN("Exception while sending FeatureAbort command"); - } - - } - LOGINFO("Command: Abort\n"); - } - void HdmiCecSourceProcessor::process (const Polling &msg, const Header &header) { - printHeader(header); - LOGINFO("Command: Polling\n"); - } - - -//=========================================== HdmiCecSource ========================================= - - HdmiCecSource::HdmiCecSource() - : PluginHost::JSONRPC(),cecEnableStatus(false),smConnection(nullptr), m_sendKeyEventThreadRun(false) - , _pwrMgrNotification(*this) - , _registeredEventHandlers(false) - { - LOGWARN("ctor"); - } - - HdmiCecSource::~HdmiCecSource() - { - LOGWARN("dtor"); - } - - const string HdmiCecSource::Initialize(PluginHost::IShell *service) - { - LOGWARN("Initlaizing CEC_2"); - uint32_t res = Core::ERROR_GENERAL; - PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + const string HdmiCecSource::Initialize(PluginHost::IShell *service) + { + LOGWARN("Initlaizing HdmiCecSource plugin \n"); profileType = searchRdkProfile(); @@ -426,1283 +63,111 @@ namespace WPEFramework return (std::string("Not supported")); } - string msg; - HdmiCecSource::_instance = this; - smConnection = NULL; - cecEnableStatus = false; - Register(HDMICECSOURCE_METHOD_SET_ENABLED, &HdmiCecSource::setEnabledWrapper, this); - Register(HDMICECSOURCE_METHOD_GET_ENABLED, &HdmiCecSource::getEnabledWrapper, this); - Register(HDMICECSOURCE_METHOD_OTP_SET_ENABLED, &HdmiCecSource::setOTPEnabledWrapper, this); - Register(HDMICECSOURCE_METHOD_OTP_GET_ENABLED, &HdmiCecSource::getOTPEnabledWrapper, this); - Register(HDMICECSOURCE_METHOD_SET_OSD_NAME, &HdmiCecSource::setOSDNameWrapper, this); - Register(HDMICECSOURCE_METHOD_GET_OSD_NAME, &HdmiCecSource::getOSDNameWrapper, this); - Register(HDMICECSOURCE_METHOD_SET_VENDOR_ID, &HdmiCecSource::setVendorIdWrapper, this); - Register(HDMICECSOURCE_METHOD_GET_VENDOR_ID, &HdmiCecSource::getVendorIdWrapper, this); - Register(HDMICECSOURCE_METHOD_PERFORM_OTP_ACTION, &HdmiCecSource::performOTPActionWrapper, this); - Register(HDMICECSOURCE_METHOD_SEND_STANDBY_MESSAGE, &HdmiCecSource::sendStandbyMessageWrapper, this); - Register(HDMICECSOURCE_METHOD_GET_ACTIVE_SOURCE_STATUS, &HdmiCecSource::getActiveSourceStatus, this); - Register(HDMICECSOURCE_METHOD_SEND_KEY_PRESS,&HdmiCecSource::sendRemoteKeyPressWrapper,this); - Register("getDeviceList", &HdmiCecSource::getDeviceList, this); - if (Utils::IARM::init()) { - - - //Initialize cecEnableStatus to false in ctor - cecEnableStatus = false; - - logicalAddressDeviceType = "None"; - logicalAddress = 0xFF; - - //CEC plugin functionalities will only work if CECmgr is available. If plugin Initialize failure upper layer will call dtor directly. - InitializeIARM(); - InitializePowerManager(service); - - // load persistence setting - loadSettings(); - - try - { - //TODO(MROLLINS) this is probably per process so we either need to be running in our own process or be carefull no other plugin is calling it - device::Manager::Initialize(); - std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); - device::VideoOutputPort vPort = device::Host::getInstance().getVideoOutputPort(strVideoPort.c_str()); - if (vPort.isDisplayConnected()) - { - std::vector edidVec; - vPort.getDisplay().getEDIDBytes(edidVec); - //Set LG vendor id if connected with LG TV - if(edidVec.at(8) == 0x1E && edidVec.at(9) == 0x6D) - { - isLGTvConnected = true; - } - LOGINFO("manufacturer byte from edid :%x: %x isLGTvConnected :%d",edidVec.at(8),edidVec.at(9),isLGTvConnected); - } - } - catch(...) - { - LOGWARN("Exception in getting edid info .\r\n"); - } - - // get power state: - ASSERT (_powerManagerPlugin); - if (_powerManagerPlugin){ - res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); - if (Core::ERROR_NONE == res) - { - powerState = (pwrStateCur == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON)?0:1 ; - LOGINFO("Current state is PowerManagerPlugin: (%d) powerState :%d \n",pwrStateCur,powerState); - } - } - - if (cecSettingEnabled) - { - try - { - CECEnable(); - } - catch(...) - { - LOGWARN("Exception while enabling CEC settings .\r\n"); - } - } - } else { - msg = "IARM bus is not available"; - LOGERR("IARM bus is not available. Failed to activate HdmiCecSource Plugin"); - } - - // On success return empty, to indicate there is no error text. - return msg; - } - - void HdmiCecSource::registerEventHandlers() - { - ASSERT (_powerManagerPlugin); - - if(!_registeredEventHandlers && _powerManagerPlugin) { - _registeredEventHandlers = true; - _powerManagerPlugin->Register(&_pwrMgrNotification); - } - } - + string msg = ""; - uint32_t HdmiCecSource::getActiveSourceStatus(const JsonObject& parameters, JsonObject& response) - { - response["status"] = isDeviceActiveSource; - returnResponse(true); - } + ASSERT(nullptr != service); + ASSERT(nullptr == _service); + ASSERT(nullptr == _hdmiCecSource); + ASSERT(0 == _connectionId); - void HdmiCecSource::Deinitialize(PluginHost::IShell* /* service */) - { - LOGWARN("Deinitialize CEC_2"); - if(_powerManagerPlugin) - { - _powerManagerPlugin.Reset(); - } - _registeredEventHandlers = false; - profileType = searchRdkProfile(); + _service = service; + _service->AddRef(); + _service->Register(&_notification); + _hdmiCecSource = _service->Root(_connectionId, 5000, _T("HdmiCecSourceImplementation")); - if (profileType == TV || profileType == NOT_FOUND) - { - LOGINFO("Invalid profile type for STB \n"); - return ; - } - - if(true == getEnabled()) - { - setEnabled(false,false); - } - isDeviceActiveSource = false; - HdmiCecSource::_instance->sendActiveSourceEvent(); - HdmiCecSource::_instance = nullptr; - smConnection = NULL; - - DeinitializeIARM(); - } - - void HdmiCecSource::sendKeyPressEvent(const int logicalAddress, int keyCode) - { - if(!(_instance->smConnection)) - return; - LOGINFO(" sendKeyPressEvent logicalAddress 0x%x keycode 0x%x\n",logicalAddress,keyCode); - switch(keyCode) - { - case VOLUME_UP: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_UP)),100); - break; - case VOLUME_DOWN: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_DOWN)), 100); - break; - case MUTE: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_MUTE)), 100); - break; - case UP: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_UP)), 100); - break; - case DOWN: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_DOWN)), 100); - break; - case LEFT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_LEFT)), 100); - break; - case RIGHT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_RIGHT)), 100); - break; - case SELECT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_SELECT)), 100); - break; - case HOME: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_HOME)), 100); - break; - case BACK: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_BACK)), 100); - break; - case NUMBER_0: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_0)), 100); - break; - case NUMBER_1: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_1)), 100); - break; - case NUMBER_2: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_2)), 100); - break; - case NUMBER_3: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_3)), 100); - break; - case NUMBER_4: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_4)), 100); - break; - case NUMBER_5: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_5)), 100); - break; - case NUMBER_6: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_6)), 100); - break; - case NUMBER_7: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_7)), 100); - break; - case NUMBER_8: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_8)), 100); - break; - case NUMBER_9: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_9)), 100); - break; - - } - } - void HdmiCecSource::sendKeyReleaseEvent(const int logicalAddress) - { - LOGINFO(" sendKeyReleaseEvent logicalAddress 0x%x \n",logicalAddress); - if(!(_instance->smConnection)) - return; - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlReleased()), 100); - - } - void HdmiCecSource::SendKeyPressMsgEvent(const int logicalAddress,const int keyCode) - { - JsonObject params; - params["logicalAddress"] = JsonValue(logicalAddress); - params["keyCode"] = JsonValue(keyCode); - sendNotify(HDMICEC_EVENT_ON_KEYPRESS_MSG_RECEIVED, params); - } - void HdmiCecSource::SendKeyReleaseMsgEvent(const int logicalAddress) - { - JsonObject params; - params["logicalAddress"] = JsonValue(logicalAddress); - sendNotify(HDMICEC_EVENT_ON_KEYRELEASE_MSG_RECEIVED, params); - } - void HdmiCecSource::SendStandbyMsgEvent(const int logicalAddress) - { - JsonObject params; - params["logicalAddress"] = JsonValue(logicalAddress); - sendNotify(HDMICEC_EVENT_ON_STANDBY_MSG_RECEIVED, params); - } - uint32_t HdmiCecSource::sendRemoteKeyPressWrapper(const JsonObject& parameters, JsonObject& response) - { - returnIfParamNotFound(parameters, "logicalAddress"); - returnIfParamNotFound(parameters, "keyCode"); - string logicalAddress = parameters["logicalAddress"].String(); - string keyCode = parameters["keyCode"].String(); - SendKeyInfo keyInfo; - try { - keyInfo.logicalAddr = stoi(logicalAddress); - keyInfo.keyCode = stoi(keyCode); - } catch (const std::invalid_argument& e) { - std::cerr << "Invalid input: " << e.what() << std::endl; - returnResponse(false); - } - std::unique_lock lk(m_sendKeyEventMutex); - m_SendKeyQueue.push(keyInfo); - m_sendKeyEventThreadRun = true; - m_sendKeyCV.notify_one(); - LOGINFO("Post send key press event to queue size:%d \n",(int)m_SendKeyQueue.size()); - returnResponse(true); - } - - uint32_t HdmiCecSource::sendStandbyMessageWrapper(const JsonObject& parameters, JsonObject& response) - { - if(sendStandbyMessage()) - { - returnResponse(true); - } - else - { - returnResponse(false); - } - } - - bool HdmiCecSource::sendStandbyMessage() - { - bool ret = false; - - if(true == cecEnableStatus) + if(nullptr != _hdmiCecSource) { - if (smConnection){ - try - { - smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(Standby())); - ret = true; - } - catch(...) - { - LOGWARN("Exception while sending CEC StandBy Message"); - } - } - else { - LOGWARN("smConnection is NULL"); - } + _hdmiCecSource->Configure(service); + _hdmiCecSource->Register(&_notification); + Exchange::JHdmiCecSource::Register(*this, _hdmiCecSource); + LOGINFO("HdmiCecSource plugin is available. Successfully activated HdmiCecSource Plugin"); } else - LOGWARN("cecEnableStatus=false"); - return ret; - } - - void HdmiCecSource::InitializePowerManager(PluginHost::IShell *service) - { - LOGINFO("Connect the COM-RPC socket\n"); - _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) - .withIShell(service) - .createInterface(); - registerEventHandlers(); - } - - const void HdmiCecSource::InitializeIARM() - { - IARM_Result_t res; - IARM_CHECK( IARM_Bus_RegisterEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, dsHdmiEventHandler) ); - } - - void HdmiCecSource::DeinitializeIARM() - { - if (Utils::IARM::isConnected()) - { - IARM_Result_t res; - IARM_CHECK( IARM_Bus_RemoveEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG,dsHdmiEventHandler) ); - } - } - void HdmiCecSource::threadHotPlugEventHandler(int data) - { - LOGINFO("entry threadHotPlugEventHandler \r\n"); - if(!HdmiCecSource::_instance) - return; - - LOGINFO("Pocessing IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG event status:%d \r\n",data); - HdmiCecSource::_instance->onHdmiHotPlug(data); - //Trigger CEC device poll here - pthread_cond_signal(&(_instance->m_condSig)); - - LOGINFO("Exit threadHotPlugEventHandler \r\n"); - } - - void HdmiCecSource::dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) - { - if(!HdmiCecSource::_instance || !_instance->cecEnableStatus) - { - LOGINFO("Return from dsHdmiEventHandler due HdmiCecSource::_instance:%p cecEnableStatus:%d \r\n", HdmiCecSource::_instance, _instance->cecEnableStatus); - return; - } - - if (owner && !strcmp(owner, IARM_BUS_DSMGR_NAME) && (IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG == eventId)) - { - IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; - if(eventData) - { - int hdmi_hotplug_event = eventData->data.hdmi_hpd.event; - LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG event data:%d \r\n", hdmi_hotplug_event); - std::thread worker(threadHotPlugEventHandler,hdmi_hotplug_event); - worker.detach(); - } - } - } - - void HdmiCecSource::onPowerModeChanged(const PowerState ¤tState, const PowerState &newState) - { - if(!HdmiCecSource::_instance) - return; - - LOGINFO("Event IARM_BUS_PWRMGR_EVENT_MODECHANGED: State Changed %d -- > %d\r", - currentState, newState); - if (WPEFramework::Exchange::IPowerManager::POWER_STATE_ON == newState) { - powerState = 0; + msg = "HdmiCecSource plugin is not available"; + LOGINFO("HdmiCecSource plugin is not available. Failed to activate HdmiCecSource Plugin"); } - else - powerState = 1; - } - - void HdmiCecSource::sendActiveSourceEvent() - { - JsonObject params; - params["status"] = isDeviceActiveSource; - LOGWARN(" sendActiveSourceEvent isDeviceActiveSource: %d ",isDeviceActiveSource); - sendNotify(eventString[HDMICECSOURCE_EVENT_ACTIVE_SOURCE_STATUS_UPDATED], params); - } - - void HdmiCecSource::onHdmiHotPlug(int connectStatus) - { - if (HDMI_HOT_PLUG_EVENT_CONNECTED == connectStatus) - { - LOGINFO ("onHdmiHotPlug Status : %d ", connectStatus); - getPhysicalAddress(); - getLogicalAddress(); - try - { - std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); - device::VideoOutputPort vPort = device::Host::getInstance().getVideoOutputPort(strVideoPort.c_str()); - if (vPort.isDisplayConnected()) - { - std::vector edidVec; - vPort.getDisplay().getEDIDBytes(edidVec); - //Set LG vendor id if connected with LG TV - if(edidVec.at(8) == 0x1E && edidVec.at(9) == 0x6D) - { - isLGTvConnected = true; - } - LOGINFO("manufacturer byte from edid :%x: %x isLGTvConnected :%d",edidVec.at(8),edidVec.at(9),isLGTvConnected); - } - } - catch(...) - { - LOGWARN("Exception in getting edid info .\r\n"); - } - if(smConnection) - { - try - { - LOGINFO(" sending ReportPhysicalAddress response physical_addr :%s logicalAddress :%x \n",physical_addr.toString().c_str(), logicalAddress.toInt()); - smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(ReportPhysicalAddress(physical_addr,logicalAddress.toInt()))); - LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n", \ - (isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); - if(isLGTvConnected) - smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(lgVendorId))); - else - smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); - } - catch(...) - { - LOGWARN("Exception while sending Messages onHdmiHotPlug\n"); - } - } - } - return; - } - - uint32_t HdmiCecSource::setEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - bool enabled = false; - - if (parameters.HasLabel("enabled")) - { - getBoolParameter("enabled", enabled); - } - else - { - returnResponse(false); - } - - setEnabled(enabled,true); - returnResponse(true); - } - - uint32_t HdmiCecSource::getEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - response["enabled"] = getEnabled(); - returnResponse(true); - } - uint32_t HdmiCecSource::setOTPEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - bool enabled = false; - - if (parameters.HasLabel("enabled")) - { - getBoolParameter("enabled", enabled); - } - else + if (0 != msg.length()) { - returnResponse(false); + Deinitialize(service); } - setOTPEnabled(enabled); - returnResponse(true); - } - - uint32_t HdmiCecSource::getOTPEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - response["enabled"] = getOTPEnabled(); - returnResponse(true); - } - - uint32_t HdmiCecSource::setOSDNameWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - if (parameters.HasLabel("name")) - { - std::string osd = parameters["name"].String(); - LOGINFO("setOSDNameWrapper osdName: %s",osd.c_str()); - osdName = osd.c_str(); - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_OSD_NAME, JsonValue(osd.c_str())); - } - else - { - returnResponse(false); - } - returnResponse(true); - } - - uint32_t HdmiCecSource::getOSDNameWrapper(const JsonObject& parameters, JsonObject& response) - { - response["name"] = osdName.toString(); - LOGINFO("getOSDNameWrapper osdName : %s \n",osdName.toString().c_str()); - returnResponse(true); - } - - uint32_t HdmiCecSource::setVendorIdWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - if (parameters.HasLabel("vendorid")) - { - std::string id = parameters["vendorid"].String(); - unsigned int vendorID = 0x00; - try - { - vendorID = stoi(id,NULL,16); - } - catch (...) - { - LOGWARN("Exception in setVendorIdWrapper set default value\n"); - vendorID = 0x0019FB; - } - appVendorId = {(uint8_t)(vendorID >> 16 & 0xff),(uint8_t)(vendorID>> 8 & 0xff),(uint8_t) (vendorID & 0xff)}; - LOGINFO("appVendorId : %s vendorID :%x \n",appVendorId.toString().c_str(), vendorID ); - - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_VENDOR_ID, JsonValue(vendorID)); - } - else - { - returnResponse(false); - } - returnResponse(true); - } - - uint32_t HdmiCecSource::getVendorIdWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFO("getVendorIdWrapper appVendorId : %s \n",appVendorId.toString().c_str()); - response["vendorid"] = appVendorId.toString() ; - returnResponse(true); + // On success return empty, to indicate there is no error text. + return msg; } - uint32_t HdmiCecSource::performOTPActionWrapper(const JsonObject& parameters, JsonObject& response) - { - if(performOTPAction()) - { - returnResponse(true); - } - else - { - returnResponse(false); - } - } - - bool HdmiCecSource::loadSettings() + void HdmiCecSource::Deinitialize(PluginHost::IShell* service) { - Core::File file; - file = CEC_SETTING_ENABLED_FILE; - - if( file.Open()) - { - JsonObject parameters; - parameters.IElement::FromFile(file); - bool isConfigAdded = false; - - if( parameters.HasLabel(CEC_SETTING_ENABLED)) - { - getBoolParameter(CEC_SETTING_ENABLED, cecSettingEnabled); - LOGINFO("CEC_SETTING_ENABLED present value:%d",cecSettingEnabled); - } - else - { - parameters[CEC_SETTING_ENABLED] = true; - cecSettingEnabled = true; - isConfigAdded = true; - LOGINFO("CEC_SETTING_ENABLED not present set dafult true:\n "); - } - - if( parameters.HasLabel(CEC_SETTING_OTP_ENABLED)) - { - getBoolParameter(CEC_SETTING_OTP_ENABLED, cecOTPSettingEnabled); - LOGINFO("CEC_SETTING_OTP_ENABLED present value :%d",cecOTPSettingEnabled); - } - else - { - parameters[CEC_SETTING_OTP_ENABLED] = true; - cecOTPSettingEnabled = true; - isConfigAdded = true; - LOGINFO("CEC_SETTING_OTP_ENABLED not present set dafult true:\n "); - } - if( parameters.HasLabel(CEC_SETTING_OSD_NAME)) - { - std::string osd_name; - getStringParameter(CEC_SETTING_OSD_NAME, osd_name); - osdName = osd_name.c_str(); - LOGINFO("CEC_SETTING_OTP_ENABLED present osd_name :%s",osdName.toString().c_str()); - } - else - { - parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); - LOGINFO("CEC_SETTING_OSD_NMAE not present set dafult value :%s\n ",osdName.toString().c_str()); - isConfigAdded = true; - } - unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); - if( parameters.HasLabel(CEC_SETTING_VENDOR_ID)) - { - getNumberParameter(CEC_SETTING_VENDOR_ID, vendorId); - LOGINFO("CEC_SETTING_VENDOR_ID present :%x ",vendorId); - } - else - { - LOGINFO("CEC_SETTING_VENDOR_ID not present set dafult value :%x \n ",vendorId); - parameters[CEC_SETTING_VENDOR_ID] = vendorId; - isConfigAdded = true; - } - - appVendorId = {(uint8_t)(vendorId >> 16 & 0xff),(uint8_t)(vendorId >> 8 & 0xff),(uint8_t) (vendorId & 0xff)}; - LOGINFO("appVendorId : %s vendorId :%x \n",appVendorId.toString().c_str(), vendorId ); - - if(isConfigAdded) - { - LOGINFO("isConfigAdded true so update file:\n "); - file.Destroy(); - file.Create(); - parameters.IElement::ToFile(file); - - } + LOGWARN("Deinitialize HdmiCecSource plugin \n"); - file.Close(); - } - else - { - LOGINFO("CEC_SETTING_ENABLED_FILE file not present create with default settings "); - file.Open(false); - if (!file.IsOpen()) - file.Create(); - - JsonObject parameters; - unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); - parameters[CEC_SETTING_ENABLED] = true; - parameters[CEC_SETTING_OTP_ENABLED] = true; - parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); - parameters[CEC_SETTING_VENDOR_ID] = vendorId; - - cecSettingEnabled = true; - cecOTPSettingEnabled = true; - parameters.IElement::ToFile(file); - - file.Close(); + ASSERT(nullptr != service); + - } - - return cecSettingEnabled; - } - - void HdmiCecSource::setEnabled(bool enabled, bool isPersist) - { - LOGINFO("Entered setEnabled "); + profileType = searchRdkProfile(); - if (isPersist && (cecSettingEnabled != enabled)) - { - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_ENABLED, JsonValue(enabled)); - cecSettingEnabled = enabled; - } - if(true == enabled) - { - CECEnable(); - } - else + if (profileType == TV || profileType == NOT_FOUND) { - CECDisable(); + LOGINFO("Invalid profile type for STB \n"); + return ; } - return; - } - void HdmiCecSource::setOTPEnabled(bool enabled) - { - if (cecOTPSettingEnabled != enabled) + bool enabled = false; + bool ret = false; + HdmiCecSource::_hdmiCecSource->GetEnabled(enabled,ret); + + if(ret && enabled) { - LOGINFO("persist setOTPEnabled "); - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_OTP_ENABLED, JsonValue(enabled)); - cecOTPSettingEnabled = enabled; + Exchange::IHdmiCecSource::HdmiCecSourceSuccess success; + HdmiCecSource::_hdmiCecSource->SetEnabled(false,success); } - return; - } - - void HdmiCecSource::CECEnable(void) - { - LOGINFO("Entered CECEnable"); - - if (cecEnableStatus) - { - LOGWARN("CEC Already Enabled"); - return; - } - - if(0 == libcecInitStatus) - { - try - { - LibCCEC::getInstance().init("HdmiCecSource"); - } - catch (const std::exception& e) - { - LOGWARN("CEC exception caught from LibCCEC::getInstance().init()"); - } - } - libcecInitStatus++; - - m_sendKeyEventThreadExit = false; - try { - if (m_sendKeyEventThread.get().joinable()) { - m_sendKeyEventThread.get().join(); - } - m_sendKeyEventThread = Utils::ThreadRAII(std::thread(threadSendKeyEvent)); - } catch(const std::system_error& e) { - LOGERR("exception in creating threadSendKeyEvent %s", e.what()); - } - - - //Acquire CEC Addresses - getPhysicalAddress(); - getLogicalAddress(); - - smConnection = new Connection(logicalAddress.toInt(),false,"ServiceManager::Connection::"); - smConnection->open(); - msgProcessor = new HdmiCecSourceProcessor(*smConnection); - msgFrameListener = new HdmiCecSourceFrameListener(*msgProcessor); - smConnection->addFrameListener(msgFrameListener); - - cecEnableStatus = true; - - if(smConnection) - { - LOGINFO("Command: sending GiveDevicePowerStatus \r\n"); - smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(GiveDevicePowerStatus())); - LOGINFO("Command: sending request active Source isDeviceActiveSource is set to false\r\n"); - smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(RequestActiveSource())); - isDeviceActiveSource = false; - LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n", \ - (isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); - if(isLGTvConnected) - smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(lgVendorId))); - else - smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); + HdmiCecSource::_notification.OnActiveSourceStatusUpdated(false); - LOGWARN("Start Update thread %p", smConnection ); - m_updateThreadExit = false; - _instance->m_lockUpdate = PTHREAD_MUTEX_INITIALIZER; - _instance->m_condSigUpdate = PTHREAD_COND_INITIALIZER; - try { - if (m_UpdateThread.get().joinable()) { - m_UpdateThread.get().join(); - } - m_UpdateThread = Utils::ThreadRAII(std::thread(threadUpdateCheck)); - } catch(const std::system_error& e) { - LOGERR("exception in creating threadUpdateCheck %s", e.what()); - } - - LOGWARN("Start Thread %p", smConnection ); - m_pollThreadExit = false; - _instance->m_numberOfDevices = 0; - _instance->m_lock = PTHREAD_MUTEX_INITIALIZER; - _instance->m_condSig = PTHREAD_COND_INITIALIZER; - try { - if (m_pollThread.get().joinable()) { - m_pollThread.get().join(); - } - m_pollThread = Utils::ThreadRAII(std::thread(threadRun)); - } catch(const std::system_error& e) { - LOGERR("exception in creating threadRun %s", e.what()); - } - - } - return; - } - - void HdmiCecSource::CECDisable(void) - { - LOGINFO("Entered CECDisable "); - - if(!cecEnableStatus) - { - LOGWARN("CEC Already Disabled "); - return; - } - - { - m_sendKeyEventThreadExit = true; - std::unique_lock lk(m_sendKeyEventMutex); - m_sendKeyEventThreadRun = true; - m_sendKeyCV.notify_one(); - } - try - { - if (m_sendKeyEventThread.get().joinable()) - m_sendKeyEventThread.get().join(); - } - catch(const std::system_error& e) - { - LOGERR("system_error exception in thread join %s", e.what()); - } - catch(const std::exception& e) - { - LOGERR("exception in thread join %s", e.what()); - } - - if (smConnection != NULL) - { - LOGWARN("Stop Thread %p", smConnection ); - - m_updateThreadExit = true; - //Trigger codition to exit poll loop - pthread_mutex_lock(&(_instance->m_lockUpdate)); //Join mutex lock to wait until thread is in its wait condition - pthread_cond_signal(&(_instance->m_condSigUpdate)); - pthread_mutex_unlock(&(_instance->m_lockUpdate)); - if (m_UpdateThread.get().joinable()) {//Join thread to make sure it's deleted before moving on. - m_UpdateThread.get().join(); - } - LOGWARN("Deleted update Thread %p", smConnection ); - - m_pollThreadExit = true; - //Trigger codition to exit poll loop - pthread_mutex_lock(&(_instance->m_lock)); //Join mutex lock to wait until thread is in its wait condition - pthread_cond_signal(&(_instance->m_condSig)); - pthread_mutex_unlock(&(_instance->m_lock)); - if (m_pollThread.get().joinable()) {//Join thread to make sure it's deleted before moving on. - m_pollThread.get().join(); - } - LOGWARN("Deleted Thread %p", smConnection ); - //Clear cec device cache. - removeAllCecDevices(); - - smConnection->close(); - delete smConnection; - delete msgProcessor; - delete msgFrameListener; - msgProcessor = NULL; - msgFrameListener = NULL; - smConnection = NULL; - } - cecEnableStatus = false; + if(nullptr != _hdmiCecSource) + { + _hdmiCecSource->Unregister(&_notification); + Exchange::JHdmiCecSource::Unregister(*this); + _hdmiCecSource->Release(); + _hdmiCecSource = nullptr; - if(1 == libcecInitStatus) - { - try - { - LibCCEC::getInstance().term(); + RPC::IRemoteConnection* connection = _service->RemoteConnection(_connectionId); + if (connection != nullptr) + { + try{ + connection->Terminate(); } - catch (const std::exception& e) + catch(const std::exception& e) { - LOGWARN("CEC exception caught from LibCCEC::getInstance().term() "); + std::string errorMessage = "Failed to terminate connection: "; + errorMessage += e.what(); + LOGWARN("%s",errorMessage.c_str()); } - } - - libcecInitStatus--; - - return; - } - - - void HdmiCecSource::getPhysicalAddress() - { - LOGINFO("Entered getPhysicalAddress "); - - uint32_t physAddress = 0x0F0F0F0F; - try { - LibCCEC::getInstance().getPhysicalAddress(&physAddress); - physical_addr = {(uint8_t)((physAddress >> 24) & 0xFF),(uint8_t)((physAddress >> 16) & 0xFF),(uint8_t) ((physAddress >> 8) & 0xFF),(uint8_t)((physAddress) & 0xFF)}; - LOGINFO("getPhysicalAddress: physicalAddress: %s ", physical_addr.toString().c_str()); - } - catch (const std::exception& e) - { - LOGWARN("exception caught from getPhysicalAddress"); - } - return; - } - - void HdmiCecSource::getLogicalAddress() - { - LOGINFO("Entered getLogicalAddress "); - - try{ - LogicalAddress addr = LibCCEC::getInstance().getLogicalAddress(DEV_TYPE_TUNER); - - std::string logicalAddrDeviceType = DeviceType(LogicalAddress(addr).getType()).toString().c_str(); - - LOGINFO("logical address obtained is %d , saved logical address is %d ", addr.toInt(), logicalAddress.toInt()); - - if (logicalAddress.toInt() != addr.toInt() || logicalAddressDeviceType != logicalAddrDeviceType) - { - logicalAddress = addr; - logicalAddressDeviceType = logicalAddrDeviceType; - } - } - catch (const std::exception& e) - { - LOGWARN("CEC exception caught from getLogicalAddress "); - } - return; - } + connection->Release(); + } + } - bool HdmiCecSource::getEnabled() - { - LOGINFO("getEnabled :%d ",cecEnableStatus); - return cecEnableStatus; + _connectionId = 0; + _service->Release(); + _service = nullptr; + LOGINFO("HdmiCecSource plugin is deactivated. Successfully deactivated HdmiCecSource Plugin"); } - bool HdmiCecSource::getOTPEnabled() + string HdmiCecSource::Information() const { - if(true == cecOTPSettingEnabled) - return true; - else - return false; - LOGINFO("getOTPEnabled :%d ",cecOTPSettingEnabled); + return("This HdmiCecSource PLugin Facilitates the HDMI CEC Source Control"); } - bool HdmiCecSource::performOTPAction() + void HdmiCecSource::Deactivated(RPC::IRemoteConnection* connection) { - LOGINFO("performOTPAction "); - bool ret = false; - - if((true == cecEnableStatus) && (cecOTPSettingEnabled == true)) + if (connection->Id() == _connectionId) { - if (smConnection) { - try - { - LOGINFO("Command: sending ImageViewOn TV \r\n"); - smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(ImageViewOn())); - usleep(10000); - LOGINFO("Command: sending ActiveSource physical_addr :%s \r\n",physical_addr.toString().c_str()); - smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(ActiveSource(physical_addr))); - usleep(10000); - isDeviceActiveSource = true; - LOGINFO("Command: sending GiveDevicePowerStatus \r\n"); - smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(GiveDevicePowerStatus())); - ret = true; - } - catch(...) - { - LOGWARN("Exception while processing performOTPAction"); - } - } - else { - LOGWARN("smConnection is NULL"); - } + ASSERT(_service != nullptr); + Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); } - else - LOGWARN("cecEnableStatus=false"); - return ret; } - uint32_t HdmiCecSource::getDeviceList (const JsonObject& parameters, JsonObject& response) - { //sample servicemanager response: - LOGINFOMETHOD(); - //Trigger CEC device poll here - pthread_cond_signal(&(_instance->m_condSig)); - - bool success = true; - response["numberofdevices"] = HdmiCecSource::_instance->m_numberOfDevices; - LOGINFO("getDeviceListWrapper m_numberOfDevices :%d \n", HdmiCecSource::_instance->m_numberOfDevices); - JsonArray deviceListArg; - try - { - int i = 0; - for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { - if (BIT_CHECK(deviceList[i].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) { - JsonObject device; - device["logicalAddress"] = HdmiCecSource::_instance->deviceList[i].m_logicalAddress.toInt(); - device["osdName"] = HdmiCecSource::_instance->deviceList[i].m_osdName.toString().c_str(); - device["vendorID"] = HdmiCecSource::_instance->deviceList[i].m_vendorID.toString().c_str(); - deviceListArg.Add(device); - } - } - } - catch (...) - { - LOGERR("Exception in api"); - success = false; - } - response["deviceList"] = deviceListArg; - returnResponse(success); - } - - bool HdmiCecSource::pingDeviceUpdateList (int idev) - { - bool isConnected = false; - //self ping is not required - if (idev == logicalAddress.toInt()){ - return isConnected; - } - if(!HdmiCecSource::_instance) - { - LOGERR("HdmiCecSource::_instance not existing"); - return isConnected; - } - if ( !(_instance->smConnection) || logicalAddress.toInt() == LogicalAddress::UNREGISTERED || (false==cecEnableStatus)){ - LOGERR("Exiting from pingDeviceUpdateList _instance->smConnection:%p, logicalAddress:%d, cecEnableStatus=%d", - _instance->smConnection, logicalAddress.toInt(), cecEnableStatus); - return isConnected; - } - - LOGWARN("PING for 0x%x \r\n",idev); - try { - _instance->smConnection->ping(logicalAddress, LogicalAddress(idev), Throw_e()); - } - catch(CECNoAckException &e) - { - if (BIT_CHECK(_instance->deviceList[idev].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) { - LOGINFO("Device disconnected: %d \r\n",idev); - removeDevice (idev); - } else { - LOGINFO("Device is not connected: %d. Ping caught %s\r\n",idev, e.what()); - } - isConnected = false; - return isConnected;; - } - catch(IOException &e) - { - LOGINFO("Device is not reachable: %d. Ping caught %s\r\n",idev, e.what()); - isConnected = false; - return isConnected;; - } - catch(Exception &e) - { - LOGINFO("Ping caught %s \r\n",e.what()); - } - - /* If we get ACK, then the device is present in the network*/ - isConnected = true; - if ( !(BIT_CHECK(_instance->deviceList[idev].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) ) - { - LOGINFO("Device connected: %d \r\n",idev); - addDevice (idev); - } - return isConnected; - } - - void HdmiCecSource::sendDeviceUpdateInfo(const int logicalAddress) - { - JsonObject params; - params["logicalAddress"] = JsonValue(logicalAddress); - LOGINFO("Device info updated notification send: for logical address:%d\r\n", logicalAddress); - sendNotify(eventString[HDMICECSOURCE_EVENT_DEVICE_INFO_UPDATED], params); - } - - void HdmiCecSource::addDevice(const int logicalAddress) { - - if(!HdmiCecSource::_instance) - return; - - if ( logicalAddress >= LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated Or its not valid"); - return; - } - - if ( !(BIT_CHECK(HdmiCecSource::_instance->deviceList[logicalAddress].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) ) - { - BIT_SET(HdmiCecSource::_instance->deviceList[logicalAddress].m_deviceInfoStatus, BIT_DEVICE_PRESENT); - HdmiCecSource::_instance->deviceList[logicalAddress].m_logicalAddress = LogicalAddress(logicalAddress); - HdmiCecSource::_instance->m_numberOfDevices++; - LOGINFO("New cec ligical address add notification send: \r\n"); - sendNotify(eventString[HDMICECSOURCE_EVENT_DEVICE_ADDED], JsonObject()); - } - //Two source devices can have same logical address. - requestCecDevDetails(logicalAddress); - } - - void HdmiCecSource::removeAllCecDevices() { - int i = 0; - for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { - removeDevice (i); - } - } - void HdmiCecSource::removeDevice(const int logicalAddress) { - if(!HdmiCecSource::_instance) - return; - - if ( logicalAddress >= LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated Or its not valid"); - return; - } - - if (BIT_CHECK(HdmiCecSource::_instance->deviceList[logicalAddress].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) - { - _instance->m_numberOfDevices--; - _instance->deviceList[logicalAddress].clear(); - LOGINFO("Cec ligical address remove notification send: \r\n"); - sendNotify(eventString[HDMICECSOURCE_EVENT_DEVICE_REMOVED], JsonObject()); - } - } - - void HdmiCecSource::sendUnencryptMsg(unsigned char* msg, int size) - { - LOGINFO("sendMessage "); - - if(true == cecEnableStatus) - { - std::vector buf; - buf.resize(size); - - int itr = 0; - for (itr= 0; itrsendAsync(frame); - } - else - LOGWARN("cecEnableStatus=false"); - return; - } - - void HdmiCecSource::requestVendorID(const int newDevlogicalAddress) - { - //Get OSD name and vendor ID only from connected devices. Since devices are identified using polling - //Once OSD name and Vendor ID is updated. We have to poll again in next iteration also. Just to check - //a new device is reconnected with same logical address - unsigned char msg [2]; - unsigned int logicalAddr = logicalAddress.toInt(); - unsigned char sender = (unsigned char)(logicalAddr & 0x0f); - unsigned char receiver = (unsigned char) (newDevlogicalAddress & 0x0f); - - msg [0] = (sender<<4)|receiver; - //Request vendor id - msg [1] = 0x8c; - LOGINFO("Sending msg request vendor id %x %x", msg [0], msg [1]); - _instance->sendUnencryptMsg (msg, sizeof(msg)); - - } - - void HdmiCecSource::requestOsdName(const int newDevlogicalAddress) - { - //Get OSD name and vendor ID only from connected devices. Since devices are identified using polling - //Once OSD name and Vendor ID is updated. We have to poll again in next iteration also. Just to check - //a new device is reconnected with same logical address - unsigned char msg [2]; - unsigned int logicalAddr = logicalAddress.toInt(); - unsigned char sender = (unsigned char)(logicalAddr & 0x0f); - unsigned char receiver = (unsigned char) (newDevlogicalAddress & 0x0f); - - msg [0] = (sender<<4)|receiver; - //Request OSD name - msg [1] = 0x46; - LOGINFO("Sending msg request osd name %x %x", msg [0], msg [1]); - _instance->sendUnencryptMsg (msg, sizeof(msg)); - - } - - void HdmiCecSource::requestCecDevDetails(const int newDevlogicalAddress) - { - //Get OSD name and vendor ID only from connected devices. Since devices are identified using polling - //Once OSD name and Vendor ID is updated. We have to poll again in next iteration also. Just to check - //a new device is reconnected with same logical address - requestVendorID (newDevlogicalAddress); - requestOsdName (newDevlogicalAddress); - } - - void HdmiCecSource::threadRun() - { - if(!HdmiCecSource::_instance) - return; - if(!(_instance->smConnection)) - return; - LOGINFO("Entering ThreadRun: _instance->m_pollThreadExit %d",_instance->m_pollThreadExit); - int i = 0; - pthread_mutex_lock(&(_instance->m_lock));//pthread_cond_wait should be mutex protected. //pthread_cond_wait will unlock the mutex and perfoms wait for the condition. - while (!_instance->m_pollThreadExit) { - bool isActivateUpdateThread = false; - LOGINFO("Starting cec device polling"); - for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { - bool isConnected = _instance->pingDeviceUpdateList(i); - if (isConnected){ - isActivateUpdateThread = isConnected; - } - - } - if (isActivateUpdateThread){ - //i any of devices is connected activate thread update check - pthread_cond_signal(&(_instance->m_condSigUpdate)); - } - //Wait for mutex signal here to continue the worker thread again. - pthread_cond_wait(&(_instance->m_condSig), &(_instance->m_lock)); - - } - pthread_mutex_unlock(&(_instance->m_lock)); - LOGINFO("%s: Thread exited", __FUNCTION__); - } - void HdmiCecSource::threadSendKeyEvent() - { - if(!HdmiCecSource::_instance) - return; - - SendKeyInfo keyInfo = {-1,-1}; - - while(!_instance->m_sendKeyEventThreadExit) - { - keyInfo.logicalAddr = -1; - keyInfo.keyCode = -1; - { - // Wait for a message to be added to the queue - std::unique_lock lk(_instance->m_sendKeyEventMutex); - _instance->m_sendKeyCV.wait(lk, []{return (_instance->m_sendKeyEventThreadRun == true);}); - } - - if (_instance->m_sendKeyEventThreadExit == true) - { - LOGINFO(" threadSendKeyEvent Exiting"); - _instance->m_sendKeyEventThreadRun = false; - break; - } - - if (_instance->m_SendKeyQueue.empty()) { - _instance->m_sendKeyEventThreadRun = false; - continue; - } - - keyInfo = _instance->m_SendKeyQueue.front(); - _instance->m_SendKeyQueue.pop(); - - LOGINFO("sendRemoteKeyThread : logical addr:0x%x keyCode: 0x%x queue size :%d \n",keyInfo.logicalAddr,keyInfo.keyCode,(int)_instance->m_SendKeyQueue.size()); - _instance->sendKeyPressEvent(keyInfo.logicalAddr,keyInfo.keyCode); - _instance->sendKeyReleaseEvent(keyInfo.logicalAddr); - } - LOGINFO("%s: Thread exited", __FUNCTION__); - } - void HdmiCecSource::threadUpdateCheck() - { - if(!HdmiCecSource::_instance) - return; - if(!(_instance->smConnection)) - return; - LOGINFO("Entering ThreadUpdate: _instance->m_updateThreadExit %d",_instance->m_updateThreadExit); - int i = 0; - pthread_mutex_lock(&(_instance->m_lockUpdate));//pthread_cond_wait should be mutex protected. //pthread_cond_wait will unlock the mutex and perfoms wait for the condition. - while (!_instance->m_updateThreadExit) { - //Wait for mutex signal here to continue the worker thread again. - pthread_cond_wait(&(_instance->m_condSigUpdate), &(_instance->m_lockUpdate)); - - LOGINFO("Starting cec device update check"); - for(i=0; ((i< LogicalAddress::UNREGISTERED)&&(!_instance->m_updateThreadExit)); i++ ) { - //If details are not updated. update now. - if (BIT_CHECK(HdmiCecSource::_instance->deviceList[i].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) - { - int itr = 0; - bool retry = true; - int iCounter = 0; - for (itr = 0; ((itr<5)&&(retry)); itr++){ - - if (!HdmiCecSource::_instance->deviceList[i].m_isOSDNameUpdated){ - iCounter = 0; - while ((!_instance->m_updateThreadExit) && (iCounter < (2*10))) { //sleep for 2sec. - usleep (100 * 1000); //sleep for 100 milli sec - iCounter ++; - } - - HdmiCecSource::_instance->requestOsdName (i); - retry = true; - } - else { - retry = false; - } - - if (!HdmiCecSource::_instance->deviceList[i].m_isVendorIDUpdated){ - iCounter = 0; - while ((!_instance->m_updateThreadExit) && (iCounter < (2*10))) { //sleep for 1sec. - usleep (100 * 1000); //sleep for 100 milli sec - iCounter ++; - } - - HdmiCecSource::_instance->requestVendorID (i); - retry = true; - } - } - if (retry){ - LOGINFO("cec device: %d update time out", i); - } - } - } - - } - pthread_mutex_unlock(&(_instance->m_lockUpdate)); - LOGINFO("%s: Thread exited", __FUNCTION__); - } - } // namespace Plugin } // namespace WPEFramework diff --git a/HdmiCecSource/HdmiCecSource.h b/HdmiCecSource/HdmiCecSource.h index 30e9d5ad..b53266e0 100644 --- a/HdmiCecSource/HdmiCecSource.h +++ b/HdmiCecSource/HdmiCecSource.h @@ -23,13 +23,6 @@ #include #include -#include "ccec/FrameListener.hpp" -#include "ccec/Connection.hpp" -#include "libIARM.h" -#include "ccec/Assert.hpp" -#include "ccec/Messages.hpp" -#include "ccec/MessageDecoder.hpp" -#include "ccec/MessageProcessor.hpp" #include #undef Assert // this define from Connection.hpp conflicts with WPEFramework @@ -39,124 +32,15 @@ #include "UtilsBIT.h" #include "UtilsThreadRAII.h" -#include -#include "PowerManagerInterface.h" +#include +#include +#include using namespace WPEFramework; -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; -using ThermalTemperature = WPEFramework::Exchange::IPowerManager::ThermalTemperature; namespace WPEFramework { namespace Plugin { - class HdmiCecSourceFrameListener : public FrameListener - { - public: - HdmiCecSourceFrameListener(MessageProcessor &processor) : processor(processor) {} - void notify(const CECFrame &in) const; - ~HdmiCecSourceFrameListener() {} - private: - MessageProcessor &processor; - }; - - class HdmiCecSourceProcessor : public MessageProcessor - { - public: - HdmiCecSourceProcessor(Connection &conn) : conn(conn) {} - void process (const ActiveSource &msg, const Header &header); - void process (const InActiveSource &msg, const Header &header); - void process (const ImageViewOn &msg, const Header &header); - void process (const TextViewOn &msg, const Header &header); - void process (const RequestActiveSource &msg, const Header &header); - void process (const Standby &msg, const Header &header); - void process (const GetCECVersion &msg, const Header &header); - void process (const CECVersion &msg, const Header &header); - void process (const SetMenuLanguage &msg, const Header &header); - void process (const GiveOSDName &msg, const Header &header); - void process (const GivePhysicalAddress &msg, const Header &header); - void process (const GiveDeviceVendorID &msg, const Header &header); - void process (const SetOSDString &msg, const Header &header); - void process (const SetOSDName &msg, const Header &header); - void process (const RoutingChange &msg, const Header &header); - void process (const RoutingInformation &msg, const Header &header); - void process (const SetStreamPath &msg, const Header &header); - void process (const GetMenuLanguage &msg, const Header &header); - void process (const ReportPhysicalAddress &msg, const Header &header); - void process (const DeviceVendorID &msg, const Header &header); - void process (const GiveDevicePowerStatus &msg, const Header &header); - void process (const ReportPowerStatus &msg, const Header &header); - void process (const UserControlPressed &msg, const Header &header); - void process (const UserControlReleased &msg, const Header &header); - void process (const FeatureAbort &msg, const Header &header); - void process (const Abort &msg, const Header &header); - void process (const Polling &msg, const Header &header); - private: - Connection conn; - void printHeader(const Header &header) - { - printf("Header : From : %s \n", header.from.toString().c_str()); - printf("Header : to : %s \n", header.to.toString().c_str()); - } - - }; - -#define BIT_DEVICE_PRESENT (0) - - class CECDeviceInfo_2 { - public: - - LogicalAddress m_logicalAddress; - VendorID m_vendorID; - OSDName m_osdName; - // - short m_deviceInfoStatus; - bool m_isOSDNameUpdated; - bool m_isVendorIDUpdated; - std::mutex m_; - std::condition_variable cv_; - std::unique_lock lk; - - CECDeviceInfo_2() - : m_logicalAddress(0),m_vendorID(0,0,0),m_osdName("NA"), m_isOSDNameUpdated (false), m_isVendorIDUpdated (false) - { - BITMASK_CLEAR(m_deviceInfoStatus, 0xFFFF); //Clear all bits - } - - void clear( ) - { - m_logicalAddress = 0; - m_vendorID = VendorID(0,0,0); - m_osdName = "NA"; - BITMASK_CLEAR(m_deviceInfoStatus, 0xFFFF); //Clear all bits - m_isOSDNameUpdated = false; - m_isVendorIDUpdated = false; - } - - bool update ( const VendorID &vendorId) { - bool isVendorIdUpdated = false; - if (!m_isVendorIDUpdated) - isVendorIdUpdated = true; //First time no need to cross check the value. Since actual value can be default value - else - isVendorIdUpdated = (m_vendorID.toString().compare(vendorId.toString())==0)?false:true; - - m_isVendorIDUpdated = true; - m_vendorID = vendorId; - return isVendorIdUpdated; - } - - bool update ( const OSDName &osdName ) { - bool isOSDNameUpdated = false; - if (!m_isOSDNameUpdated) - isOSDNameUpdated = true; //First time no need to cross check the value. Since actual value can be default value - else - isOSDNameUpdated = (m_osdName.toString().compare(osdName.toString())==0)?false:true; - - m_isOSDNameUpdated = true; - m_osdName = osdName; - return isOSDNameUpdated; - } - - }; // This is a server for a JSONRPC communication channel. // For a plugin to be capable to handle JSONRPC, inherit from PluginHost::JSONRPC. // By inheriting from this class, the plugin realizes the interface PluginHost::IDispatcher. @@ -170,168 +54,130 @@ namespace WPEFramework { // this class exposes a public method called, Notify(), using this methods, all subscribed clients // will receive a JSONRPC message as a notification, in case this method is called. class HdmiCecSource : public PluginHost::IPlugin, public PluginHost::JSONRPC { - enum { - VOLUME_UP = 0x41, - VOLUME_DOWN = 0x42, - MUTE = 0x43, - UP = 0x01, - DOWN = 0x02, - LEFT = 0x03, - RIGHT = 0x04, - SELECT = 0x00, - HOME = 0x09, - BACK = 0x0D, - NUMBER_0 = 0x20, - NUMBER_1 = 0x21, - NUMBER_2 = 0x22, - NUMBER_3 = 0x23, - NUMBER_4 = 0x24, - NUMBER_5 = 0x25, - NUMBER_6 = 0x26, - NUMBER_7 = 0x27, - NUMBER_8 = 0x28, - NUMBER_9 = 0x29 - }; - public: - HdmiCecSource(); - virtual ~HdmiCecSource(); - virtual const string Initialize(PluginHost::IShell* service) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override { return {}; } - void onPowerModeChanged(const PowerState ¤tState, const PowerState &newState); - void registerEventHandlers(); - static HdmiCecSource* _instance; - CECDeviceInfo_2 deviceList[16]; - pthread_cond_t m_condSig; - pthread_mutex_t m_lock; - pthread_cond_t m_condSigUpdate; - pthread_mutex_t m_lockUpdate; - bool cecEnableStatus; - - void SendKeyPressMsgEvent(const int logicalAddress,const int keyCode); - void SendKeyReleaseMsgEvent(const int logicalAddress); - void SendStandbyMsgEvent(const int logicalAddress); - void sendActiveSourceEvent(); - void addDevice(const int logicalAddress); - void removeDevice(const int logicalAddress); - void sendUnencryptMsg(unsigned char* msg, int size); - void sendDeviceUpdateInfo(const int logicalAddress); - void sendKeyPressEvent(const int logicalAddress, int keyCode); - void sendKeyReleaseEvent(const int logicalAddress); - typedef struct sendKeyInfo - { - int logicalAddr; - int keyCode; - }SendKeyInfo; - BEGIN_INTERFACE_MAP(HdmiCecSource) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - private: - class PowerManagerNotification : public Exchange::IPowerManager::INotification { private: - PowerManagerNotification(const PowerManagerNotification&) = delete; - PowerManagerNotification& operator=(const PowerManagerNotification&) = delete; - + class Notification : public RPC::IRemoteConnection::INotification, + public Exchange::IHdmiCecSource::INotification + { + private: + Notification() = delete; + Notification(const Notification&) = delete; + Notification& operator=(const Notification&) = delete; + + public: + explicit Notification(HdmiCecSource* parent) + : _parent(*parent) + { + ASSERT(parent != nullptr); + } + + virtual ~Notification() + { + } + + BEGIN_INTERFACE_MAP(Notification) + INTERFACE_ENTRY(Exchange::IHdmiCecSource::INotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP + + void Activated(RPC::IRemoteConnection*) override + { + } + + void Deactivated(RPC::IRemoteConnection *connection) override + { + _parent.Deactivated(connection); + } + + void OnDeviceAdded(const int logicalAddress) override + { + LOGINFO("OnDeviceAdded"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSource::Event::OnDeviceAdded(_parent, logicalAddress); + } + void OnDeviceRemoved(const int logicalAddress) override + { + LOGINFO("OnDeviceRemoved"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSource::Event::OnDeviceRemoved(_parent, logicalAddress); + } + void OnDeviceInfoUpdated(const int logicalAddress) override + { + LOGINFO("OnDeviceInfoUpdated"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSource::Event::OnDeviceInfoUpdated(_parent, logicalAddress); + } + void OnActiveSourceStatusUpdated(const bool status) override + { + LOGINFO("OnActiveSourceStatusUpdated"); + LOGINFO("status: %d", status); + Exchange::JHdmiCecSource::Event::OnActiveSourceStatusUpdated(_parent, status); + } + void StandbyMessageReceived(const int logicalAddress) override + { + LOGINFO("StandbyMessageReceived"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSource::Event::StandbyMessageReceived(_parent, logicalAddress); + } + void OnKeyReleaseEvent(const int logicalAddress) override + { + LOGINFO("OnKeyReleaseEvent"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSource::Event::OnKeyReleaseEvent(_parent, logicalAddress); + } + void OnKeyPressEvent(const int logicalAddress, const int keyCode) override + { + LOGINFO("OnKeyPressEvent"); + LOGINFO("logicalAddress: %d, keyCode: %d", logicalAddress, keyCode); + Exchange::JHdmiCecSource::Event::OnKeyPressEvent(_parent, logicalAddress, keyCode); + } + + private: + HdmiCecSource &_parent; + + }; + public: - explicit PowerManagerNotification(HdmiCecSource& parent) - : _parent(parent) + // We do not allow this plugin to be copied !! + HdmiCecSource(const HdmiCecSource&) = delete; + HdmiCecSource& operator=(const HdmiCecSource&) = delete; + + HdmiCecSource() + : PluginHost::IPlugin() + , PluginHost::JSONRPC() + , _service(nullptr) + , _notification(this) + , _hdmiCecSource(nullptr) + , _connectionId(0) { + } - ~PowerManagerNotification() override = default; - - public: - void OnPowerModeChanged(const PowerState ¤tState, const PowerState &newState) override + virtual ~HdmiCecSource() { - _parent.onPowerModeChanged(currentState, newState); + } - void OnPowerModePreChange(const PowerState ¤tState, const PowerState &newState) override {} - void OnDeepSleepTimeout(const int &wakeupTimeout) override {} - void OnNetworkStandbyModeChanged(const bool &enabled) override {} - void OnThermalModeChanged(const ThermalTemperature ¤tThermalLevel, const ThermalTemperature &newThermalLevel, const float ¤tTemperature) override {} - void OnRebootBegin(const string &rebootReasonCustom, const string &rebootReasonOther, const string &rebootRequestor) override {} - - BEGIN_INTERFACE_MAP(PowerManagerNotification) - INTERFACE_ENTRY(Exchange::IPowerManager::INotification) + + BEGIN_INTERFACE_MAP(HdmiCecSource) + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_AGGREGATE(Exchange::IHdmiCecSource, _hdmiCecSource) END_INTERFACE_MAP - + + // IPlugin methods + // ------------------------------------------------------------------------------------------------------- + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + //Begin methods + private: - HdmiCecSource& _parent; - }; - // We do not allow this plugin to be copied !! - HdmiCecSource(const HdmiCecSource&) = delete; - HdmiCecSource& operator=(const HdmiCecSource&) = delete; + void Deactivated(RPC::IRemoteConnection* connection); - //Begin methods - uint32_t setEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setOTPEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getOTPEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setOSDNameWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getOSDNameWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setVendorIdWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getVendorIdWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t performOTPActionWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendStandbyMessageWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getDeviceList (const JsonObject& parameters, JsonObject& response); - uint32_t getActiveSourceStatus(const JsonObject& parameters, JsonObject& response); - uint32_t sendRemoteKeyPressWrapper(const JsonObject& parameters, JsonObject& response); - - //End methods - std::string logicalAddressDeviceType; - bool cecSettingEnabled; - bool cecOTPSettingEnabled; - Connection *smConnection; - int m_numberOfDevices; - bool m_pollThreadExit; - Utils::ThreadRAII m_pollThread; - bool m_updateThreadExit; - Utils::ThreadRAII m_UpdateThread; - bool m_sendKeyEventThreadExit; - bool m_sendKeyEventThreadRun; - Utils::ThreadRAII m_sendKeyEventThread; - std::mutex m_sendKeyEventMutex; - std::queue m_SendKeyQueue; - std::condition_variable m_sendKeyCV; - - HdmiCecSourceProcessor *msgProcessor; - HdmiCecSourceFrameListener *msgFrameListener; - void InitializePowerManager(PluginHost::IShell *service); - const void InitializeIARM(); - void DeinitializeIARM(); - static void dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); - void onHdmiHotPlug(int connectStatus); - bool loadSettings(); - void persistSettings(bool enableStatus); - void persistOTPSettings(bool enableStatus); - void persistOSDName(const char *name); - void persistVendorId(unsigned int vendorID); - void setEnabled(bool enabled, bool isPersist); - bool getEnabled(); - void setOTPEnabled(bool enabled); - bool getOTPEnabled(); - bool performOTPAction(); - void CECEnable(void); - void CECDisable(void); - void getPhysicalAddress(); - void getLogicalAddress(); - void cecAddressesChanged(int changeStatus); - bool sendStandbyMessage(); - bool pingDeviceUpdateList (int idev); - void removeAllCecDevices(); - void requestVendorID(const int newDevlogicalAddress); - void requestOsdName(const int newDevlogicalAddress); - void requestCecDevDetails(const int logicalAddress); - static void threadRun(); - static void threadUpdateCheck(); - static void threadSendKeyEvent(); - static void threadHotPlugEventHandler(int data); - static void threadCecDaemonInitHandler(); - static void threadCecStatusUpdateHandler(int data); - PowerManagerInterfaceRef _powerManagerPlugin; - Core::Sink _pwrMgrNotification; - bool _registeredEventHandlers; + private: + PluginHost::IShell* _service{}; + Core::Sink _notification; + Exchange::IHdmiCecSource* _hdmiCecSource; + uint32_t _connectionId; }; } // namespace Plugin } // namespace WPEFramework diff --git a/HdmiCecSource/HdmiCecSourceImplementation.cpp b/HdmiCecSource/HdmiCecSourceImplementation.cpp new file mode 100644 index 00000000..bc944221 --- /dev/null +++ b/HdmiCecSource/HdmiCecSourceImplementation.cpp @@ -0,0 +1,1639 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2025 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. +**/ + +#include "HdmiCecSourceImplementation.h" + + +#include "ccec/Connection.hpp" +#include "ccec/CECFrame.hpp" +#include "ccec/MessageEncoder.hpp" +#include "host.hpp" +#include "ccec/host/RDK.hpp" + +#include "dsMgr.h" +#include "dsDisplay.h" +#include "videoOutputPort.hpp" +#include "manager.hpp" +#include "websocket/URL.h" + +#include "UtilsIarm.h" +#include "UtilsJsonRpc.h" +#include "UtilssyncPersistFile.h" +#include "UtilsSearchRDKProfile.h" + +#define HDMICECSOURCE_METHOD_SET_ENABLED "SetEnabled" +#define HDMICECSOURCE_METHOD_GET_ENABLED "GetEnabled" +#define HDMICECSOURCE_METHOD_OTP_SET_ENABLED "SetOTPEnabled" +#define HDMICECSOURCE_METHOD_OTP_GET_ENABLED "GetOTPEnabled" +#define HDMICECSOURCE_METHOD_SET_OSD_NAME "SetOSDName" +#define HDMICECSOURCE_METHOD_GET_OSD_NAME "GetOSDName" +#define HDMICECSOURCE_METHOD_SET_VENDOR_ID "SetVendorId" +#define HDMICECSOURCE_METHOD_GET_VENDOR_ID "GetVendorId" +#define HDMICECSOURCE_METHOD_PERFORM_OTP_ACTION "PerformOTPAction" +#define HDMICECSOURCE_METHOD_SEND_STANDBY_MESSAGE "SendStandbyMessage" +#define HDMICECSOURCE_METHOD_GET_ACTIVE_SOURCE_STATUS "getActiveSourceStatus" +#define HDMICECSOURCE_METHOD_SEND_KEY_PRESS "SendKeyPressEvent" +#define HDMICEC_EVENT_ON_DEVICES_CHANGED "onDevicesChanged" +#define HDMICEC_EVENT_ON_HDMI_HOT_PLUG "onHdmiHotPlug" +#define HDMICEC_EVENT_ON_STANDBY_MSG_RECEIVED "standbyMessageReceived" +#define HDMICEC_EVENT_ON_KEYPRESS_MSG_RECEIVED "onKeyPressEvent" +#define HDMICEC_EVENT_ON_KEYRELEASE_MSG_RECEIVED "onKeyReleaseEvent" +#define DEV_TYPE_TUNER 1 +#define HDMI_HOT_PLUG_EVENT_CONNECTED 0 +#define ABORT_REASON_ID 4 + +#define API_VERSION_NUMBER_MAJOR 1 +#define API_VERSION_NUMBER_MINOR 0 +#define API_VERSION_NUMBER_PATCH 8 + +#define CEC_SETTING_ENABLED_FILE "/opt/persistent/ds/cecData_2.json" +#define CEC_SETTING_ENABLED "cecEnabled" +#define CEC_SETTING_OTP_ENABLED "cecOTPEnabled" +#define CEC_SETTING_OSD_NAME "cecOSDName" +#define CEC_SETTING_VENDOR_ID "cecVendorId" + +static std::vector defaultVendorId = {0x00,0x19,0xFB}; +static VendorID appVendorId = {defaultVendorId.at(0),defaultVendorId.at(1),defaultVendorId.at(2)}; +static VendorID lgVendorId = {0x00,0xE0,0x91}; +static PhysicalAddress physical_addr = {0x0F,0x0F,0x0F,0x0F}; +static LogicalAddress logicalAddress = 0xF; +static OSDName osdName = "TV Box"; +static int32_t powerState = 1; +static PowerStatus tvPowerState = 1; +static bool isDeviceActiveSource = false; +static bool isLGTvConnected = false; + +using namespace WPEFramework; + + +namespace WPEFramework +{ + namespace Plugin + { + SERVICE_REGISTRATION(HdmiCecSourceImplementation, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); + + HdmiCecSourceImplementation* HdmiCecSourceImplementation::_instance = nullptr; + static int libcecInitStatus = 0; + +//=========================================== HdmiCecSourceFrameListener ========================================= + void HdmiCecSourceFrameListener::notify(const CECFrame &in) const { + const uint8_t *buf = NULL; + char strBuffer[512] = {0}; + size_t len = 0; + + in.getBuffer(&buf, &len); + for (unsigned int i = 0; i < len; i++) { + snprintf(strBuffer + (i*3) , sizeof(strBuffer) - (i*3), "%02X ",(uint8_t) *(buf + i)); + } + LOGINFO(" >>>>> Received CEC Frame: :%s \n",strBuffer); + + MessageDecoder(processor).decode(in); + } + +//=========================================== HdmiCecSourceProcessor ========================================= + void HdmiCecSourceProcessor::process (const ActiveSource &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); + if(msg.physicalAddress.toString() == physical_addr.toString()) + isDeviceActiveSource = true; + else + isDeviceActiveSource = false; + LOGINFO("ActiveSource isDeviceActiveSource status :%d \n", isDeviceActiveSource); + HdmiCecSourceImplementation::_instance->sendActiveSourceEvent(); + HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const InActiveSource &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: InActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); + } + void HdmiCecSourceProcessor::process (const ImageViewOn &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ImageViewOn \n"); + HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const TextViewOn &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: TextViewOn\n"); + HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const RequestActiveSource &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: RequestActiveSource\n"); + if(isDeviceActiveSource) + { + LOGINFO("sending ActiveSource\n"); + try + { + conn.sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(ActiveSource(physical_addr))); + } + catch(...) + { + LOGWARN("Exception while sending ActiveSource"); + } + } + } + void HdmiCecSourceProcessor::process (const Standby &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: Standby from %s\n", header.from.toString().c_str()); + HdmiCecSourceImplementation::_instance->SendStandbyMsgEvent(header.from.toInt()); + + } + void HdmiCecSourceProcessor::process (const GetCECVersion &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GetCECVersion sending CECVersion response \n"); + try + { + conn.sendTo(header.from, MessageEncoder().encode(CECVersion(Version::V_1_4))); + } + catch(...) + { + LOGWARN("Exception while sending CECVersion "); + } + } + void HdmiCecSourceProcessor::process (const CECVersion &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: CECVersion Version : %s \n",msg.version.toString().c_str()); + HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const SetMenuLanguage &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetMenuLanguage Language : %s \n",msg.language.toString().c_str()); + } + void HdmiCecSourceProcessor::process (const GiveOSDName &msg, const Header &header) + { + printHeader(header); + if (!(header.from == LogicalAddress(LogicalAddress::UNREGISTERED))) + { + LOGINFO("Command: GiveOSDName sending SetOSDName : %s\n",osdName.toString().c_str()); + try + { + conn.sendTo(header.from, MessageEncoder().encode(SetOSDName(osdName))); + } + catch(...) + { + LOGWARN("Exception while sending SetOSDName"); + } + } + } + void HdmiCecSourceProcessor::process (const GivePhysicalAddress &msg, const Header &header) + { + LOGINFO("Command: GivePhysicalAddress\n"); + try + { + LOGINFO(" sending ReportPhysicalAddress response physical_addr :%s logicalAddress :%x \n",physical_addr.toString().c_str(), logicalAddress.toInt()); + conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(ReportPhysicalAddress(physical_addr,logicalAddress.toInt()))); + } + catch(...) + { + LOGWARN("Exception while sending ReportPhysicalAddress "); + } + } + void HdmiCecSourceProcessor::process (const GiveDeviceVendorID &msg, const Header &header) + { + printHeader(header); + try + { + LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n",(isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); + if(isLGTvConnected) + conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(lgVendorId))); + else + conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); + } + catch(...) + { + LOGWARN("Exception while sending DeviceVendorID"); + } + + } + void HdmiCecSourceProcessor::process (const SetOSDString &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetOSDString OSDString : %s\n",msg.osdString.toString().c_str()); + } + void HdmiCecSourceProcessor::process (const SetOSDName &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetOSDName OSDName : %s\n",msg.osdName.toString().c_str()); + if (HdmiCecSourceImplementation::_instance) { + bool isOSDNameUpdated = HdmiCecSourceImplementation::_instance->deviceList[header.from.toInt()].update(msg.osdName); + if (isOSDNameUpdated) + HdmiCecSourceImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } else { + LOGWARN("Exception HdmiCecSourceImplementation::_instance NULL"); + } + } + void HdmiCecSourceProcessor::process (const RoutingChange &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: RoutingChange From : %s To: %s \n",msg.from.toString().c_str(),msg.to.toString().c_str()); + if(msg.to.toString() == physical_addr.toString()) + isDeviceActiveSource = true; + else + isDeviceActiveSource = false; + LOGINFO("physical_addr : %s isDeviceActiveSource :%d \n",physical_addr.toString().c_str(),isDeviceActiveSource); + HdmiCecSourceImplementation::_instance->sendActiveSourceEvent(); + } + void HdmiCecSourceProcessor::process (const RoutingInformation &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: RoutingInformation Routing Information to Sink : %s\n",msg.toSink.toString().c_str()); + if(msg.toSink.toString() == physical_addr.toString()) + isDeviceActiveSource = true; + else + isDeviceActiveSource = false; + LOGINFO("physical_addr : %s isDeviceActiveSource :%d \n",physical_addr.toString().c_str(),isDeviceActiveSource); + HdmiCecSourceImplementation::_instance->sendActiveSourceEvent(); + } + void HdmiCecSourceProcessor::process (const SetStreamPath &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetStreamPath Set Stream Path to Sink : %s\n",msg.toSink.toString().c_str()); + if(msg.toSink.toString() == physical_addr.toString()) + isDeviceActiveSource = true; + else + isDeviceActiveSource = false; + LOGINFO("physical_addr : %s isDeviceActiveSource :%d \n",physical_addr.toString().c_str(),isDeviceActiveSource); + HdmiCecSourceImplementation::_instance->sendActiveSourceEvent(); + + } + void HdmiCecSourceProcessor::process (const GetMenuLanguage &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GetMenuLanguage\n"); + } + void HdmiCecSourceProcessor::process (const ReportPhysicalAddress &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ReportPhysicalAddress\n"); + HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const DeviceVendorID &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: DeviceVendorID VendorID : %s\n",msg.vendorId.toString().c_str()); + if (HdmiCecSourceImplementation::_instance){ + bool isVendorIdUpdated = HdmiCecSourceImplementation::_instance->deviceList[header.from.toInt()].update(msg.vendorId); + if (isVendorIdUpdated) + HdmiCecSourceImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } + else { + LOGWARN("Exception HdmiCecSourceImplementation::_instance NULL"); + } + + } + void HdmiCecSourceProcessor::process (const GiveDevicePowerStatus &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GiveDevicePowerStatus sending powerState :%d \n",powerState); + try + { + conn.sendTo(header.from, MessageEncoder().encode(ReportPowerStatus(PowerStatus(powerState)))); + } + catch(...) + { + LOGWARN("Exception while sending ReportPowerStatus"); + } + } + void HdmiCecSourceProcessor::process (const ReportPowerStatus &msg, const Header &header) + { + printHeader(header); + if ((header.from == LogicalAddress(LogicalAddress::TV))) + tvPowerState = msg.status; + LOGINFO("Command: ReportPowerStatus TV Power Status from:%s status : %s \n",header.from.toString().c_str(),msg.status.toString().c_str()); + HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const UserControlPressed &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: UserControlPressed message received from:%s command : %d \n",header.from.toString().c_str(),msg.uiCommand.toInt()); + HdmiCecSourceImplementation::_instance->SendKeyPressMsgEvent(header.from.toInt(),msg.uiCommand.toInt()); + } + void HdmiCecSourceProcessor::process (const UserControlReleased &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: UserControlReleased message received from:%s \n",header.from.toString().c_str()); + HdmiCecSourceImplementation::_instance->SendKeyReleaseMsgEvent(header.from.toInt()); + } + void HdmiCecSourceProcessor::process (const FeatureAbort &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: FeatureAbort\n"); + } + void HdmiCecSourceProcessor::process (const Abort &msg, const Header &header) + { + printHeader(header); + if (!(header.from == LogicalAddress(LogicalAddress::BROADCAST))) + { + LOGINFO("Command: Abort, sending FeatureAbort"); + try + { + conn.sendTo(header.from, MessageEncoder().encode(FeatureAbort(OpCode(msg.opCode()),AbortReason(ABORT_REASON_ID)))); + } + catch(...) + { + LOGWARN("Exception while sending FeatureAbort command"); + } + + } + LOGINFO("Command: Abort\n"); + } + void HdmiCecSourceProcessor::process (const Polling &msg, const Header &header) { + printHeader(header); + LOGINFO("Command: Polling\n"); + } + + +//=========================================== HdmiCecSourceImplementation ========================================= + + HdmiCecSourceImplementation::HdmiCecSourceImplementation() + : cecEnableStatus(false),smConnection(nullptr), m_sendKeyEventThreadRun(false) + , _pwrMgrNotification(*this) + , _registeredEventHandlers(false) + { + LOGWARN("ctor"); + HdmiCecSourceImplementation::_instance = this; + } + + HdmiCecSourceImplementation::~HdmiCecSourceImplementation() + { + LOGWARN("dtor"); + HdmiCecSourceImplementation::_instance = nullptr; + + if(_powerManagerPlugin) + { + _powerManagerPlugin.Reset(); + } + _registeredEventHandlers = false; + + DeinitializeIARM(); + } + + uint32_t HdmiCecSourceImplementation::Configure(PluginHost::IShell* service) + { + LOGINFO("Configure"); + ASSERT(service != nullptr); + PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + uint32_t res = Core::ERROR_GENERAL; + string msg; + if (Utils::IARM::init()) { + //Initialize cecEnableStatus to false in ctor + cecEnableStatus = false; + + logicalAddressDeviceType = "None"; + logicalAddress = 0xFF; + + //CEC plugin functionalities will only work if CECmgr is available. If plugin Initialize failure upper layer will call dtor directly. + InitializeIARM(); + InitializePowerManager(service); + + // load persistence setting + loadSettings(); + try + { + //TODO(MROLLINS) this is probably per process so we either need to be running in our own process or be carefull no other plugin is calling it + device::Manager::Initialize(); + std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); + device::VideoOutputPort vPort = device::Host::getInstance().getVideoOutputPort(strVideoPort.c_str()); + if (vPort.isDisplayConnected()) + { + std::vector edidVec; + vPort.getDisplay().getEDIDBytes(edidVec); + //Set LG vendor id if connected with LG TV + if(edidVec.at(8) == 0x1E && edidVec.at(9) == 0x6D) + { + isLGTvConnected = true; + } + LOGINFO("manufacturer byte from edid :%x: %x isLGTvConnected :%d",edidVec.at(8),edidVec.at(9),isLGTvConnected); + } + } + catch(...) + { + LOGWARN("Exception in getting edid info .\r\n"); + } + + // get power state: + ASSERT (_powerManagerPlugin); + if (_powerManagerPlugin){ + res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); + if (Core::ERROR_NONE == res) + { + powerState = (pwrStateCur == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON)?0:1 ; + LOGINFO("Current state is PowerManagerPlugin: (%d) powerState :%d \n",pwrStateCur,powerState); + } + } + + if (cecSettingEnabled) + { + try + { + CECEnable(); + } + catch(...) + { + LOGWARN("Exception while enabling CEC settings .\r\n"); + } + } + } else { + msg = "IARM bus is not available"; + LOGERR("IARM bus is not available. Failed to activate HdmiCecSource Plugin"); + } + ASSERT(_powerManagerPlugin); + registerEventHandlers(); + return Core::ERROR_NONE; + } + + void HdmiCecSourceImplementation::registerEventHandlers() + { + ASSERT (_powerManagerPlugin); + + if(!_registeredEventHandlers && _powerManagerPlugin) { + _registeredEventHandlers = true; + _powerManagerPlugin->Register(&_pwrMgrNotification); + } + + + } + + uint32_t HdmiCecSourceImplementation::Register(Exchange::IHdmiCecSource::INotification* notification) + { + + LOGINFO("Register"); + if(notification != nullptr){ + _adminLock.Lock(); + if(std::find(_hdmiCecSourceNotifications.begin(), _hdmiCecSourceNotifications.end(), notification) == _hdmiCecSourceNotifications.end()) + { + _hdmiCecSourceNotifications.push_back(notification); + notification->AddRef(); + } + else + { + LOGERR("Same notification is registered already"); + } + _adminLock.Unlock(); + } + + return Core::ERROR_NONE; + } + + + uint32_t HdmiCecSourceImplementation::Unregister(Exchange::IHdmiCecSource::INotification* notification) + { + LOGINFO("Unregister"); + if(notification != nullptr){ + _adminLock.Lock(); + std::list::iterator index = std::find(_hdmiCecSourceNotifications.begin(), _hdmiCecSourceNotifications.end(), notification); + if(index != _hdmiCecSourceNotifications.end()) + { + (*index)->Release(); + _hdmiCecSourceNotifications.erase(index); + } + else + { + LOGERR("Notification is not registered"); + } + _adminLock.Unlock(); + } + + return Core::ERROR_NONE; + } + + void HdmiCecSourceImplementation::addDevice(const int logicalAddress) { + + if(!HdmiCecSourceImplementation::_instance) + return; + + if ( logicalAddress >= LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated Or its not valid"); + return; + } + + if ( !(BIT_CHECK(HdmiCecSourceImplementation::_instance->deviceList[logicalAddress].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) ) + { + BIT_SET(HdmiCecSourceImplementation::_instance->deviceList[logicalAddress].m_deviceInfoStatus, BIT_DEVICE_PRESENT); + HdmiCecSourceImplementation::_instance->deviceList[logicalAddress].m_logicalAddress = LogicalAddress(logicalAddress); + HdmiCecSourceImplementation::_instance->m_numberOfDevices++; + LOGINFO("New cec ligical address add notification send: \r\n"); + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->OnDeviceAdded(logicalAddress); + index++; + } + } + //Two source devices can have same logical address. + requestCecDevDetails(logicalAddress); + } + + void HdmiCecSourceImplementation::removeDevice(const int logicalAddress) { + if(!HdmiCecSourceImplementation::_instance) + return; + + if ( logicalAddress >= LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated Or its not valid"); + return; + } + + if (BIT_CHECK(HdmiCecSourceImplementation::_instance->deviceList[logicalAddress].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) + { + _instance->m_numberOfDevices--; + _instance->deviceList[logicalAddress].clear(); + LOGINFO("Cec ligical address remove notification send: \r\n"); + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->OnDeviceRemoved(logicalAddress); + index++; + } + + } + } + + + uint32_t HdmiCecSourceImplementation::GetActiveSourceStatus(bool &isActiveSource, bool &success) + { + isActiveSource = isDeviceActiveSource; + success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::sendKeyPressEvent(const int logicalAddress, int keyCode) + { + if(!(_instance->smConnection)) + { + return Core::ERROR_GENERAL; + } + LOGINFO(" SendKeyPressEvent logicalAddress 0x%x keycode 0x%x\n",logicalAddress,keyCode); + switch(keyCode) + { + case VOLUME_UP: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_UP)),100); + break; + case VOLUME_DOWN: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_DOWN)), 100); + break; + case MUTE: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_MUTE)), 100); + break; + case UP: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_UP)), 100); + break; + case DOWN: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_DOWN)), 100); + break; + case LEFT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_LEFT)), 100); + break; + case RIGHT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_RIGHT)), 100); + break; + case SELECT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_SELECT)), 100); + break; + case HOME: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_HOME)), 100); + break; + case BACK: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_BACK)), 100); + break; + case NUMBER_0: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_0)), 100); + break; + case NUMBER_1: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_1)), 100); + break; + case NUMBER_2: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_2)), 100); + break; + case NUMBER_3: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_3)), 100); + break; + case NUMBER_4: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_4)), 100); + break; + case NUMBER_5: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_5)), 100); + break; + case NUMBER_6: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_6)), 100); + break; + case NUMBER_7: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_7)), 100); + break; + case NUMBER_8: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_8)), 100); + break; + case NUMBER_9: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_9)), 100); + break; + + } + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::SendKeyPressEvent(const uint32_t &logicalAddress,const uint32_t &keyCode, HdmiCecSourceSuccess &success) + { + SendKeyInfo keyInfo; + try { + keyInfo.logicalAddr = logicalAddress; + keyInfo.keyCode = keyCode; + } catch (const std::invalid_argument& e) { + std::cerr << "Invalid input: " << e.what() << std::endl; + success.success = false; + return Core::ERROR_GENERAL; + } + std::unique_lock lk(m_sendKeyEventMutex); + m_SendKeyQueue.push(keyInfo); + m_sendKeyEventThreadRun = true; + m_sendKeyCV.notify_one(); + LOGINFO("Post send key press event to queue size:%d \n",(int)m_SendKeyQueue.size()); + success.success = true; + return Core::ERROR_NONE; + } + + void HdmiCecSourceImplementation::sendKeyReleaseEvent(const int logicalAddress) + { + LOGINFO(" sendKeyReleaseEvent logicalAddress 0x%x \n",logicalAddress); + if(!(_instance->smConnection)) + { + return; + } + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlReleased()), 100); + + } + + uint32_t HdmiCecSourceImplementation::SendStandbyMessage(HdmiCecSourceSuccess &success) + { + bool ret = false; + + if(true == cecEnableStatus) + { + if (smConnection){ + try + { + smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(Standby())); + ret = true; + } + catch(...) + { + LOGWARN("Exception while sending CEC StandBy Message"); + } + } + else { + LOGWARN("smConnection is NULL"); + } + } + else + LOGWARN("cecEnableStatus=false"); + + if(ret) + { + success.success = true; + return Core::ERROR_NONE; + } + else{ + success.success = false; + return Core::ERROR_GENERAL; + } + } + + void HdmiCecSourceImplementation::InitializePowerManager(PluginHost::IShell *service) + { + LOGINFO("Connect the COM-RPC socket\n"); + _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) + .withIShell(service) + .createInterface(); + registerEventHandlers(); + } + + const void HdmiCecSourceImplementation::InitializeIARM() + { + IARM_Result_t res; + IARM_CHECK( IARM_Bus_RegisterEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, dsHdmiEventHandler) ); + } + + void HdmiCecSourceImplementation::DeinitializeIARM() + { + if (Utils::IARM::isConnected()) + { + IARM_Result_t res; + IARM_CHECK( IARM_Bus_RemoveEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG,dsHdmiEventHandler) ); + } + } + void HdmiCecSourceImplementation::threadHotPlugEventHandler(int data) + { + LOGINFO("entry threadHotPlugEventHandler \r\n"); + if(!HdmiCecSourceImplementation::_instance) + return; + + LOGINFO("Pocessing IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG event status:%d \r\n",data); + HdmiCecSourceImplementation::_instance->onHdmiHotPlug(data); + //Trigger CEC device poll here + pthread_cond_signal(&(_instance->m_condSig)); + + LOGINFO("Exit threadHotPlugEventHandler \r\n"); + } + + void HdmiCecSourceImplementation::dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) + { + if(!HdmiCecSourceImplementation::_instance || !_instance->cecEnableStatus) + { + LOGINFO("Return from dsHdmiEventHandler due HdmiCecSourceImplementation::_instance:%p cecEnableStatus:%d \r\n", HdmiCecSourceImplementation::_instance, _instance->cecEnableStatus); + return; + } + + if (owner && !strcmp(owner, IARM_BUS_DSMGR_NAME) && (IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG == eventId)) + { + IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; + if(eventData) + { + int hdmi_hotplug_event = eventData->data.hdmi_hpd.event; + LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG event data:%d \r\n", hdmi_hotplug_event); + std::thread worker(threadHotPlugEventHandler,hdmi_hotplug_event); + worker.detach(); + } + } + } + + void HdmiCecSourceImplementation::onPowerModeChanged(const PowerState ¤tState, const PowerState &newState) + { + if(!HdmiCecSourceImplementation::_instance) + return; + + LOGINFO("Event IARM_BUS_PWRMGR_EVENT_MODECHANGED: State Changed %d -- > %d\r", + currentState, newState); + if (WPEFramework::Exchange::IPowerManager::POWER_STATE_ON == newState) + { + powerState = 0; + HdmiCecSourceImplementation::_instance->getLogicalAddress(); // get the updated LA after wakeup + } + else + powerState = 1; + } + + void HdmiCecSourceImplementation::onHdmiHotPlug(int connectStatus) + { + if (HDMI_HOT_PLUG_EVENT_CONNECTED == connectStatus) + { + LOGINFO ("onHdmiHotPlug Status : %d ", connectStatus); + getPhysicalAddress(); + getLogicalAddress(); + try + { + std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); + device::VideoOutputPort vPort = device::Host::getInstance().getVideoOutputPort(strVideoPort.c_str()); + if (vPort.isDisplayConnected()) + { + std::vector edidVec; + vPort.getDisplay().getEDIDBytes(edidVec); + //Set LG vendor id if connected with LG TV + if(edidVec.at(8) == 0x1E && edidVec.at(9) == 0x6D) + { + isLGTvConnected = true; + } + LOGINFO("manufacturer byte from edid :%x: %x isLGTvConnected :%d",edidVec.at(8),edidVec.at(9),isLGTvConnected); + } + } + catch(...) + { + LOGWARN("Exception in getting edid info .\r\n"); + } + if(smConnection) + { + try + { + LOGINFO(" sending ReportPhysicalAddress response physical_addr :%s logicalAddress :%x \n",physical_addr.toString().c_str(), logicalAddress.toInt()); + smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(ReportPhysicalAddress(physical_addr,logicalAddress.toInt()))); + + LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n", \ + (isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); + if(isLGTvConnected) + smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(lgVendorId))); + else + smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); + } + catch(...) + { + LOGWARN("Exception while sending Messages onHdmiHotPlug\n"); + } + } + } + return; + } + + bool HdmiCecSourceImplementation::loadSettings() + { + Core::File file; + file = CEC_SETTING_ENABLED_FILE; + + if( file.Open()) + { + JsonObject parameters; + parameters.IElement::FromFile(file); + bool isConfigAdded = false; + + if( parameters.HasLabel(CEC_SETTING_ENABLED)) + { + getBoolParameter(CEC_SETTING_ENABLED, cecSettingEnabled); + LOGINFO("CEC_SETTING_ENABLED present value:%d",cecSettingEnabled); + } + else + { + parameters[CEC_SETTING_ENABLED] = true; + cecSettingEnabled = true; + isConfigAdded = true; + LOGINFO("CEC_SETTING_ENABLED not present set dafult true:\n "); + } + + if( parameters.HasLabel(CEC_SETTING_OTP_ENABLED)) + { + getBoolParameter(CEC_SETTING_OTP_ENABLED, cecOTPSettingEnabled); + LOGINFO("CEC_SETTING_OTP_ENABLED present value :%d",cecOTPSettingEnabled); + } + else + { + parameters[CEC_SETTING_OTP_ENABLED] = true; + cecOTPSettingEnabled = true; + isConfigAdded = true; + LOGINFO("CEC_SETTING_OTP_ENABLED not present set dafult true:\n "); + } + if( parameters.HasLabel(CEC_SETTING_OSD_NAME)) + { + std::string osd_name; + getStringParameter(CEC_SETTING_OSD_NAME, osd_name); + osdName = osd_name.c_str(); + LOGINFO("CEC_SETTING_OTP_ENABLED present osd_name :%s",osdName.toString().c_str()); + } + else + { + parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); + LOGINFO("CEC_SETTING_OSD_NMAE not present set dafult value :%s\n ",osdName.toString().c_str()); + isConfigAdded = true; + } + unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); + if( parameters.HasLabel(CEC_SETTING_VENDOR_ID)) + { + getNumberParameter(CEC_SETTING_VENDOR_ID, vendorId); + LOGINFO("CEC_SETTING_VENDOR_ID present :%x ",vendorId); + } + else + { + LOGINFO("CEC_SETTING_VENDOR_ID not present set dafult value :%x \n ",vendorId); + parameters[CEC_SETTING_VENDOR_ID] = vendorId; + isConfigAdded = true; + } + + appVendorId = {(uint8_t)(vendorId >> 16 & 0xff),(uint8_t)(vendorId >> 8 & 0xff),(uint8_t) (vendorId & 0xff)}; + LOGINFO("appVendorId : %s vendorId :%x \n",appVendorId.toString().c_str(), vendorId ); + + if(isConfigAdded) + { + LOGINFO("isConfigAdded true so update file:\n "); + file.Destroy(); + file.Create(); + parameters.IElement::ToFile(file); + + } + + file.Close(); + } + else + { + LOGINFO("CEC_SETTING_ENABLED_FILE file not present create with default settings "); + file.Open(false); + if (!file.IsOpen()) + file.Create(); + + JsonObject parameters; + unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); + parameters[CEC_SETTING_ENABLED] = true; + parameters[CEC_SETTING_OTP_ENABLED] = true; + parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); + parameters[CEC_SETTING_VENDOR_ID] = vendorId; + + cecSettingEnabled = true; + cecOTPSettingEnabled = true; + parameters.IElement::ToFile(file); + + file.Close(); + + } + + return cecSettingEnabled; + } + + uint32_t HdmiCecSourceImplementation::SetEnabled(const bool &enabled, HdmiCecSourceSuccess &success) + { + LOGINFO("Entered SetEnabled "); + + if (cecSettingEnabled != enabled) + { + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_ENABLED, JsonValue(enabled)); + cecSettingEnabled = enabled; + } + if(true == enabled) + { + CECEnable(); + } + else + { + CECDisable(); + } + success.success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::SetOTPEnabled(const bool &enabled, HdmiCecSourceSuccess &success) + { + if (cecOTPSettingEnabled != enabled) + { + LOGINFO("persist SetOTPEnabled "); + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_OTP_ENABLED, JsonValue(enabled)); + cecOTPSettingEnabled = enabled; + } + success.success = true; + return Core::ERROR_NONE; + } + + void HdmiCecSourceImplementation::CECEnable(void) + { + LOGINFO("Entered CECEnable"); + + if (cecEnableStatus) + { + LOGWARN("CEC Already Enabled"); + return; + } + + if(0 == libcecInitStatus) + { + try + { + LibCCEC::getInstance().init("HdmiCecSource"); + } + catch (const std::exception& e) + { + LOGWARN("CEC exception caught from LibCCEC::getInstance().init()"); + } + } + libcecInitStatus++; + + m_sendKeyEventThreadExit = false; + try { + if (m_sendKeyEventThread.get().joinable()) { + m_sendKeyEventThread.get().join(); + } + m_sendKeyEventThread = Utils::ThreadRAII(std::thread(threadSendKeyEvent)); + } catch(const std::system_error& e) { + LOGERR("exception in creating threadSendKeyEvent %s", e.what()); + } + + + //Acquire CEC Addresses + getPhysicalAddress(); + getLogicalAddress(); + + smConnection = new Connection(logicalAddress.toInt(),false,"ServiceManager::Connection::"); + smConnection->open(); + msgProcessor = new HdmiCecSourceProcessor(*smConnection); + msgFrameListener = new HdmiCecSourceFrameListener(*msgProcessor); + smConnection->addFrameListener(msgFrameListener); + + cecEnableStatus = true; + + if(smConnection) + { + LOGINFO("Command: sending GiveDevicePowerStatus \r\n"); + smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(GiveDevicePowerStatus())); + LOGINFO("Command: sending request active Source isDeviceActiveSource is set to false\r\n"); + smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(RequestActiveSource())); + isDeviceActiveSource = false; + LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n", \ + (isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); + if(isLGTvConnected) + smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(lgVendorId))); + else + smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); + + LOGWARN("Start Update thread %p", smConnection ); + m_updateThreadExit = false; + _instance->m_lockUpdate = PTHREAD_MUTEX_INITIALIZER; + _instance->m_condSigUpdate = PTHREAD_COND_INITIALIZER; + try { + if (m_UpdateThread.get().joinable()) { + m_UpdateThread.get().join(); + } + m_UpdateThread = Utils::ThreadRAII(std::thread(threadUpdateCheck)); + } catch(const std::system_error& e) { + LOGERR("exception in creating threadUpdateCheck %s", e.what()); + } + + LOGWARN("Start Thread %p", smConnection ); + m_pollThreadExit = false; + _instance->m_numberOfDevices = 0; + _instance->m_lock = PTHREAD_MUTEX_INITIALIZER; + _instance->m_condSig = PTHREAD_COND_INITIALIZER; + try { + if (m_pollThread.get().joinable()) { + m_pollThread.get().join(); + } + m_pollThread = Utils::ThreadRAII(std::thread(threadRun)); + } catch(const std::system_error& e) { + LOGERR("exception in creating threadRun %s", e.what()); + } + + } + return; + } + + void HdmiCecSourceImplementation::CECDisable(void) + { + LOGINFO("Entered CECDisable "); + + if(!cecEnableStatus) + { + LOGWARN("CEC Already Disabled "); + return; + } + + { + m_sendKeyEventThreadExit = true; + std::unique_lock lk(m_sendKeyEventMutex); + m_sendKeyEventThreadRun = true; + m_sendKeyCV.notify_one(); + } + try + { + if (m_sendKeyEventThread.get().joinable()) + m_sendKeyEventThread.get().join(); + } + catch(const std::system_error& e) + { + LOGERR("system_error exception in thread join %s", e.what()); + } + catch(const std::exception& e) + { + LOGERR("exception in thread join %s", e.what()); + } + + if (smConnection != NULL) + { + LOGWARN("Stop Thread %p", smConnection ); + + m_updateThreadExit = true; + //Trigger codition to exit poll loop + pthread_mutex_lock(&(_instance->m_lockUpdate)); //Join mutex lock to wait until thread is in its wait condition + pthread_cond_signal(&(_instance->m_condSigUpdate)); + pthread_mutex_unlock(&(_instance->m_lockUpdate)); + if (m_UpdateThread.get().joinable()) {//Join thread to make sure it's deleted before moving on. + m_UpdateThread.get().join(); + } + LOGWARN("Deleted update Thread %p", smConnection ); + + m_pollThreadExit = true; + //Trigger codition to exit poll loop + pthread_mutex_lock(&(_instance->m_lock)); //Join mutex lock to wait until thread is in its wait condition + pthread_cond_signal(&(_instance->m_condSig)); + pthread_mutex_unlock(&(_instance->m_lock)); + if (m_pollThread.get().joinable()) {//Join thread to make sure it's deleted before moving on. + m_pollThread.get().join(); + } + LOGWARN("Deleted Thread %p", smConnection ); + //Clear cec device cache. + removeAllCecDevices(); + + smConnection->close(); + delete smConnection; + delete msgProcessor; + delete msgFrameListener; + msgProcessor = NULL; + msgFrameListener = NULL; + smConnection = NULL; + } + cecEnableStatus = false; + + if(1 == libcecInitStatus) + { + try + { + LibCCEC::getInstance().term(); + } + catch (const std::exception& e) + { + LOGWARN("CEC exception caught from LibCCEC::getInstance().term() "); + } + } + + libcecInitStatus--; + + return; + } + + + void HdmiCecSourceImplementation::getPhysicalAddress() + { + LOGINFO("Entered getPhysicalAddress "); + + uint32_t physAddress = 0x0F0F0F0F; + try { + LibCCEC::getInstance().getPhysicalAddress(&physAddress); + physical_addr = {(uint8_t)((physAddress >> 24) & 0xFF),(uint8_t)((physAddress >> 16) & 0xFF),(uint8_t) ((physAddress >> 8) & 0xFF),(uint8_t)((physAddress) & 0xFF)}; + LOGINFO("getPhysicalAddress: physicalAddress: %s ", physical_addr.toString().c_str()); + } + catch (const std::exception& e) + { + LOGWARN("exception caught from getPhysicalAddress"); + } + return; + } + + void HdmiCecSourceImplementation::getLogicalAddress() + { + LOGINFO("Entered getLogicalAddress "); + + try{ + LogicalAddress addr = LibCCEC::getInstance().getLogicalAddress(DEV_TYPE_TUNER); + + std::string logicalAddrDeviceType = DeviceType(LogicalAddress(addr).getType()).toString().c_str(); + + LOGINFO("logical address obtained is %d , saved logical address is %d ", addr.toInt(), logicalAddress.toInt()); + + if (logicalAddress.toInt() != addr.toInt() || logicalAddressDeviceType != logicalAddrDeviceType) + { + logicalAddress = addr; + logicalAddressDeviceType = logicalAddrDeviceType; + if(smConnection) + smConnection->setSource(logicalAddress); //update initiator LA + } + } + catch (const std::exception& e) + { + LOGWARN("CEC exception caught from getLogicalAddress "); + } + return; + } + + uint32_t HdmiCecSourceImplementation::GetEnabled(bool &enabled, bool &success) + { + LOGINFO("GetEnabled :%d ",cecEnableStatus); + enabled = cecEnableStatus; + success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::GetOTPEnabled(bool &enabled, bool &success) + { + enabled = cecOTPSettingEnabled; + LOGINFO("GetOTPEnabled :%d ",cecOTPSettingEnabled); + success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::GetOSDName(std::string &name, bool &success) + { + name = osdName.toString(); + LOGINFO("GetOSDName :%s ",name.c_str()); + success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::SetOSDName(const std::string &name, HdmiCecSourceSuccess &success) + { + LOGINFO("SetOSDName :%s ",name.c_str()); + osdName = name.c_str(); + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_OSD_NAME, JsonValue(name.c_str())); + success.success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::GetVendorId(std::string &vendorid, bool &success) + { + vendorid = appVendorId.toString(); + LOGINFO("GetVendorId :%s ",vendorid.c_str()); + success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::SetVendorId(const string &vendorid, HdmiCecSourceSuccess &success) + { + LOGINFO("SetVendorId :%s ",vendorid.c_str()); + unsigned int vendorIdInt = 0; + try + { + vendorIdInt = stoi(vendorid,NULL,16); + } + catch (...) + { + LOGWARN("Exception in setVendorIdWrapper set default value\n"); + vendorIdInt = 0x0019FB; + } + appVendorId = {(uint8_t)(vendorIdInt >> 16 & 0xff),(uint8_t)(vendorIdInt >> 8 & 0xff),(uint8_t) (vendorIdInt & 0xff)}; + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_VENDOR_ID, JsonValue(vendorIdInt)); + LOGINFO("SetVendorId :%s ",appVendorId.toString().c_str()); + success.success = true; + return Core::ERROR_NONE; + } + + uint32_t HdmiCecSourceImplementation::PerformOTPAction(HdmiCecSourceSuccess &success) + { + LOGINFO("PerformOTPAction "); + bool ret = false; + + if((true == cecEnableStatus) && (cecOTPSettingEnabled == true)) + { + if (smConnection) { + try + { + LOGINFO("Command: sending ImageViewOn TV \r\n"); + smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(ImageViewOn())); + usleep(10000); + LOGINFO("Command: sending ActiveSource physical_addr :%s \r\n",physical_addr.toString().c_str()); + smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(ActiveSource(physical_addr))); + usleep(10000); + isDeviceActiveSource = true; + LOGINFO("Command: sending GiveDevicePowerStatus \r\n"); + smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(GiveDevicePowerStatus())); + ret = true; + } + catch(...) + { + LOGWARN("Exception while processing PerformOTPAction"); + } + } + else { + LOGWARN("smConnection is NULL"); + } + } + else + LOGWARN("cecEnableStatus=false"); + + if (ret){ + success.success = true; + return Core::ERROR_NONE; + } else { + success.success = false; + return Core::ERROR_GENERAL; + } + } + + uint32_t HdmiCecSourceImplementation::GetDeviceList(uint32_t &numberofdevices, IHdmiCecSourceDeviceListIterator*& deviceList, bool &success) + { //sample servicemanager response: + std::vector localDevices; + Exchange::IHdmiCecSource::HdmiCecSourceDevices actual_hdmicecdevices = {0}; + + //Trigger CEC device poll here + pthread_cond_signal(&(_instance->m_condSig)); + + success = true; + LOGINFO("getDeviceListWrapper m_numberOfDevices :%d \n", HdmiCecSourceImplementation::_instance->m_numberOfDevices); + numberofdevices = HdmiCecSourceImplementation::_instance->m_numberOfDevices; + try + { + int i = 0; + for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { + if (BIT_CHECK(HdmiCecSourceImplementation::_instance->deviceList[i].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) { + actual_hdmicecdevices.logicalAddress = HdmiCecSourceImplementation::_instance->deviceList[i].m_logicalAddress.toInt(); + actual_hdmicecdevices.osdName = HdmiCecSourceImplementation::_instance->deviceList[i].m_osdName.toString(); + actual_hdmicecdevices.vendorID = HdmiCecSourceImplementation::_instance->deviceList[i].m_vendorID.toString(); + localDevices.push_back(actual_hdmicecdevices); + } + } + } + catch (...) + { + LOGERR("Exception in api"); + success = false; + } + deviceList = (Core::Service>::Create(localDevices)); + return Core::ERROR_NONE; + } + + bool HdmiCecSourceImplementation::pingDeviceUpdateList (int idev) + { + bool isConnected = false; + //self ping is not required + if (idev == logicalAddress.toInt()){ + return isConnected; + } + if(!HdmiCecSourceImplementation::_instance) + { + LOGERR("HdmiCecSourceImplementation::_instance not existing"); + return isConnected; + } + if ( !(_instance->smConnection) || logicalAddress.toInt() == LogicalAddress::UNREGISTERED || (false==cecEnableStatus)){ + LOGERR("Exiting from pingDeviceUpdateList _instance->smConnection:%p, logicalAddress:%d, cecEnableStatus=%d", + _instance->smConnection, logicalAddress.toInt(), cecEnableStatus); + return isConnected; + } + + LOGWARN("PING for 0x%x \r\n",idev); + try { + _instance->smConnection->ping(logicalAddress, LogicalAddress(idev), Throw_e()); + } + catch(CECNoAckException &e) + { + if (BIT_CHECK(_instance->deviceList[idev].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) { + LOGINFO("Device disconnected: %d \r\n",idev); + removeDevice (idev); + } else { + LOGINFO("Device is not connected: %d. Ping caught %s\r\n",idev, e.what()); + } + isConnected = false; + return isConnected;; + } + catch(IOException &e) + { + LOGINFO("Device is not reachable: %d. Ping caught %s\r\n",idev, e.what()); + isConnected = false; + return isConnected;; + } + catch(Exception &e) + { + LOGINFO("Ping caught %s \r\n",e.what()); + } + + /* If we get ACK, then the device is present in the network*/ + isConnected = true; + if ( !(BIT_CHECK(_instance->deviceList[idev].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) ) + { + LOGINFO("Device connected: %d \r\n",idev); + addDevice (idev); + } + return isConnected; + } + + void HdmiCecSourceImplementation::removeAllCecDevices() { + int i = 0; + for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { + removeDevice (i); + } + } + + void HdmiCecSourceImplementation::sendUnencryptMsg(unsigned char* msg, int size) + { + LOGINFO("sendMessage "); + + if(true == cecEnableStatus) + { + std::vector buf; + buf.resize(size); + + int itr = 0; + for (itr= 0; itrsendAsync(frame); + } + else + LOGWARN("cecEnableStatus=false"); + return; + } + + void HdmiCecSourceImplementation::requestVendorID(const int newDevlogicalAddress) + { + //Get OSD name and vendor ID only from connected devices. Since devices are identified using polling + //Once OSD name and Vendor ID is updated. We have to poll again in next iteration also. Just to check + //a new device is reconnected with same logical address + unsigned char msg [2]; + unsigned int logicalAddr = logicalAddress.toInt(); + unsigned char sender = (unsigned char)(logicalAddr & 0x0f); + unsigned char receiver = (unsigned char) (newDevlogicalAddress & 0x0f); + + msg [0] = (sender<<4)|receiver; + //Request vendor id + msg [1] = 0x8c; + LOGINFO("Sending msg request vendor id %x %x", msg [0], msg [1]); + _instance->sendUnencryptMsg (msg, sizeof(msg)); + + } + + void HdmiCecSourceImplementation::requestOsdName(const int newDevlogicalAddress) + { + //Get OSD name and vendor ID only from connected devices. Since devices are identified using polling + //Once OSD name and Vendor ID is updated. We have to poll again in next iteration also. Just to check + //a new device is reconnected with same logical address + unsigned char msg [2]; + unsigned int logicalAddr = logicalAddress.toInt(); + unsigned char sender = (unsigned char)(logicalAddr & 0x0f); + unsigned char receiver = (unsigned char) (newDevlogicalAddress & 0x0f); + + msg [0] = (sender<<4)|receiver; + //Request OSD name + msg [1] = 0x46; + LOGINFO("Sending msg request osd name %x %x", msg [0], msg [1]); + _instance->sendUnencryptMsg (msg, sizeof(msg)); + + } + + void HdmiCecSourceImplementation::requestCecDevDetails(const int newDevlogicalAddress) + { + //Get OSD name and vendor ID only from connected devices. Since devices are identified using polling + //Once OSD name and Vendor ID is updated. We have to poll again in next iteration also. Just to check + //a new device is reconnected with same logical address + requestVendorID (newDevlogicalAddress); + requestOsdName (newDevlogicalAddress); + } + + void HdmiCecSourceImplementation::threadRun() + { + if(!HdmiCecSourceImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + LOGINFO("Entering ThreadRun: _instance->m_pollThreadExit %d",_instance->m_pollThreadExit); + int i = 0; + pthread_mutex_lock(&(_instance->m_lock));//pthread_cond_wait should be mutex protected. //pthread_cond_wait will unlock the mutex and perfoms wait for the condition. + while (!_instance->m_pollThreadExit) { + bool isActivateUpdateThread = false; + LOGINFO("Starting cec device polling"); + for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { + bool isConnected = _instance->pingDeviceUpdateList(i); + if (isConnected){ + isActivateUpdateThread = isConnected; + } + + } + if (isActivateUpdateThread){ + //i any of devices is connected activate thread update check + pthread_cond_signal(&(_instance->m_condSigUpdate)); + } + //Wait for mutex signal here to continue the worker thread again. + pthread_cond_wait(&(_instance->m_condSig), &(_instance->m_lock)); + + } + pthread_mutex_unlock(&(_instance->m_lock)); + LOGINFO("%s: Thread exited", __FUNCTION__); + } + void HdmiCecSourceImplementation::threadSendKeyEvent() + { + if(!HdmiCecSourceImplementation::_instance) + return; + + SendKeyInfo keyInfo = {-1,-1}; + + while(!_instance->m_sendKeyEventThreadExit) + { + keyInfo.logicalAddr = -1; + keyInfo.keyCode = -1; + { + // Wait for a message to be added to the queue + std::unique_lock lk(_instance->m_sendKeyEventMutex); + _instance->m_sendKeyCV.wait(lk, []{return (_instance->m_sendKeyEventThreadRun == true);}); + } + + if (_instance->m_sendKeyEventThreadExit == true) + { + LOGINFO(" threadSendKeyEvent Exiting"); + _instance->m_sendKeyEventThreadRun = false; + break; + } + + if (_instance->m_SendKeyQueue.empty()) { + _instance->m_sendKeyEventThreadRun = false; + continue; + } + + keyInfo = _instance->m_SendKeyQueue.front(); + _instance->m_SendKeyQueue.pop(); + + LOGINFO("sendRemoteKeyThread : logical addr:0x%x keyCode: 0x%x queue size :%d \n",keyInfo.logicalAddr,keyInfo.keyCode,(int)_instance->m_SendKeyQueue.size()); + _instance->sendKeyPressEvent(keyInfo.logicalAddr,keyInfo.keyCode); + _instance->sendKeyReleaseEvent(keyInfo.logicalAddr); + } + LOGINFO("%s: Thread exited", __FUNCTION__); + } + void HdmiCecSourceImplementation::threadUpdateCheck() + { + if(!HdmiCecSourceImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + LOGINFO("Entering ThreadUpdate: _instance->m_updateThreadExit %d",_instance->m_updateThreadExit); + int i = 0; + pthread_mutex_lock(&(_instance->m_lockUpdate));//pthread_cond_wait should be mutex protected. //pthread_cond_wait will unlock the mutex and perfoms wait for the condition. + while (!_instance->m_updateThreadExit) { + //Wait for mutex signal here to continue the worker thread again. + pthread_cond_wait(&(_instance->m_condSigUpdate), &(_instance->m_lockUpdate)); + + LOGINFO("Starting cec device update check"); + for(i=0; ((i< LogicalAddress::UNREGISTERED)&&(!_instance->m_updateThreadExit)); i++ ) { + //If details are not updated. update now. + if (BIT_CHECK(HdmiCecSourceImplementation::_instance->deviceList[i].m_deviceInfoStatus, BIT_DEVICE_PRESENT)) + { + int itr = 0; + bool retry = true; + int iCounter = 0; + for (itr = 0; ((itr<5)&&(retry)); itr++){ + + if (!HdmiCecSourceImplementation::_instance->deviceList[i].m_isOSDNameUpdated){ + iCounter = 0; + while ((!_instance->m_updateThreadExit) && (iCounter < (2*10))) { //sleep for 2sec. + usleep (100 * 1000); //sleep for 100 milli sec + iCounter ++; + } + + HdmiCecSourceImplementation::_instance->requestOsdName (i); + retry = true; + } + else { + retry = false; + } + + if (!HdmiCecSourceImplementation::_instance->deviceList[i].m_isVendorIDUpdated){ + iCounter = 0; + while ((!_instance->m_updateThreadExit) && (iCounter < (2*10))) { //sleep for 1sec. + usleep (100 * 1000); //sleep for 100 milli sec + iCounter ++; + } + + HdmiCecSourceImplementation::_instance->requestVendorID (i); + retry = true; + } + } + if (retry){ + LOGINFO("cec device: %d update time out", i); + } + } + } + + } + pthread_mutex_unlock(&(_instance->m_lockUpdate)); + LOGINFO("%s: Thread exited", __FUNCTION__); + } + + + void HdmiCecSourceImplementation::sendDeviceUpdateInfo(const int logicalAddress) + { + LOGINFO("Device info updated notification send: for logical address:%d\r\n", logicalAddress); + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->OnDeviceInfoUpdated(logicalAddress); + index++; + } + } + + void HdmiCecSourceImplementation::sendActiveSourceEvent() + { + LOGWARN(" sendActiveSourceEvent isDeviceActiveSource: %d ",isDeviceActiveSource); + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->OnActiveSourceStatusUpdated(isDeviceActiveSource); + index++; + } + } + + void HdmiCecSourceImplementation::SendStandbyMsgEvent(const int logicalAddress) + { + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->StandbyMessageReceived(logicalAddress); + index++; + } + } + + void HdmiCecSourceImplementation::SendKeyReleaseMsgEvent(const int logicalAddress) + { + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->OnKeyReleaseEvent(logicalAddress); + index++; + } + } + + void HdmiCecSourceImplementation::SendKeyPressMsgEvent(const int logicalAddress,const int keyCode) + { + std::list::const_iterator index(_hdmiCecSourceNotifications.begin()); + while (index != _hdmiCecSourceNotifications.end()) { + (*index)->OnKeyPressEvent(logicalAddress,keyCode); + index++; + } + } + + } // namespace Plugin +} // namespace WPEFramework diff --git a/HdmiCecSource/HdmiCecSourceImplementation.h b/HdmiCecSource/HdmiCecSourceImplementation.h new file mode 100644 index 00000000..7a8bf445 --- /dev/null +++ b/HdmiCecSource/HdmiCecSourceImplementation.h @@ -0,0 +1,344 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2025 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. +**/ + +#pragma once + +#include +#include +#include + +#include "ccec/FrameListener.hpp" +#include "ccec/Connection.hpp" +#include "libIARM.h" +#include "ccec/Assert.hpp" +#include "ccec/Messages.hpp" +#include "ccec/MessageDecoder.hpp" +#include "ccec/MessageProcessor.hpp" +#include + +#undef Assert // this define from Connection.hpp conflicts with WPEFramework + +#include "Module.h" + +#include "UtilsBIT.h" +#include "UtilsThreadRAII.h" + +#include +#include "PowerManagerInterface.h" +#include + +using namespace WPEFramework; +using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; +using ThermalTemperature = WPEFramework::Exchange::IPowerManager::ThermalTemperature; + +namespace WPEFramework { + + namespace Plugin { + class HdmiCecSourceFrameListener : public FrameListener + { + public: + HdmiCecSourceFrameListener(MessageProcessor &processor) : processor(processor) {} + void notify(const CECFrame &in) const; + ~HdmiCecSourceFrameListener() {} + private: + MessageProcessor &processor; + }; + + class HdmiCecSourceProcessor : public MessageProcessor + { + public: + HdmiCecSourceProcessor(Connection &conn) : conn(conn) {} + void process (const ActiveSource &msg, const Header &header); + void process (const InActiveSource &msg, const Header &header); + void process (const ImageViewOn &msg, const Header &header); + void process (const TextViewOn &msg, const Header &header); + void process (const RequestActiveSource &msg, const Header &header); + void process (const Standby &msg, const Header &header); + void process (const GetCECVersion &msg, const Header &header); + void process (const CECVersion &msg, const Header &header); + void process (const SetMenuLanguage &msg, const Header &header); + void process (const GiveOSDName &msg, const Header &header); + void process (const GivePhysicalAddress &msg, const Header &header); + void process (const GiveDeviceVendorID &msg, const Header &header); + void process (const SetOSDString &msg, const Header &header); + void process (const SetOSDName &msg, const Header &header); + void process (const RoutingChange &msg, const Header &header); + void process (const RoutingInformation &msg, const Header &header); + void process (const SetStreamPath &msg, const Header &header); + void process (const GetMenuLanguage &msg, const Header &header); + void process (const ReportPhysicalAddress &msg, const Header &header); + void process (const DeviceVendorID &msg, const Header &header); + void process (const GiveDevicePowerStatus &msg, const Header &header); + void process (const ReportPowerStatus &msg, const Header &header); + void process (const UserControlPressed &msg, const Header &header); + void process (const UserControlReleased &msg, const Header &header); + void process (const FeatureAbort &msg, const Header &header); + void process (const Abort &msg, const Header &header); + void process (const Polling &msg, const Header &header); + private: + Connection conn; + void printHeader(const Header &header) + { + printf("Header : From : %s \n", header.from.toString().c_str()); + printf("Header : to : %s \n", header.to.toString().c_str()); + } + + }; + +#define BIT_DEVICE_PRESENT (0) + + class CECDeviceInfo_2 { + public: + + LogicalAddress m_logicalAddress; + VendorID m_vendorID; + OSDName m_osdName; + // + short m_deviceInfoStatus; + bool m_isOSDNameUpdated; + bool m_isVendorIDUpdated; + std::mutex m_; + std::condition_variable cv_; + std::unique_lock lk; + + CECDeviceInfo_2() + : m_logicalAddress(0),m_vendorID(0,0,0),m_osdName("NA"), m_isOSDNameUpdated (false), m_isVendorIDUpdated (false) + { + BITMASK_CLEAR(m_deviceInfoStatus, 0xFFFF); //Clear all bits + } + + void clear( ) + { + m_logicalAddress = 0; + m_vendorID = VendorID(0,0,0); + m_osdName = "NA"; + BITMASK_CLEAR(m_deviceInfoStatus, 0xFFFF); //Clear all bits + m_isOSDNameUpdated = false; + m_isVendorIDUpdated = false; + } + + bool update ( const VendorID &vendorId) { + bool isVendorIdUpdated = false; + if (!m_isVendorIDUpdated) + isVendorIdUpdated = true; //First time no need to cross check the value. Since actual value can be default value + else + isVendorIdUpdated = (m_vendorID.toString().compare(vendorId.toString())==0)?false:true; + + m_isVendorIDUpdated = true; + m_vendorID = vendorId; + return isVendorIdUpdated; + } + + bool update ( const OSDName &osdName ) { + bool isOSDNameUpdated = false; + if (!m_isOSDNameUpdated) + isOSDNameUpdated = true; //First time no need to cross check the value. Since actual value can be default value + else + isOSDNameUpdated = (m_osdName.toString().compare(osdName.toString())==0)?false:true; + + m_isOSDNameUpdated = true; + m_osdName = osdName; + return isOSDNameUpdated; + } + + }; + // This is a server for a JSONRPC communication channel. + // For a plugin to be capable to handle JSONRPC, inherit from PluginHost::JSONRPC. + // By inheriting from this class, the plugin realizes the interface PluginHost::IDispatcher. + // This realization of this interface implements, by default, the following methods on this plugin + // - exists + // - register + // - unregister + // Any other methood to be handled by this plugin can be added can be added by using the + // templated methods Register on the PluginHost::JSONRPC class. + // As the registration/unregistration of notifications is realized by the class PluginHost::JSONRPC, + // this class exposes a public method called, Notify(), using this methods, all subscribed clients + // will receive a JSONRPC message as a notification, in case this method is called. + class HdmiCecSourceImplementation : public Exchange::IHdmiCecSource { + enum { + VOLUME_UP = 0x41, + VOLUME_DOWN = 0x42, + MUTE = 0x43, + UP = 0x01, + DOWN = 0x02, + LEFT = 0x03, + RIGHT = 0x04, + SELECT = 0x00, + HOME = 0x09, + BACK = 0x0D, + NUMBER_0 = 0x20, + NUMBER_1 = 0x21, + NUMBER_2 = 0x22, + NUMBER_3 = 0x23, + NUMBER_4 = 0x24, + NUMBER_5 = 0x25, + NUMBER_6 = 0x26, + NUMBER_7 = 0x27, + NUMBER_8 = 0x28, + NUMBER_9 = 0x29 + }; + public: + HdmiCecSourceImplementation(); + virtual ~HdmiCecSourceImplementation(); + void onPowerModeChanged(const PowerState ¤tState, const PowerState &newState); + void registerEventHandlers(); + static HdmiCecSourceImplementation* _instance; + CECDeviceInfo_2 deviceList[16]; + pthread_cond_t m_condSig; + pthread_mutex_t m_lock; + pthread_cond_t m_condSigUpdate; + pthread_mutex_t m_lockUpdate; + bool cecEnableStatus; + + void SendStandbyMsgEvent(const int logicalAddress); + void SendKeyPressMsgEvent(const int logicalAddress,const int keyCode); + void SendKeyReleaseMsgEvent(const int logicalAddress); + void sendActiveSourceEvent(); + void addDevice(const int logicalAddress); + void removeDevice(const int logicalAddress); + void sendUnencryptMsg(unsigned char* msg, int size); + void sendDeviceUpdateInfo(const int logicalAddress); + void sendKeyReleaseEvent(const int logicalAddress); + typedef struct sendKeyInfo + { + int logicalAddr; + int keyCode; + }SendKeyInfo; + BEGIN_INTERFACE_MAP(HdmiCecSourceImplementation) + INTERFACE_ENTRY(Exchange::IHdmiCecSource) + END_INTERFACE_MAP + + + private: + class PowerManagerNotification : public Exchange::IPowerManager::INotification { + private: + PowerManagerNotification(const PowerManagerNotification&) = delete; + PowerManagerNotification& operator=(const PowerManagerNotification&) = delete; + + public: + explicit PowerManagerNotification(HdmiCecSourceImplementation& parent) + : _parent(parent) + { + } + ~PowerManagerNotification() override = default; + + public: + void OnPowerModeChanged(const PowerState ¤tState, const PowerState &newState) override + { + _parent.onPowerModeChanged(currentState, newState); + } + void OnPowerModePreChange(const PowerState ¤tState, const PowerState &newState) override {} + void OnDeepSleepTimeout(const int &wakeupTimeout) override {} + void OnNetworkStandbyModeChanged(const bool &enabled) override {} + void OnThermalModeChanged(const ThermalTemperature ¤tThermalLevel, const ThermalTemperature &newThermalLevel, const float ¤tTemperature) override {} + void OnRebootBegin(const string &rebootReasonCustom, const string &rebootReasonOther, const string &rebootRequestor) override {} + + BEGIN_INTERFACE_MAP(PowerManagerNotification) + INTERFACE_ENTRY(Exchange::IPowerManager::INotification) + END_INTERFACE_MAP + + private: + HdmiCecSourceImplementation& _parent; + + }; + // We do not allow this plugin to be copied !! + HdmiCecSourceImplementation(const HdmiCecSourceImplementation&) = delete; + HdmiCecSourceImplementation& operator=(const HdmiCecSourceImplementation&) = delete; + + + + //End methods + std::string logicalAddressDeviceType; + bool cecSettingEnabled; + bool cecOTPSettingEnabled; + Connection *smConnection; + int m_numberOfDevices; + bool m_pollThreadExit; + Utils::ThreadRAII m_pollThread; + bool m_updateThreadExit; + Utils::ThreadRAII m_UpdateThread; + bool m_sendKeyEventThreadExit; + bool m_sendKeyEventThreadRun; + Utils::ThreadRAII m_sendKeyEventThread; + std::mutex m_sendKeyEventMutex; + std::queue m_SendKeyQueue; + std::condition_variable m_sendKeyCV; + + HdmiCecSourceProcessor *msgProcessor; + HdmiCecSourceFrameListener *msgFrameListener; + void InitializePowerManager(PluginHost::IShell *service); + const void InitializeIARM(); + void DeinitializeIARM(); + static void dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); + void onHdmiHotPlug(int connectStatus); + bool loadSettings(); + void persistSettings(bool enableStatus); + void persistOTPSettings(bool enableStatus); + void persistOSDName(const char *name); + void persistVendorId(unsigned int vendorID); + void CECEnable(void); + void CECDisable(void); + void getPhysicalAddress(); + void getLogicalAddress(); + void cecAddressesChanged(int changeStatus); + bool pingDeviceUpdateList (int idev); + void removeAllCecDevices(); + void requestVendorID(const int newDevlogicalAddress); + void requestOsdName(const int newDevlogicalAddress); + void requestCecDevDetails(const int logicalAddress); + static void threadRun(); + static void threadUpdateCheck(); + static void threadSendKeyEvent(); + static void threadHotPlugEventHandler(int data); + static void threadCecDaemonInitHandler(); + static void threadCecStatusUpdateHandler(int data); + uint32_t sendKeyPressEvent(const int logicalAddress, int keyCode); + PowerManagerInterfaceRef _powerManagerPlugin; + Core::Sink _pwrMgrNotification; + bool _registeredEventHandlers; + private: + mutable Core::CriticalSection _adminLock; + std::list _hdmiCecSourceNotifications; + + public: + uint32_t SetEnabled(const bool &enabled, HdmiCecSourceSuccess &success) override; + uint32_t GetEnabled(bool &enabled, bool &success) override; + uint32_t SetOTPEnabled(const bool &enabled, HdmiCecSourceSuccess &success) override; + uint32_t GetOTPEnabled(bool &enabled, bool &success) override; + uint32_t SetOSDName(const string &name, HdmiCecSourceSuccess &success) override; + uint32_t GetOSDName(string &name, bool &success) override; + uint32_t SetVendorId(const string &vendorid, HdmiCecSourceSuccess &success) override; + uint32_t GetVendorId(string &vendorid, bool &success) override; + uint32_t PerformOTPAction(HdmiCecSourceSuccess &success) override; + uint32_t SendStandbyMessage(HdmiCecSourceSuccess &success) override; + uint32_t SendKeyPressEvent(const uint32_t &logicalAddress,const uint32_t &keyCode, HdmiCecSourceSuccess &success) override; + uint32_t GetActiveSourceStatus(bool &isActiveSource, bool &success) override; + uint32_t GetDeviceList(uint32_t &numberofdevices, IHdmiCecSourceDeviceListIterator*& deviceList, bool &success) override; + uint32_t Configure(PluginHost::IShell* service) override; + uint32_t Register(Exchange::IHdmiCecSource::INotification *notification) override; + uint32_t Unregister(Exchange::IHdmiCecSource::INotification *notification) override; + + + }; + } // namespace Plugin +} // namespace WPEFramework + + + + diff --git a/HdmiCecSource/Module.cpp b/HdmiCecSource/Module.cpp index ce759b61..a05f0666 100644 --- a/HdmiCecSource/Module.cpp +++ b/HdmiCecSource/Module.cpp @@ -2,7 +2,7 @@ * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * -* Copyright 2019 RDK Management +* Copyright 2025 RDK Management * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/HdmiCecSource/Module.h b/HdmiCecSource/Module.h index be06c844..3b75197f 100644 --- a/HdmiCecSource/Module.h +++ b/HdmiCecSource/Module.h @@ -2,7 +2,7 @@ * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * -* Copyright 2019 RDK Management +* Copyright 2025 RDK Management * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.