#include "AdapterCommunication.h"
#include "AdapterMessage.h"
-#include "CECProcessor.h"
-#include "platform/serialport/serialport.h"
+#include "../CECProcessor.h"
+#include "../platform/serialport/serialport.h"
+#include "../LibCEC.h"
using namespace std;
using namespace CEC;
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;
}
if (!m_port)
{
- m_processor->AddLog(CEC_LOG_ERROR, "port is NULL");
+ CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
return false;
}
if (IsOpen())
{
- m_processor->AddLog(CEC_LOG_ERROR, "port is already open");
+ CLibCEC::AddLog(CEC_LOG_ERROR, "port is already open");
return true;
}
if (!bConnected)
{
- m_processor->AddLog(CEC_LOG_ERROR, strError);
+ CLibCEC::AddLog(CEC_LOG_ERROR, strError);
return false;
}
- m_processor->AddLog(CEC_LOG_DEBUG, "connection opened");
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened");
//clear any input bytes
uint8_t buff[1];
if (CreateThread())
{
- m_processor->AddLog(CEC_LOG_DEBUG, "communication thread started");
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
return true;
}
else
{
- m_processor->AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
}
return false;
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)
+ {
+ CLibCEC::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;
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
+ }
+ }
+ else
+ {
+ bReturn = true;
+ }
+
+ return bReturn;
}
bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove
{
if (msg.Size() > 0)
- m_processor->AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+ CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
msg.Clear();
bGotStart = true;
}
}
if (bGotFullMessage)
- msg.state = ADAPTER_MESSAGE_STATE_RECEIVED;
+ msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
return bGotFullMessage;
}
if (!IsRunning())
return bReturn;
- m_processor->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "starting the bootloader");
CCECAdapterMessage *output = new CCECAdapterMessage;
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)
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not start the bootloader");
delete output;
return bReturn;
if (!IsRunning())
return bReturn;
- m_processor->AddLog(CEC_LOG_DEBUG, "sending ping");
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping");
CCECAdapterMessage *output = new CCECAdapterMessage;
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)
+ CLibCEC::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)
+ {
+ CLibCEC::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)
+ CLibCEC::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);
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");
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the idletime");
delete output;
}
return bReturn;
}
+bool CAdapterCommunication::SetAckMask(uint16_t iMask)
+{
+ bool bReturn(false);
+ CStdString strLog;
+ strLog.Format("setting ackmask to %2x", iMask);
+ CLibCEC::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)
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the ackmask");
+ delete output;
+
+ return bReturn;
+}
+
bool CAdapterCommunication::IsOpen(void)
{
return !IsStopped() && m_port->IsOpen() && IsRunning();
if (bError)
{
message->reply = msg.Message();
- m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+ CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString());
}
else
{
switch(msg.Message())
{
case MSGCODE_COMMAND_ACCEPTED:
- m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+ CLibCEC::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());
+ CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString());
bTransmitSucceeded = (iPacketsLeft == 0);
bError = !bTransmitSucceeded;
message->reply = MSGCODE_TRANSMIT_SUCCEEDED;
if (!m_port)
return false;
+ CLockObject lock(m_mutex);
iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
if (iBytesRead < 0 || iBytesRead > 256)
{
CStdString strError;
strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
- m_processor->AddLog(CEC_LOG_ERROR, strError);
+ CLibCEC::AddLog(CEC_LOG_ERROR, strError);
return false;
}
else if (iBytesRead > 0)
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())
{
CStdString strError;
strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
- m_processor->AddLog(CEC_LOG_ERROR, strError);
+ CLibCEC::AddLog(CEC_LOG_ERROR, strError);
msg->state = ADAPTER_MESSAGE_STATE_ERROR;
}
else
{
- m_processor->AddLog(CEC_LOG_DEBUG, "command sent");
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "command sent");
msg->state = ADAPTER_MESSAGE_STATE_SENT;
}
msg->condition.Signal();