cec: handle bus scan from LG TVs
authorLars Op den Kamp <lars@opdenkamp.eu>
Fri, 2 Dec 2011 22:11:25 +0000 (23:11 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Fri, 2 Dec 2011 22:11:25 +0000 (23:11 +0100)
src/lib/AdapterCommunication.cpp
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/platform/linux/serialport.cpp
src/lib/platform/serialport.h

index e28be13b2ea42b6af26206582fa940b5300b68fd..32ceeafc02e5835be628af9a2d8e140056c838b0 100644 (file)
@@ -215,8 +215,7 @@ CStdString CCECAdapterMessage::ToString(void) const
 bool CCECAdapterMessage::is_error(void) const
 {
   cec_adapter_messagecode code = message();
-  return (code == MSGCODE_TIMEOUT_ERROR ||
-    code == MSGCODE_HIGH_ERROR ||
+  return (code == MSGCODE_HIGH_ERROR ||
     code == MSGCODE_LOW_ERROR ||
     code == MSGCODE_RECEIVE_FAILED ||
     code == MSGCODE_COMMAND_REJECTED ||
@@ -414,7 +413,8 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
     }
     else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove
     {
-      m_controller->AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+      if (msg.size() > 0)
+        m_controller->AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
       msg.clear();
       bGotStart = true;
     }
index 373c6f3322e995a226c914ed719873c9b4e52671..673e83e34dc9e799da86d66d2f4f7036fb3b1276 100644 (file)
@@ -51,6 +51,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm
     m_bStarted(false),
     m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
     m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
+    m_lastInitiator(CECDEVICE_UNKNOWN),
     m_strDeviceName(strDeviceName),
     m_communication(serComm),
     m_controller(controller),
@@ -232,6 +233,22 @@ bool CCECProcessor::FindLogicalAddresses(void)
   return bReturn;
 }
 
+bool CCECProcessor::SetLineTimeout(uint8_t iTimeout)
+{
+  bool bReturn(false);
+  CCECAdapterMessage *output = new CCECAdapterMessage;
+
+  output->push_back(MSGSTART);
+  output->push_escaped(MSGCODE_TRANSMIT_IDLETIME);
+  output->push_escaped(iTimeout);
+  output->push_back(MSGEND);
+
+  if ((bReturn = Transmit(output)) == false)
+    m_controller->AddLog(CEC_LOG_ERROR, "could not set the idletime");
+  delete output;
+  return bReturn;
+}
+
 void *CCECProcessor::Process(void)
 {
   bool                  bParseFrame(false);
@@ -266,7 +283,6 @@ void *CCECProcessor::Process(void)
       }
       else if (m_communication->IsOpen() && m_communication->Read(msg, 50))
       {
-        m_controller->AddLog(msg.is_error() ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
         if ((bParseFrame = (ParseMessage(msg) && !IsStopped())) == true)
           command = m_currentframe;
       }
@@ -490,7 +506,29 @@ bool CCECProcessor::SwitchMonitoring(bool bEnable)
   strLog.Format("== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
   m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
-  m_bMonitor = bEnable;
+  {
+    CLockObject lock(&m_mutex);
+    m_bMonitor = bEnable;
+
+    if (bEnable)
+    {
+      if (!m_busScan)
+      {
+        m_busScan = new CCECBusScan(this);
+        m_busScan->CreateThread(true);
+      }
+    }
+    else
+    {
+      if (m_busScan)
+      {
+        m_busScan->StopThread();
+        delete m_busScan;
+        m_busScan = NULL;
+      }
+    }
+  }
+
   if (bEnable)
     return SetAckMask(0);
   else
@@ -683,6 +721,23 @@ bool CCECProcessor::WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout
       continue;
     }
 
+    if (msg.message() == MSGCODE_FRAME_START && msg.ack())
+    {
+      m_busDevices[msg.initiator()]->GetHandler()->HandlePoll(msg.initiator(), msg.destination());
+      m_lastInitiator = msg.initiator();
+      iNow = GetTimeMs();
+      continue;
+    }
+
+    bError = msg.is_error();
+    if (msg.message() == MSGCODE_RECEIVE_FAILED &&
+        m_lastInitiator != CECDEVICE_UNKNOWN &&
+        !m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed())
+    {
+      iNow = GetTimeMs();
+      continue;
+    }
+
     if ((bError = msg.is_error()) == false)
     {
       m_controller->AddLog(bError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
@@ -711,7 +766,8 @@ bool CCECProcessor::WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout
 
 bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
 {
-  bool bEom = false;
+  bool bEom(false);
+  bool bIsError(msg.is_error());
 
   if (msg.empty())
     return bEom;
@@ -728,6 +784,17 @@ bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
         m_currentframe.ack         = msg.ack();
         m_currentframe.eom         = msg.eom();
       }
+      if (m_currentframe.ack == true)
+      {
+        m_lastInitiator = m_currentframe.initiator;
+        m_busDevices[m_lastInitiator]->GetHandler()->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
+      }
+    }
+    break;
+  case MSGCODE_RECEIVE_FAILED:
+    {
+      if (m_lastInitiator != CECDEVICE_UNKNOWN)
+        bIsError = m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
     }
     break;
   case MSGCODE_FRAME_DATA:
@@ -744,6 +811,7 @@ bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
     break;
   }
 
+  m_controller->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
   return bEom;
 }
 
index 5ee861d8b55d20ea54f9e37260119653b167da3d..7ec9d8105857d5913a51fe2ca0fdbb8dc5db17fc 100644 (file)
@@ -93,6 +93,8 @@ namespace CEC
       virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = false);
       virtual bool EnablePhysicalAddressDetection(void) { return false; };
 
+      bool SetLineTimeout(uint8_t iTimeout);
+
       const char *ToString(const cec_menu_state state);
       const char *ToString(const cec_version version);
       const char *ToString(const cec_power_status status);
@@ -138,6 +140,7 @@ namespace CEC
       cec_logical_address    m_iBaseDevice;
       cec_command            m_currentframe;
       cec_logical_addresses  m_logicalAddresses;
+      cec_logical_address    m_lastInitiator;
       std::string            m_strDeviceName;
       cec_device_type_list   m_types;
       CMutex                 m_mutex;
index a33a577b0606367ebee5da10c32a142cb7523747..d1a4855c793364ac65981cf7913d6906f3dfac02 100644 (file)
@@ -53,6 +53,8 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
   strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode);
   m_busDevice->AddLog(CEC_LOG_NOTICE, strLog);
 
+  m_processor->AddCommand(command);
+
   switch(command.opcode)
   {
   case CEC_OPCODE_REPORT_POWER_STATUS:
@@ -110,13 +112,13 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleSystemAudioModeRequest(command);
     break;
   case CEC_OPCODE_REPORT_AUDIO_STATUS:
-    HandleReportAudioStatus(command);//YYY
+    HandleReportAudioStatus(command);
     break;
   case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
-    HandleSystemAudioModeStatus(command);//YYY
+    HandleSystemAudioModeStatus(command);
     break;
   case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
-    HandleSetSystemAudioMode(command);//YYY
+    HandleSetSystemAudioMode(command);
     break;
   case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
     HandleRequestActiveSource(command);
@@ -154,7 +156,6 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     break;
   }
 
-  m_processor->AddCommand(command);
   return bHandled;
 }
 
@@ -642,3 +643,16 @@ void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16
     }
   }
 }
+
+void CCECCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  CStdString strLog;
+  strLog.Format("<< POLL: %s (%x) -> %s (%x)", m_processor->ToString(iInitiator), iInitiator, m_processor->ToString(iDestination), iDestination);
+  m_processor->AddLog(CEC_LOG_DEBUG, strLog);
+}
+
+bool CCECCommandHandler::HandleReceiveFailed(void)
+{
+  /* default = error */
+  return true;
+}
index 8fb9446f8bfac6f1c7050b52537c056270f52cb1..8c6d0c10506149e5faff24e997b3c1c06b4ab296 100644 (file)
@@ -47,6 +47,8 @@ namespace CEC
 
     virtual bool HandleCommand(const cec_command &command);
     virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_UNKNOWN; };
+    virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool HandleReceiveFailed(void);
 
   protected:
     virtual bool HandleActiveSource(const cec_command &command);
index 40c0066ad3d400f0467a8ac956f32b43e5b17cc3..62e70d83e53bae1781012875f9e2075a9b161081 100644 (file)
@@ -37,7 +37,8 @@
 using namespace CEC;
 
 CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
-    CCECCommandHandler(busDevice)
+    CCECCommandHandler(busDevice),
+    m_bAwaitingReceiveFailed(false)
 {
 }
 
@@ -88,3 +89,21 @@ bool CSLCommandHandler::HandleCommand(const cec_command &command)
 
   return bHandled;
 }
+
+
+void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  CCECCommandHandler::HandlePoll(iInitiator, iDestination);
+  m_bAwaitingReceiveFailed = true;
+}
+
+bool CSLCommandHandler::HandleReceiveFailed(void)
+{
+  if (m_bAwaitingReceiveFailed)
+  {
+    m_bAwaitingReceiveFailed = false;
+    return false;
+  }
+
+  return true;
+}
index bc917dccf4976b81e3d8290ccd0e0c4b8cc18251..7566fb795d773fd13e8a78cb8352f723829d5bb6 100644 (file)
@@ -43,9 +43,13 @@ namespace CEC
     virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_LG; };
 
     virtual bool HandleCommand(const cec_command &command);
+    virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool HandleReceiveFailed(void);
 
   protected:
     virtual bool HandleGiveDeviceVendorId(const cec_command &command);
     virtual bool HandleVendorCommand(const cec_command &command);
+
+    bool m_bAwaitingReceiveFailed;
   };
 };
index 3a274fec12f35f88e9f1ec3e07b439a324fa3aa7..2e4560d56c683766bbdf876f6c360b51a2e180d8 100644 (file)
@@ -53,6 +53,7 @@ using namespace CEC;
 CSerialPort::CSerialPort()
 {
   m_fd = -1;
+  m_tostdout = false;
 }
 
 CSerialPort::~CSerialPort()
@@ -94,14 +95,14 @@ int8_t CSerialPort::Write(CCECAdapterMessage *data)
   }
 
   //print what's written to stdout for debugging
-//  if (m_tostdout)
-//  {
-//    printf("%s write:", m_name.c_str());
-//    for (int i = 0; i < byteswritten; i++)
-//      printf(" %02x", (unsigned int)data[i]);
-//
-//    printf("\n");
-//  }
+  if (m_tostdout)
+  {
+    printf("%s write:", m_name.c_str());
+    for (int i = 0; i < byteswritten; i++)
+      printf(" %02x", data->at(i));
+
+    printf("\n");
+  }
 
   return byteswritten;
 }
@@ -167,14 +168,14 @@ int32_t CSerialPort::Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs /*= 0
   }
 
   //print what's read to stdout for debugging
-//  if (m_tostdout && bytesread > 0)
-//  {
-//    printf("%s read:", m_name.c_str());
-//    for (int i = 0; i < bytesread; i++)
-//      printf(" %02x", (unsigned int)data[i]);
-//
-//    printf("\n");
-//  }
+  if (m_tostdout && bytesread > 0)
+  {
+    printf("%s read:", m_name.c_str());
+    for (int i = 0; i < bytesread; i++)
+      printf(" %02x", data[i]);
+
+    printf("\n");
+  }
 
   return bytesread;
 }
index 45c28506ee575498230adca2de0b234aac65fc24..f5035b908f21705a57bdee173b5e127784145198 100644 (file)
@@ -72,6 +72,7 @@ namespace CEC
       std::string     m_error;
       std::string     m_name;
       CMutex          m_mutex;
+      bool            m_tostdout;
 
   #ifdef __WINDOWS__
       bool SetTimeouts(bool bBlocking);