cec_adapter_message_state CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool &bRetry, uint32_t iLineTimeout, bool bIsReply, VC_CEC_ERROR_T &vcReply) { // handle POLL (msg like '11') in a special way - the way it was // originally designed by BCM, expected to happen and documented // in API docs (/opt/vc/includes) // due to often (more than 20% test cases - CEC bus with 8 devices) // irregularities on returned status, repeat until we get SAME // result twice in a row if (!command.opcode_set && command.destination == command.initiator) { int iReturnPrev = -1; int iReturn = 0; while((iReturn = vc_cec_poll_address((CEC_AllDevices_T)command.destination)) != iReturnPrev) iReturnPrev = iReturn; if (iReturn == 0) return ADAPTER_MESSAGE_STATE_SENT_ACKED; else if (iReturn > 0) return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; else return ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT; } CRPiCECAdapterMessageQueueEntry *entry = new CRPiCECAdapterMessageQueueEntry(this, command); uint64_t iEntryId(0); /* add to the wait for ack queue */ { CLockObject lock(m_mutex); iEntryId = m_iNextMessage++; m_messages.insert(std::make_pair(iEntryId, entry)); } #if defined(RPI_USE_SEND_MESSAGE2) VC_CEC_MESSAGE_T message; message.initiator = (CEC_AllDevices_T)command.initiator; message.follower = (CEC_AllDevices_T)command.destination; message.length = 1; if (command.opcode_set) { message.length += 1; message.payload[0] = command.opcode; message.length += command.parameters.size; for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) message.payload[iPtr + 1] = command.parameters.At(iPtr); } #ifdef CEC_DEBUGGING std::string strDump; strDump = StringUtils::Format("len = %d, payload = %X%X", message.length, (int)message.initiator, (int)message.follower); for (uint8_t iPtr = 0; iPtr < message.length - 1; iPtr++) strDump += StringUtils::Format(":%02X", message.payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); #endif int iReturn = vc_cec_send_message2(&message); #else uint8_t payload[32]; uint32_t iLength(0); if (command.opcode_set) { iLength += 1; payload[0] = command.opcode; iLength += command.parameters.size; for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) payload[iPtr + 1] = command.parameters.At(iPtr); } #ifdef CEC_DEBUGGING std:string strDump; strDump = StringUtils::Format("len = %d, payload = %X%X", iLength, (int)command.initiator, (int)command.destination); for (uint8_t iPtr = 0; iPtr < iLength; iPtr++) strDump += StringUtils::Format(":%02X", payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); #endif int iReturn = vc_cec_send_message((uint32_t)command.destination, command.opcode_set ? (uint8_t*)&payload : NULL, iLength, bIsReply); #endif bRetry = false; if (iReturn != VCHIQ_SUCCESS) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending command '%s' failed (%d)", CCECTypeUtils::ToString(command.opcode), iReturn); delete entry; m_messages.erase(iEntryId); return ADAPTER_MESSAGE_STATE_ERROR; } cec_adapter_message_state bReturn(ADAPTER_MESSAGE_STATE_ERROR); if (entry) { if (entry->Wait(iLineTimeout)) { int status = entry->Result(); if (status == VC_CEC_ERROR_NO_ACK) bReturn = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; else if (status == VC_CEC_SUCCESS) bReturn = ADAPTER_MESSAGE_STATE_SENT_ACKED; else bReturn = ADAPTER_MESSAGE_STATE_SENT; } else { bRetry = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' timeout", CCECTypeUtils::ToString(command.opcode)); CEvent::Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT); bReturn = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT; } vcReply = (VC_CEC_ERROR_T)entry->Result(); CLockObject lock(m_mutex); m_messages.erase(iEntryId); delete entry; } return bReturn; }
cec_adapter_message_state CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool &bRetry, uint32_t iLineTimeout, bool bIsReply, VC_CEC_ERROR_T &vcReply) { CRPiCECAdapterMessageQueueEntry *entry = new CRPiCECAdapterMessageQueueEntry(this, command); uint64_t iEntryId(0); /* add to the wait for ack queue */ { CLockObject lock(m_mutex); iEntryId = m_iNextMessage++; m_messages.insert(make_pair(iEntryId, entry)); } #if defined(RPI_USE_SEND_MESSAGE2) VC_CEC_MESSAGE_T message; message.initiator = (CEC_AllDevices_T)command.initiator; message.follower = (CEC_AllDevices_T)command.destination; message.length = 1; if (command.opcode_set) { message.length += 1; message.payload[0] = command.opcode; message.length += command.parameters.size; for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) message.payload[iPtr + 1] = command.parameters.At(iPtr); } #ifdef CEC_DEBUGGING CStdString strDump; strDump.Format("len = %d, payload = %X%X", message.length, (int)message.initiator, (int)message.follower); for (uint8_t iPtr = 0; iPtr < message.length - 1; iPtr++) strDump.AppendFormat(":%02X", message.payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); #endif int iReturn = vc_cec_send_message2(&message); #else uint8_t payload[32]; uint32_t iLength(0); if (command.opcode_set) { iLength += 1; payload[0] = command.opcode; iLength += command.parameters.size; for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) payload[iPtr + 1] = command.parameters.At(iPtr); } #ifdef CEC_DEBUGGING CStdString strDump; strDump.Format("len = %d, payload = %X%X", iLength, (int)command.initiator, (int)command.destination); for (uint8_t iPtr = 0; iPtr < iLength; iPtr++) strDump.AppendFormat(":%02X", payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); #endif int iReturn = vc_cec_send_message((uint32_t)command.destination, command.opcode_set ? (uint8_t*)&payload : NULL, iLength, bIsReply); #endif bRetry = false; if (iReturn != VCHIQ_SUCCESS) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending command '%s' failed (%d)", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL", iReturn); delete (entry); return ADAPTER_MESSAGE_STATE_ERROR; } cec_adapter_message_state bReturn(ADAPTER_MESSAGE_STATE_ERROR); if (entry) { if (entry->Wait(iLineTimeout)) { int status = entry->Result(); if (status == VC_CEC_ERROR_NO_ACK) bReturn = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; else if (status == VC_CEC_SUCCESS) bReturn = ADAPTER_MESSAGE_STATE_SENT_ACKED; else bReturn = ADAPTER_MESSAGE_STATE_SENT; } else { if (command.opcode_set) { bRetry = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' timeout", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL"); CEvent::Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT); } bReturn = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT; } vcReply = (VC_CEC_ERROR_T)entry->Result(); CLockObject lock(m_mutex); m_messages.erase(iEntryId); delete entry; } return bReturn; }
bool CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool bIsReply) { CRPiCECAdapterMessageQueueEntry *entry = new CRPiCECAdapterMessageQueueEntry(this, command); uint64_t iEntryId(0); /* add to the wait for ack queue */ { CLockObject lock(m_mutex); iEntryId = m_iNextMessage++; m_messages.insert(make_pair(iEntryId, entry)); } #if defined(RPI_USE_SEND_MESSAGE2) VC_CEC_MESSAGE_T message; message.initiator = (CEC_AllDevices_T)command.initiator; message.follower = (CEC_AllDevices_T)command.destination; message.length = 1; if (command.opcode_set) { message.length += 1; message.payload[0] = command.opcode; message.length += command.parameters.size; for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) message.payload[iPtr + 1] = command.parameters.At(iPtr); } CStdString strDump; strDump.Format("len = %d, payload = %X%X", message.length, (int)message.initiator, (int)message.follower); for (uint8_t iPtr = 0; iPtr < message.length - 1; iPtr++) strDump.AppendFormat(":%02X", message.payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); int iReturn = vc_cec_send_message2(&message); #else uint8_t payload[32]; uint32_t iLength(0); if (command.opcode_set) { iLength += 1; payload[0] = command.opcode; iLength += command.parameters.size; for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) payload[iPtr + 1] = command.parameters.At(iPtr); } CStdString strDump; strDump.Format("len = %d, payload = %X%X", iLength, (int)command.initiator, (int)command.destination); for (uint8_t iPtr = 0; iPtr < iLength; iPtr++) strDump.AppendFormat(":%02X", payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); int iReturn = vc_cec_send_message((uint32_t)command.destination, (uint8_t*)&payload, iLength, bIsReply); #endif if (iReturn != VCHIQ_SUCCESS) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending command '%s' failed (%d)", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL", iReturn); delete (entry); return false; } bool bReturn(true); if (entry) { if (!entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT)) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL"); bReturn = false; } CLockObject lock(m_mutex); m_messages.erase(iEntryId); delete entry; } return bReturn; }