#include "USBCECAdapterMessageQueue.h"
#include "../platform/sockets/serialport.h"
#include "../platform/util/timeutils.h"
+#include "../platform/util/util.h"
+#include "../platform/util/edid.h"
+#include "../platform/adl/adl-edid.h"
+#include "../platform/nvidia/nv-edid.h"
#include "../LibCEC.h"
#include "../CECProcessor.h"
for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
m_bWaitingForAck[iPtr] = false;
m_port = new CSerialPort(strPort, iBaudRate);
+ m_commands = new CUSBCECAdapterCommands(this);
}
CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
{
Close();
- delete m_commands;
- delete m_adapterMessageQueue;
- delete m_port;
+ DELETE_AND_NULL(m_commands);
+ DELETE_AND_NULL(m_adapterMessageQueue);
+ DELETE_AND_NULL(m_port);
+}
+
+void CUSBCECAdapterCommunication::ResetMessageQueue(void)
+{
+ DELETE_AND_NULL(m_adapterMessageQueue);
+ m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
+ m_adapterMessageQueue->CreateThread();
}
bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
return true;
}
- /* adapter commands */
- if (!m_commands)
- m_commands = new CUSBCECAdapterCommands(this);
-
- if (!m_adapterMessageQueue)
- {
- m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
- m_adapterMessageQueue->CreateThread();
- }
+ ResetMessageQueue();
/* try to open the connection */
CStdString strError;
if (!bConnectionOpened)
{
LIB_CEC->AddLog(CEC_LOG_ERROR, strError);
+
+ if (m_port->GetErrorNumber() == EACCES)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"No permission to open the device";
+ LIB_CEC->Alert(CEC_ALERT_PERMISSION_ERROR, param);
+ }
+ else if (m_port->GetErrorNumber() == EBUSY)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"The serial port is busy. Only one program can access the device directly.";
+ LIB_CEC->Alert(CEC_ALERT_PORT_BUSY, param);
+ }
return false;
}
ClearInputBytes();
}
+ // always start by setting the ackmask to 0, to clear previous values
+ SetAckMask(0);
+
if (!CreateThread())
{
bConnectionOpened = false;
CLockObject lock(m_mutex);
/* set the ackmask to 0 before closing the connection */
- if (IsRunning() && m_port->IsOpen() && m_port->GetErrorNumber() == 0)
+ if (IsOpen() && m_port->GetErrorNumber() == 0)
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
SetAckMask(0);
m_adapterMessageQueue->Clear();
/* stop and delete the ping thread */
- if (m_pingThread)
- m_pingThread->StopThread(0);
- delete m_pingThread;
- m_pingThread = NULL;
+ DELETE_AND_NULL(m_pingThread);
/* close and delete the com port connection */
if (m_port)
bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
{
CLockObject adapterLock(m_mutex);
- if (!m_port->IsOpen())
+ if (!IsOpen())
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str());
message->state = ADAPTER_MESSAGE_STATE_ERROR;
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
message->state = ADAPTER_MESSAGE_STATE_ERROR;
- Close();
+ // this will trigger an alert in the reader thread
+ m_port->Close();
return false;
}
/* read from the serial port */
{
CLockObject lock(m_mutex);
- if (!m_port || !m_port->IsOpen())
+ if (!IsOpen())
return false;
iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage ¶ms, bool bIsRetry /* = false */)
{
- if (!m_port || !m_port->IsOpen() ||
- !m_adapterMessageQueue)
+ if (!IsOpen() || !m_adapterMessageQueue)
return NULL;
/* create the adapter message for this command */
/* write the command */
if (!m_adapterMessageQueue->Write(output))
{
+ // this will trigger an alert in the reader thread
if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
- {
- libcec_parameter param;
- param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
- LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
-
- Close();
- }
+ m_port->Close();
return output;
}
else
{
if (m_port->IsOpen() && m_commands->StartBootloader())
{
- Close();
+ m_port->Close();
return true;
}
return false;
bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
{
- if (m_iAckMask == iMask)
- return true;
+ {
+ CLockObject lock(m_mutex);
+ if (m_iAckMask == iMask)
+ return true;
+ }
- if (m_port && m_port->IsOpen() && m_commands->SetAckMask(iMask))
+ if (IsOpen() && m_commands->SetAckMask(iMask))
{
+ CLockObject lock(m_mutex);
m_iAckMask = iMask;
return true;
}
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "couldn't change the ackmask: the connection is closed");
return false;
}
uint16_t CUSBCECAdapterCommunication::GetAckMask(void)
{
+ CLockObject lock(m_mutex);
return m_iAckMask;
}
bool CUSBCECAdapterCommunication::PingAdapter(void)
{
- return m_port->IsOpen() ? m_commands->PingAdapter() : false;
+ return IsOpen() ? m_commands->PingAdapter() : false;
}
uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
{
- return m_commands->GetFirmwareVersion();
+ return m_commands ? m_commands->GetFirmwareVersion() : CEC_FW_VERSION_UNKNOWN;
}
uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
{
- return m_commands->RequestBuildDate();
+ return IsOpen() ? m_commands->RequestBuildDate() : m_commands ? m_commands->GetPersistedBuildDate() : 0;
}
bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE;
}
-bool CUSBCECAdapterCommunication::PersistConfiguration(libcec_configuration *configuration)
+bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration &configuration)
{
- return m_port->IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
+ return IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
}
-bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration *configuration)
+bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration &configuration)
{
- return m_port->IsOpen() ? m_commands->GetConfiguration(configuration) : false;
+ return IsOpen() ? m_commands->GetConfiguration(configuration) : false;
}
CStdString CUSBCECAdapterCommunication::GetPortName(void)
bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
{
- return m_port->IsOpen() ? m_commands->SetControlledMode(controlled) : false;
+ return IsOpen() ? m_commands->SetControlledMode(controlled) : false;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetPhysicalAddress(void)
+{
+ uint16_t iPA(0);
+
+ // try to get the PA from ADL
+#if defined(HAS_ADL_EDID_PARSER)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via ADL", __FUNCTION__);
+ CADLEdidParser adl;
+ iPA = adl.GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - ADL returned physical address %04x", __FUNCTION__, iPA);
+ }
+#endif
+
+ // try to get the PA from the nvidia driver
+#if defined(HAS_NVIDIA_EDID_PARSER)
+ if (iPA == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via nvidia driver", __FUNCTION__);
+ CNVEdidParser nv;
+ iPA = nv.GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - nvidia driver returned physical address %04x", __FUNCTION__, iPA);
+ }
+#endif
+
+ // try to get the PA from the OS
+ if (iPA == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address from the OS", __FUNCTION__);
+ iPA = CEDIDParser::GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - OS returned physical address %04x", __FUNCTION__, iPA);
+ }
+
+ return iPA;
}
void *CAdapterPingThread::Process(void)