cec: return false when SetHDMIPort() is called with invalid arguments
[deb_libcec.git] / src / lib / adapter / USBCECAdapterCommunication.cpp
CommitLineData
a8f0bd18
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
b492c10e 4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
a8f0bd18
LOK
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
7bb4ed43 33#include "USBCECAdapterCommunication.h"
a75e3a5a
LOK
34#include "USBCECAdapterCommands.h"
35#include "USBCECAdapterMessageQueue.h"
ba65909d
LOK
36#include "../platform/sockets/serialport.h"
37#include "../platform/util/timeutils.h"
5477a250 38#include "../LibCEC.h"
7bb4ed43 39#include "../CECProcessor.h"
a8f0bd18
LOK
40
41using namespace std;
42using namespace CEC;
f00ff009 43using namespace PLATFORM;
a8f0bd18 44
ae54110f
LOK
45#define CEC_ADAPTER_PING_TIMEOUT 15000
46
b32ffd87 47CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
a75e3a5a 48 IAdapterCommunication(callback),
12027dbe 49 m_port(NULL),
1fc16cfd 50 m_iLineTimeout(0),
a75e3a5a 51 m_lastPollDestination(CECDEVICE_UNKNOWN),
56e53c14 52 m_bInitialised(false),
a75e3a5a
LOK
53 m_pingThread(NULL),
54 m_commands(NULL),
55 m_adapterMessageQueue(NULL)
a8f0bd18 56{
4164923b
LOK
57 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
58 m_bWaitingForAck[iPtr] = false;
089f0e9d 59 m_port = new CSerialPort(strPort, iBaudRate);
a8f0bd18
LOK
60}
61
a75e3a5a 62CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
a8f0bd18 63{
a75e3a5a
LOK
64 Close();
65 delete m_commands;
66 delete m_adapterMessageQueue;
e4a53f8e 67 delete m_port;
efed01e1 68}
a8f0bd18 69
b32ffd87 70bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
efed01e1 71{
a75e3a5a 72 bool bConnectionOpened(false);
2c780401 73 {
efed01e1
LOK
74 CLockObject lock(m_mutex);
75
a75e3a5a 76 /* we need the port settings here */
efed01e1
LOK
77 if (!m_port)
78 {
79 CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
a75e3a5a 80 return bConnectionOpened;
efed01e1
LOK
81 }
82
a75e3a5a 83 /* return true when the port is already open */
efed01e1
LOK
84 if (IsOpen())
85 {
a75e3a5a 86 CLibCEC::AddLog(CEC_LOG_WARNING, "port is already open");
efed01e1
LOK
87 return true;
88 }
89
a75e3a5a
LOK
90 /* adapter commands */
91 if (!m_commands)
92 m_commands = new CUSBCECAdapterCommands(this);
93
94 if (!m_adapterMessageQueue)
a8559e01 95 {
a75e3a5a 96 m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
a8559e01
LOK
97 m_adapterMessageQueue->CreateThread();
98 }
a75e3a5a
LOK
99
100 /* try to open the connection */
efed01e1 101 CStdString strError;
a75e3a5a
LOK
102 CTimeout timeout(iTimeoutMs);
103 while (!bConnectionOpened && timeout.TimeLeft() > 0)
efed01e1 104 {
a75e3a5a 105 if ((bConnectionOpened = m_port->Open(timeout.TimeLeft())) == false)
efed01e1
LOK
106 {
107 strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
108 Sleep(250);
efed01e1 109 }
a75e3a5a 110 /* and retry every 250ms until the timeout passed */
efed01e1
LOK
111 }
112
a75e3a5a
LOK
113 /* return false when we couldn't connect */
114 if (!bConnectionOpened)
efed01e1
LOK
115 {
116 CLibCEC::AddLog(CEC_LOG_ERROR, strError);
117 return false;
118 }
119
120 CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
a75e3a5a 121 ClearInputBytes();
2c780401 122 }
a8f0bd18 123
a75e3a5a 124 if (!CreateThread())
a8f0bd18 125 {
a75e3a5a
LOK
126 bConnectionOpened = false;
127 CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
128 }
129 else if (!bSkipChecks && !CheckAdapter())
130 {
131 bConnectionOpened = false;
befa3a23 132 CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
befa3a23 133 }
f80cd208 134 else if (bStartListening)
befa3a23 135 {
a75e3a5a
LOK
136 /* start a ping thread, that will ping the adapter every 15 seconds
137 if it doesn't receive any ping for 30 seconds, it'll switch to auto mode */
56e53c14 138 m_pingThread = new CAdapterPingThread(this, CEC_ADAPTER_PING_TIMEOUT);
a75e3a5a 139 if (m_pingThread->CreateThread())
efed01e1 140 {
a75e3a5a 141 bConnectionOpened = true;
efed01e1
LOK
142 }
143 else
144 {
a75e3a5a
LOK
145 bConnectionOpened = false;
146 CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a ping thread");
efed01e1 147 }
a8f0bd18 148 }
a75e3a5a
LOK
149
150 if (!bConnectionOpened || !bStartListening)
151 StopThread(0);
a8f0bd18 152
a75e3a5a 153 return bConnectionOpened;
a8f0bd18
LOK
154}
155
7bb4ed43 156void CUSBCECAdapterCommunication::Close(void)
a8f0bd18 157{
0b714871
LOK
158 /* stop the reader thread */
159 StopThread(0);
160
161 CLockObject lock(m_mutex);
162
a75e3a5a 163 /* set the ackmask to 0 before closing the connection */
0b714871 164 if (IsRunning() && m_port->IsOpen() && m_port->GetErrorNumber() == 0)
a75e3a5a 165 {
0b714871 166 CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
a75e3a5a
LOK
167 SetAckMask(0);
168 if (m_commands->GetFirmwareVersion() >= 2)
169 SetControlledMode(false);
170 }
171
a8559e01
LOK
172 m_adapterMessageQueue->Clear();
173
a75e3a5a 174 /* stop and delete the ping thread */
56e53c14
LOK
175 if (m_pingThread)
176 m_pingThread->StopThread(0);
177 delete m_pingThread;
178 m_pingThread = NULL;
a8f0bd18 179
a75e3a5a 180 /* close and delete the com port connection */
e4a53f8e
LOK
181 if (m_port)
182 m_port->Close();
0b714871
LOK
183
184 libcec_parameter param;
185 CLibCEC::Alert(CEC_ALERT_CONNECTION_LOST, param);
a8f0bd18
LOK
186}
187
33dd87a9 188cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout)
7bb4ed43
LOK
189{
190 cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
9f68cc28
LOK
191 if (!IsRunning())
192 return retVal;
7bb4ed43 193
33dd87a9 194 CCECAdapterMessage *output = new CCECAdapterMessage(data, iLineTimeout);
7bb4ed43 195
a75e3a5a
LOK
196 /* mark as waiting for an ack from the destination */
197 MarkAsWaiting(data.destination);
4164923b 198
a75e3a5a 199 /* send the message */
33dd87a9 200 bRetry = (!m_adapterMessageQueue->Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
a8559e01 201 if (bRetry)
33dd87a9 202 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
7bb4ed43
LOK
203 retVal = output->state;
204
205 delete output;
206 return retVal;
207}
208
a75e3a5a 209void *CUSBCECAdapterCommunication::Process(void)
3c53ac93 210{
a75e3a5a
LOK
211 CCECAdapterMessage msg;
212 CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
5dcf9f25 213
a75e3a5a 214 while (!IsStopped())
5dcf9f25 215 {
a75e3a5a
LOK
216 /* read from the serial port */
217 if (!ReadFromDevice(50, 5))
218 break;
219
220 /* TODO sleep 5 ms so other threads can get a lock */
221 Sleep(5);
5dcf9f25
LOK
222 }
223
a75e3a5a
LOK
224 m_adapterMessageQueue->Clear();
225 CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread ended");
226 return NULL;
a8f0bd18
LOK
227}
228
a75e3a5a 229bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage &msg)
a8f0bd18 230{
a75e3a5a
LOK
231 bool bIsError(msg.IsError());
232 cec_adapter_messagecode messageCode(msg.Message());
233 CLockObject lock(m_mutex);
9f68cc28 234
a75e3a5a 235 if (messageCode == MSGCODE_FRAME_START && msg.IsACK())
a8f0bd18 236 {
a75e3a5a
LOK
237 m_lastPollDestination = msg.Destination();
238 if (msg.Destination() < CECDEVICE_BROADCAST)
a8f0bd18 239 {
a75e3a5a
LOK
240 if (!m_bWaitingForAck[msg.Destination()] && !msg.IsEOM())
241 {
242 if (m_callback)
243 m_callback->HandlePoll(msg.Initiator(), msg.Destination());
244 }
245 else
246 m_bWaitingForAck[msg.Destination()] = false;
a8f0bd18 247 }
7bb4ed43 248 }
a75e3a5a 249 else if (messageCode == MSGCODE_RECEIVE_FAILED)
7bb4ed43 250 {
a75e3a5a
LOK
251 /* hack to suppress warnings when an LG is polling */
252 if (m_lastPollDestination != CECDEVICE_UNKNOWN)
253 bIsError = m_callback->HandleReceiveFailed(m_lastPollDestination);
7bb4ed43 254 }
a8f0bd18 255
a75e3a5a 256 return bIsError;
a8f0bd18 257}
2abe74eb 258
a75e3a5a 259void CUSBCECAdapterCommunication::MarkAsWaiting(const cec_logical_address dest)
2abe74eb 260{
a75e3a5a
LOK
261 /* mark as waiting for an ack from the destination */
262 if (dest < CECDEVICE_BROADCAST)
7bb4ed43 263 {
a75e3a5a
LOK
264 CLockObject lock(m_mutex);
265 m_bWaitingForAck[dest] = true;
7bb4ed43 266 }
7bb4ed43
LOK
267}
268
b32ffd87 269void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout /* = CEC_CLEAR_INPUT_DEFAULT_WAIT */)
1fc16cfd 270{
a75e3a5a
LOK
271 CTimeout timeout(iTimeout);
272 uint8_t buff[1024];
273 ssize_t iBytesRead(0);
a4d657c7 274 bool bGotMsgEnd(true);
1fc16cfd 275
a75e3a5a 276 while (timeout.TimeLeft() > 0 && ((iBytesRead = m_port->Read(buff, 1024, 5)) > 0 || !bGotMsgEnd))
1fc16cfd 277 {
a4d657c7 278 bGotMsgEnd = false;
a75e3a5a
LOK
279 /* if something was received, wait for MSGEND */
280 for (ssize_t iPtr = 0; iPtr < iBytesRead; iPtr++)
281 bGotMsgEnd = buff[iPtr] == MSGEND;
1fc16cfd 282 }
1fc16cfd
LOK
283}
284
7bb4ed43 285bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
a171d2fd 286{
16459df9 287 bool bReturn(true);
a75e3a5a 288 bool bChanged(false);
089f0e9d 289
a75e3a5a 290 /* only send the command if the timeout changed */
089f0e9d 291 {
a75e3a5a
LOK
292 CLockObject lock(m_mutex);
293 bChanged = (m_iLineTimeout != iTimeout);
294 m_iLineTimeout = iTimeout;
089f0e9d
LOK
295 }
296
a75e3a5a
LOK
297 if (bChanged)
298 bReturn = m_commands->SetLineTimeout(iTimeout);
a171d2fd 299
a75e3a5a 300 return bReturn;
f9e01dac
LOK
301}
302
a75e3a5a 303bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
5dcf9f25 304{
a75e3a5a
LOK
305 CLockObject adapterLock(m_mutex);
306 if (!m_port->IsOpen())
307 {
0b714871 308 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());
a75e3a5a
LOK
309 message->state = ADAPTER_MESSAGE_STATE_ERROR;
310 return false;
311 }
5dcf9f25 312
a75e3a5a
LOK
313 /* write the message */
314 if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
315 {
0b714871 316 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());
a75e3a5a 317 message->state = ADAPTER_MESSAGE_STATE_ERROR;
a8559e01 318 Close();
cb4ee028 319 return false;
a75e3a5a 320 }
cb4ee028 321
a75e3a5a
LOK
322 CLibCEC::AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
323 message->state = ADAPTER_MESSAGE_STATE_SENT;
324 return true;
c214d197 325}
b057edad 326
a75e3a5a 327bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
12a36be9 328{
a75e3a5a
LOK
329 ssize_t iBytesRead(0);
330 uint8_t buff[256];
331 if (iSize > 256)
332 iSize = 256;
12a36be9 333
a75e3a5a 334 /* read from the serial port */
12a36be9 335 {
a75e3a5a 336 CLockObject lock(m_mutex);
0b714871 337 if (!m_port || !m_port->IsOpen())
a75e3a5a 338 return false;
a8559e01 339
a75e3a5a 340 iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
a8559e01
LOK
341
342 if (m_port->GetErrorNumber())
343 {
344 CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
345 m_port->Close();
346 return false;
347 }
12a36be9
LOK
348 }
349
a75e3a5a 350 if (iBytesRead < 0 || iBytesRead > 256)
a75e3a5a 351 return false;
a75e3a5a 352 else if (iBytesRead > 0)
12a36be9 353 {
a75e3a5a
LOK
354 /* add the data to the current frame */
355 m_adapterMessageQueue->AddData(buff, iBytesRead);
12a36be9
LOK
356 }
357
a75e3a5a 358 return true;
b057edad
BL
359}
360
a75e3a5a 361CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage &params, bool bIsRetry /* = false */)
c214d197 362{
a75e3a5a
LOK
363 if (!m_port || !m_port->IsOpen() ||
364 !m_adapterMessageQueue)
365 return NULL;
c214d197 366
a75e3a5a
LOK
367 /* create the adapter message for this command */
368 CCECAdapterMessage *output = new CCECAdapterMessage;
369 output->PushBack(MSGSTART);
370 output->PushEscaped((uint8_t)msgCode);
371 output->Append(params);
372 output->PushBack(MSGEND);
12a36be9 373
a75e3a5a
LOK
374 /* write the command */
375 if (!m_adapterMessageQueue->Write(output))
12a36be9 376 {
0b714871
LOK
377 if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
378 Close();
a75e3a5a 379 return output;
12a36be9 380 }
a75e3a5a 381 else
12a36be9 382 {
ee090252
LOK
383 if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED &&
384 msgCode != MSGCODE_GET_BUILDDATE /* same messagecode value had a different meaning in older fw builds */)
a75e3a5a
LOK
385 {
386 /* if the controller reported that the command was rejected, and we didn't send the command
387 to set controlled mode, then the controller probably switched to auto mode. set controlled
388 mode and retry */
389 CLibCEC::AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
390 delete output;
391 if (SetControlledMode(true))
392 return SendCommand(msgCode, params, true);
393 }
12a36be9 394 }
12a36be9 395
a75e3a5a 396 return output;
c214d197
LOK
397}
398
b32ffd87 399bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
12a36be9 400{
a75e3a5a
LOK
401 bool bReturn(false);
402 CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
12a36be9 403
a75e3a5a
LOK
404 /* try to ping the adapter */
405 bool bPinged(false);
406 unsigned iPingTry(0);
407 while (timeout.TimeLeft() > 0 && (bPinged = PingAdapter()) == false)
12a36be9 408 {
a75e3a5a
LOK
409 CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
410 CEvent::Sleep(500);
12a36be9 411 }
c214d197 412
a75e3a5a
LOK
413 /* try to read the firmware version */
414 if (bPinged && timeout.TimeLeft() > 0 && m_commands->RequestFirmwareVersion() >= 2)
12a36be9 415 {
a75e3a5a
LOK
416 /* try to set controlled mode for v2+ firmwares */
417 unsigned iControlledTry(0);
418 bool bControlled(false);
419 while (timeout.TimeLeft() > 0 && (bControlled = SetControlledMode(true)) == false)
420 {
421 CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
422 CEvent::Sleep(500);
423 }
424 bReturn = bControlled;
12a36be9 425 }
a75e3a5a
LOK
426 else
427 bReturn = true;
c214d197 428
baabc020
LOK
429 /* try to read the build date */
430 m_commands->RequestBuildDate();
431
a75e3a5a
LOK
432 SetInitialised(bReturn);
433 return bReturn;
c214d197
LOK
434}
435
a75e3a5a 436bool CUSBCECAdapterCommunication::IsOpen(void)
12a36be9 437{
a75e3a5a
LOK
438 /* thread is not being stopped, the port is open and the thread is running */
439 return !IsStopped() && m_port->IsOpen() && IsRunning();
12a36be9
LOK
440}
441
a75e3a5a 442CStdString CUSBCECAdapterCommunication::GetError(void) const
c214d197 443{
a75e3a5a 444 return m_port->GetError();
c214d197
LOK
445}
446
a75e3a5a 447void CUSBCECAdapterCommunication::SetInitialised(bool bSetTo /* = true */)
12a36be9
LOK
448{
449 CLockObject lock(m_mutex);
a75e3a5a 450 m_bInitialised = bSetTo;
12a36be9
LOK
451}
452
a75e3a5a 453bool CUSBCECAdapterCommunication::IsInitialised(void)
c214d197
LOK
454{
455 CLockObject lock(m_mutex);
a75e3a5a 456 return m_bInitialised;
c214d197
LOK
457}
458
a75e3a5a 459bool CUSBCECAdapterCommunication::StartBootloader(void)
12a36be9 460{
0b714871 461 return m_port->IsOpen() ? m_commands->StartBootloader() : false;
12a36be9
LOK
462}
463
a75e3a5a 464bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
13fd6a66 465{
0b714871 466 return m_port->IsOpen() ? m_commands->SetAckMask(iMask) : false;
13fd6a66 467}
ef7696f5 468
a75e3a5a 469bool CUSBCECAdapterCommunication::PingAdapter(void)
6729ac71 470{
0b714871 471 return m_port->IsOpen() ? m_commands->PingAdapter() : false;
6729ac71
LOK
472}
473
a75e3a5a 474uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
ef7696f5 475{
a75e3a5a 476 return m_commands->GetFirmwareVersion();
ef7696f5
LOK
477}
478
b2f56d35
LOK
479uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
480{
481 return m_commands->RequestBuildDate();
482}
483
a75e3a5a 484bool CUSBCECAdapterCommunication::PersistConfiguration(libcec_configuration *configuration)
ef7696f5 485{
0b714871 486 return m_port->IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
ef7696f5
LOK
487}
488
a75e3a5a 489bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration *configuration)
ef7696f5 490{
0b714871 491 return m_port->IsOpen() ? m_commands->GetConfiguration(configuration) : false;
ef7696f5
LOK
492}
493
cba904a6
LOK
494CStdString CUSBCECAdapterCommunication::GetPortName(void)
495{
a75e3a5a 496 return m_port->GetName();
c9c282a4 497}
d4db0c6f 498
a75e3a5a 499bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
d4db0c6f 500{
0b714871 501 return m_port->IsOpen() ? m_commands->SetControlledMode(controlled) : false;
d4db0c6f 502}
56e53c14
LOK
503
504void *CAdapterPingThread::Process(void)
505{
506 while (!IsStopped())
507 {
508 if (m_timeout.TimeLeft() == 0)
509 {
a75e3a5a 510 /* reinit the timeout */
56e53c14 511 m_timeout.Init(CEC_ADAPTER_PING_TIMEOUT);
a75e3a5a
LOK
512
513 /* send a ping to the adapter */
514 bool bPinged(false);
515 int iFailedCounter(0);
516 while (!bPinged && iFailedCounter < 3)
517 {
518 if (!m_com->PingAdapter())
519 {
b32ffd87
LOK
520 /* sleep and retry */
521 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
a75e3a5a
LOK
522 ++iFailedCounter;
523 }
524 else
525 {
526 bPinged = true;
527 }
528 }
529
530 if (iFailedCounter == 3)
531 {
532 /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
533 CLibCEC::AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
534 m_com->StopThread(false);
535 break;
536 }
56e53c14
LOK
537 }
538
539 Sleep(500);
540 }
541 return NULL;
542}