#endif
} cec_logical_addresses;
-
typedef int (CEC_CDECL* CBCecLogMessageType)(void *param, const CEC::cec_log_message &);
typedef int (CEC_CDECL* CBCecKeyPressType)(void *param, const cec_keypress &key);
typedef int (CEC_CDECL* CBCecCommandType)(void *param, const cec_command &command);
<ClInclude Include="..\include\cecloader.h" />
<ClInclude Include="..\include\cectypes.h" />
<ClInclude Include="..\src\lib\adapter\AdapterCommunication.h" />
- <ClInclude Include="..\src\lib\adapter\AdapterDetection.h" />
- <ClInclude Include="..\src\lib\adapter\AdapterMessage.h" />
+ <ClInclude Include="..\src\lib\adapter\USBCECAdapterCommunication.h" />
+ <ClInclude Include="..\src\lib\adapter\USBCECAdapterDetection.h" />
+ <ClInclude Include="..\src\lib\adapter\USBCECAdapterMessage.h" />
<ClInclude Include="..\src\lib\CECProcessor.h" />
<ClInclude Include="..\src\lib\devices\CECAudioSystem.h" />
<ClInclude Include="..\src\lib\devices\CECBusDevice.h" />
<ClInclude Include="..\src\lib\platform\windows\stdint.h" />
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\src\lib\adapter\AdapterCommunication.cpp" />
- <ClCompile Include="..\src\lib\adapter\AdapterDetection.cpp" />
+ <ClCompile Include="..\src\lib\adapter\USBCECAdapterCommunication.cpp" />
+ <ClCompile Include="..\src\lib\adapter\USBCECAdapterDetection.cpp" />
<ClCompile Include="..\src\lib\CECProcessor.cpp" />
<ClCompile Include="..\src\lib\devices\CECAudioSystem.cpp" />
<ClCompile Include="..\src\lib\devices\CECBusDevice.cpp" />
<ClInclude Include="..\src\lib\devices\CECTV.h">
<Filter>devices</Filter>
</ClInclude>
- <ClInclude Include="..\src\lib\adapter\AdapterCommunication.h">
- <Filter>adapter</Filter>
- </ClInclude>
- <ClInclude Include="..\src\lib\adapter\AdapterDetection.h">
- <Filter>adapter</Filter>
- </ClInclude>
- <ClInclude Include="..\src\lib\adapter\AdapterMessage.h">
- <Filter>adapter</Filter>
- </ClInclude>
<ClInclude Include="..\src\lib\platform\os.h">
<Filter>platform</Filter>
</ClInclude>
<ClInclude Include="..\src\lib\platform\windows\stdint.h">
<Filter>platform\windows</Filter>
</ClInclude>
+ <ClInclude Include="..\src\lib\adapter\AdapterCommunication.h">
+ <Filter>adapter</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\lib\adapter\USBCECAdapterCommunication.h">
+ <Filter>adapter</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\lib\adapter\USBCECAdapterDetection.h">
+ <Filter>adapter</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\lib\adapter\USBCECAdapterMessage.h">
+ <Filter>adapter</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\lib\CECProcessor.cpp" />
<ClCompile Include="..\src\lib\devices\CECTV.cpp">
<Filter>devices</Filter>
</ClCompile>
- <ClCompile Include="..\src\lib\adapter\AdapterCommunication.cpp">
- <Filter>adapter</Filter>
+ <ClCompile Include="..\src\lib\platform\windows\serialport.cpp">
+ <Filter>platform\windows</Filter>
</ClCompile>
- <ClCompile Include="..\src\lib\adapter\AdapterDetection.cpp">
+ <ClCompile Include="..\src\lib\adapter\USBCECAdapterCommunication.cpp">
<Filter>adapter</Filter>
</ClCompile>
- <ClCompile Include="..\src\lib\platform\windows\serialport.cpp">
- <Filter>platform\windows</Filter>
+ <ClCompile Include="..\src\lib\adapter\USBCECAdapterDetection.cpp">
+ <Filter>adapter</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
#include "CECProcessor.h"
-#include "adapter/AdapterMessage.h"
+#include "adapter/USBCECAdapterCommunication.h"
#include "devices/CECBusDevice.h"
#include "devices/CECAudioSystem.h"
#include "devices/CECPlaybackDevice.h"
m_bInitialised(false),
m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
- m_lastInitiator(CECDEVICE_UNKNOWN),
m_strDeviceName(strDeviceName),
m_communication(NULL),
m_controller(controller),
return bReturn;
}
- m_communication = new CAdapterCommunication(this, strPort, iBaudRate);
+ m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
/* check for an already opened connection */
if (m_communication->IsOpen())
{
ReplaceHandlers();
command.Clear();
- msg.Clear();
{
CLockObject lock(m_mutex);
if (m_commandBuffer.Pop(command))
bParseFrame = true;
- else if (m_communication->IsOpen() && m_communication->Read(msg, 50))
- {
- if ((bParseFrame = (ParseMessage(msg) && !IsStopped())) == true)
- command = m_currentframe;
- }
+ else if (m_communication->IsOpen() && m_communication->Read(command, 50))
+ bParseFrame = true;
}
if (bParseFrame)
bool CCECProcessor::Transmit(const cec_command &data)
{
- bool bReturn(false);
- LogOutput(data);
-
- CCECAdapterMessage *output = new CCECAdapterMessage(data);
-
- /* set the number of retries */
- if (data.opcode == CEC_OPCODE_NONE)
- output->maxTries = 1;
- else if (data.initiator != CECDEVICE_BROADCAST)
- output->maxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
-
- bReturn = Transmit(output);
-
- /* set to "not present" on failed ack */
- if (output->state == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED &&
- output->Destination() != CECDEVICE_BROADCAST)
- m_busDevices[output->Destination()]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
-
- delete output;
- return bReturn;
-}
-
-bool CCECProcessor::Transmit(CCECAdapterMessage *output)
-{
- bool bReturn(false);
- CLockObject lock(m_mutex);
+ cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
{
- if (!m_communication)
- return bReturn;
-
+ CLockObject lock(m_mutex);
+ LogOutput(data);
m_iLastTransmission = GetTimeMs();
- m_communication->SetLineTimeout(m_iStandardLineTimeout);
- output->tries = 0;
-
- do
- {
- if (output->tries > 0)
- m_communication->SetLineTimeout(m_iRetryLineTimeout);
- bReturn = m_communication->Write(output);
- if (!bReturn)
- Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
- }while (!bReturn && output->transmit_timeout > 0 && output->NeedsRetry() && ++output->tries < output->maxTries);
+ if (!m_communication)
+ return false;
+ uint8_t iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
+ retVal = m_communication->Write(data, iMaxTries, m_iLineTimeout, m_iRetryLineTimeout);
}
- m_communication->SetLineTimeout(m_iStandardLineTimeout);
+ /* set to "not present" on failed ack */
+ if (retVal == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED &&
+ data.destination != CECDEVICE_BROADCAST)
+ m_busDevices[data.destination]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
- return bReturn;
+ return retVal == ADAPTER_MESSAGE_STATE_SENT_ACKED;
}
void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
Transmit(command);
}
-bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
-{
- bool bEom(false);
- bool bIsError(msg.IsError());
-
- if (msg.IsEmpty())
- return bEom;
-
- switch(msg.Message())
- {
- case MSGCODE_FRAME_START:
- {
- m_currentframe.Clear();
- if (msg.Size() >= 2)
- {
- m_currentframe.initiator = msg.Initiator();
- m_currentframe.destination = msg.Destination();
- m_currentframe.ack = msg.IsACK();
- m_currentframe.eom = msg.IsEOM();
- }
- if (m_currentframe.ack == 0x1)
- {
- m_lastInitiator = m_currentframe.initiator;
- m_busDevices[m_lastInitiator]->GetHandler()->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
- }
- }
- break;
- case MSGCODE_RECEIVE_FAILED:
- {
- if (m_lastInitiator != CECDEVICE_UNKNOWN)
- bIsError = m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
- }
- break;
- case MSGCODE_FRAME_DATA:
- {
- if (msg.Size() >= 2)
- {
- m_currentframe.PushBack(msg[1]);
- m_currentframe.eom = msg.IsEOM();
- }
- bEom = msg.IsEOM();
- }
- break;
- default:
- break;
- }
-
- CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
- return bEom;
-}
-
void CCECProcessor::ParseCommand(cec_command &command)
{
CStdString dataStr;
void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
{
m_busDevices[initiator]->GetHandler()->HandlePoll(initiator, destination);
- m_lastInitiator = initiator;
}
-bool CCECProcessor::HandleReceiveFailed(void)
+bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
{
- return m_lastInitiator != CECDEVICE_UNKNOWN &&
- !m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
+ return !m_busDevices[initiator]->GetHandler()->HandleReceiveFailed();
}
#include <string>
#include <cectypes.h>
-#include "adapter/AdapterCommunication.h"
+#include "platform/threads/threads.h"
#include "platform/util/buffer.h"
-class CSerialPort;
-
namespace CEC
{
class CLibCEC;
- class CAdapterCommunication;
+ class IAdapterCommunication;
class CCECBusDevice;
class CCECProcessor : public PLATFORM::CThread
const char *ToString(const cec_vendor_id vendor);
virtual bool Transmit(const cec_command &data);
- virtual bool Transmit(CCECAdapterMessage *output);
virtual void TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
virtual bool ChangeDeviceType(cec_device_type from, cec_device_type to);
virtual bool StartBootloader(void);
virtual bool PingAdapter(void);
virtual void HandlePoll(cec_logical_address initiator, cec_logical_address destination);
- virtual bool HandleReceiveFailed(void);
+ virtual bool HandleReceiveFailed(cec_logical_address initiator);
CCECBusDevice * m_busDevices[16];
PLATFORM::CMutex m_transmitMutex;
bool FindLogicalAddressAudioSystem(void);
void LogOutput(const cec_command &data);
- bool ParseMessage(const CCECAdapterMessage &msg);
void ParseCommand(cec_command &command);
bool m_bStarted;
bool m_bInitialised;
uint8_t m_iHDMIPort;
cec_logical_address m_iBaseDevice;
- cec_command m_currentframe;
cec_logical_addresses m_logicalAddresses;
- cec_logical_address m_lastInitiator;
std::string m_strDeviceName;
cec_device_type_list m_types;
PLATFORM::CMutex m_mutex;
PLATFORM::CCondition m_startCondition;
- CAdapterCommunication* m_communication;
+ IAdapterCommunication * m_communication;
CLibCEC* m_controller;
bool m_bMonitor;
PLATFORM::SyncedBuffer<cec_command> m_commandBuffer;
#include "LibCEC.h"
-#include "adapter/AdapterCommunication.h"
-#include "adapter/AdapterDetection.h"
+#include "adapter/USBCECAdapterDetection.h"
#include "CECProcessor.h"
#include "devices/CECBusDevice.h"
#include "platform/util/timeutils.h"
strDebug.Format("trying to autodetect all CEC adapters");
AddLog(CEC_LOG_DEBUG, strDebug);
- return CAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
+ return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
}
bool CLibCEC::PingAdapter(void)
libcec_la_SOURCES = CECProcessor.cpp \
LibCEC.cpp \
LibCECC.cpp \
- adapter/AdapterCommunication.cpp \
- adapter/AdapterDetection.cpp \
+ adapter/USBCECAdapterCommunication.cpp \
+ adapter/USBCECAdapterDetection.cpp \
devices/CECAudioSystem.cpp \
devices/CECBusDevice.cpp \
devices/CECPlaybackDevice.cpp \
* http://www.pulse-eight.net/
*/
-#include <cectypes.h>
-#include "../platform/threads/threads.h"
-#include "../platform/util/buffer.h"
#include "../platform/util/StdString.h"
-namespace PLATFORM
-{
- class ISocket;
-}
-
namespace CEC
{
- class CCECProcessor;
- class CCECAdapterMessage;
+ typedef enum cec_adapter_message_state
+ {
+ ADAPTER_MESSAGE_STATE_UNKNOWN = 0, /**< the initial state */
+ ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT, /**< waiting in the send queue of the adapter, or timed out */
+ ADAPTER_MESSAGE_STATE_SENT, /**< sent and waiting on an ACK */
+ ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED, /**< sent, but failed to ACK */
+ ADAPTER_MESSAGE_STATE_SENT_ACKED, /**< sent, and ACK received */
+ ADAPTER_MESSAGE_STATE_INCOMING, /**< received from another device */
+ ADAPTER_MESSAGE_STATE_ERROR /**< an error occured */
+ } cec_adapter_message_state;
- class CAdapterCommunication : private PLATFORM::CThread
+ class IAdapterCommunication
{
public:
- CAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
- virtual ~CAdapterCommunication();
+ /*!
+ * @brief Open a connection to the CEC adapter
+ * @param iTimeoutMs Connection timeout in ms
+ * @return True when connected, false otherwise
+ */
+ virtual bool Open(uint32_t iTimeoutMs = 10000) = 0;
+
+ /*!
+ * @brief Close an open connection
+ */
+ virtual void Close(void) = 0;
+
+ /*!
+ * @return True when the connection is open, false otherwise
+ */
+ virtual bool IsOpen(void) = 0;
+
+ /*!
+ * @return The last error message, or an empty string if there was none
+ */
+ virtual CStdString GetError(void) const = 0;
+
+ /*!
+ * @brief Reads one cec_command from the adapter
+ * @param command The command that will be read (output)
+ * @param iTimeout The read timeout
+ * @return True when a command has been read, false otherwise.
+ */
+ virtual bool Read(cec_command &command, uint32_t iTimeout) = 0;
- bool Open(uint32_t iTimeoutMs = 10000);
- bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000);
- bool Write(CCECAdapterMessage *data);
- void Close(void);
- bool IsOpen(void);
- CStdString GetError(void) const;
+ /*!
+ * @brief Write a cec_command to the adapter
+ * @param data The command to write
+ * @param iMaxTries The maximum number of tries
+ * @param iLineTimeout The line timeout for the first try
+ * @param iRetryLineTimeout The line timeout for each next try
+ * @return The last state of the transmitted command
+ */
+ virtual cec_adapter_message_state Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout = 3, uint8_t iRetryLineTimeout = 3) = 0;
- void *Process(void);
+ /*!
+ * @brief Change the current line timeout on the CEC bus
+ * @param iTimeout The new timeout
+ * @return True when set, false otherwise
+ */
+ virtual bool SetLineTimeout(uint8_t iTimeout) = 0;
- bool SetLineTimeout(uint8_t iTimeout);
- bool StartBootloader(void);
- bool SetAckMask(uint16_t iMask);
- bool PingAdapter(void);
- uint16_t GetFirmwareVersion(void);
+ /*!
+ * @brief Put the device in bootloader mode (which will disrupt CEC communication when it succeeds)
+ * @return True when the bootloader command has been sent, false otherwise.
+ */
+ virtual bool StartBootloader(void) = 0;
- bool WaitForAck(CCECAdapterMessage &message);
+ /*!
+ * @brief Change the ACK-mask of the device, the mask for logical addresses to which the CEC device should ACK
+ * @param iMask The new mask
+ * @return True when set, false otherwise.
+ */
+ virtual bool SetAckMask(uint16_t iMask) = 0;
- private:
- void SendMessageToAdapter(CCECAdapterMessage *msg);
- void WriteNextCommand(void);
- void AddData(uint8_t *data, size_t iLen);
- bool ReadFromDevice(uint32_t iTimeout);
+ /*!
+ * @brief Check whether the CEC adapter responds
+ * @return True when the ping was sent and acked, false otherwise.
+ */
+ virtual bool PingAdapter(void) = 0;
- PLATFORM::ISocket * m_port;
- CCECProcessor * m_processor;
- PLATFORM::SyncedBuffer<uint8_t> m_inBuffer;
- PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_outBuffer;
- PLATFORM::CMutex m_mutex;
- PLATFORM::CCondition m_rcvCondition;
- uint8_t m_iLineTimeout;
- uint16_t m_iFirmwareVersion;
+ /*!
+ * @return The firmware version of this CEC adapter.
+ */
+ virtual uint16_t GetFirmwareVersion(void) = 0;
};
};
* http://www.pulse-eight.net/
*/
-#include "AdapterCommunication.h"
-
-#include "AdapterMessage.h"
-#include "../CECProcessor.h"
+#include "USBCECAdapterCommunication.h"
#include "../platform/sockets/serialport.h"
#include "../platform/util/timeutils.h"
#include "../LibCEC.h"
+#include "../CECProcessor.h"
using namespace std;
using namespace CEC;
using namespace PLATFORM;
-CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate /* = 38400 */) :
+CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate /* = 38400 */) :
m_port(NULL),
m_processor(processor),
m_iLineTimeout(0),
- m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN)
+ m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN),
+ m_lastInitiator(CECDEVICE_UNKNOWN),
+ m_bNextIsEscaped(false),
+ m_bGotStart(false)
{
m_port = new PLATFORM::CSerialPort(strPort, iBaudRate);
}
-CAdapterCommunication::~CAdapterCommunication(void)
+CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
{
Close();
}
}
-bool CAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
{
uint64_t iNow = GetTimeMs();
uint64_t iTimeout = iNow + iTimeoutMs;
return false;
}
-void CAdapterCommunication::Close(void)
+void CUSBCECAdapterCommunication::Close(void)
{
CLockObject lock(m_mutex);
m_rcvCondition.Broadcast();
StopThread();
}
-void *CAdapterCommunication::Process(void)
+void *CUSBCECAdapterCommunication::Process(void)
{
while (!IsStopped())
{
return NULL;
}
-bool CAdapterCommunication::Write(CCECAdapterMessage *data)
+cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout /* = 3 */, uint8_t iRetryLineTimeout /* = 3 */)
+{
+ cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
+
+ CCECAdapterMessage *output = new CCECAdapterMessage(data);
+
+ /* set the number of retries */
+ if (data.opcode == CEC_OPCODE_NONE) //TODO
+ output->maxTries = 1;
+ else if (data.initiator != CECDEVICE_BROADCAST)
+ output->maxTries = iMaxTries;
+
+ output->lineTimeout = iLineTimeout;
+ output->retryTimeout = iRetryLineTimeout;
+ output->tries = 0;
+
+ bool bRetry(true);
+ while (bRetry && ++output->tries < output->maxTries)
+ {
+ bRetry = (!Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
+ if (bRetry)
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+ }
+ retVal = output->state;
+
+ delete output;
+ return retVal;
+}
+
+bool CUSBCECAdapterCommunication::Write(CCECAdapterMessage *data)
{
bool bReturn(false);
return bReturn;
}
-bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::Read(cec_command &command, 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)
+ CCECAdapterMessage msg;
+ if (Read(msg, iTimeout))
{
- uint8_t buf = 0;
- if (!m_inBuffer.Pop(buf))
+ if (ParseMessage(msg))
{
- if (!m_rcvCondition.Wait(m_mutex, (uint32_t) (iTarget - iNow)))
- return false;
+ command = m_currentframe;
+ m_currentframe.Clear();
+ return true;
}
+ }
+ 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
- {
- if (msg.Size() > 0)
- CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
- msg.Clear();
- bGotStart = true;
- }
+bool CUSBCECAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
+{
+ CLockObject lock(m_mutex);
- if (buf == MSGEND)
- {
- bGotFullMessage = true;
- }
- else if (bNextIsEscaped)
- {
- msg.PushBack(buf + (uint8_t)ESCOFFSET);
- bNextIsEscaped = false;
- }
- else if (buf == MSGESC)
- bNextIsEscaped = true;
- else
- msg.PushBack(buf);
- }
+ msg.Clear();
+ CCECAdapterMessage *buf(NULL);
- if (bGotFullMessage)
- msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
+ if (!m_inBuffer.Pop(buf))
+ {
+ if (!m_rcvCondition.Wait(m_mutex, iTimeout))
+ return false;
+ m_inBuffer.Pop(buf);
+ }
- return bGotFullMessage;
+ if (buf)
+ {
+ msg.packet = buf->packet;
+ msg.state = msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
+ delete buf;
+ return true;
+ }
+ return false;
}
-CStdString CAdapterCommunication::GetError(void) const
+CStdString CUSBCECAdapterCommunication::GetError(void) const
{
CStdString strError;
strError = m_port->GetError();
return strError;
}
-bool CAdapterCommunication::StartBootloader(void)
+bool CUSBCECAdapterCommunication::StartBootloader(void)
{
bool bReturn(false);
if (!IsRunning())
return bReturn;
}
-bool CAdapterCommunication::PingAdapter(void)
+bool CUSBCECAdapterCommunication::PingAdapter(void)
{
bool bReturn(false);
if (!IsRunning())
return bReturn;
}
-uint16_t CAdapterCommunication::GetFirmwareVersion(void)
+bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
+{
+ bool bEom(false);
+ bool bIsError(msg.IsError());
+
+ if (msg.IsEmpty())
+ return bEom;
+
+ switch(msg.Message())
+ {
+ case MSGCODE_FRAME_START:
+ {
+ m_currentframe.Clear();
+ if (msg.Size() >= 2)
+ {
+ m_currentframe.initiator = msg.Initiator();
+ m_currentframe.destination = msg.Destination();
+ m_currentframe.ack = msg.IsACK();
+ m_currentframe.eom = msg.IsEOM();
+ }
+ if (m_currentframe.ack == 0x1)
+ {
+ m_lastInitiator = m_currentframe.initiator;
+ m_processor->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
+ }
+ }
+ break;
+ case MSGCODE_RECEIVE_FAILED:
+ {
+ m_currentframe.Clear();
+ if (m_lastInitiator != CECDEVICE_UNKNOWN)
+ bIsError = m_processor->HandleReceiveFailed(m_lastInitiator);
+ }
+ break;
+ case MSGCODE_FRAME_DATA:
+ {
+ if (msg.Size() >= 2)
+ {
+ m_currentframe.PushBack(msg[1]);
+ m_currentframe.eom = msg.IsEOM();
+ }
+ bEom = msg.IsEOM();
+ }
+ break;
+ default:
+ break;
+ }
+
+ CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
+ return bEom;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
{
uint16_t iReturn(m_iFirmwareVersion);
if (!IsRunning())
return iReturn;
}
-bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
+bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
{
- bool bReturn(m_iLineTimeout != iTimeout);
-
- if (!bReturn)
- {
- CCECAdapterMessage *output = new CCECAdapterMessage;
-
- output->PushBack(MSGSTART);
- output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME);
- output->PushEscaped(iTimeout);
- output->PushBack(MSGEND);
- output->isTransmission = false;
-
- if ((bReturn = Write(output)) == false)
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the idletime");
- delete output;
- }
-
- return bReturn;
+ m_iLineTimeout = iTimeout;
+ return true;
+ //TODO
+// bool bReturn(m_iLineTimeout != iTimeout);
+//
+// if (!bReturn)
+// {
+// CCECAdapterMessage *output = new CCECAdapterMessage;
+//
+// output->PushBack(MSGSTART);
+// output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME);
+// output->PushEscaped(iTimeout);
+// output->PushBack(MSGEND);
+// output->isTransmission = false;
+//
+// if ((bReturn = Write(output)) == false)
+// CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the idletime");
+// delete output;
+// }
+//
+// return bReturn;
}
-bool CAdapterCommunication::SetAckMask(uint16_t iMask)
+bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
{
bool bReturn(false);
CStdString strLog;
return bReturn;
}
-bool CAdapterCommunication::IsOpen(void)
+bool CUSBCECAdapterCommunication::IsOpen(void)
{
return !IsStopped() && m_port->IsOpen() && IsRunning();
}
-bool CAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
+bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
{
bool bError(false);
bool bTransmitSucceeded(false);
if (msg.Message() == MSGCODE_FRAME_START && msg.IsACK())
{
m_processor->HandlePoll(msg.Initiator(), msg.Destination());
+ m_lastInitiator = msg.Initiator();
iNow = GetTimeMs();
continue;
}
if (msg.Message() == MSGCODE_RECEIVE_FAILED &&
- m_processor->HandleReceiveFailed())
+ m_lastInitiator != CECDEVICE_UNKNOWN &&
+ m_processor->HandleReceiveFailed(m_lastInitiator))
{
iNow = GetTimeMs();
continue;
return bTransmitSucceeded && !bError;
}
-void CAdapterCommunication::AddData(uint8_t *data, size_t iLen)
+void CUSBCECAdapterCommunication::AddData(uint8_t *data, size_t iLen)
{
CLockObject lock(m_mutex);
for (size_t iPtr = 0; iPtr < iLen; iPtr++)
- m_inBuffer.Push(data[iPtr]);
-
- m_rcvCondition.Signal();
+ {
+ if (!m_bGotStart)
+ {
+ if (data[iPtr] == MSGSTART)
+ m_bGotStart = true;
+ }
+ else if (data[iPtr] == MSGSTART) //we found a msgstart before msgend, this is not right, remove
+ {
+ if (m_currentAdapterMessage.Size() > 0)
+ CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+ m_currentAdapterMessage.Clear();
+ m_bGotStart = true;
+ }
+ else if (data[iPtr] == MSGEND)
+ {
+ CCECAdapterMessage *newMessage = new CCECAdapterMessage;
+ newMessage->packet = m_currentAdapterMessage.packet;
+ m_inBuffer.Push(newMessage);
+ m_currentAdapterMessage.Clear();
+ m_bGotStart = false;
+ m_bNextIsEscaped = false;
+ m_rcvCondition.Signal();
+ }
+ else if (m_bNextIsEscaped)
+ {
+ m_currentAdapterMessage.PushBack(data[iPtr] + (uint8_t)ESCOFFSET);
+ m_bNextIsEscaped = false;
+ }
+ else if (data[iPtr] == MSGESC)
+ {
+ m_bNextIsEscaped = true;
+ }
+ else
+ {
+ m_currentAdapterMessage.PushBack(data[iPtr]);
+ }
+ }
}
-bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
{
ssize_t iBytesRead;
uint8_t buff[256];
return iBytesRead > 0;
}
-void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
+void CUSBCECAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
{
CLockObject adapterLock(m_mutex);
CLockObject lock(msg->mutex);
+ if (msg->tries == 1)
+ SetLineTimeout(msg->lineTimeout);
+ else
+ SetLineTimeout(msg->retryTimeout);
+
if (m_port->Write(msg->packet.data, msg->Size()) != (ssize_t) msg->Size())
{
CStdString strError;
msg->condition.Signal();
}
-void CAdapterCommunication::WriteNextCommand(void)
+void CUSBCECAdapterCommunication::WriteNextCommand(void)
{
CCECAdapterMessage *msg(NULL);
if (m_outBuffer.Pop(msg))
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include <cectypes.h>
+#include "../platform/threads/threads.h"
+#include "../platform/util/buffer.h"
+#include "AdapterCommunication.h"
+#include "USBCECAdapterMessage.h"
+
+namespace PLATFORM
+{
+ class ISocket;
+}
+
+namespace CEC
+{
+ class CCECProcessor;
+
+ class CUSBCECAdapterCommunication : public IAdapterCommunication, private PLATFORM::CThread
+ {
+ public:
+ CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
+ virtual ~CUSBCECAdapterCommunication();
+
+ virtual bool Open(uint32_t iTimeoutMs = 10000);
+ virtual void Close(void);
+ virtual bool IsOpen(void);
+ virtual CStdString GetError(void) const;
+
+ bool Read(cec_command &command, uint32_t iTimeout);
+ cec_adapter_message_state Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout = 3, uint8_t iRetryLineTimeout = 3);
+
+ virtual bool SetLineTimeout(uint8_t iTimeout);
+ virtual bool StartBootloader(void);
+ virtual bool SetAckMask(uint16_t iMask);
+ virtual bool PingAdapter(void);
+ virtual uint16_t GetFirmwareVersion(void);
+
+ void *Process(void);
+ private:
+ bool Write(CCECAdapterMessage *data);
+ bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000);
+ bool ParseMessage(const CCECAdapterMessage &msg);
+ void SendMessageToAdapter(CCECAdapterMessage *msg);
+ void WriteNextCommand(void);
+ void AddData(uint8_t *data, size_t iLen);
+ bool ReadFromDevice(uint32_t iTimeout);
+ bool WaitForAck(CCECAdapterMessage &message);
+
+ PLATFORM::ISocket * m_port;
+ CCECProcessor * m_processor;
+ PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_inBuffer;
+ PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_outBuffer;
+ PLATFORM::CMutex m_mutex;
+ PLATFORM::CCondition m_rcvCondition;
+ uint8_t m_iLineTimeout;
+ uint16_t m_iFirmwareVersion;
+ cec_command m_currentframe;
+ cec_logical_address m_lastInitiator;
+ CCECAdapterMessage m_currentAdapterMessage;
+ bool m_bNextIsEscaped;
+ bool m_bGotStart;
+ };
+};
* http://www.pulse-eight.net/
*/
-#include "AdapterDetection.h"
+#include "USBCECAdapterDetection.h"
#include "../platform/util/StdString.h"
#if defined(__APPLE__)
}
#endif
-uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
{
uint8_t iFound(0);
namespace CEC
{
- class CAdapterDetection
+ class CUSBCECAdapterDetection
{
public:
static uint8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
namespace CEC
{
- typedef enum cec_adapter_message_state
- {
- ADAPTER_MESSAGE_STATE_UNKNOWN = 0,
- ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT,
- ADAPTER_MESSAGE_STATE_SENT,
- ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED,
- ADAPTER_MESSAGE_STATE_SENT_ACKED,
- ADAPTER_MESSAGE_STATE_INCOMING,
- ADAPTER_MESSAGE_STATE_ERROR
- } cec_adapter_message_state;
-
-
class CCECAdapterMessage
{
public:
reply = MSGCODE_NOTHING;
isTransmission = true;
expectControllerAck = true;
+ lineTimeout = 3;
+ retryTimeout = 3;
}
void Shift(uint8_t iShiftBy)
int32_t transmit_timeout;
bool isTransmission;
bool expectControllerAck;
+ uint8_t lineTimeout;
+ uint8_t retryTimeout;
PLATFORM::CMutex mutex;
PLATFORM::CCondition condition;
};