예제 #1
0
bool CCECProcessor::PowerOnDevice(const cec_logical_address initiator, cec_logical_address address)
{
  CCECBusDevice *device = m_busDevices->At(address);
  return device ? device->PowerOn(initiator) : false;
}
예제 #2
0
void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
{
  CCECBusDevice *device = m_busDevices->At(destination);
  if (device)
    device->HandlePollFrom(initiator);
}
예제 #3
0
bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
{
  cec_command transmitData(data);
  uint8_t iMaxTries(0);
  bool bRetry(true);
  uint8_t iTries(0);

  // get the current timeout setting
  uint8_t iLineTimeout(GetStandardLineTimeout());

  // reset the state of this message to 'unknown'
  cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;

  if (data.initiator == CECDEVICE_UNKNOWN && data.destination == CECDEVICE_UNKNOWN)
    return false;

  CLockObject lock(m_mutex);
  if (!m_communication)
    return false;

  if (!m_communication->SupportsSourceLogicalAddress(transmitData.initiator))
  {
    if (transmitData.initiator == CECDEVICE_UNREGISTERED && m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE))
    {
      m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter. using '%s' instead", ToString(transmitData.initiator), ToString(CECDEVICE_FREEUSE));
      transmitData.initiator = CECDEVICE_FREEUSE;
    }
    else
    {
      m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter", ToString(transmitData.initiator));
      return false;
    }
  }

  LogOutput(transmitData);

  // find the initiator device
  CCECBusDevice *initiator = m_busDevices->At(transmitData.initiator);
  if (!initiator)
  {
    m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator");
    return false;
  }

  // find the destination device, if it's not the broadcast address
  if (transmitData.destination != CECDEVICE_BROADCAST)
  {
    // check if the device is marked as handled by libCEC
    CCECBusDevice *destination = m_busDevices->At(transmitData.destination);
    if (destination && destination->IsHandledByLibCEC())
    {
      // and reject the command if it's trying to send data to a device that is handled by libCEC
      m_libcec->AddLog(CEC_LOG_WARNING, "not sending data to myself!");
      return false;
    }
  }

  // wait until we finished allocating a new LA if it got lost
  lock.Unlock();
  while (m_bStallCommunication) Sleep(5);
  lock.Lock();

  m_iLastTransmission = GetTimeMs();
  // set the number of tries
  iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
  initiator->MarkHandlerReady();

  // and try to send the command
  while (bRetry && ++iTries < iMaxTries)
  {
    if (initiator->IsUnsupportedFeature(transmitData.opcode))
      return false;

    adapterState = !IsStopped() && m_communication && m_communication->IsOpen() ?
        m_communication->Write(transmitData, bRetry, iLineTimeout, bIsReply) :
        ADAPTER_MESSAGE_STATE_ERROR;
    iLineTimeout = m_iRetryLineTimeout;
  }

  return bIsReply ?
      adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED || adapterState == ADAPTER_MESSAGE_STATE_SENT || adapterState == ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT :
      adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
}
예제 #4
0
bool CCECProcessor::IsPresentDevice(cec_logical_address address)
{
  CCECBusDevice *device = m_busDevices->At(address);
  return device && device->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
}
예제 #5
0
bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
{
  CCECBusDevice *device = m_busDevices->At(iAddress);
  return device && device->IsActiveSource();
}
예제 #6
0
bool CCECProcessor::IsHandledByLibCEC(const cec_logical_address address) const
{
  CCECBusDevice *device = GetDevice(address);
  return device && device->IsHandledByLibCEC();
}
예제 #7
0
bool CCECProcessor::RegisterClient(CECClientPtr client)
{
  if (!client)
    return false;

  libcec_configuration &configuration = *client->GetConfiguration();
  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->GetPrimaryLogicalAddress();

  // 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;
}
예제 #8
0
bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
{
  CCECBusDevice *device = m_busDevices->At(initiator);
  return !device || !device->HandleReceiveFailed();
}
예제 #9
0
bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
{
  if (m_iLogicalAddress == CECDEVICE_BROADCAST)
    return false;

  bool bInitHandler(false);
  {
    CLockObject lock(m_mutex);
    CLockObject handlerLock(m_handlerMutex);
    if (m_iHandlerUseCount > 0)
      return false;

    MarkBusy();

    if (m_vendor != m_handler->GetVendorId())
    {
      if (CCECCommandHandler::HasSpecificHandler(m_vendor))
      {
        LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());

        int32_t iTransmitTimeout     = m_handler->m_iTransmitTimeout;
        int32_t iTransmitWait        = m_handler->m_iTransmitWait;
        int8_t  iTransmitRetries     = m_handler->m_iTransmitRetries;
        int64_t iActiveSourcePending = m_handler->m_iActiveSourcePending;

        SAFE_DELETE(m_handler);

        switch (m_vendor)
        {
        case CEC_VENDOR_SAMSUNG:
          m_handler = new CANCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        case CEC_VENDOR_LG:
          m_handler = new CSLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        case CEC_VENDOR_PANASONIC:
          m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        case CEC_VENDOR_PHILIPS:
          m_handler = new CPHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        case CEC_VENDOR_TOSHIBA:
        case CEC_VENDOR_TOSHIBA2:
          m_handler = new CRLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        case CEC_VENDOR_ONKYO:
          m_handler = new CRHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        case CEC_VENDOR_SHARP:
        case CEC_VENDOR_SHARP2:
          m_handler = new CAQCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        default:
          m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
          break;
        }

        /** override the vendor ID set in the handler, as a single vendor may have multiple IDs */
        m_handler->SetVendorId(m_vendor);
        bInitHandler = true;
      }
    }
  }

  if (bInitHandler)
  {
    CCECBusDevice *primary = GetProcessor()->GetPrimaryDevice();
    if (primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
    {
      m_handler->InitHandler();

      if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
        m_handler->ActivateSource();
    }
  }

  MarkReady();

  return true;
}