extern "C" {
namespace CEC {
#endif
- #define CEC_MIN_VERSION 2
+ #define CEC_MIN_VERSION 3
#define CEC_LIB_VERSION 3
#define CEC_SETTLE_DOWN_TIME 1000
+ #define CEC_BUTTON_TIMEOUT 500
typedef std::vector<uint8_t> cec_frame;
unsigned int duration;
} cec_keypress;
- typedef struct cec_device
+ typedef struct cec_adapter
{
std::string path;
std::string comm;
- } cec_device;
+ } cec_adapter;
typedef struct cec_command
{
*/
extern DECLSPEC void cec_close(void);
+/*!
+ * @brief Try to find all connected CEC adapters. Only implemented on Linux at the moment.
+ * @param deviceList The vector to store device descriptors in.
+ * @param strDevicePath Optional device path. Only adds device descriptors that match the given device path.
+ * @return The number of devices that were found, or -1 when an error occured.
+ */
+#ifdef __cplusplus
+extern DECLSPEC int cec_find_adapters(std::vector<CEC::cec_adapter> &deviceList, const char *strDevicePath = NULL);
+#else
+extern DECLSPEC int cec_find_adapters(std::vector<cec_adapter> &deviceList, const char *strDevicePath = NULL);
+#endif
+
/*!
* @brief Ping the CEC adapter.
* @return True when the ping was succesful, false otherwise.
*/
-extern DECLSPEC bool cec_ping(void);
+extern DECLSPEC bool cec_ping_adapters(void);
/*!
* @brief Start the bootloader of the CEC adapter.
extern DECLSPEC bool cec_start_bootloader(void);
/*!
- * @depcrecated Use cec_standby_devices() instead
+ * @return Get the minimal version of libcec that this version of libcec can interface with.
+ */
+extern DECLSPEC int cec_get_min_version(void);
+
+/*!
+ * @return Get the version of libcec.
*/
-#ifdef __cplusplus
-extern DECLSPEC bool cec_power_off_devices(CEC::cec_logical_address address = CEC::CECDEVICE_BROADCAST);
-#else
-extern DECLSPEC bool cec_power_off_devices(cec_logical_address address = CECDEVICE_BROADCAST);
-#endif
+extern DECLSPEC int cec_get_lib_version(void);
/*!
* @brief Power on the connected CEC capable devices.
extern DECLSPEC bool cec_set_logical_address(cec_logical_address myAddress, cec_logical_address targetAddress);
#endif
-/*!
- * @deprecated Use cec_set_logical_address() instead.
- * @brief Set the ack mask of the CEC adapter.
- * @param iMask The cec adapter's ack mask.
- * @return True when the ack mask was sent succesfully, false otherwise.
- */
-extern DECLSPEC bool cec_set_ack_mask(uint16_t iMask);
-
-/*!
- * @return Get the minimal version of libcec that this version of libcec can interface with.
- */
-extern DECLSPEC int cec_get_min_version(void);
-
-/*!
- * @return Get the version of libcec.
- */
-extern DECLSPEC int cec_get_lib_version(void);
-
-/*!
- * @brief Try to find all connected CEC adapters. Only implemented on Linux at the moment.
- * @param deviceList The vector to store device descriptors in.
- * @param strDevicePath Optional device path. Only adds device descriptors that match the given device path.
- * @return The number of devices that were found, or -1 when an error occured.
- */
-#ifdef __cplusplus
-extern DECLSPEC int cec_find_devices(std::vector<CEC::cec_device> &deviceList, const char *strDevicePath = NULL);
-#else
-extern DECLSPEC int cec_find_devices(std::vector<cec_device> &deviceList, const char *strDevicePath = NULL);
-#endif
-
#ifdef __cplusplus
};
#endif
namespace CEC
{
- class ICECDevice
+ class ICECAdapter
{
public:
+ /*! @name Adapter methods */
+ //@{
/*!
* @see cec_open
*/
virtual void Close(void) = 0;
/*!
- * @see cec_find_devices
+ * @see cec_find_adapters
*/
- virtual int FindDevices(std::vector<cec_device> &deviceList, const char *strDevicePath = NULL) = 0;
+ virtual int FindAdapters(std::vector<cec_adapter> &deviceList, const char *strDevicePath = NULL) = 0;
/*!
- * @see cec_ping
+ * @see cec_ping_adapters
*/
- virtual bool Ping(void) = 0;
+ virtual bool PingAdapter(void) = 0;
/*!
* @see cec_start_bootloader
*/
virtual bool StartBootloader(void) = 0;
+ //@}
/*!
- * @depcrecated Use StandbyDevices() instead
- */
- virtual bool PowerOffDevices(cec_logical_address address = CECDEVICE_BROADCAST) = 0;
-
- /*!
- * @see cec_power_on_devices
- */
- virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_BROADCAST) = 0;
-
- /*!
- * @see cec_standby_devices
- */
- virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST) = 0;
-
- /*!
- * @see cec_set_active_view
+ * @see cec_get_min_version
*/
- virtual bool SetActiveView(void) = 0;
+ virtual int GetMinVersion(void) = 0;
/*!
- * @see cec_set_inactive_view
+ * @see cec_get_lib_version
*/
- virtual bool SetInactiveView(void) = 0;
+ virtual int GetLibVersion(void) = 0;
/*!
* @see cec_get_next_log_message
virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress) = 0;
/*!
- * @deprecated use SetLogicalAddress() instead
+ * @see cec_power_on_devices
*/
- virtual bool SetAckMask(uint16_t iMask) = 0;
+ virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV) = 0;
/*!
- * @see cec_get_min_version
+ * @see cec_standby_devices
*/
- virtual int GetMinVersion(void) = 0;
+ virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST) = 0;
/*!
- * @see cec_get_lib_version
+ * @see cec_set_active_view
*/
- virtual int GetLibVersion(void) = 0;
+ virtual bool SetActiveView(void) = 0;
+
+ /*!
+ * @see cec_set_inactive_view
+ */
+ virtual bool SetInactiveView(void) = 0;
+
};
};
/*!
* @see cec_init
*/
-inline CEC::ICECDevice *LoadLibCec(const char *strName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS)
+inline CEC::ICECAdapter *LoadLibCec(const char *strName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS)
{
typedef void* (__cdecl*_CreateLibCec)(const char *, uint8_t, uint8_t);
_CreateLibCec CreateLibCec;
CreateLibCec = (_CreateLibCec) (GetProcAddress(g_libCEC, "CECCreate"));
if (!CreateLibCec)
return NULL;
- return static_cast< CEC::ICECDevice* > (CreateLibCec(strName, iLogicalAddress, iPhysicalAddress));
+ return static_cast< CEC::ICECAdapter* > (CreateLibCec(strName, iLogicalAddress, iPhysicalAddress));
}
/*!
* @brief Unload the given libcec instance.
* @param device The instance to unload.
*/
-inline void UnloadLibCec(CEC::ICECDevice *device)
+inline void UnloadLibCec(CEC::ICECAdapter *device)
{
delete device;
/*!
* @see cec_init
*/
-inline CEC::ICECDevice *LoadLibCec(const char *strName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS)
+inline CEC::ICECAdapter *LoadLibCec(const char *strName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS)
{
- return (CEC::ICECDevice*) CECCreate(strName, iLogicalAddress, iPhysicalAddress);
+ return (CEC::ICECAdapter*) CECCreate(strName, iLogicalAddress, iPhysicalAddress);
};
/*!
* @brief Unload the given libcec instance.
* @param device The instance to unload.
*/
-inline void UnloadLibCec(CEC::ICECDevice *device)
+inline void UnloadLibCec(CEC::ICECAdapter *device)
{
delete device;
};
* http://www.pulse-eight.net/
*/
-#include <stdint.h>
-#include <vector>
-#include <string>
-#include "CECExports.h"
-
typedef enum
{
CEC_ABORT_REASON_UNRECOGNIZED_OPCODE = 0,
*/
#include "AdapterCommunication.h"
-#include "CECParser.h"
+
+#include "LibCEC.h"
#include "libPlatform/serialport.h"
#include "util/StdString.h"
using namespace std;
using namespace CEC;
-CAdapterCommunication::CAdapterCommunication(CCECParser *parser) :
- m_parser(parser),
+CAdapterCommunication::CAdapterCommunication(CLibCEC *controller) :
+ m_controller(controller),
m_inbuf(NULL),
m_iInbufSize(0),
m_iInbufUsed(0),
{
CStdString strError;
strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str());
- m_parser->AddLog(CEC_LOG_ERROR, strError);
+ m_controller->AddLog(CEC_LOG_ERROR, strError);
return false;
}
- m_parser->AddLog(CEC_LOG_DEBUG, "connection opened");
+ m_controller->AddLog(CEC_LOG_DEBUG, "connection opened");
//clear any input bytes
uint8_t buff[1024];
if (CreateThread())
{
- m_parser->AddLog(CEC_LOG_DEBUG, "reader thread created");
+ m_controller->AddLog(CEC_LOG_DEBUG, "reader thread created");
return true;
}
else
{
- m_parser->AddLog(CEC_LOG_DEBUG, "could not create a reader thread");
+ m_controller->AddLog(CEC_LOG_DEBUG, "could not create a reader thread");
}
return false;
CCondition::Sleep(50);
}
- m_parser->AddLog(CEC_LOG_DEBUG, "reader thread terminated");
+ m_controller->AddLog(CEC_LOG_DEBUG, "reader thread terminated");
CLockObject lock(&m_commMutex);
m_bStarted = false;
{
CStdString strError;
strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
- m_parser->AddLog(CEC_LOG_ERROR, strError);
+ m_controller->AddLog(CEC_LOG_ERROR, strError);
return false;
}
else if (iBytesRead > 0)
{
CStdString strError;
strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
- m_parser->AddLog(CEC_LOG_ERROR, strError);
+ m_controller->AddLog(CEC_LOG_ERROR, strError);
return false;
}
- m_parser->AddLog(CEC_LOG_DEBUG, "command sent");
+ m_controller->AddLog(CEC_LOG_DEBUG, "command sent");
+
+ CCondition::Sleep((int) data.size() * 24 /*data*/ + 5 /*start bit (4.5 ms)*/ + 50 /* to be on the safe side */);
+
return true;
}
if (startpos > 0) //we found a msgstart before msgend, this is not right, remove
{
- m_parser->AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
+ m_controller->AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
m_iInbufUsed -= startpos;
return false;
{
return m_port->GetError();
}
+
+bool CAdapterCommunication::StartBootloader(void)
+{
+ if (!IsRunning())
+ return false;
+
+ m_controller->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+ cec_frame output;
+ output.push_back(MSGSTART);
+ PushEscaped(output, MSGCODE_START_BOOTLOADER);
+ output.push_back(MSGEND);
+
+ if (!Write(output))
+ {
+ m_controller->AddLog(CEC_LOG_ERROR, "could not start the bootloader");
+ return false;
+ }
+ m_controller->AddLog(CEC_LOG_DEBUG, "bootloader start command transmitted");
+ return true;
+}
+
+void CAdapterCommunication::PushEscaped(cec_frame &vec, uint8_t byte)
+{
+ if (byte >= MSGESC && byte != MSGSTART)
+ {
+ vec.push_back(MSGESC);
+ vec.push_back(byte - ESCOFFSET);
+ }
+ else
+ {
+ vec.push_back(byte);
+ }
+}
+
+bool CAdapterCommunication::SetAckMask(uint16_t iMask)
+{
+ if (!IsRunning())
+ return false;
+
+ CStdString strLog;
+ strLog.Format("setting ackmask to %2x", iMask);
+ m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+
+ cec_frame output;
+
+ output.push_back(MSGSTART);
+ PushEscaped(output, MSGCODE_SET_ACK_MASK);
+ PushEscaped(output, iMask >> 8);
+ PushEscaped(output, (uint8_t)iMask);
+ output.push_back(MSGEND);
+
+ if (!Write(output))
+ {
+ m_controller->AddLog(CEC_LOG_ERROR, "could not set the ackmask");
+ return false;
+ }
+
+ return true;
+}
+
+bool CAdapterCommunication::PingAdapter(void)
+{
+ if (!IsRunning())
+ return false;
+
+ m_controller->AddLog(CEC_LOG_DEBUG, "sending ping");
+ cec_frame output;
+ output.push_back(MSGSTART);
+ PushEscaped(output, MSGCODE_PING);
+ output.push_back(MSGEND);
+
+ if (!Write(output))
+ {
+ m_controller->AddLog(CEC_LOG_ERROR, "could not send ping command");
+ return false;
+ }
+
+ m_controller->AddLog(CEC_LOG_DEBUG, "ping tranmitted");
+
+ // TODO check for pong
+ return true;
+}
* http://www.pulse-eight.net/
*/
-#include <queue>
-#include <stdio.h>
#include "../../include/CECExports.h"
-#include "../../include/CECTypes.h"
-#include "util/buffer.h"
#include "util/threads.h"
class CSerialPort;
namespace CEC
{
- class CCECParser;
+ class CLibCEC;
class CAdapterCommunication : CThread
{
public:
- CAdapterCommunication(CCECParser *parser);
+ CAdapterCommunication(CLibCEC *controller);
virtual ~CAdapterCommunication();
bool Open(const char *strPort, int iBaudRate = 38400, int iTimeoutMs = 10000);
bool Read(cec_frame &msg, int iTimeout = 1000);
bool Write(const cec_frame &frame);
+ bool PingAdapter(void);
void Close(void);
bool IsOpen(void) const { return !m_bStop && m_bStarted; }
std::string GetError(void) const;
void *Process(void);
+
+ bool StartBootloader(void);
+ bool SetAckMask(uint16_t iMask);
+ static void PushEscaped(cec_frame &vec, uint8_t byte);
private:
void AddData(uint8_t *data, int iLen);
bool ReadFromDevice(int iTimeout);
CSerialPort * m_port;
- CCECParser * m_parser;
+ CLibCEC * m_controller;
uint8_t* m_inbuf;
int m_iInbufSize;
int m_iInbufUsed;
* http://www.pulse-eight.net/
*/
-#include "CECDetect.h"
+#include "AdapterDetection.h"
#include "libPlatform/os-dependent.h"
#include "util/StdString.h"
-#include <string.h>
#if !defined(__WINDOWS__)
#include <dirent.h>
}
#endif
-int CCECDetect::FindDevices(vector<cec_device> &deviceList, const char *strDevicePath /* = NULL */)
+int CAdapterDetection::FindAdapters(vector<cec_adapter> &deviceList, const char *strDevicePath /* = NULL */)
{
int iFound(0);
CStdString strComm(strPath);
if (FindComPort(strComm))
{
- cec_device foundDev;
+ cec_adapter foundDev;
foundDev.path = strPath;
foundDev.comm = strComm;
deviceList.push_back(foundDev);
if (_tcslen(strPortName) > 3 && _tcsnicmp(strPortName, _T("COM"), 3) == 0 &&
_ttoi(&(strPortName[3])) > 0)
{
- cec_device foundDev;
+ cec_adapter foundDev;
foundDev.path = devicedetailData->DevicePath;
foundDev.comm = strPortName;
deviceList.push_back(foundDev);
namespace CEC
{
- class CCECDetect
+ class CAdapterDetection
{
public:
- static int FindDevices(std::vector<cec_device> &deviceList, const char *strDevicePath = NULL);
+ static int FindAdapters(std::vector<cec_adapter> &deviceList, const char *strDevicePath = NULL);
};
};
* http://www.pulse-eight.net/
*/
-#include "CECParser.h"
+#include "CECProcessor.h"
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <sys/stat.h>
+#include "AdapterCommunication.h"
+#include "LibCEC.h"
#include "util/StdString.h"
-#include "libPlatform/serialport.h"
-#include "util/threads.h"
#include "util/timeutils.h"
-#include "CECDetect.h"
-#include "AdapterCommunication.h"
using namespace CEC;
using namespace std;
-#define CEC_MAX_RETRY 5
-#define CEC_BUTTON_TIMEOUT 500
-
-/*!
- * ICECDevice implementation
- */
-//@{
-CCECParser::CCECParser(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
- m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
m_physicaladdress(iPhysicalAddress),
m_iLogicalAddress(iLogicalAddress),
- m_strDeviceName(strDeviceName)
+ m_strDeviceName(strDeviceName),
+ m_communication(serComm),
+ m_controller(controller)
{
- m_communication = new CAdapterCommunication(this);
}
-CCECParser::~CCECParser(void)
+CCECProcessor::~CCECProcessor(void)
{
- Close();
- m_communication->Close();
- delete m_communication;
+ StopThread();
+ m_communication = NULL;
+ m_controller = NULL;
}
-bool CCECParser::Open(const char *strPort, int iTimeoutMs /* = 10000 */)
+bool CCECProcessor::Start(void)
{
- if (!m_communication)
- return false;
-
- if (m_communication->IsOpen())
- {
- AddLog(CEC_LOG_ERROR, "connection already open");
+ if (!m_communication || !m_communication->IsOpen())
return false;
- }
-
- if (!m_communication->Open(strPort, 38400, iTimeoutMs))
- {
- AddLog(CEC_LOG_ERROR, "could not open a connection");
- return false;
- }
if (!SetLogicalAddress(m_iLogicalAddress))
{
- AddLog(CEC_LOG_ERROR, "could not set the logical address");
+ m_controller->AddLog(CEC_LOG_ERROR, "could not set the logical address");
return false;
}
if (CreateThread())
return true;
else
- AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+ m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
return false;
}
-void CCECParser::Close(void)
+void *CCECProcessor::Process(void)
{
- StopThread();
-}
-
-void *CCECParser::Process(void)
-{
- AddLog(CEC_LOG_DEBUG, "processor thread started");
+ m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
- int64_t now = GetTimeMs();
while (!m_bStop)
{
bool bParseFrame(false);
if (bParseFrame)
ParseCurrentFrame();
- now = GetTimeMs();
- CheckKeypressTimeout(now);
+ m_controller->CheckKeypressTimeout();
CCondition::Sleep(50);
}
- AddLog(CEC_LOG_DEBUG, "processor thread terminated");
+ m_controller->AddLog(CEC_LOG_DEBUG, "processor thread terminated");
return NULL;
}
-bool CCECParser::Ping(void)
-{
- if (!IsRunning())
- return false;
-
- AddLog(CEC_LOG_DEBUG, "sending ping");
- cec_frame output;
- output.push_back(MSGSTART);
- PushEscaped(output, MSGCODE_PING);
- output.push_back(MSGEND);
-
- if (!TransmitFormatted(output, false))
- {
- AddLog(CEC_LOG_ERROR, "could not send ping command");
- return false;
- }
-
- AddLog(CEC_LOG_DEBUG, "ping tranmitted");
-
- // TODO check for pong
- return true;
-}
-
-bool CCECParser::StartBootloader(void)
-{
- if (!IsRunning())
- return false;
-
- AddLog(CEC_LOG_DEBUG, "starting the bootloader");
- cec_frame output;
- output.push_back(MSGSTART);
- PushEscaped(output, MSGCODE_START_BOOTLOADER);
- output.push_back(MSGEND);
-
- if (!TransmitFormatted(output, false))
- {
- AddLog(CEC_LOG_ERROR, "could not start the bootloader");
- return false;
- }
-
- AddLog(CEC_LOG_DEBUG, "bootloader start command transmitted");
- return true;
-}
-
-uint8_t CCECParser::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */)
-{
- return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
-}
-
-bool CCECParser::PowerOffDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
-{
- return StandbyDevices(address);
-}
-
-bool CCECParser::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
+bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
{
if (!IsRunning())
return false;
CStdString strLog;
strLog.Format("powering on devices with logical address %d", (int8_t)address);
- AddLog(CEC_LOG_DEBUG, strLog.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
cec_frame frame;
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_TEXT_VIEW_ON);
return Transmit(frame);
}
-bool CCECParser::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
{
if (!IsRunning())
return false;
CStdString strLog;
strLog.Format("putting all devices with logical address %d in standby mode", (int8_t)address);
- AddLog(CEC_LOG_DEBUG, strLog.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
cec_frame frame;
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_STANDBY);
return Transmit(frame);
}
-bool CCECParser::SetActiveView(void)
+bool CCECProcessor::SetActiveView(void)
{
if (!IsRunning())
return false;
- AddLog(CEC_LOG_DEBUG, "setting active view");
+ m_controller->AddLog(CEC_LOG_DEBUG, "setting active view");
cec_frame frame;
frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
frame.push_back(CEC_OPCODE_ACTIVE_SOURCE);
return Transmit(frame);
}
-bool CCECParser::SetInactiveView(void)
+bool CCECProcessor::SetInactiveView(void)
{
if (!IsRunning())
return false;
- AddLog(CEC_LOG_DEBUG, "setting inactive view");
+ m_controller->AddLog(CEC_LOG_DEBUG, "setting inactive view");
cec_frame frame;
frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
frame.push_back(CEC_OPCODE_INACTIVE_SOURCE);
return Transmit(frame);
}
-bool CCECParser::GetNextLogMessage(cec_log_message *message)
+bool CCECProcessor::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
{
- return m_logBuffer.Pop(*message);
+ CStdString txStr = "transmit ";
+ for (unsigned int i = 0; i < data.size(); i++)
+ txStr.AppendFormat(" %02x", data[i]);
+ m_controller->AddLog(CEC_LOG_DEBUG, txStr.c_str());
+
+ if (data.empty())
+ {
+ m_controller->AddLog(CEC_LOG_WARNING, "transmit buffer is empty");
+ return false;
+ }
+
+ cec_frame output;
+
+ //set ack polarity to high when transmitting to the broadcast address
+ //set ack polarity low when transmitting to any other address
+ output.push_back(MSGSTART);
+ CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_ACK_POLARITY);
+
+ if ((data[0] & 0xF) == 0xF)
+ CAdapterCommunication::PushEscaped(output, CEC_TRUE);
+ else
+ CAdapterCommunication::PushEscaped(output, CEC_FALSE);
+
+ output.push_back(MSGEND);
+
+ for (unsigned int i = 0; i < data.size(); i++)
+ {
+ output.push_back(MSGSTART);
+
+ if (i == data.size() - 1)
+ CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_EOM);
+ else
+ CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT);
+
+ CAdapterCommunication::PushEscaped(output, data[i]);
+
+ output.push_back(MSGEND);
+ }
+
+ return TransmitFormatted(output, bWaitForAck);
}
-bool CCECParser::GetNextKeypress(cec_keypress *key)
+bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
{
- return IsRunning() ? m_keyBuffer.Pop(*key) : false;
+ CStdString strLog;
+ strLog.Format("setting logical address to %d", iLogicalAddress);
+ m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
+
+ m_iLogicalAddress = iLogicalAddress;
+ return m_communication && m_communication->SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
}
-bool CCECParser::GetNextCommand(cec_command *command)
+bool CCECProcessor::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */)
{
- return IsRunning() ? m_commandBuffer.Pop(*command) : false;
+ CLockObject lock(&m_mutex);
+ if (!m_communication || !m_communication->Write(data))
+ return false;
+
+ if (bWaitForAck && !WaitForAck())
+ {
+ m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ACK");
+ return false;
+ }
+
+ return true;
}
-//@}
-void CCECParser::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
+void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
{
- AddLog(CEC_LOG_DEBUG, "transmitting abort message");
+ m_controller->AddLog(CEC_LOG_DEBUG, "transmitting abort message");
cec_frame frame;
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_FEATURE_ABORT);
Transmit(frame);
}
-void CCECParser::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
+void CCECProcessor::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
{
cec_frame frame;
- AddLog(CEC_LOG_NOTICE, "reporting CEC version as 1.3a");
+ m_controller->AddLog(CEC_LOG_NOTICE, "reporting CEC version as 1.3a");
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_CEC_VERSION);
frame.push_back(CEC_VERSION_1_3A);
Transmit(frame);
}
-void CCECParser::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
+void CCECProcessor::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
{
cec_frame frame;
if (bOn)
- AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
+ m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
else
- AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
+ m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_REPORT_POWER_STATUS);
Transmit(frame);
}
-void CCECParser::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
+void CCECProcessor::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
{
cec_frame frame;
if (bActive)
- AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
+ m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
else
- AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
+ m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_MENU_STATUS);
Transmit(frame);
}
-void CCECParser::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
+void CCECProcessor::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
{
- AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
+ m_controller->AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
TransmitAbort(address, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
}
-void CCECParser::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
+void CCECProcessor::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
{
cec_frame frame;
const char *osdname = m_strDeviceName.c_str();
CStdString strLog;
strLog.Format("reporting OSD name as %s", osdname);
- AddLog(CEC_LOG_NOTICE, strLog.c_str());
+ m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
frame.push_back(GetSourceDestination(address));
frame.push_back(CEC_OPCODE_SET_OSD_NAME);
Transmit(frame);
}
-void CCECParser::ReportPhysicalAddress(void)
+void CCECProcessor::ReportPhysicalAddress(void)
{
cec_frame frame;
CStdString strLog;
strLog.Format("reporting physical address as %04x", m_physicaladdress);
- AddLog(CEC_LOG_NOTICE, strLog.c_str());
+ m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
frame.push_back(CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
frame.push_back((m_physicaladdress >> 8) & 0xFF);
Transmit(frame);
}
-void CCECParser::BroadcastActiveSource(void)
+void CCECProcessor::BroadcastActiveSource(void)
{
cec_frame frame;
- AddLog(CEC_LOG_NOTICE, "broadcasting active source");
+ m_controller->AddLog(CEC_LOG_NOTICE, "broadcasting active source");
frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
frame.push_back(CEC_OPCODE_ACTIVE_SOURCE);
frame.push_back((m_physicaladdress >> 8) & 0xFF);
Transmit(frame);
}
-bool CCECParser::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */)
-{
- CLockObject lock(&m_mutex);
- if (!m_communication || !m_communication->Write(data))
- {
- return false;
- }
-
- CCondition::Sleep((int) data.size() * 24 /*data*/ + 5 /*start bit (4.5 ms)*/ + 50 /* to be on the safe side */);
- if (bWaitForAck && !WaitForAck())
- {
- AddLog(CEC_LOG_DEBUG, "did not receive ACK");
- return false;
- }
-
- return true;
-}
-
-bool CCECParser::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
+uint8_t CCECProcessor::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */) const
{
- CStdString txStr = "transmit ";
- for (unsigned int i = 0; i < data.size(); i++)
- txStr.AppendFormat(" %02x", data[i]);
- AddLog(CEC_LOG_DEBUG, txStr.c_str());
-
- if (data.empty())
- {
- AddLog(CEC_LOG_WARNING, "transmit buffer is empty");
- return false;
- }
-
- cec_frame output;
-
- //set ack polarity to high when transmitting to the broadcast address
- //set ack polarity low when transmitting to any other address
- output.push_back(MSGSTART);
- PushEscaped(output, MSGCODE_TRANSMIT_ACK_POLARITY);
-
- if ((data[0] & 0xF) == 0xF)
- PushEscaped(output, CEC_TRUE);
- else
- PushEscaped(output, CEC_FALSE);
-
- output.push_back(MSGEND);
-
- for (unsigned int i = 0; i < data.size(); i++)
- {
- output.push_back(MSGSTART);
-
- if (i == data.size() - 1)
- PushEscaped(output, MSGCODE_TRANSMIT_EOM);
- else
- PushEscaped(output, MSGCODE_TRANSMIT);
-
- PushEscaped(output, data[i]);
-
- output.push_back(MSGEND);
- }
-
- return TransmitFormatted(output, bWaitForAck);
+ return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
}
-bool CCECParser::WaitForAck(int iTimeout /* = 1000 */)
+bool CCECProcessor::WaitForAck(int iTimeout /* = 1000 */)
{
bool bGotAck(false);
bool bError(false);
switch (iCode)
{
case MSGCODE_COMMAND_ACCEPTED:
- AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
+ m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
break;
case MSGCODE_TRANSMIT_SUCCEEDED:
- AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
+ m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
// TODO
bGotAck = true;
break;
case MSGCODE_RECEIVE_FAILED:
- AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
+ m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
bError = true;
break;
case MSGCODE_COMMAND_REJECTED:
- AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
+ m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
bError = true;
break;
case MSGCODE_TRANSMIT_FAILED_LINE:
- AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
+ m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
bError = true;
break;
case MSGCODE_TRANSMIT_FAILED_ACK:
- AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_ACK");
+ m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_ACK");
bError = true;
break;
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
- AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA");
+ m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA");
bError = true;
break;
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
- AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
+ m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
bError = true;
break;
default:
return bGotAck && !bError;
}
-bool CCECParser::ParseMessage(cec_frame &msg)
+bool CCECProcessor::ParseMessage(cec_frame &msg)
{
bool bReturn(false);
switch(iCode)
{
case MSGCODE_NOTHING:
- AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
+ m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
break;
case MSGCODE_TIMEOUT_ERROR:
case MSGCODE_HIGH_ERROR:
uint32_t iTime = (msg.size() >= 7) ? (msg[3] << 24) | (msg[4] << 16) | (msg[5] << 8) | (msg[6]) : 0;
logStr.AppendFormat(" line:%i", iLine);
logStr.AppendFormat(" time:%u", iTime);
- AddLog(CEC_LOG_WARNING, logStr.c_str());
+ m_controller->AddLog(CEC_LOG_WARNING, logStr.c_str());
}
break;
case MSGCODE_FRAME_START:
m_currentframe.push_back(msg[1]);
}
- AddLog(CEC_LOG_DEBUG, logStr.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
}
break;
case MSGCODE_FRAME_DATA:
logStr.AppendFormat(" %02x", iData);
m_currentframe.push_back(iData);
}
- AddLog(CEC_LOG_DEBUG, logStr.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
}
if (bEom)
bReturn = true;
return bReturn;
}
-void CCECParser::ParseCurrentFrame(void)
+void CCECProcessor::ParseCurrentFrame(void)
{
uint8_t initiator = m_currentframe[0] >> 4;
uint8_t destination = m_currentframe[0] & 0xF;
for (unsigned int i = 1; i < m_currentframe.size(); i++)
dataStr.AppendFormat(" %02x", m_currentframe[i]);
}
- AddLog(CEC_LOG_DEBUG, dataStr.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str());
if (m_currentframe.size() <= 1)
return;
case CEC_OPCODE_USER_CONTROL_PRESSED:
if (m_currentframe.size() > 2)
{
- AddKey();
+ m_controller->AddKey();
if (m_currentframe[2] <= CEC_USER_CONTROL_CODE_MAX)
- {
- m_iCurrentButton = (cec_user_control_code) m_currentframe[2];
- m_buttontime = GetTimeMs();
- }
+ m_controller->SetCurrentButton((cec_user_control_code) m_currentframe[2]);
}
break;
case CEC_OPCODE_USER_CONTROL_RELEASE:
- AddKey();
+ m_controller->AddKey();
break;
default:
cec_frame params = m_currentframe;
params.erase(params.begin(), params.begin() + 2);
- AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, ¶ms);
+ m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, ¶ms);
break;
}
}
int streamaddr = ((int)m_currentframe[2] << 8) | ((int)m_currentframe[3]);
CStdString strLog;
strLog.Format("%i requests stream path from physical address %04x", initiator, streamaddr);
- AddLog(CEC_LOG_DEBUG, strLog.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
if (streamaddr == m_physicaladdress)
BroadcastActiveSource();
}
{
cec_frame params = m_currentframe;
params.erase(params.begin(), params.begin() + 2);
- AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, ¶ms);
+ m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, ¶ms);
}
}
else
{
CStdString strLog;
strLog.Format("ignoring frame: destination: %u != %u", destination, (uint16_t)m_iLogicalAddress);
- AddLog(CEC_LOG_DEBUG, strLog.c_str());
+ m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
}
}
-
-void CCECParser::PushEscaped(cec_frame &vec, uint8_t byte)
-{
- if (byte >= MSGESC && byte != MSGSTART)
- {
- vec.push_back(MSGESC);
- vec.push_back(byte - ESCOFFSET);
- }
- else
- {
- vec.push_back(byte);
- }
-}
-
-void CCECParser::CheckKeypressTimeout(int64_t now)
-{
- if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && now - m_buttontime > CEC_BUTTON_TIMEOUT)
- {
- AddKey();
- m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
- }
-}
-
-bool CCECParser::SetLogicalAddress(cec_logical_address iLogicalAddress)
-{
- CStdString strLog;
- strLog.Format("setting logical address to %d", iLogicalAddress);
- AddLog(CEC_LOG_NOTICE, strLog.c_str());
-
- m_iLogicalAddress = iLogicalAddress;
- return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
-}
-
-bool CCECParser::SetAckMask(uint16_t iMask)
-{
- CStdString strLog;
- strLog.Format("setting ackmask to %2x", iMask);
- AddLog(CEC_LOG_DEBUG, strLog.c_str());
-
- cec_frame output;
-
- output.push_back(MSGSTART);
- PushEscaped(output, MSGCODE_SET_ACK_MASK);
- PushEscaped(output, iMask >> 8);
- PushEscaped(output, (uint8_t)iMask);
- output.push_back(MSGEND);
-
- if (!m_communication->Write(output))
- {
- AddLog(CEC_LOG_ERROR, "could not set the ackmask");
- return false;
- }
-
- return true;
-}
-
-void CCECParser::AddLog(cec_log_level level, const string &strMessage)
-{
- cec_log_message message;
- message.level = level;
- message.message.assign(strMessage.c_str());
- m_logBuffer.Push(message);
-}
-
-void CCECParser::AddKey(void)
-{
- if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
- {
- cec_keypress key;
- key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
- key.keycode = m_iCurrentButton;
- m_keyBuffer.Push(key);
- m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
- m_buttontime = 0;
- }
-}
-
-void CCECParser::AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters)
-{
- cec_command command;
- command.source = source;
- command.destination = destination;
- command.opcode = opcode;
- if (parameters)
- command.parameters = *parameters;
- if (m_commandBuffer.Push(command))
- {
- CStdString strDebug;
- strDebug.Format("stored command '%d' in the command buffer. buffer size = %d", opcode, m_commandBuffer.Size());
- AddLog(CEC_LOG_DEBUG, strDebug);
- }
- else
- {
- AddLog(CEC_LOG_WARNING, "command buffer is full");
- }
-}
-
-int CCECParser::GetMinVersion(void)
-{
- return CEC_MIN_VERSION;
-}
-
-int CCECParser::GetLibVersion(void)
-{
- return CEC_LIB_VERSION;
-}
-
-int CCECParser::FindDevices(std::vector<cec_device> &deviceList, const char *strDevicePath /* = NULL */)
-{
- CStdString strDebug;
- if (strDevicePath)
- strDebug.Format("trying to autodetect the com port for device path '%s'", strDevicePath);
- else
- strDebug.Format("trying to autodetect all CEC adapters");
- AddLog(CEC_LOG_DEBUG, strDebug);
-
- return CCECDetect::FindDevices(deviceList, strDevicePath);
-}
-
-DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress /*= CEC::CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
-{
- return static_cast< void* > (new CCECParser(strDeviceName, iLogicalAddress, iPhysicalAddress));
-}
* http://www.pulse-eight.net/
*/
-#include <queue>
-#include <stdio.h>
#include "../../include/CECExports.h"
#include "../../include/CECTypes.h"
#include "util/threads.h"
namespace CEC
{
+ class CLibCEC;
class CAdapterCommunication;
- class CCECParser : public ICECDevice, public CThread
+ class CCECProcessor : public CThread
{
public:
- /*!
- * ICECDevice implementation
- */
- //@{
- CCECParser(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
- virtual ~CCECParser(void);
+ CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+ virtual ~CCECProcessor(void);
+
+ virtual bool Start(void);
+ void *Process(void);
- virtual bool Open(const char *strPort, int iTimeout = 10000);
- virtual void Close(void);
- virtual int FindDevices(std::vector<cec_device> &deviceList, const char *strDevicePath = NULL);
- virtual bool Ping(void);
- virtual bool StartBootloader(void);
- virtual bool PowerOffDevices(cec_logical_address address = CECDEVICE_BROADCAST);
virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV);
virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
virtual bool SetActiveView(void);
virtual bool SetInactiveView(void);
- virtual bool GetNextLogMessage(cec_log_message *message);
- virtual bool GetNextKeypress(cec_keypress *key);
- virtual bool GetNextCommand(cec_command *command);
virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true);
virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
- virtual bool SetAckMask(uint16_t iMask);
- virtual int GetMinVersion(void);
- virtual int GetLibVersion(void);
- //@}
-
- void *Process(void);
- void AddLog(cec_log_level level, const std::string &strMessage);
protected:
virtual bool TransmitFormatted(const cec_frame &data, bool bWaitForAck = true);
virtual void TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
virtual void ReportOSDName(cec_logical_address address = CECDEVICE_TV);
virtual void ReportPhysicalAddress(void);
virtual void BroadcastActiveSource(void);
- virtual uint8_t GetSourceDestination(cec_logical_address destination = CECDEVICE_BROADCAST);
+ virtual uint8_t GetSourceDestination(cec_logical_address destination = CECDEVICE_BROADCAST) const;
private:
- void AddKey(void);
- void AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters);
bool WaitForAck(int iTimeout = 1000);
- bool ReadFromDevice(int iTimeout);
- void ProcessMessages(void);
- bool GetMessage(cec_frame &msg, bool bFromBuffer = true);
bool ParseMessage(cec_frame &msg);
void ParseCurrentFrame(void);
- void AddData(uint8_t* data, int len);
- void PushEscaped(cec_frame &vec, uint8_t iByte);
-
- void CheckKeypressTimeout(int64_t now);
-
cec_frame m_currentframe;
- cec_user_control_code m_iCurrentButton;
- int64_t m_buttontime;
int m_physicaladdress;
cec_logical_address m_iLogicalAddress;
CecBuffer<cec_frame> m_frameBuffer;
- CecBuffer<cec_log_message> m_logBuffer;
- CecBuffer<cec_keypress> m_keyBuffer;
- CecBuffer<cec_command> m_commandBuffer;
std::string m_strDeviceName;
CMutex m_mutex;
- CAdapterCommunication *m_communication;
+ CAdapterCommunication *m_communication;
+ CLibCEC *m_controller;
};
};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 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 "LibCEC.h"
+
+#include "AdapterCommunication.h"
+#include "AdapterDetection.h"
+#include "CECProcessor.h"
+#include "util/StdString.h"
+#include "util/timeutils.h"
+
+using namespace std;
+using namespace CEC;
+
+CLibCEC::CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */) :
+ m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+ m_buttontime(0)
+{
+ m_comm = new CAdapterCommunication(this);
+ m_cec = new CCECProcessor(this, m_comm, strDeviceName, iLogicalAddress, iPhysicalAddress);
+}
+
+CLibCEC::~CLibCEC(void)
+{
+ delete m_cec;
+ m_cec = NULL;
+
+ delete m_comm;
+ m_comm = NULL;
+}
+
+bool CLibCEC::Open(const char *strPort, int iTimeoutMs /* = 10000 */)
+{
+ if (!m_comm)
+ return false;
+
+ if (m_comm->IsOpen())
+ {
+ AddLog(CEC_LOG_ERROR, "connection already open");
+ return false;
+ }
+
+ if (!m_comm->Open(strPort, 38400, iTimeoutMs))
+ {
+ AddLog(CEC_LOG_ERROR, "could not open a connection");
+ return false;
+ }
+
+ if (!m_cec->Start())
+ {
+ AddLog(CEC_LOG_ERROR, "could not start CEC communications");
+ return false;
+ }
+
+ return true;
+}
+
+void CLibCEC::Close(void)
+{
+ if (m_cec)
+ m_cec->StopThread();
+ if (m_comm)
+ m_comm->Close();
+}
+
+int CLibCEC::FindAdapters(std::vector<cec_adapter> &deviceList, const char *strDevicePath /* = NULL */)
+{
+ CStdString strDebug;
+ if (strDevicePath)
+ strDebug.Format("trying to autodetect the com port for device path '%s'", strDevicePath);
+ else
+ strDebug.Format("trying to autodetect all CEC adapters");
+ AddLog(CEC_LOG_DEBUG, strDebug);
+
+ return CAdapterDetection::FindAdapters(deviceList, strDevicePath);
+}
+
+bool CLibCEC::PingAdapter(void)
+{
+ return m_comm ? m_comm->PingAdapter() : false;
+}
+
+bool CLibCEC::StartBootloader(void)
+{
+ return m_comm ? m_comm->StartBootloader() : false;
+}
+
+int CLibCEC::GetMinVersion(void)
+{
+ return CEC_MIN_VERSION;
+}
+
+int CLibCEC::GetLibVersion(void)
+{
+ return CEC_LIB_VERSION;
+}
+
+bool CLibCEC::GetNextLogMessage(cec_log_message *message)
+{
+ return m_logBuffer.Pop(*message);
+}
+
+bool CLibCEC::GetNextKeypress(cec_keypress *key)
+{
+ return m_keyBuffer.Pop(*key);
+}
+
+bool CLibCEC::GetNextCommand(cec_command *command)
+{
+ return m_commandBuffer.Pop(*command);
+}
+
+bool CLibCEC::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
+{
+ return m_cec ? m_cec->Transmit(data, bWaitForAck) : false;
+}
+
+bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
+{
+ return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false;
+}
+
+bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
+{
+ return m_cec ? m_cec->PowerOnDevices(address) : false;
+}
+
+bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+{
+ return m_cec ? m_cec->StandbyDevices(address) : false;
+}
+
+bool CLibCEC::SetActiveView(void)
+{
+ return m_cec ? m_cec->SetActiveView() : false;
+}
+
+bool CLibCEC::SetInactiveView(void)
+{
+ return m_cec ? m_cec->SetInactiveView() : false;
+}
+
+void CLibCEC::AddLog(cec_log_level level, const string &strMessage)
+{
+ cec_log_message message;
+ message.level = level;
+ message.message.assign(strMessage.c_str());
+ m_logBuffer.Push(message);
+}
+
+void CLibCEC::AddKey(void)
+{
+ if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+ {
+ cec_keypress key;
+ key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
+ key.keycode = m_iCurrentButton;
+ m_keyBuffer.Push(key);
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ m_buttontime = 0;
+ }
+}
+
+void CLibCEC::AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters)
+{
+ cec_command command;
+ command.source = source;
+ command.destination = destination;
+ command.opcode = opcode;
+ if (parameters)
+ command.parameters = *parameters;
+ if (m_commandBuffer.Push(command))
+ {
+ CStdString strDebug;
+ strDebug.Format("stored command '%d' in the command buffer. buffer size = %d", opcode, m_commandBuffer.Size());
+ AddLog(CEC_LOG_DEBUG, strDebug);
+ }
+ else
+ {
+ AddLog(CEC_LOG_WARNING, "command buffer is full");
+ }
+}
+
+void CLibCEC::CheckKeypressTimeout(void)
+{
+ if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
+ {
+ AddKey();
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ }
+}
+
+void CLibCEC::SetCurrentButton(cec_user_control_code iButtonCode)
+{
+ m_iCurrentButton = iButtonCode;
+ m_buttontime = GetTimeMs();
+}
+
+DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress /*= CEC::CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
+{
+ return static_cast< void* > (new CLibCEC(strDeviceName, iLogicalAddress, iPhysicalAddress));
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 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 "../../include/CECExports.h"
+#include "../../include/CECTypes.h"
+#include "util/buffer.h"
+
+namespace CEC
+{
+ class CAdapterCommunication;
+ class CCECProcessor;
+
+ class CLibCEC : public ICECAdapter
+ {
+ public:
+ /*!
+ * ICECAdapter implementation
+ */
+ //@{
+ CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+ virtual ~CLibCEC(void);
+
+ virtual bool Open(const char *strPort, int iTimeout = 10000);
+ virtual void Close(void);
+ virtual int FindAdapters(std::vector<cec_adapter> &deviceList, const char *strDevicePath = NULL);
+ virtual bool PingAdapter(void);
+ virtual bool StartBootloader(void);
+
+ virtual int GetMinVersion(void);
+ virtual int GetLibVersion(void);
+
+ virtual bool GetNextLogMessage(cec_log_message *message);
+ virtual bool GetNextKeypress(cec_keypress *key);
+ virtual bool GetNextCommand(cec_command *command);
+
+ virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true);
+ virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
+
+ virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV);
+ virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
+ virtual bool SetActiveView(void);
+ virtual bool SetInactiveView(void);
+ //@}
+
+ virtual void AddLog(cec_log_level level, const std::string &strMessage);
+ virtual void AddKey(void);
+ virtual void AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters);
+ virtual void CheckKeypressTimeout(void);
+ virtual void SetCurrentButton(cec_user_control_code iButtonCode);
+
+ protected:
+ cec_user_control_code m_iCurrentButton;
+ int64_t m_buttontime;
+ CCECProcessor *m_cec;
+ CAdapterCommunication *m_comm;
+ CecBuffer<cec_log_message> m_logBuffer;
+ CecBuffer<cec_keypress> m_keyBuffer;
+ CecBuffer<cec_command> m_commandBuffer;
+ };
+};
* http://www.pulse-eight.net/
*/
-#include "CECParser.h"
+#include "LibCEC.h"
using namespace CEC;
using namespace std;
* C interface implementation
*/
//@{
-ICECDevice *cec_parser;
+ICECAdapter *cec_parser;
bool cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
{
- cec_parser = (ICECDevice *) CECCreate(strDeviceName, iLogicalAddress, iPhysicalAddress);
+ cec_parser = (ICECAdapter *) CECCreate(strDeviceName, iLogicalAddress, iPhysicalAddress);
return (cec_parser != NULL);
}
cec_parser->Close();
}
-bool cec_ping(void)
+int cec_find_adapters(vector<cec_adapter> &deviceList, const char *strDevicePath /* = NULL */)
{
if (cec_parser)
- return cec_parser->Ping();
- return false;
-}
-
-bool cec_start_bootloader(void)
-{
- if (cec_parser)
- return cec_parser->StartBootloader();
- return false;
-}
-
-bool cec_power_off_devices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
-{
- if (cec_parser)
- return cec_parser->PowerOffDevices(address);
- return false;
+ return cec_parser->FindAdapters(deviceList, strDevicePath);
+ return -1;
}
-bool cec_power_on_devices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool cec_ping_adapters(void)
{
if (cec_parser)
- return cec_parser->PowerOnDevices(address);
+ return cec_parser->PingAdapter();
return false;
}
-bool cec_standby_devices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool cec_start_bootloader(void)
{
if (cec_parser)
- return cec_parser->StandbyDevices(address);
+ return cec_parser->StartBootloader();
return false;
}
-bool cec_set_active_view(void)
+int cec_get_min_version(void)
{
if (cec_parser)
- return cec_parser->SetActiveView();
- return false;
+ return cec_parser->GetMinVersion();
+ return -1;
}
-bool cec_set_inactive_view(void)
+int cec_get_lib_version(void)
{
if (cec_parser)
- return cec_parser->SetInactiveView();
- return false;
+ return cec_parser->GetLibVersion();
+ return -1;
}
bool cec_get_next_log_message(cec_log_message *message)
return false;
}
-bool cec_set_ack_mask(uint16_t iMask)
+bool cec_power_on_devices(cec_logical_address address /* = CECDEVICE_TV */)
{
if (cec_parser)
- return cec_parser->SetAckMask(iMask);
+ return cec_parser->PowerOnDevices(address);
return false;
}
-int cec_get_min_version(void)
+bool cec_standby_devices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
{
if (cec_parser)
- return cec_parser->GetMinVersion();
- return -1;
+ return cec_parser->StandbyDevices(address);
+ return false;
}
-int cec_get_lib_version(void)
+bool cec_set_active_view(void)
{
if (cec_parser)
- return cec_parser->GetLibVersion();
- return -1;
+ return cec_parser->SetActiveView();
+ return false;
}
-int cec_find_devices(vector<cec_device> &deviceList, const char *strDevicePath /* = NULL */)
+bool cec_set_inactive_view(void)
{
if (cec_parser)
- return cec_parser->FindDevices(deviceList, strDevicePath);
- return -1;
+ return cec_parser->SetInactiveView();
+ return false;
}
//@}
*/
#include "CECExports.h"
-#include "CECParser.h"
using namespace CEC;
pkgconfig_DATA = libcec.pc
-libcec_la_SOURCES = CECParser.cpp \
- CECParser.h \
- CECParserC.cpp \
- CECDetect.cpp \
- CECDetect.h \
- AdapterCommunication.cpp \
+libcec_la_SOURCES = AdapterCommunication.cpp \
AdapterCommunication.h \
+ AdapterDetection.cpp \
+ AdapterDetection.h \
+ CECProcessor.cpp \
+ CECProcessor.h \
+ LibCEC.cpp \
+ LibCEC.h \
+ LibCECC.cpp \
../../include/CECExports.h \
../../include/CECExportsCpp.h \
../../include/CECExportsC.h \
- util/misc.h \
util/misc.cpp \
+ util/misc.h \
util/StdString.h \
util/threads.cpp \
util/threads.h \
#define CEC_TEST_CLIENT_VERSION 3
-void flush_log(ICECDevice *cecParser)
+void flush_log(ICECAdapter *cecParser)
{
cec_log_message message;
while (cecParser && cecParser->GetNextLogMessage(&message))
}
}
-void list_devices(ICECDevice *parser)
+void list_devices(ICECAdapter *parser)
{
cout << "Found devices: ";
- vector<cec_device> devices;
- int iDevicesFound = parser->FindDevices(devices);
+ vector<cec_adapter> devices;
+ int iDevicesFound = parser->FindAdapters(devices);
if (iDevicesFound <= 0)
{
#ifdef __WINDOWS__
"tx {bytes} transfer bytes over the CEC line." << endl <<
"[tx 40 00 FF 11 22 33] sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" << endl <<
endl <<
- "am {ackmack} change the ackmask of the CEC adapter." << endl <<
- "[am 10] ackmask 0x10 (logical address 4)" << endl <<
- endl <<
"la {logical_address} change the logical address of the CEC adapter." << endl <<
"[la 4] logical address 4" << endl <<
endl <<
int main (int argc, char *argv[])
{
- ICECDevice *parser = LoadLibCec("CEC Tester");
+ ICECAdapter *parser = LoadLibCec("CEC Tester");
if (!parser && parser->GetMinVersion() > CEC_TEST_CLIENT_VERSION)
{
cout << "Unable to create parser. Is libcec.dll present?" << endl;
if (argc < 2)
{
cout << "no serial port given. trying autodetect: ";
- vector<cec_device> devices;
- int iDevicesFound = parser->FindDevices(devices);
+ vector<cec_adapter> devices;
+ int iDevicesFound = parser->FindAdapters(devices);
if (iDevicesFound <= 0)
{
cout << "FAILED" << endl;
parser->Transmit(bytes);
}
- else if (command == "am")
- {
- string strvalue;
- int ackmask;
- if (GetWord(input, strvalue) && HexStrToInt(strvalue, ackmask))
- {
- parser->SetAckMask(ackmask);
- }
- }
else if (command == "la")
{
string strvalue;
}
else if (command == "ping")
{
- parser->Ping();
+ parser->PingAdapter();
}
else if (command == "bl")
{
CCondition::Sleep(50);
}
- parser->PowerOffDevices(CECDEVICE_BROADCAST);
+ parser->StandbyDevices(CECDEVICE_BROADCAST);
parser->Close();
flush_log(parser);
UnloadLibCec(parser);