Merge branch 'master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Sun, 9 Oct 2011 13:22:44 +0000 (15:22 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Sun, 9 Oct 2011 13:23:14 +0000 (15:23 +0200)
  * bumped interface version to 6
  * fixed packet output (reporting the OSD name correctly now)
  * refactored packet structs: split up in cec commands and adapter messages
  * fixed i/o timings
  * added Darwin support (thanks Davilla!)
  * fixed WaitForAck()
  * fixed possible deadlock when starting a new thread
  * implemented vendor id and device class parsing. full detection will follow
  * added "on" and "standby" commands to the test client
  * retransmit packets if needed
  * fix GetTimeMs() on linux
  * added timestamp to log messages

27 files changed:
ChangeLog
configure.ac
debian/changelog
include/CECExports.h
include/CECExportsC.h
include/CECExportsCpp.h
include/CECTypes.h
project/libcec.vcxproj
project/testclient.vcxproj
pthreadVC2d.dll [deleted file]
src/lib/AdapterCommunication.cpp
src/lib/AdapterCommunication.h
src/lib/AdapterDetection.cpp
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/LibCECC.cpp
src/lib/Makefile.am
src/lib/libcec.pc.in
src/lib/platform/linux/serialport.cpp
src/lib/platform/pthread_win32/pthreadVC2d.lib [deleted file]
src/lib/platform/serialport.h
src/lib/platform/threads.cpp
src/lib/platform/timeutils.h
src/lib/platform/windows/serialport.cpp
src/testclient/main.cpp

index 54df56b035ee31a0cee2f72f826597c4292f77e8..3ad8683b60b093bcf1c3bf7c4795c685148ed67b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+libcec (0.6-1) unstable; urgency=low
+
+  * bumped interface version to 6
+  * fixed packet output (reporting the OSD name correctly now)
+  * refactored packet structs: split up in cec commands and adapter messages
+  * fixed i/o timings
+  * added Darwin support (thanks Davilla!)
+  * fixed WaitForAck()
+  * fixed possible deadlock when starting a new thread
+  * implemented vendor id and device class parsing. full detection will follow
+  * added "on" and "standby" commands to the test client
+  * retransmit packets if needed
+  * fix GetTimeMs() on linux
+  * added timestamp to log messages
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Sun, 09 Oct 2011 15:15:00 +0200
+
 libcec (0.5-1) unstable; urgency=low
 
   * bumped interface version to 5
@@ -6,7 +23,7 @@ libcec (0.5-1) unstable; urgency=low
   * fixed some memory leaks
   * reset all structs to default values before doing with them
 
- -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 07 Oct 2011 22:00:00 +0200
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Fri, 07 Oct 2011 22:00:00 +0200
 
 libcec (0.4-3) unstable; urgency=low
 
index 2034c08dd0320fbb16fbdf6e274247b11484d1d9..49bbc7f077581939dae5325f85b3783e5b7929ce 100644 (file)
@@ -1,14 +1,24 @@
-AC_INIT([libcec], 0:5:0)
+AC_INIT([libcec], 0:6:0)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 AC_PROG_CXX
 AC_PROG_LIBTOOL
 
-AC_CHECK_LIB([rt], [main],, AC_MSG_ERROR("required library 'rt' is missing"))
+case "${host}" in
+  *-*-linux*)
+    AC_CHECK_LIB([rt], [main],, AC_MSG_ERROR("required library 'rt' is missing"))
+    AC_CHECK_LIB([udev], [main],, AC_MSG_ERROR("required library 'udev' is missing"))
+    REQUIRES="udev"
+    ;;
+  *-apple-darwin*)
+    LIBS+="-framework CoreVideo -framework IOKit"
+    ;;
+esac
+
 AC_CHECK_LIB([pthread], [main],, AC_MSG_ERROR("required library 'pthread' is missing"))
-AC_CHECK_LIB([udev], [main],, AC_MSG_ERROR("required library 'udev' is missing"))
 
 CXXFLAGS="-fPIC -Wall -Wextra $CXXFLAGS"
 
+AC_SUBST(REQUIRES)
 AC_CONFIG_FILES([src/lib/libcec.pc])
 AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile])
index 54df56b035ee31a0cee2f72f826597c4292f77e8..3ad8683b60b093bcf1c3bf7c4795c685148ed67b 100644 (file)
@@ -1,3 +1,20 @@
+libcec (0.6-1) unstable; urgency=low
+
+  * bumped interface version to 6
+  * fixed packet output (reporting the OSD name correctly now)
+  * refactored packet structs: split up in cec commands and adapter messages
+  * fixed i/o timings
+  * added Darwin support (thanks Davilla!)
+  * fixed WaitForAck()
+  * fixed possible deadlock when starting a new thread
+  * implemented vendor id and device class parsing. full detection will follow
+  * added "on" and "standby" commands to the test client
+  * retransmit packets if needed
+  * fix GetTimeMs() on linux
+  * added timestamp to log messages
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Sun, 09 Oct 2011 15:15:00 +0200
+
 libcec (0.5-1) unstable; urgency=low
 
   * bumped interface version to 5
@@ -6,7 +23,7 @@ libcec (0.5-1) unstable; urgency=low
   * fixed some memory leaks
   * reset all structs to default values before doing with them
 
- -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 07 Oct 2011 22:00:00 +0200
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Fri, 07 Oct 2011 22:00:00 +0200
 
 libcec (0.4-3) unstable; urgency=low
 
index d1a7414242d83f8c389056fa1d66ec245c5bcf18..e3f1b76964fd4459089711106f289c6daed0f09e 100644 (file)
@@ -54,8 +54,8 @@
 extern "C" {
 namespace CEC {
 #endif
-  #define CEC_MIN_VERSION      5
-  #define CEC_LIB_VERSION      5
+  #define CEC_MIN_VERSION      6
+  #define CEC_LIB_VERSION      6
   #define CEC_SETTLE_DOWN_TIME 1000
   #define CEC_BUTTON_TIMEOUT   500
 
@@ -243,6 +243,7 @@ namespace CEC {
   {
     char          message[1024];
     cec_log_level level;
+    int64_t       time;
   } cec_log_message;
 
   typedef struct cec_keypress
@@ -257,21 +258,62 @@ namespace CEC {
     char comm[1024];
   } cec_adapter;
 
-  typedef struct cec_frame
+  typedef enum cec_adapter_messagecode
   {
-    uint8_t data[20];
+    MSGCODE_NOTHING = 0,
+    MSGCODE_PING,
+    MSGCODE_TIMEOUT_ERROR,
+    MSGCODE_HIGH_ERROR,
+    MSGCODE_LOW_ERROR,
+    MSGCODE_FRAME_START,
+    MSGCODE_FRAME_DATA,
+    MSGCODE_RECEIVE_FAILED,
+    MSGCODE_COMMAND_ACCEPTED,
+    MSGCODE_COMMAND_REJECTED,
+    MSGCODE_SET_ACK_MASK,
+    MSGCODE_TRANSMIT,
+    MSGCODE_TRANSMIT_EOM,
+    MSGCODE_TRANSMIT_IDLETIME,
+    MSGCODE_TRANSMIT_ACK_POLARITY,
+    MSGCODE_TRANSMIT_LINE_TIMEOUT,
+    MSGCODE_TRANSMIT_SUCCEEDED,
+    MSGCODE_TRANSMIT_FAILED_LINE,
+    MSGCODE_TRANSMIT_FAILED_ACK,
+    MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA,
+    MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE,
+    MSGCODE_FIRMWARE_VERSION,
+    MSGCODE_START_BOOTLOADER,
+    MSGCODE_FRAME_EOM = 0x80,
+    MSGCODE_FRAME_ACK = 0x40,
+  } cec_adapter_messagecode;
+
+  typedef struct cec_datapacket
+  {
+    uint8_t data[100];
     uint8_t size;
 
-    void shift(uint8_t num)
+    bool    empty(void) const             { return size == 0; }
+    bool    full(void) const              { return size == 100; }
+    uint8_t operator[](uint8_t pos) const { return pos < size ? data[pos] : 0; }
+    uint8_t at(uint8_t pos) const         { return pos < size ? data[pos] : 0; }
+
+    void shift(uint8_t iShiftBy)
     {
-      for (uint8_t iPtr = 0; iPtr < num; iPtr++)
-        data[iPtr] = iPtr + num < size ? data[iPtr + num] : 0;
-      size -= num;
+      if (iShiftBy >= size)
+      {
+        clear();
+      }
+      else
+      {
+        for (uint8_t iPtr = 0; iPtr < size; iPtr++)
+          data[iPtr] = (iPtr + iShiftBy < size) ? data[iPtr + iShiftBy] : 0;
+        size = (uint8_t) (size - iShiftBy);
+      }
     }
 
     void push_back(uint8_t add)
     {
-      if (size < 20)
+      if (size < 100)
         data[size++] = add;
     }
 
@@ -280,24 +322,86 @@ namespace CEC {
       memset(data, 0, sizeof(data));
       size = 0;
     }
-  } cec_frame;
+
+  } cec_datapacket;
+
+  typedef struct cec_adapter_message
+  {
+    cec_datapacket packet;
+
+    bool                    empty(void) const             { return packet.empty(); }
+    uint8_t                 operator[](uint8_t pos) const { return packet[pos]; }
+    uint8_t                 at(uint8_t pos) const         { return packet[pos]; }
+    uint8_t                 size(void) const              { return packet.size; }
+    void                    clear(void)                   { packet.clear(); }
+    void                    shift(uint8_t iShiftBy)       { packet.shift(iShiftBy); }
+    void                    push_back(uint8_t add)        { packet.push_back(add); }
+    cec_adapter_messagecode message(void) const           { return packet.size >= 1 ? (cec_adapter_messagecode) (packet.at(0) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK))  : MSGCODE_NOTHING; }
+    bool                    eom(void) const               { return packet.size >= 1 ? (packet.at(0) & MSGCODE_FRAME_EOM) != 0 : false; }
+    bool                    ack(void) const               { return packet.size >= 1 ? (packet.at(0) & MSGCODE_FRAME_ACK) != 0 : false; }
+    cec_logical_address     initiator(void) const         { return packet.size >= 2 ? (cec_logical_address) (packet.at(1) >> 4)  : CECDEVICE_UNKNOWN; };
+    cec_logical_address     destination(void) const       { return packet.size >= 2 ? (cec_logical_address) (packet.at(1) & 0xF) : CECDEVICE_UNKNOWN; };
+  } cec_adapter_message;
 
   typedef struct cec_command
   {
-    cec_logical_address source;
+    cec_logical_address initiator;
     cec_logical_address destination;
+    bool                ack;
+    bool                eom;
     cec_opcode          opcode;
-    cec_frame           parameters;
+    cec_datapacket      parameters;
+    bool                opcode_set;
+
+    static void format(cec_command &command, cec_logical_address initiator, cec_logical_address destination, cec_opcode opcode)
+    {
+      command.clear();
+      command.initiator   = initiator;
+      command.destination = destination;
+      command.opcode      = opcode;
+      command.opcode_set  = true;
+    }
+
+    void push_back(uint8_t data)
+    {
+      if (!opcode_set)
+      {
+        opcode_set = true;
+        opcode = (cec_opcode) data;
+      }
+      else
+        parameters.push_back(data);
+    }
 
     void clear(void)
     {
-      source      = CECDEVICE_UNKNOWN;
+      initiator   = CECDEVICE_UNKNOWN;
       destination = CECDEVICE_UNKNOWN;
+      ack         = false;
+      eom         = false;
+      opcode_set  = false;
       opcode      = CEC_OPCODE_FEATURE_ABORT;
       parameters.clear();
     };
   } cec_command;
 
+  typedef enum cec_vendor_id
+  {
+    CEC_VENDOR_SAMSUNG = 240,
+    CEC_VENDOR_UNKNOWN = 0
+  } vendor_id;
+
+  static const char *CECVendorIdToString(const uint64_t iVendorId)
+  {
+    switch (iVendorId)
+    {
+    case CEC_VENDOR_SAMSUNG:
+      return "Samsung";
+    default:
+      return "Unknown";
+    }
+  }
+
   //default physical address 1.0.0.0
   #define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
 
index d1987cb18720233b064ef474976b88e74a6107cd..359b0e6d7a8431e552e49ad715dd6ac3eec932c8 100644 (file)
@@ -177,9 +177,9 @@ extern DECLSPEC bool cec_get_next_command(cec_command *command);
  * @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);
+extern DECLSPEC bool cec_transmit(const CEC::cec_command &data, bool bWaitForAck = true);
 #else
-extern DECLSPEC bool cec_transmit(const cec_frame &data, bool bWaitForAck = true);
+extern DECLSPEC bool cec_transmit(const cec_command &data, bool bWaitForAck = true);
 #endif
 
 /*!
index 34905735ea63a3931fde9925cc20bccf564b2f2c..7d70e7fe24c830cf74a36512bf7f316d6a5e0bff 100644 (file)
@@ -36,6 +36,7 @@ namespace CEC
   class ICECAdapter
   {
   public:
+    virtual ~ICECAdapter() {};
     /*! @name Adapter methods */
     //@{
     /*!
@@ -92,7 +93,7 @@ namespace CEC
     /*!
      * @see cec_transmit
      */
-    virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true) = 0;
+    virtual bool Transmit(const cec_command &data, bool bWaitForAck = true) = 0;
 
     /*!
      * @see cec_set_logical_address
index b9bd2addd7df062e03dbc30b6a20eb06927fbff1..beff7f502823b6b61c35baf405d810d7fd6f6279 100644 (file)
@@ -326,35 +326,6 @@ typedef enum
   CEC_BROADCAST_SYSTEM_OTHER_SYSTEM = 30
 } ECecBroadcastSystem;
 
-typedef enum
-{
-  MSGCODE_NOTHING = 0,
-  MSGCODE_PING,
-  MSGCODE_TIMEOUT_ERROR,
-  MSGCODE_HIGH_ERROR,
-  MSGCODE_LOW_ERROR,
-  MSGCODE_FRAME_START,
-  MSGCODE_FRAME_DATA,
-  MSGCODE_RECEIVE_FAILED,
-  MSGCODE_COMMAND_ACCEPTED,
-  MSGCODE_COMMAND_REJECTED,
-  MSGCODE_SET_ACK_MASK,
-  MSGCODE_TRANSMIT,
-  MSGCODE_TRANSMIT_EOM,
-  MSGCODE_TRANSMIT_IDLETIME,
-  MSGCODE_TRANSMIT_ACK_POLARITY,
-  MSGCODE_TRANSMIT_LINE_TIMEOUT,
-  MSGCODE_TRANSMIT_SUCCEEDED,
-  MSGCODE_TRANSMIT_FAILED_LINE,
-  MSGCODE_TRANSMIT_FAILED_ACK,
-  MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA,
-  MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE,
-  MSGCODE_FIRMWARE_VERSION,
-  MSGCODE_START_BOOTLOADER,
-  MSGCODE_FRAME_EOM = 0x80,
-  MSGCODE_FRAME_ACK = 0x40,
-} ECecMessageCode;
-
 #define MSGSTART                     0xFF
 #define MSGEND                       0xFE
 #define MSGESC                       0xFD
index 30a88482c6c9ec79098c4dacd49b6435f19194bf..34f7817e9ba7612a1cffe9cd400222ec3fd2dea7 100644 (file)
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_USE_32BIT_TIME_T;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;__WINDOWS__;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(SolutionDir)..\src\lib\platform\pthread_win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <DisableSpecificWarnings>4996;4100;4309</DisableSpecificWarnings>
+      <DisableSpecificWarnings>4996;4100;4309;4505</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <OutputFile>$(SolutionDir)..\libcec.dll</OutputFile>
-      <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;$(SolutionDir)..\src\lib\platform\pthread_win32\pthreadVC2d.lib</AdditionalDependencies>
+      <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;$(SolutionDir)..\src\lib\platform\pthread_win32\pthreadVC2.lib</AdditionalDependencies>
       <IgnoreSpecificDefaultLibraries>libcmtd</IgnoreSpecificDefaultLibraries>
-      <Version>5</Version>
+      <Version>6</Version>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
index 42cc447cfa0e4c63cce815cb81e7f5e9b197cf75..13b32a7b2c8bb97128dfa4c14f08978a3399d672 100644 (file)
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_USE_32BIT_TIME_T;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;__WINDOWS__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <TreatWarningAsError>true</TreatWarningAsError>
-      <DisableSpecificWarnings>4100;4309</DisableSpecificWarnings>
+      <DisableSpecificWarnings>4100;4309;4505</DisableSpecificWarnings>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>$(ProjectDir)..\src\lib\platform\pthread_win32\pthreadVC2d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>$(ProjectDir)..\src\lib\platform\pthread_win32\pthreadVC2.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <OutputFile>$(SolutionDir)..\cec-client.exe</OutputFile>
     </Link>
   </ItemDefinitionGroup>
diff --git a/pthreadVC2d.dll b/pthreadVC2d.dll
deleted file mode 100644 (file)
index 6fffdc4..0000000
Binary files a/pthreadVC2d.dll and /dev/null differ
index 68f31a42ee9c3249aec52e25b7f64c1018122abf..2ee72707773d9db64ad1fd0d53634ff16a26921d 100644 (file)
@@ -65,7 +65,7 @@ CAdapterCommunication::~CAdapterCommunication(void)
 
 bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */)
 {
-  CLockObject lock(&m_mutex);
+  CLockObject lock(&m_commMutex);
   if (!m_port)
   {
     m_controller->AddLog(CEC_LOG_ERROR, "port is NULL");
@@ -108,9 +108,7 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38
 
 void CAdapterCommunication::Close(void)
 {
-  m_rcvCondition.Broadcast();
-
-  CLockObject lock(&m_mutex);
+  CLockObject lock(&m_commMutex);
   StopThread();
 
   if (m_inbuf)
@@ -120,6 +118,8 @@ void CAdapterCommunication::Close(void)
     m_iInbufSize = 0;
     m_iInbufUsed = 0;
   }
+
+  m_rcvCondition.Broadcast();
 }
 
 void *CAdapterCommunication::Process(void)
@@ -128,18 +128,13 @@ void *CAdapterCommunication::Process(void)
 
   while (!IsStopped())
   {
-    bool bSignal(false);
     {
-      CLockObject lock(&m_mutex, true);
-      if (lock.IsLocked())
-        bSignal = ReadFromDevice(50);
+      CLockObject lock(&m_commMutex);
+      ReadFromDevice(100);
     }
 
-    if (bSignal)
-      m_rcvCondition.Signal();
-
     if (!IsStopped())
-      Sleep(50);
+      Sleep(5);
   }
 
   return NULL;
@@ -158,7 +153,6 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
     CStdString strError;
     strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
     m_controller->AddLog(CEC_LOG_ERROR, strError);
-    StopThread(false);
     return false;
   }
   else if (iBytesRead > 0)
@@ -169,6 +163,7 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
 
 void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen)
 {
+  CLockObject lock(&m_bufferMutex);
   if (m_iInbufUsed + iLen > m_iInbufSize)
   {
     m_iInbufSize = m_iInbufUsed + iLen;
@@ -177,35 +172,34 @@ void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen)
 
   memcpy(m_inbuf + m_iInbufUsed, data, iLen);
   m_iInbufUsed += iLen;
+
+  m_rcvCondition.Signal();
 }
 
-bool CAdapterCommunication::Write(const cec_frame &data)
+bool CAdapterCommunication::Write(const cec_adapter_message &data)
 {
+  CLockObject lock(&m_commMutex);
+  if (m_port->Write(data) != (int32_t) data.size())
   {
-    CLockObject lock(&m_mutex);
-    if (m_port->Write(data) != (int32_t) 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((uint32_t) data.size * (uint32_t)24 /*data*/ + (uint32_t)5 /*start bit (4.5 ms)*/ + (uint32_t)50 /* to be on the safe side */);
+    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((uint32_t) data.size() * (uint32_t)24 /*data*/ + (uint32_t)5 /*start bit (4.5 ms)*/);
+
   return true;
 }
 
-bool CAdapterCommunication::Read(cec_frame &msg, uint32_t iTimeout)
+bool CAdapterCommunication::Read(cec_adapter_message &msg, uint32_t iTimeout)
 {
-  CLockObject lock(&m_mutex);
+  CLockObject lock(&m_bufferMutex);
 
   if (m_iInbufUsed < 1)
   {
-    if (!m_rcvCondition.Wait(&m_mutex, iTimeout))
+    if (!m_rcvCondition.Wait(&m_bufferMutex, iTimeout))
       return false;
   }
 
@@ -304,7 +298,7 @@ bool CAdapterCommunication::StartBootloader(void)
     return false;
 
   m_controller->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
-  cec_frame output;
+  cec_adapter_message output;
   output.clear();
 
   output.push_back(MSGSTART);
@@ -320,7 +314,7 @@ bool CAdapterCommunication::StartBootloader(void)
   return true;
 }
 
-void CAdapterCommunication::PushEscaped(cec_frame &vec, uint8_t byte)
+void CAdapterCommunication::PushEscaped(cec_adapter_message &vec, uint8_t byte)
 {
   if (byte >= MSGESC && byte != MSGSTART)
   {
@@ -342,7 +336,7 @@ bool CAdapterCommunication::SetAckMask(uint16_t iMask)
   strLog.Format("setting ackmask to %2x", iMask);
   m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
-  cec_frame output;
+  cec_adapter_message output;
   output.clear();
 
   output.push_back(MSGSTART);
@@ -366,7 +360,7 @@ bool CAdapterCommunication::PingAdapter(void)
     return false;
 
   m_controller->AddLog(CEC_LOG_DEBUG, "sending ping");
-  cec_frame output;
+  cec_adapter_message output;
   output.clear();
 
   output.push_back(MSGSTART);
@@ -389,3 +383,46 @@ bool CAdapterCommunication::IsOpen(void) const
 {
   return !IsStopped() && m_port->IsOpen();
 }
+
+void CAdapterCommunication::FormatAdapterMessage(const cec_command &command, cec_adapter_message &packet)
+{
+  packet.clear();
+
+  //set ack polarity to high when transmitting to the broadcast address
+  //set ack polarity low when transmitting to any other address
+  packet.push_back(MSGSTART);
+  PushEscaped(packet, MSGCODE_TRANSMIT_ACK_POLARITY);
+  if (command.destination == CECDEVICE_BROADCAST)
+    PushEscaped(packet, CEC_TRUE);
+  else
+    PushEscaped(packet, CEC_FALSE);
+  packet.push_back(MSGEND);
+
+  // add source and destination
+  packet.push_back(MSGSTART);
+  PushEscaped(packet, MSGCODE_TRANSMIT);
+  packet.push_back(((uint8_t)command.initiator << 4) + (uint8_t)command.destination);
+  packet.push_back(MSGEND);
+
+  // add opcode
+  packet.push_back(MSGSTART);
+  PushEscaped(packet, command.parameters.empty() ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
+  packet.push_back((uint8_t) command.opcode);
+  packet.push_back(MSGEND);
+
+  // add parameters
+  for (int8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+  {
+    packet.push_back(MSGSTART);
+
+    if (iPtr == command.parameters.size - 1)
+      PushEscaped(packet, MSGCODE_TRANSMIT_EOM);
+    else
+      PushEscaped(packet, MSGCODE_TRANSMIT);
+
+    PushEscaped(packet, command.parameters[iPtr]);
+
+    packet.push_back(MSGEND);
+  }
+}
+
index 135b5c2cdadf3947e3d4955b40df7b78632f9b18..934915ba336782e4ee55f1fa7619e1f8cfe6099c 100644 (file)
@@ -47,8 +47,8 @@ namespace CEC
     virtual ~CAdapterCommunication();
 
     bool Open(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000);
-    bool Read(cec_frame &msg, uint32_t iTimeout = 1000);
-    bool Write(const cec_frame &frame);
+    bool Read(cec_adapter_message &msg, uint32_t iTimeout = 1000);
+    bool Write(const cec_adapter_message &frame);
     bool PingAdapter(void);
     void Close(void);
     bool IsOpen(void) const;
@@ -58,7 +58,9 @@ namespace CEC
 
     bool StartBootloader(void);
     bool SetAckMask(uint16_t iMask);
-    static void PushEscaped(cec_frame &vec, uint8_t byte);
+    static void PushEscaped(cec_adapter_message &vec, uint8_t byte);
+    static void FormatAdapterMessage(const cec_command &command, cec_adapter_message &packet);
+
   private:
     void AddData(uint8_t *data, uint8_t iLen);
     bool ReadFromDevice(uint32_t iTimeout);
@@ -68,7 +70,8 @@ namespace CEC
     uint8_t*             m_inbuf;
     int16_t              m_iInbufSize;
     int16_t              m_iInbufUsed;
-    CMutex               m_mutex;
+    CMutex               m_bufferMutex;
+    CMutex               m_commMutex;
     CCondition           m_rcvCondition;
   };
 };
index 5d957a7a0150300bcd582a49616077e79f81e6b2..98c3a0e60a09a083daf38fc9e8cbc80d03b2a500 100644 (file)
 #include "platform/os-dependent.h"
 #include "util/StdString.h"
 
-#if !defined(__WINDOWS__)
+#if defined(__APPLE__)
+#include <dirent.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/serial/IOSerialKeys.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#elif !defined(__WINDOWS__)
 #include <dirent.h>
 #include <libudev.h>
 #include <poll.h>
@@ -104,7 +114,74 @@ uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSiz
 {
   uint8_t iFound(0);
 
-#if !defined(__WINDOWS__)
+#if defined(__APPLE__)
+  kern_return_t        kresult;
+  char bsdPath[MAXPATHLEN] = {0};
+  io_iterator_t        serialPortIterator;
+
+  CFMutableDictionaryRef classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
+  if (classesToMatch)
+  {
+    CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType));
+    kresult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &serialPortIterator);    
+    if (kresult == KERN_SUCCESS)
+    {
+      io_object_t serialService;
+      while ((serialService = IOIteratorNext(serialPortIterator)))
+      {
+        int iVendor = 0, iProduct = 0;
+        CFTypeRef      bsdPathAsCFString;
+
+        // fetch the device path.
+        bsdPathAsCFString = IORegistryEntryCreateCFProperty(serialService,
+          CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
+        if (bsdPathAsCFString)
+        {
+          // convert the path from a CFString to a C (NUL-terminated) string.
+          CFStringGetCString((CFStringRef)bsdPathAsCFString, bsdPath, MAXPATHLEN - 1, kCFStringEncodingUTF8);
+          CFRelease(bsdPathAsCFString);
+          
+          // now walk up the hierarchy until we find the entry with vendor/product IDs
+          io_registry_entry_t parent;
+          CFTypeRef vendorIdAsCFNumber  = NULL;
+          CFTypeRef productIdAsCFNumber = NULL;
+          kern_return_t kresult = IORegistryEntryGetParentEntry(serialService, kIOServicePlane, &parent);
+          while (kresult == KERN_SUCCESS)
+          {
+            vendorIdAsCFNumber  = IORegistryEntrySearchCFProperty(parent,
+              kIOServicePlane, CFSTR(kUSBVendorID),  kCFAllocatorDefault, 0);
+            productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
+              kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
+            if (vendorIdAsCFNumber && productIdAsCFNumber)
+            {
+              CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberIntType, &iVendor);
+              CFRelease(vendorIdAsCFNumber);
+              CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberIntType, &iProduct);
+              CFRelease(productIdAsCFNumber);
+              IOObjectRelease(parent);
+              break;
+            }
+            io_registry_entry_t oldparent = parent;
+            kresult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent);
+            IOObjectRelease(oldparent);
+          }
+          if (strlen(bsdPath) && iVendor == CEC_VID && iProduct == CEC_PID)
+          {
+            if (!strDevicePath || !strcmp(bsdPath, strDevicePath))
+            {
+              // on darwin, the device path is the same as the comm path.
+              snprintf(deviceList[iFound  ].path, sizeof(deviceList[iFound].path), "%s", bsdPath);
+              snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", bsdPath);
+            }
+          }
+        }
+             IOObjectRelease(serialService);
+      }
+    }
+    IOObjectRelease(serialPortIterator);
+  }
+
+#elif !defined(__WINDOWS__)
   struct udev *udev;
   if (!(udev = udev_new()))
     return -1;
index 4f2caa70d38ba7526f1bb31bae26bc58ac6cf319..bf559065d19941190b74df568270387e299924e9 100644 (file)
@@ -47,6 +47,10 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm
     m_communication(serComm),
     m_controller(controller)
 {
+  for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+    m_vendorIds[iPtr] = CEC_VENDOR_UNKNOWN;
+  for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+    m_vendorClasses[iPtr] = (uint8_t) 0;
 }
 
 CCECProcessor::~CCECProcessor(void)
@@ -82,10 +86,13 @@ void *CCECProcessor::Process(void)
 {
   m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
 
+  cec_command command;
+  cec_adapter_message msg;
+
   while (!IsStopped())
   {
     bool bParseFrame(false);
-    cec_frame msg;
+    command.clear();
     msg.clear();
 
     {
@@ -94,19 +101,16 @@ void *CCECProcessor::Process(void)
         bParseFrame = ParseMessage(msg) && !IsStopped();
 
       if (bParseFrame)
-      {
-        msg.clear();
-        msg = m_currentframe;
-      }
+        command = m_currentframe;
     }
 
     if (bParseFrame)
-      ParseCurrentFrame(msg);
+      ParseCommand(command);
 
     m_controller->CheckKeypressTimeout();
 
     if (!IsStopped())
-      Sleep(50);
+      Sleep(5);
   }
 
   return NULL;
@@ -118,14 +122,13 @@ bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV
     return false;
 
   CStdString strLog;
-  strLog.Format("powering on devices with logical address %d", (int8_t)address);
+  strLog.Format("<< powering on device with logical address %d", (int8_t)address);
   m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
-  cec_frame frame;
-  frame.clear();
 
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back((uint8_t) CEC_OPCODE_IMAGE_VIEW_ON);
-  return Transmit(frame);
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_IMAGE_VIEW_ON);
+
+  return Transmit(command);
 }
 
 bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
@@ -134,14 +137,13 @@ bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BR
     return false;
 
   CStdString strLog;
-  strLog.Format("putting all devices with logical address %d in standby mode", (int8_t)address);
+  strLog.Format("<< putting device with logical address %d in standby mode", (int8_t)address);
   m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
-  cec_frame frame;
-  frame.clear();
 
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back((uint8_t) CEC_OPCODE_STANDBY);
-  return Transmit(frame);
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_STANDBY);
+
+  return Transmit(command);
 }
 
 bool CCECProcessor::SetActiveView(void)
@@ -149,15 +151,14 @@ bool CCECProcessor::SetActiveView(void)
   if (!IsRunning())
     return false;
 
-  m_controller->AddLog(CEC_LOG_DEBUG, "setting active view");
-  cec_frame frame;
-  frame.clear();
+  m_controller->AddLog(CEC_LOG_DEBUG, "<< setting active view");
+
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
+  command.parameters.push_back((m_physicaladdress >> 8) & 0xFF);
+  command.parameters.push_back(m_physicaladdress & 0xFF);
 
-  frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
-  frame.push_back((uint8_t) CEC_OPCODE_ACTIVE_SOURCE);
-  frame.push_back((m_physicaladdress >> 8) & 0xFF);
-  frame.push_back(m_physicaladdress & 0xFF);
-  return Transmit(frame);
+  return Transmit(command);
 }
 
 bool CCECProcessor::SetInactiveView(void)
@@ -165,58 +166,34 @@ bool CCECProcessor::SetInactiveView(void)
   if (!IsRunning())
     return false;
 
-  m_controller->AddLog(CEC_LOG_DEBUG, "setting inactive view");
-  cec_frame frame;
-  frame.clear();
+  m_controller->AddLog(CEC_LOG_DEBUG, "<< setting inactive view");
 
-  frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
-  frame.push_back((uint8_t) CEC_OPCODE_INACTIVE_SOURCE);
-  frame.push_back((m_physicaladdress >> 8) & 0xFF);
-  frame.push_back(m_physicaladdress & 0xFF);
-  return Transmit(frame);
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_INACTIVE_SOURCE);
+  command.parameters.push_back((m_physicaladdress >> 8) & 0xFF);
+  command.parameters.push_back(m_physicaladdress & 0xFF);
+
+  return Transmit(command);
 }
 
-bool CCECProcessor::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
+void CCECProcessor::LogOutput(const cec_command &data)
 {
   CStdString txStr = "transmit ";
-  for (unsigned int i = 0; i < data.size; i++)
-    txStr.AppendFormat(" %02x", data.data[i]);
+  txStr.AppendFormat(" %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
+  txStr.AppendFormat(" %02x", (uint8_t)data.opcode);
+
+  for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
+    txStr.AppendFormat(" %02x", data.parameters[iPtr]);
   m_controller->AddLog(CEC_LOG_DEBUG, txStr.c_str());
+}
 
-  if (data.size == 0)
-  {
-    m_controller->AddLog(CEC_LOG_WARNING, "transmit buffer is empty");
-    return false;
-  }
+bool CCECProcessor::Transmit(const cec_command &data, bool bWaitForAck /* = true */)
+{
+  LogOutput(data);
 
-  cec_frame output;
+  cec_adapter_message output;
   output.clear();
-
-  //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.data[0] & 0xF) == 0xF)
-    CAdapterCommunication::PushEscaped(output, CEC_TRUE);
-  else
-    CAdapterCommunication::PushEscaped(output, CEC_FALSE);
-
-  output.push_back(MSGEND);
-
-  for (int8_t i = 0; i < data.size; i++)
-  {
-    output.push_back(MSGSTART);
-
-    if (i == (int8_t)data.size - 1)
-      CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_EOM);
-    else
-      CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT);
-
-    CAdapterCommunication::PushEscaped(output, data.data[i]);
-
-    output.push_back(MSGEND);
-  }
+  CAdapterCommunication::FormatAdapterMessage(data, output);
 
   return TransmitFormatted(output, bWaitForAck);
 }
@@ -224,23 +201,38 @@ bool CCECProcessor::Transmit(const cec_frame &data, bool bWaitForAck /* = true *
 bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
 {
   CStdString strLog;
-  strLog.Format("setting logical address to %d", iLogicalAddress);
+  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 */)
+bool CCECProcessor::TransmitFormatted(const cec_adapter_message &data, bool bWaitForAck /* = true */)
 {
   CLockObject lock(&m_mutex);
   if (!m_communication || !m_communication->Write(data))
     return false;
 
-  if (bWaitForAck && !WaitForAck())
+  if (bWaitForAck)
   {
-    m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ACK");
-    return false;
+    uint64_t now = GetTimeMs();
+    uint64_t target = now + 1000;
+    bool bError(false);
+    bool bGotAck(false);
+
+    while (!bGotAck && now < target)
+    {
+      bGotAck = WaitForAck(&bError, (uint32_t) (target - now));
+      now = GetTimeMs();
+
+      if (bError && now < target)
+      {
+        m_controller->AddLog(CEC_LOG_ERROR, "retransmitting previous frame");
+        if (!m_communication->Write(data))
+          return false;
+      }
+    }
   }
 
   return true;
@@ -248,195 +240,175 @@ bool CCECProcessor::TransmitFormatted(const cec_frame &data, bool bWaitForAck /*
 
 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.clear();
-
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back((uint8_t) CEC_OPCODE_FEATURE_ABORT);
-  frame.push_back((uint8_t) opcode);
-  frame.push_back((uint8_t) reason);
-  Transmit(frame);
+  m_controller->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
+
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_FEATURE_ABORT);
+  command.parameters.push_back((uint8_t)opcode);
+  command.parameters.push_back((uint8_t)reason);
+
+  Transmit(command);
 }
 
 void CCECProcessor::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
 {
-  cec_frame frame;
-  frame.clear();
-
-  m_controller->AddLog(CEC_LOG_NOTICE, "reporting CEC version as 1.3a");
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back((uint8_t) CEC_OPCODE_CEC_VERSION);
-  frame.push_back((uint8_t) CEC_VERSION_1_3A);
-  Transmit(frame);
+  m_controller->AddLog(CEC_LOG_NOTICE, "<< reporting CEC version as 1.3a");
+
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_CEC_VERSION);
+  command.parameters.push_back(CEC_VERSION_1_3A);
+
+  Transmit(command);
 }
 
 void CCECProcessor::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
 {
-  cec_frame frame;
-  frame.clear();
-
   if (bOn)
-    m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
+    m_controller->AddLog(CEC_LOG_NOTICE, "<< reporting \"On\" power status");
   else
-    m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
+    m_controller->AddLog(CEC_LOG_NOTICE, "<< reporting \"Off\" power status");
 
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back((uint8_t) CEC_OPCODE_REPORT_POWER_STATUS);
-  frame.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY);
-  Transmit(frame);
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_REPORT_POWER_STATUS);
+  command.parameters.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY);
+
+  Transmit(command);
 }
 
 void CCECProcessor::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
 {
-  cec_frame frame;
-  frame.clear();
-
   if (bActive)
-    m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
+    m_controller->AddLog(CEC_LOG_NOTICE, "<< reporting menu state as active");
   else
-    m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
+    m_controller->AddLog(CEC_LOG_NOTICE, "<< reporting menu state as inactive");
+
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_MENU_STATUS);
+  command.parameters.push_back(bActive ? (uint8_t) CEC_MENU_STATE_ACTIVATED : (uint8_t) CEC_MENU_STATE_DEACTIVATED);
 
-  frame.push_back(GetSourceDestination(address));
-  frame.push_back((uint8_t) CEC_OPCODE_MENU_STATUS);
-  frame.push_back(bActive ? (uint8_t) CEC_MENU_STATE_ACTIVATED : (uint8_t) CEC_MENU_STATE_DEACTIVATED);
-  Transmit(frame);
+  Transmit(command);
 }
 
 void CCECProcessor::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
 {
-  m_controller->AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
+  m_controller->AddLog(CEC_LOG_NOTICE, "<< vendor ID requested, feature abort");
   TransmitAbort(address, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
 }
 
 void CCECProcessor::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
 {
-  cec_frame frame;
-  frame.clear();
-
   const char *osdname = m_strDeviceName.c_str();
   CStdString strLog;
-  strLog.Format("reporting OSD name as %s", osdname);
+  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((uint8_t) CEC_OPCODE_SET_OSD_NAME);
 
-  for (unsigned int i = 0; i < strlen(osdname); i++)
-    frame.push_back(osdname[i]);
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_SET_OSD_NAME);
+  for (unsigned int iPtr = 0; iPtr < strlen(osdname); iPtr++)
+    command.parameters.push_back(osdname[iPtr]);
 
-  Transmit(frame);
+  Transmit(command);
 }
 
 void CCECProcessor::ReportPhysicalAddress(void)
 {
-  cec_frame frame;
-  frame.clear();
-
   CStdString strLog;
-  strLog.Format("reporting physical address as %04x", m_physicaladdress);
+  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((uint8_t) CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
-  frame.push_back((uint8_t) ((m_physicaladdress >> 8) & 0xFF));
-  frame.push_back((uint8_t) (m_physicaladdress & 0xFF));
-  frame.push_back((uint8_t) CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
-  Transmit(frame);
+
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
+  command.parameters.push_back((uint8_t) ((m_physicaladdress >> 8) & 0xFF));
+  command.parameters.push_back((uint8_t) (m_physicaladdress & 0xFF));
+
+  Transmit(command);
 }
 
 void CCECProcessor::BroadcastActiveSource(void)
 {
-  cec_frame frame;
-  frame.clear();
-
-  m_controller->AddLog(CEC_LOG_NOTICE, "broadcasting active source");
-  frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
-  frame.push_back((uint8_t) CEC_OPCODE_ACTIVE_SOURCE);
-  frame.push_back((uint8_t) ((m_physicaladdress >> 8) & 0xFF));
-  frame.push_back((uint8_t) (m_physicaladdress & 0xFF));
-  Transmit(frame);
-}
+  m_controller->AddLog(CEC_LOG_NOTICE, "<< broadcasting active source");
 
-uint8_t CCECProcessor::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */) const
-{
-  return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
+  cec_command command;
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
+  command.parameters.push_back((uint8_t) ((m_physicaladdress >> 8) & 0xFF));
+  command.parameters.push_back((uint8_t) (m_physicaladdress & 0xFF));
+
+  Transmit(command);
 }
 
-bool CCECProcessor::WaitForAck(uint32_t iTimeout /* = 1000 */)
+bool CCECProcessor::WaitForAck(bool *bError, uint32_t iTimeout /* = 1000 */)
 {
   bool bGotAck(false);
-  bool bError(false);
+  *bError = false;
 
   int64_t iNow = GetTimeMs();
   int64_t iTargetTime = iNow + (uint64_t) iTimeout;
 
-  while (!bGotAck && !bError && (iTimeout == 0 || iNow < iTargetTime))
+  while (!bGotAck && !*bError && (iTimeout == 0 || iNow < iTargetTime))
   {
-    cec_frame msg;
+    cec_adapter_message msg;
     msg.clear();
 
-    while (!bGotAck && !bError && m_communication->Read(msg, iTimeout))
+    if (!m_communication->Read(msg, iTimeout > 0 ? (int32_t)(iTargetTime - iNow) : 1000))
     {
-      uint8_t iCode = msg.data[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.data[0] & MSGCODE_FRAME_ACK) != 0;
-        break;
-      }
       iNow = GetTimeMs();
+      continue;
+    }
+
+    switch (msg.message())
+    {
+    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");
+      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);
+      break;
     }
+
+    iNow = GetTimeMs();
   }
 
-  return bGotAck && !bError;
+  return bGotAck && !*bError;
 }
 
-bool CCECProcessor::ParseMessage(cec_frame &msg)
+bool CCECProcessor::ParseMessage(cec_adapter_message &msg)
 {
   bool bReturn(false);
 
-  if (msg.size == 0)
+  if (msg.empty())
     return bReturn;
 
   CStdString logStr;
-  uint8_t iCode = msg.data[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
-  bool    bEom  = (msg.data[0] & MSGCODE_FRAME_EOM) != 0;
-  bool    bAck  = (msg.data[0] & MSGCODE_FRAME_ACK) != 0;
 
-  switch(iCode)
+  switch(msg.message())
   {
   case MSGCODE_NOTHING:
     m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
@@ -445,15 +417,15 @@ bool CCECProcessor::ParseMessage(cec_frame &msg)
   case MSGCODE_HIGH_ERROR:
   case MSGCODE_LOW_ERROR:
     {
-      if (iCode == MSGCODE_TIMEOUT_ERROR)
+      if (msg.message() == MSGCODE_TIMEOUT_ERROR)
         logStr = "MSGCODE_TIMEOUT";
-      else if (iCode == MSGCODE_HIGH_ERROR)
+      else if (msg.message() == MSGCODE_HIGH_ERROR)
         logStr = "MSGCODE_HIGH_ERROR";
       else
         logStr = "MSGCODE_LOW_ERROR";
 
-      int iLine      = (msg.size >= 3) ? (msg.data[1] << 8) | (msg.data[2]) : 0;
-      uint32_t iTime = (msg.size >= 7) ? (msg.data[3] << 24) | (msg.data[4] << 16) | (msg.data[5] << 8) | (msg.data[6]) : 0;
+      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());
@@ -463,13 +435,13 @@ bool CCECProcessor::ParseMessage(cec_frame &msg)
     {
       logStr = "MSGCODE_FRAME_START";
       m_currentframe.clear();
-      if (msg.size >= 2)
+      if (msg.size() >= 2)
       {
-        int iInitiator = msg.data[1] >> 4;
-        int iDestination = msg.data[1] & 0xF;
-        logStr.AppendFormat(" initiator:%u destination:%u ack:%s %s", iInitiator, iDestination, bAck ? "high" : "low", bEom ? "eom" : "");
-
-        m_currentframe.push_back(msg.data[1]);
+        logStr.AppendFormat(" initiator:%u destination:%u ack:%s %s", msg.initiator(), msg.destination(), msg.ack() ? "high" : "low", msg.eom() ? "eom" : "");
+        m_currentframe.initiator   =  msg.initiator();
+        m_currentframe.destination = msg.destination();
+        m_currentframe.ack         = msg.ack();
+        m_currentframe.eom         = msg.eom();
       }
       m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
     }
@@ -477,15 +449,15 @@ bool CCECProcessor::ParseMessage(cec_frame &msg)
   case MSGCODE_FRAME_DATA:
     {
       logStr = "MSGCODE_FRAME_DATA";
-      if (msg.size >= 2)
+      if (msg.size() >= 2)
       {
-        uint8_t iData = msg.data[1];
+        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)
+    if (msg.eom())
       bReturn = true;
     break;
   default:
@@ -495,83 +467,102 @@ bool CCECProcessor::ParseMessage(cec_frame &msg)
   return bReturn;
 }
 
-void CCECProcessor::ParseCurrentFrame(cec_frame &frame)
+void CCECProcessor::ParseVendorId(cec_logical_address device, const cec_datapacket &data)
 {
-  uint8_t initiator = frame.data[0] >> 4;
-  uint8_t destination = frame.data[0] & 0xF;
+  if (data.size < 3)
+  {
+    m_controller->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
+    return;
+  }
 
-  CStdString dataStr;
-  dataStr.Format("received frame: initiator: %u destination: %u", initiator, destination);
+  uint64_t iVendorId = ((uint64_t)data[0] << 3) +
+                       ((uint64_t)data[1] << 2) +
+                        (uint64_t)data[2];
+
+  m_vendorIds[(uint8_t)device]     = iVendorId;
+  m_vendorClasses[(uint8_t)device] = data.size >= 4 ? data[3] : 0;
+
+  CStdString strLog;
+  strLog.Format("device %d: vendor = %s (%lld) class = %2x", (uint8_t)device, CECVendorIdToString(m_vendorIds[(uint8_t)device]), iVendorId, m_vendorClasses[(uint8_t)device]);
+  m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+}
 
-  if (frame.size > 1)
+void CCECProcessor::ParseCommand(cec_command &command)
+{
+  CStdString dataStr;
+  dataStr.Format(">> received frame: initiator: %u destination: %u", command.initiator, command.destination);
+  if (command.parameters.size > 1)
   {
     dataStr += " data:";
-    for (unsigned int i = 1; i < frame.size; i++)
-      dataStr.AppendFormat(" %02x", frame.data[i]);
+    for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+      dataStr.AppendFormat(" %02x", (unsigned int)command.parameters[iPtr]);
   }
   m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str());
 
-  if (frame.size <= 1)
-    return;
-
-  cec_opcode opCode = (cec_opcode) frame.data[1];
-  if (destination == (uint16_t) m_iLogicalAddress)
+  if (command.destination == m_iLogicalAddress)
   {
-    switch(opCode)
+    switch(command.opcode)
     {
     case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
       ReportPhysicalAddress();
-      SetActiveView();
       break;
     case CEC_OPCODE_GIVE_OSD_NAME:
-      ReportOSDName((cec_logical_address)initiator);
+      ReportOSDName(command.initiator);
       break;
     case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-      ReportVendorID((cec_logical_address)initiator);
+      ReportVendorID(command.initiator);
+      break;
+    case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
+      ParseVendorId(command.initiator, command.parameters);
+      TransmitAbort(command.initiator, CEC_OPCODE_VENDOR_COMMAND_WITH_ID);
+      break;
+    case CEC_OPCODE_GIVE_DECK_STATUS:
+      // need to support opcodes play and deck control before doing anything with this
+      TransmitAbort(command.initiator, CEC_OPCODE_GIVE_DECK_STATUS);
       break;
     case CEC_OPCODE_MENU_REQUEST:
-      ReportMenuState((cec_logical_address)initiator);
+      if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY)
+        ReportMenuState(command.initiator);
       break;
     case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-      ReportPowerState((cec_logical_address)initiator);
+      ReportPowerState(command.initiator);
+      SetActiveView();
       break;
     case CEC_OPCODE_GET_CEC_VERSION:
-      ReportCECVersion((cec_logical_address)initiator);
+      ReportCECVersion(command.initiator);
       break;
     case CEC_OPCODE_USER_CONTROL_PRESSED:
-      if (frame.size > 2)
+      if (command.parameters.size > 0)
       {
         m_controller->AddKey();
 
-        if (frame.data[2] <= CEC_USER_CONTROL_CODE_MAX)
-          m_controller->SetCurrentButton((cec_user_control_code) frame.data[2]);
+        if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
+          m_controller->SetCurrentButton((cec_user_control_code) command.parameters[0]);
       }
       break;
     case CEC_OPCODE_USER_CONTROL_RELEASE:
       m_controller->AddKey();
       break;
     default:
-      cec_frame params = frame;
-      params.shift(2);
-      m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+      m_controller->AddCommand(command);
       break;
     }
   }
-  else if (destination == (uint8_t) CECDEVICE_BROADCAST)
+  else if (command.destination == CECDEVICE_BROADCAST)
   {
     CStdString strLog;
-    if (opCode == CEC_OPCODE_REQUEST_ACTIVE_SOURCE)
+    if (command.opcode == CEC_OPCODE_REQUEST_ACTIVE_SOURCE)
     {
-      strLog.Format("%i requests active source", initiator);
+      strLog.Format(">> %i requests active source", (uint8_t) command.initiator);
       m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
       BroadcastActiveSource();
     }
-    else if (opCode == CEC_OPCODE_SET_STREAM_PATH)
+    else if (command.opcode == CEC_OPCODE_SET_STREAM_PATH)
     {
-      if (frame.size >= 4)
+      if (command.parameters.size >= 2)
       {
-        int streamaddr = ((int)frame.data[2] << 8) | ((int)frame.data[3]);
-        strLog.Format("%i requests stream path from physical address %04x", initiator, streamaddr);
+        int streamaddr = ((int)command.parameters[0] << 8) | ((int)command.parameters[1]);
+        strLog.Format(">> %i requests stream path from physical address %04x", command.initiator, streamaddr);
         m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
         if (streamaddr == m_physicaladdress)
           BroadcastActiveSource();
@@ -579,15 +570,13 @@ void CCECProcessor::ParseCurrentFrame(cec_frame &frame)
     }
     else
     {
-      cec_frame params = frame;
-      params.shift(2);
-      m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+      m_controller->AddCommand(command);
     }
   }
   else
   {
     CStdString strLog;
-    strLog.Format("ignoring frame: destination: %u != %u", destination, (uint16_t)m_iLogicalAddress);
+    strLog.Format("ignoring frame: destination: %u != %u", command.destination, (uint8_t)m_iLogicalAddress);
     m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
   }
 }
index 660fee0ffc98053507a1f5142e0f8f326a27a200..2bebc5c05a27d4b5e245082aa6be0ee3c35ca1a2 100644 (file)
@@ -57,10 +57,10 @@ namespace CEC
       virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
       virtual bool SetActiveView(void);
       virtual bool SetInactiveView(void);
-      virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true);
+      virtual bool Transmit(const cec_command &data, bool bWaitForAck = true);
       virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
     protected:
-      virtual bool TransmitFormatted(const cec_frame &data, bool bWaitForAck = true);
+      virtual bool TransmitFormatted(const cec_adapter_message &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);
@@ -69,20 +69,23 @@ 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) const;
 
     private:
-      bool WaitForAck(uint32_t iTimeout = 1000);
-      bool ParseMessage(cec_frame &msg);
-      void ParseCurrentFrame(cec_frame &frame);
+      void LogOutput(const cec_command &data);
+      bool WaitForAck(bool *bError, uint32_t iTimeout = 1000);
+      bool ParseMessage(cec_adapter_message &msg);
+      void ParseCommand(cec_command &command);
+      void ParseVendorId(cec_logical_address device, const cec_datapacket &data);
 
-      cec_frame                  m_currentframe;
-      uint16_t                   m_physicaladdress;
-      cec_logical_address        m_iLogicalAddress;
-      CecBuffer<cec_frame>       m_frameBuffer;
-      std::string                m_strDeviceName;
-      CMutex                     m_mutex;
-      CAdapterCommunication     *m_communication;
-      CLibCEC                   *m_controller;
+      cec_command                    m_currentframe;
+      uint16_t                       m_physicaladdress;
+      cec_logical_address            m_iLogicalAddress;
+      CecBuffer<cec_adapter_message> m_frameBuffer;
+      std::string                    m_strDeviceName;
+      CMutex                         m_mutex;
+      CAdapterCommunication         *m_communication;
+      CLibCEC                       *m_controller;
+      uint64_t                       m_vendorIds[16];
+      uint8_t                        m_vendorClasses[16];
   };
 };
index 0f88470554dec9957713e9d4e6d318e10634af5f..afbf2260f5c16dbeaee4e55a764bf2eb49875e16 100644 (file)
@@ -42,6 +42,7 @@ using namespace std;
 using namespace CEC;
 
 CLibCEC::CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */) :
+    m_iStartTime(GetTimeMs()),
     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
     m_buttontime(0)
 {
@@ -147,7 +148,7 @@ bool CLibCEC::GetNextCommand(cec_command *command)
   return m_commandBuffer.Pop(*command);
 }
 
-bool CLibCEC::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
+bool CLibCEC::Transmit(const cec_command &data, bool bWaitForAck /* = true */)
 {
   return m_cec ? m_cec->Transmit(data, bWaitForAck) : false;
 }
@@ -183,6 +184,7 @@ void CLibCEC::AddLog(cec_log_level level, const string &strMessage)
   {
     cec_log_message message;
     message.level = level;
+    message.time = GetTimeMs() - m_iStartTime;
     snprintf(message.message, sizeof(message.message), "%s", strMessage.c_str());
     m_logBuffer.Push(message);
   }
@@ -202,20 +204,12 @@ void CLibCEC::AddKey(void)
   }
 }
 
-void CLibCEC::AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters)
+void CLibCEC::AddCommand(cec_command &command)
 {
-  cec_command command;
-  command.clear();
-
-  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());
+    strDebug.Format("stored command '%2x' in the command buffer. buffer size = %d", command.opcode, m_commandBuffer.Size());
     AddLog(CEC_LOG_DEBUG, strDebug);
   }
   else
index 2a849526a323ea0565743ae8b1a05d3030de1f7f..a602beafa62d0024ea542f4f680e4b83d736e92f 100644 (file)
@@ -64,7 +64,7 @@ namespace CEC
       virtual bool GetNextKeypress(cec_keypress *key);
       virtual bool GetNextCommand(cec_command *command);
 
-      virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true);
+      virtual bool Transmit(const cec_command &data, bool bWaitForAck = true);
       virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
 
       virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV);
@@ -75,11 +75,12 @@ namespace CEC
 
       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 AddCommand(cec_command &command);
       virtual void CheckKeypressTimeout(void);
       virtual void SetCurrentButton(cec_user_control_code iButtonCode);
 
     protected:
+      int64_t                    m_iStartTime;
       cec_user_control_code      m_iCurrentButton;
       int64_t                    m_buttontime;
       CCECProcessor             *m_cec;
index 4c7276a0fe5d8c28c4861ced3c1c6ad56f653b56..98c020de26df1ca864814e98ebc60587f657fb7f 100644 (file)
@@ -123,7 +123,7 @@ bool cec_get_next_command(cec_command *command)
   return false;
 }
 
-bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck /* = true */)
+bool cec_transmit(const CEC::cec_command &data, bool bWaitForAck /* = true */)
 {
   if (cec_parser)
     return cec_parser->Transmit(data, bWaitForAck);
index 3522cb5644e1563d976e13734a4239bbb20e59c2..7a0f6a39db2355a7184666b35ef0354962768407 100644 (file)
@@ -30,4 +30,4 @@ libcec_la_SOURCES = AdapterCommunication.cpp \
                     platform/threads.cpp \
                     platform/threads.h
 
-libcec_la_LDFLAGS = -lrt -lpthread -ludev -version-info @VERSION@
+libcec_la_LDFLAGS = @LIBS@ -version-info @VERSION@
index 058a9de8ff23036dee48a00e906a13c1c214b8ec..d0a6e7bdf5ac7cf1384937d83df19f7a9e1c54e8 100644 (file)
@@ -7,6 +7,6 @@ Name: libcec
 Description: CEC interface library
 URL: http://www.pulse-eight.com/
 Version: @VERSION@
-Requires: udev
+Requires: @REQUIRES@
 Libs: -L${libdir} -lcec
 Cflags: -I${includedir}
index 0bb4e2cf6c419ad0980fea55ecab2033664015f4..d323708214c8b602a9edc1dd02f0ead087a3b635 100644 (file)
 #include "../baudrate.h"
 #include "../timeutils.h"
 
+#if defined(__APPLE__)
+#ifndef XCASE
+#define XCASE  0
+#endif
+#ifndef OLCUC
+#define OLCUC  0
+#endif
+#ifndef IUCLC
+#define IUCLC  0
+#endif
+#endif
 using namespace std;
 using namespace CEC;
 
@@ -35,7 +46,7 @@ CSerialPort::~CSerialPort()
   Close();
 }
 
-int8_t CSerialPort::Write(const cec_frame &data)
+int8_t CSerialPort::Write(const cec_adapter_message &data)
 {
   fd_set port;
 
@@ -48,7 +59,7 @@ int8_t CSerialPort::Write(const cec_frame &data)
 
   int32_t byteswritten = 0;
 
-  while (byteswritten < (int32_t) data.size)
+  while (byteswritten < (int32_t) data.size())
   {
     FD_ZERO(&port);
     FD_SET(m_fd, &port);
@@ -59,7 +70,7 @@ int8_t CSerialPort::Write(const cec_frame &data)
       return -1;
     }
 
-    returnv = write(m_fd, data.data + byteswritten, data.size - byteswritten);
+    returnv = write(m_fd, data.packet.data + byteswritten, data.size() - byteswritten);
     if (returnv == -1)
     {
       m_error = strerror(errno);
@@ -73,7 +84,7 @@ int8_t CSerialPort::Write(const cec_frame &data)
 //  {
 //    printf("%s write:", m_name.c_str());
 //    for (int i = 0; i < byteswritten; i++)
-//      printf(" %02x", (unsigned int)data.data[i]);
+//      printf(" %02x", (unsigned int)data[i]);
 //
 //    printf("\n");
 //  }
diff --git a/src/lib/platform/pthread_win32/pthreadVC2d.lib b/src/lib/platform/pthread_win32/pthreadVC2d.lib
deleted file mode 100644 (file)
index 0df71c7..0000000
Binary files a/src/lib/platform/pthread_win32/pthreadVC2d.lib and /dev/null differ
index 9cc2c9a1439b5530b5380e1d85312b7451c992bf..f4f085e6b81d33a897189a7c697818281ea801fa 100644 (file)
@@ -46,7 +46,7 @@ namespace CEC
       bool IsOpen();
       void Close();
 
-      int8_t Write(const cec_frame &data);
+      int8_t Write(const cec_adapter_message &data);
       int32_t Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs = 0);
 
       std::string GetError() { return m_error; }
index 31a0fb31571e4c3d49c6e077bf56d155b18d8748..8ba391920feb2695326b52ca6e7467f033771dd1 100644 (file)
@@ -175,10 +175,17 @@ void *CThread::ThreadHandler(CThread *thread)
 
   if (thread)
   {
+    CLockObject lock(&thread->m_threadMutex);
     thread->m_bRunning = true;
+    lock.Leave();
     thread->m_threadCondition.Broadcast();
+
     retVal = thread->Process();
+
+    lock.Lock();
     thread->m_bRunning = false;
+    lock.Leave();
+    thread->m_threadCondition.Broadcast();
   }
 
   return retVal;
index c4140203736bc258e3551a31fda001009a985e45..1dd454fd51a8d7167375b5df69ccbd515db0a7bd 100644 (file)
  */
 
 #include <stdint.h>
+#if defined(__APPLE__)
+#include <mach/mach_time.h>
+#include <CoreVideo/CVHostTime.h>
+#elif defined(__WINDOWS__)
 #include <time.h>
+#else
+#include <sys/time.h>
+#endif
 
 namespace CEC
 {
   inline int64_t GetTimeMs()
   {
-  #ifdef __WINDOWS__
+  #if defined(__APPLE__)
+    return (int64_t) (CVGetCurrentHostTime() * 1000 / CVGetHostClockFrequency());
+  #elif defined(__WINDOWS__)
     time_t rawtime;
     time(&rawtime);
 
@@ -38,10 +47,9 @@ namespace CEC
     }
     return -1;
   #else
-    struct timespec time;
-    clock_gettime(CLOCK_MONOTONIC, &time);
-
-    return ((int64_t)time.tv_sec * (int64_t)1000) + (int64_t)time.tv_nsec / (int64_t)1000;
+    timeval time;
+    gettimeofday(&time, NULL);
+    return (int64_t) (time.tv_sec * 1000 + time.tv_usec / 1000);
   #endif
   }
 
index 443b426b2fd9c9e174e830b00e1ece7b5ade7961..de2a9a394171f8c60367038cac90592953223afd 100644 (file)
@@ -166,14 +166,14 @@ void CSerialPort::Close(void)
   }
 }
 
-int8_t CSerialPort::Write(const cec_frame &data)
+int8_t CSerialPort::Write(const cec_adapter_message &data)
 {
   CLockObject lock(&m_mutex);
   DWORD iBytesWritten = 0;
   if (!m_bIsOpen)
     return -1;
 
-  if (!WriteFile(m_handle, data.data, data.size, &iBytesWritten, NULL))
+  if (!WriteFile(m_handle, data.packet.data, data.size(), &iBytesWritten, NULL))
   {
     m_error = "Error while writing to COM port";
     FormatWindowsError(GetLastError(), m_error);
index c239d3b1d802312d9369bb79118e742ac4e94951..c67f0cc90ef020f0a0ef2d5b563c5c006c3c544c 100644 (file)
@@ -42,7 +42,7 @@
 using namespace CEC;
 using namespace std;
 
-#define CEC_TEST_CLIENT_VERSION 5
+#define CEC_TEST_CLIENT_VERSION 6
 
 
 inline bool HexStrToInt(const std::string& data, uint8_t& value)
@@ -105,18 +105,22 @@ void flush_log(ICECAdapter *cecParser)
     switch (message.level)
     {
     case CEC_LOG_ERROR:
-      cout << "ERROR:   " << message.message << endl;
+      cout << "ERROR:   ";
       break;
     case CEC_LOG_WARNING:
-      cout << "WARNING: " << message.message << endl;
+      cout << "WARNING: ";
       break;
     case CEC_LOG_NOTICE:
-      cout << "NOTICE:  " << message.message << endl;
+      cout << "NOTICE:  ";
       break;
     case CEC_LOG_DEBUG:
-      cout << "DEBUG:   " << message.message << endl;
+      cout << "DEBUG:   ";
       break;
     }
+
+    CStdString strMessageTmp;
+    strMessageTmp.Format("[%16lld]\t%s", message.time, message.message);
+    cout << strMessageTmp.c_str() << endl;
   }
 }
 
@@ -164,13 +168,22 @@ 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 <<
+  "on {address}              power on the device with the given logical address." << endl <<
+  "[on 5]                    power on a connected audio system" << endl <<
+  endl <<
+  "standby {address}         put the device with the given address in standby mode." << endl <<
+  "[standby 0]               powers off the TV" << endl <<
+  endl <<
   "la {logical_address}      change the logical address of the CEC adapter." << endl <<
   "[la 4]                    logical address 4" << endl <<
   endl <<
   "[ping]                    send a ping command to the CEC adapter." << endl <<
-  "[bl]                      to let the adapter enter the bootloader, to upgrade the flash rom." << endl <<
+  "[bl]                      to let the adapter enter the bootloader, to upgrade" << endl <<
+  "                          the flash rom." << endl <<
+  "[r]                       reconnect to the CEC adapter." << endl <<
   "[h] or [help]             show this help." << endl <<
-  "[q] or [quit]             to quit the CEC test client and switch off all connected CEC devices." << endl <<
+  "[q] or [quit]             to quit the CEC test client and switch off all" << endl <<
+  "                          connected CEC devices." << endl <<
   "================================================================================" << endl;
 }
 
@@ -263,7 +276,7 @@ int main (int argc, char *argv[])
         {
           string strvalue;
           uint8_t ivalue;
-          cec_frame bytes;
+          cec_command bytes;
           bytes.clear();
 
           while (GetWord(input, strvalue) && HexStrToInt(strvalue, ivalue))
@@ -271,6 +284,32 @@ int main (int argc, char *argv[])
 
           parser->Transmit(bytes);
         }
+        else if (command == "on")
+        {
+          string strValue;
+          uint8_t iValue = 0;
+          if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+          {
+            parser->PowerOnDevices((cec_logical_address) iValue);
+          }
+          else
+          {
+            cout << "invalid destination" << endl;
+          }
+        }
+        else if (command == "standby")
+        {
+          string strValue;
+          uint8_t iValue = 0;
+          if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+          {
+            parser->StandbyDevices((cec_logical_address) iValue);
+          }
+          else
+          {
+            cout << "invalid destination" << endl;
+          }
+        }
         else if (command == "la")
         {
           string strvalue;