From: Lars Op den Kamp Date: Thu, 12 Jan 2012 22:41:36 +0000 (+0100) Subject: Merge branch 'master' into release X-Git-Tag: upstream/2.2.0~1^2~41 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=b034ac864ea18dd5df70a7176789e00be3b59589;hp=2b2767288398d6cdcbe1201a8b52ef515a5f6591;p=deb_libcec.git Merge branch 'master' into release --- diff --git a/ChangeLog b/ChangeLog index 7bd4547..fbf5d23 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,30 @@ -libcec (1.3-3) unstable; urgency=low +libcec (1.4-1) unstable; urgency=low + + * changed/added: + * added the vendor id for Sony + * always refresh the power state of a device when it hasn't been updated + for 30 seconds + * do silent builds by default + * interface changes: + * added optional callback methods to libCEC. enable them by calling + EnableCallbacks(ICECCallbacks *callbacks) / + cec_enable_callbacks(ICECCallbacks *callbacks). after this method is + called, the GetNext...() methods will not return any data + * added the same callbacks to LibCecSharp. implement CecCallbackMethods + and override the methods in there + * fixed: + * use the given timeout when trying to open a connection to the CEC + adapter + * resolved difference between method name in LibCECC.cpp and cecc.h. + credits: Doug Johnson + * don't transmit physical addresses while holding a lock in CCECProcessor + * don't hold a lock when sending an active source message. + * unload libCEC when the lib version is invalid + * "unused" warnings suppressed + + -- Pulse-Eight Packaging Thu, 12 Jan 2012 19:06:00 +0100 + + libcec (1.3-3) unstable; urgency=low * changed/added: * place in libudev include in an extern C block. fixes compilations on diff --git a/configure.ac b/configure.ac index 6c8c7fd..ebb68da 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,8 @@ -AC_INIT([libcec], 1:3:0) +AC_INIT([libcec], 1:4:0) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) +AM_SILENT_RULES([yes]) + AC_PROG_CXX AC_PROG_LIBTOOL @@ -30,7 +32,7 @@ libs_pre_dl=$LIBS AC_SUBST([LIBS_DL]) LIBS=$libs_pre_dl -CXXFLAGS="-fPIC -Wall -Wextra $CXXFLAGS" +CXXFLAGS="-fPIC -Wall -Wextra -Wno-missing-field-initializers $CXXFLAGS" AC_SUBST(REQUIRES) AC_CONFIG_FILES([src/lib/libcec.pc]) diff --git a/debian/changelog b/debian/changelog index 7bd4547..fbf5d23 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,30 @@ -libcec (1.3-3) unstable; urgency=low +libcec (1.4-1) unstable; urgency=low + + * changed/added: + * added the vendor id for Sony + * always refresh the power state of a device when it hasn't been updated + for 30 seconds + * do silent builds by default + * interface changes: + * added optional callback methods to libCEC. enable them by calling + EnableCallbacks(ICECCallbacks *callbacks) / + cec_enable_callbacks(ICECCallbacks *callbacks). after this method is + called, the GetNext...() methods will not return any data + * added the same callbacks to LibCecSharp. implement CecCallbackMethods + and override the methods in there + * fixed: + * use the given timeout when trying to open a connection to the CEC + adapter + * resolved difference between method name in LibCECC.cpp and cecc.h. + credits: Doug Johnson + * don't transmit physical addresses while holding a lock in CCECProcessor + * don't hold a lock when sending an active source message. + * unload libCEC when the lib version is invalid + * "unused" warnings suppressed + + -- Pulse-Eight Packaging Thu, 12 Jan 2012 19:06:00 +0100 + + libcec (1.3-3) unstable; urgency=low * changed/added: * place in libudev include in an extern C block. fixes compilations on diff --git a/debian/rules b/debian/rules index f9d1196..5205032 100755 --- a/debian/rules +++ b/debian/rules @@ -3,7 +3,7 @@ # Copyright Pulse-Eight 2011 # Uncomment this to turn on verbose mode. -export DH_VERBOSE=1 +#export DH_VERBOSE=1 DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) diff --git a/include/cec.h b/include/cec.h index 61e4bb3..9e09902 100644 --- a/include/cec.h +++ b/include/cec.h @@ -59,7 +59,15 @@ namespace CEC virtual void Close(void) = 0; /*! - * @brief Try to find all connected CEC adapters. Only implemented on Linux at the moment. + * @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used. + * @param cbParam Parameter to pass to callback methods. + * @param callbacks The callbacks to set. + * @return True when enabled, false otherwise. + */ + virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0; + + /*! + * @brief Try to find all connected CEC adapters. Only implemented on Linux and Windows at the moment. * @param deviceList The vector to store device descriptors in. * @param iBufSize The size of the deviceList buffer. * @param strDevicePath Optional device path. Only adds device descriptors that match the given device path. @@ -352,7 +360,6 @@ namespace CEC virtual const char *ToString(const cec_system_audio_status mode) = 0; virtual const char *ToString(const cec_audio_status status) = 0; virtual const char *ToString(const cec_vendor_id vendor) = 0; - }; }; diff --git a/include/cecc.h b/include/cecc.h index ddb141b..8c9bc93 100644 --- a/include/cecc.h +++ b/include/cecc.h @@ -59,6 +59,12 @@ extern DECLSPEC int cec_open(const char *strPort, uint32_t iTimeout); extern DECLSPEC void cec_close(void); +#ifdef __cplusplus +extern DECLSPEC int cec_enable_callbacks(void *cbParam, CEC::ICECCallbacks *callbacks); +#else +extern DECLSPEC int cec_enable_callbacks(void *cbParam, ICECCallbacks *callbacks); +#endif + #ifdef __cplusplus extern DECLSPEC int8_t cec_find_adapters(CEC::cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath); #else diff --git a/include/cectypes.h b/include/cectypes.h index f2b2f02..ba21200 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -37,6 +37,12 @@ #include #include +#if defined(_WIN32) || defined(_WIN64) +#define CEC_CDECL __cdecl +#else +#define CEC_CDECL +#endif + #if !defined(DECLSPEC) #if defined(_WIN32) || defined(_WIN64) #include @@ -64,6 +70,7 @@ namespace CEC { #define MSGESC 0xFD #define ESCOFFSET 3 #define CEC_BUTTON_TIMEOUT 500 +#define CEC_POWER_STATE_REFRESH_TIME 30000 #define CEC_DEFAULT_TRANSMIT_TIMEOUT 1000 #define CEC_DEFAULT_TRANSMIT_WAIT 2000 @@ -71,7 +78,7 @@ namespace CEC { #define CEC_MIN_LIB_VERSION 1 #define CEC_LIB_VERSION_MAJOR 1 -#define CEC_LIB_VERSION_MINOR 3 +#define CEC_LIB_VERSION_MINOR 4 typedef enum cec_abort_reason { @@ -599,13 +606,14 @@ typedef enum cec_bus_device_status typedef enum cec_vendor_id { - CEC_VENDOR_SAMSUNG = 0x00F0, - CEC_VENDOR_LG = 0xE091, - CEC_VENDOR_PANASONIC = 0x8045, - CEC_VENDOR_PIONEER = 0xE036, - CEC_VENDOR_ONKYO = 0x09B0, - CEC_VENDOR_YAMAHA = 0xA0DE, - CEC_VENDOR_PHILIPS = 0x903E, + CEC_VENDOR_SAMSUNG = 0x0000F0, + CEC_VENDOR_LG = 0x00E091, + CEC_VENDOR_PANASONIC = 0x008045, + CEC_VENDOR_PIONEER = 0x00E036, + CEC_VENDOR_ONKYO = 0x0009B0, + CEC_VENDOR_YAMAHA = 0x00A0DE, + CEC_VENDOR_PHILIPS = 0x00903E, + CEC_VENDOR_SONY = 0x080046, CEC_VENDOR_UNKNOWN = 0 } cec_vendor_id; @@ -864,6 +872,44 @@ typedef struct cec_logical_addresses #endif } cec_logical_addresses; + +typedef int (CEC_CDECL* CBCecLogMessageType)(void *param, const CEC::cec_log_message &); +typedef int (CEC_CDECL* CBCecKeyPressType)(void *param, const cec_keypress &key); +typedef int (CEC_CDECL* CBCecCommandType)(void *param, const cec_command &command); + +typedef struct ICECCallbacks +{ + /*! + * @brief Transfer a log message from libCEC to the client. + * @param message The message to transfer. + * @return 1 when ok, 0 otherwise. + */ + CBCecLogMessageType CBCecLogMessage; + + /*! + * @brief Transfer a keypress from libCEC to the client. + * @param key The keypress to transfer. + * @return 1 when ok, 0 otherwise. + */ + CBCecKeyPressType CBCecKeyPress; + + /*! + * @brief Transfer a CEC command from libCEC to the client. + * @param command The command to transfer. + * @return 1 when ok, 0 otherwise. + */ + CBCecCommandType CBCecCommand; +} ICECCallbacks; + +#ifdef UNUSED +#elif defined(__GNUC__) +#define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +#define UNUSED(x) /*@unused@*/ x +#else +#define UNUSED(x) x +#endif + #ifdef __cplusplus }; }; diff --git a/project/libcec.rc b/project/libcec.rc index e18b9a3..2b1e541 100644 Binary files a/project/libcec.rc and b/project/libcec.rc differ diff --git a/project/testclient.rc b/project/testclient.rc index 339801b..f80c470 100644 Binary files a/project/testclient.rc and b/project/testclient.rc differ diff --git a/src/CecSharpTester/AssemblyInfo.cs b/src/CecSharpTester/AssemblyInfo.cs index 73ffc39..d742067 100644 --- a/src/CecSharpTester/AssemblyInfo.cs +++ b/src/CecSharpTester/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Pulse-Eight Ltd.")] [assembly: AssemblyProduct("CecSharpClient")] -[assembly: AssemblyCopyright("Copyright (c) Pulse-Eight Ltd. 2012)] +[assembly: AssemblyCopyright("Copyright (c) Pulse-Eight Ltd. 2012)")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.3.2.0")] -[assembly: AssemblyFileVersion("1.3.2.0")] +[assembly: AssemblyVersion("1.4.0.0")] +[assembly: AssemblyFileVersion("1.4.0.0")] diff --git a/src/CecSharpTester/CecSharpClient.cs b/src/CecSharpTester/CecSharpClient.cs index 3d8ec32..342d7c0 100644 --- a/src/CecSharpTester/CecSharpClient.cs +++ b/src/CecSharpTester/CecSharpClient.cs @@ -37,7 +37,7 @@ using System.Text; namespace CecSharpClient { - class CecSharpClient + class CecSharpClient : CecCallbackMethods { public CecSharpClient() { @@ -50,6 +50,47 @@ namespace CecSharpClient Console.WriteLine("CEC Parser created - libcec version " + Lib.GetLibVersionMajor() + "." + Lib.GetLibVersionMinor()); } + public override int ReceiveCommand(CecCommand command) + { + return 1; + } + + public override int ReceiveKeypress(CecKeypress key) + { + return 1; + } + + public override int ReceiveLogMessage(CecLogMessage message) + { + if (((int)message.Level & LogLevel) == (int)message.Level) + { + string strLevel = ""; + switch (message.Level) + { + case CecLogLevel.Error: + strLevel = "ERROR: "; + break; + case CecLogLevel.Warning: + strLevel = "WARNING: "; + break; + case CecLogLevel.Notice: + strLevel = "NOTICE: "; + break; + case CecLogLevel.Traffic: + strLevel = "TRAFFIC: "; + break; + case CecLogLevel.Debug: + strLevel = "DEBUG: "; + break; + default: + break; + } + string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message); + Console.WriteLine(strLog); + } + return 1; + } + void FlushLog() { CecLogMessage message = Lib.GetNextLogMessage(); @@ -154,17 +195,15 @@ namespace CecSharpClient public void MainLoop() { - Lib.PowerOnDevices(CecLogicalAddress.Tv); - FlushLog(); + Lib.EnableCallbacks(this); + Lib.PowerOnDevices(CecLogicalAddress.Tv); Lib.SetActiveSource(CecDeviceType.PlaybackDevice); - FlushLog(); bool bContinue = true; string command; while (bContinue) { - FlushLog(); Console.WriteLine("waiting for input"); command = Console.ReadLine(); @@ -283,11 +322,9 @@ namespace CecSharpClient { Console.WriteLine("closing the connection"); Lib.Close(); - FlushLog(); Console.WriteLine("opening a new connection"); Connect(10000); - FlushLog(); Console.WriteLine("setting active source"); Lib.SetActiveSource(CecDeviceType.PlaybackDevice); @@ -346,7 +383,6 @@ namespace CecSharpClient { Console.WriteLine("Could not open a connection to the CEC adapter"); } - p.FlushLog(); } private int LogLevel; diff --git a/src/CecSharpTester/CecSharpClient.csproj b/src/CecSharpTester/CecSharpClient.csproj index eff98ef..9a7e65d 100644 --- a/src/CecSharpTester/CecSharpClient.csproj +++ b/src/CecSharpTester/CecSharpClient.csproj @@ -34,7 +34,7 @@ 4 - + False ..\..\LibCecSharp.dll diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp index 0624b82..c5dd8e2 100644 --- a/src/LibCecSharp/AssemblyInfo.cpp +++ b/src/LibCecSharp/AssemblyInfo.cpp @@ -31,7 +31,7 @@ using namespace System::Security::Permissions; // You can specify all the value or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly:AssemblyVersionAttribute("1.3.2.0")]; +[assembly:AssemblyVersionAttribute("1.4.0.0")]; [assembly:ComVisible(false)]; diff --git a/src/LibCecSharp/LibCecSharp.cpp b/src/LibCecSharp/LibCecSharp.cpp index 088c9ef..3aa1253 100644 --- a/src/LibCecSharp/LibCecSharp.cpp +++ b/src/LibCecSharp/LibCecSharp.cpp @@ -38,6 +38,7 @@ #using using namespace System; +using namespace System::Runtime::InteropServices; using namespace CEC; using namespace msclr::interop; @@ -494,25 +495,102 @@ public: property int64_t Time; }; +public ref class CecCallbackMethods +{ +public: + virtual int ReceiveLogMessage(CecLogMessage ^ message) + { + return 0; + } + + virtual int ReceiveKeypress(CecKeypress ^ key) + { + return 0; + } + + virtual int ReceiveCommand(CecCommand ^ command) + { + return 0; + } +}; + +#pragma unmanaged +// unmanaged callback methods +typedef int (__stdcall *LOGCB) (const cec_log_message &message); +typedef int (__stdcall *KEYCB) (const cec_keypress &key); +typedef int (__stdcall *COMMANDCB)(const cec_command &command); + +static LOGCB g_logCB; +static KEYCB g_keyCB; +static COMMANDCB g_commandCB; +static ICECCallbacks g_cecCallbacks; + +int CecLogMessageCB(void *cbParam, const cec_log_message &message) +{ + if (g_logCB) + return g_logCB(message); + return 0; +} + +int CecKeyPressCB(void *cbParam, const cec_keypress &key) +{ + if (g_keyCB) + return g_keyCB(key); + return 0; +} + +int CecCommandCB(void *cbParam, const cec_command &command) +{ + if (g_commandCB) + return g_commandCB(command); + return 0; +} + +#pragma managed +// delegates for the unmanaged callback methods +public delegate int CecLogMessageManagedDelegate(const cec_log_message &); +public delegate int CecKeyPressManagedDelegate(const cec_keypress &); +public delegate int CecCommandManagedDelegate(const cec_command &); + public ref class LibCecSharp { public: - LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes) - { - marshal_context ^ context = gcnew marshal_context(); + LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes) + { + marshal_context ^ context = gcnew marshal_context(); + m_bHasCallbacks = false; + const char* strDeviceNameC = context->marshal_as(strDeviceName); - const char* strDeviceNameC = context->marshal_as(strDeviceName); + cec_device_type_list types; + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + types.types[iPtr] = (cec_device_type)deviceTypes->Types[iPtr]; + m_libCec = (ICECAdapter *) CECInit(strDeviceNameC, types); + + // create the delegate method for the log message callback + m_logMessageDelegate = gcnew CecLogMessageManagedDelegate(this, &LibCecSharp::CecLogMessageManaged); + m_logMessageGCHandle = GCHandle::Alloc(m_logMessageDelegate); + g_logCB = static_cast(Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer()); + g_cecCallbacks.CBCecLogMessage = CecLogMessageCB; + + // create the delegate method for the keypress callback + m_keypressDelegate = gcnew CecKeyPressManagedDelegate(this, &LibCecSharp::CecKeyPressManaged); + m_keypressGCHandle = GCHandle::Alloc(m_keypressDelegate); + g_keyCB = static_cast(Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer()); + g_cecCallbacks.CBCecKeyPress = CecKeyPressCB; + + // create the delegate method for the command callback + m_commandDelegate = gcnew CecCommandManagedDelegate(this, &LibCecSharp::CecCommandManaged); + m_commandGCHandle = GCHandle::Alloc(m_commandDelegate); + g_commandCB = static_cast(Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer()); + g_cecCallbacks.CBCecCommand = CecCommandCB; - cec_device_type_list types; - for (unsigned int iPtr = 0; iPtr < 5; iPtr++) - types.types[iPtr] = (cec_device_type)deviceTypes->Types[iPtr]; - m_libCec = (ICECAdapter *) CECInit(strDeviceNameC, types); - delete context; - } + delete context; + } ~LibCecSharp(void) { CECDestroy(m_libCec); + DestroyDelegates(); m_libCec = NULL; } @@ -520,6 +598,7 @@ protected: !LibCecSharp(void) { CECDestroy(m_libCec); + DestroyDelegates(); m_libCec = NULL; } @@ -556,6 +635,18 @@ public: m_libCec->Close(); } + bool EnableCallbacks(CecCallbackMethods ^ callbacks) + { + if (m_libCec && !m_bHasCallbacks) + { + m_bHasCallbacks = true; + m_callbacks = callbacks; + return m_libCec->EnableCallbacks(NULL, &g_cecCallbacks); + } + + return false; + } + bool PingAdapter(void) { return m_libCec->PingAdapter(); @@ -858,5 +949,56 @@ public: } private: - ICECAdapter *m_libCec; + void DestroyDelegates() + { + m_logMessageGCHandle.Free(); + m_keypressGCHandle.Free(); + m_commandGCHandle.Free(); + } + + // managed callback methods + int CecLogMessageManaged(const cec_log_message &message) + { + int iReturn(0); + if (m_bHasCallbacks) + iReturn = m_callbacks->ReceiveLogMessage(gcnew CecLogMessage(gcnew String(message.message), (CecLogLevel)message.level, message.time)); + return iReturn; + } + + int CecKeyPressManaged(const cec_keypress &key) + { + int iReturn(0); + if (m_bHasCallbacks) + iReturn = m_callbacks->ReceiveKeypress(gcnew CecKeypress(key.keycode, key.duration)); + return iReturn; + } + + int CecCommandManaged(const cec_command &command) + { + int iReturn(0); + if (m_bHasCallbacks) + { + CecCommand ^ newCommand = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout); + for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) + newCommand->Parameters->PushBack(command.parameters[iPtr]); + iReturn = m_callbacks->ReceiveCommand(newCommand); + } + return iReturn; + } + + ICECAdapter * m_libCec; + CecCallbackMethods ^ m_callbacks; + bool m_bHasCallbacks; + + CecLogMessageManagedDelegate ^ m_logMessageDelegate; + static GCHandle m_logMessageGCHandle; + LOGCB m_logMessageCallback; + + CecKeyPressManagedDelegate ^ m_keypressDelegate; + static GCHandle m_keypressGCHandle; + KEYCB m_keypressCallback; + + CecCommandManagedDelegate ^ m_commandDelegate; + static GCHandle m_commandGCHandle; + COMMANDCB m_commandCallback; }; diff --git a/src/lib/AdapterCommunication.cpp b/src/lib/AdapterCommunication.cpp index 54077d6..8d351f0 100644 --- a/src/lib/AdapterCommunication.cpp +++ b/src/lib/AdapterCommunication.cpp @@ -265,7 +265,11 @@ CAdapterCommunication::~CAdapterCommunication(void) bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */) { + uint64_t iNow = GetTimeMs(); + uint64_t iTimeout = iNow + iTimeoutMs; + CLockObject lock(&m_mutex); + if (!m_port) { m_processor->AddLog(CEC_LOG_ERROR, "port is NULL"); @@ -275,12 +279,23 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38 if (IsOpen()) { m_processor->AddLog(CEC_LOG_ERROR, "port is already open"); + return true; } - if (!m_port->Open(strPort, iBaudRate)) + CStdString strError; + bool bConnected(false); + while (!bConnected && iNow < iTimeout) + { + if ((bConnected = m_port->Open(strPort, iBaudRate)) == false) + { + strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str()); + Sleep(250); + iNow = GetTimeMs(); + } + } + + if (!bConnected) { - CStdString strError; - strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str()); m_processor->AddLog(CEC_LOG_ERROR, strError); return false; } diff --git a/src/lib/AdapterDetection.cpp b/src/lib/AdapterDetection.cpp index de1da7c..f068099 100644 --- a/src/lib/AdapterDetection.cpp +++ b/src/lib/AdapterDetection.cpp @@ -324,5 +324,7 @@ uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSiz } #endif + iBufSize = 0; /* silence "unused" warning on linux/osx */ + return iFound; } diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 5071ec6..798c38a 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -527,12 +527,16 @@ bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, else if (iPhysicalAddress % 0x10 == 0) iPhysicalAddress += iPort; - SetPhysicalAddress(iPhysicalAddress); bReturn = true; } if (!bReturn) m_controller->AddLog(CEC_LOG_ERROR, "failed to set the physical address"); + else + { + lock.Leave(); + SetPhysicalAddress(iPhysicalAddress); + } return bReturn; } @@ -601,23 +605,38 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate /* = true */) { - bool bWasActiveSource(false); - CLockObject lock(&m_mutex); - if (!m_logicalAddresses.IsEmpty()) + bool bSendActiveView(false); + bool bReturn(false); + cec_logical_addresses sendUpdatesTo; + { - for (uint8_t iPtr = 0; iPtr < 15; iPtr++) - if (m_logicalAddresses[iPtr]) - { - bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource(); - m_busDevices[iPtr]->SetInactiveSource(); - m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress); - if (bSendUpdate) - m_busDevices[iPtr]->TransmitPhysicalAddress(); - } + CLockObject lock(&m_mutex); + if (!m_logicalAddresses.IsEmpty()) + { + bool bWasActiveSource(false); + for (uint8_t iPtr = 0; iPtr < 15; iPtr++) + if (m_logicalAddresses[iPtr]) + { + bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource(); + m_busDevices[iPtr]->SetInactiveSource(); + m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress); + if (bSendUpdate) + sendUpdatesTo.Set((cec_logical_address)iPtr); + } - return bWasActiveSource && bSendUpdate ? SetActiveView() : true; + bSendActiveView = bWasActiveSource && bSendUpdate; + bReturn = true; + } } - return false; + + for (uint8_t iPtr = 0; iPtr < 15; iPtr++) + if (sendUpdatesTo[iPtr]) + m_busDevices[iPtr]->TransmitPhysicalAddress(); + + if (bSendActiveView) + SetActiveView(); + + return bReturn; } bool CCECProcessor::SwitchMonitoring(bool bEnable) @@ -1397,7 +1416,7 @@ const char *CCECProcessor::ToString(const cec_system_audio_status mode) } } -const char *CCECProcessor::ToString(const cec_audio_status status) +const char *CCECProcessor::ToString(const cec_audio_status UNUSED(status)) { // TODO this is a mask return "TODO"; @@ -1421,6 +1440,8 @@ const char *CCECProcessor::ToString(const cec_vendor_id vendor) return "Yamaha"; case CEC_VENDOR_PHILIPS: return "Philips"; + case CEC_VENDOR_SONY: + return "Sony"; default: return "Unknown"; } diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 1366ff6..52dfa51 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -45,7 +45,9 @@ 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_buttontime(0), + m_callbacks(NULL), + m_cbParam(NULL) { m_cec = new CCECProcessor(this, strDeviceName, types); } @@ -53,7 +55,9 @@ CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list 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), - m_buttontime(0) + m_buttontime(0), + m_callbacks(NULL), + m_cbParam(NULL) { m_cec = new CCECProcessor(this, strDeviceName, iLogicalAddress, iPhysicalAddress); } @@ -87,6 +91,17 @@ void CLibCEC::Close(void) m_cec->StopThread(); } +bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) +{ + CLockObject lock(&m_mutex); + if (m_cec) + { + m_cbParam = cbParam; + m_callbacks = callbacks; + } + return false; +} + int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) { CStdString strDebug; @@ -328,32 +343,46 @@ cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress) void CLibCEC::AddLog(cec_log_level level, const string &strMessage) { + CLockObject lock(&m_mutex); if (m_cec) { cec_log_message message; message.level = level; message.time = GetTimeMs() - m_iStartTime; snprintf(message.message, sizeof(message.message), "%s", strMessage.c_str()); - m_logBuffer.Push(message); + + if (m_callbacks) + m_callbacks->CBCecLogMessage(m_cbParam, message); + else + m_logBuffer.Push(message); } } void CLibCEC::AddKey(cec_keypress &key) { - m_keyBuffer.Push(key); + CLockObject lock(&m_mutex); + if (m_callbacks) + m_callbacks->CBCecKeyPress(m_cbParam, key); + else + m_keyBuffer.Push(key); m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN; m_buttontime = 0; } void CLibCEC::AddKey(void) { + CLockObject lock(&m_mutex); if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN) { cec_keypress key; key.duration = (unsigned int) (GetTimeMs() - m_buttontime); key.keycode = m_iCurrentButton; - m_keyBuffer.Push(key); + + if (m_callbacks) + m_callbacks->CBCecKeyPress(m_cbParam, key); + else + m_keyBuffer.Push(key); m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN; } m_buttontime = 0; @@ -361,7 +390,12 @@ void CLibCEC::AddKey(void) void CLibCEC::AddCommand(const cec_command &command) { - if (m_commandBuffer.Push(command)) + CLockObject lock(&m_mutex); + if (m_callbacks) + { + m_callbacks->CBCecCommand(m_cbParam, command); + } + else if (m_commandBuffer.Push(command)) { CStdString strDebug; strDebug.Format("stored command '%2x' in the command buffer. buffer size = %d", command.opcode, m_commandBuffer.Size()); diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index 9c3e8f1..ef1ded2 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -53,6 +53,7 @@ namespace CEC virtual bool Open(const char *strPort, uint32_t iTimeout = 10000); virtual void Close(void); + virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks); virtual int8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL); virtual bool PingAdapter(void); virtual bool StartBootloader(void); @@ -126,5 +127,8 @@ namespace CEC CecBuffer m_logBuffer; CecBuffer m_keyBuffer; CecBuffer m_commandBuffer; + ICECCallbacks *m_callbacks; + void *m_cbParam; + CMutex m_mutex; }; }; diff --git a/src/lib/LibCECC.cpp b/src/lib/LibCECC.cpp index cbf7b28..91ab395 100644 --- a/src/lib/LibCECC.cpp +++ b/src/lib/LibCECC.cpp @@ -74,6 +74,13 @@ void cec_close(void) cec_parser->Close(); } +int cec_enable_callbacks(void *cbParam, ICECCallbacks *callbacks) +{ + if (cec_parser) + return cec_parser->EnableCallbacks(cbParam, callbacks) ? 1 : 0; + return -1; +} + int8_t cec_find_adapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) { if (cec_parser) @@ -95,7 +102,7 @@ int cec_start_bootloader(void) return -1; } -int8_t cec_get_min_version(void) +int8_t cec_get_min_lib_version(void) { if (cec_parser) return cec_parser->GetMinLibVersion(); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 9e9145c..d6e447f 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -54,6 +54,7 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi m_menuState(CEC_MENU_STATE_ACTIVATED), m_bActiveSource(false), m_iLastActive(0), + m_iLastPowerStateUpdate(0), m_cecVersion(CEC_VERSION_UNKNOWN), m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN), m_handlerMutex(false) @@ -314,7 +315,9 @@ cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */) CLockObject lock(&m_mutex); bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN || - m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)); + m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON || + m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY || + GetTimeMs() - m_iLastPowerStateUpdate >= CEC_POWER_STATE_REFRESH_TIME)); } if (bRequestUpdate) @@ -619,6 +622,7 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) CLockObject lock(&m_mutex); if (m_powerStatus != powerStatus) { + m_iLastPowerStateUpdate = GetTimeMs(); CStdString strLog; strLog.Format(">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus)); m_processor->AddLog(CEC_LOG_DEBUG, strLog); diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 6157e0a..2bef3a7 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -132,6 +132,7 @@ namespace CEC cec_menu_state m_menuState; bool m_bActiveSource; uint64_t m_iLastActive; + uint64_t m_iLastPowerStateUpdate; cec_version m_cecVersion; cec_bus_device_status m_deviceStatus; std::set m_unsupportedFeatures; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 40b4f07..bed4ff9 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -639,6 +639,11 @@ bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command) return true; } +bool CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command)) +{ + return true; +} + void CCECCommandHandler::UnhandledCommand(const cec_command &command) { CStdString strLog; diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index 0e3602d..71badde 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -122,7 +122,7 @@ namespace CEC virtual bool HandleTextViewOn(const cec_command &command); virtual bool HandleUserControlPressed(const cec_command &command); virtual bool HandleUserControlRelease(const cec_command &command); - virtual bool HandleVendorCommand(const cec_command &command) { return true; } + virtual bool HandleVendorCommand(const cec_command &command); virtual void UnhandledCommand(const cec_command &command); virtual unsigned int GetMyDevices(std::vector &devices) const; diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index 9a0bf3a..256a484 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -57,7 +57,19 @@ uint8_t g_iHDMIPort(CEC_DEFAULT_HDMI_PORT); cec_logical_address g_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE); cec_device_type_list g_typeList; bool g_bSingleCommand(false); +CMutex g_outputMutex; +ICECCallbacks g_callbacks; +inline void PrintToStdOut(const char *strOut) +{ + CLockObject lock(&g_outputMutex); + cout << strOut << endl; +} + +inline void PrintToStdOut(const CStdString &strOut) +{ + PrintToStdOut(strOut.c_str()); +} inline bool HexStrToInt(const std::string& data, uint8_t& value) { @@ -111,48 +123,64 @@ bool GetWord(string& data, string& word) return true; } -void FlushLog(ICECAdapter *cecParser) +int CecLogMessage(void *UNUSED(cbParam), const cec_log_message &message) { - cec_log_message message; - while (cecParser && cecParser->GetNextLogMessage(&message)) + if ((message.level & g_cecLogLevel) == message.level) { - if ((message.level & g_cecLogLevel) == message.level) + CStdString strLevel; + switch (message.level) { - CStdString strLevel; - switch (message.level) - { - case CEC_LOG_ERROR: - strLevel = "ERROR: "; - break; - case CEC_LOG_WARNING: - strLevel = "WARNING: "; - break; - case CEC_LOG_NOTICE: - strLevel = "NOTICE: "; - break; - case CEC_LOG_TRAFFIC: - strLevel = "TRAFFIC: "; - break; - case CEC_LOG_DEBUG: - strLevel = "DEBUG: "; - break; - default: - break; - } + case CEC_LOG_ERROR: + strLevel = "ERROR: "; + break; + case CEC_LOG_WARNING: + strLevel = "WARNING: "; + break; + case CEC_LOG_NOTICE: + strLevel = "NOTICE: "; + break; + case CEC_LOG_TRAFFIC: + strLevel = "TRAFFIC: "; + break; + case CEC_LOG_DEBUG: + strLevel = "DEBUG: "; + break; + default: + break; + } - CStdString strFullLog; - strFullLog.Format("%s[%16lld]\t%s", strLevel.c_str(), message.time, message.message); - cout << strFullLog.c_str() << endl; + CStdString strFullLog; + strFullLog.Format("%s[%16lld]\t%s", strLevel.c_str(), message.time, message.message); + PrintToStdOut(strFullLog); - if (g_logOutput.is_open()) - { - if (g_bShortLog) - g_logOutput << message.message << endl; - else - g_logOutput << strFullLog.c_str() << endl; - } + if (g_logOutput.is_open()) + { + if (g_bShortLog) + g_logOutput << message.message << endl; + else + g_logOutput << strFullLog.c_str() << endl; } } + + return 0; +} + +int CecKeyPress(void *UNUSED(cbParam), const cec_keypress &UNUSED(key)) +{ + return 0; +} + +int CecCommand(void *UNUSED(cbParam), const cec_command &UNUSED(command)) +{ + return 0; +} + +void EnableCallbacks(ICECAdapter *adapter) +{ + g_callbacks.CBCecLogMessage = &CecLogMessage; + g_callbacks.CBCecKeyPress = &CecKeyPress; + g_callbacks.CBCecCommand = &CecCommand; + adapter->EnableCallbacks(NULL, &g_callbacks); } void ListDevices(ICECAdapter *parser) @@ -161,24 +189,25 @@ void ListDevices(ICECAdapter *parser) uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL); if (iDevicesFound <= 0) { - cout << "Found devices: NONE" << endl; + PrintToStdOut("Found devices: NONE"); } else { CStdString strLog; strLog.Format("Found devices: %d", iDevicesFound); - cout << strLog.c_str() << endl; + PrintToStdOut(strLog); for (unsigned int iDevicePtr = 0; iDevicePtr < iDevicesFound; iDevicePtr++) { CStdString strDevice; strDevice.Format("device: %d\npath: %s\ncom port: %s", iDevicePtr + 1, devices[iDevicePtr].path, devices[iDevicePtr].comm); - cout << endl << strDevice.c_str() << endl; + PrintToStdOut(strDevice); } } } void ShowHelpCommandLine(const char* strExec) { + CLockObject lock(&g_outputMutex); cout << endl << strExec << " {-h|--help|-l|--list-devices|[COM PORT]}" << endl << endl << @@ -209,22 +238,23 @@ ICECAdapter *CreateParser(cec_device_type_list typeList) if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION) { #ifdef __WINDOWS__ - cout << "Cannot load libcec.dll" << endl; + PrintToStdOut("Cannot load libcec.dll"); #else - cout << "Cannot load libcec.so" << endl; + PrintToStdOut("Cannot load libcec.so"); #endif return NULL; } CStdString strLog; strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor()); - cout << strLog.c_str() << endl; + PrintToStdOut(strLog.c_str()); return parser; } void ShowHelpConsole(void) { + CLockObject lock(&g_outputMutex); cout << endl << "================================================================================" << endl << "Available commands:" << endl << @@ -299,7 +329,7 @@ bool ProcessCommandON(ICECAdapter *parser, const string &command, string &argume } else { - cout << "invalid destination" << endl; + PrintToStdOut("invalid destination"); } } @@ -319,7 +349,7 @@ bool ProcessCommandSTANDBY(ICECAdapter *parser, const string &command, string &a } else { - cout << "invalid destination" << endl; + PrintToStdOut("invalid destination"); } } @@ -335,14 +365,14 @@ bool ProcessCommandPOLL(ICECAdapter *parser, const string &command, string &argu if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF) { if (parser->PollDevice((cec_logical_address) iValue)) - cout << "POLL message sent" << endl; + PrintToStdOut("POLL message sent"); else - cout << "POLL message not sent" << endl; + PrintToStdOut("POLL message not sent"); return true; } else { - cout << "invalid destination" << endl; + PrintToStdOut("invalid destination"); } } @@ -423,7 +453,7 @@ bool ProcessCommandOSD(ICECAdapter *parser, const string &command, string &argum return false; } -bool ProcessCommandAS(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandAS(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "as") { @@ -435,7 +465,7 @@ bool ProcessCommandAS(ICECAdapter *parser, const string &command, string &argume } -bool ProcessCommandPING(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandPING(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "ping") { @@ -446,39 +476,39 @@ bool ProcessCommandPING(ICECAdapter *parser, const string &command, string &argu return false; } -bool ProcessCommandVOLUP(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandVOLUP(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "volup") { CStdString strLog; strLog.Format("volume up: %2X", parser->VolumeUp()); - cout << strLog.c_str() << endl; + PrintToStdOut(strLog); return true; } return false; } -bool ProcessCommandVOLDOWN(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandVOLDOWN(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "voldown") { CStdString strLog; - strLog.Format("volume up: %2X", parser->VolumeDown()); - cout << strLog.c_str() << endl; + strLog.Format("volume down: %2X", parser->VolumeDown()); + PrintToStdOut(strLog); return true; } return false; } -bool ProcessCommandMUTE(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandMUTE(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "mute") { CStdString strLog; strLog.Format("mute: %2X", parser->MuteAudio()); - cout << strLog.c_str() << endl; + PrintToStdOut(strLog); return true; } @@ -500,7 +530,7 @@ bool ProcessCommandMON(ICECAdapter *parser, const string &command, string &argum return false; } -bool ProcessCommandBL(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandBL(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "bl") { @@ -527,7 +557,7 @@ bool ProcessCommandLANG(ICECAdapter *parser, const string &command, string &argu strLog.Format("menu language '%s'", language.language); else strLog = "failed!"; - cout << strLog.c_str() << endl; + PrintToStdOut(strLog); return true; } } @@ -549,7 +579,7 @@ bool ProcessCommandVEN(ICECAdapter *parser, const string &command, string &argum uint64_t iVendor = parser->GetDeviceVendorId((cec_logical_address) iDev); CStdString strLog; strLog.Format("vendor id: %06x", iVendor); - cout << strLog.c_str() << endl; + PrintToStdOut(strLog); return true; } } @@ -569,7 +599,9 @@ bool ProcessCommandVER(ICECAdapter *parser, const string &command, string &argum if (iDev >= 0 && iDev < 15) { cec_version iVersion = parser->GetDeviceCecVersion((cec_logical_address) iDev); - cout << "CEC version " << parser->ToString(iVersion) << endl; + CStdString strLog; + strLog.Format("CEC version %s", parser->ToString(iVersion)); + PrintToStdOut(strLog); return true; } } @@ -589,8 +621,9 @@ bool ProcessCommandPOW(ICECAdapter *parser, const string &command, string &argum if (iDev >= 0 && iDev < 15) { cec_power_status iPower = parser->GetDevicePowerStatus((cec_logical_address) iDev); - cout << "power status: " << parser->ToString(iPower) << endl; - + CStdString strLog; + strLog.Format("power status: %s", parser->ToString(iPower)); + PrintToStdOut(strLog); return true; } } @@ -610,7 +643,9 @@ bool ProcessCommandNAME(ICECAdapter *parser, const string &command, string &argu if (iDev >= 0 && iDev < 15) { cec_osd_name name = parser->GetDeviceOSDName((cec_logical_address)iDev); - cout << "OSD name of device " << iDev << " is '" << name.name << "'" << endl; + CStdString strLog; + strLog.Format("OSD name of device %d is '%s'", iDev, name.name); + PrintToStdOut(strLog); } return true; } @@ -619,15 +654,19 @@ bool ProcessCommandNAME(ICECAdapter *parser, const string &command, string &argu return false; } -bool ProcessCommandLAD(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandLAD(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "lad") { - cout << "listing active devices:" << endl; + CStdString strLog; + PrintToStdOut("listing active devices:"); cec_logical_addresses addresses = parser->GetActiveDevices(); for (uint8_t iPtr = 0; iPtr <= 11; iPtr++) if (addresses[iPtr]) - cout << "logical address " << (int)iPtr << endl; + { + strLog.Format("logical address %X", (int)iPtr); + PrintToStdOut(strLog); + } return true; } @@ -643,7 +682,11 @@ bool ProcessCommandAD(ICECAdapter *parser, const string &command, string &argume { int iDev = atoi(strDev); if (iDev >= 0 && iDev < 15) - cout << "logical address " << iDev << " is " << (parser->IsActiveDevice((cec_logical_address)iDev) ? "active" : "not active") << endl; + { + CStdString strLog; + strLog.Format("logical address %X is %s", iDev, (parser->IsActiveDevice((cec_logical_address)iDev) ? "active" : "not active")); + PrintToStdOut(strLog); + } } } @@ -666,7 +709,9 @@ bool ProcessCommandAT(ICECAdapter *parser, const string &command, string &argume type = CEC_DEVICE_TYPE_RECORDING_DEVICE; else if (strType.Equals("t")) type = CEC_DEVICE_TYPE_TUNER; - cout << "device " << type << " is " << (parser->IsActiveDeviceType(type) ? "active" : "not active") << endl; + CStdString strLog; + strLog.Format("device %d is %s", type, (parser->IsActiveDeviceType(type) ? "active" : "not active")); + PrintToStdOut(strLog); return true; } } @@ -674,19 +719,17 @@ bool ProcessCommandAT(ICECAdapter *parser, const string &command, string &argume return false; } -bool ProcessCommandR(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandR(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "r") { - cout << "closing the connection" << endl; + PrintToStdOut("closing the connection"); parser->Close(); - FlushLog(parser); - cout << "opening a new connection" << endl; + PrintToStdOut("opening a new connection"); parser->Open(g_strPort.c_str()); - FlushLog(parser); - cout << "setting active source" << endl; + PrintToStdOut("setting active source"); parser->SetActiveSource(); return true; } @@ -694,7 +737,7 @@ bool ProcessCommandR(ICECAdapter *parser, const string &command, string &argumen return false; } -bool ProcessCommandH(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandH(ICECAdapter * UNUSED(parser), const string &command, string & UNUSED(arguments)) { if (command == "h" || command == "help") { @@ -705,7 +748,7 @@ bool ProcessCommandH(ICECAdapter *parser, const string &command, string &argumen return false; } -bool ProcessCommandLOG(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandLOG(ICECAdapter * UNUSED(parser), const string &command, string &arguments) { if (command == "log") { @@ -716,7 +759,9 @@ bool ProcessCommandLOG(ICECAdapter *parser, const string &command, string &argum if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL) { g_cecLogLevel = iNewLevel; - cout << "log level changed to " << strLevel.c_str() << endl; + CStdString strLog; + strLog.Format("log level changed to %s", strLevel.c_str()); + PrintToStdOut(strLog); return true; } } @@ -725,17 +770,18 @@ bool ProcessCommandLOG(ICECAdapter *parser, const string &command, string &argum return false; } -bool ProcessCommandSCAN(ICECAdapter *parser, const string &command, string &arguments) +bool ProcessCommandSCAN(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { if (command == "scan") { - cout << "CEC bus information" << endl; - cout << "===================" << endl; + PrintToStdOut("CEC bus information"); + PrintToStdOut("==================="); cec_logical_addresses addresses = parser->GetActiveDevices(); for (uint8_t iPtr = 0; iPtr < 16; iPtr++) { if (addresses[iPtr]) { + CStdString strLog; uint64_t iVendorId = parser->GetDeviceVendorId((cec_logical_address)iPtr); bool bActive = parser->IsActiveSource((cec_logical_address)iPtr); uint16_t iPhysicalAddress = parser->GetDevicePhysicalAddress((cec_logical_address)iPtr); @@ -748,16 +794,17 @@ bool ProcessCommandSCAN(ICECAdapter *parser, const string &command, string &argu lang.device = CECDEVICE_UNKNOWN; parser->GetDeviceMenuLanguage((cec_logical_address)iPtr, &lang); - cout << "device #" << (int)iPtr << ": " << parser->ToString((cec_logical_address)iPtr) << endl; - cout << "address: " << strAddr.c_str() << endl; - cout << "active source: " << (bActive ? "yes" : "no") << endl; - cout << "vendor: " << parser->ToString((cec_vendor_id)iVendorId) << endl; - cout << "osd string: " << osdName.name << endl; - cout << "CEC version: " << parser->ToString(iCecVersion) << endl; - cout << "power status: " << parser->ToString(power) << endl; + strLog.AppendFormat("device #%X: %s\n", (int)iPtr, parser->ToString((cec_logical_address)iPtr)); + strLog.AppendFormat("address: %s\n", strAddr.c_str()); + strLog.AppendFormat("active source: %s\n", (bActive ? "yes" : "no")); + strLog.AppendFormat("vendor: %s\n", parser->ToString((cec_vendor_id)iVendorId)); + strLog.AppendFormat("osd string: %s\n", osdName.name); + strLog.AppendFormat("CEC version: %s\n", parser->ToString(iCecVersion)); + strLog.AppendFormat("power status: %s\n", parser->ToString(power)); if ((uint8_t)lang.device == iPtr) - cout << "language: " << lang.language << endl; - cout << endl; + strLog.AppendFormat("language: %s\n", lang.language); + strLog.append("\n"); + PrintToStdOut(strLog); } } return true; @@ -972,6 +1019,10 @@ int main (int argc, char *argv[]) #else cout << "Cannot load libcec.so" << endl; #endif + + if (parser) + UnloadLibCec(parser); + return 1; } @@ -1014,40 +1065,33 @@ int main (int argc, char *argv[]) } } + EnableCallbacks(parser); + parser->SetHDMIPort(g_iBaseDevice, g_iHDMIPort); - cout << "opening a connection to the CEC adapter..." << endl; + PrintToStdOut("opening a connection to the CEC adapter..."); if (!parser->Open(g_strPort.c_str())) { - cout << "unable to open the device on port " << g_strPort << endl; - FlushLog(parser); + CStdString strLog; + strLog.Format("unable to open the device on port %s"); + PrintToStdOut(strLog); UnloadLibCec(parser); return 1; } if (!g_bSingleCommand) { - FlushLog(parser); - cout << "cec device opened" << endl; + PrintToStdOut("cec device opened"); parser->PowerOnDevices(CECDEVICE_TV); - FlushLog(parser); - parser->SetActiveSource(); - FlushLog(parser); - cout << "waiting for input" << endl; + PrintToStdOut("waiting for input"); } bool bContinue(true); while (bContinue) { - FlushLog(parser); - - /* just ignore the command buffer and clear it */ - cec_command dummy; - while (parser && parser->GetNextCommand(&dummy)) {} - string input; getline(cin, input); cin.clear(); @@ -1055,7 +1099,7 @@ int main (int argc, char *argv[]) if (ProcessConsoleCommand(parser, input) && !g_bSingleCommand) { if (!input.empty()) - cout << "waiting for input" << endl; + PrintToStdOut("waiting for input"); } else bContinue = false; @@ -1068,7 +1112,6 @@ int main (int argc, char *argv[]) parser->StandbyDevices(CECDEVICE_BROADCAST); parser->Close(); - FlushLog(parser); UnloadLibCec(parser); if (g_logOutput.is_open())