X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fadapter%2FUSBCECAdapterCommunication.cpp;h=e130514ee807df6bbac77affde5dc40d068b52a9;hb=c9c282a414c59bc86989920ac3d9692e5a36a175;hp=95c46946c70fd5638c4add7688e63e83929ec717;hpb=120d4ca86e6f7e187e2d4a97e8fe9b8e31c85c8c;p=deb_libcec.git diff --git a/src/lib/adapter/USBCECAdapterCommunication.cpp b/src/lib/adapter/USBCECAdapterCommunication.cpp index 95c4694..e130514 100644 --- a/src/lib/adapter/USBCECAdapterCommunication.cpp +++ b/src/lib/adapter/USBCECAdapterCommunication.cpp @@ -40,6 +40,8 @@ using namespace std; using namespace CEC; using namespace PLATFORM; +#define CEC_ADAPTER_PING_TIMEOUT 15000 + void *CUSBCECAdapterProcessor::Process(void) { cec_command command; @@ -67,7 +69,8 @@ CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(CCECProcessor *processo m_lastInitiator(CECDEVICE_UNKNOWN), m_bNextIsEscaped(false), m_bGotStart(false), - m_messageProcessor(NULL) + m_messageProcessor(NULL), + m_bInitialised(false) { m_port = new PLATFORM::CSerialPort(strPort, iBaudRate); } @@ -89,20 +92,26 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */ while (iNow < iTarget && (bPinged = PingAdapter()) == false) { CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry); - Sleep(500); + CEvent::Sleep(500); iNow = GetTimeMs(); } /* try to read the firmware version */ m_iFirmwareVersion = CEC_FW_VERSION_UNKNOWN; unsigned iFwVersionTry(0); - while (bPinged && iNow < iTarget && (m_iFirmwareVersion = GetFirmwareVersion()) == CEC_FW_VERSION_UNKNOWN) + while (bPinged && iNow < iTarget && (m_iFirmwareVersion = GetFirmwareVersion()) == CEC_FW_VERSION_UNKNOWN && iFwVersionTry < 3) { - CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond with a correct firmware version (try %d)", ++iFwVersionTry); - Sleep(500); + CLibCEC::AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", ++iFwVersionTry); + CEvent::Sleep(500); iNow = GetTimeMs(); } + if (m_iFirmwareVersion == CEC_FW_VERSION_UNKNOWN) + { + CLibCEC::AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1"); + m_iFirmwareVersion = 1; + } + if (m_iFirmwareVersion >= 2) { /* try to set controlled mode */ @@ -111,7 +120,7 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */ while (iNow < iTarget && (bControlled = SetControlledMode(true)) == false) { CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry); - Sleep(500); + CEvent::Sleep(500); iNow = GetTimeMs(); } bReturn = bControlled; @@ -119,10 +128,15 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */ else bReturn = true; + { + CLockObject lock(m_mutex); + m_bInitialised = bReturn; + } + return bReturn; } -bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */) +bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */, bool bSkipChecks /* = false */) { uint64_t iNow = GetTimeMs(); uint64_t iTimeout = iNow + iTimeoutMs; @@ -163,29 +177,35 @@ bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32 CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting"); - //clear any input bytes - uint8_t buff[1024]; - while (m_port->Read(buff, 1024, 100) > 0) + if (!bSkipChecks) { - CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it"); - Sleep(250); + //clear any input bytes + uint8_t buff[1024]; + while (m_port->Read(buff, 1024, 100) > 0) + { + CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it"); + Sleep(250); + } } } - if (CreateThread()) + if (!bSkipChecks && !CheckAdapter()) + { + CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks"); + return false; + } + else { - if (!CheckAdapter()) + if (CreateThread()) { - StopThread(); - CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks"); + CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started"); + return true; } else { - CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started"); - return true; + CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread"); } } - CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread"); return false; } @@ -203,18 +223,26 @@ void *CUSBCECAdapterCommunication::Process(void) cec_command command; command.Clear(); bool bCommandReceived(false); + CTimeout pingTimeout(CEC_ADAPTER_PING_TIMEOUT); while (!IsStopped()) { { CLockObject lock(m_mutex); ReadFromDevice(50); - bCommandReceived = m_callback && Read(command, 0); + bCommandReceived = m_callback && Read(command, 0) && m_bInitialised; } /* push the next command to the callback method if there is one */ if (!IsStopped() && bCommandReceived) m_messageProcessor->AddCommand(command); + /* ping the adapter every 15 seconds */ + if (pingTimeout.TimeLeft() == 0) + { + pingTimeout.Init(CEC_ADAPTER_PING_TIMEOUT); + PingAdapter(); + } + if (!IsStopped()) { Sleep(5); @@ -234,6 +262,9 @@ void *CUSBCECAdapterCommunication::Process(void) /* set the ackmask to 0 before closing the connection */ SetAckMaskInternal(0, true); + if (m_iFirmwareVersion >= 2) + SetControlledMode(false); + if (m_port) { delete m_port; @@ -364,11 +395,9 @@ bool CUSBCECAdapterCommunication::StartBootloader(void) bool CUSBCECAdapterCommunication::PingAdapter(void) { - bool bReturn(false); - if (!IsRunning()) - return bReturn; - + CLockObject lock(m_mutex); CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping"); + CCECAdapterMessage *output = new CCECAdapterMessage; output->PushBack(MSGSTART); @@ -376,11 +405,16 @@ bool CUSBCECAdapterCommunication::PingAdapter(void) output->PushBack(MSGEND); output->isTransmission = false; - if ((bReturn = Write(output)) == false) - CLibCEC::AddLog(CEC_LOG_ERROR, "could not ping the adapter"); + SendMessageToAdapter(output); + bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; delete output; + if (!bWriteOk) + { + CLibCEC::AddLog(CEC_LOG_ERROR, "could not ping the adapter"); + return false; + } - return bReturn; + return true; } bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg) @@ -425,7 +459,6 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg) m_currentframe.PushBack(msg[1]); m_currentframe.eom = msg.IsEOM(); } - bEom = msg.IsEOM(); } break; default: @@ -433,14 +466,12 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg) } CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString()); - return bEom; + return msg.IsEOM(); } uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void) { uint16_t iReturn(m_iFirmwareVersion); - if (!IsRunning()) - return iReturn; if (iReturn == CEC_FW_VERSION_UNKNOWN) { @@ -538,10 +569,27 @@ bool CUSBCECAdapterCommunication::SetAckMaskInternal(uint16_t iMask, bool bWrite return bReturn; } +bool CUSBCECAdapterCommunication::PersistConfiguration(libcec_configuration *configuration) +{ + if (m_iFirmwareVersion < 2) + return false; + + bool bReturn(true); + bReturn &= SetAutoEnabled(true); + bReturn &= SetDeviceType(CLibCEC::GetType(configuration->logicalAddresses.primary)); + bReturn &= SetDefaultLogicalAddress(configuration->logicalAddresses.primary); + bReturn &= SetLogicalAddressMask(configuration->logicalAddresses.AckMask()); + bReturn &= SetPhysicalAddress(configuration->iPhysicalAddress); + bReturn &= SetCECVersion(CEC_VERSION_1_3A); + bReturn &= SetOSDName(configuration->strDeviceName); + if (bReturn) + bReturn = WriteEEPROM(); + return bReturn; +} bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled) { - bool bReturn(false); + CLockObject lock(m_mutex); CLibCEC::AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off"); CCECAdapterMessage *output = new CCECAdapterMessage; @@ -552,11 +600,98 @@ bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled) output->PushBack(MSGEND); output->isTransmission = false; - if ((bReturn = Write(output)) == false) - CLibCEC::AddLog(CEC_LOG_ERROR, "could not set controlled mode"); + SendMessageToAdapter(output); + bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; delete output; + if (!bWriteOk) + { + CLibCEC::AddLog(CEC_LOG_ERROR, "could not set controlled mode"); + return false; + } - return bReturn; + return true; +} + +bool CUSBCECAdapterCommunication::SetAutoEnabled(bool enabled) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off"); + + CCECAdapterMessage params; + params.PushEscaped(enabled ? 1 : 0); + return SendCommand(MSGCODE_SET_AUTO_ENABLED, params); +} + +bool CUSBCECAdapterCommunication::SetDeviceType(cec_device_type type) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the device type to %1X", (uint8_t)type); + + CCECAdapterMessage params; + params.PushEscaped((uint8_t)type); + return SendCommand(MSGCODE_SET_DEVICE_TYPE, params); +} + +bool CUSBCECAdapterCommunication::SetDefaultLogicalAddress(cec_logical_address address) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the default logical address to %1X", address); + + CCECAdapterMessage params; + params.PushEscaped((uint8_t)address); + return SendCommand(MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, params); +} + +bool CUSBCECAdapterCommunication::SetLogicalAddressMask(uint16_t iMask) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X", iMask); + + CCECAdapterMessage params; + params.PushEscaped(iMask >> 8); + params.PushEscaped((uint8_t)iMask); + return SendCommand(MSGCODE_SET_LOGICAL_ADDRESS_MASK, params); +} + +bool CUSBCECAdapterCommunication::SetPhysicalAddress(uint16_t iPhysicalAddress) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the physical address to %2X", iPhysicalAddress); + + CCECAdapterMessage params; + params.PushEscaped(iPhysicalAddress >> 8); + params.PushEscaped((uint8_t)iPhysicalAddress); + return SendCommand(MSGCODE_SET_PHYSICAL_ADDRESS, params); +} + +bool CUSBCECAdapterCommunication::SetCECVersion(cec_version version) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s", CLibCEC::GetInstance()->ToString(version)); + + CCECAdapterMessage params; + params.PushEscaped((uint8_t)version); + return SendCommand(MSGCODE_SET_HDMI_VERSION, params); +} + +bool CUSBCECAdapterCommunication::SetOSDName(const char *strOSDName) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s", strOSDName); + + CCECAdapterMessage params; + for (size_t iPtr = 0; iPtr < strlen(strOSDName); iPtr++) + params.PushEscaped(strOSDName[iPtr]); + return SendCommand(MSGCODE_SET_OSD_NAME, params); +} + +bool CUSBCECAdapterCommunication::WriteEEPROM(void) +{ + CLockObject lock(m_mutex); + CLibCEC::AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM"); + + CCECAdapterMessage params; + return SendCommand(MSGCODE_WRITE_EEPROM, params); } bool CUSBCECAdapterCommunication::IsOpen(void) @@ -568,7 +703,7 @@ bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message) { bool bError(false); bool bTransmitSucceeded(false); - uint8_t iPacketsLeft(message.Size() / 4); + uint8_t iPacketsLeft(message.isTransmission ? message.Size() / 4 : 1); int64_t iNow = GetTimeMs(); int64_t iTargetTime = iNow + (message.transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : message.transmit_timeout); @@ -610,11 +745,11 @@ bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message) switch(msg.Message()) { case MSGCODE_COMMAND_ACCEPTED: - CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString()); if (iPacketsLeft > 0) iPacketsLeft--; if (!message.isTransmission && iPacketsLeft == 0) bTransmitSucceeded = true; + CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - waiting for %d more", msg.ToString().c_str(), iPacketsLeft); break; case MSGCODE_TRANSMIT_SUCCEEDED: CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString()); @@ -754,3 +889,28 @@ CStdString CUSBCECAdapterCommunication::GetPortName(void) strName = m_port->GetName(); return strName; } + +bool CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage ¶ms) +{ + CLockObject lock(m_mutex); + + CCECAdapterMessage *output = new CCECAdapterMessage; + + output->PushBack(MSGSTART); + output->PushEscaped(msgCode); + output->Append(params); + output->PushBack(MSGEND); + output->isTransmission = false; + + SendMessageToAdapter(output); + bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; + if (!bWriteOk) + { + CLibCEC::AddLog(CEC_LOG_ERROR, "'%s' failed", output->ToString().c_str()); + delete output; + return false; + } + + delete output; + return true; +}