cec: added logical address autodetection and let libcec handle multiple types simulta...
authorLars Op den Kamp <lars@opdenkamp.eu>
Sun, 6 Nov 2011 01:59:32 +0000 (02:59 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Sun, 6 Nov 2011 02:50:46 +0000 (03:50 +0100)
16 files changed:
include/cec.h
include/cecc.h
include/cecloader.h
include/cectypes.h
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/LibCECC.cpp
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/VLCommandHandler.cpp
src/testclient/main.cpp

index c1aad1cb5602774d669603d883a4bfb7f3b2d22c..582bf24be77a6b4537965e637fc39ef16eddbb09 100644 (file)
@@ -172,6 +172,7 @@ namespace CEC
   };
 };
 
+extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_type_list devicesTypes);
 extern "C" DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
 extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);
 
index 8a06956223177874ab30e6663a4104bb17a25818..466714667e37bcbd26652eaffa6686ed2d39a248 100644 (file)
@@ -53,6 +53,19 @@ extern DECLSPEC int cec_init(const char *strDeviceName, CEC::cec_logical_address
 extern DECLSPEC int cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
 #endif
 
+/*!
+ * @brief Load the CEC adapter library.
+ * @param strDeviceName How to present this device to other devices.
+ * @param deviceTypes The device types to use on the CEC bus.
+ * @return True when initialised, false otherwise.
+ */
+#ifdef __cplusplus
+extern DECLSPEC int cec_init_typed(const char *strDeviceName, CEC::cec_device_type_list devicesTypes);
+#else
+extern DECLSPEC int cec_init_typed(const char *strDeviceName, cec_device_type_list devicesTypes);
+#endif
+
+
 /*!
  * @brief Unload the CEC adapter library.
  */
index 242d4fe52d9fb0cbe12cbfeeca6fa8af828d7e7b..d20ca2ff22e22007f0a41fd2e3886e10f9e219e6 100644 (file)
@@ -96,13 +96,44 @@ CEC::ICECAdapter *LoadLibCec(const char *strName, CEC::cec_logical_address iLogi
   _CreateLibCec* CreateLibCec = (_CreateLibCec*) dlsym(g_libCEC, "CECCreate");
   if (!CreateLibCec)
   {
-    cout << "cannot find CreateLibCec" << endl;
+    cout << "cannot find CECCreate" << endl;
     return NULL;
   }
 
   return (CEC::ICECAdapter*) CreateLibCec(strName, iLogicalAddress, iPhysicalAddress);
 }
 
+CEC::ICECAdapter *LibCecInit(const char *strDeviceName, CEC::cec_device_type_list types, const char *strLib = NULL)
+{
+  if (!g_libCEC)
+  {
+#if defined(__APPLE__)
+    g_libCEC = dlopen(strLib ? strLib : "libcec.dylib", RTLD_LAZY);
+#else
+    g_libCEC = dlopen(strLib ? strLib : "libcec.so", RTLD_LAZY);
+#endif
+    if (!g_libCEC)
+    {
+#if defined(__APPLE__)
+      cout << "cannot find " << (strLib ? strLib : "libcec.dylib") << dlerror() << endl;
+#else
+      cout << "cannot find " << (strLib ? strLib : "libcec.so") << dlerror() << endl;
+#endif
+      return NULL;
+    }
+  }
+
+  typedef void* _LibCecInit(const char *, CEC::cec_device_type_list);
+  _LibCecInit* LibCecInit = (_LibCecInit*) dlsym(g_libCEC, "CECInit");
+  if (!LibCecInit)
+  {
+    cout << "cannot find CECInit" << endl;
+    return NULL;
+  }
+
+  return (CEC::ICECAdapter*) LibCecInit(strDeviceName, types);
+}
+
 void UnloadLibCec(CEC::ICECAdapter *device)
 {
   typedef void* _DestroyLibCec(CEC::ICECAdapter *);
index 9481a1f3eb79f7f59e11ec8d5b026ccec8761906..6b9e0b5c6cfed5a75246ad450d882b5cd0728a66 100644 (file)
@@ -142,7 +142,7 @@ typedef enum
   CEC_DECK_INFO_OTHER_STATUS = 0x1F
 } ECecDeckInfo;
 
-typedef enum
+typedef enum cec_device_type
 {
   CEC_DEVICE_TYPE_TV = 0,
   CEC_DEVICE_TYPE_RECORDING_DEVICE = 1,
@@ -150,7 +150,54 @@ typedef enum
   CEC_DEVICE_TYPE_TUNER = 3,
   CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4,
   CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5
-} ECecDeviceType;
+} cec_device_type;
+
+typedef struct cec_device_type_list
+{
+  cec_device_type types[5];
+
+#ifdef __cplusplus
+  void clear(void)
+  {
+    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+     types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+  }
+
+  void add(const cec_device_type type)
+  {
+    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+    {
+      if (types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+      {
+        types[iPtr] = type;
+        break;
+      }
+    }
+  }
+
+  bool isset(cec_device_type type)
+  {
+    bool bReturn(false);
+    for (unsigned int iPtr = 0; !bReturn && iPtr < 5; iPtr++)
+    {
+      if (types[iPtr] == type)
+        bReturn = true;
+    }
+    return bReturn;
+  }
+
+  bool empty()
+  {
+    bool bReturn(true);
+    for (unsigned int iPtr = 0; bReturn && iPtr < 5; iPtr++)
+    {
+      if (types[iPtr] != CEC_DEVICE_TYPE_RESERVED)
+        bReturn = false;
+    }
+    return bReturn;
+  }
+#endif
+} cec_device_type_list;
 
 typedef enum cec_display_control
 {
@@ -463,6 +510,53 @@ typedef enum cec_logical_address
   CECDEVICE_BROADCAST = 15
 } cec_logical_address;
 
+typedef struct cec_logical_addresses
+{
+  cec_logical_address primary;
+  int                 addresses[16];
+
+#ifdef __cplusplus
+  void clear(void)
+  {
+    primary = CECDEVICE_UNKNOWN;
+    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+      addresses[iPtr] = 0;
+  }
+
+  bool empty(void) const
+  {
+    return primary == CECDEVICE_UNKNOWN;
+  }
+
+  uint16_t ackmask(void) const
+  {
+    uint16_t mask = 0;
+    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+      if (addresses[iPtr] == 1)
+        mask |= 0x1 << iPtr;
+    return mask;
+  }
+
+  void set(cec_logical_address address)
+  {
+    if (primary == CECDEVICE_UNKNOWN)
+      primary = address;
+
+    addresses[(int) address] = 1;
+  }
+
+  void unset(cec_logical_address address)
+  {
+    if (primary == address)
+      primary = CECDEVICE_UNKNOWN;
+
+    addresses[(int) address] = 0;
+  }
+
+  bool isset(cec_logical_address address) const { return addresses[(int) address] == 1; }
+#endif
+} cec_logical_addresses;
+
 typedef enum cec_opcode
 {
   CEC_OPCODE_ACTIVE_SOURCE = 0x82,
index 49b3bd2e35a11e5727e0f4c4f850b878999cc440..e46f48be4b133432d95910abb568c1569fc6b077 100644 (file)
@@ -42,16 +42,32 @@ using namespace CEC;
 using namespace std;
 
 CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
-    m_iLogicalAddress(iLogicalAddress),
+    m_bStarted(false),
     m_strDeviceName(strDeviceName),
     m_communication(serComm),
     m_controller(controller),
     m_bMonitor(false)
 {
+  m_logicalAddresses.clear();
+  m_logicalAddresses.set(iLogicalAddress);
+  m_types.clear();
   for (int iPtr = 0; iPtr < 16; iPtr++)
     m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, iPtr == iLogicalAddress ? iPhysicalAddress : 0);
 }
 
+CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types) :
+    m_bStarted(false),
+    m_strDeviceName(strDeviceName),
+    m_types(types),
+    m_communication(serComm),
+    m_controller(controller),
+    m_bMonitor(false)
+{
+  m_logicalAddresses.clear();
+  for (int iPtr = 0; iPtr < 16; iPtr++)
+    m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0);
+}
+
 CCECProcessor::~CCECProcessor(void)
 {
   m_startCondition.Broadcast();
@@ -73,7 +89,7 @@ bool CCECProcessor::Start(void)
 
   if (CreateThread())
   {
-    if (!m_startCondition.Wait(&m_mutex))
+    if (!m_startCondition.Wait(&m_mutex) || !m_bStarted)
     {
       m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
       return false;
@@ -86,17 +102,111 @@ bool CCECProcessor::Start(void)
   return false;
 }
 
+bool CCECProcessor::TryLogicalAddress(cec_logical_address address, const char *strLabel)
+{
+  CStdString strLog;
+  strLog.Format("trying logical address '%s'", strLabel);
+  AddLog(CEC_LOG_DEBUG, strLog);
+
+  SetAckMask(0x1 << address);
+  if (!m_busDevices[address]->PollDevice(address))
+  {
+
+    strLog.Format("using logical address '%s'", strLabel);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    m_logicalAddresses.set(address);
+
+    // TODO
+    m_busDevices[address]->SetPhysicalAddress(CEC_DEFAULT_PHYSICAL_ADDRESS);
+
+    return true;
+  }
+
+  strLog.Format("logical address '%s' already taken", strLabel);
+  AddLog(CEC_LOG_DEBUG, strLog);
+  return false;
+}
+
+bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
+{
+  AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
+  return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1, "recording 1") ||
+      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2, "recording 2") ||
+      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3, "recording 3");
+}
+
+bool CCECProcessor::FindLogicalAddressTuner(void)
+{
+  AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
+  return TryLogicalAddress(CECDEVICE_TUNER1, "tuner 1") ||
+      TryLogicalAddress(CECDEVICE_TUNER2, "tuner 2") ||
+      TryLogicalAddress(CECDEVICE_TUNER3, "tuner 3") ||
+      TryLogicalAddress(CECDEVICE_TUNER4, "tuner 4");
+}
+
+bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
+{
+  AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
+  return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1, "playback 1") ||
+      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2, "playback 2") ||
+      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3, "playback 3");
+}
+
+bool CCECProcessor::FindLogicalAddressAudioSystem(void)
+{
+  AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
+  return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM, "audio");
+}
+
+bool CCECProcessor::FindLogicalAddresses(void)
+{
+  bool bReturn(true);
+  m_logicalAddresses.clear();
+  CStdString strLog;
+
+  for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+  {
+    if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+      continue;
+
+    strLog.Format("%s - device %d: type %d", __FUNCTION__, iPtr, m_types.types[iPtr]);
+    AddLog(CEC_LOG_DEBUG, strLog);
+
+    if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+      bReturn &= FindLogicalAddressRecordingDevice();
+    if (m_types.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
+      bReturn &= FindLogicalAddressTuner();
+    if (m_types.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
+      bReturn &= FindLogicalAddressPlaybackDevice();
+    if (m_types.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+      bReturn &= FindLogicalAddressAudioSystem();
+  }
+
+  return bReturn;
+}
+
 void *CCECProcessor::Process(void)
 {
   cec_command           command;
   CCECAdapterMessage    msg;
 
-  SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
-
   {
-    CLockObject lock(&m_mutex);
-    m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
-    m_startCondition.Signal();
+    if (m_logicalAddresses.empty() && !FindLogicalAddresses())
+    {
+      CLockObject lock(&m_mutex);
+      m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addressed");
+      m_startCondition.Signal();
+      return NULL;
+    }
+
+    SetAckMask(m_logicalAddresses.ackmask());
+
+    {
+      CLockObject lock(&m_mutex);
+      m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
+      m_bStarted = true;
+      m_startCondition.Signal();
+    }
   }
 
   while (!IsStopped())
@@ -138,8 +248,8 @@ bool CCECProcessor::SetActiveView(void)
   if (!IsRunning())
     return false;
 
-  if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress])
-    return m_busDevices[m_iLogicalAddress]->BroadcastActiveView();
+  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
+    return m_busDevices[m_logicalAddresses.primary]->BroadcastActiveView();
   return false;
 }
 
@@ -148,8 +258,8 @@ bool CCECProcessor::SetInactiveView(void)
   if (!IsRunning())
     return false;
 
-  if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress])
-    return m_busDevices[m_iLogicalAddress]->BroadcastInactiveView();
+  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
+    return m_busDevices[m_logicalAddresses.primary]->BroadcastInactiveView();
   return false;
 }
 
@@ -167,13 +277,14 @@ void CCECProcessor::LogOutput(const cec_command &data)
 
 bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
 {
-  if (m_iLogicalAddress != iLogicalAddress)
+  if (m_logicalAddresses.primary != iLogicalAddress)
   {
     CStdString strLog;
-    strLog.Format("<< setting logical address to %1x", iLogicalAddress);
+    strLog.Format("<< setting primary logical address to %1x", iLogicalAddress);
     m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
-    m_iLogicalAddress = iLogicalAddress;
-    return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
+    m_logicalAddresses.primary = iLogicalAddress;
+    m_logicalAddresses.set(iLogicalAddress);
+    return SetAckMask(m_logicalAddresses.ackmask());
   }
 
   return true;
@@ -181,10 +292,10 @@ bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
 
 bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress)
 {
-  if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress])
+  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
   {
-    m_busDevices[m_iLogicalAddress]->SetPhysicalAddress(iPhysicalAddress);
-    return m_busDevices[m_iLogicalAddress]->BroadcastActiveView();
+    m_busDevices[m_logicalAddresses.primary]->SetPhysicalAddress(iPhysicalAddress);
+    return m_busDevices[m_logicalAddresses.primary]->BroadcastActiveView();
   }
   return false;
 }
@@ -199,7 +310,7 @@ bool CCECProcessor::SwitchMonitoring(bool bEnable)
   if (bEnable)
     return SetAckMask(0);
   else
-    return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
+    return SetAckMask(m_logicalAddresses.ackmask());
 }
 
 bool CCECProcessor::PollDevice(cec_logical_address iAddress)
@@ -285,7 +396,8 @@ void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode
   m_controller->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
 
   cec_command command;
-  cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_FEATURE_ABORT);
+  // TODO
+  cec_command::format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
   command.parameters.push_back((uint8_t)opcode);
   command.parameters.push_back((uint8_t)reason);
 
@@ -388,8 +500,8 @@ void CCECProcessor::ParseCommand(cec_command &command)
 
 uint16_t CCECProcessor::GetPhysicalAddress(void) const
 {
-  if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress])
-    return m_busDevices[m_iLogicalAddress]->GetPhysicalAddress();
+  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
+    return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress();
   return false;
 }
 
index ea61365c18959b74bb663dda90b9a5d85692287b..a9c1065b918dd8a9d357998d5ccdec23fa9f3bed 100644 (file)
@@ -50,6 +50,7 @@ namespace CEC
   {
     public:
       CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+      CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types);
       virtual ~CCECProcessor(void);
 
       virtual bool Start(void);
@@ -60,7 +61,8 @@ namespace CEC
       virtual const std::string & GetDeviceName(void) { return m_strDeviceName; }
       virtual uint64_t            GetDeviceVendorId(cec_logical_address iAddress);
       virtual cec_power_status    GetDevicePowerStatus(cec_logical_address iAddress);
-      virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; }
+      virtual cec_logical_address GetLogicalAddress(void) const { return m_logicalAddresses.primary; }
+      virtual bool                HasLogicalAddress(cec_logical_address address) const { return m_logicalAddresses.isset(address); }
       virtual uint16_t            GetPhysicalAddress(void) const;
 
       virtual bool SetActiveView(void);
@@ -80,22 +82,32 @@ namespace CEC
       virtual void AddKey(void);
       virtual void AddLog(cec_log_level level, const CStdString &strMessage);
 
+      virtual bool FindLogicalAddresses(void);
+
       CCECBusDevice *m_busDevices[16];
 
   private:
+      bool TryLogicalAddress(cec_logical_address address, const char *strLabel);
+      bool FindLogicalAddressRecordingDevice(void);
+      bool FindLogicalAddressTuner(void);
+      bool FindLogicalAddressPlaybackDevice(void);
+      bool FindLogicalAddressAudioSystem(void);
+
       bool SetAckMask(uint16_t iMask);
       void LogOutput(const cec_command &data);
       bool WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout = 1000);
       bool ParseMessage(const CCECAdapterMessage &msg);
       void ParseCommand(cec_command &command);
 
+      bool                   m_bStarted;
       cec_command            m_currentframe;
-      cec_logical_address    m_iLogicalAddress;
+      cec_logical_addresses  m_logicalAddresses;
       std::string            m_strDeviceName;
+      cec_device_type_list   m_types;
       CMutex                 m_mutex;
       CCondition             m_startCondition;
-      CAdapterCommunication *m_communication;
-      CLibCEC               *m_controller;
+      CAdapterCommunicationm_communication;
+      CLibCEC*               m_controller;
       bool                   m_bMonitor;
   };
 };
index aff5776727b895272060c66d6beb7ce1e852cc19..7c87a8fdcbd6e74f0d9a502d7facc6c1f1ed2d3e 100644 (file)
 using namespace std;
 using namespace CEC;
 
+CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list types) :
+    m_iStartTime(GetTimeMs()),
+    m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+    m_buttontime(0)
+{
+  m_comm = new CAdapterCommunication(this);
+  m_cec = new CCECProcessor(this, m_comm, strDeviceName, types);
+}
+
 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),
@@ -296,6 +305,11 @@ void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAdd
   return static_cast< void* > (new CLibCEC(strDeviceName, iLogicalAddress, iPhysicalAddress));
 }
 
+void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types)
+{
+  return static_cast< void* > (new CLibCEC(strDeviceName, types));
+}
+
 void CECDestroy(CEC::ICECAdapter *instance)
 {
   CLibCEC *lib = static_cast< CLibCEC* > (instance);
index bd3ca600cd7bdd4817090d0e4770d2f54bc8e30f..69c5b1890f78488c5838de3ad0711c85feaeb2db 100644 (file)
@@ -47,6 +47,7 @@ namespace CEC
      * ICECAdapter implementation
      */
     //@{
+      CLibCEC(const char *strDeviceName, cec_device_type_list types);
       CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
       virtual ~CLibCEC(void);
 
index 09b40dba942af682b6a6ae3d41dce3520e5cdbc8..a2e58c509434ce5a4fb37a8408b15b306bcec340 100644 (file)
@@ -48,6 +48,12 @@ int cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress /* =
   return (cec_parser != NULL) ? 1 : 0;
 }
 
+int cec_init_typed(const char *strDeviceName, cec_device_type_list devicesTypes)
+{
+  cec_parser = (ICECAdapter *) CECInit(strDeviceName, devicesTypes);
+  return (cec_parser != NULL) ? 1 : 0;
+}
+
 void cec_destroy(void)
 {
   cec_close();
index 5a56dc4baaae6b757cd8c037bb9cb37d3fdbdb1c..d9855379610600f7ded92bef0d85b5a1461d68cf 100644 (file)
@@ -67,6 +67,11 @@ cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
   return m_processor->GetLogicalAddress();
 }
 
+bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
+{
+  return m_processor->HasLogicalAddress(address);
+}
+
 uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
 {
   return m_processor->GetPhysicalAddress();
@@ -191,7 +196,7 @@ const cec_vendor &CCECBusDevice::GetVendor(void)
   {
     AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID");
     cec_command command;
-    cec_command::format(command, GetMyLogicalAddress(), GetLogicalAddress(), CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+    cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
     CLockObject lock(&m_mutex);
 
     if (m_processor->Transmit(command))
@@ -211,7 +216,7 @@ void CCECBusDevice::PollVendorId(void)
     m_iLastActive = GetTimeMs();
 
     cec_command command;
-    cec_command::format(command, GetMyLogicalAddress(), GetLogicalAddress(), CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+    cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
     if (m_processor->Transmit(command))
       m_condition.Wait(&m_mutex, 1000);
   }
@@ -222,7 +227,7 @@ void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress, uint16_t iOldAddres
   if (iNewAddress > 0)
   {
     CStdString strLog;
-    strLog.Format(">> %i changed physical address from %04x to %04x", GetLogicalAddress(), m_iPhysicalAddress, iNewAddress);
+    strLog.Format(">> %i changed physical address from %04x to %04x", m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
     AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
     m_iPhysicalAddress = iNewAddress;
@@ -269,26 +274,26 @@ bool CCECBusDevice::SetOSDString(cec_display_control duration, const char *strMe
   return m_processor->Transmit(command);
 }
 
-bool CCECBusDevice::ReportCECVersion(void)
+bool CCECBusDevice::ReportCECVersion(cec_logical_address dest)
 {
   AddLog(CEC_LOG_NOTICE, "<< reporting CEC version as 1.3a");
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_CEC_VERSION);
+  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_CEC_VERSION);
   command.parameters.push_back(CEC_VERSION_1_3A);
 
   return m_processor->Transmit(command);
 }
 
-bool CCECBusDevice::ReportDeckStatus(void)
+bool CCECBusDevice::ReportDeckStatus(cec_logical_address dest)
 {
   // need to support opcodes play and deck control before doing anything with this
   AddLog(CEC_LOG_NOTICE, "<< deck status requested, feature abort");
-  m_processor->TransmitAbort(m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+  m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
   return false;
 }
 
-bool CCECBusDevice::ReportMenuState(bool bActive /* = true */)
+bool CCECBusDevice::ReportMenuState(cec_logical_address dest, bool bActive /* = true */)
 {
   if (bActive)
     AddLog(CEC_LOG_NOTICE, "<< reporting menu state as active");
@@ -296,13 +301,13 @@ bool CCECBusDevice::ReportMenuState(bool bActive /* = true */)
     AddLog(CEC_LOG_NOTICE, "<< reporting menu state as inactive");
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_MENU_STATUS);
+  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_MENU_STATUS);
   command.parameters.push_back(bActive ? (uint8_t) CEC_MENU_STATE_ACTIVATED : (uint8_t) CEC_MENU_STATE_DEACTIVATED);
 
   return m_processor->Transmit(command);
 }
 
-bool CCECBusDevice::ReportOSDName(void)
+bool CCECBusDevice::ReportOSDName(cec_logical_address dest)
 {
   const char *osdname = m_processor->GetDeviceName().c_str();
   CStdString strLog;
@@ -310,31 +315,29 @@ bool CCECBusDevice::ReportOSDName(void)
   AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_SET_OSD_NAME);
+  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_SET_OSD_NAME);
   for (unsigned int iPtr = 0; iPtr < strlen(osdname); iPtr++)
     command.parameters.push_back(osdname[iPtr]);
 
   return m_processor->Transmit(command);
 }
 
-bool CCECBusDevice::ReportPowerState(bool bOn /* = true */)
+bool CCECBusDevice::ReportPowerState(cec_logical_address dest)
 {
-  if (bOn)
-    AddLog(CEC_LOG_NOTICE, "<< reporting \"On\" power status");
-  else
-    AddLog(CEC_LOG_NOTICE, "<< reporting \"Off\" power status");
+  AddLog(CEC_LOG_NOTICE, "<< reporting \"On\" power status");
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_REPORT_POWER_STATUS);
-  command.parameters.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY);
+  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_REPORT_POWER_STATUS);
+//  command.parameters.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY);
+  command.parameters.push_back((uint8_t) CEC_POWER_STATUS_ON);
 
   return m_processor->Transmit(command);
 }
 
-bool CCECBusDevice::ReportVendorID(void)
+bool CCECBusDevice::ReportVendorID(cec_logical_address dest)
 {
   AddLog(CEC_LOG_NOTICE, "<< vendor ID requested, feature abort");
-  m_processor->TransmitAbort(m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+  m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
   return false;
 }
 
@@ -343,7 +346,7 @@ bool CCECBusDevice::BroadcastActiveView(void)
   AddLog(CEC_LOG_DEBUG, "<< setting active view");
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
   command.parameters.push_back((m_iPhysicalAddress >> 8) & 0xFF);
   command.parameters.push_back(m_iPhysicalAddress & 0xFF);
 
@@ -355,7 +358,7 @@ bool CCECBusDevice::BroadcastInactiveView(void)
   AddLog(CEC_LOG_DEBUG, "<< setting inactive view");
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_INACTIVE_SOURCE);
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_INACTIVE_SOURCE);
   command.parameters.push_back((m_iPhysicalAddress >> 8) & 0xFF);
   command.parameters.push_back(m_iPhysicalAddress & 0xFF);
 
@@ -369,7 +372,7 @@ bool CCECBusDevice::BroadcastPhysicalAddress(void)
   AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
   command.parameters.push_back((uint8_t) ((m_iPhysicalAddress >> 8) & 0xFF));
   command.parameters.push_back((uint8_t) (m_iPhysicalAddress & 0xFF));
   command.parameters.push_back((uint8_t) (CEC_DEVICE_TYPE_PLAYBACK_DEVICE));
@@ -382,7 +385,7 @@ bool CCECBusDevice::BroadcastActiveSource(void)
   AddLog(CEC_LOG_NOTICE, "<< broadcasting active source");
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
+  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
   command.parameters.push_back((uint8_t) ((m_iPhysicalAddress >> 8) & 0xFF));
   command.parameters.push_back((uint8_t) (m_iPhysicalAddress & 0xFF));
 
@@ -434,16 +437,19 @@ cec_power_status CCECBusDevice::GetPowerStatus(bool bRefresh /* = true */)
   return m_powerStatus;
 }
 
-bool CCECBusDevice::PollDevice(void)
+bool CCECBusDevice::PollDevice(cec_logical_address source /* = CECDEVICE_UNKNOWN */)
 {
   bool bReturn(false);
 
+  if (source == CECDEVICE_UNKNOWN)
+    source = GetMyLogicalAddress();
+
   CStdString strLog;
-  strLog.Format("<< sending POLL from device %1x to device %1x", (int8_t)GetMyLogicalAddress(), m_iLogicalAddress);
+  strLog.Format("<< sending POLL from device %1x to device %1x", (int8_t)source, m_iLogicalAddress);
   AddLog(CEC_LOG_DEBUG, strLog);
 
   cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_NONE);
+  cec_command::format(command, source, m_iLogicalAddress, CEC_OPCODE_NONE);
   CLockObject lock(&m_mutex);
 
   bReturn = m_processor->Transmit(command);
index 278c0386c5619b165870d7515bb636a440849659..362e86ed4c0d146e12455d75e79453b10093e003 100644 (file)
@@ -46,6 +46,7 @@ namespace CEC
     CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0);
     virtual ~CCECBusDevice(void);
 
+    virtual bool                MyLogicalAddressContains(cec_logical_address address) const;
     virtual cec_logical_address GetMyLogicalAddress(void) const;
     virtual uint16_t            GetMyPhysicalAddress(void) const;
     virtual const char *        GetVendorName(void) { return GetVendor().AsString(); }
@@ -58,7 +59,7 @@ namespace CEC
     virtual cec_version         GetCecVersion(bool bRefresh = true);
     virtual cec_menu_language & GetMenuLanguage(bool bRefresh = true);
     virtual cec_power_status    GetPowerStatus(bool bRefresh = true);
-    virtual bool                PollDevice(void);
+    virtual bool                PollDevice(cec_logical_address source = CECDEVICE_UNKNOWN);
 
     virtual bool PowerOn(void);
     virtual bool Standby(void);
@@ -78,12 +79,12 @@ namespace CEC
     virtual CCECProcessor *GetProcessor() const { return m_processor; }
     virtual CCECCommandHandler *GetHandler(void) const { return m_handler; };
 
-    virtual bool ReportCECVersion(void);
-    virtual bool ReportDeckStatus(void);
-    virtual bool ReportMenuState(bool bActive = true);
-    virtual bool ReportOSDName(void);
-    virtual bool ReportPowerState(bool bOn = true);
-    virtual bool ReportVendorID(void);
+    virtual bool ReportCECVersion(cec_logical_address dest);
+    virtual bool ReportDeckStatus(cec_logical_address dest);
+    virtual bool ReportMenuState(cec_logical_address dest, bool bActive = true);
+    virtual bool ReportOSDName(cec_logical_address dest);
+    virtual bool ReportPowerState(cec_logical_address dest);
+    virtual bool ReportVendorID(cec_logical_address dest);
 
     virtual bool BroadcastActiveView(void);
     virtual bool BroadcastInactiveView(void);
index f1e3dd5b1c2da7b7ec7fe50bb96e80ebeaf97cdd..3da959eb5939f61c2e1189cddac4abbe1d297bfc 100644 (file)
@@ -75,7 +75,7 @@ bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
 bool CANCommandHandler::HandleCommand(const cec_command &command)
 {
   bool bHandled(false);
-  if (command.destination == m_busDevice->GetMyLogicalAddress())
+  if (m_busDevice->MyLogicalAddressContains(command.destination))
   {
     switch(command.opcode)
     {
index ac00ebf86ab18e9957ce66fcd1a5d9d09d6cb77a..625ed010c3b42b23500179f22524d76e27e44237 100644 (file)
@@ -45,7 +45,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
 {
   bool bHandled(true);
 
-  if (command.destination == m_busDevice->GetMyLogicalAddress())
+  if (m_busDevice->MyLogicalAddressContains(command.destination))
   {
     switch(command.opcode)
     {
@@ -135,7 +135,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
   else
   {
     CStdString strLog;
-    strLog.Format("ignoring frame: destination: %u != %u", command.destination, (uint8_t)m_busDevice->GetMyLogicalAddress());
+    strLog.Format("ignoring frame: we're not at destination %x", command.destination);
     m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
     bHandled = false;
   }
@@ -175,52 +175,52 @@ bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
 
 bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.initiator);
+  CCECBusDevice *device = GetDevice(command.destination);
   if (device)
-    return device->ReportCECVersion();
+    return device->ReportCECVersion(command.initiator);
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.initiator);
+  CCECBusDevice *device = GetDevice(command.destination);
   if (device)
-    return device->ReportDeckStatus();
+    return device->ReportDeckStatus(command.initiator);
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.initiator);
+  CCECBusDevice *device = GetDevice(command.destination);
   if (device)
-    return device->ReportPowerState();
+    return device->ReportPowerState(command.initiator);
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.initiator);
+  CCECBusDevice *device = GetDevice(command.destination);
   if (device)
-    return device->ReportVendorID();
+    return device->ReportVendorID(command.initiator);
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.initiator);
+  CCECBusDevice *device = GetDevice(command.destination);
   if (device)
-    return device->ReportOSDName();
+    return device->ReportOSDName(command.initiator);
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
 {
-  CCECBusDevice *device = GetThisDevice();
+  CCECBusDevice *device = GetDevice(command.destination);
   if (device)
     return device->BroadcastPhysicalAddress();
 
@@ -231,9 +231,9 @@ bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
 {
   if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY)
   {
-    CCECBusDevice *device = GetDevice(command.initiator);
+    CCECBusDevice *device = GetDevice(command.destination);
     if (device)
-      return device->ReportMenuState();
+      return device->ReportMenuState(command.initiator);
   }
   return false;
 }
@@ -254,7 +254,7 @@ bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
   CStdString strLog;
   strLog.Format(">> %i requests active source", (uint8_t) command.initiator);
   m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
-  CCECBusDevice *device = GetThisDevice();
+  CCECBusDevice *device = m_busDevice->GetProcessor()->m_busDevices[m_busDevice->GetMyLogicalAddress()];
   if (device)
     return device->BroadcastActiveSource();
   return false;
@@ -302,7 +302,7 @@ bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
     m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
     if (streamaddr == m_busDevice->GetMyPhysicalAddress())
     {
-      CCECBusDevice *device = GetThisDevice();
+      CCECBusDevice *device = GetDevice(command.destination);
       if (device)
         return device->BroadcastActiveSource();
       return false;
@@ -351,8 +351,3 @@ CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress
 
   return device;
 }
-
-CCECBusDevice *CCECCommandHandler::GetThisDevice(void) const
-{
-  return m_busDevice->GetProcessor()->m_busDevices[m_busDevice->GetMyLogicalAddress()];
-}
index 0505c7cc81ff23e77ec1a78ae0bc825d4d1e152b..d6acd7512a84f6c21da0f7d74055878941d49046 100644 (file)
@@ -69,7 +69,6 @@ namespace CEC
     void SendToCommandBuffer(const cec_command &command);
 
     CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
-    CCECBusDevice *GetThisDevice(void) const;
     CCECBusDevice *m_busDevice;
   };
 };
index 89f5b2eadebc5668436040c68b841e4c4b798f0d..0104e9a240e86baa26799e96ee95f16ac04e3bd9 100644 (file)
@@ -51,13 +51,12 @@ bool CVLCommandHandler::HandleSetStreamPath(const cec_command &command)
     m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
     if (streamaddr == m_busDevice->GetMyPhysicalAddress())
     {
-      CCECBusDevice *device = GetThisDevice();
-      CCECBusDevice *initiatorDevice = GetDevice(command.initiator);
-      if (device && initiatorDevice)
+      CCECBusDevice *device = GetDevice(command.destination);
+      if (device)
       {
         return device->BroadcastActiveSource() &&
                device->BroadcastActiveView() &&
-               initiatorDevice->ReportMenuState();
+               device->ReportMenuState(command.initiator);
       }
       return false;
     }
index 048182985923f58af7ce76c3764fe6603c02c06f..f16bcbf0404eb8baaacec0cef18662af921530a5 100644 (file)
@@ -49,7 +49,6 @@ using namespace std;
 #include <cecloader.h>
 
 int        g_cecLogLevel = CEC_LOG_ALL;
-int        g_iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1;
 ofstream   g_logOutput;
 bool       g_bShortLog = false;
 CStdString g_strPort;
@@ -180,7 +179,7 @@ void show_help(const char* strExec)
       "parameters:" << endl <<
       "  -h --help                   Shows this help text" << endl <<
       "  -l --list-devices           List all devices on this system" << endl <<
-      "  -la --logical-address {a}   The logical address to use." << endl <<
+      "  -t --type {p|r|t|a}         The device type to use. More than one is possible." << endl <<
       "  -f --log-file {file}        Writes all libCEC log message to a file" << endl <<
       "  -sf --short-log-file {file} Writes all libCEC log message without timestamps" << endl <<
       "                              and log levels to a file." << endl <<
@@ -193,6 +192,26 @@ void show_help(const char* strExec)
       "available commands" << endl;
 }
 
+ICECAdapter *create_parser(cec_device_type_list typeList)
+{
+  ICECAdapter *parser = LibCecInit("CECTester", typeList);
+  if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION)
+  {
+  #ifdef __WINDOWS__
+    cout << "Cannot load libcec.dll" << endl;
+  #else
+    cout << "Cannot load libcec.so" << endl;
+  #endif
+    return NULL;
+  }
+
+  CStdString strLog;
+  strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor());
+  cout << strLog.c_str() << endl;
+
+  return parser;
+}
+
 void show_console_help(void)
 {
   cout << endl <<
@@ -247,26 +266,8 @@ void show_console_help(void)
 
 int main (int argc, char *argv[])
 {
-  ICECAdapter *parser = LoadLibCec("CECTester");
-  if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION)
-  {
-#ifdef __WINDOWS__
-    cout << "Cannot load libcec.dll" << endl;
-#else
-    cout << "Cannot load libcec.so" << endl;
-#endif
-    return 1;
-  }
-  CStdString strLog;
-  strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor());
-  cout << strLog.c_str() << endl;
-
-  //make stdin non-blocking
-#ifndef __WINDOWS__
-  int flags = fcntl(0, F_GETFL, 0);
-  flags |= O_NONBLOCK;
-  fcntl(0, F_SETFL, flags);
-#endif
+  cec_device_type_list typeList;
+  typeList.clear();
 
   int iArgPtr = 1;
   while (iArgPtr < argc)
@@ -313,41 +314,54 @@ int main (int argc, char *argv[])
           ++iArgPtr;
         }
       }
-      else if (!strcmp(argv[iArgPtr], "-la") ||
-               !strcmp(argv[iArgPtr], "--logical-address"))
+      else if (!strcmp(argv[iArgPtr], "-t") ||
+               !strcmp(argv[iArgPtr], "--type"))
       {
         if (argc >= iArgPtr + 2)
         {
-          int iNewAddress = atoi(argv[iArgPtr + 1]);
-          if (iNewAddress >= 0 && iNewAddress <= 15)
+          if (!strcmp(argv[iArgPtr + 1], "p"))
+          {
+            cout << "== using device type 'playback device'" << endl;
+            typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+          }
+          else if (!strcmp(argv[iArgPtr + 1], "r"))
           {
-            g_iLogicalAddress = iNewAddress;
-            cout << "logical address set to " << argv[iArgPtr + 1] << endl;
+            cout << "== using device type 'recording device'" << endl;
+            typeList.add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+          }
+          else if (!strcmp(argv[iArgPtr + 1], "t"))
+          {
+            cout << "== using device type 'tuner'" << endl;
+            typeList.add(CEC_DEVICE_TYPE_TUNER);
+          }
+          else if (!strcmp(argv[iArgPtr + 1], "a"))
+          {
+            cout << "== using device type 'audio system'" << endl;
+            typeList.add(CEC_DEVICE_TYPE_AUDIO_SYSTEM);
           }
           else
           {
-            cout << "== skipped logical-address parameter: invalid address '" << argv[iArgPtr + 1] << "' ==" << endl;
+            cout << "== skipped invalid device type '" << argv[iArgPtr + 1] << "'" << endl;
           }
-          iArgPtr += 2;
-        }
-        else
-        {
-          cout << "== skipped logical-address parameter: no address given ==" << endl;
           ++iArgPtr;
         }
+        ++iArgPtr;
       }
       else if (!strcmp(argv[iArgPtr], "--list-devices") ||
                !strcmp(argv[iArgPtr], "-l"))
       {
-        list_devices(parser);
-        UnloadLibCec(parser);
+        ICECAdapter *parser = create_parser(typeList);
+        if (parser)
+        {
+          list_devices(parser);
+          UnloadLibCec(parser);
+        }
         return 0;
       }
       else if (!strcmp(argv[iArgPtr], "--help") ||
                !strcmp(argv[iArgPtr], "-h"))
       {
         show_help(argv[0]);
-        UnloadLibCec(parser);
         return 0;
       }
       else
@@ -357,6 +371,33 @@ int main (int argc, char *argv[])
     }
   }
 
+  if (typeList.empty())
+  {
+    cout << "No device type given. Using 'playback device'" << endl;
+    typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+  }
+
+  ICECAdapter *parser = LibCecInit("CECTester", typeList);
+  if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION)
+  {
+#ifdef __WINDOWS__
+    cout << "Cannot load libcec.dll" << endl;
+#else
+    cout << "Cannot load libcec.so" << endl;
+#endif
+    return 1;
+  }
+  CStdString strLog;
+  strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor());
+  cout << strLog.c_str() << endl;
+
+  //make stdin non-blocking
+#ifndef __WINDOWS__
+  int flags = fcntl(0, F_GETFL, 0);
+  flags |= O_NONBLOCK;
+  fcntl(0, F_SETFL, flags);
+#endif
+
   if (g_strPort.IsEmpty())
   {
     cout << "no serial port given. trying autodetect: ";
@@ -376,8 +417,6 @@ int main (int argc, char *argv[])
     }
   }
 
-  parser->SetLogicalAddress((cec_logical_address) g_iLogicalAddress);
-
   if (!parser->Open(g_strPort.c_str()))
   {
     cout << "unable to open the device on port " << g_strPort << endl;