X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fadapter%2FRPi%2FRPiCECAdapterCommunication.cpp;h=9af5357602ae5b32597c383ff0b4845f7d3a66e6;hb=f9c4a2de412487b78c333dc21d9b7e41a5fe69e3;hp=5e1efd493f4a8117018816616870219974d5d3fe;hpb=29104708fa8abe6f55b83da37702b754486918af;p=deb_libcec.git diff --git a/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp b/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp index 5e1efd4..9af5357 100644 --- a/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp +++ b/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp @@ -1,7 +1,7 @@ /* * This file is part of the libCEC(R) library. * - * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved. * libCEC(R) is an original work, containing original code. * * libCEC(R) is a trademark of Pulse-Eight Limited. @@ -58,10 +58,19 @@ void rpi_cec_callback(void *callback_data, uint32_t p0, uint32_t p1, uint32_t p2 static_cast(callback_data)->OnDataReceived(p0, p1, p2, p3, p4); } +// callback for the TV service +void rpi_tv_callback(void *callback_data, uint32_t reason, uint32_t p0, uint32_t p1) +{ + if (callback_data) + static_cast(callback_data)->OnTVServiceCallback(reason, p0, p1); +} + CRPiCECAdapterCommunication::CRPiCECAdapterCommunication(IAdapterCommunicationCallback *callback) : IAdapterCommunication(callback), m_logicalAddress(CECDEVICE_UNKNOWN), - m_bLogicalAddressChanged(false) + m_bLogicalAddressChanged(false), + m_previousLogicalAddress(CECDEVICE_FREEUSE), + m_bLogicalAddressRegistered(false) { m_queue = new CRPiCECAdapterMessageQueue(this); } @@ -69,7 +78,9 @@ CRPiCECAdapterCommunication::CRPiCECAdapterCommunication(IAdapterCommunicationCa CRPiCECAdapterCommunication::~CRPiCECAdapterCommunication(void) { delete(m_queue); + UnregisterLogicalAddress(); Close(); + vc_cec_set_passive(false); } const char *ToString(const VC_CEC_ERROR_T error) @@ -105,11 +116,35 @@ bool CRPiCECAdapterCommunication::IsInitialised(void) return m_bInitialised; } +void CRPiCECAdapterCommunication::OnTVServiceCallback(uint32_t reason, uint32_t UNUSED(p0), uint32_t UNUSED(p1)) +{ + switch(reason) + { + case VC_HDMI_ATTACHED: + { + uint16_t iNewAddress = GetPhysicalAddress(); + m_callback->HandlePhysicalAddressChanged(iNewAddress); + break; + } + case VC_HDMI_UNPLUGGED: + case VC_HDMI_DVI: + case VC_HDMI_HDMI: + case VC_HDMI_HDCP_UNAUTH: + case VC_HDMI_HDCP_AUTH: + case VC_HDMI_HDCP_KEY_DOWNLOAD: + case VC_HDMI_HDCP_SRM_DOWNLOAD: + default: + break; + } +} + void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) { VC_CEC_NOTIFY_T reason = (VC_CEC_NOTIFY_T)CEC_CB_REASON(header); +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "received data: header:%08X p0:%08X p1:%08X p2:%08X p3:%08X reason:%x", header, p0, p1, p2, p3, reason); +#endif switch (reason) { @@ -142,10 +177,14 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u } break; case VC_CEC_BUTTON_PRESSED: + case VC_CEC_REMOTE_PRESSED: { // translate into a cec_command cec_command command; - cec_command::Format(command, (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_OPCODE_USER_CONTROL_PRESSED); + cec_command::Format(command, + (cec_logical_address)CEC_CB_INITIATOR(p0), + (cec_logical_address)CEC_CB_FOLLOWER(p0), + reason == VC_CEC_BUTTON_PRESSED ? CEC_OPCODE_USER_CONTROL_PRESSED : CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN); command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0)); // send to libCEC @@ -153,10 +192,14 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u } break; case VC_CEC_BUTTON_RELEASE: + case VC_CEC_REMOTE_RELEASE: { // translate into a cec_command cec_command command; - cec_command::Format(command, (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_OPCODE_USER_CONTROL_RELEASE); + cec_command::Format(command, + (cec_logical_address)CEC_CB_INITIATOR(p0), + (cec_logical_address)CEC_CB_FOLLOWER(p0), + reason == VC_CEC_BUTTON_PRESSED ? CEC_OPCODE_USER_CONTROL_RELEASE : CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP); command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0)); // send to libCEC @@ -166,23 +209,40 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u case VC_CEC_LOGICAL_ADDR: { CLockObject lock(m_mutex); + m_previousLogicalAddress = m_logicalAddress; if (CEC_CB_RC(header) == VCHIQ_SUCCESS) { m_bLogicalAddressChanged = true; m_logicalAddress = (cec_logical_address)(p0 & 0xF); + m_bLogicalAddressRegistered = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address changed to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress); } else { - m_logicalAddress = CECDEVICE_BROADCAST; + m_logicalAddress = CECDEVICE_FREEUSE; LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to change the logical address, reset to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress); } m_logicalAddressCondition.Signal(); } break; + case VC_CEC_LOGICAL_ADDR_LOST: + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical %s (%x) address lost", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress); + // the logical address was taken by another device + cec_logical_address previousAddress = m_logicalAddress == CECDEVICE_FREEUSE ? m_previousLogicalAddress : m_logicalAddress; + m_logicalAddress = CECDEVICE_UNKNOWN; + + // notify libCEC that we lost our LA when the connection was initialised + bool bNotify(false); + { + CLockObject lock(m_mutex); + bNotify = m_bInitialised && m_bLogicalAddressRegistered; + } + if (bNotify) + m_callback->HandleLogicalAddressLost(previousAddress); + } + break; case VC_CEC_TOPOLOGY: - case VC_CEC_REMOTE_PRESSED: - case VC_CEC_REMOTE_RELEASE: break; default: LIB_CEC->AddLog(CEC_LOG_DEBUG, "ignoring unknown reason %x", reason); @@ -245,26 +305,22 @@ bool CRPiCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN // enable passive mode vc_cec_set_passive(true); - // register the callback - vc_cec_register_callback(((CECSERVICE_CALLBACK_T)rpi_cec_callback), (void*)this); - - // release previous LA - vc_cec_release_logical_address(); - if (!m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged, iTimeoutMs)) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to release the previous LA"); - return false; - } + // register the callbacks + vc_cec_register_callback(rpi_cec_callback, (void*)this); + vc_tv_register_callback(rpi_tv_callback, (void*)this); // register LA "freeuse" - if (RegisterLogicalAddress(CECDEVICE_FREEUSE)) + if (RegisterLogicalAddress(CECDEVICE_FREEUSE, iTimeoutMs)) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vc_cec initialised", __FUNCTION__); CLockObject lock(m_mutex); m_bInitialised = true; } else + { LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec could not be initialised", __FUNCTION__); + return false; + } } return true; @@ -289,17 +345,10 @@ uint16_t CRPiCECAdapterCommunication::GetPhysicalAddress(void) void CRPiCECAdapterCommunication::Close(void) { - { - CLockObject lock(m_mutex); - if (m_bInitialised) - m_bInitialised = false; - else - return; + if (m_bInitialised) { + vc_tv_unregister_callback(rpi_tv_callback); + m_bInitialised = false; } - UnregisterLogicalAddress(); - - // disable passive mode - vc_cec_set_passive(false); if (!g_bHostInited) { @@ -314,22 +363,16 @@ std::string CRPiCECAdapterCommunication::GetError(void) const return strError; } -cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool bIsReply) +cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply) { - // ensure that the source LA is registered - if (!RegisterLogicalAddress(data.initiator)) - { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to register logical address %s (%X)", CCECTypeUtils::ToString(data.initiator), data.initiator); - return (data.initiator == data.destination) ? ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED : ADAPTER_MESSAGE_STATE_ERROR; - } - - if (!data.opcode_set && data.initiator == data.destination) - { - // registration of the logical address would have failed - return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; - } + VC_CEC_ERROR_T vcAnswer; + uint32_t iTimeout = (data.transmit_timeout ? data.transmit_timeout : iLineTimeout*1000); - return m_queue->Write(data, bIsReply) ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; + cec_adapter_message_state rc = m_queue->Write(data, bRetry, iTimeout, bIsReply, vcAnswer); +#ifdef CEC_DEBUGGING + LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: result %s", ToString(vcAnswer)); +#endif + return rc; } uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void) @@ -339,66 +382,58 @@ uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void) cec_logical_address CRPiCECAdapterCommunication::GetLogicalAddress(void) { - { - CLockObject lock(m_mutex); - if (m_logicalAddress != CECDEVICE_UNKNOWN) - return m_logicalAddress; - } + CLockObject lock(m_mutex); - CEC_AllDevices_T address; - return (vc_cec_get_logical_address(&address) == VCHIQ_SUCCESS) ? - (cec_logical_address)address : CECDEVICE_UNKNOWN; + return m_logicalAddress; } bool CRPiCECAdapterCommunication::UnregisterLogicalAddress(void) { CLockObject lock(m_mutex); - if (m_logicalAddress == CECDEVICE_UNKNOWN || - m_logicalAddress == CECDEVICE_BROADCAST) + if (!m_bInitialised) return true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - releasing previous logical address", __FUNCTION__); - m_bLogicalAddressChanged = false; + { + CLockObject lock(m_mutex); + m_bLogicalAddressRegistered = false; + m_bLogicalAddressChanged = false; + } vc_cec_release_logical_address(); return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged); } -bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_address address) +bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_address address, uint32_t iTimeoutMs) { { CLockObject lock(m_mutex); - if (m_logicalAddress == address) + if ((m_logicalAddress == address) && m_bLogicalAddressRegistered) return true; } - if (!UnregisterLogicalAddress()) - return false; - - LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - registering address %x", __FUNCTION__, address); - - CLockObject lock(m_mutex); m_bLogicalAddressChanged = false; - vc_cec_poll_address((CEC_AllDevices_T)address); // register the new LA int iRetval = vc_cec_set_logical_address((CEC_AllDevices_T)address, (CEC_DEVICE_TYPE_T)CCECTypeUtils::GetType(address), CEC_VENDOR_ID_BROADCOM); if (iRetval != VCHIQ_SUCCESS) { LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec_set_logical_address(%X) returned %s (%d)", __FUNCTION__, address, ToString((VC_CEC_ERROR_T)iRetval), iRetval); - return false; + UnregisterLogicalAddress(); } - - return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged); + else if (m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged, iTimeoutMs)) + { + return true; + } + return false; } cec_logical_addresses CRPiCECAdapterCommunication::GetLogicalAddresses(void) { cec_logical_addresses addresses; addresses.Clear(); - cec_logical_address current = GetLogicalAddress(); - if (current != CECDEVICE_UNKNOWN) - addresses.Set(current); + if (m_bLogicalAddressRegistered) + addresses.primary = GetLogicalAddress(); return addresses; }