cec: added a command to the interface to start the bootloader directly, without going...
authorLars Op den Kamp <lars@opdenkamp.eu>
Mon, 27 Feb 2012 22:03:33 +0000 (23:03 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Mon, 27 Feb 2012 22:14:50 +0000 (23:14 +0100)
include/cec.h
include/cecloader.h
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/adapter/AdapterCommunication.h
src/lib/adapter/USBCECAdapterCommunication.cpp
src/lib/adapter/USBCECAdapterCommunication.h
src/testclient/main.cpp
support/cec-flash-device.sh

index 4a6ad989e7ef84042c2d47928cffda86e1b77124..0332088906e72a0a5c254ec42b023251aa02e00e 100644 (file)
@@ -443,6 +443,12 @@ extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_ty
  */
 extern "C" DECLSPEC void * CECInitialise(CEC::libcec_configuration *configuration);
 
+/*!
+ * @brief Try to connect to the adapter and send the "start bootloader" command, without initialising libCEC and going through all checks
+ * @return True when the command was send, false otherwise.
+ */
+extern "C" DECLSPEC bool CECStartBootloader(void);
+
 /*!
  * @brief Unload the CEC adapter library.
  */
index 624f29a5c7a54961ab53f0565e95945138fbb65c..1b0be87cad7e9995538c83f1c984bfca2e97f6f1 100644 (file)
@@ -111,6 +111,33 @@ void UnloadLibCec(CEC::ICECAdapter *device)
   g_libCEC = NULL;
 }
 
+/*!
+ * @brief Start the bootloader on the first device that was detected.
+ * @param strLib The name of and/or path to libCEC
+ * @return True when the command was sent, false otherwise.
+ */
+bool LibCecBootloader(const char *strLib = NULL)
+{
+  if (!g_libCEC)
+#if defined(_WIN64)
+    g_libCEC = LoadLibrary(strLib ? strLib : "libcec.x64.dll");
+#else
+    g_libCEC = LoadLibrary(strLib ? strLib : "libcec.dll");
+#endif
+  if (!g_libCEC)
+    return NULL;
+
+  typedef bool (__cdecl*_LibCecBootloader)(void);
+  _LibCecBootloader LibCecBootloader;
+  LibCecBootloader = (_LibCecBootloader) (GetProcAddress(g_libCEC, "CECStartBootloader"));
+  if (!LibCecBootloader)
+    return false;
+
+  bool bReturn = LibCecBootloader();
+  UnloadLibCec(static_cast< CEC::ICECAdapter* > g_libCEC);
+  return bReturn;
+}
+
 #else
 
 #include <dlfcn.h>
@@ -206,6 +233,44 @@ void UnloadLibCec(CEC::ICECAdapter *device)
   dlclose(g_libCEC);
 }
 
+/*!
+ * @brief Start the bootloader on the first device that was detected.
+ * @param strLib The name of and/or path to libCEC
+ * @return True when the command was sent, false otherwise.
+ */
+bool LibCecBootloader(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 bool _LibCecBootloader(void);
+  _LibCecBootloader* LibCecBootloader = (_LibCecBootloader*) dlsym(g_libCEC, "CECStartBootloader");
+  if (!LibCecBootloader)
+  {
+    cout << "cannot find CECStartBootloader" << endl;
+    return NULL;
+  }
+
+  bool bReturn = LibCecBootloader();
+  UnloadLibCec((CEC::ICECAdapter*)g_libCEC);
+  return bReturn;
+}
+
 #endif
 
 #endif /* CECLOADER_H_ */
index cf7b5b4ec62f0d046483464d8528c09bdf55b9e3..e0f8c3ffd01f6f0a21aae476c196dc6f368f36ad 100644 (file)
@@ -1439,9 +1439,31 @@ void CCECBusScan::WaitUntilIdle(void)
   }
 }
 
-bool CCECProcessor::StartBootloader(void)
+bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
 {
-  return m_communication->StartBootloader();
+  if (!m_communication && strPort)
+  {
+    bool bReturn(false);
+    IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort);
+    CTimeout timeout(10000);
+    int iConnectTry(0);
+    while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(NULL, (timeout.TimeLeft() / CEC_CONNECT_TRIES)), true) == false)
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+      comm->Close();
+      Sleep(500);
+    }
+    if (comm->IsOpen())
+    {
+      bReturn = comm->StartBootloader();
+      delete comm;
+    }
+    return bReturn;
+  }
+  else
+  {
+    return m_communication->StartBootloader();
+  }
 }
 
 bool CCECProcessor::PingAdapter(void)
index 61ea68691e36f56ceea33dca4e98ff925b030b13..08bf8d00bf441fbfada9b51191b3cbc939d241fe 100644 (file)
@@ -137,7 +137,7 @@ namespace CEC
       virtual bool FindLogicalAddresses(void);
       virtual bool SetAckMask(uint16_t iMask);
 
-      virtual bool StartBootloader(void);
+      virtual bool StartBootloader(const char *strPort = NULL);
       virtual bool PingAdapter(void);
       virtual void HandlePoll(cec_logical_address initiator, cec_logical_address destination);
       virtual bool HandleReceiveFailed(cec_logical_address initiator);
index 4f7fea203372b9768cd47a67080ee38500b854fd..ef4c84cd024d0960400eee0c5cfce524d082677e 100644 (file)
@@ -352,6 +352,8 @@ void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
   va_end(argList);
 
   CLibCEC *instance = CLibCEC::GetInstance();
+  if (!instance)
+    return;
   CLockObject lock(instance->m_mutex);
 
   cec_log_message message;
@@ -368,6 +370,8 @@ void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
 void CLibCEC::AddKey(const cec_keypress &key)
 {
   CLibCEC *instance = CLibCEC::GetInstance();
+  if (!instance)
+    return;
   CLockObject lock(instance->m_mutex);
 
   AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
@@ -407,6 +411,8 @@ void CLibCEC::SetCurrentButton(cec_user_control_code iButtonCode)
 void CLibCEC::AddKey(void)
 {
   CLibCEC *instance = CLibCEC::GetInstance();
+  if (!instance)
+    return;
   CLockObject lock(instance->m_mutex);
 
   if (instance->m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
@@ -429,6 +435,8 @@ void CLibCEC::AddKey(void)
 void CLibCEC::AddCommand(const cec_command &command)
 {
   CLibCEC *instance = CLibCEC::GetInstance();
+  if (!instance)
+    return;
   CLockObject lock(instance->m_mutex);
 
   AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", instance->m_cec->ToString(command.initiator), command.initiator, instance->m_cec->ToString(command.destination), command.destination, instance->m_cec->ToString(command.opcode), command.opcode);
@@ -494,6 +502,22 @@ void * CECInitialise(libcec_configuration *configuration)
   return static_cast< void* > (lib);
 }
 
+bool CECStartBootloader(void)
+{
+  libcec_configuration dummy;
+  dummy.Clear();
+  CLibCEC *lib = new CLibCEC(&dummy);
+
+  bool bReturn(false);
+  cec_adapter deviceList[1];
+  if (CUSBCECAdapterDetection::FindAdapters(deviceList, 1) > 0)
+  {
+    bReturn = lib->m_cec->StartBootloader(deviceList[0].comm);
+    delete lib;
+  }
+  return bReturn;
+}
+
 void CECDestroy(CEC::ICECAdapter *UNUSED(instance))
 {
   CLibCEC::SetInstance(NULL);
index e2e815392d1bef72bd31b5ef4998b3cc35a1a722..9241a2c3f8336ce602ee353367f4ca7f52eeb4e7 100644 (file)
@@ -134,11 +134,11 @@ namespace CEC
       static CLibCEC *GetInstance(void);
       static void SetInstance(CLibCEC *instance);
 
+      CCECProcessor *                         m_cec;
     protected:
       int64_t                                 m_iStartTime;
       cec_user_control_code                   m_iCurrentButton;
       int64_t                                 m_buttontime;
-      CCECProcessor *                         m_cec;
       PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer;
       PLATFORM::SyncedBuffer<cec_keypress>    m_keyBuffer;
       PLATFORM::SyncedBuffer<cec_command>     m_commandBuffer;
index 38d0a13b0369bf40d6726029ef195d21bceb24a6..d78b11d0164d37e4cf66f1c13b353aa2bc62717b 100644 (file)
@@ -70,9 +70,10 @@ namespace CEC
      * @brief Open a connection to the CEC adapter
      * @param cb The callback struct. if set to NULL, the Read() method has to be used to read commands. if set, OnCommandReceived() will be called for each command that was received
      * @param iTimeoutMs Connection timeout in ms
+     * @param bSkipChecks Skips all initial checks of the adapter, and starts the reader/writer threads directly after connecting.
      * @return True when connected, false otherwise
      */
-    virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000) = 0;
+    virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000, bool bSkipChecks = false) = 0;
 
     /*!
      * @brief Close an open connection
index 0f73bae0f958139e0a52a9535bae6f92d330ff6a..5400325bb215ff2bf7a41c2e7245df5acaf0541f 100644 (file)
@@ -128,7 +128,7 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */
   return bReturn;
 }
 
-bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */, bool bSkipChecks /* = false */)
 {
   uint64_t iNow = GetTimeMs();
   uint64_t iTimeout = iNow + iTimeoutMs;
@@ -169,21 +169,25 @@ bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32
 
     CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
 
-    //clear any input bytes
-    uint8_t buff[1024];
-    while (m_port->Read(buff, 1024, 100) > 0)
+    if (!bSkipChecks)
     {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
-      Sleep(250);
+      //clear any input bytes
+      uint8_t buff[1024];
+      while (m_port->Read(buff, 1024, 100) > 0)
+      {
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
+        Sleep(250);
+      }
     }
   }
 
   if (CreateThread())
   {
-    if (!CheckAdapter())
+    if (!bSkipChecks && !CheckAdapter())
     {
       StopThread();
       CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+      return false;
     }
     else
     {
index 513900d5be28d8584d3e7431002913c2d6ec977b..c71453a4a4f0cf20a3827f0a4714a8d091e1160c 100644 (file)
@@ -69,7 +69,7 @@ namespace CEC
     CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
     virtual ~CUSBCECAdapterCommunication();
 
-    virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000);
+    virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000, bool bSkipChecks = false);
     virtual void Close(void);
     virtual bool IsOpen(void);
     virtual CStdString GetError(void) const;
index 69309bc7dfc078592691e4b99acb035dcca1097a..2b2c54dc772fc4e99b12d9cf4244efa3ea7986fc 100644 (file)
@@ -975,6 +975,11 @@ bool ProcessCommandLineArguments(int argc, char *argv[])
         }
         bReturn = false;
       }
+      else if (!strcmp(argv[iArgPtr], "--bootloader"))
+      {
+        LibCecBootloader();
+        bReturn = false;
+      }
       else if (!strcmp(argv[iArgPtr], "--single-command") ||
           !strcmp(argv[iArgPtr], "-s"))
       {
index 93ee576e94b7d24384304267ec9cb608bb966beb..10715cb93c0b36213f861d55edaf07a912daa695 100755 (executable)
@@ -26,7 +26,7 @@ _enter_bootloader()
   echo "Instructing the CEC adapter to enter bootloader mode"
   cec_adapter=`lsusb  | grep "2548:1001" | wc -l`
   if [ $cec_adapter -gt 0 ]; then
-    echo "bl" | cec-client -s -d 2
+    echo "bl" | cec-client --bootloader
     echo "Waiting for the device to reinitialise"
     sleep 5
   fi