void CCECAdapterMessageQueue::MessageReceived(const CCECAdapterMessage &msg)
{
  bool bHandled(false);
  CLockObject lock(m_mutex);
  /* send the received message to each entry in the queue until it is handled */
  for (std::map<uint64_t, CCECAdapterMessageQueueEntry *>::iterator it = m_messages.begin(); !bHandled && it != m_messages.end(); it++)
    bHandled = it->second->MessageReceived(msg);

  if (!bHandled)
  {
    /* the message wasn't handled */
    bool bIsError(m_com->HandlePoll(msg));
#ifdef CEC_DEBUGGING
    m_com->m_callback->GetLib()->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString().c_str());
#else
    if (bIsError)
      m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, msg.ToString().c_str());
#endif

    /* push this message to the current frame */
    if (!bIsError && msg.PushToCecCommand(m_currentCECFrame))
    {
      /* and push the current frame back over the callback method when a full command was received */
      if (m_com->IsInitialised())
        m_com->m_callback->OnCommandReceived(m_currentCECFrame);

      /* clear the current frame */
      m_currentCECFrame.Clear();
    }
  }
}
bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage &msg)
{
  bool bIsError(msg.IsError());
  cec_adapter_messagecode messageCode(msg.Message());
  CLockObject lock(m_mutex);

  if (messageCode == MSGCODE_FRAME_START && msg.IsACK())
  {
    m_lastPollDestination = msg.Destination();
    if (msg.Destination() < CECDEVICE_BROADCAST)
    {
      if (!m_bWaitingForAck[msg.Destination()] && !msg.IsEOM())
      {
        if (m_callback)
          m_callback->HandlePoll(msg.Initiator(), msg.Destination());
      }
      else
        m_bWaitingForAck[msg.Destination()] = false;
    }
  }
  else if (messageCode == MSGCODE_RECEIVE_FAILED)
  {
    /* hack to suppress warnings when an LG is polling */
    if (m_lastPollDestination != CECDEVICE_UNKNOWN)
      bIsError = m_callback->HandleReceiveFailed(m_lastPollDestination);
  }

  return bIsError;
}
bool CCECAdapterMessageQueueEntry::IsResponse(const CCECAdapterMessage &msg)
{
  cec_adapter_messagecode thisMsgCode = m_message->Message();
  cec_adapter_messagecode msgCode = msg.Message();
  cec_adapter_messagecode msgResponse = msg.ResponseTo();

  // msgcode matches, always a response
  if (msgCode == MessageCode())
    return true;

  if (!ProvidesExtendedResponse())
    return IsResponseOld(msg);

  // response without a msgcode
  if (msgResponse == MSGCODE_NOTHING)
  {
    m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, "no response code received");
    return true;
  }

  // commands that only repond with accepted/rejected
  if (thisMsgCode == MSGCODE_PING ||
      thisMsgCode == MSGCODE_SET_ACK_MASK ||
      thisMsgCode == MSGCODE_SET_CONTROLLED ||
      thisMsgCode == MSGCODE_SET_AUTO_ENABLED ||
      thisMsgCode == MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS ||
      thisMsgCode == MSGCODE_SET_LOGICAL_ADDRESS_MASK ||
      thisMsgCode == MSGCODE_SET_PHYSICAL_ADDRESS ||
      thisMsgCode == MSGCODE_SET_DEVICE_TYPE ||
      thisMsgCode == MSGCODE_SET_HDMI_VERSION ||
      thisMsgCode == MSGCODE_SET_OSD_NAME ||
      thisMsgCode == MSGCODE_WRITE_EEPROM ||
      thisMsgCode == MSGCODE_TRANSMIT_IDLETIME)
    return thisMsgCode == msgResponse;

  if (!m_message->IsTranmission())
  {
    m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, "FIXME! not a transmission");
    return false;
  }

  return ((msgCode == MSGCODE_COMMAND_ACCEPTED || msgCode == MSGCODE_COMMAND_REJECTED) &&
      (msgResponse == MSGCODE_TRANSMIT_ACK_POLARITY || msgResponse == MSGCODE_TRANSMIT || msgResponse == MSGCODE_TRANSMIT_EOM)) ||
      msgCode == MSGCODE_TIMEOUT_ERROR ||
      msgCode == MSGCODE_HIGH_ERROR ||
      msgCode == MSGCODE_LOW_ERROR ||
      msgCode == MSGCODE_RECEIVE_FAILED ||
      msgCode == MSGCODE_TRANSMIT_FAILED_LINE ||
      msgCode == MSGCODE_TRANSMIT_FAILED_ACK ||
      msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
      msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
      msgCode == MSGCODE_TRANSMIT_SUCCEEDED;
}
示例#4
0
bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
{
  CLockObject lock(&m_mutex);

  msg.clear();
  uint64_t iNow = GetTimeMs();
  uint64_t iTarget = iNow + iTimeout;
  bool bGotFullMessage(false);
  bool bNextIsEscaped(false);
  bool bGotStart(false);

  while(!bGotFullMessage && iNow < iTarget)
  {
    uint8_t buf = 0;
    if (!m_inBuffer.Pop(buf))
    {
      if (!m_rcvCondition.Wait(&m_mutex, (uint32_t) (iTarget - iNow)))
        return false;
    }

    if (!bGotStart)
    {
      if (buf == MSGSTART)
        bGotStart = true;
      continue;
    }
    else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove
    {
      m_controller->AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
      msg.clear();
      bGotStart = true;
    }

    if (buf == MSGEND)
    {
      bGotFullMessage = true;
    }
    else if (bNextIsEscaped)
    {
      msg.push_back(buf + (uint8_t)ESCOFFSET);
      bNextIsEscaped = false;
    }
    else if (buf == MSGESC)
      bNextIsEscaped = true;
    else
      msg.push_back(buf);
  }

  if (bGotFullMessage)
    msg.state = ADAPTER_MESSAGE_STATE_RECEIVED;

  return bGotFullMessage;
}
bool CCECAdapterMessageQueueEntry::IsResponse(const CCECAdapterMessage &msg)
{
  if (m_message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED)
    return false;

  cec_adapter_messagecode thisMsgCode = m_message->Message();
  cec_adapter_messagecode msgCode = msg.Message();
  cec_adapter_messagecode msgResponse = msg.ResponseTo();

  // msgcode matches, always a response
  if (msgCode == MessageCode())
    return true;

  if (!ProvidesExtendedResponse())
    return IsResponseOld(msg);

  // response without a msgcode
  if (msgResponse == MSGCODE_NOTHING)
    return false;

  // commands that only repond with accepted/rejected
  if (thisMsgCode == MSGCODE_PING ||
      thisMsgCode == MSGCODE_SET_ACK_MASK ||
      thisMsgCode == MSGCODE_SET_CONTROLLED ||
      thisMsgCode == MSGCODE_SET_AUTO_ENABLED ||
      thisMsgCode == MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS ||
      thisMsgCode == MSGCODE_SET_LOGICAL_ADDRESS_MASK ||
      thisMsgCode == MSGCODE_SET_PHYSICAL_ADDRESS ||
      thisMsgCode == MSGCODE_SET_DEVICE_TYPE ||
      thisMsgCode == MSGCODE_SET_HDMI_VERSION ||
      thisMsgCode == MSGCODE_SET_OSD_NAME ||
      thisMsgCode == MSGCODE_WRITE_EEPROM ||
      thisMsgCode == MSGCODE_TRANSMIT_IDLETIME ||
      thisMsgCode == MSGCODE_SET_ACTIVE_SOURCE)
    return thisMsgCode == msgResponse;

  if (!m_message->IsTranmission())
    return false;

  return ((msgCode == MSGCODE_COMMAND_ACCEPTED || msgCode == MSGCODE_COMMAND_REJECTED) &&
      (msgResponse == MSGCODE_TRANSMIT_ACK_POLARITY || msgResponse == MSGCODE_TRANSMIT || msgResponse == MSGCODE_TRANSMIT_EOM)) ||
      msgCode == MSGCODE_TIMEOUT_ERROR ||
      msgCode == MSGCODE_RECEIVE_FAILED ||
      msgCode == MSGCODE_TRANSMIT_FAILED_ACK ||
      msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
      msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
      msgCode == MSGCODE_TRANSMIT_SUCCEEDED;
}
示例#6
0
bool CAdapterCommunication::StartBootloader(void)
{
  bool bReturn(false);
  if (!IsRunning())
    return bReturn;

  m_controller->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
  CCECAdapterMessage *output = new CCECAdapterMessage;

  output->push_back(MSGSTART);
  output->push_escaped(MSGCODE_START_BOOTLOADER);
  output->push_back(MSGEND);

  if ((bReturn = Write(output)) == false)
    m_controller->AddLog(CEC_LOG_ERROR, "could not start the bootloader");

  delete output;

  return bReturn;
}
cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool UNUSED(bIsReply))
{
  cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
  if (!IsRunning())
    return retVal;

  CCECAdapterMessage *output = new CCECAdapterMessage(data, iLineTimeout);

  /* mark as waiting for an ack from the destination */
  MarkAsWaiting(data.destination);

  /* send the message */
  bRetry = (!m_adapterMessageQueue->Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
  if (bRetry)
    Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
  retVal = output->state;

  delete output;
  return retVal;
}
bool CCECAdapterMessageQueueEntry::MessageReceivedResponse(const CCECAdapterMessage &message)
{
  {
    CLockObject lock(m_mutex);
#ifdef CEC_DEBUGGING
    m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
#else
    if (message.IsError())
      m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
#endif
    m_message->response = message.packet;
    if (m_message->IsTranmission())
      m_message->state = message.Message() == MSGCODE_TRANSMIT_SUCCEEDED ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
    else
      m_message->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
  }

  Signal();

  return true;
}
示例#9
0
bool CAdapterCommunication::PingAdapter(void)
{
  bool bReturn(false);
  if (!IsRunning())
    return bReturn;

  m_controller->AddLog(CEC_LOG_DEBUG, "sending ping");
  CCECAdapterMessage *output = new CCECAdapterMessage;

  output->push_back(MSGSTART);
  output->push_escaped(MSGCODE_PING);
  output->push_back(MSGEND);

  if ((bReturn = Write(output)) == false)
    m_controller->AddLog(CEC_LOG_ERROR, "could not send ping command");

  // TODO check for pong
  delete output;

  return bReturn;
}
示例#10
0
void CAdapterCommunication::WriteNextCommand(void)
{
  CCECAdapterMessage *msg;
  if (m_outBuffer.Pop(msg))
  {
    CLockObject lock(&msg->mutex);
    if (m_port->Write(msg) != (int32_t) msg->size())
    {
      CStdString strError;
      strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
      m_controller->AddLog(CEC_LOG_ERROR, strError);
      msg->state = ADAPTER_MESSAGE_STATE_ERROR;
    }
    else
    {
      m_controller->AddLog(CEC_LOG_DEBUG, "command sent");
      CCondition::Sleep((uint32_t) msg->size() * 24 /*data*/ + 5 /*start bit (4.5 ms)*/ + 10);
      msg->state = ADAPTER_MESSAGE_STATE_SENT;
    }
    msg->condition.Signal();
  }
}
bool CCECAdapterMessageQueueEntry::IsResponseOld(const CCECAdapterMessage &msg)
{
  cec_adapter_messagecode msgCode = msg.Message();

  return msgCode == MessageCode() ||
         msgCode == MSGCODE_COMMAND_ACCEPTED ||
         msgCode == MSGCODE_COMMAND_REJECTED ||
         (m_message->IsTranmission() && (msgCode == MSGCODE_TIMEOUT_ERROR ||
             msgCode == MSGCODE_HIGH_ERROR ||
             msgCode == MSGCODE_LOW_ERROR ||
             msgCode == MSGCODE_RECEIVE_FAILED ||
             msgCode == MSGCODE_TRANSMIT_FAILED_LINE ||
             msgCode == MSGCODE_TRANSMIT_FAILED_ACK ||
             msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
             msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
             msgCode == MSGCODE_TRANSMIT_SUCCEEDED));
}
bool CCECAdapterMessageQueueEntry::MessageReceived(const CCECAdapterMessage &message)
{
  bool bHandled(false);

  if (IsResponse(message))
  {
    switch (message.Message())
    {
    case MSGCODE_COMMAND_ACCEPTED:
      bHandled = MessageReceivedCommandAccepted(message);
      break;
    case MSGCODE_TRANSMIT_SUCCEEDED:
      bHandled = MessageReceivedTransmitSucceeded(message);
      break;
    default:
      bHandled = MessageReceivedResponse(message);
      break;
    }
  }

  return bHandled;
}
CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage &params, bool bIsRetry /* = false */)
{
  if (!IsOpen() || !m_adapterMessageQueue)
    return NULL;

  /* create the adapter message for this command */
  CCECAdapterMessage *output = new CCECAdapterMessage;
  output->PushBack(MSGSTART);
  output->PushEscaped((uint8_t)msgCode);
  output->Append(params);
  output->PushBack(MSGEND);

  /* write the command */
  if (!m_adapterMessageQueue->Write(output))
  {
    // this will trigger an alert in the reader thread
    if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
      m_port->Close();
    return output;
  }
  else
  {
    if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED &&
        msgCode != MSGCODE_GET_BUILDDATE /* same messagecode value had a different meaning in older fw builds */)
    {
      /* if the controller reported that the command was rejected, and we didn't send the command
         to set controlled mode, then the controller probably switched to auto mode. set controlled
         mode and retry */
      LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
      delete output;
      if (SetControlledMode(true))
        return SendCommand(msgCode, params, true);
    }
  }

  return output;
}