#define CEC_ADAPTER_PING_TIMEOUT 15000
-CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = 38400 */) :
+// firmware version 2
+#define CEC_LATEST_ADAPTER_FW_VERSION 2
+// firmware date Thu Apr 26 20:14:49 2012 +0000
+#define CEC_LATEST_ADAPTER_FW_DATE 0x4F99ACB9
+
+CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
IAdapterCommunication(callback),
m_port(NULL),
m_iLineTimeout(0),
m_commands(NULL),
m_adapterMessageQueue(NULL)
{
- for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
+ for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
m_bWaitingForAck[iPtr] = false;
m_port = new CSerialPort(strPort, iBaudRate);
}
Close();
delete m_commands;
delete m_adapterMessageQueue;
+ delete m_port;
}
-bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
+bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
{
bool bConnectionOpened(false);
{
m_commands = new CUSBCECAdapterCommands(this);
if (!m_adapterMessageQueue)
+ {
m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
+ m_adapterMessageQueue->CreateThread();
+ }
/* try to open the connection */
CStdString strError;
if (!bConnectionOpened || !bStartListening)
StopThread(0);
- if (!bConnectionOpened)
- {
- delete m_port;
- m_port = NULL;
- }
return bConnectionOpened;
}
void CUSBCECAdapterCommunication::Close(void)
{
+ /* stop the reader thread */
+ StopThread(0);
+
+ CLockObject lock(m_mutex);
+
/* set the ackmask to 0 before closing the connection */
- if (IsRunning())
+ if (IsRunning() && m_port->IsOpen() && m_port->GetErrorNumber() == 0)
{
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
SetAckMask(0);
if (m_commands->GetFirmwareVersion() >= 2)
SetControlledMode(false);
}
+ m_adapterMessageQueue->Clear();
+
/* stop and delete the ping thread */
if (m_pingThread)
m_pingThread->StopThread(0);
delete m_pingThread;
m_pingThread = NULL;
- /* stop the reader thread */
- StopThread(0);
-
/* close and delete the com port connection */
- delete m_port;
- m_port = NULL;
+ if (m_port)
+ m_port->Close();
+
+ libcec_parameter param;
+ CLibCEC::Alert(CEC_ALERT_CONNECTION_LOST, param);
}
-cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout /* = 3 */, uint8_t iRetryLineTimeout /* = 3 */)
+cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout)
{
cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
if (!IsRunning())
return retVal;
- CCECAdapterMessage *output = new CCECAdapterMessage(data, iMaxTries, iLineTimeout, iRetryLineTimeout);
+ CCECAdapterMessage *output = new CCECAdapterMessage(data, iLineTimeout);
/* mark as waiting for an ack from the destination */
MarkAsWaiting(data.destination);
/* send the message */
- bool bRetry(true);
- while (bRetry && ++output->tries < output->maxTries)
- {
- bRetry = (!m_adapterMessageQueue->Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
- if (bRetry)
- Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
- }
+ bRetry = (!m_adapterMessageQueue->Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
+ if (bRetry)
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
retVal = output->state;
delete output;
}
}
-void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout /* = 1000 */)
+void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout /* = CEC_CLEAR_INPUT_DEFAULT_WAIT */)
{
CTimeout timeout(iTimeout);
uint8_t buff[1024];
CLockObject adapterLock(m_mutex);
if (!m_port->IsOpen())
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "error writing command '%s' to the serial port: the connection is closed", CCECAdapterMessage::ToString(message->Message()));
+ CLibCEC::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;
return false;
}
/* write the message */
if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "error writing command '%s' to the serial port: %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetError().c_str());
+ CLibCEC::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();
return false;
}
/* read from the serial port */
{
CLockObject lock(m_mutex);
- if (!m_port)
+ if (!m_port || !m_port->IsOpen())
return false;
+
iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
+
+ if (m_port->GetErrorNumber())
+ {
+ CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
+ m_port->Close();
+ return false;
+ }
}
if (iBytesRead < 0 || iBytesRead > 256)
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
- StopThread(false);
return false;
- }
else if (iBytesRead > 0)
{
/* add the data to the current frame */
/* write the command */
if (!m_adapterMessageQueue->Write(output))
{
- // timed out
+ if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
+ Close();
return output;
}
else
{
- if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED)
+ if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED &&
+ msgCode != MSGCODE_GET_BUILDDATE /* same messagecode value had a different meaning in older fw builds */)
{
/* if the controller reported that the command was rejected, and we didn't send the command
to set controlled mode, then the controller probably switched to auto mode. set controlled
return output;
}
-bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
{
bool bReturn(false);
CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
else
bReturn = true;
+ /* try to read the build date */
+ m_commands->RequestBuildDate();
+
SetInitialised(bReturn);
return bReturn;
}
bool CUSBCECAdapterCommunication::StartBootloader(void)
{
- if (!IsRunning())
- return false;
-
- return m_commands->StartBootloader();
+ if (m_port->IsOpen() && m_commands->StartBootloader())
+ {
+ Close();
+ return true;
+ }
+ return false;
}
bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
{
- return m_commands->SetAckMask(iMask);
+ return m_port->IsOpen() ? m_commands->SetAckMask(iMask) : false;
}
bool CUSBCECAdapterCommunication::PingAdapter(void)
{
- return m_commands->PingAdapter();
+ return m_port->IsOpen() ? m_commands->PingAdapter() : false;
}
uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
return m_commands->GetFirmwareVersion();
}
+uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
+{
+ return m_commands->RequestBuildDate();
+}
+
+bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
+{
+ return GetFirmwareVersion() >= CEC_LATEST_ADAPTER_FW_VERSION &&
+ GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE;
+}
+
bool CUSBCECAdapterCommunication::PersistConfiguration(libcec_configuration *configuration)
{
- return m_commands->PersistConfiguration(configuration);
+ return m_port->IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
}
bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration *configuration)
{
- return m_commands->GetConfiguration(configuration);
+ return m_port->IsOpen() ? m_commands->GetConfiguration(configuration) : false;
}
CStdString CUSBCECAdapterCommunication::GetPortName(void)
bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
{
- return m_commands->SetControlledMode(controlled);
+ return m_port->IsOpen() ? m_commands->SetControlledMode(controlled) : false;
}
void *CAdapterPingThread::Process(void)
{
if (!m_com->PingAdapter())
{
- /* sleep 1 second and retry */
- Sleep(1000);
+ /* sleep and retry */
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
++iFailedCounter;
}
else