X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fadapter%2FAdapterCommunication.cpp;h=15b6851ae5abcf843d00d516626095ad85ae7ee5;hb=ae56385d74f096a4d746e221ff53e53b21ebd24c;hp=4a136ab113f4bef0a8e1fcdd83b19506d49f7eb1;hpb=ef7696f555d4051a4412346939f3da4c649fb128;p=deb_libcec.git diff --git a/src/lib/adapter/AdapterCommunication.cpp b/src/lib/adapter/AdapterCommunication.cpp index 4a136ab..15b6851 100644 --- a/src/lib/adapter/AdapterCommunication.cpp +++ b/src/lib/adapter/AdapterCommunication.cpp @@ -43,7 +43,8 @@ using namespace PLATFORM; CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor) : m_port(NULL), m_processor(processor), - m_iLineTimeout(0) + m_iLineTimeout(0), + m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN) { m_port = new PLATFORM::CSerialPort; } @@ -140,9 +141,38 @@ void *CAdapterCommunication::Process(void) bool CAdapterCommunication::Write(CCECAdapterMessage *data) { - data->state = ADAPTER_MESSAGE_STATE_WAITING; + bool bReturn(false); + + CLockObject lock(data->mutex); + data->state = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT; m_outBuffer.Push(data); - return true; + data->condition.Wait(data->mutex); + + if (data->state != ADAPTER_MESSAGE_STATE_SENT) + { + m_processor->AddLog(CEC_LOG_ERROR, "command was not sent"); + } + + if (data->expectControllerAck) + { + bReturn = WaitForTransmitSucceeded(data); + if (bReturn) + { + if (data->isTransmission) + data->state = ADAPTER_MESSAGE_STATE_SENT_ACKED; + } + else + { + data->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; + m_processor->AddLog(CEC_LOG_DEBUG, "did not receive ack"); + } + } + else + { + bReturn = true; + } + + return bReturn; } bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout) @@ -195,7 +225,7 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout) } if (bGotFullMessage) - msg.state = ADAPTER_MESSAGE_STATE_RECEIVED; + msg.state = ADAPTER_MESSAGE_STATE_INCOMING; return bGotFullMessage; } @@ -217,11 +247,11 @@ bool CAdapterCommunication::StartBootloader(void) output->PushBack(MSGSTART); output->PushEscaped(MSGCODE_START_BOOTLOADER); output->PushBack(MSGEND); + output->isTransmission = false; + output->expectControllerAck = false; - CLockObject lock(output->mutex); - if (Write(output)) - output->condition.Wait(output->mutex); - bReturn = output->state == ADAPTER_MESSAGE_STATE_SENT; + if ((bReturn = Write(output)) == false) + m_processor->AddLog(CEC_LOG_ERROR, "could not start the bootloader"); delete output; return bReturn; @@ -239,16 +269,48 @@ bool CAdapterCommunication::PingAdapter(void) output->PushBack(MSGSTART); output->PushEscaped(MSGCODE_PING); output->PushBack(MSGEND); + output->isTransmission = false; - CLockObject lock(output->mutex); - if (Write(output)) - output->condition.Wait(output->mutex); - bReturn = output->state == ADAPTER_MESSAGE_STATE_SENT; + if ((bReturn = Write(output)) == false) + m_processor->AddLog(CEC_LOG_ERROR, "could not ping the adapter"); delete output; return bReturn; } +uint16_t CAdapterCommunication::GetFirmwareVersion(void) +{ + uint16_t iReturn(m_iFirmwareVersion); + if (!IsRunning()) + return iReturn; + + if (iReturn == CEC_FW_VERSION_UNKNOWN) + { + m_processor->AddLog(CEC_LOG_DEBUG, "requesting the firmware version"); + CCECAdapterMessage *output = new CCECAdapterMessage; + + output->PushBack(MSGSTART); + output->PushEscaped(MSGCODE_FIRMWARE_VERSION); + output->PushBack(MSGEND); + output->isTransmission = false; + output->expectControllerAck = false; + + SendMessageToAdapter(output); + delete output; + + CCECAdapterMessage input; + if (!Read(input, CEC_DEFAULT_TRANSMIT_WAIT) || input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3) + m_processor->AddLog(CEC_LOG_ERROR, "no or invalid firmware version"); + else + { + m_iFirmwareVersion = (input[1] << 8 | input[2]); + iReturn = m_iFirmwareVersion; + } + } + + return iReturn; +} + bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout) { bool bReturn(m_iLineTimeout != iTimeout); @@ -261,6 +323,7 @@ bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout) output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME); output->PushEscaped(iTimeout); output->PushBack(MSGEND); + output->isTransmission = false; if ((bReturn = Write(output)) == false) m_processor->AddLog(CEC_LOG_ERROR, "could not set the idletime"); @@ -270,11 +333,102 @@ bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout) return bReturn; } +bool CAdapterCommunication::SetAckMask(uint16_t iMask) +{ + bool bReturn(false); + CStdString strLog; + strLog.Format("setting ackmask to %2x", iMask); + m_processor->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + + CCECAdapterMessage *output = new CCECAdapterMessage; + + output->PushBack(MSGSTART); + output->PushEscaped(MSGCODE_SET_ACK_MASK); + output->PushEscaped(iMask >> 8); + output->PushEscaped((uint8_t)iMask); + output->PushBack(MSGEND); + output->isTransmission = false; + + if ((bReturn = Write(output)) == false) + m_processor->AddLog(CEC_LOG_ERROR, "could not set the ackmask"); + delete output; + + return bReturn; +} + bool CAdapterCommunication::IsOpen(void) { return !IsStopped() && m_port->IsOpen() && IsRunning(); } +bool CAdapterCommunication::WaitForTransmitSucceeded(CCECAdapterMessage *message) +{ + bool bError(false); + bool bTransmitSucceeded(false); + uint8_t iPacketsLeft(message->Size() / 4); + + int64_t iNow = GetTimeMs(); + int64_t iTargetTime = iNow + message->transmit_timeout; + + while (!bTransmitSucceeded && !bError && (message->transmit_timeout == 0 || iNow < iTargetTime)) + { + CCECAdapterMessage msg; + + if (!Read(msg, message->transmit_timeout > 0 ? (int32_t)(iTargetTime - iNow) : 1000)) + { + iNow = GetTimeMs(); + continue; + } + + if (msg.Message() == MSGCODE_FRAME_START && msg.IsACK()) + { + m_processor->HandlePoll(msg.Initiator(), msg.Destination()); + iNow = GetTimeMs(); + continue; + } + + if (msg.Message() == MSGCODE_RECEIVE_FAILED && + m_processor->HandleReceiveFailed()) + { + iNow = GetTimeMs(); + continue; + } + + bError = msg.IsError(); + if (bError) + { + message->reply = msg.Message(); + m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString()); + } + else + { + switch(msg.Message()) + { + case MSGCODE_COMMAND_ACCEPTED: + m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString()); + if (iPacketsLeft > 0) + iPacketsLeft--; + if (!message->isTransmission && iPacketsLeft == 0) + bTransmitSucceeded = true; + break; + case MSGCODE_TRANSMIT_SUCCEEDED: + m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString()); + bTransmitSucceeded = (iPacketsLeft == 0); + bError = !bTransmitSucceeded; + message->reply = MSGCODE_TRANSMIT_SUCCEEDED; + break; + default: + // ignore other data while waiting + break; + } + + iNow = GetTimeMs(); + } + } + + return bTransmitSucceeded && !bError; +} + void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen) { CLockObject lock(m_mutex); @@ -291,6 +445,7 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout) if (!m_port) return false; + CLockObject lock(m_mutex); iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout); if (iBytesRead < 0 || iBytesRead > 256) { @@ -307,6 +462,7 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout) void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg) { + CLockObject adapterLock(m_mutex); CLockObject lock(msg->mutex); if (m_port->Write(msg->packet.data, msg->Size()) != (int32_t) msg->Size()) {