+libcec (1.3-2) unstable; urgency=low
+
+ * changed/added:
+ * copy libcec.dll to the XBMC installation dir when XBMC is found
+ * disable background polling. let the client request this info when needed
+ * update the power status of a device when it's set to
+ CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON
+ * wait for the correct response when requesting something, not just any
+ response
+ * don't keep trying the same command/request after receiving a feature
+ abort message
+ * interface changes:
+ * change the previously unused boolean parameter in volume control methods
+ to bSendRelease, and only send a key release when it's true. default to
+ true
+ * fixed:
+ * don't send the power up/down keypress to listeners when in the initial
+ device state (powered off). fixes unexpected shutdown in XBMC when
+ connecting to the CEC adapter.
+ * send a 'menu state activated' command when starting up. bugzid: 113
+ * don't wait for a response when not needed
+ * don't hold a lock while waiting for a response. fixes failed libCEC
+ inits and slow responses
+ * don't replace a command handler when it's being used. fixes possible
+ crash on startup
+ * don't try to do anything before the processor thread has started
+ * don't transmit active source messages when the physical address is
+ still 0xFFFF
+ * don't init the default handler before the physical address is known
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Thu, 29 Dec 2011 03:05:00 +0100
+
libcec (1.3-1) unstable; urgency=low
* changed/added:
+libcec (1.3-2) unstable; urgency=low
+
+ * changed/added:
+ * copy libcec.dll to the XBMC installation dir when XBMC is found
+ * disable background polling. let the client request this info when needed
+ * update the power status of a device when it's set to
+ CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON
+ * wait for the correct response when requesting something, not just any
+ response
+ * don't keep trying the same command/request after receiving a feature
+ abort message
+ * interface changes:
+ * change the previously unused boolean parameter in volume control methods
+ to bSendRelease, and only send a key release when it's true. default to
+ true
+ * fixed:
+ * don't send the power up/down keypress to listeners when in the initial
+ device state (powered off). fixes unexpected shutdown in XBMC when
+ connecting to the CEC adapter.
+ * send a 'menu state activated' command when starting up. bugzid: 113
+ * don't wait for a response when not needed
+ * don't hold a lock while waiting for a response. fixes failed libCEC
+ inits and slow responses
+ * don't replace a command handler when it's being used. fixes possible
+ crash on startup
+ * don't try to do anything before the processor thread has started
+ * don't transmit active source messages when the physical address is
+ still 0xFFFF
+ * don't init the default handler before the physical address is known
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Thu, 29 Dec 2011 03:05:00 +0100
+
libcec (1.3-1) unstable; urgency=low
* changed/added:
/*!
* @brief Sends a volume up keypress to an audiosystem if it's present.
- * @param bWait Wait for the response of the audiosystem when true.
+ * @param bSendRelease Send a key release after the keypress.
* @return The new audio status.
*/
- virtual uint8_t VolumeUp(bool bWait = true) = 0;
+ virtual uint8_t VolumeUp(bool bSendRelease = true) = 0;
/*!
* @brief Sends a volume down keypress to an audiosystem if it's present.
- * @param bWait Wait for the response of the audiosystem when true.
+ * @param bSendRelease Send a key release after the keypress.
* @return The new audio status.
*/
- virtual uint8_t VolumeDown(bool bWait = true) = 0;
+ virtual uint8_t VolumeDown(bool bSendRelease = true) = 0;
/*!
* @brief Sends a mute keypress to an audiosystem if it's present.
- * @param bWait Wait for the response of the audiosystem when true.
+ * @param bSendRelease Send a key release after the keypress.
* @return The new audio status.
*/
- virtual uint8_t MuteAudio(bool bWait = true) = 0;
+ virtual uint8_t MuteAudio(bool bSendRelease = true) = 0;
/*!
* @brief Send a keypress to a device on the CEC bus.
extern DECLSPEC int cec_set_hdmi_port(cec_logical_address iBaseDevice, uint8_t iPort);
#endif
-extern DECLSPEC int cec_volume_up(int bWait);
+extern DECLSPEC int cec_volume_up(int bSendRelease);
-extern DECLSPEC int cec_volume_down(int bWait);
+extern DECLSPEC int cec_volume_down(int bSendRelease);
-extern DECLSPEC int cec_mute_audio(int bWait);
+extern DECLSPEC int cec_mute_audio(int bSendRelease);
#ifdef __cplusplus
extern DECLSPEC int cec_send_keypress(CEC::cec_logical_address iDestination, CEC::cec_user_control_code key, int bWait);
File "..\pthreadVC2.dll"
File "..\README"
+ ; Copy to XBMC\system
+ ReadRegStr $1 HKCU "Software\XBMC" ""
+ ${If} $1 != ""
+ SetOutPath "$1\system"
+ File "..\libcec.dll"
+ ${EndIf}
+
SetOutPath "$INSTDIR\driver"
File "..\dpinst-amd64.exe"
File "..\dpinst-x86.exe"
// 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.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.3.1.0")]
+[assembly: AssemblyFileVersion("1.3.1.0")]
CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
m_bStarted(false),
+ m_bInitialised(false),
m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
m_lastInitiator(CECDEVICE_UNKNOWN),
m_strDeviceName(strDeviceName),
m_controller(controller),
m_bMonitor(false),
- m_busScan(NULL),
m_iStandardLineTimeout(3),
m_iRetryLineTimeout(3),
m_iLastTransmission(0)
CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) :
m_bStarted(false),
+ m_bInitialised(false),
m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
m_strDeviceName(strDeviceName),
bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */)
{
- CLockObject lock(&m_mutex);
- if (!m_communication || m_communication->IsOpen())
- {
- m_controller->AddLog(CEC_LOG_ERROR, "connection already opened");
- return false;
- }
+ bool bReturn(false);
- if (!m_communication->Open(strPort, iBaudRate, iTimeoutMs))
{
- m_controller->AddLog(CEC_LOG_ERROR, "could not open a connection");
- return false;
- }
+ CLockObject lock(&m_mutex);
- if (CreateThread())
- {
- if (!m_startCondition.Wait(&m_mutex) || !m_bStarted)
+ /* check for an already opened connection */
+ if (!m_communication || m_communication->IsOpen())
{
- m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
- return false;
+ m_controller->AddLog(CEC_LOG_ERROR, "connection already opened");
+ return bReturn;
}
- lock.Leave();
-
- m_busDevices[CECDEVICE_TV]->GetVendorId();
-
- if (SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true))
+ /* open a new connection */
+ if (!m_communication->Open(strPort, iBaudRate, iTimeoutMs))
{
- m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
- m_busScan = new CCECBusScan(this);
- m_busScan->CreateThread(true);
- return true;
+ m_controller->AddLog(CEC_LOG_ERROR, "could not open a connection");
+ return bReturn;
}
- else
+
+ /* create the processor thread */
+ if (!CreateThread() || !m_startCondition.Wait(&m_mutex) || !m_bStarted)
{
- m_controller->AddLog(CEC_LOG_ERROR, "failed to initialise the processor");
+ m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+ return bReturn;
}
}
- m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
- return false;
+ /* find the logical address for the adapter */
+ bReturn = m_logicalAddresses.IsEmpty() ? FindLogicalAddresses() : true;
+ if (!bReturn)
+ m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
+
+ /* set the physical address for the adapter */
+ if (bReturn)
+ {
+ /* only set our OSD name for the primary device */
+ m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName;
+
+ /* get the vendor id from the TV, so we are using the correct handler */
+ m_busDevices[CECDEVICE_TV]->GetVendorId();
+ ReplaceHandlers();
+
+ bReturn = SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true);
+ }
+
+ /* make the primary device the active source */
+ if (bReturn)
+ {
+ m_bInitialised = true;
+ m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true;
+ bReturn = m_busDevices[CECDEVICE_TV]->InitHandler();
+ }
+
+ if (bReturn)
+ {
+ m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
+ }
+ else
+ {
+ m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+ StopThread(true);
+ }
+
+ return bReturn;
}
bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
bReturn &= FindLogicalAddressAudioSystem();
}
+ if (bReturn)
+ SetAckMask(m_logicalAddresses.AckMask());
+
return bReturn;
}
+void CCECProcessor::ReplaceHandlers(void)
+{
+ for (uint8_t iPtr = 0; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
+ m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
+}
+
void *CCECProcessor::Process(void)
{
bool bParseFrame(false);
cec_command command;
CCECAdapterMessage msg;
- if (m_logicalAddresses.IsEmpty() && !FindLogicalAddresses())
{
- CLockObject lock(&m_mutex);
- m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
- m_startCondition.Signal();
- return NULL;
- }
- else
- {
- /* only set our OSD name and active source for the primary device */
- m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName;
- m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true;
-
- SetAckMask(m_logicalAddresses.AckMask());
-
CLockObject lock(&m_mutex);
m_bStarted = true;
m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
while (!IsStopped())
{
+ ReplaceHandlers();
command.Clear();
msg.clear();
m_controller->CheckKeypressTimeout();
}
- if (m_busScan)
- {
- m_busScan->StopThread();
- delete m_busScan;
- m_busScan = NULL;
- }
-
if (m_communication)
m_communication->Close();
}
m_busDevices[addr]->SetActiveSource();
- bReturn = m_busDevices[addr]->TransmitActiveSource();
-
- if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
- m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+ if (m_busDevices[addr]->GetPhysicalAddress(false) != 0xFFFF)
{
- bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV);
+ bReturn = m_busDevices[addr]->TransmitActiveSource();
+
+ if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+ m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+ {
+ bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV);
+ }
}
return bReturn;
bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
{
bool bReturn(false);
+ {
+ CLockObject lock(&m_mutex);
- m_iBaseDevice = iBaseDevice;
- m_iHDMIPort = iPort;
- if (!m_bStarted && !bForce)
- return true;
+ m_iBaseDevice = iBaseDevice;
+ m_iHDMIPort = iPort;
+ if (!m_bStarted && !bForce)
+ return true;
+ }
CStdString strLog;
strLog.Format("setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
if (iBaseDevice > CECDEVICE_TV)
iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
- if (iPhysicalAddress == 0xffff)
- {
- SetPhysicalAddress((uint16_t)iPort * 0x1000);
- bReturn = false;
- }
- else
+ if (iPhysicalAddress < 0xffff)
{
- uint16_t iPos = 0;
if (iPhysicalAddress == 0)
- iPos = 0x1000;
+ iPhysicalAddress += 0x1000 * iPort;
else if (iPhysicalAddress % 0x1000 == 0)
- iPos = 0x100;
+ iPhysicalAddress += 0x100 * iPort;
else if (iPhysicalAddress % 0x100 == 0)
- iPos = 0x10;
+ iPhysicalAddress += 0x10 * iPort;
else if (iPhysicalAddress % 0x10 == 0)
- iPos = 0x1;
+ iPhysicalAddress += iPort;
- while(!bReturn && iPos > 0)
- {
- iPhysicalAddress += (uint16_t)(iPort * iPos);
- strLog.Format("checking physical address %4x", iPhysicalAddress);
- AddLog(CEC_LOG_DEBUG, strLog);
- if (PhysicalAddressInUse(iPhysicalAddress))
- {
- strLog.Format("physical address %4x is in use", iPhysicalAddress);
- AddLog(CEC_LOG_DEBUG, strLog);
- iPos = (iPos == 1) ? 0 : iPos / 0x10;
- }
- else
- {
- strLog.Format("physical address %4x is free", iPhysicalAddress);
- AddLog(CEC_LOG_DEBUG, strLog);
- SetPhysicalAddress(iPhysicalAddress);
- bReturn = true;
- }
- }
+ SetPhysicalAddress(iPhysicalAddress);
+ bReturn = true;
}
+ if (!bReturn)
+ m_controller->AddLog(CEC_LOG_ERROR, "failed to set the physical address");
+
return bReturn;
}
bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
{
+ CLockObject lock(&m_mutex);
if (m_logicalAddresses.primary != iLogicalAddress)
{
CStdString strLog;
bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress)
{
+ CLockObject lock(&m_mutex);
if (!m_logicalAddresses.IsEmpty())
{
for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
{
CLockObject lock(&m_mutex);
m_bMonitor = bEnable;
-
- if (!bEnable)
- {
- if (!m_busScan)
- {
- m_busScan = new CCECBusScan(this);
- m_busScan->CreateThread(true);
- }
- }
- else
- {
- if (m_busScan)
- {
- m_busScan->StopThread();
- delete m_busScan;
- m_busScan = NULL;
- }
- }
}
if (bEnable)
return false;
}
-uint8_t CCECProcessor::VolumeUp(void)
+uint8_t CCECProcessor::VolumeUp(bool bSendRelease /* = true */)
{
uint8_t status = 0;
if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
- status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp();
+ status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bSendRelease);
return status;
}
-uint8_t CCECProcessor::VolumeDown(void)
+uint8_t CCECProcessor::VolumeDown(bool bSendRelease /* = true */)
{
uint8_t status = 0;
if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
- status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown();
+ status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bSendRelease);
return status;
}
-uint8_t CCECProcessor::MuteAudio(void)
+uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
{
uint8_t status = 0;
if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
- status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio();
+ status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bSendRelease);
return status;
}
{
CCECBusDevice *device = NULL;
- for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+ for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
{
- if (m_busDevices[iPtr]->m_type == type)
+ if (m_busDevices[iPtr]->m_type == type && m_logicalAddresses[iPtr])
{
device = m_busDevices[iPtr];
break;
return device;
}
+CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const
+{
+ CCECBusDevice *device(NULL);
+ cec_logical_address primary = m_logicalAddresses.primary;
+ if (primary != CECDEVICE_UNKNOWN)
+ device = m_busDevices[primary];
+ return device;
+}
+
cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
{
return m_busDevices[iAddress]->GetCecVersion();
return bReturn;
}
-bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key)
+bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
{
- return m_busDevices[iDestination]->TransmitKeypress(key);
+ return m_busDevices[iDestination]->TransmitKeypress(key, bWait);
}
-bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination)
+bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
{
- return m_busDevices[iDestination]->TransmitKeyRelease();
+ return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
}
const char *CCECProcessor::ToString(const cec_menu_state state)
virtual bool IsMonitoring(void) const { return m_bMonitor; }
virtual CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const;
virtual CCECBusDevice * GetDeviceByType(cec_device_type type) const;
+ virtual CCECBusDevice * GetPrimaryDevice(void) const;
virtual cec_version GetDeviceCecVersion(cec_logical_address iAddress);
virtual bool GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
virtual const std::string & GetDeviceName(void) { return m_strDeviceName; }
virtual bool IsStarted(void) const { return m_bStarted; }
virtual cec_logical_address GetActiveSource(void);
virtual bool IsActiveSource(cec_logical_address iAddress);
+ virtual bool IsInitialised(void) const { return m_bInitialised; }
virtual bool SetActiveView(void);
virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
virtual bool SetActiveSource(uint16_t iStreamPath);
virtual bool SwitchMonitoring(bool bEnable);
virtual bool PollDevice(cec_logical_address iAddress);
- virtual uint8_t VolumeUp(void);
- virtual uint8_t VolumeDown(void);
- virtual uint8_t MuteAudio(void);
- virtual bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key);
- virtual bool TransmitKeyRelease(cec_logical_address iDestination);
+ virtual uint8_t VolumeUp(bool bSendRelease = true);
+ virtual uint8_t VolumeDown(bool bSendRelease = true);
+ virtual uint8_t MuteAudio(bool bSendRelease = true);
+ virtual bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
+ virtual bool TransmitKeyRelease(cec_logical_address iDestination, bool bWait = true);
virtual bool EnablePhysicalAddressDetection(void) { return false; };
void SetStandardLineTimeout(uint8_t iTimeout);
void SetRetryLineTimeout(uint8_t iTimeout);
CMutex m_transmitMutex;
private:
+ void ReplaceHandlers(void);
void ScanCECBus(void);
bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
bool TryLogicalAddress(cec_logical_address address);
void ParseCommand(cec_command &command);
bool m_bStarted;
+ bool m_bInitialised;
uint8_t m_iHDMIPort;
cec_logical_address m_iBaseDevice;
cec_command m_currentframe;
return false;
}
-uint8_t CLibCEC::VolumeUp(bool bWait /* = true */)
+uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
{
if (m_cec)
- return m_cec->VolumeUp();
+ return m_cec->VolumeUp(bSendRelease);
return 0;
}
-uint8_t CLibCEC::VolumeDown(bool bWait /* = true */)
+uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
{
if (m_cec)
- return m_cec->VolumeDown();
+ return m_cec->VolumeDown(bSendRelease);
return 0;
}
-uint8_t CLibCEC::MuteAudio(bool bWait /* = true */)
+uint8_t CLibCEC::MuteAudio(bool bSendRelease /* = true */)
{
if (m_cec)
- return m_cec->MuteAudio();
+ return m_cec->MuteAudio(bSendRelease);
return 0;
}
-bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = false */)
+bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
{
if (m_cec)
- return m_cec->TransmitKeypress(iDestination, key);
+ return m_cec->TransmitKeypress(iDestination, key, bWait);
return false;
}
-bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = false */)
+bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
{
if (m_cec)
- return m_cec->TransmitKeyRelease(iDestination);
+ return m_cec->TransmitKeyRelease(iDestination, bWait);
return false;
}
virtual bool IsActiveDevice(cec_logical_address iAddress);
virtual bool IsActiveDeviceType(cec_device_type type);
virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort = CEC_DEFAULT_HDMI_PORT);
- virtual uint8_t VolumeUp(bool bWait = true);
- virtual uint8_t VolumeDown(bool bWait = true);
- virtual uint8_t MuteAudio(bool bWait = true);
- virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = false);
- virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = false);
+ virtual uint8_t VolumeUp(bool bSendRelease = true);
+ virtual uint8_t VolumeDown(bool bSendRelease = true);
+ virtual uint8_t MuteAudio(bool bSendRelease = true);
+ virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
+ virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = true);
virtual cec_osd_name GetDeviceOSDName(cec_logical_address iAddress);
virtual bool EnablePhysicalAddressDetection(void);
virtual cec_logical_address GetActiveSource(void);
return -1;
}
-int cec_volume_up(int bWait)
+int cec_volume_up(int bSendRelease)
{
if (cec_parser)
- return cec_parser->VolumeUp(bWait == 1);
+ return cec_parser->VolumeUp(bSendRelease == 1);
return -1;
}
-int cec_volume_down(int bWait)
+int cec_volume_down(int bSendRelease)
{
if (cec_parser)
- return cec_parser->VolumeDown(bWait == 1);
+ return cec_parser->VolumeDown(bSendRelease == 1);
return -1;
}
-int cec_mute_audio(int bWait)
+int cec_mute_audio(int bSendRelease)
{
if (cec_parser)
- return cec_parser->MuteAudio(bWait == 1);
+ return cec_parser->MuteAudio(bSendRelease == 1);
return -1;
}
bool CCECAudioSystem::SetAudioStatus(uint8_t status)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_audioStatus != status)
{
CStdString strLog;
bool CCECAudioSystem::SetSystemAudioModeStatus(const cec_system_audio_status mode)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_systemAudioStatus != mode)
{
CStdString strLog;
{
uint8_t state;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
AddLog(CEC_LOG_NOTICE, strLog);
{
cec_system_audio_status state;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
AddLog(CEC_LOG_NOTICE, strLog);
{
cec_system_audio_status state;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
AddLog(CEC_LOG_NOTICE, strLog);
return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state);
}
-uint8_t CCECAudioSystem::VolumeUp(void)
+uint8_t CCECAudioSystem::VolumeUp(bool bSendRelease /* = true */)
{
- if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP))
+ if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP) && bSendRelease)
TransmitKeyRelease();
CLockObject lock(&m_mutex);
return m_audioStatus;
}
-uint8_t CCECAudioSystem::VolumeDown(void)
+uint8_t CCECAudioSystem::VolumeDown(bool bSendRelease /* = true */)
{
- if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN))
+ if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN) && bSendRelease)
TransmitKeyRelease();
CLockObject lock(&m_mutex);
return m_audioStatus;
}
-uint8_t CCECAudioSystem::MuteAudio(void)
+uint8_t CCECAudioSystem::MuteAudio(bool bSendRelease /* = true */)
{
- if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE))
+ if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE) && bSendRelease)
TransmitKeyRelease();
CLockObject lock(&m_mutex);
virtual bool TransmitSetSystemAudioMode(cec_logical_address dest);
virtual bool TransmitSystemAudioModeStatus(cec_logical_address dest);
- virtual uint8_t VolumeUp(void);
- virtual uint8_t VolumeDown(void);
- virtual uint8_t MuteAudio(void);
+ virtual uint8_t VolumeUp(bool bSendRelease = true);
+ virtual uint8_t VolumeDown(bool bSendRelease = true);
+ virtual uint8_t MuteAudio(bool bSendRelease = true);
virtual bool TransmitActiveSource(void) { return false; }
m_powerStatus(CEC_POWER_STATUS_UNKNOWN),
m_processor(processor),
m_vendor(CEC_VENDOR_UNKNOWN),
+ m_bReplaceHandler(false),
m_menuState(CEC_MENU_STATE_ACTIVATED),
m_bActiveSource(false),
m_iLastActive(0),
m_cecVersion(CEC_VERSION_UNKNOWN),
- m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN)
+ m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN),
+ m_handlerMutex(false)
{
m_handler = new CCECCommandHandler(this);
/* update "last active" */
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
m_iLastActive = GetTimeMs();
if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
/* change status to present */
if (bHandled)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
{
if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
AddLog(CEC_LOG_DEBUG, strLog.c_str());
- if (m_handler->TransmitPowerOn(GetMyLogicalAddress(), m_iLogicalAddress))
+ if (m_handler->TransmitImageViewOn(GetMyLogicalAddress(), m_iLogicalAddress))
{
{
CLockObject lock(&m_mutex);
//@{
cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
{
- CLockObject lock(&m_mutex);
- if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
- (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN))
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(&m_mutex);
+ bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+ (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN));
+ }
+
+ if (bRequestUpdate)
RequestCecVersion();
+ CLockObject lock(&m_mutex);
return m_cecVersion;
}
bool CCECBusDevice::RequestCecVersion(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress))
{
CStdString strLog;
cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
{
- CLockObject lock(&m_mutex);
- if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
- (bUpdate || !strcmp(m_menuLanguage.language, "???")))
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(&m_mutex);
+ bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+ (bUpdate || !strcmp(m_menuLanguage.language, "???")));
+ }
+
+ if (bRequestUpdate)
RequestMenuLanguage();
+ CLockObject lock(&m_mutex);
return m_menuLanguage;
}
bool CCECBusDevice::RequestMenuLanguage(void)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress))
+
+ if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
{
CStdString strLog;
strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
{
- CLockObject lock(&m_mutex);
- if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
- (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
- m_type != CEC_DEVICE_TYPE_TV)
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(&m_mutex);
+ bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+ (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
+ m_type != CEC_DEVICE_TYPE_TV);
+ }
+
+ if (bRequestUpdate)
RequestOSDName();
+ CLockObject lock(&m_mutex);
return m_strDeviceName;
}
bool CCECBusDevice::RequestOSDName(void)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress))
+
+ if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
{
CStdString strLog;
strLog.Format("<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
uint16_t CCECBusDevice::GetPhysicalAddress(bool bUpdate /* = false */)
{
- CLockObject lock(&m_mutex);
- if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
- (m_iPhysicalAddress == 0xFFFF || bUpdate))
+ bool bRequestUpdate(false);
{
- if (!RequestPhysicalAddress())
- AddLog(CEC_LOG_ERROR, "failed to request the physical address");
+ CLockObject lock(&m_mutex);
+ bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+ (m_iPhysicalAddress == 0xFFFF || bUpdate));
}
+ if (bRequestUpdate && !RequestPhysicalAddress())
+ AddLog(CEC_LOG_ERROR, "failed to request the physical address (1)");
+
+ CLockObject lock(&m_mutex);
return m_iPhysicalAddress;
}
bool CCECBusDevice::RequestPhysicalAddress(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress))
{
CStdString strLog;
cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
{
- CLockObject lock(&m_mutex);
- if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
- (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN))
+ bool bRequestUpdate(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));
+ }
+
+ if (bRequestUpdate)
RequestPowerStatus();
+ CLockObject lock(&m_mutex);
return m_powerStatus;
}
bool CCECBusDevice::RequestPowerStatus(void)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress))
+
+ if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
{
CStdString strLog;
strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */)
{
- CLockObject lock(&m_mutex);
- if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
- (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN))
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(&m_mutex);
+ bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+ (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+ }
+
+ if (bRequestUpdate)
RequestVendorId();
+ CLockObject lock(&m_mutex);
return m_vendor;
}
bool CCECBusDevice::RequestVendorId(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress))
{
CStdString strLog;
cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC &&
(m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN || bForcePoll))
{
void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (language.device == m_iLogicalAddress)
{
CStdString strLog;
void CCECBusDevice::SetOSDName(CStdString strName)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_strDeviceName != strName)
{
CStdString strLog;
void CCECBusDevice::SetMenuState(const cec_menu_state state)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_menuState != state)
{
CStdString strLog;
void CCECBusDevice::SetInactiveSource(void)
{
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
m_bActiveSource = false;
}
void CCECBusDevice::SetActiveSource(void)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
for (int iPtr = 0; iPtr < 16; iPtr++)
if (iPtr != m_iLogicalAddress)
void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
switch (newStatus)
{
case CEC_DEVICE_STATUS_UNKNOWN:
void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
{
CStdString strLog;
void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = 0 */)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (iNewAddress > 0)
{
CStdString strLog;
void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_powerStatus != powerStatus)
{
CStdString strLog;
}
}
-bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */)
+bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */)
{
- bool bVendorChanged(false);
+ CLockObject lock(&m_mutex);
+ CLockObject handlerLock(&m_handlerMutex);
+ if (m_vendor != m_handler->GetVendorId())
{
- CLockObject lock(&m_writeMutex);
- bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
- m_vendor = (cec_vendor_id)iVendorId;
+ if (m_handler->InUse())
+ return false;
- if (bVendorChanged)
- delete m_handler;
+ delete m_handler;
- switch (iVendorId)
+ switch (m_vendor)
{
case CEC_VENDOR_SAMSUNG:
- if (bVendorChanged)
- m_handler = new CANCommandHandler(this);
+ m_handler = new CANCommandHandler(this);
break;
case CEC_VENDOR_LG:
- if (bVendorChanged)
- m_handler = new CSLCommandHandler(this);
+ m_handler = new CSLCommandHandler(this);
break;
case CEC_VENDOR_PANASONIC:
- if (bVendorChanged)
- m_handler = new CVLCommandHandler(this);
+ m_handler = new CVLCommandHandler(this);
break;
default:
- if (bVendorChanged)
- m_handler = new CCECCommandHandler(this);
+ m_handler = new CCECCommandHandler(this);
break;
}
+
+ if (bInitHandler && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised())
+ m_handler->InitHandler();
}
- if (bVendorChanged && bInitHandler)
- m_handler->InitHandler();
+ return true;
+}
+
+bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */)
+{
+ bool bVendorChanged(false);
+
+ {
+ CLockObject lock(&m_mutex);
+ bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
+ m_vendor = (cec_vendor_id)iVendorId;
+ ReplaceHandler(bInitHandler);
+ }
CStdString strLog;
strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
bool bSendActiveSource(false);
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_powerStatus != CEC_POWER_STATUS_ON)
{
CStdString strLog;
}
}
- return bSendActiveSource ? m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress) : false;
+ if (bSendActiveSource)
+ {
+ m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+ m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+ return true;
+ }
+
+ return false;
}
bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
{
cec_version version;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
AddLog(CEC_LOG_NOTICE, strLog);
{
uint16_t iPhysicalAddress;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
AddLog(CEC_LOG_NOTICE, strLog);
{
cec_menu_state menuState;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
AddLog(CEC_LOG_NOTICE, strLog);
{
CStdString strDeviceName;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
AddLog(CEC_LOG_NOTICE, strLog.c_str());
bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage)
{
- CStdString strLog;
- strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
- AddLog(CEC_LOG_NOTICE, strLog.c_str());
+ if (!IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
+ {
+ CStdString strLog;
+ strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
+ AddLog(CEC_LOG_NOTICE, strLog.c_str());
- return m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage);
+ return m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage);
+ }
+ return false;
}
bool CCECBusDevice::TransmitPhysicalAddress(void)
uint16_t iPhysicalAddress;
cec_device_type type;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_iPhysicalAddress == 0xffff)
return false;
bReturn = m_handler->TransmitPoll(m_iLogicalAddress, dest);
AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (bReturn)
{
m_iLastActive = GetTimeMs();
{
cec_power_status state;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
AddLog(CEC_LOG_NOTICE, strLog.c_str());
{
uint64_t iVendorId;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
iVendorId = (uint64_t)m_vendor;
}
}
}
-bool CCECBusDevice::TransmitKeypress(cec_user_control_code key)
+bool CCECBusDevice::TransmitKeypress(cec_user_control_code key, bool bWait /* = true */)
{
- return m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key);
+ return m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key, bWait);
}
-bool CCECBusDevice::TransmitKeyRelease(void)
+bool CCECBusDevice::TransmitKeyRelease(bool bWait /* = true */)
{
- return m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress);
+ return m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress, bWait);
}
+
+bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode) const
+{
+ return m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end();
+}
+
+void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+{
+ m_unsupportedFeatures.insert(opcode);
+}
+
+bool CCECBusDevice::InitHandler(void)
+{
+ CLockObject lock(&m_mutex);
+ return m_handler->InitHandler();
+}
+
//@}
*/
#include <cectypes.h>
+#include <set>
#include "../platform/threads.h"
#include "../util/StdString.h"
virtual bool MyLogicalAddressContains(cec_logical_address address) const;
virtual cec_bus_device_status GetStatus(bool bForcePoll = false);
virtual bool IsActiveSource(void) const { return m_bActiveSource; }
-
+ virtual bool IsUnsupportedFeature(cec_opcode opcode) const;
+ virtual void SetUnsupportedFeature(cec_opcode opcode);
virtual void SetInactiveSource(void);
virtual void SetActiveSource(void);
virtual bool TryLogicalAddress(void);
+ virtual bool InitHandler(void);
virtual void SetDeviceStatus(const cec_bus_device_status newStatus);
virtual void SetPhysicalAddress(uint16_t iNewAddress);
virtual bool TransmitPowerState(cec_logical_address dest);
virtual bool TransmitPoll(cec_logical_address dest);
virtual bool TransmitVendorID(cec_logical_address dest, bool bSendAbort = true);
- virtual bool TransmitKeypress(cec_user_control_code key);
- virtual bool TransmitKeyRelease(void);
+ virtual bool TransmitKeypress(cec_user_control_code key, bool bWait = true);
+ virtual bool TransmitKeyRelease(bool bWait = true);
protected:
+ bool ReplaceHandler(bool bInitHandler = true);
+
bool RequestCecVersion(void);
bool RequestMenuLanguage(void);
bool RequestPowerStatus(void);
CCECProcessor * m_processor;
CCECCommandHandler * m_handler;
cec_vendor_id m_vendor;
+ bool m_bReplaceHandler;
cec_menu_state m_menuState;
bool m_bActiveSource;
uint64_t m_iLastActive;
cec_version m_cecVersion;
cec_bus_device_status m_deviceStatus;
- CMutex m_writeMutex;
+ std::set<cec_opcode> m_unsupportedFeatures;
CMutex m_mutex;
+ CMutex m_handlerMutex;
};
};
void CCECPlaybackDevice::SetDeckStatus(cec_deck_info deckStatus)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_deckStatus != deckStatus && m_deckStatus != CEC_DECK_INFO_OTHER_STATUS_LG)
{
CStdString strLog;
void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode)
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
if (m_deckControlMode != mode)
{
CStdString strLog;
{
cec_deck_info state;
{
- CLockObject lock(&m_writeMutex);
+ CLockObject lock(&m_mutex);
CStdString strLog;
strLog.Format("<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
AddLog(CEC_LOG_NOTICE, strLog);
m_processor(m_busDevice->GetProcessor()),
m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
- m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES)
+ m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
+ m_bHandlerInited(false),
+ m_iUseCounter(0),
+ m_expectedResponse(CEC_OPCODE_NONE)
{
}
CCECCommandHandler::~CCECCommandHandler(void)
{
+ CLockObject lock(&m_processor->m_transmitMutex);
+ CLockObject receiveLock(&m_receiveMutex);
m_condition.Broadcast();
}
{
bool bHandled(true), bHandlerChanged(false);
+ MarkBusy();
CStdString strLog;
strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode);
m_busDevice->AddLog(CEC_LOG_NOTICE, strLog);
case CEC_OPCODE_TEXT_VIEW_ON:
HandleTextViewOn(command);
break;
+ case CEC_OPCODE_FEATURE_ABORT:
+ HandleFeatureAbort(command);
+ break;
+ case CEC_OPCODE_VENDOR_COMMAND:
+ HandleVendorCommand(command);
+ break;
default:
UnhandledCommand(command);
bHandled = false;
if (bHandled && !bHandlerChanged)
{
CLockObject lock(&m_receiveMutex);
- m_condition.Signal();
+ if (m_expectedResponse == CEC_OPCODE_NONE ||
+ m_expectedResponse == command.opcode)
+ m_condition.Signal();
}
+ MarkReady();
return bHandled;
}
return SetVendorId(command);
}
+bool CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
+{
+ if (command.parameters.size == 2)
+ {
+ m_processor->m_busDevices[command.initiator]->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
+ }
+ return true;
+}
+
bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
{
if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
- return device->TransmitPhysicalAddress();
+ {
+ device->SetActiveSource();
+ return device->TransmitPhysicalAddress() &&
+ device->TransmitActiveSource();
+ }
}
return false;
}
}
}
-
- m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+ else
+ {
+ m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+ }
return true;
}
}
return true;
}
-bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
{
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION);
- return Transmit(command);
+ return Transmit(command, true, CEC_OPCODE_CEC_VERSION);
}
bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE);
- return Transmit(command);
+ return Transmit(command, true, CEC_OPCODE_SET_MENU_LANGUAGE);
}
bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME);
- return Transmit(command);
+ return Transmit(command, true, CEC_OPCODE_SET_OSD_NAME);
}
bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
- return Transmit(command);
+ return Transmit(command, true, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
}
bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
- return Transmit(command);
+ return Transmit(command, true, CEC_OPCODE_REPORT_POWER_STATUS);
}
bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
- return Transmit(command);
+ return Transmit(command, true, CEC_OPCODE_DEVICE_VENDOR_ID);
}
bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION);
command.parameters.PushBack((uint8_t)cecVersion);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF);
command.parameters.PushBack(iPhysicalAddress & 0xFF);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS);
command.parameters.PushBack((uint8_t)menuState);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName)
for (unsigned int iPtr = 0; iPtr < strDeviceName.length(); iPtr++)
command.parameters.PushBack(strDeviceName.at(iPtr));
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage)
for (unsigned int iPtr = 0; iPtr < iLen; iPtr++)
command.parameters.PushBack(strMessage[iPtr]);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type)
command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
command.parameters.PushBack((uint8_t) (type));
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS);
command.parameters.PushBack((uint8_t) state);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId)
command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF));
command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF));
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS);
command.parameters.PushBack(state);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
command.parameters.PushBack((uint8_t)state);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
command.parameters.PushBack((uint8_t)state);
- return Transmit(command);
+ return Transmit(command, false);
}
bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state)
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS);
command.PushBack((uint8_t)state);
- return Transmit(command);
+ return Transmit(command, false);
}
-bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key)
+bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
{
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED);
command.parameters.PushBack((uint8_t)key);
- return Transmit(command);
+ return Transmit(command, bWait);
}
-bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */)
{
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE);
- return Transmit(command);
+ return Transmit(command, bWait);
}
-bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */)
+bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */, cec_opcode expectedResponse /* = CEC_OPCODE_NONE */)
{
+ bool bReturn(false);
command.transmit_timeout = m_iTransmitTimeout;
- CLockObject writeLock(&m_processor->m_transmitMutex);
- CLockObject receiveLock(&m_receiveMutex);
- if (m_processor->Transmit(command))
{
- if (bExpectResponse)
- return m_condition.Wait(&m_receiveMutex, m_iTransmitWait);
- return true;
+ uint8_t iTries(0), iMaxTries(command.opcode == CEC_OPCODE_NONE ? 1 : m_iTransmitRetries + 1);
+ CLockObject writeLock(&m_processor->m_transmitMutex);
+ CLockObject receiveLock(&m_receiveMutex);
+ ++m_iUseCounter;
+ while (!bReturn && ++iTries <= iMaxTries)
+ {
+ m_expectedResponse = expectedResponse;
+ if (m_processor->Transmit(command))
+ {
+ m_processor->AddLog(CEC_LOG_DEBUG, "command transmitted");
+ bReturn = bExpectResponse ?
+ m_condition.Wait(&m_receiveMutex, m_iTransmitWait) :
+ true;
+ }
+ }
+ --m_iUseCounter;
}
- return false;
+ return bReturn;
+}
+
+bool CCECCommandHandler::InitHandler(void)
+{
+ if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+ {
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ primary->SetPowerStatus(CEC_POWER_STATUS_ON);
+ primary->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+
+ if (m_processor->GetPrimaryDevice()->GetPhysicalAddress(false) != 0xffff)
+ {
+ m_processor->SetActiveSource();
+ primary->TransmitMenuState(m_busDevice->GetLogicalAddress());
+ m_bHandlerInited = true;
+ }
+ }
+ return true;
+}
+
+void CCECCommandHandler::MarkBusy(void)
+{
+ CLockObject receiveLock(&m_receiveMutex);
+ ++m_iUseCounter;
+}
+
+bool CCECCommandHandler::MarkReady(void)
+{
+ CLockObject receiveLock(&m_receiveMutex);
+ return m_iUseCounter > 0 ? (--m_iUseCounter == 0) : true;
+}
+
+bool CCECCommandHandler::InUse(void)
+{
+ CLockObject receiveLock(&m_receiveMutex);
+ return m_iUseCounter > 0;
}
virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool HandleReceiveFailed(void);
- virtual bool InitHandler(void) { return true; }
+ virtual bool InitHandler(void);
virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; }
- virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+ virtual bool TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state);
virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state);
virtual bool TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state);
- virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key);
- virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+ virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
+ virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true);
+
+ virtual void MarkBusy(void);
+ virtual bool MarkReady(void);
+ virtual bool InUse(void);
protected:
virtual bool HandleActiveSource(const cec_command &command);
virtual bool HandleDeviceCecVersion(const cec_command &command);
virtual bool HandleDeviceVendorCommandWithId(const cec_command &command);
virtual bool HandleDeviceVendorId(const cec_command &command);
+ virtual bool HandleFeatureAbort(const cec_command &command);
virtual bool HandleGetCecVersion(const cec_command &command);
virtual bool HandleGiveAudioStatus(const cec_command &command);
virtual bool HandleGiveDeckStatus(const cec_command &command);
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 void UnhandledCommand(const cec_command &command);
virtual unsigned int GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
virtual bool SetVendorId(const cec_command &command);
virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
- virtual bool Transmit(cec_command &command, bool bExpectResponse = true);
+ virtual bool Transmit(cec_command &command, bool bExpectResponse = true, cec_opcode expectedResponse = CEC_OPCODE_NONE);
CCECBusDevice *m_busDevice;
CCECProcessor *m_processor;
int32_t m_iTransmitTimeout;
int32_t m_iTransmitWait;
int8_t m_iTransmitRetries;
+ bool m_bHandlerInited;
+ uint8_t m_iUseCounter;
+ cec_opcode m_expectedResponse;
CMutex m_receiveMutex;
CCondition m_condition;
};
#include "../devices/CECPlaybackDevice.h"
#include "../CECProcessor.h"
#include "../platform/timeutils.h"
+#include "../platform/threads.h"
using namespace CEC;
CCECCommandHandler(busDevice),
m_bAwaitingReceiveFailed(false),
m_bSLEnabled(false),
- m_bVendorIdSent(false)
+ m_bPowerStateReset(false)
{
- /* TODO set to powered off until we fixed the connect on start loop issue */
- m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary]->m_powerStatus = CEC_POWER_STATUS_STANDBY;
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+
+ /* imitate LG devices */
+ if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+ primary->SetVendorId(CEC_VENDOR_LG, false);
+ SetLGDeckStatus();
+
+ /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */
+ if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+ m_busDevice->SetCecVersion(CEC_VERSION_1_3A);
+
+ /* LG devices always return "korean" as language */
+ cec_menu_language lang;
+ lang.device = m_busDevice->GetLogicalAddress();
+ snprintf(lang.language, 4, "eng");
+ m_busDevice->SetMenuLanguage(lang);
+}
+
+
+void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ CCECCommandHandler::HandlePoll(iInitiator, iDestination);
+ m_bAwaitingReceiveFailed = true;
+}
+
+bool CSLCommandHandler::HandleReceiveFailed(void)
+{
+ if (m_bAwaitingReceiveFailed)
+ {
+ m_bAwaitingReceiveFailed = false;
+ return false;
+ }
+
+ return true;
+}
+
+bool CSLCommandHandler::InitHandler(void)
+{
+ if (m_bHandlerInited)
+ return true;
+ m_bHandlerInited = true;
+
+ /* reply with LGs vendor id */
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+ primary->TransmitVendorID(CECDEVICE_TV, false);
+
+ primary->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+ return true;
+}
+
+bool CSLCommandHandler::HandleActiveSource(const cec_command &command)
+{
+ if (command.parameters.size == 2)
+ {
+ uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+ if (iAddress != m_busDevice->GetPhysicalAddress(false))
+ m_bSLEnabled = false;
+ return m_processor->SetActiveSource(iAddress);
+ }
+
+ return true;
+}
+
+bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
+{
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ if (primary->GetPowerStatus(false) == CEC_POWER_STATUS_ON && !m_bPowerStateReset && !m_bSLEnabled)
+ {
+ m_bPowerStateReset = true;
+ primary->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+ }
+
+ return CCECCommandHandler::HandleFeatureAbort(command);
+}
+
+bool CSLCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
+{
+ if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ return device->TransmitPhysicalAddress();
+ }
+
+ return false;
}
bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
return false;
}
-bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
-{
- if (command.parameters.size == 1)
- {
- if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE ||
- command.parameters[0] == CEC_STATUS_REQUEST_ON)
- {
- TransmitDeckStatus(command.initiator);
- }
- else
- {
- CCECCommandHandler::HandleGiveDeckStatus(command);
- }
- }
- return true;
-}
-
void CSLCommandHandler::HandleVendorCommand01(const cec_command &command)
{
TransmitVendorCommand0205(command.destination, command.initiator);
response.PushBack(SL_COMMAND_UNKNOWN_02);
response.PushBack(SL_COMMAND_UNKNOWN_03);
- Transmit(response);
-}
-
-void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination)
-{
- m_bSLEnabled = true;
- cec_command response;
- cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
- response.PushBack(SL_COMMAND_CONNECT_ACCEPT);
- response.PushBack((uint8_t)iSource);
- Transmit(response);
+ Transmit(response, false);
}
void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
{
- CCECBusDevice *device = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
+ CCECBusDevice *device = m_processor->GetPrimaryDevice();
if (device)
{
m_bSLEnabled = true;
- device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+
+ device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); //XXX
device->TransmitPowerState(command.initiator);
- device->TransmitVendorID(command.initiator);
- TransmitPowerOn(device->GetLogicalAddress(), command.initiator);
- }
-}
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
-void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
-{
- m_bSLEnabled = true;
- m_processor->m_busDevices[command.initiator]->SetActiveSource();
- m_processor->m_busDevices[command.destination]->TransmitActiveSource();
- TransmitVendorCommand05(command.destination, command.initiator);
- TransmitDeckStatus(command.initiator);
+ SetLGDeckStatus();
+ device->SetActiveSource();
+ TransmitImageViewOn(device->GetLogicalAddress(), command.initiator);
+ }
}
-
void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &command)
{
if (command.destination != CECDEVICE_BROADCAST)
}
}
-void CSLCommandHandler::TransmitDeckStatus(const cec_logical_address iDestination)
-{
- /* set deck status for the playback device */
- CCECBusDevice *primary = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
- if (primary->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
- {
- ((CCECPlaybackDevice *)primary)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
- ((CCECPlaybackDevice *)primary)->TransmitDeckStatus(iDestination);
- }
-}
-
-bool CSLCommandHandler::TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
-{
- cec_command response;
- cec_command::Format(response, iInitiator, iDestination, CEC_OPCODE_DEVICE_VENDOR_ID);
- response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 16) & 0xFF));
- response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 8) & 0xFF));
- response.parameters.PushBack((uint8_t) ((uint64_t)CEC_VENDOR_LG & 0xFF));
-
- Transmit(response);
- return true;
-}
-
-bool CSLCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
-{
- /* imitate LG devices */
- CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- device->SetVendorId(CEC_VENDOR_LG);
-
- return CCECCommandHandler::HandleGiveDeviceVendorId(command);
-}
-
-bool CSLCommandHandler::HandleCommand(const cec_command &command)
-{
- bool bHandled(false);
-
- if (m_processor->IsStarted() && (m_busDevice->MyLogicalAddressContains(command.destination) ||
- command.destination == CECDEVICE_BROADCAST))
- {
- switch(command.opcode)
- {
- case CEC_OPCODE_VENDOR_COMMAND:
- bHandled = HandleVendorCommand(command);
- break;
- case CEC_OPCODE_FEATURE_ABORT:
- {
- if (!m_bVendorIdSent)
- {
- m_bVendorIdSent = true;
- TransmitLGVendorId(m_processor->GetLogicalAddresses().primary, CECDEVICE_BROADCAST);
- }
- }
- bHandled = true;
- default:
- break;
- }
- }
-
- if (!bHandled)
- bHandled = CCECCommandHandler::HandleCommand(command);
-
- return bHandled;
-}
-
-void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
{
- CCECCommandHandler::HandlePoll(iInitiator, iDestination);
- m_bAwaitingReceiveFailed = true;
-}
+ m_bSLEnabled = true;
+ SetLGDeckStatus();
-bool CSLCommandHandler::HandleReceiveFailed(void)
-{
- if (m_bAwaitingReceiveFailed)
- {
- m_bAwaitingReceiveFailed = false;
- return false;
- }
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
- return true;
+ primary->SetActiveSource();
+ TransmitImageViewOn(primary->GetLogicalAddress(), command.initiator);
+ TransmitVendorCommand05(primary->GetLogicalAddress(), command.initiator);
}
-bool CSLCommandHandler::InitHandler(void)
+void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination)
{
- m_processor->SetStandardLineTimeout(3);
- m_processor->SetRetryLineTimeout(3);
-
- /* increase the number of retries because the tv is keeping the bus busy at times */
- m_iTransmitWait = 2000;
- m_iTransmitRetries = 4;
- m_iTransmitTimeout = 500;
-
- CCECBusDevice *primary = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
- if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
- {
- primary->SetVendorId(CEC_VENDOR_LG, false);
- primary->TransmitVendorID(CECDEVICE_TV, false);
- }
-
- if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
- {
- /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */
- m_busDevice->SetCecVersion(CEC_VERSION_1_3A);
- }
-
- /* LG devices always return "korean" as language */
- cec_menu_language lang;
- lang.device = m_busDevice->GetLogicalAddress();
- snprintf(lang.language, 4, "eng");
- m_busDevice->SetMenuLanguage(lang);
-
- if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
- {
- m_processor->SetActiveSource();
-
- /* LG TVs only route keypresses when the deck status is set to 0x20 */
- cec_logical_addresses addr = m_processor->GetLogicalAddresses();
- for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
- {
- CCECBusDevice *device = m_processor->m_busDevices[iPtr];
-
- if (addr[iPtr])
- {
- if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
- device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
- {
- ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
- ((CCECPlaybackDevice *)device)->TransmitDeckStatus(CECDEVICE_TV);
- }
- }
- }
- }
-
- return true;
+ cec_command response;
+ cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+ response.PushBack(SL_COMMAND_CONNECT_ACCEPT);
+ response.PushBack((uint8_t)iSource);
+ Transmit(response, false);
}
-bool CSLCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+void CSLCommandHandler::SetLGDeckStatus(void)
{
- if (iDestination != CECDEVICE_BROADCAST &&
- iDestination != CECDEVICE_TV &&
- m_processor->m_busDevices[iDestination]->GetVendorId(false) == CEC_VENDOR_LG)
- {
- cec_command command;
- cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_VENDOR_COMMAND);
- command.parameters.PushBack((uint8_t)SL_COMMAND_POWER_ON);
- command.parameters.PushBack(0x00);
- return Transmit(command);
- }
+ /* LG TVs only route keypresses when the deck status is set to 0x20 */
+ CCECBusDevice *device = m_processor->GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+ if (device)
+ ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
- return CCECCommandHandler::TransmitPowerOn(iInitiator, iDestination);
+ device = m_processor->GetDeviceByType(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ if (device)
+ ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
}
-
virtual ~CSLCommandHandler(void) {};
virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_LG; };
- virtual bool HandleCommand(const cec_command &command);
virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool HandleReceiveFailed(void);
virtual bool InitHandler(void);
- virtual bool TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination);
- virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
protected:
+ virtual bool HandleActiveSource(const cec_command &command);
+ virtual bool HandleFeatureAbort(const cec_command &command);
+ virtual bool HandleGivePhysicalAddress(const cec_command &command);
+ virtual bool HandleVendorCommand(const cec_command &command);
+
virtual void HandleVendorCommand01(const cec_command &command);
+ virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
+
virtual void HandleVendorCommandPowerOn(const cec_command &command);
- virtual void HandleVendorCommandSLConnect(const cec_command &command);
virtual void HandleVendorCommandPowerOnStatus(const cec_command &command);
- virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
+ virtual void HandleVendorCommandSLConnect(const cec_command &command);
virtual void TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination);
- virtual void TransmitDeckStatus(const cec_logical_address iDestination);
- virtual bool HandleGiveDeviceVendorId(const cec_command &command);
- virtual bool HandleVendorCommand(const cec_command &command);
- virtual bool HandleGiveDeckStatus(const cec_command &command);
+
+ virtual void SetLGDeckStatus(void);
bool m_bAwaitingReceiveFailed;
bool m_bSLEnabled;
- bool m_bVendorIdSent;
+ bool m_bPowerStateReset;
};
};
using namespace CEC;
-CMutex::CMutex(void)
+CMutex::CMutex(bool bRecursive /* = true */)
{
- pthread_mutex_init(&m_mutex, NULL);
+ pthread_mutex_init(&m_mutex, bRecursive ? GetMutexAttribute() : NULL);
}
CMutex::~CMutex(void)
pthread_mutex_unlock(&m_mutex);
}
+static pthread_mutexattr_t g_mutexAttr;
+pthread_mutexattr_t *CMutex::GetMutexAttribute()
+{
+ static bool bAttributeInitialised = false;
+ if (!bAttributeInitialised)
+ {
+ pthread_mutexattr_init(&g_mutexAttr);
+ pthread_mutexattr_settype(&g_mutexAttr, PTHREAD_MUTEX_RECURSIVE);
+ bAttributeInitialised = true;
+ }
+ return &g_mutexAttr;
+}
+
CLockObject::CLockObject(CMutex *mutex, bool bTryLock /* = false */) :
m_mutex(mutex)
{
class CMutex
{
public:
- CMutex(void);
+ CMutex(bool bRecursive = true);
virtual ~CMutex(void);
bool TryLock(void);
void Unlock(void);
pthread_mutex_t m_mutex;
+
+ private:
+ static pthread_mutexattr_t *GetMutexAttribute();
};
class CLockObject