Close();
}
-bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */)
{
+ bool bReturn(false);
uint64_t iNow = GetTimeMs();
- uint64_t iTimeout = iNow + iTimeoutMs;
-
- CLockObject lock(m_mutex);
+ uint64_t iTarget = iTimeoutMs > 0 ? iNow + iTimeoutMs : iNow + CEC_DEFAULT_TRANSMIT_WAIT;
- if (!m_port)
+ /* try to ping the adapter */
+ bool bPinged(false);
+ unsigned iPingTry(0);
+ while (iNow < iTarget && (bPinged = PingAdapter()) == false)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
- return false;
+ CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
+ Sleep(500);
+ iNow = GetTimeMs();
}
- if (IsOpen())
+ /* try to read the firmware version */
+ m_iFirmwareVersion = CEC_FW_VERSION_UNKNOWN;
+ unsigned iFwVersionTry(0);
+ while (bPinged && iNow < iTarget && (m_iFirmwareVersion = GetFirmwareVersion()) == CEC_FW_VERSION_UNKNOWN)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "port is already open");
- return true;
+ CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond with a correct firmware version (try %d)", ++iFwVersionTry);
+ Sleep(500);
+ iNow = GetTimeMs();
}
- CStdString strError;
- bool bConnected(false);
- while (!bConnected && iNow < iTimeout)
+ if (m_iFirmwareVersion >= 2)
{
- if ((bConnected = m_port->Open(iTimeout)) == false)
+ /* try to set controlled mode */
+ unsigned iControlledTry(0);
+ bool bControlled(false);
+ while (iNow < iTarget && (bControlled = SetControlledMode(true)) == false)
{
- strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
- Sleep(250);
+ CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
+ Sleep(500);
iNow = GetTimeMs();
}
+ bReturn = bControlled;
}
+ else
+ bReturn = true;
- if (!bConnected)
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, strError);
- return false;
- }
+ return bReturn;
+}
- CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */)
+{
+ uint64_t iNow = GetTimeMs();
+ uint64_t iTimeout = iNow + iTimeoutMs;
- //clear any input bytes
- uint8_t buff[1024];
- while (m_port->Read(buff, 1024, 100) > 0)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
- Sleep(250);
+ CLockObject lock(m_mutex);
+
+ if (!m_port)
+ {
+ CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
+ return false;
+ }
+
+ if (IsOpen())
+ {
+ CLibCEC::AddLog(CEC_LOG_ERROR, "port is already open");
+ return true;
+ }
+
+ m_callback = cb;
+ CStdString strError;
+ bool bConnected(false);
+ while (!bConnected && iNow < iTimeout)
+ {
+ if ((bConnected = m_port->Open(iTimeout)) == false)
+ {
+ strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
+ Sleep(250);
+ iNow = GetTimeMs();
+ }
+ }
+
+ if (!bConnected)
+ {
+ CLibCEC::AddLog(CEC_LOG_ERROR, strError);
+ return false;
+ }
+
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+
+ //clear any input bytes
+ uint8_t buff[1024];
+ while (m_port->Read(buff, 1024, 100) > 0)
+ {
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
+ Sleep(250);
+ }
}
if (CreateThread())
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
- return true;
- }
- else
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+ if (!CheckAdapter())
+ {
+ StopThread();
+ CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+ }
+ else
+ {
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
+ return true;
+ }
}
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
return false;
}
void CUSBCECAdapterCommunication::Close(void)
{
+ SetAckMask(0);
CLockObject lock(m_mutex);
m_rcvCondition.Broadcast();
StopThread();
void *CUSBCECAdapterCommunication::Process(void)
{
+ cec_command command;
+ bool bCommandReceived(false);
while (!IsStopped())
{
- ReadFromDevice(50);
- Sleep(5);
- WriteNextCommand();
+ {
+ CLockObject lock(m_mutex);
+ ReadFromDevice(50);
+ bCommandReceived = m_callback && Read(command, 0);
+ }
+
+ /* push the next command to the callback method if there is one */
+ if (!IsStopped() && bCommandReceived)
+ m_callback->OnCommandReceived(command);
+
+ if (!IsStopped())
+ {
+ Sleep(5);
+ WriteNextCommand();
+ }
}
CCECAdapterMessage *msg(NULL);
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 retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
+ if (!IsRunning())
+ return retVal;
CCECAdapterMessage *output = new CCECAdapterMessage(data);
bool CUSBCECAdapterCommunication::Write(CCECAdapterMessage *data)
{
- bool bReturn(false);
-
CLockObject lock(data->mutex);
data->state = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
m_outBuffer.Push(data);
data->condition.Wait(data->mutex);
- if (data->state != ADAPTER_MESSAGE_STATE_SENT)
+ if ((data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT_ACKED) ||
+ (!data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT))
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "command was not sent");
- }
- else if (data->expectControllerAck)
- {
- bReturn = WaitForAck(*data);
- if (bReturn)
- {
- if (data->isTransmission)
- data->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
- }
- else
- {
- data->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
- }
- }
- else
- {
- bReturn = true;
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "command was not %s", data->state == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED ? "acked" : "sent");
+ return false;
}
- return bReturn;
+ return true;
}
bool CUSBCECAdapterCommunication::Read(cec_command &command, uint32_t iTimeout)
{
+ if (!IsRunning())
+ return false;
+
CCECAdapterMessage msg;
if (Read(msg, iTimeout))
{
if (!m_inBuffer.Pop(buf))
{
- if (!m_rcvCondition.Wait(m_mutex, iTimeout))
+ if (iTimeout == 0 || !m_rcvCondition.Wait(m_mutex, iTimeout))
return false;
m_inBuffer.Pop(buf);
}
if (buf)
{
msg.packet = buf->packet;
- msg.state = msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
+ msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
delete buf;
return true;
}
uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
{
+ CLockObject lock(m_mutex);
uint16_t iReturn(m_iFirmwareVersion);
if (!IsRunning())
return iReturn;
output->expectControllerAck = false;
SendMessageToAdapter(output);
+ bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT;
delete output;
+ if (!bWriteOk)
+ {
+ CLibCEC::AddLog(CEC_LOG_ERROR, "could not request the firmware version");
+ return iReturn;
+ }
+ Sleep(250); // TODO ReadFromDevice() isn't waiting for the timeout to pass on win32
+ ReadFromDevice(CEC_DEFAULT_TRANSMIT_WAIT, 5 /* start + msgcode + 2 bytes for fw version + end */);
CCECAdapterMessage input;
- if (!Read(input, CEC_DEFAULT_TRANSMIT_WAIT) || input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3)
- CLibCEC::AddLog(CEC_LOG_ERROR, "no or invalid firmware version (size = %d, message = %d)", input.Size(), input.Message());
+ if (Read(input, 0))
+ {
+ if (input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3)
+ CLibCEC::AddLog(CEC_LOG_ERROR, "invalid firmware version (size = %d, message = %d)", input.Size(), input.Message());
+ else
+ {
+ m_iFirmwareVersion = (input[1] << 8 | input[2]);
+ iReturn = m_iFirmwareVersion;
+ }
+ }
else
{
- m_iFirmwareVersion = (input[1] << 8 | input[2]);
- iReturn = m_iFirmwareVersion;
+ CLibCEC::AddLog(CEC_LOG_ERROR, "no firmware version received");
}
}
uint8_t iPacketsLeft(message.Size() / 4);
int64_t iNow = GetTimeMs();
- int64_t iTargetTime = iNow + message.transmit_timeout;
+ int64_t iTargetTime = iNow + (message.transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : message.transmit_timeout);
- while (!bTransmitSucceeded && !bError && (message.transmit_timeout == 0 || iNow < iTargetTime))
+ while (!bTransmitSucceeded && !bError && iNow < iTargetTime)
{
+ ReadFromDevice(50);
CCECAdapterMessage msg;
- int32_t iWait = (int32_t)(iTargetTime - iNow);
- if (iWait <= 5 || message.transmit_timeout <= 5)
- iWait = CEC_DEFAULT_TRANSMIT_WAIT;
-
- if (!Read(msg, iWait))
+ if (!Read(msg, 0))
{
iNow = GetTimeMs();
continue;
}
}
+ message.state = bTransmitSucceeded && !bError ?
+ ADAPTER_MESSAGE_STATE_SENT_ACKED :
+ ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+
return bTransmitSucceeded && !bError;
}
}
}
-bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
{
ssize_t iBytesRead;
uint8_t buff[256];
if (!m_port)
return false;
+ if (iSize > 256)
+ iSize = 256;
CLockObject lock(m_mutex);
- iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
+ iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
if (iBytesRead < 0 || iBytesRead > 256)
{
CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
{
CLibCEC::AddLog(CEC_LOG_DEBUG, "command sent");
msg->state = ADAPTER_MESSAGE_STATE_SENT;
+
+ if (msg->expectControllerAck)
+ {
+ if (!WaitForAck(*msg))
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
+ }
}
msg->condition.Signal();
}