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),
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),
/* 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]->GetHandler()->InitHandler();
+ bReturn = m_busDevices[CECDEVICE_TV]->InitHandler();
}
if (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;
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++)
for (unsigned int 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;
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);
void ParseCommand(cec_command &command);
bool m_bStarted;
+ bool m_bInitialised;
uint8_t m_iHDMIPort;
cec_logical_address m_iBaseDevice;
cec_command m_currentframe;
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);
}
/* handle the command */
+ ReplaceHandler(true);
bHandled = m_handler->HandleCommand(command);
/* change status to 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);
bool CCECBusDevice::RequestCecVersion(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress))
{
CStdString strLog;
bool CCECBusDevice::RequestMenuLanguage(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress) &&
!IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
{
bool CCECBusDevice::RequestOSDName(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress) &&
!IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
{
bool CCECBusDevice::RequestPhysicalAddress(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress))
{
CStdString strLog;
bool CCECBusDevice::RequestPowerStatus(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress) &&
!IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
{
bool CCECBusDevice::RequestVendorId(void)
{
bool bReturn(false);
+
if (!MyLogicalAddressContains(m_iLogicalAddress))
{
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_mutex);
- 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->GetVendorId() != CEC_VENDOR_UNKNOWN)
- 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);
}
}
- return bSendActiveSource ? m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress) : false;
+ if (bSendActiveSource)
+ {
+ m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+ m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+ return true;
+ }
+
+ return false;
}
bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
{
m_unsupportedFeatures.insert(opcode);
}
+
+bool CCECBusDevice::InitHandler(void)
+{
+ CLockObject lock(&m_mutex);
+ ReplaceHandler(false);
+ return m_handler->InitHandler();
+}
+
//@}
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 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_bus_device_status m_deviceStatus;
std::set<cec_opcode> m_unsupportedFeatures;
CMutex m_mutex;
+ CMutex m_handlerMutex;
};
};
m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
- m_bHandlerInited(false)
+ m_bHandlerInited(false),
+ m_iUseCounter(0)
{
}
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);
m_condition.Signal();
}
+ MarkReady();
return bHandled;
}
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);
bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */)
{
+ 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;
+ CLockObject writeLock(&m_processor->m_transmitMutex);
+ CLockObject receiveLock(&m_receiveMutex);
+ ++m_iUseCounter;
+ if (m_processor->Transmit(command))
+ {
+ bReturn = bExpectResponse ?
+ m_condition.Wait(&m_receiveMutex, m_iTransmitWait) :
+ true;
+ }
+ --m_iUseCounter;
}
- return false;
+ return bReturn;
}
bool CCECCommandHandler::InitHandler(void)
}
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 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 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 HandleDeckControl(const cec_command &command);
int32_t m_iTransmitWait;
int8_t m_iTransmitRetries;
bool m_bHandlerInited;
+ uint8_t m_iUseCounter;
CMutex m_receiveMutex;
CCondition m_condition;
};