void *CCECProcessor::Process(void) { uint16_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME; m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started"); if (!m_connCheck) m_connCheck = new CCECStandbyProtection(this); m_connCheck->CreateThread(); cec_command command; command.Clear(); CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL); CTimeout tvPresentCheck(TV_PRESENT_CHECK_INTERVAL); // as long as we're not being stopped and the connection is open while (!IsStopped() && m_communication->IsOpen()) { // wait for a new incoming command, and process it if (m_inBuffer.Pop(command, timeout)) ProcessCommand(command); if (CECInitialised() && !IsStopped()) { // check clients for keypress timeouts timeout = m_libcec->CheckKeypressTimeout(); // check if we need to replace handlers ReplaceHandlers(); // check whether we need to activate a source, if it failed before if (activeSourceCheck.TimeLeft() == 0) { if (CECInitialised()) TransmitPendingActiveSourceCommands(); activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL); } // check whether the TV is present and responding if (tvPresentCheck.TimeLeft() == 0) { CECClientPtr primary = GetPrimaryClient(); // only check whether the tv responds to polls when a client is connected and not in monitoring mode if (primary && primary->GetConfiguration()->bMonitorOnly != 1) { if (!m_busDevices->At(CECDEVICE_TV)->IsPresent()) { libcec_parameter param; param.paramType = CEC_PARAMETER_TYPE_STRING; param.paramData = (void*)"TV does not respond to CEC polls"; primary->Alert(CEC_ALERT_TV_POLL_FAILED, param); } } tvPresentCheck.Init(TV_PRESENT_CHECK_INTERVAL); } } else timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME; } return NULL; }
void CCECProcessor::HandlePhysicalAddressChanged(uint16_t iNewAddress) { m_libcec->AddLog(CEC_LOG_NOTICE, "physical address changed to %04x", iNewAddress); CECClientPtr client = GetPrimaryClient(); if (client) client->SetPhysicalAddress(iNewAddress); }
void CCECProcessor::HandlePhysicalAddressChanged(uint16_t iNewAddress) { if (!m_bStallCommunication) { CECClientPtr client = GetPrimaryClient(); if (!!client) client->SetPhysicalAddress(iNewAddress); } }
int CRLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command) { if (!m_processor->IsHandledByLibCEC(command.destination)) return CEC_ABORT_REASON_INVALID_OPERAND; if (command.parameters.size < 4) return CEC_ABORT_REASON_INVALID_OPERAND; // check whether the vendor id matches if (command.parameters[0] != 0x00 || command.parameters[1] != 0x00 || command.parameters[2] != 0x39) return CEC_ABORT_REASON_INVALID_OPERAND; bool bHandled(false); CECClientPtr client = m_processor->GetClient(command.destination); if (client) { switch (command.parameters[3]) { // user control pressed case CEC_OPCODE_USER_CONTROL_PRESSED: if (command.parameters.size == 5) { bHandled = true; switch (command.parameters[4]) { // top menu case RL_KEY_TOP_MENU: client->SetCurrentButton(CEC_USER_CONTROL_CODE_TOP_MENU); break; // dvd menu case RL_KEY_DVD_MENU: client->SetCurrentButton(CEC_USER_CONTROL_CODE_DVD_MENU); break; default: bHandled = false; break; } } break; // user control released case CEC_OPCODE_USER_CONTROL_RELEASE: client->AddKey(); bHandled = true; break; default: break; } } return bHandled ? COMMAND_HANDLED : CCECCommandHandler::HandleDeviceVendorCommandWithId(command); }
bool CCECProcessor::AllocateLogicalAddresses(CECClientPtr client) { libcec_configuration &configuration = *client->GetConfiguration(); // mark as unregistered client->SetRegistered(false); // unregister this client from the old addresses CECDEVICEVEC devices; m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) { // remove client entry CLockObject lock(m_mutex); m_clients.erase((*it)->GetLogicalAddress()); } // find logical addresses for this client if (!client->AllocateLogicalAddresses()) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to find a free logical address for the client"); return false; } // refresh the address if (configuration.bAutodetectAddress) client->AutodetectPhysicalAddress(); // register this client on the new addresses devices.clear(); m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) { // set the physical address of the device at this LA if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress)) (*it)->SetPhysicalAddress(configuration.iPhysicalAddress); // replace a previous client CLockObject lock(m_mutex); m_clients.erase((*it)->GetLogicalAddress()); m_clients.insert(make_pair((*it)->GetLogicalAddress(), client)); } // set the new ackmask SetLogicalAddresses(GetLogicalAddresses()); // resume outgoing communication m_bStallCommunication = false; return true; }
bool CCECProcessor::UnregisterClient(CECClientPtr client) { if (!client) return false; if (client->IsRegistered()) m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering client: %s", client->GetConnectionInfo().c_str()); // notify the client that it will be unregistered client->OnUnregister(); { CLockObject lock(m_mutex); // find all devices that match the LA's of this client CECDEVICEVEC devices; m_busDevices->GetByLogicalAddresses(devices, client->GetConfiguration()->logicalAddresses); for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) { // find the client std::map<cec_logical_address, CECClientPtr>::iterator entry = m_clients.find((*it)->GetLogicalAddress()); // unregister the client if (entry != m_clients.end()) m_clients.erase(entry); // reset the device status (*it)->ResetDeviceStatus(true); } } // set the new ackmask cec_logical_addresses addresses = GetLogicalAddresses(); if (SetLogicalAddresses(addresses)) { // no more clients left, disable controlled mode if (addresses.IsEmpty() && !m_bMonitor) m_communication->SetControlledMode(false); return true; } return false; }
ICECAdapter* CECInitialise(libcec_configuration *configuration) { if (!configuration) return NULL; // create a new libCEC instance CLibCEC *lib = new CLibCEC; // register a new client CECClientPtr client; if (lib && configuration) client = lib->RegisterClient(*configuration); // update the current configuration if (client) client->GetCurrentConfiguration(*configuration); // ensure that the correct server version is set configuration->serverVersion = LIBCEC_VERSION_CURRENT; return static_cast<ICECAdapter*> (lib); }
void CCECBusDevice::MarkAsInactiveSource(bool bClientUnregistered /* = false */) { bool bWasDeactivated(false); { CLockObject lock(m_mutex); if (m_bActiveSource) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress); bWasDeactivated = true; } m_bActiveSource = false; } if (bWasDeactivated) { if (IsHandledByLibCEC()) m_processor->SetActiveSource(false, bClientUnregistered); CECClientPtr client = GetClient(); if (client) client->SourceDeactivated(m_iLogicalAddress); } }
void CCECBusDevice::MarkAsActiveSource(void) { bool bWasActivated(false); // set the power status to powered on SetPowerStatus(CEC_POWER_STATUS_ON); // mark this device as active source { CLockObject lock(m_mutex); if (!m_bActiveSource) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress); bWasActivated = true; } else LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress); m_bActiveSource = true; } CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV); if (tv) tv->OnImageViewOnSent(false); // mark other devices as inactive sources CECDEVICEVEC devices; m_processor->GetDevices()->Get(devices); for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++) if ((*it)->GetLogicalAddress() != m_iLogicalAddress) (*it)->MarkAsInactiveSource(); if (bWasActivated && IsHandledByLibCEC()) m_processor->SetActiveSource(true, false); CECClientPtr client = GetClient(); if (client) client->SourceActivated(m_iLogicalAddress); }
bool CCECProcessor::RegisterClient(CECClientPtr client) { if (!client) return false; libcec_configuration &configuration = *client->GetConfiguration(); if (configuration.clientVersion < LIBCEC_VERSION_TO_UINT(2, 3, 0)) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: client version %s is no longer supported", CCECTypeUtils::VersionToString(configuration.clientVersion).c_str()); return false; } if (configuration.bMonitorOnly == 1) return true; if (!CECInitialised()) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: CEC processor is not initialised"); return false; } // unregister the client first if it's already been marked as registered if (client->IsRegistered()) UnregisterClient(client); // ensure that controlled mode is enabled m_communication->SetControlledMode(true); m_bMonitor = false; // source logical address for requests cec_logical_address sourceAddress(CECDEVICE_UNREGISTERED); if (!m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED)) { if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) sourceAddress = CECDEVICE_FREEUSE; else { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: both unregistered and free use are not supported by the device"); return false; } } // ensure that we know the vendor id of the TV CCECBusDevice *tv = GetTV(); cec_vendor_id tvVendor(tv->GetVendorId(sourceAddress)); // wait until the handler is replaced, to avoid double registrations if (tvVendor != CEC_VENDOR_UNKNOWN && CCECCommandHandler::HasSpecificHandler(tvVendor)) { while (!tv->ReplaceHandler(false)) CEvent::Sleep(5); } // get the configuration from the client m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", CCECTypeUtils::VersionToString(configuration.clientVersion).c_str()); // get the current ackmask, so we can restore it if polling fails cec_logical_addresses previousMask = GetLogicalAddresses(); // mark as uninitialised client->SetInitialised(false); // find logical addresses for this client if (!AllocateLogicalAddresses(client)) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types"); SetLogicalAddresses(previousMask); return false; } // get the settings from the rom if (configuration.bGetSettingsFromROM == 1) { libcec_configuration config; config.Clear(); m_communication->GetConfiguration(config); CLockObject lock(m_mutex); if (!config.deviceTypes.IsEmpty()) configuration.deviceTypes = config.deviceTypes; if (CLibCEC::IsValidPhysicalAddress(config.iPhysicalAddress)) configuration.iPhysicalAddress = config.iPhysicalAddress; snprintf(configuration.strDeviceName, 13, "%s", config.strDeviceName); } // set the firmware version and build date configuration.serverVersion = LIBCEC_VERSION_CURRENT; configuration.iFirmwareVersion = m_communication->GetFirmwareVersion(); configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate(); configuration.adapterType = m_communication->GetAdapterType(); // mark the client as registered client->SetRegistered(true); sourceAddress = client->GetPrimaryLogicalAdddress(); // initialise the client bool bReturn = client->OnRegister(); // log the new registration std::string strLog; strLog = StringUtils::Format("%s: %s", bReturn ? "CEC client registered" : "failed to register the CEC client", client->GetConnectionInfo().c_str()); m_libcec->AddLog(bReturn ? CEC_LOG_NOTICE : CEC_LOG_ERROR, strLog.c_str()); // display a warning if the firmware can be upgraded if (bReturn && !IsRunningLatestFirmware()) { const char *strUpgradeMessage = "The firmware of this adapter can be upgraded. Please visit http://blog.pulse-eight.com/ for more information."; m_libcec->AddLog(CEC_LOG_WARNING, strUpgradeMessage); libcec_parameter param; param.paramData = (void*)strUpgradeMessage; param.paramType = CEC_PARAMETER_TYPE_STRING; client->Alert(CEC_ALERT_SERVICE_DEVICE, param); } // ensure that the command handler for the TV is initialised if (bReturn) { CCECCommandHandler *handler = GetTV()->GetHandler(); if (handler) handler->InitHandler(); GetTV()->MarkHandlerReady(); } // report our OSD name to the TV, since some TVs don't request it client->GetPrimaryDevice()->TransmitOSDName(CECDEVICE_TV, false); // request the power status of the TV tv->RequestPowerStatus(sourceAddress, true, true); return bReturn; }