X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2FCECProcessor.cpp;h=1c92bb1ba8b94b6f0bffcd443c618275b4750ed3;hb=c36dd10675100ca44b11421ed977c7b987a478fb;hp=c7d586e79cce42ab39e061a69b419ebbf786d3f6;hpb=46dfe6c479beeded3b4df937567ff93ec94cc0a8;p=deb_libcec.git diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index c7d586e..1c92bb1 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -47,6 +47,8 @@ using namespace CEC; using namespace std; using namespace PLATFORM; +#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000 + CCECProcessor::CCECProcessor(CLibCEC *controller, libcec_configuration *configuration) : m_bConnectionOpened(false), m_bInitialised(false), @@ -59,7 +61,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, libcec_configuration *configur { CreateBusDevices(); m_configuration.Clear(); - m_configuration.serverVersion = CEC_SERVER_VERSION_1_6_0; + m_configuration.serverVersion = CEC_SERVER_VERSION_1_6_2; SetConfiguration(configuration); if (m_configuration.tvVendor != CEC_VENDOR_UNKNOWN) @@ -77,7 +79,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, con m_iLastTransmission(0) { m_configuration.Clear(); - m_configuration.serverVersion = CEC_SERVER_VERSION_1_6_0; + m_configuration.serverVersion = CEC_SERVER_VERSION_1_6_2; // client version < 1.5.0 m_configuration.clientVersion = (uint32_t)CEC_CLIENT_VERSION_PRE_1_5; @@ -99,29 +101,29 @@ void CCECProcessor::CreateBusDevices(void) switch(iPtr) { case CECDEVICE_AUDIOSYSTEM: - m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr, 0xFFFF); + m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr, CEC_INVALID_PHYSICAL_ADDRESS); break; case CECDEVICE_PLAYBACKDEVICE1: case CECDEVICE_PLAYBACKDEVICE2: case CECDEVICE_PLAYBACKDEVICE3: - m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr, 0xFFFF); + m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr, CEC_INVALID_PHYSICAL_ADDRESS); break; case CECDEVICE_RECORDINGDEVICE1: case CECDEVICE_RECORDINGDEVICE2: case CECDEVICE_RECORDINGDEVICE3: - m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr, 0xFFFF); + m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr, CEC_INVALID_PHYSICAL_ADDRESS); break; case CECDEVICE_TUNER1: case CECDEVICE_TUNER2: case CECDEVICE_TUNER3: case CECDEVICE_TUNER4: - m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr, 0xFFFF); + m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr, CEC_INVALID_PHYSICAL_ADDRESS); break; case CECDEVICE_TV: - m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr, 0); + m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr, CEC_PHYSICAL_ADDRESS_TV); break; default: - m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0xFFFF); + m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, CEC_INVALID_PHYSICAL_ADDRESS); break; } } @@ -182,13 +184,23 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint { CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry); m_communication->Close(); - CEvent::Sleep(1000); + CEvent::Sleep(CEC_DEFAULT_CONNECT_RETRY_WAIT); } if (bReturn) { m_configuration.iFirmwareVersion = m_communication->GetFirmwareVersion(); - CLibCEC::AddLog(CEC_LOG_NOTICE, "connected to the CEC adapter. firmware version = %d, client version = %s", m_configuration.iFirmwareVersion, ToString((cec_client_version)m_configuration.clientVersion)); + m_configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate(); + CStdString strLog; + strLog.Format("connected to the CEC adapter. libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version)m_configuration.serverVersion), ToString((cec_client_version)m_configuration.clientVersion), m_configuration.iFirmwareVersion); + if (m_configuration.iFirmwareBuildDate != CEC_DEFAULT_FIRMWARE_BUILD_DATE) + { + time_t buildTime = (time_t)m_configuration.iFirmwareBuildDate; + strLog.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime))); + strLog = strLog.Left((int)strLog.length() - 1); // strip \n added by asctime + strLog.append(" +0000"); + } + CLibCEC::AddLog(CEC_LOG_NOTICE, strLog); } if (m_configuration.bGetSettingsFromROM == 1) @@ -210,7 +222,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint bool CCECProcessor::IsInitialised(void) { - CLockObject lock(m_mutex); + CLockObject lock(m_threadMutex); return m_bInitialised; } @@ -240,6 +252,21 @@ bool CCECProcessor::Initialise(void) /* make the primary device the active source if the option is set */ if (m_configuration.bActivateSource == 1) m_busDevices[m_configuration.logicalAddresses.primary]->m_bActiveSource = true; + + /* set the default menu language for devices we control */ + cec_menu_language language; + language.device = m_configuration.logicalAddresses.primary; + memcpy(language.language, m_configuration.strDeviceLanguage, 3); + language.language[3] = 0; + + for (uint8_t iPtr = 0; iPtr < 16; iPtr++) + { + if (m_configuration.logicalAddresses[iPtr]) + { + language.device = (cec_logical_address) iPtr; + m_busDevices[iPtr]->SetMenuLanguage(language); + } + } } /* get the vendor id from the TV, so we are using the correct handler */ @@ -265,7 +292,7 @@ bool CCECProcessor::Initialise(void) return bReturn; } -bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */) +bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */) { bool bReturn(false); @@ -377,12 +404,6 @@ bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to) previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN); newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false)); - cec_menu_language lang; - lang.device = previousDevice->GetLogicalAddress(); - for (unsigned int iPtr = 0; iPtr < 4; iPtr++) - lang.language[iPtr] = '?'; - lang.language[3] = 0; - previousDevice->SetMenuLanguage(lang); newDevice->SetMenuState(previousDevice->GetMenuState()); previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED); @@ -390,8 +411,8 @@ bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to) newDevice->SetOSDName(previousDevice->GetOSDName(false)); previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress())); - newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress(false)); - previousDevice->SetPhysicalAddress(0xFFFF); + newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress()); + previousDevice->SetPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS); newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false)); previousDevice->SetPowerStatus(CEC_POWER_STATUS_UNKNOWN); @@ -470,7 +491,7 @@ void *CCECProcessor::Process(void) while (!IsStopped() && m_communication->IsOpen()) { - if (m_inBuffer.Pop(command, 500)) + if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME)) ParseCommand(command); if (IsInitialised()) @@ -506,7 +527,7 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE } m_busDevices[addr]->SetActiveSource(); - if (m_busDevices[addr]->GetPhysicalAddress(false) != 0xFFFF) + if (m_busDevices[addr]->GetPhysicalAddress() != CEC_INVALID_PHYSICAL_ADDRESS) bReturn = m_busDevices[addr]->ActivateSource(); return bReturn; @@ -517,12 +538,16 @@ bool CCECProcessor::SetActiveSource(uint16_t iStreamPath) bool bReturn(false); // suppress polls when searching for a device - CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath, false, true); + CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath); if (device) { device->SetActiveSource(); bReturn = true; } + else + { + CLibCEC::AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath); + } return bReturn; } @@ -604,7 +629,7 @@ bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress(); } - if (iPhysicalAddress < 0xffff) + if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS) { if (iPhysicalAddress == 0) iPhysicalAddress += 0x1000 * iPort; @@ -630,7 +655,7 @@ bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress) { for (unsigned int iPtr = 0; iPtr < 15; iPtr++) { - if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress) + if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress) return true; } return false; @@ -791,19 +816,19 @@ uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */) return status; } -CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */, bool bSuppressPoll /* = false */) const +CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */) { - if (m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress) - return m_busDevices[m_configuration.logicalAddresses.primary]; + CCECBusDevice *device(NULL); - CCECBusDevice *device = NULL; - for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + // invalid PA + if (iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS) + return device; + + // check each device until we found a match + for (unsigned int iPtr = 0; !device && iPtr < 16; iPtr++) { - if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh, bSuppressPoll) == iPhysicalAddress) - { + if (m_busDevices[iPtr]->GetPhysicalAddress(bSuppressUpdate) == iPhysicalAddress) device = m_busDevices[iPtr]; - break; - } } return device; @@ -860,6 +885,13 @@ bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu return false; } +CStdString CCECProcessor::GetDeviceName(void) const +{ + CStdString strName; + strName = m_configuration.strDeviceName; + return strName; +} + uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress) { if (m_busDevices[iAddress]) @@ -881,7 +913,7 @@ cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddres return CEC_POWER_STATUS_UNKNOWN; } -cec_logical_address CCECProcessor::GetActiveSource(void) +cec_logical_address CCECProcessor::GetActiveSource(bool bRequestActiveSource /* = true */) { for (uint8_t iPtr = 0; iPtr <= 11; iPtr++) { @@ -889,12 +921,21 @@ cec_logical_address CCECProcessor::GetActiveSource(void) return (cec_logical_address)iPtr; } + if (bRequestActiveSource && m_configuration.logicalAddresses.primary != CECDEVICE_UNKNOWN) + { + CCECBusDevice *primary = m_busDevices[m_configuration.logicalAddresses.primary]; + if (primary) + primary->RequestActiveSource(); + + return GetActiveSource(false); + } + return CECDEVICE_UNKNOWN; } bool CCECProcessor::IsActiveSource(cec_logical_address iAddress) { - return iAddress > CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST ? + return iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST ? m_busDevices[iAddress]->IsActiveSource() : false; } @@ -922,8 +963,21 @@ bool CCECProcessor::Transmit(const cec_command &data) iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1; } - return m_communication->Write(data, iMaxTries, m_iStandardLineTimeout, m_iRetryLineTimeout) - == ADAPTER_MESSAGE_STATE_SENT_ACKED; + bool bRetry(true); + uint8_t iTries(0); + uint8_t iLineTimeout = m_iStandardLineTimeout; + cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN; + + while (bRetry && ++iTries < iMaxTries) + { + if (m_busDevices[data.initiator]->IsUnsupportedFeature(data.opcode)) + return false; + + adapterState = m_communication->Write(data, bRetry, iLineTimeout); + iLineTimeout = m_iRetryLineTimeout; + } + + return adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED; } void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */) @@ -984,13 +1038,13 @@ bool CCECProcessor::IsPresentDeviceType(cec_device_type type) uint16_t CCECProcessor::GetPhysicalAddress(void) const { if (!m_configuration.logicalAddresses.IsEmpty() && m_busDevices[m_configuration.logicalAddresses.primary]) - return m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress(false); + return m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress(); return false; } bool CCECProcessor::SetAckMask(uint16_t iMask) { - return m_communication->SetAckMask(iMask); + return m_communication ? m_communication->SetAckMask(iMask) : false; } bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */) @@ -1026,7 +1080,10 @@ bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BR for (uint8_t iPtr = 0; iPtr <= 0xF; iPtr++) { if (m_configuration.powerOffDevices[iPtr]) + { + CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - putting '%s' in standby mode", __FUNCTION__, ToString((cec_logical_address)iPtr)); bReturn &= m_busDevices[iPtr]->Standby(); + } } return bReturn; } @@ -1041,8 +1098,11 @@ bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BR bool bReturn(true); for (uint8_t iPtr = 0; iPtr <= 0xF; iPtr++) { - if (m_configuration.powerOffDevices[iPtr]) + if (m_configuration.wakeDevices[iPtr]) + { + CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - powering on '%s'", __FUNCTION__, ToString((cec_logical_address)iPtr)); bReturn &= m_busDevices[iPtr]->PowerOn(); + } } return bReturn; } @@ -1414,6 +1474,10 @@ const char *CCECProcessor::ToString(const cec_client_version version) return "1.5.3"; case CEC_CLIENT_VERSION_1_6_0: return "1.6.0"; + case CEC_CLIENT_VERSION_1_6_1: + return "1.6.1"; + case CEC_CLIENT_VERSION_1_6_2: + return "1.6.2"; default: return "Unknown"; } @@ -1435,69 +1499,28 @@ const char *CCECProcessor::ToString(const cec_server_version version) return "1.5.3"; case CEC_SERVER_VERSION_1_6_0: return "1.6.0"; + case CEC_SERVER_VERSION_1_6_1: + return "1.6.1"; + case CEC_SERVER_VERSION_1_6_2: + return "1.6.2"; default: return "Unknown"; } } -void *CCECBusScan::Process(void) -{ - CCECBusDevice *device(NULL); - uint8_t iCounter(0); - - while (!IsStopped()) - { - if (++iCounter < 10) - { - Sleep(1000); - continue; - } - for (unsigned int iPtr = 0; iPtr <= 11 && !IsStopped(); iPtr++) - { - device = m_processor->m_busDevices[iPtr]; - WaitUntilIdle(); - if (device && device->GetStatus(true) == CEC_DEVICE_STATUS_PRESENT) - { - WaitUntilIdle(); - if (!IsStopped()) - device->GetVendorId(); - - WaitUntilIdle(); - if (!IsStopped()) - device->GetPowerStatus(true); - } - } - } - - return NULL; -} - -void CCECBusScan::WaitUntilIdle(void) -{ - if (IsStopped()) - return; - - int32_t iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission()); - while (iWaitTime > 0) - { - Sleep(iWaitTime); - iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission()); - } -} - bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */) { if (!m_communication && strPort) { bool bReturn(false); IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort); - CTimeout timeout(10000); + CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT); int iConnectTry(0); while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false) { CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry); comm->Close(); - Sleep(500); + Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT); } if (comm->IsOpen()) { @@ -1650,6 +1673,12 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration) m_configuration.bShutdownOnStandby = configuration->bShutdownOnStandby; } + // client version 1.6.2 + if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2) + { + memcpy(m_configuration.strDeviceLanguage, configuration->strDeviceLanguage, 3); + } + // ensure that there is at least 1 device type set if (m_configuration.deviceTypes.IsEmpty()) m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE); @@ -1713,34 +1742,47 @@ bool CCECProcessor::GetCurrentConfiguration(libcec_configuration *configuration) configuration->bShutdownOnStandby = m_configuration.bShutdownOnStandby; } + // client version 1.6.2 + if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2) + { + memcpy(configuration->strDeviceLanguage, m_configuration.strDeviceLanguage, 3); + configuration->iFirmwareBuildDate = m_configuration.iFirmwareBuildDate; + } return true; } bool CCECProcessor::CanPersistConfiguration(void) { - return m_communication->GetFirmwareVersion() >= 2; + return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false; } bool CCECProcessor::PersistConfiguration(libcec_configuration *configuration) { - return m_communication->PersistConfiguration(configuration); + return m_communication ? m_communication->PersistConfiguration(configuration) : false; } void CCECProcessor::RescanActiveDevices(void) { - for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + for (unsigned int iPtr = 0; iPtr < CECDEVICE_BROADCAST; iPtr++) m_busDevices[iPtr]->GetStatus(true); } -bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = 10000 */) +bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */) { - if (!OpenConnection(strPort, 38400, iTimeoutMs, false)) + if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false)) return false; - config->iFirmwareVersion = m_communication->GetFirmwareVersion(); - config->iPhysicalAddress = m_communication->GetPhysicalAddress(); + config->iFirmwareVersion = m_communication->GetFirmwareVersion(); + config->iPhysicalAddress = m_communication->GetPhysicalAddress(); + config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate(); - delete m_communication; - m_communication = NULL; return true; } + +bool CCECProcessor::TransmitPendingActiveSourceCommands(void) +{ + bool bReturn(true); + for (unsigned int iPtr = 0; iPtr < CECDEVICE_BROADCAST; iPtr++) + bReturn &= m_busDevices[iPtr]->TransmitPendingActiveSourceCommands(); + return bReturn; +}