Merge branch 'master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Mon, 3 Oct 2011 22:54:29 +0000 (00:54 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Mon, 3 Oct 2011 22:54:53 +0000 (00:54 +0200)
  * bumped interface version to 4
  * timeout parameter removed from Close()/cec_close(). return type changed to
    void
  * added cec_destroy() method
  * removed timeout parameter from Transmit()
  * change the default argument of PowerOnDevices() to CECDEVICE_TV
  * removed PowerOffDevices(). use StandbyDevices() instead
  * removed obsolete methods from the interface
  * fixed bug: pthread_cond_wait was called without the mutex locked
  * fixed possible deadlock: don't send messages and wait for an ack with the
    mutex locked in CCECParser
  * created a separate reader thread and fixed the 'lock timeout' bug
  * testclient: use CECDEVICE_TV instead of the default argument
    (CECDEVICE_BROADCAST) for PowerOnDevices() and PowerOffDevices()

24 files changed:
ChangeLog
configure.ac
debian/changelog
include/CECExports.h
include/CECExportsC.h
include/CECExportsCpp.h
include/CECTypes.h
project/libcec.vcxproj
project/libcec.vcxproj.filters
src/lib/AdapterCommunication.cpp [new file with mode: 0644]
src/lib/AdapterCommunication.h [new file with mode: 0644]
src/lib/AdapterDetection.cpp [moved from src/lib/CECDetect.cpp with 97% similarity]
src/lib/AdapterDetection.h [moved from src/lib/CECDetect.h with 91% similarity]
src/lib/CECParser.cpp [deleted file]
src/lib/CECProcessor.cpp [new file with mode: 0644]
src/lib/CECProcessor.h [moved from src/lib/CECParser.h with 55% similarity]
src/lib/LibCEC.cpp [new file with mode: 0644]
src/lib/LibCEC.h [new file with mode: 0644]
src/lib/LibCECC.cpp [moved from src/lib/CECParserC.cpp with 79% similarity]
src/lib/LibCECDll.cpp [moved from src/lib/CECDll.cpp with 98% similarity]
src/lib/Makefile.am
src/lib/util/threads.cpp
src/lib/util/threads.h
src/testclient/main.cpp

index 3a893f2308b54c90e862deced6121632d76fb0eb..10c85f199556890f357c851bd110adddc40308c3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+libcec (0.4-1) unstable; urgency=low
+
+  * bumped interface version to 4
+  * timeout parameter removed from Close()/cec_close(). return type changed to
+    void
+  * added cec_destroy() method
+  * removed timeout parameter from Transmit()
+  * change the default argument of PowerOnDevices() to CECDEVICE_TV
+  * removed PowerOffDevices(). use StandbyDevices() instead
+  * removed obsolete methods from the interface
+  * fixed bug: pthread_cond_wait was called without the mutex locked
+  * fixed possible deadlock: don't send messages and wait for an ack with the
+    mutex locked in CCECParser
+  * created a separate reader thread and fixed the 'lock timeout' bug
+  * testclient: use CECDEVICE_TV instead of the default argument
+    (CECDEVICE_BROADCAST) for PowerOnDevices() and PowerOffDevices()
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Tue, 04 Oct 2011 00:48:00 +0200
+
 libcec (0.3-1) unstable; urgency=low
 
   * added device detection support for Windows
index 883d414ac3e2172f527dfeea734c62166ae08d09..bd97334aa8a1ab87a63aaa7c9c1ea4154a3803e2 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT([libcec], 0:2:0)
+AC_INIT([libcec], 0:4:0)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 AC_PROG_CXX
index 3a893f2308b54c90e862deced6121632d76fb0eb..10c85f199556890f357c851bd110adddc40308c3 100644 (file)
@@ -1,3 +1,22 @@
+libcec (0.4-1) unstable; urgency=low
+
+  * bumped interface version to 4
+  * timeout parameter removed from Close()/cec_close(). return type changed to
+    void
+  * added cec_destroy() method
+  * removed timeout parameter from Transmit()
+  * change the default argument of PowerOnDevices() to CECDEVICE_TV
+  * removed PowerOffDevices(). use StandbyDevices() instead
+  * removed obsolete methods from the interface
+  * fixed bug: pthread_cond_wait was called without the mutex locked
+  * fixed possible deadlock: don't send messages and wait for an ack with the
+    mutex locked in CCECParser
+  * created a separate reader thread and fixed the 'lock timeout' bug
+  * testclient: use CECDEVICE_TV instead of the default argument
+    (CECDEVICE_BROADCAST) for PowerOnDevices() and PowerOffDevices()
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Tue, 04 Oct 2011 00:48:00 +0200
+
 libcec (0.3-1) unstable; urgency=low
 
   * added device detection support for Windows
index 0aef25c30723e72e5b32fa177a1aeaf86b02e775..9a5c0952c6f8cc5c3fc94edf812160ad6bb3275d 100644 (file)
 extern "C" {
 namespace CEC {
 #endif
-  #define CEC_MIN_VERSION      2
-  #define CEC_LIB_VERSION      2
+  #define CEC_MIN_VERSION      4
+  #define CEC_LIB_VERSION      4
   #define CEC_SETTLE_DOWN_TIME 1000
+  #define CEC_BUTTON_TIMEOUT   500
 
   typedef std::vector<uint8_t> cec_frame;
 
@@ -253,11 +254,11 @@ namespace CEC {
     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
   {
index 8d91fe26ad9010d964a061c45694a84e28c7eba6..61cabd2bd4e18fee19588af863c5e3f67b8e6e75 100644 (file)
@@ -45,13 +45,17 @@ extern "C" {
  * @param iPhysicalAddress The physical address of this device. 0x1000 by default.
  * @return True when initialised, false otherwise.
  */
-
 #ifdef __cplusplus
 extern DECLSPEC bool cec_init(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
 #else
 extern DECLSPEC bool cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
 #endif
 
+/*!
+ * @brief Unload the CEC adapter library.
+ */
+extern DECLSPEC void cec_destroy(void);
+
 /*!
  * @brief Open a connection to the CEC adapter.
  * @param strPort The path to the port.
@@ -62,15 +66,26 @@ extern DECLSPEC bool cec_open(const char *strPort, int iTimeout);
 
 /*!
  * @brief Close the connection to the CEC adapter.
- * @param iTimeout Timeout in ms
  */
-extern DECLSPEC bool cec_close(int iTimeout);
+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.
@@ -79,15 +94,14 @@ extern DECLSPEC bool cec_ping(void);
 extern DECLSPEC bool cec_start_bootloader(void);
 
 /*!
- * @brief Power off connected CEC capable devices.
- * @param address The logical address to power off.
- * @return True when the command was sent succesfully, false otherwise.
+ * @return Get the minimal version of libcec that this version of libcec can interface with.
  */
-#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_min_version(void);
+
+/*!
+ * @return Get the version of libcec.
+ */
+extern DECLSPEC int cec_get_lib_version(void);
 
 /*!
  * @brief Power on the connected CEC capable devices.
@@ -95,9 +109,9 @@ extern DECLSPEC bool cec_power_off_devices(cec_logical_address address = CECDEVI
  * @return True when the command was sent succesfully, false otherwise.
  */
 #ifdef __cplusplus
-extern DECLSPEC bool cec_power_on_devices(CEC::cec_logical_address address = CEC::CECDEVICE_BROADCAST);
+extern DECLSPEC bool cec_power_on_devices(CEC::cec_logical_address address = CEC::CECDEVICE_TV);
 #else
-extern DECLSPEC bool cec_power_on_devices(cec_logical_address address = CECDEVICE_BROADCAST);
+extern DECLSPEC bool cec_power_on_devices(cec_logical_address address = CECDEVICE_TV);
 #endif
 
 /*!
@@ -160,13 +174,12 @@ extern DECLSPEC bool cec_get_next_command(cec_command *command);
  * @brief Transmit a frame on the CEC line.
  * @param data The frame to send.
  * @param bWaitForAck Wait for an ACK message for 1 second after this frame has been sent.
- * @param iTimeout Timeout if the message could not be sent for this amount of ms. Does not influence the timeout of the wait for the ACK message. That timeout is specified by the CEC standard.
  * @return True when the data was sent and acked, false otherwise.
  */
 #ifdef __cplusplus
-extern DECLSPEC bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 5000);
+extern DECLSPEC bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck = true);
 #else
-extern DECLSPEC bool cec_transmit(const cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 5000);
+extern DECLSPEC bool cec_transmit(const cec_frame &data, bool bWaitForAck = true);
 #endif
 
 /*!
@@ -180,36 +193,6 @@ extern DECLSPEC bool cec_set_logical_address(CEC::cec_logical_address iLogicalAd
 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
index ac00190571599ea9510396faa83f489b25b79cb4..54dbcbfe3770e16eb027451f1b6970cf814fc066 100644 (file)
 
 namespace CEC
 {
-  class ICECDevice
+  class ICECAdapter
   {
   public:
+    /*! @name Adapter methods */
+    //@{
     /*!
      * @see cec_open
      */
@@ -44,47 +46,33 @@ namespace CEC
     /*!
      * @see cec_close
      */
-    virtual bool Close(int iTimeoutMs = 2000) = 0;
+    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;
+    //@}
 
     /*!
-     * @see cec_power_off_devices
-     */
-    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
@@ -104,7 +92,7 @@ namespace CEC
     /*!
      * @see cec_transmit
      */
-    virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 5000) = 0;
+    virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true) = 0;
 
     /*!
      * @see cec_set_logical_address
@@ -112,19 +100,25 @@ namespace CEC
     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;
+
   };
 };
 
@@ -141,7 +135,7 @@ static int g_iLibCECInstanceCount = 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;
@@ -155,14 +149,14 @@ inline CEC::ICECDevice *LoadLibCec(const char *strName, CEC::cec_logical_address
   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;
 
@@ -178,16 +172,16 @@ inline void UnloadLibCec(CEC::ICECDevice *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;
 };
index 3518d20a61236d41179a699c70526d907146b131..b9bd2addd7df062e03dbc30b6a20eb06927fbff1 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
-#include <stdint.h>
-#include <vector>
-#include <string>
-#include "CECExports.h"
-
 typedef enum
 {
   CEC_ABORT_REASON_UNRECOGNIZED_OPCODE = 0,
index c4a3372883aaeb2773070bf6ce87b584ca6f80aa..a9edbba0b9cdd689cf745086cc18c2c0e6e8a9e1 100644 (file)
     <ClInclude Include="..\include\CECExportsC.h" />
     <ClInclude Include="..\include\CECExportsCpp.h" />
     <ClInclude Include="..\include\CECTypes.h" />
-    <ClInclude Include="..\src\lib\CECDetect.h" />
-    <ClInclude Include="..\src\lib\CECParser.h" />
+    <ClInclude Include="..\src\lib\AdapterCommunication.h" />
+    <ClInclude Include="..\src\lib\AdapterDetection.h" />
+    <ClInclude Include="..\src\lib\CECProcessor.h" />
+    <ClInclude Include="..\src\lib\LibCEC.h" />
     <ClInclude Include="..\src\lib\libPlatform\baudrate.h" />
     <ClInclude Include="..\src\lib\libPlatform\os-dependent.h" />
     <ClInclude Include="..\src\lib\libPlatform\pthread_win32\pthread.h" />
     <ClInclude Include="..\src\lib\util\timeutils.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\src\lib\CECDetect.cpp" />
-    <ClCompile Include="..\src\lib\CECDll.cpp" />
-    <ClCompile Include="..\src\lib\CECParser.cpp" />
-    <ClCompile Include="..\src\lib\CECParserC.cpp" />
+    <ClCompile Include="..\src\lib\AdapterCommunication.cpp" />
+    <ClCompile Include="..\src\lib\AdapterDetection.cpp" />
+    <ClCompile Include="..\src\lib\CECProcessor.cpp" />
+    <ClCompile Include="..\src\lib\LibCEC.cpp" />
+    <ClCompile Include="..\src\lib\LibCECC.cpp" />
+    <ClCompile Include="..\src\lib\LibCECDll.cpp" />
     <ClCompile Include="..\src\lib\libPlatform\windows\dlfcn-win32.cpp" />
     <ClCompile Include="..\src\lib\libPlatform\windows\os_windows.cpp" />
     <ClCompile Include="..\src\lib\libPlatform\windows\serialport.cpp" />
index f9f44b3428569c273688b4f4a0294c7a99c53bec..2bc976f0ed3022b908412c8265f91632b23dc6df 100644 (file)
@@ -42,7 +42,6 @@
     <ClInclude Include="..\src\lib\libPlatform\pthread_win32\semaphore.h">
       <Filter>platform</Filter>
     </ClInclude>
-    <ClInclude Include="..\src\lib\CECParser.h" />
     <ClInclude Include="..\include\CECExports.h">
       <Filter>exports</Filter>
     </ClInclude>
     <ClInclude Include="..\include\CECExportsC.h">
       <Filter>exports</Filter>
     </ClInclude>
-    <ClInclude Include="..\src\lib\CECDetect.h" />
+    <ClInclude Include="..\src\lib\AdapterCommunication.h" />
+    <ClInclude Include="..\src\lib\AdapterDetection.h" />
+    <ClInclude Include="..\src\lib\CECProcessor.h" />
+    <ClInclude Include="..\src\lib\LibCEC.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\src\lib\util\misc.cpp">
     <ClCompile Include="..\src\lib\libPlatform\windows\os_windows.cpp">
       <Filter>platform</Filter>
     </ClCompile>
-    <ClCompile Include="..\src\lib\CECParser.cpp" />
     <ClCompile Include="..\src\lib\libPlatform\windows\serialport.cpp">
       <Filter>platform</Filter>
     </ClCompile>
-    <ClCompile Include="..\src\lib\CECDll.cpp" />
-    <ClCompile Include="..\src\lib\CECParserC.cpp" />
-    <ClCompile Include="..\src\lib\CECDetect.cpp" />
+    <ClCompile Include="..\src\lib\AdapterCommunication.cpp" />
+    <ClCompile Include="..\src\lib\AdapterDetection.cpp" />
+    <ClCompile Include="..\src\lib\CECProcessor.cpp" />
+    <ClCompile Include="..\src\lib\LibCEC.cpp" />
+    <ClCompile Include="..\src\lib\LibCECC.cpp" />
+    <ClCompile Include="..\src\lib\LibCECDll.cpp" />
   </ItemGroup>
   <ItemGroup>
     <Library Include="..\src\lib\libPlatform\pthread_win32\pthreadVC2.lib">
diff --git a/src/lib/AdapterCommunication.cpp b/src/lib/AdapterCommunication.cpp
new file mode 100644 (file)
index 0000000..266842f
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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 "AdapterCommunication.h"
+
+#include "LibCEC.h"
+#include "libPlatform/serialport.h"
+#include "util/StdString.h"
+
+using namespace std;
+using namespace CEC;
+
+CAdapterCommunication::CAdapterCommunication(CLibCEC *controller) :
+    m_controller(controller),
+    m_inbuf(NULL),
+    m_iInbufSize(0),
+    m_iInbufUsed(0),
+    m_bStarted(false),
+    m_bStop(false)
+{
+  m_port = new CSerialPort;
+}
+
+CAdapterCommunication::~CAdapterCommunication(void)
+{
+  m_port->Close();
+  m_port = NULL;
+}
+
+bool CAdapterCommunication::Open(const char *strPort, int iBaudRate /* = 38400 */, int iTimeoutMs /* = 10000 */)
+{
+  CLockObject lock(&m_commMutex);
+  if (m_bStarted)
+    return false;
+
+  if (!m_port->Open(strPort, iBaudRate))
+  {
+    CStdString strError;
+    strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str());
+    m_controller->AddLog(CEC_LOG_ERROR, strError);
+    return false;
+  }
+
+  m_controller->AddLog(CEC_LOG_DEBUG, "connection opened");
+
+  //clear any input bytes
+  uint8_t buff[1024];
+  m_port->Read(buff, sizeof(buff), 50);
+
+  CCondition::Sleep(CEC_SETTLE_DOWN_TIME);
+
+  m_bStop = false;
+  m_bStarted = true;
+
+  if (CreateThread())
+  {
+    m_controller->AddLog(CEC_LOG_DEBUG, "reader thread created");
+    return true;
+  }
+  else
+  {
+    m_controller->AddLog(CEC_LOG_DEBUG, "could not create a reader thread");
+  }
+
+  return false;
+}
+
+void CAdapterCommunication::Close(void)
+{
+  StopThread();
+  m_port->Close();
+}
+
+void *CAdapterCommunication::Process(void)
+{
+  while (!m_bStop)
+  {
+    if (!ReadFromDevice(250))
+    {
+      m_bStarted = false;
+      break;
+    }
+
+    CCondition::Sleep(50);
+  }
+
+  m_controller->AddLog(CEC_LOG_DEBUG, "reader thread terminated");
+
+  CLockObject lock(&m_commMutex);
+  m_bStarted = false;
+  return NULL;
+}
+
+bool CAdapterCommunication::ReadFromDevice(int iTimeout)
+{
+  uint8_t buff[1024];
+  CLockObject lock(&m_commMutex);
+  int iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
+  lock.Leave();
+  if (iBytesRead < 0)
+  {
+    CStdString strError;
+    strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
+    m_controller->AddLog(CEC_LOG_ERROR, strError);
+    return false;
+  }
+  else if (iBytesRead > 0)
+    AddData(buff, iBytesRead);
+
+  return true;
+}
+
+void CAdapterCommunication::AddData(uint8_t *data, int iLen)
+{
+  CLockObject lock(&m_bufferMutex);
+  if (iLen + m_iInbufUsed > m_iInbufSize)
+  {
+    m_iInbufSize = iLen + m_iInbufUsed;
+    m_inbuf = (uint8_t*)realloc(m_inbuf, m_iInbufSize);
+  }
+
+  memcpy(m_inbuf + m_iInbufUsed, data, iLen);
+  m_iInbufUsed += iLen;
+  lock.Leave();
+  m_condition.Signal();
+}
+
+bool CAdapterCommunication::Write(const cec_frame &data)
+{
+  CLockObject lock(&m_commMutex);
+
+  if (m_port->Write(data) != data.size())
+  {
+    CStdString strError;
+    strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
+    m_controller->AddLog(CEC_LOG_ERROR, strError);
+    return false;
+  }
+
+  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;
+}
+
+bool CAdapterCommunication::Read(cec_frame &msg, int iTimeout)
+{
+  CLockObject lock(&m_bufferMutex);
+
+  if (m_iInbufUsed < 1)
+    m_condition.Wait(&m_bufferMutex, iTimeout);
+
+  if (m_iInbufUsed < 1)
+    return false;
+
+  //search for first start of message
+  int startpos = -1;
+  for (int i = 0; i < m_iInbufUsed; i++)
+  {
+    if (m_inbuf[i] == MSGSTART)
+    {
+      startpos = i;
+      break;
+    }
+  }
+
+  if (startpos == -1)
+    return false;
+
+  //move anything from the first start of message to the beginning of the buffer
+  if (startpos > 0)
+  {
+    memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
+    m_iInbufUsed -= startpos;
+  }
+
+  if (m_iInbufUsed < 2)
+    return false;
+
+  //look for end of message
+  startpos = -1;
+  int endpos = -1;
+  for (int i = 1; i < m_iInbufUsed; i++)
+  {
+    if (m_inbuf[i] == MSGEND)
+    {
+      endpos = i;
+      break;
+    }
+    else if (m_inbuf[i] == MSGSTART)
+    {
+      startpos = i;
+      break;
+    }
+  }
+
+  if (startpos > 0) //we found a msgstart before msgend, this is not right, remove
+  {
+    m_controller->AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
+    memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
+    m_iInbufUsed -= startpos;
+    return false;
+  }
+
+  if (endpos > 0) //found a MSGEND
+  {
+    msg.clear();
+    bool isesc = false;
+    for (int i = 1; i < endpos; i++)
+    {
+      if (isesc)
+      {
+        msg.push_back(m_inbuf[i] + (uint8_t)ESCOFFSET);
+        isesc = false;
+      }
+      else if (m_inbuf[i] == MSGESC)
+      {
+        isesc = true;
+      }
+      else
+      {
+        msg.push_back(m_inbuf[i]);
+      }
+    }
+
+    if (endpos + 1 < m_iInbufUsed)
+      memmove(m_inbuf, m_inbuf + endpos + 1, m_iInbufUsed - endpos - 1);
+
+    m_iInbufUsed -= endpos + 1;
+
+    return true;
+  }
+
+  return false;
+}
+
+std::string CAdapterCommunication::GetError(void) const
+{
+  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;
+}
diff --git a/src/lib/AdapterCommunication.h b/src/lib/AdapterCommunication.h
new file mode 100644 (file)
index 0000000..f7dafa0
--- /dev/null
@@ -0,0 +1,77 @@
+#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 "util/threads.h"
+
+class CSerialPort;
+
+namespace CEC
+{
+  class CLibCEC;
+
+  class CAdapterCommunication : CThread
+  {
+  public:
+    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;
+    CLibCEC *            m_controller;
+    uint8_t*             m_inbuf;
+    int                  m_iInbufSize;
+    int                  m_iInbufUsed;
+    bool                 m_bStarted;
+    bool                 m_bStop;
+    CMutex               m_commMutex;
+    CMutex               m_bufferMutex;
+    CCondition           m_condition;
+  };
+};
similarity index 97%
rename from src/lib/CECDetect.cpp
rename to src/lib/AdapterDetection.cpp
index a8aa7e1cd531c29adbfb94572f8fabfdeaf06395..747ea16d24565f882e1890a9cad50c07326007f5 100644 (file)
  *     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>
@@ -101,7 +100,7 @@ bool FindComPort(CStdString &strLocation)
 }
 #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);
 
@@ -146,7 +145,7 @@ int CCECDetect::FindDevices(vector<cec_device> &deviceList, const char *strDevic
       CStdString strComm(strPath);
       if (FindComPort(strComm))
       {
-        cec_device foundDev;
+        cec_adapter foundDev;
         foundDev.path = strPath;
         foundDev.comm = strComm;
         deviceList.push_back(foundDev);
@@ -244,7 +243,7 @@ int CCECDetect::FindDevices(vector<cec_device> &deviceList, const char *strDevic
       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);
similarity index 91%
rename from src/lib/CECDetect.h
rename to src/lib/AdapterDetection.h
index b3cb7e052f92e5803d367a8bee9b84ba920f6bef..d775bbc88984a50417d6e38b3e0a3f3deb1e467d 100644 (file)
@@ -35,9 +35,9 @@
 
 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);
   };
 };
diff --git a/src/lib/CECParser.cpp b/src/lib/CECParser.cpp
deleted file mode 100644 (file)
index dad7a0d..0000000
+++ /dev/null
@@ -1,952 +0,0 @@
-/*
- * 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 "CECParser.h"
-
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <sys/stat.h>
-#include "util/StdString.h"
-#include "libPlatform/serialport.h"
-#include "util/threads.h"
-#include "util/timeutils.h"
-#include "CECDetect.h"
-
-using namespace CEC;
-using namespace std;
-
-#define CEC_MAX_RETRY 5
-
-/*!
- * ICECDevice implementation
- */
-//@{
-CCECParser::CCECParser(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
-    m_inbuf(NULL),
-    m_iInbufSize(0),
-    m_iInbufUsed(0),
-    m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
-    m_physicaladdress(iPhysicalAddress),
-    m_iLogicalAddress(iLogicalAddress),
-    m_strDeviceName(strDeviceName),
-    m_bRunning(false)
-{
-  m_serialport = new CSerialPort;
-}
-
-CCECParser::~CCECParser(void)
-{
-  Close(0);
-  m_serialport->Close();
-  delete m_serialport;
-}
-
-bool CCECParser::Open(const char *strPort, int iTimeoutMs /* = 10000 */)
-{
-  bool bReturn(false);
-
-  if (!(bReturn = m_serialport->Open(strPort, 38400)))
-  {
-    CStdString strError;
-    strError.Format("error opening serial port '%s': %s", strPort, m_serialport->GetError().c_str());
-    AddLog(CEC_LOG_ERROR, strError);
-    return bReturn;
-  }
-
-  //clear any input bytes
-  uint8_t buff[1024];
-  m_serialport->Read(buff, sizeof(buff), CEC_SETTLE_DOWN_TIME);
-
-  if (bReturn)
-    bReturn = SetLogicalAddress(m_iLogicalAddress);
-
-  if (!bReturn)
-  {
-    CStdString strError;
-    strError.Format("error opening serial port '%s': %s", strPort, m_serialport->GetError().c_str());
-    AddLog(CEC_LOG_ERROR, strError);
-    return bReturn;
-  }
-
-  if (bReturn)
-  {
-    m_bRunning = true;
-    if (pthread_create(&m_thread, NULL, (void *(*) (void *))&CCECParser::ThreadHandler, (void *)this) == 0)
-      pthread_detach(m_thread);
-    else
-      m_bRunning = false;
-  }
-
-  return bReturn;
-}
-
-bool CCECParser::Close(int iTimeoutMs /* = 2000 */)
-{
-  m_bRunning = false;
-  bool bExit(false);
-  if (iTimeoutMs > 0)
-  {
-    bExit = m_exitCondition.Wait(&m_mutex, iTimeoutMs);
-    m_mutex.Unlock();
-  }
-  else
-  {
-    pthread_join(m_thread, NULL);
-    bExit = true;
-  }
-
-  return bExit;
-}
-
-void *CCECParser::ThreadHandler(CCECParser *parser)
-{
-  if (parser)
-    parser->Process();
-  return 0;
-}
-
-bool CCECParser::Process(void)
-{
-  int64_t now = GetTimeMs();
-  while (m_bRunning)
-  {
-    {
-      CLockObject lock(&m_mutex, 1000);
-      if (lock.IsLocked())
-      {
-        if (!ReadFromDevice(100))
-        {
-          m_bRunning = false;
-          return false;
-        }
-      }
-    }
-
-    //AddLog(CEC_LOG_DEBUG, "processing messages");
-    ProcessMessages();
-    now = GetTimeMs();
-    CheckKeypressTimeout(now);
-    CCondition::Sleep(50);
-  }
-
-  AddLog(CEC_LOG_DEBUG, "reader thread terminated");
-  m_bRunning = false;
-  m_exitCondition.Signal();
-  return true;
-}
-
-bool CCECParser::Ping(void)
-{
-  if (!m_bRunning)
-    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, (int64_t) 5000))
-  {
-    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 (!m_bRunning)
-    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, (int64_t) 5000))
-  {
-    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 */)
-{
-  if (!m_bRunning)
-    return false;
-
-  CStdString strLog;
-  strLog.Format("powering off devices with logical address %d", (int8_t)address);
-  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::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
-{
-  if (!m_bRunning)
-    return false;
-
-  CStdString strLog;
-  strLog.Format("powering on devices with logical address %d", (int8_t)address);
-  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 */)
-{
-  if (!m_bRunning)
-    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());
-  cec_frame frame;
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back(CEC_OPCODE_STANDBY);
-  return Transmit(frame);
-}
-
-bool CCECParser::SetActiveView(void)
-{
-  if (!m_bRunning)
-    return false;
-
-  AddLog(CEC_LOG_DEBUG, "setting active view");
-  cec_frame frame;
-  frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
-  frame.push_back(CEC_OPCODE_ACTIVE_SOURCE);
-  frame.push_back((m_physicaladdress >> 8) & 0xFF);
-  frame.push_back(m_physicaladdress & 0xFF);
-  return Transmit(frame);
-}
-
-bool CCECParser::SetInactiveView(void)
-{
-  if (!m_bRunning)
-    return false;
-
-  AddLog(CEC_LOG_DEBUG, "setting inactive view");
-  cec_frame frame;
-  frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
-  frame.push_back(CEC_OPCODE_INACTIVE_SOURCE);
-  frame.push_back((m_physicaladdress >> 8) & 0xFF);
-  frame.push_back(m_physicaladdress & 0xFF);
-  return Transmit(frame);
-}
-
-bool CCECParser::GetNextLogMessage(cec_log_message *message)
-{
-  return m_bRunning ? m_logBuffer.Pop(*message) : false;
-}
-
-bool CCECParser::GetNextKeypress(cec_keypress *key)
-{
-  return m_bRunning ? m_keyBuffer.Pop(*key) : false;
-}
-
-bool CCECParser::GetNextCommand(cec_command *command)
-{
-  return m_bRunning ? m_commandBuffer.Pop(*command) : false;
-}
-//@}
-
-void CCECParser::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
-{
-  AddLog(CEC_LOG_DEBUG, "transmitting abort message");
-  cec_frame frame;
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back(CEC_OPCODE_FEATURE_ABORT);
-  frame.push_back(opcode);
-  frame.push_back(reason);
-  Transmit(frame);
-}
-
-void CCECParser::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
-{
-  cec_frame frame;
-  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 */)
-{
-  cec_frame frame;
-  if (bOn)
-    AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
-  else
-    AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
-
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back(CEC_OPCODE_REPORT_POWER_STATUS);
-  frame.push_back(bOn ? CEC_POWER_STATUS_ON : CEC_POWER_STATUS_STANDBY);
-  Transmit(frame);
-}
-
-void CCECParser::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
-{
-  cec_frame frame;
-  if (bActive)
-    AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
-  else
-    AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
-
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back(CEC_OPCODE_MENU_STATUS);
-  frame.push_back(bActive ? CEC_MENU_STATE_ACTIVATED : CEC_MENU_STATE_DEACTIVATED);
-  Transmit(frame);
-}
-
-void CCECParser::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
-{
-  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 */)
-{
-  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());
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back(CEC_OPCODE_SET_OSD_NAME);
-
-  for (unsigned int i = 0; i < strlen(osdname); i++)
-    frame.push_back(osdname[i]);
-
-  Transmit(frame);
-}
-
-void CCECParser::ReportPhysicalAddress(void)
-{
-  cec_frame frame;
-  CStdString strLog;
-  strLog.Format("reporting physical address as %04x", m_physicaladdress);
-  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);
-  frame.push_back(m_physicaladdress & 0xFF);
-  frame.push_back(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
-  Transmit(frame);
-}
-
-void CCECParser::BroadcastActiveSource(void)
-{
-  cec_frame frame;
-  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);
-  frame.push_back(m_physicaladdress & 0xFF);
-  Transmit(frame);
-}
-
-bool CCECParser::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */, int64_t iTimeout /* = 2000 */)
-{
-  CLockObject lock(&m_mutex, iTimeout);
-  if (!lock.IsLocked())
-  {
-    AddLog(CEC_LOG_ERROR, "could not get a write lock");
-    return false;
-  }
-
-  if (m_serialport->Write(data) != data.size())
-  {
-    CStdString strError;
-    strError.Format("error writing to serial port: %s", m_serialport->GetError().c_str());
-    AddLog(CEC_LOG_ERROR, strError);
-    return false;
-  }
-  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 */);
-  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 */, int64_t iTimeout /* = 5000 */)
-{
-  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, iTimeout);
-}
-
-bool CCECParser::WaitForAck(int64_t iTimeout /* = 1000 */)
-{
-  bool bGotAck(false);
-  bool bError(false);
-
-  int64_t iNow = GetTimeMs();
-  int64_t iTargetTime = iNow + iTimeout;
-
-  while (!bGotAck && !bError && (iTimeout <= 0 || iNow < iTargetTime))
-  {
-    if (!ReadFromDevice((int) iTimeout))
-    {
-      AddLog(CEC_LOG_ERROR, "failed to read from device");
-      return false;
-    }
-
-    cec_frame msg;
-    while (!bGotAck && !bError && GetMessage(msg, false))
-    {
-      uint8_t iCode = msg[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
-
-      switch (iCode)
-      {
-      case MSGCODE_COMMAND_ACCEPTED:
-        AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
-        break;
-      case MSGCODE_TRANSMIT_SUCCEEDED:
-        AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
-        // TODO
-        bGotAck = true;
-        break;
-      case MSGCODE_RECEIVE_FAILED:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
-        bError = true;
-        break;
-      case MSGCODE_COMMAND_REJECTED:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
-        bError = true;
-        break;
-      case MSGCODE_TRANSMIT_FAILED_LINE:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
-        bError = true;
-        break;
-      case MSGCODE_TRANSMIT_FAILED_ACK:
-        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");
-        bError = true;
-        break;
-      case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
-        bError = true;
-        break;
-      default:
-        m_frameBuffer.Push(msg);
-        bGotAck = (msg[0] & MSGCODE_FRAME_ACK) != 0;
-        break;
-      }
-      iNow = GetTimeMs();
-    }
-  }
-
-  return bGotAck && !bError;
-}
-
-bool CCECParser::ReadFromDevice(int iTimeout)
-{
-  uint8_t buff[1024];
-  int iBytesRead = m_serialport->Read(buff, sizeof(buff), iTimeout);
-  if (iBytesRead < 0)
-  {
-    CStdString strError;
-    strError.Format("error reading from serial port: %s", m_serialport->GetError().c_str());
-    AddLog(CEC_LOG_ERROR, strError);
-    return false;
-  }
-  else if (iBytesRead > 0)
-    AddData(buff, iBytesRead);
-
-  return true;
-}
-
-void CCECParser::ProcessMessages(void)
-{
-  cec_frame msg;
-  while (m_bRunning && GetMessage(msg))
-    ParseMessage(msg);
-}
-
-bool CCECParser::GetMessage(cec_frame &msg, bool bFromBuffer /* = true */)
-{
-  if (bFromBuffer && m_frameBuffer.Pop(msg))
-    return true;
-
-  if (m_iInbufUsed < 1)
-    return false;
-
-  //search for first start of message
-  int startpos = -1;
-  for (int i = 0; i < m_iInbufUsed; i++)
-  {
-    if (m_inbuf[i] == MSGSTART)
-    {
-      startpos = i;
-      break;
-    }
-  }
-
-  if (startpos == -1)
-    return false;
-
-  //move anything from the first start of message to the beginning of the buffer
-  if (startpos > 0)
-  {
-    memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
-    m_iInbufUsed -= startpos;
-  }
-
-  if (m_iInbufUsed < 2)
-    return false;
-
-  //look for end of message
-  startpos = -1;
-  int endpos = -1;
-  for (int i = 1; i < m_iInbufUsed; i++)
-  {
-    if (m_inbuf[i] == MSGEND)
-    {
-      endpos = i;
-      break;
-    }
-    else if (m_inbuf[i] == MSGSTART)
-    {
-      startpos = i;
-      break;
-    }
-  }
-
-  if (startpos > 0) //we found a msgstart before msgend, this is not right, remove
-  {
-    AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
-    memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
-    m_iInbufUsed -= startpos;
-    return false;
-  }
-
-  if (endpos > 0) //found a MSGEND
-  {
-    msg.clear();
-    bool isesc = false;
-    for (int i = 1; i < endpos; i++)
-    {
-      if (isesc)
-      {
-        msg.push_back(m_inbuf[i] + (uint8_t)ESCOFFSET);
-        isesc = false;
-      }
-      else if (m_inbuf[i] == MSGESC)
-      {
-        isesc = true;
-      }
-      else
-      {
-        msg.push_back(m_inbuf[i]);
-      }
-    }
-
-    if (endpos + 1 < m_iInbufUsed)
-      memmove(m_inbuf, m_inbuf + endpos + 1, m_iInbufUsed - endpos - 1);
-
-    m_iInbufUsed -= endpos + 1;
-
-    return true;
-  }
-
-  return false;
-}
-
-void CCECParser::ParseMessage(cec_frame &msg)
-{
-  if (msg.empty())
-    return;
-
-  CStdString logStr;
-  uint8_t iCode = msg[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
-  bool    bEom  = (msg[0] & MSGCODE_FRAME_EOM) != 0;
-  bool    bAck  = (msg[0] & MSGCODE_FRAME_ACK) != 0;
-
-  switch(iCode)
-  {
-  case MSGCODE_NOTHING:
-    AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
-    break;
-  case MSGCODE_TIMEOUT_ERROR:
-  case MSGCODE_HIGH_ERROR:
-  case MSGCODE_LOW_ERROR:
-    {
-      if (iCode == MSGCODE_TIMEOUT_ERROR)
-        logStr = "MSGCODE_TIMEOUT";
-      else if (iCode == MSGCODE_HIGH_ERROR)
-        logStr = "MSGCODE_HIGH_ERROR";
-      else
-        logStr = "MSGCODE_LOW_ERROR";
-
-      int iLine      = (msg.size() >= 3) ? (msg[1] << 8) | (msg[2]) : 0;
-      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());
-    }
-    break;
-  case MSGCODE_FRAME_START:
-    {
-      logStr = "MSGCODE_FRAME_START";
-      m_currentframe.clear();
-      if (msg.size() >= 2)
-      {
-        int iInitiator = msg[1] >> 4;
-        int iDestination = msg[1] & 0xF;
-        logStr.AppendFormat(" initiator:%u destination:%u ack:%s %s", iInitiator, iDestination, bAck ? "high" : "low", bEom ? "eom" : "");
-
-        m_currentframe.push_back(msg[1]);
-      }
-      AddLog(CEC_LOG_DEBUG, logStr.c_str());
-    }
-    break;
-  case MSGCODE_FRAME_DATA:
-    {
-      logStr = "MSGCODE_FRAME_DATA";
-      if (msg.size() >= 2)
-      {
-        uint8_t iData = msg[1];
-        logStr.AppendFormat(" %02x", iData);
-        m_currentframe.push_back(iData);
-      }
-      AddLog(CEC_LOG_DEBUG, logStr.c_str());
-    }
-    if (bEom)
-      ParseCurrentFrame();
-    break;
-  default:
-    break;
-  }
-}
-
-void CCECParser::ParseCurrentFrame(void)
-{
-  uint8_t initiator = m_currentframe[0] >> 4;
-  uint8_t destination = m_currentframe[0] & 0xF;
-
-  CStdString dataStr;
-  dataStr.Format("received frame: initiator: %u destination: %u", initiator, destination);
-
-  if (m_currentframe.size() > 1)
-  {
-    dataStr += " data:";
-    for (unsigned int i = 1; i < m_currentframe.size(); i++)
-      dataStr.AppendFormat(" %02x", m_currentframe[i]);
-  }
-  AddLog(CEC_LOG_DEBUG, dataStr.c_str());
-
-  if (m_currentframe.size() <= 1)
-    return;
-
-  vector<uint8_t> tx;
-  cec_opcode opCode = (cec_opcode) m_currentframe[1];
-  if (destination == (uint16_t) m_iLogicalAddress)
-  {
-    switch(opCode)
-    {
-    case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
-      ReportPhysicalAddress();
-      SetActiveView();
-      break;
-    case CEC_OPCODE_GIVE_OSD_NAME:
-      ReportOSDName((cec_logical_address)initiator);
-      break;
-    case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-      ReportVendorID((cec_logical_address)initiator);
-      break;
-    case CEC_OPCODE_MENU_REQUEST:
-      ReportMenuState((cec_logical_address)initiator);
-      break;
-    case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-      ReportPowerState((cec_logical_address)initiator);
-      break;
-    case CEC_OPCODE_GET_CEC_VERSION:
-      ReportCECVersion((cec_logical_address)initiator);
-      break;
-    case CEC_OPCODE_USER_CONTROL_PRESSED:
-      if (m_currentframe.size() > 2)
-      {
-        AddKey();
-
-        if (m_currentframe[2] <= CEC_USER_CONTROL_CODE_MAX)
-        {
-          m_iCurrentButton = (cec_user_control_code) m_currentframe[2];
-          m_buttontime = GetTimeMs();
-        }
-      }
-      break;
-    case CEC_OPCODE_USER_CONTROL_RELEASE:
-      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, &params);
-      break;
-    }
-  }
-  else if (destination == (uint8_t) CECDEVICE_BROADCAST)
-  {
-    if (opCode == CEC_OPCODE_REQUEST_ACTIVE_SOURCE)
-    {
-      BroadcastActiveSource();
-    }
-    else if (opCode == CEC_OPCODE_SET_STREAM_PATH)
-    {
-      if (m_currentframe.size() >= 4)
-      {
-        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());
-        if (streamaddr == m_physicaladdress)
-          BroadcastActiveSource();
-      }
-    }
-    else
-    {
-      cec_frame params = m_currentframe;
-      params.erase(params.begin(), params.begin() + 2);
-      AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
-    }
-  }
-  else
-  {
-    CStdString strLog;
-    strLog.Format("ignoring frame: destination: %u != %u", destination, (uint16_t)m_iLogicalAddress);
-    AddLog(CEC_LOG_DEBUG, strLog.c_str());
-  }
-}
-
-void CCECParser::AddData(uint8_t *data, int iLen)
-{
-  if (iLen + m_iInbufUsed > m_iInbufSize)
-  {
-    m_iInbufSize = iLen + m_iInbufUsed;
-    m_inbuf = (uint8_t*)realloc(m_inbuf, m_iInbufSize);
-  }
-
-  memcpy(m_inbuf + m_iInbufUsed, data, iLen);
-  m_iInbufUsed += iLen;
-}
-
-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 > 500)
-  {
-    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_serialport->Write(output) == -1)
-  {
-    strLog.Format("error writing to serial port: %s", m_serialport->GetError().c_str());
-    AddLog(CEC_LOG_ERROR, strLog);
-    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));
-}
diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp
new file mode 100644 (file)
index 0000000..f3b89c3
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * 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 "CECProcessor.h"
+
+#include "AdapterCommunication.h"
+#include "LibCEC.h"
+#include "util/StdString.h"
+#include "util/timeutils.h"
+
+using namespace CEC;
+using namespace std;
+
+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_communication(serComm),
+    m_controller(controller)
+{
+}
+
+CCECProcessor::~CCECProcessor(void)
+{
+  StopThread();
+  m_communication = NULL;
+  m_controller = NULL;
+}
+
+bool CCECProcessor::Start(void)
+{
+  if (!m_communication || !m_communication->IsOpen())
+    return false;
+
+  if (!SetLogicalAddress(m_iLogicalAddress))
+  {
+    m_controller->AddLog(CEC_LOG_ERROR, "could not set the logical address");
+    return false;
+  }
+
+  if (CreateThread())
+    return true;
+  else
+    m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+
+  return false;
+}
+
+void *CCECProcessor::Process(void)
+{
+  m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
+
+  while (!m_bStop)
+  {
+    bool bParseFrame(false);
+    {
+      CLockObject lock(&m_mutex);
+      cec_frame msg;
+      if (!m_bStop && m_communication->IsOpen() && m_communication->Read(msg, CEC_BUTTON_TIMEOUT))
+        bParseFrame = ParseMessage(msg);
+    }
+
+    if (bParseFrame)
+      ParseCurrentFrame();
+
+    m_controller->CheckKeypressTimeout();
+    CCondition::Sleep(50);
+  }
+
+  m_controller->AddLog(CEC_LOG_DEBUG, "processor thread terminated");
+  return NULL;
+}
+
+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);
+  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 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);
+  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 CCECProcessor::SetActiveView(void)
+{
+  if (!IsRunning())
+    return false;
+
+  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);
+  frame.push_back((m_physicaladdress >> 8) & 0xFF);
+  frame.push_back(m_physicaladdress & 0xFF);
+  return Transmit(frame);
+}
+
+bool CCECProcessor::SetInactiveView(void)
+{
+  if (!IsRunning())
+    return false;
+
+  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);
+  frame.push_back((m_physicaladdress >> 8) & 0xFF);
+  frame.push_back(m_physicaladdress & 0xFF);
+  return Transmit(frame);
+}
+
+bool CCECProcessor::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
+{
+  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 CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
+{
+  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 CCECProcessor::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */)
+{
+  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 CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
+{
+  m_controller->AddLog(CEC_LOG_DEBUG, "transmitting abort message");
+  cec_frame frame;
+  frame.push_back(GetSourceDestination(address));
+  frame.push_back(CEC_OPCODE_FEATURE_ABORT);
+  frame.push_back(opcode);
+  frame.push_back(reason);
+  Transmit(frame);
+}
+
+void CCECProcessor::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
+{
+  cec_frame frame;
+  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 CCECProcessor::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
+{
+  cec_frame frame;
+  if (bOn)
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
+  else
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
+
+  frame.push_back(GetSourceDestination(address));
+  frame.push_back(CEC_OPCODE_REPORT_POWER_STATUS);
+  frame.push_back(bOn ? CEC_POWER_STATUS_ON : CEC_POWER_STATUS_STANDBY);
+  Transmit(frame);
+}
+
+void CCECProcessor::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
+{
+  cec_frame frame;
+  if (bActive)
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
+  else
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
+
+  frame.push_back(GetSourceDestination(address));
+  frame.push_back(CEC_OPCODE_MENU_STATUS);
+  frame.push_back(bActive ? CEC_MENU_STATE_ACTIVATED : CEC_MENU_STATE_DEACTIVATED);
+  Transmit(frame);
+}
+
+void CCECProcessor::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
+{
+  m_controller->AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
+  TransmitAbort(address, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+}
+
+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);
+  m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
+  frame.push_back(GetSourceDestination(address));
+  frame.push_back(CEC_OPCODE_SET_OSD_NAME);
+
+  for (unsigned int i = 0; i < strlen(osdname); i++)
+    frame.push_back(osdname[i]);
+
+  Transmit(frame);
+}
+
+void CCECProcessor::ReportPhysicalAddress(void)
+{
+  cec_frame frame;
+  CStdString strLog;
+  strLog.Format("reporting physical address as %04x", m_physicaladdress);
+  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);
+  frame.push_back(m_physicaladdress & 0xFF);
+  frame.push_back(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+  Transmit(frame);
+}
+
+void CCECProcessor::BroadcastActiveSource(void)
+{
+  cec_frame frame;
+  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);
+  frame.push_back(m_physicaladdress & 0xFF);
+  Transmit(frame);
+}
+
+uint8_t CCECProcessor::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */) const
+{
+  return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
+}
+
+bool CCECProcessor::WaitForAck(int iTimeout /* = 1000 */)
+{
+  bool bGotAck(false);
+  bool bError(false);
+
+  int64_t iNow = GetTimeMs();
+  int64_t iTargetTime = iNow + (int64_t) iTimeout;
+
+  while (!bGotAck && !bError && (iTimeout <= 0 || iNow < iTargetTime))
+  {
+    cec_frame msg;
+    while (!bGotAck && !bError && m_communication->Read(msg, iTimeout))
+    {
+      uint8_t iCode = msg[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
+
+      switch (iCode)
+      {
+      case MSGCODE_COMMAND_ACCEPTED:
+        m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
+        break;
+      case MSGCODE_TRANSMIT_SUCCEEDED:
+        m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
+        // TODO
+        bGotAck = true;
+        break;
+      case MSGCODE_RECEIVE_FAILED:
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
+        bError = true;
+        break;
+      case MSGCODE_COMMAND_REJECTED:
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
+        bError = true;
+        break;
+      case MSGCODE_TRANSMIT_FAILED_LINE:
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
+        bError = true;
+        break;
+      case MSGCODE_TRANSMIT_FAILED_ACK:
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_ACK");
+        bError = true;
+        break;
+      case 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:
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
+        bError = true;
+        break;
+      default:
+        m_frameBuffer.Push(msg);
+        bGotAck = (msg[0] & MSGCODE_FRAME_ACK) != 0;
+        break;
+      }
+      iNow = GetTimeMs();
+    }
+  }
+
+  return bGotAck && !bError;
+}
+
+bool CCECProcessor::ParseMessage(cec_frame &msg)
+{
+  bool bReturn(false);
+
+  if (msg.empty())
+    return bReturn;
+
+  CStdString logStr;
+  uint8_t iCode = msg[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
+  bool    bEom  = (msg[0] & MSGCODE_FRAME_EOM) != 0;
+  bool    bAck  = (msg[0] & MSGCODE_FRAME_ACK) != 0;
+
+  switch(iCode)
+  {
+  case MSGCODE_NOTHING:
+    m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
+    break;
+  case MSGCODE_TIMEOUT_ERROR:
+  case MSGCODE_HIGH_ERROR:
+  case MSGCODE_LOW_ERROR:
+    {
+      if (iCode == MSGCODE_TIMEOUT_ERROR)
+        logStr = "MSGCODE_TIMEOUT";
+      else if (iCode == MSGCODE_HIGH_ERROR)
+        logStr = "MSGCODE_HIGH_ERROR";
+      else
+        logStr = "MSGCODE_LOW_ERROR";
+
+      int iLine      = (msg.size() >= 3) ? (msg[1] << 8) | (msg[2]) : 0;
+      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);
+      m_controller->AddLog(CEC_LOG_WARNING, logStr.c_str());
+    }
+    break;
+  case MSGCODE_FRAME_START:
+    {
+      logStr = "MSGCODE_FRAME_START";
+      m_currentframe.clear();
+      if (msg.size() >= 2)
+      {
+        int iInitiator = msg[1] >> 4;
+        int iDestination = msg[1] & 0xF;
+        logStr.AppendFormat(" initiator:%u destination:%u ack:%s %s", iInitiator, iDestination, bAck ? "high" : "low", bEom ? "eom" : "");
+
+        m_currentframe.push_back(msg[1]);
+      }
+      m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
+    }
+    break;
+  case MSGCODE_FRAME_DATA:
+    {
+      logStr = "MSGCODE_FRAME_DATA";
+      if (msg.size() >= 2)
+      {
+        uint8_t iData = msg[1];
+        logStr.AppendFormat(" %02x", iData);
+        m_currentframe.push_back(iData);
+      }
+      m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
+    }
+    if (bEom)
+      bReturn = true;
+    break;
+  default:
+    break;
+  }
+
+  return bReturn;
+}
+
+void CCECProcessor::ParseCurrentFrame(void)
+{
+  uint8_t initiator = m_currentframe[0] >> 4;
+  uint8_t destination = m_currentframe[0] & 0xF;
+
+  CStdString dataStr;
+  dataStr.Format("received frame: initiator: %u destination: %u", initiator, destination);
+
+  if (m_currentframe.size() > 1)
+  {
+    dataStr += " data:";
+    for (unsigned int i = 1; i < m_currentframe.size(); i++)
+      dataStr.AppendFormat(" %02x", m_currentframe[i]);
+  }
+  m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str());
+
+  if (m_currentframe.size() <= 1)
+    return;
+
+  vector<uint8_t> tx;
+  cec_opcode opCode = (cec_opcode) m_currentframe[1];
+  if (destination == (uint16_t) m_iLogicalAddress)
+  {
+    switch(opCode)
+    {
+    case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+      ReportPhysicalAddress();
+      SetActiveView();
+      break;
+    case CEC_OPCODE_GIVE_OSD_NAME:
+      ReportOSDName((cec_logical_address)initiator);
+      break;
+    case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+      ReportVendorID((cec_logical_address)initiator);
+      break;
+    case CEC_OPCODE_MENU_REQUEST:
+      ReportMenuState((cec_logical_address)initiator);
+      break;
+    case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+      ReportPowerState((cec_logical_address)initiator);
+      break;
+    case CEC_OPCODE_GET_CEC_VERSION:
+      ReportCECVersion((cec_logical_address)initiator);
+      break;
+    case CEC_OPCODE_USER_CONTROL_PRESSED:
+      if (m_currentframe.size() > 2)
+      {
+        m_controller->AddKey();
+
+        if (m_currentframe[2] <= CEC_USER_CONTROL_CODE_MAX)
+          m_controller->SetCurrentButton((cec_user_control_code) m_currentframe[2]);
+      }
+      break;
+    case CEC_OPCODE_USER_CONTROL_RELEASE:
+      m_controller->AddKey();
+      break;
+    default:
+      cec_frame params = m_currentframe;
+      params.erase(params.begin(), params.begin() + 2);
+      m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+      break;
+    }
+  }
+  else if (destination == (uint8_t) CECDEVICE_BROADCAST)
+  {
+    if (opCode == CEC_OPCODE_REQUEST_ACTIVE_SOURCE)
+    {
+      BroadcastActiveSource();
+    }
+    else if (opCode == CEC_OPCODE_SET_STREAM_PATH)
+    {
+      if (m_currentframe.size() >= 4)
+      {
+        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);
+        m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+        if (streamaddr == m_physicaladdress)
+          BroadcastActiveSource();
+      }
+    }
+    else
+    {
+      cec_frame params = m_currentframe;
+      params.erase(params.begin(), params.begin() + 2);
+      m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+    }
+  }
+  else
+  {
+    CStdString strLog;
+    strLog.Format("ignoring frame: destination: %u != %u", destination, (uint16_t)m_iLogicalAddress);
+    m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+  }
+}
similarity index 55%
rename from src/lib/CECParser.h
rename to src/lib/CECProcessor.h
index be958553cb8ea9b22502d5ac44594064521ca199..339653c3bf8164fa988897d91bded8e98857468b 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
-#include <queue>
-#include <stdio.h>
 #include "../../include/CECExports.h"
 #include "../../include/CECTypes.h"
+#include "util/threads.h"
 #include "util/buffer.h"
 
 class CSerialPort;
 
 namespace CEC
 {
-  class CCECParser : public ICECDevice
+  class CLibCEC;
+  class CAdapterCommunication;
+
+  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 bool Close(int iTimeoutMs = 2000);
-      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_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, int64_t iTimeout = (int64_t) 5000);
+      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);
-    //@}
-
-      static void *ThreadHandler(CCECParser *parser);
-      bool Process(void);
     protected:
-      virtual bool TransmitFormatted(const cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 2000);
+      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 ReportCECVersion(cec_logical_address address = CECDEVICE_TV);
       virtual void ReportPowerState(cec_logical_address address = CECDEVICE_TV, bool bOn = true);
@@ -83,41 +68,20 @@ namespace CEC
       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);
-      void AddLog(cec_log_level level, const std::string &strMessage);
-      bool WaitForAck(int64_t iTimeout = (int64_t) 1000);
-      bool ReadFromDevice(int iTimeout);
-      void ProcessMessages(void);
-      bool GetMessage(cec_frame &msg, bool bFromBuffer = true);
-      void ParseMessage(cec_frame &msg);
+      bool WaitForAck(int iTimeout = 1000);
+      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);
-
-      uint8_t*                   m_inbuf;
-      int                        m_iInbufSize;
-      int                        m_iInbufUsed;
-      CSerialPort *              m_serialport;
       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;
-      pthread_t                  m_thread;
       CMutex                     m_mutex;
-      CCondition                 m_exitCondition;
-      bool                       m_bRunning;
+      CAdapterCommunication     *m_communication;
+      CLibCEC                   *m_controller;
   };
 };
diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp
new file mode 100644 (file)
index 0000000..23c4b18
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * 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));
+}
diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h
new file mode 100644 (file)
index 0000000..b863cb4
--- /dev/null
@@ -0,0 +1,90 @@
+#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;
+  };
+};
similarity index 79%
rename from src/lib/CECParserC.cpp
rename to src/lib/LibCECC.cpp
index b21f1c0b461a3d17358983e3dfdda9afd8ec4821..7f2475b5eb38118b28090f79b516f4b2e1c3284d 100644 (file)
@@ -30,7 +30,7 @@
  *     http://www.pulse-eight.net/
  */
 
-#include "CECParser.h"
+#include "LibCEC.h"
 
 using namespace CEC;
 using namespace std;
@@ -39,79 +39,67 @@ 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);
 }
 
-bool cec_open(const char *strPort, int iTimeout)
-{
-  if (cec_parser)
-    return cec_parser->Open(strPort, iTimeout);
-  return false;
-}
-
-bool cec_close(int iTimeout)
+void cec_destroy(void)
 {
-  bool bReturn = false;
-  if (cec_parser)
-    bReturn = cec_parser->Close(iTimeout);
-
+  cec_close();
   delete cec_parser;
   cec_parser = NULL;
-  return bReturn;
 }
 
-bool cec_ping(void)
+bool cec_open(const char *strPort, int iTimeout)
 {
   if (cec_parser)
-    return cec_parser->Ping();
+    return cec_parser->Open(strPort, iTimeout);
   return false;
 }
 
-bool cec_start_bootloader(void)
+void cec_close(void)
 {
   if (cec_parser)
-    return cec_parser->StartBootloader();
-  return false;
+    cec_parser->Close();
 }
 
-bool cec_power_off_devices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+int cec_find_adapters(vector<cec_adapter> &deviceList, const char *strDevicePath /* = NULL */)
 {
   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)
@@ -135,10 +123,10 @@ bool cec_get_next_command(cec_command *command)
   return false;
 }
 
-bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck /* = true */, int64_t iTimeout /* = 2000 */)
+bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck /* = true */)
 {
   if (cec_parser)
-    return cec_parser->Transmit(data, bWaitForAck, iTimeout);
+    return cec_parser->Transmit(data, bWaitForAck);
   return false;
 }
 
@@ -149,32 +137,32 @@ bool cec_set_logical_address(cec_logical_address iLogicalAddress)
   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;
 }
 
 //@}
similarity index 98%
rename from src/lib/CECDll.cpp
rename to src/lib/LibCECDll.cpp
index ad9016415c2db86f1a2049273beb048e7e2bb328..fb25d0e2c1e0807f6941c82ce243fa6db0dae645 100644 (file)
@@ -31,7 +31,6 @@
  */
 
 #include "CECExports.h"
-#include "CECParser.h"
 
 using namespace CEC;
 
index ca89d5a77aedc3cf8018586f1eda74624eb8120c..47664b8758a7ddf4b20c67a6014425af79978426 100644 (file)
@@ -8,16 +8,20 @@ pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libcec.pc
 
 
-libcec_la_SOURCES = CECParser.cpp \
-                    CECParser.h \
-                    CECParserC.cpp \
-                    CECDetect.cpp \
-                    CECDetect.h \
+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 \
index 3e40c2ba0370288cb668662514a91f52b3f10405..58aff3630f61314d5f695b266e173de4832508bd 100644 (file)
 CMutex::CMutex(void)
 {
   pthread_mutex_init(&m_mutex, NULL);
-  m_condition = new CCondition();
-  m_bLocked = false;
 }
 
 CMutex::~CMutex(void)
 {
-  delete m_condition;
   pthread_mutex_destroy(&m_mutex);
 }
 
-bool CMutex::TryLock(int64_t iTimeout)
+bool CMutex::TryLock(void)
 {
-  m_bLocked = (pthread_mutex_trylock(&m_mutex) == 0);
-  if (!m_bLocked)
-  {
-    if (m_condition->Wait(this, iTimeout))
-      m_bLocked = (pthread_mutex_trylock(&m_mutex) == 0);
-  }
-
-  return m_bLocked;
+  return (pthread_mutex_trylock(&m_mutex) == 0);
 }
 
 bool CMutex::Lock(void)
 {
-  m_bLocked = (pthread_mutex_lock(&m_mutex) == 0);
-  return m_bLocked;
+  return (pthread_mutex_lock(&m_mutex) == 0);
 }
 
 void CMutex::Unlock(void)
 {
   pthread_mutex_unlock(&m_mutex);
-  m_bLocked = false;
-  m_condition->Signal();
 }
 
-CLockObject::CLockObject(CMutex *mutex, int64_t iTimeout /* = -1 */) :
-  m_mutex(mutex),
-  m_bLocked(false)
+CLockObject::CLockObject(CMutex *mutex) :
+  m_mutex(mutex)
 {
-  if (iTimeout > 0)
-    m_bLocked = m_mutex->TryLock(iTimeout);
-  else
-    m_bLocked = m_mutex->Lock();
+  m_mutex->Lock();
 }
 
 CLockObject::~CLockObject(void)
 {
-  m_mutex->Unlock();
-  m_bLocked = false;
+  Leave();
   m_mutex = NULL;
 }
 
+void CLockObject::Leave(void)
+{
+  m_mutex->Unlock();
+}
+
+void CLockObject::Lock(void)
+{
+  m_mutex->Lock();
+}
+
 CCondition::CCondition(void)
 {
   pthread_cond_init(&m_cond, NULL);
-  m_bSignaled = false;
 }
 
 CCondition::~CCondition(void)
@@ -107,6 +98,7 @@ void CCondition::Signal(void)
 
 bool CCondition::Wait(CMutex *mutex, int64_t iTimeout)
 {
+  bool bReturn(false);
   struct timespec abstime;
   struct timeval now;
   if (gettimeofday(&now, NULL) == 0)
@@ -114,14 +106,9 @@ bool CCondition::Wait(CMutex *mutex, int64_t iTimeout)
     iTimeout       += now.tv_usec / 1000;
     abstime.tv_sec  = now.tv_sec + (time_t)(iTimeout / 1000);
     abstime.tv_nsec = (long)((iTimeout % (unsigned long)1000) * (unsigned long)1000000);
-    m_bSignaled     = (pthread_cond_timedwait(&m_cond, &mutex->m_mutex, &abstime) == 0);
-    if (!m_bSignaled)
-      pthread_mutex_unlock(&mutex->m_mutex);
+    bReturn         = (pthread_cond_timedwait(&m_cond, &mutex->m_mutex, &abstime) == 0);
   }
 
-  bool bReturn = m_bSignaled;
-  m_bSignaled = false;
-
   return bReturn;
 }
 
@@ -130,5 +117,46 @@ void CCondition::Sleep(int iTimeout)
   sched_yield();
   CCondition w;
   CMutex m;
+  CLockObject lock(&m);
   w.Wait(&m, iTimeout);
 }
+
+CThread::CThread(void) :
+    m_bRunning(false),
+    m_bStop(false)
+{
+}
+
+CThread::~CThread(void)
+{
+  m_bStop = true;
+  pthread_join(m_thread, NULL);
+}
+
+bool CThread::CreateThread(void)
+{
+  bool bReturn(false);
+
+  if (!m_bRunning && pthread_create(&m_thread, NULL, (void *(*) (void *))&CThread::ThreadHandler, (void *)this) == 0)
+  {
+    m_bRunning = true;
+    pthread_detach(m_thread);
+    bReturn = true;
+  }
+
+  return bReturn;
+}
+
+void *CThread::ThreadHandler(CThread *thread)
+{
+  if (thread)
+    return thread->Process();
+  return NULL;
+}
+
+void CThread::StopThread(bool bWaitForExit /* = true */)
+{
+  m_bStop = true;
+  if (bWaitForExit)
+    pthread_join(m_thread, NULL);
+}
index 41ad2b5e569bbc1c02c83f55e6241511a2e4596c..d1b6239e852252a482e9334c152235f9fea8bab0 100644 (file)
@@ -39,14 +39,13 @@ class CCondition
 {
 public:
   CCondition(void);
-  ~CCondition(void);
+  virtual ~CCondition(void);
 
   void Signal(void);
   bool Wait(CMutex *mutex, int64_t iTimeout);
   static void Sleep(int iTimeout);
 
 private:
-  bool            m_bSignaled;
   pthread_cond_t  m_cond;
 };
 
@@ -56,25 +55,43 @@ public:
   CMutex(void);
   virtual ~CMutex(void);
 
-  bool TryLock(int64_t iTimeout);
+  bool TryLock(void);
   bool Lock(void);
   void Unlock(void);
-  bool IsLocked(void) const { return m_bLocked; }
 
   pthread_mutex_t m_mutex;
-  CCondition     *m_condition;
-  bool            m_bLocked;
 };
 
 class CLockObject
 {
 public:
-  CLockObject(CMutex *mutex, int64_t iTimeout = -1);
+  CLockObject(CMutex *mutex);
   ~CLockObject(void);
 
   bool IsLocked(void) const { return m_bLocked; }
+  void Leave(void);
+  void Lock(void);
 
 private:
   CMutex *m_mutex;
   bool    m_bLocked;
 };
+
+class CThread
+{
+public:
+  CThread(void);
+  virtual ~CThread(void);
+
+  virtual bool IsRunning(void) const { return m_bRunning; }
+  virtual bool CreateThread(void);
+  virtual void StopThread(bool bWaitForExit = true);
+
+  static void *ThreadHandler(CThread *thread);
+  virtual void *Process(void) = 0;
+
+protected:
+  pthread_t m_thread;
+  bool      m_bRunning;
+  bool      m_bStop;
+};
index 15a333d0f78f2f9a49ade060e3662ef68fadc0ac..90158edbec031ac5fb0ef0dc4fefe28d9b27e4eb 100644 (file)
@@ -42,9 +42,9 @@
 using namespace CEC;
 using namespace std;
 
-#define CEC_TEST_CLIENT_VERSION 2
+#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))
@@ -67,11 +67,11 @@ void flush_log(ICECDevice *cecParser)
   }
 }
 
-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__
@@ -114,9 +114,6 @@ void show_console_help(void)
   "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 <<
@@ -129,7 +126,7 @@ void show_console_help(void)
 
 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;
@@ -150,8 +147,8 @@ int main (int argc, char *argv[])
   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;
@@ -192,7 +189,7 @@ int main (int argc, char *argv[])
   cout << "cec device opened" << endl;
   usleep(CEC_SETTLE_DOWN_TIME);
 
-  parser->PowerOnDevices();
+  parser->PowerOnDevices(CECDEVICE_TV);
   flush_log(parser);
 
   parser->SetActiveView();
@@ -223,15 +220,6 @@ int main (int argc, char *argv[])
 
           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;
@@ -242,7 +230,7 @@ int main (int argc, char *argv[])
         }
         else if (command == "ping")
         {
-          parser->Ping();
+          parser->PingAdapter();
         }
         else if (command == "bl")
         {
@@ -263,7 +251,8 @@ int main (int argc, char *argv[])
     CCondition::Sleep(50);
   }
 
-  parser->PowerOffDevices();
+  parser->StandbyDevices(CECDEVICE_BROADCAST);
+  parser->Close();
   flush_log(parser);
   UnloadLibCec(parser);
   return 0;