-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 <packaging@pulse-eight.com> 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
-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
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])
-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 <packaging@pulse-eight.com> 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
# 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))
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.
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;
-
};
};
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
#include <stdint.h>
#include <string.h>
+#if defined(_WIN32) || defined(_WIN64)
+#define CEC_CDECL __cdecl
+#else
+#define CEC_CDECL
+#endif
+
#if !defined(DECLSPEC)
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#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
#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
{
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;
#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
};
};
[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("")]
// 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")]
namespace CecSharpClient
{
- class CecSharpClient
+ class CecSharpClient : CecCallbackMethods
{
public 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();
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();
{
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);
{
Console.WriteLine("Could not open a connection to the CEC adapter");
}
- p.FlushLog();
}
private int LogLevel;
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
- <Reference Include="LibCecSharp, Version=1.0.4334.36379, Culture=neutral, processorArchitecture=x86">
+ <Reference Include="LibCecSharp, Version=1.3.2.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\LibCecSharp.dll</HintPath>
</Reference>
// 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)];
#using <System.dll>
using namespace System;
+using namespace System::Runtime::InteropServices;
using namespace CEC;
using namespace msclr::interop;
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<const char*>(strDeviceName);
- const char* strDeviceNameC = context->marshal_as<const char*>(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<LOGCB>(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<KEYCB>(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<COMMANDCB>(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;
}
!LibCecSharp(void)
{
CECDestroy(m_libCec);
+ DestroyDelegates();
m_libCec = NULL;
}
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();
}
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;
};
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");
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;
}
}
#endif
+ iBufSize = 0; /* silence "unused" warning on linux/osx */
+
return iFound;
}
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;
}
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)
}
}
-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";
return "Yamaha";
case CEC_VENDOR_PHILIPS:
return "Philips";
+ case CEC_VENDOR_SONY:
+ return "Sony";
default:
return "Unknown";
}
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);
}
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);
}
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;
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;
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());
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);
CecBuffer<cec_log_message> m_logBuffer;
CecBuffer<cec_keypress> m_keyBuffer;
CecBuffer<cec_command> m_commandBuffer;
+ ICECCallbacks *m_callbacks;
+ void *m_cbParam;
+ CMutex m_mutex;
};
};
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)
return -1;
}
-int8_t cec_get_min_version(void)
+int8_t cec_get_min_lib_version(void)
{
if (cec_parser)
return cec_parser->GetMinLibVersion();
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)
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)
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);
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<cec_opcode> m_unsupportedFeatures;
return true;
}
+bool CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command))
+{
+ return true;
+}
+
void CCECCommandHandler::UnhandledCommand(const cec_command &command)
{
CStdString strLog;
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<CCECBusDevice *> &devices) const;
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)
{
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)
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 <<
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 <<
}
else
{
- cout << "invalid destination" << endl;
+ PrintToStdOut("invalid destination");
}
}
}
else
{
- cout << "invalid destination" << endl;
+ PrintToStdOut("invalid destination");
}
}
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");
}
}
return false;
}
-bool ProcessCommandAS(ICECAdapter *parser, const string &command, string &arguments)
+bool ProcessCommandAS(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
{
if (command == "as")
{
}
-bool ProcessCommandPING(ICECAdapter *parser, const string &command, string &arguments)
+bool ProcessCommandPING(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
{
if (command == "ping")
{
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;
}
return false;
}
-bool ProcessCommandBL(ICECAdapter *parser, const string &command, string &arguments)
+bool ProcessCommandBL(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
{
if (command == "bl")
{
strLog.Format("menu language '%s'", language.language);
else
strLog = "failed!";
- cout << strLog.c_str() << endl;
+ PrintToStdOut(strLog);
return true;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
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;
}
{
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);
+ }
}
}
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;
}
}
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;
}
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")
{
return false;
}
-bool ProcessCommandLOG(ICECAdapter *parser, const string &command, string &arguments)
+bool ProcessCommandLOG(ICECAdapter * UNUSED(parser), const string &command, string &arguments)
{
if (command == "log")
{
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;
}
}
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);
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;
#else
cout << "Cannot load libcec.so" << endl;
#endif
+
+ if (parser)
+ UnloadLibCec(parser);
+
return 1;
}
}
}
+ 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();
if (ProcessConsoleCommand(parser, input) && !g_bSingleCommand)
{
if (!input.empty())
- cout << "waiting for input" << endl;
+ PrintToStdOut("waiting for input");
}
else
bContinue = false;
parser->StandbyDevices(CECDEVICE_BROADCAST);
parser->Close();
- FlushLog(parser);
UnloadLibCec(parser);
if (g_logOutput.is_open())