bool bConnected(false), bPinged(false), bControlled(false);
/* open a new connection */
- while (iNow < iTarget && (bConnected = m_communication->Open(iTimeoutMs)) == false)
+ while (iNow < iTarget && (bConnected = m_communication->Open(this, iTimeoutMs)) == false)
{
CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
Sleep(500);
m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
}
+bool CCECProcessor::OnCommandReceived(const cec_command &command)
+{
+ m_commandBuffer.Push(command);
+ return true;
+}
+
void *CCECProcessor::Process(void)
{
- bool bParseCommand(false);
cec_command command;
CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
- while (!IsStopped())
+ while (!IsStopped() && m_communication->IsOpen())
{
ReplaceHandlers();
- command.Clear();
-
- {
- CLockObject lock(m_mutex);
- if (m_commandBuffer.Pop(command))
- bParseCommand = true;
- else if (m_communication->IsOpen() && m_communication->Read(command, 50))
- bParseCommand = true;
- }
-
- if (bParseCommand)
+ if (m_commandBuffer.Pop(command))
ParseCommand(command);
- bParseCommand = false;
-
- Sleep(5);
m_controller->CheckKeypressTimeout();
+ Sleep(5);
}
if (m_communication)
Transmit(command);
}
-void CCECProcessor::ParseCommand(cec_command &command)
+void CCECProcessor::ParseCommand(const cec_command &command)
{
CStdString dataStr;
dataStr.Format(">> %1x%1x:%02x", command.initiator, command.destination, command.opcode);
#include <cectypes.h>
#include "platform/threads/threads.h"
#include "platform/util/buffer.h"
+#include "adapter/AdapterCommunication.h"
namespace CEC
{
class IAdapterCommunication;
class CCECBusDevice;
- class CCECProcessor : public PLATFORM::CThread
+ class CCECProcessor : public PLATFORM::CThread, public IAdapterCommunicationCallback
{
public:
CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
virtual bool Start(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000);
virtual void *Process(void);
+ virtual bool OnCommandReceived(const cec_command &command);
+
virtual bool IsMonitoring(void) const { return m_bMonitor; }
virtual CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const;
virtual CCECBusDevice * GetDeviceByType(cec_device_type type) const;
bool FindLogicalAddressAudioSystem(void);
void LogOutput(const cec_command &data);
- void ParseCommand(cec_command &command);
+ void ParseCommand(const cec_command &command);
bool m_bInitialised;
uint8_t m_iHDMIPort;
ADAPTER_MESSAGE_STATE_ERROR /**< an error occured */
} cec_adapter_message_state;
- class IAdapterCommunication
+ struct IAdapterCommunicationCallback
+ {
+ public:
+ /*!
+ * @brief Callback method for IAdapterCommunication, called when a new cec_command is received
+ * @param command The command that has been received
+ * @return True when it was handled by this listener, false otherwise.
+ */
+ virtual bool OnCommandReceived(const cec_command &command) = 0;
+ };
+
+ struct IAdapterCommunication
{
public:
/*!
* @brief Open a connection to the CEC adapter
+ * @param cb The callback struct. if set to NULL, the Read() method has to be used to read commands. if set, OnCommandReceived() will be called for each command that was received
* @param iTimeoutMs Connection timeout in ms
* @return True when connected, false otherwise
*/
- virtual bool Open(uint32_t iTimeoutMs = 10000) = 0;
+ virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000) = 0;
/*!
* @brief Close an open connection
Close();
}
-bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */)
{
uint64_t iNow = GetTimeMs();
uint64_t iTimeout = iNow + iTimeoutMs;
return true;
}
+ m_callback = cb;
CStdString strError;
bool bConnected(false);
while (!bConnected && iNow < iTimeout)
void *CUSBCECAdapterCommunication::Process(void)
{
+ cec_command command;
while (!IsStopped())
{
ReadFromDevice(50);
+
+ /* push the next command to the callback method if there is one */
+ if (m_callback && Read(command, 0))
+ m_callback->OnCommandReceived(command);
+
Sleep(5);
WriteNextCommand();
}
bool CUSBCECAdapterCommunication::Write(CCECAdapterMessage *data)
{
- bool bReturn(false);
-
CLockObject lock(data->mutex);
data->state = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
m_outBuffer.Push(data);
data->condition.Wait(data->mutex);
- if (data->state != ADAPTER_MESSAGE_STATE_SENT)
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "command was not sent");
- }
- else if (data->expectControllerAck)
- {
- bReturn = WaitForAck(*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
+ if ((data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT_ACKED) ||
+ (!data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT))
{
- bReturn = true;
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "command was not %s", data->state == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED ? "acked" : "sent");
+ return false;
}
- return bReturn;
+ return true;
}
bool CUSBCECAdapterCommunication::Read(cec_command &command, uint32_t iTimeout)
if (!m_inBuffer.Pop(buf))
{
- if (!m_rcvCondition.Wait(m_mutex, iTimeout))
+ if (iTimeout == 0 || !m_rcvCondition.Wait(m_mutex, iTimeout))
return false;
m_inBuffer.Pop(buf);
}
output->isTransmission = false;
output->expectControllerAck = false;
- SendMessageToAdapter(output);
+ bool bWriteOk = Write(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 (size = %d, message = %d)", input.Size(), input.Message());
+ if (!bWriteOk)
+ {
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not request the firmware version");
+ }
else
{
- m_iFirmwareVersion = (input[1] << 8 | input[2]);
- iReturn = m_iFirmwareVersion;
+ ReadFromDevice(CEC_DEFAULT_TRANSMIT_WAIT, 5 /* start + msgcode + 2 bytes for fw version + end */);
+ CCECAdapterMessage input;
+ if (!Read(input, 0) || input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3)
+ CLibCEC::AddLog(CEC_LOG_ERROR, "no or invalid firmware version (size = %d, message = %d)", input.Size(), input.Message());
+ else
+ {
+ m_iFirmwareVersion = (input[1] << 8 | input[2]);
+ iReturn = m_iFirmwareVersion;
+ }
}
}
uint8_t iPacketsLeft(message.Size() / 4);
int64_t iNow = GetTimeMs();
- int64_t iTargetTime = iNow + message.transmit_timeout;
+ int64_t iTargetTime = iNow + (message.transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : message.transmit_timeout);
- while (!bTransmitSucceeded && !bError && (message.transmit_timeout == 0 || iNow < iTargetTime))
+ while (!bTransmitSucceeded && !bError && iNow < iTargetTime)
{
+ ReadFromDevice(50);
CCECAdapterMessage msg;
- int32_t iWait = (int32_t)(iTargetTime - iNow);
- if (iWait <= 5 || message.transmit_timeout <= 5)
- iWait = CEC_DEFAULT_TRANSMIT_WAIT;
-
- if (!Read(msg, iWait))
+ if (!Read(msg, 0))
{
iNow = GetTimeMs();
continue;
}
}
+ message.state = bTransmitSucceeded && !bError ?
+ ADAPTER_MESSAGE_STATE_SENT_ACKED :
+ ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+
return bTransmitSucceeded && !bError;
}
}
}
-bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
{
ssize_t iBytesRead;
uint8_t buff[256];
if (!m_port)
return false;
+ if (iSize > 256)
+ iSize = 256;
CLockObject lock(m_mutex);
- iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
+ iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
if (iBytesRead < 0 || iBytesRead > 256)
{
CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
{
CLibCEC::AddLog(CEC_LOG_DEBUG, "command sent");
msg->state = ADAPTER_MESSAGE_STATE_SENT;
+
+ if (msg->expectControllerAck)
+ {
+ if (!WaitForAck(*msg))
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
+ }
}
msg->condition.Signal();
}
CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
virtual ~CUSBCECAdapterCommunication();
- virtual bool Open(uint32_t iTimeoutMs = 10000);
+ virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000);
virtual void Close(void);
virtual bool IsOpen(void);
virtual CStdString GetError(void) const;
void SendMessageToAdapter(CCECAdapterMessage *msg);
void WriteNextCommand(void);
void AddData(uint8_t *data, size_t iLen);
- bool ReadFromDevice(uint32_t iTimeout);
+ bool ReadFromDevice(uint32_t iTimeout, size_t iSize = 256);
bool WaitForAck(CCECAdapterMessage &message);
PLATFORM::ISocket * m_port;
CCECAdapterMessage m_currentAdapterMessage;
bool m_bNextIsEscaped;
bool m_bGotStart;
+ IAdapterCommunicationCallback * m_callback;
};
};