Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
void CCECProcessor::HandlePhysicalAddressChanged(uint16_t iNewAddress)
{
  if (!m_bStallCommunication) {
    CECClientPtr client = GetPrimaryClient();
    if (!!client)
      client->SetPhysicalAddress(iNewAddress);
  }
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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);
}
Ejemplo n.º 8
0
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);
  }
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
0
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;
}