From a2198e5e7bf23df91c2cfe2acc5a75521395d531 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Mon, 27 Feb 2012 23:03:33 +0100 Subject: [PATCH] cec: added a command to the interface to start the bootloader directly, without going through all checks. bugzid: 218 --- include/cec.h | 6 ++ include/cecloader.h | 65 +++++++++++++++++++ src/lib/CECProcessor.cpp | 26 +++++++- src/lib/CECProcessor.h | 2 +- src/lib/LibCEC.cpp | 24 +++++++ src/lib/LibCEC.h | 2 +- src/lib/adapter/AdapterCommunication.h | 3 +- .../adapter/USBCECAdapterCommunication.cpp | 18 +++-- src/lib/adapter/USBCECAdapterCommunication.h | 2 +- src/testclient/main.cpp | 5 ++ support/cec-flash-device.sh | 2 +- 11 files changed, 141 insertions(+), 14 deletions(-) diff --git a/include/cec.h b/include/cec.h index 4a6ad98..0332088 100644 --- a/include/cec.h +++ b/include/cec.h @@ -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. */ diff --git a/include/cecloader.h b/include/cecloader.h index 624f29a..1b0be87 100644 --- a/include/cecloader.h +++ b/include/cecloader.h @@ -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 @@ -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_ */ diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index cf7b5b4..e0f8c3f 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -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) diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 61ea686..08bf8d0 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -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); diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 4f7fea2..ef4c84c 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -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); diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index e2e8153..9241a2c 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -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 m_logBuffer; PLATFORM::SyncedBuffer m_keyBuffer; PLATFORM::SyncedBuffer m_commandBuffer; diff --git a/src/lib/adapter/AdapterCommunication.h b/src/lib/adapter/AdapterCommunication.h index 38d0a13..d78b11d 100644 --- a/src/lib/adapter/AdapterCommunication.h +++ b/src/lib/adapter/AdapterCommunication.h @@ -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 diff --git a/src/lib/adapter/USBCECAdapterCommunication.cpp b/src/lib/adapter/USBCECAdapterCommunication.cpp index 0f73bae..5400325 100644 --- a/src/lib/adapter/USBCECAdapterCommunication.cpp +++ b/src/lib/adapter/USBCECAdapterCommunication.cpp @@ -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 { diff --git a/src/lib/adapter/USBCECAdapterCommunication.h b/src/lib/adapter/USBCECAdapterCommunication.h index 513900d..c71453a 100644 --- a/src/lib/adapter/USBCECAdapterCommunication.h +++ b/src/lib/adapter/USBCECAdapterCommunication.h @@ -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; diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index 69309bc..2b2c54d 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -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")) { diff --git a/support/cec-flash-device.sh b/support/cec-flash-device.sh index 93ee576..10715cb 100755 --- a/support/cec-flash-device.sh +++ b/support/cec-flash-device.sh @@ -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 -- 2.34.1