cec: added SetHDMIPort()/cec_set_hdmi_port(). devices are now detected on load and...
authorLars Op den Kamp <lars@opdenkamp.eu>
Fri, 25 Nov 2011 15:58:15 +0000 (16:58 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Fri, 25 Nov 2011 16:21:19 +0000 (17:21 +0100)
13 files changed:
include/cec.h
include/cecc.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/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/testclient/main.cpp

index 2e47abde32cb17ff4a13f89e4d787e3470eda31a..5edbe1819fd2b777f8133e9f75a3423d1a740cba 100644 (file)
@@ -262,6 +262,13 @@ namespace CEC
      * @return True when active, false otherwise.
      */
     virtual bool IsActiveDeviceType(cec_device_type type) = 0;
+
+    /*!
+     * @brief Changes the active HDMI port.
+     * @param iPort The new port number.
+     * @return True when changed, false otherwise.
+     */
+    virtual bool SetHDMIPort(uint8_t iPort) = 0;
   };
 };
 
index c6446622c1598e506e0e8dcb721f1dc2ce224de3..409f03a57e730cfe7a471964fa9728611de9623c 100644 (file)
@@ -185,6 +185,8 @@ extern DECLSPEC int cec_is_active_device_type(CEC::cec_device_type type);
 extern DECLSPEC int cec_is_active_device_type(cec_device_type type);
 #endif
 
+extern DECLSPEC int cec_set_hdmi_port(uint8_t iPort);
+
 #ifdef __cplusplus
 };
 #endif
index bc661a8d2d7e1840462af64357337a02cb4de8ec..96ac6035f60ee8b12caefe89a8c020a2e123bc94 100644 (file)
@@ -57,6 +57,7 @@ namespace CEC {
 
 //default physical address 1.0.0.0, HDMI port 1
 #define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
+#define CEC_DEFAULT_HDMI_PORT        1
 #define MSGSTART                     0xFF
 #define MSGEND                       0xFE
 #define MSGESC                       0xFD
index 27bf5bb640714938fd798f2912e8063569267534..8315cd297b1f66ba6d204b924351f939b7bdd6df 100644 (file)
@@ -49,6 +49,7 @@ 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_bStarted(false),
+    m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
     m_strDeviceName(strDeviceName),
     m_communication(serComm),
     m_controller(controller),
@@ -63,6 +64,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm
 
 CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types) :
     m_bStarted(false),
+    m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
     m_strDeviceName(strDeviceName),
     m_types(types),
     m_communication(serComm),
@@ -148,10 +150,6 @@ bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
       m_busDevices[address]->m_bActiveSource = true;
     }
     m_logicalAddresses.Set(address);
-
-    // TODO
-    m_busDevices[address]->SetPhysicalAddress((uint16_t)CEC_DEFAULT_PHYSICAL_ADDRESS);
-
     return true;
   }
 
@@ -226,7 +224,7 @@ void *CCECProcessor::Process(void)
     if (m_logicalAddresses.IsEmpty() && !FindLogicalAddresses())
     {
       CLockObject lock(&m_mutex);
-      m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addressed");
+      m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
       m_startCondition.Signal();
       return NULL;
     }
@@ -235,8 +233,13 @@ void *CCECProcessor::Process(void)
 
     {
       CLockObject lock(&m_mutex);
-      m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
       m_bStarted = true;
+      lock.Leave();
+
+      SetHDMIPort(m_iHDMIPort);
+
+      lock.Lock();
+      m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
       m_startCondition.Signal();
     }
   }
@@ -301,13 +304,13 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE
     }
   }
 
-  return SetStreamPath(m_busDevices[addr]->GetPhysicalAddress()) &&
+  return SetStreamPath(m_busDevices[addr]->GetPhysicalAddress(false)) &&
       m_busDevices[addr]->TransmitActiveSource();
 }
 
 bool CCECProcessor::SetActiveSource(cec_logical_address iAddress)
 {
-  return SetStreamPath(m_busDevices[iAddress]->GetPhysicalAddress());
+  return SetStreamPath(m_busDevices[iAddress]->GetPhysicalAddress(false));
 }
 
 bool CCECProcessor::SetActiveView(void)
@@ -347,6 +350,51 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true *
   return bReturn;
 }
 
+bool CCECProcessor::SetHDMIPort(uint8_t iPort)
+{
+  bool bReturn(false);
+
+  CStdString strLog;
+  strLog.Format("setting HDMI port to %d", iPort);
+  AddLog(CEC_LOG_DEBUG, strLog);
+
+  m_iHDMIPort = iPort;
+  if (!m_bStarted)
+    return true;
+
+  uint16_t iPhysicalAddress(0);
+  int iPos = 3;
+  while(!bReturn && iPos >= 0)
+  {
+    iPhysicalAddress += ((uint16_t)iPort * (0x1 << iPos*4));
+    strLog.Format("checking physical address %4x", iPhysicalAddress);
+    AddLog(CEC_LOG_DEBUG, strLog);
+    if (CheckPhysicalAddress(iPhysicalAddress))
+    {
+      strLog.Format("physical address %4x is in use", iPhysicalAddress);
+      AddLog(CEC_LOG_DEBUG, strLog);
+      iPos--;
+    }
+    else
+    {
+      SetPhysicalAddress(iPhysicalAddress);
+      bReturn = true;
+    }
+  }
+
+  return bReturn;
+}
+
+bool CCECProcessor::CheckPhysicalAddress(uint16_t iPhysicalAddress)
+{
+  for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+  {
+    if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress)
+      return true;
+  }
+  return false;
+}
+
 bool CCECProcessor::SetStreamPath(uint16_t iStreamPath)
 {
   bool bReturn(false);
@@ -414,9 +462,11 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru
 
 bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress)
 {
-  if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
+  if (!m_logicalAddresses.IsEmpty())
   {
-    m_busDevices[m_logicalAddresses.primary]->SetPhysicalAddress(iPhysicalAddress);
+    for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
+      if (m_logicalAddresses[iPtr])
+        m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
     return SetActiveView();
   }
   return false;
@@ -442,15 +492,15 @@ bool CCECProcessor::PollDevice(cec_logical_address iAddress)
   return false;
 }
 
-CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const
 {
-  if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress() == iPhysicalAddress)
+  if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
     return m_busDevices[m_logicalAddresses.primary];
 
   CCECBusDevice *device = NULL;
   for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
   {
-    if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress)
+    if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress)
     {
       device = m_busDevices[iPtr];
       break;
@@ -685,7 +735,7 @@ bool CCECProcessor::IsActiveDeviceType(cec_device_type type)
 uint16_t CCECProcessor::GetPhysicalAddress(void) const
 {
   if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
-    return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress();
+    return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false);
   return false;
 }
 
index e23561b71bc608905408309c9e07dea03217ea46..cf9980ca9429ddc310046ffb30dae294a33bd2bb 100644 (file)
@@ -57,7 +57,7 @@ namespace CEC
       virtual void *Process(void);
 
       virtual bool                  IsMonitoring(void) const { return m_bMonitor; }
-      virtual CCECBusDevice *       GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const;
+      virtual CCECBusDevice *       GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const;
       virtual CCECBusDevice *       GetDeviceByType(cec_device_type type) const;
       virtual cec_version           GetDeviceCecVersion(cec_logical_address iAddress);
       virtual bool                  GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
@@ -77,6 +77,7 @@ namespace CEC
       virtual bool SetActiveSource(cec_logical_address iAddress);
       virtual bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true);
       virtual bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
+      virtual bool SetHDMIPort(uint8_t iPort);
       virtual bool SetInactiveView(void);
       virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
       virtual bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
@@ -101,6 +102,7 @@ namespace CEC
       CCECBusDevice *m_busDevices[16];
 
   private:
+      bool CheckPhysicalAddress(uint16_t iPhysicalAddress);
       bool TryLogicalAddress(cec_logical_address address);
       bool FindLogicalAddressRecordingDevice(void);
       bool FindLogicalAddressTuner(void);
@@ -113,6 +115,7 @@ namespace CEC
       void ParseCommand(cec_command &command);
 
       bool                   m_bStarted;
+      uint8_t                m_iHDMIPort;
       cec_command            m_currentframe;
       cec_logical_addresses  m_logicalAddresses;
       std::string            m_strDeviceName;
index 3b4765134d9fdfd0f1de53f3f87532865480bcab..50ab94fc6949b1b3515a13b2102036656db3c6f3 100644 (file)
@@ -161,11 +161,16 @@ bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
   return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false;
 }
 
-bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress)
+bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
 {
   return m_cec ? m_cec->SetPhysicalAddress(iPhysicalAddress) : false;
 }
 
+bool CLibCEC::SetHDMIPort(uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
+{
+  return m_cec ? m_cec->SetHDMIPort(iPort) : false;
+}
+
 bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
 {
   return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->m_busDevices[(uint8_t)address]->PowerOn() : false;
index b6948e49d42b9ef4e02c7dfd657f99a193bd00dc..66f1b75eb5c78542094908fa19b5b932e3631e03 100644 (file)
@@ -87,6 +87,7 @@ namespace CEC
       virtual cec_logical_addresses GetActiveDevices(void);
       virtual bool IsActiveDevice(cec_logical_address iAddress);
       virtual bool IsActiveDeviceType(cec_device_type type);
+      virtual bool SetHDMIPort(uint8_t iPort = CEC_DEFAULT_HDMI_PORT);
     //@}
 
       virtual void AddLog(cec_log_level level, const std::string &strMessage);
index ec703f2d69ba6c178fb3365f012b8d91977c1195..76f2992882a97c41d4bd255da8b21aad1498ea44 100644 (file)
@@ -264,4 +264,11 @@ int cec_is_active_device_type(cec_device_type type)
   return -1;
 }
 
+int cec_set_hdmi_port(uint8_t iPort)
+{
+  if (cec_parser)
+    return cec_parser->SetHDMIPort(iPort) ? 1 : 0;
+  return -1;
+}
+
 //@}
index 5ca9b5781f4b9411e18965bb5ca77c3460dc2737..d5a0be6aef11dcb76351ad0bea58eaf4e3eb408a 100644 (file)
@@ -214,6 +214,40 @@ uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
   return m_processor->GetPhysicalAddress();
 }
 
+uint16_t CCECBusDevice::GetPhysicalAddress(bool bRefresh /* = true */)
+{
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+  {
+    CLockObject lock(&m_mutex);
+    if (m_iPhysicalAddress == 0xFFFF || bRefresh)
+    {
+      lock.Leave();
+      RequestPhysicalAddress();
+      lock.Lock();
+    }
+  }
+
+  CLockObject lock(&m_mutex);
+  return m_iPhysicalAddress;
+}
+
+bool CCECBusDevice::RequestPhysicalAddress(void)
+{
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
+  {
+    CStdString strLog;
+    strLog.Format("<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    cec_command command;
+    cec_command::Format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
+    CLockObject lock(&m_transmitMutex);
+    if (m_processor->Transmit(command))
+      bReturn = m_condition.Wait(&m_transmitMutex, 1000);
+  }
+  return bReturn;
+}
+
 cec_power_status CCECBusDevice::GetPowerStatus(void)
 {
   CLockObject lock(&m_mutex);
index 9173cadcdbafe2e02f19e0b4e2609f4909a87f37..57d353b4ff3e8547114c54dbcd67be44458e16af 100644 (file)
@@ -63,7 +63,7 @@ namespace CEC
     virtual cec_menu_language &   GetMenuLanguage(void);
     virtual cec_logical_address   GetMyLogicalAddress(void) const;
     virtual uint16_t              GetMyPhysicalAddress(void) const;
-    virtual uint16_t              GetPhysicalAddress(void) const { return m_iPhysicalAddress; }
+    virtual uint16_t              GetPhysicalAddress(bool bRefresh = true);
     virtual cec_power_status      GetPowerStatus(void);
     virtual CCECProcessor *       GetProcessor(void) const { return m_processor; }
     virtual cec_device_type       GetType(void) const { return m_type; }
@@ -76,6 +76,7 @@ namespace CEC
     bool RequestMenuLanguage(void);
     bool RequestPowerStatus(void);
     bool RequestVendorId(void);
+    bool RequestPhysicalAddress(void);
 
     virtual void SetInactiveDevice(void);
     virtual void SetActiveDevice(void);
index 0a39333e54c52f8a410f066481fe56062c78b0e1..a073a3fe475b031010a84c042a7a3d5d426c5c0b 100644 (file)
@@ -341,11 +341,7 @@ bool CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
   if (command.parameters.size == 3)
   {
     uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-    cec_device_type type = (cec_device_type)command.parameters[2];
-
-    CCECBusDevice *device = GetDevice(command.initiator);
-    if (device && device->GetType() == type)
-      device->SetPhysicalAddress(iNewAddress);
+    SetPhysicalAddress(command.initiator, iNewAddress);
   }
   return true;
 }
@@ -393,13 +389,7 @@ bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
   if (command.parameters.size == 2)
   {
     uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-
-    CCECBusDevice *device = GetDevice(command.initiator);
-    if (device)
-    {
-      device->SetStreamPath(iNewAddress);
-      return true;
-    }
+    m_busDevice->GetProcessor()->SetStreamPath(iNewAddress);
   }
 
   return false;
@@ -601,6 +591,22 @@ void CCECCommandHandler::SetVendorId(const cec_command &command)
     device->SetVendorId(iVendorId);
 }
 
+void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
+{
+  if (!m_busDevice->MyLogicalAddressContains(iAddress))
+  {
+    bool bOurAddress(m_busDevice->GetProcessor()->GetPhysicalAddress() == iNewAddress);
+    GetDevice(iAddress)->SetPhysicalAddress(iNewAddress);
+    if (bOurAddress)
+    {
+      /* another device reported the same physical address as ours
+       * since we don't have physical address detection yet, we'll just use the
+       * given address, increased by 0x100 for now */
+      m_busDevice->GetProcessor()->SetPhysicalAddress(iNewAddress + 0x100);
+    }
+  }
+}
+
 const char *CCECCommandHandler::ToString(const cec_menu_state state)
 {
   switch (state)
index 9d3ec03fae58619396ba36d5122a62d093112737..245d39e8aa64a81d10f8589ab09f50c34da5da6c 100644 (file)
@@ -97,6 +97,8 @@ namespace CEC
     virtual CCECBusDevice *GetDeviceByType(cec_device_type type) const;
 
     virtual void SetVendorId(const cec_command &command);
+    virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
+
     CCECBusDevice *m_busDevice;
   };
 };
index dbb62e70804825094853973f43425cc44d54139b..7a60eb2c5a9e9673c899aad00816356459da482c 100644 (file)
@@ -180,7 +180,7 @@ void ShowHelpCommandLine(const char* strExec)
       "  -h --help                   Shows this help text" << endl <<
       "  -l --list-devices           List all devices on this system" << endl <<
       "  -t --type {p|r|t|a}         The device type to use. More than one is possible." << endl <<
-      "  -p --physical {hex-address} The physical address to use for the primary logical device." << endl <<
+      "  -p --port {int}             The HDMI port to use as active source." << 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 <<
@@ -225,8 +225,9 @@ void ShowHelpConsole(void)
   "txn {bytes}               transfer bytes but don't wait for transmission ACK." << endl <<
   "on {address}              power on the device with the given logical address." << endl <<
   "standby {address}         put the device with the given address in standby mode." << endl <<
-  "la {logical_address}      change the logical address of the CEC adapter." << endl <<
-  "pa {physical_address}     change the physical address of the CEC adapter." << endl <<
+  "la {logical address}      change the logical address of the CEC adapter." << endl <<
+  "p {port number}           change the HDMI port number of the CEC adapter." << endl <<
+  "pa {physical address}     change the physical address of the CEC adapter." << endl <<
   "osd {addr} {string}       set OSD message on the specified device." << endl <<
   "ver {addr}                get the CEC version of the specified device." << endl <<
   "ven {addr}                get the vendor ID of the specified device." << endl <<
@@ -250,7 +251,7 @@ void ShowHelpConsole(void)
 
 int main (int argc, char *argv[])
 {
-  int16_t iPhysicalAddress = -1;
+  int8_t iHDMIPort(-1);
   cec_device_type_list typeList;
   typeList.clear();
 
@@ -362,14 +363,12 @@ int main (int argc, char *argv[])
         return 0;
       }
       else if (!strcmp(argv[iArgPtr], "-p") ||
-               !strcmp(argv[iArgPtr], "--physical"))
+               !strcmp(argv[iArgPtr], "--port"))
       {
         if (argc >= iArgPtr + 2)
         {
-          if (sscanf(argv[iArgPtr + 1], "%x", &iPhysicalAddress))
-            cout << "using physical address '" << std::hex << iPhysicalAddress << "'" << endl;
-          else
-            cout << "== skipped physical address parameter: invalid physical address '" << argv[iArgPtr + 1] << "' ==" << endl;
+          iHDMIPort= atoi(argv[iArgPtr + 1]);
+          cout << "using HDMI port '" << iHDMIPort << "'" << endl;
           ++iArgPtr;
         }
         ++iArgPtr;
@@ -438,6 +437,14 @@ int main (int argc, char *argv[])
     }
   }
 
+  if (iHDMIPort > 0)
+  {
+    parser->SetHDMIPort((uint8_t)iHDMIPort);
+    FlushLog(parser);
+  }
+
+  cout << "scanning the CEC bus..." << endl;
+
   if (!parser->Open(g_strPort.c_str()))
   {
     cout << "unable to open the device on port " << g_strPort << endl;
@@ -450,12 +457,6 @@ int main (int argc, char *argv[])
   {
     cout << "cec device opened" << endl;
 
-    if (-1 != iPhysicalAddress)
-    {
-      parser->SetPhysicalAddress(iPhysicalAddress);
-      FlushLog(parser);
-    }
-
     parser->PowerOnDevices(CECDEVICE_TV);
     FlushLog(parser);
 
@@ -551,6 +552,14 @@ int main (int argc, char *argv[])
             parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
           }
         }
+        else if (command == "p")
+        {
+          string strvalue;
+          if (GetWord(input, strvalue))
+          {
+            parser->SetHDMIPort(atoi(strvalue.c_str()));
+          }
+        }
         else if (command == "pa")
         {
           string strB1, strB2;