cec: set the ackmask to 0 when starting, so the earlier mask is cleared when starting...
[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
5daed059
LOK
47// firmware version 2
48#define CEC_LATEST_ADAPTER_FW_VERSION 2
49// firmware date Thu Apr 26 20:14:49 2012 +0000
50#define CEC_LATEST_ADAPTER_FW_DATE 0x4F99ACB9
51
004b8382
LOK
52#define LIB_CEC m_callback->GetLib()
53
b32ffd87 54CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
a75e3a5a 55 IAdapterCommunication(callback),
12027dbe 56 m_port(NULL),
1fc16cfd 57 m_iLineTimeout(0),
a75e3a5a 58 m_lastPollDestination(CECDEVICE_UNKNOWN),
56e53c14 59 m_bInitialised(false),
a75e3a5a
LOK
60 m_pingThread(NULL),
61 m_commands(NULL),
004b8382
LOK
62 m_adapterMessageQueue(NULL),
63 m_iAckMask(0xFFFF)
a8f0bd18 64{
d2d1660c 65 for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
4164923b 66 m_bWaitingForAck[iPtr] = false;
089f0e9d 67 m_port = new CSerialPort(strPort, iBaudRate);
a8f0bd18
LOK
68}
69
a75e3a5a 70CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
a8f0bd18 71{
a75e3a5a
LOK
72 Close();
73 delete m_commands;
74 delete m_adapterMessageQueue;
e4a53f8e 75 delete m_port;
efed01e1 76}
a8f0bd18 77
b32ffd87 78bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
efed01e1 79{
a75e3a5a 80 bool bConnectionOpened(false);
2c780401 81 {
efed01e1
LOK
82 CLockObject lock(m_mutex);
83
a75e3a5a 84 /* we need the port settings here */
efed01e1
LOK
85 if (!m_port)
86 {
004b8382 87 LIB_CEC->AddLog(CEC_LOG_ERROR, "port is NULL");
a75e3a5a 88 return bConnectionOpened;
efed01e1
LOK
89 }
90
a75e3a5a 91 /* return true when the port is already open */
efed01e1
LOK
92 if (IsOpen())
93 {
004b8382 94 LIB_CEC->AddLog(CEC_LOG_WARNING, "port is already open");
efed01e1
LOK
95 return true;
96 }
97
a75e3a5a
LOK
98 /* adapter commands */
99 if (!m_commands)
100 m_commands = new CUSBCECAdapterCommands(this);
101
102 if (!m_adapterMessageQueue)
a8559e01 103 {
a75e3a5a 104 m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
a8559e01
LOK
105 m_adapterMessageQueue->CreateThread();
106 }
a75e3a5a
LOK
107
108 /* try to open the connection */
efed01e1 109 CStdString strError;
a75e3a5a
LOK
110 CTimeout timeout(iTimeoutMs);
111 while (!bConnectionOpened && timeout.TimeLeft() > 0)
efed01e1 112 {
a75e3a5a 113 if ((bConnectionOpened = m_port->Open(timeout.TimeLeft())) == false)
efed01e1
LOK
114 {
115 strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
116 Sleep(250);
efed01e1 117 }
a75e3a5a 118 /* and retry every 250ms until the timeout passed */
efed01e1
LOK
119 }
120
a75e3a5a
LOK
121 /* return false when we couldn't connect */
122 if (!bConnectionOpened)
efed01e1 123 {
004b8382 124 LIB_CEC->AddLog(CEC_LOG_ERROR, strError);
efed01e1
LOK
125 return false;
126 }
127
004b8382 128 LIB_CEC->AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
a75e3a5a 129 ClearInputBytes();
2c780401 130 }
a8f0bd18 131
a75e3a5a 132 if (!CreateThread())
a8f0bd18 133 {
a75e3a5a 134 bConnectionOpened = false;
004b8382 135 LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a communication thread");
a75e3a5a
LOK
136 }
137 else if (!bSkipChecks && !CheckAdapter())
138 {
139 bConnectionOpened = false;
004b8382 140 LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
befa3a23 141 }
f80cd208 142 else if (bStartListening)
befa3a23 143 {
a75e3a5a
LOK
144 /* start a ping thread, that will ping the adapter every 15 seconds
145 if it doesn't receive any ping for 30 seconds, it'll switch to auto mode */
56e53c14 146 m_pingThread = new CAdapterPingThread(this, CEC_ADAPTER_PING_TIMEOUT);
a75e3a5a 147 if (m_pingThread->CreateThread())
efed01e1 148 {
a75e3a5a 149 bConnectionOpened = true;
efed01e1
LOK
150 }
151 else
152 {
a75e3a5a 153 bConnectionOpened = false;
004b8382 154 LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a ping thread");
efed01e1 155 }
a8f0bd18 156 }
a75e3a5a
LOK
157
158 if (!bConnectionOpened || !bStartListening)
159 StopThread(0);
a8f0bd18 160
a75e3a5a 161 return bConnectionOpened;
a8f0bd18
LOK
162}
163
7bb4ed43 164void CUSBCECAdapterCommunication::Close(void)
a8f0bd18 165{
0b714871
LOK
166 /* stop the reader thread */
167 StopThread(0);
168
169 CLockObject lock(m_mutex);
170
a75e3a5a 171 /* set the ackmask to 0 before closing the connection */
0b8c7eab 172 if (IsOpen() && m_port->GetErrorNumber() == 0)
a75e3a5a 173 {
004b8382 174 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
a75e3a5a
LOK
175 SetAckMask(0);
176 if (m_commands->GetFirmwareVersion() >= 2)
177 SetControlledMode(false);
178 }
179
a8559e01
LOK
180 m_adapterMessageQueue->Clear();
181
a75e3a5a 182 /* stop and delete the ping thread */
56e53c14
LOK
183 if (m_pingThread)
184 m_pingThread->StopThread(0);
185 delete m_pingThread;
186 m_pingThread = NULL;
a8f0bd18 187
a75e3a5a 188 /* close and delete the com port connection */
e4a53f8e
LOK
189 if (m_port)
190 m_port->Close();
a8f0bd18
LOK
191}
192
33dd87a9 193cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout)
7bb4ed43
LOK
194{
195 cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
9f68cc28
LOK
196 if (!IsRunning())
197 return retVal;
7bb4ed43 198
33dd87a9 199 CCECAdapterMessage *output = new CCECAdapterMessage(data, iLineTimeout);
7bb4ed43 200
a75e3a5a
LOK
201 /* mark as waiting for an ack from the destination */
202 MarkAsWaiting(data.destination);
4164923b 203
a75e3a5a 204 /* send the message */
33dd87a9 205 bRetry = (!m_adapterMessageQueue->Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
a8559e01 206 if (bRetry)
33dd87a9 207 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
7bb4ed43
LOK
208 retVal = output->state;
209
210 delete output;
211 return retVal;
212}
213
a75e3a5a 214void *CUSBCECAdapterCommunication::Process(void)
3c53ac93 215{
a75e3a5a 216 CCECAdapterMessage msg;
004b8382 217 LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread started");
5dcf9f25 218
a75e3a5a 219 while (!IsStopped())
5dcf9f25 220 {
a75e3a5a
LOK
221 /* read from the serial port */
222 if (!ReadFromDevice(50, 5))
2fbffb25
LOK
223 {
224 libcec_parameter param;
225 param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
226 LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
227
a75e3a5a 228 break;
2fbffb25 229 }
a75e3a5a
LOK
230
231 /* TODO sleep 5 ms so other threads can get a lock */
232 Sleep(5);
5dcf9f25
LOK
233 }
234
a75e3a5a 235 m_adapterMessageQueue->Clear();
004b8382 236 LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread ended");
a75e3a5a 237 return NULL;
a8f0bd18
LOK
238}
239
a75e3a5a 240bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage &msg)
a8f0bd18 241{
a75e3a5a
LOK
242 bool bIsError(msg.IsError());
243 cec_adapter_messagecode messageCode(msg.Message());
244 CLockObject lock(m_mutex);
9f68cc28 245
a75e3a5a 246 if (messageCode == MSGCODE_FRAME_START && msg.IsACK())
a8f0bd18 247 {
a75e3a5a
LOK
248 m_lastPollDestination = msg.Destination();
249 if (msg.Destination() < CECDEVICE_BROADCAST)
a8f0bd18 250 {
a75e3a5a
LOK
251 if (!m_bWaitingForAck[msg.Destination()] && !msg.IsEOM())
252 {
253 if (m_callback)
254 m_callback->HandlePoll(msg.Initiator(), msg.Destination());
255 }
256 else
257 m_bWaitingForAck[msg.Destination()] = false;
a8f0bd18 258 }
7bb4ed43 259 }
a75e3a5a 260 else if (messageCode == MSGCODE_RECEIVE_FAILED)
7bb4ed43 261 {
a75e3a5a
LOK
262 /* hack to suppress warnings when an LG is polling */
263 if (m_lastPollDestination != CECDEVICE_UNKNOWN)
264 bIsError = m_callback->HandleReceiveFailed(m_lastPollDestination);
7bb4ed43 265 }
a8f0bd18 266
a75e3a5a 267 return bIsError;
a8f0bd18 268}
2abe74eb 269
a75e3a5a 270void CUSBCECAdapterCommunication::MarkAsWaiting(const cec_logical_address dest)
2abe74eb 271{
a75e3a5a
LOK
272 /* mark as waiting for an ack from the destination */
273 if (dest < CECDEVICE_BROADCAST)
7bb4ed43 274 {
a75e3a5a
LOK
275 CLockObject lock(m_mutex);
276 m_bWaitingForAck[dest] = true;
7bb4ed43 277 }
7bb4ed43
LOK
278}
279
b32ffd87 280void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout /* = CEC_CLEAR_INPUT_DEFAULT_WAIT */)
1fc16cfd 281{
a75e3a5a
LOK
282 CTimeout timeout(iTimeout);
283 uint8_t buff[1024];
284 ssize_t iBytesRead(0);
a4d657c7 285 bool bGotMsgEnd(true);
1fc16cfd 286
a75e3a5a 287 while (timeout.TimeLeft() > 0 && ((iBytesRead = m_port->Read(buff, 1024, 5)) > 0 || !bGotMsgEnd))
1fc16cfd 288 {
a4d657c7 289 bGotMsgEnd = false;
a75e3a5a
LOK
290 /* if something was received, wait for MSGEND */
291 for (ssize_t iPtr = 0; iPtr < iBytesRead; iPtr++)
292 bGotMsgEnd = buff[iPtr] == MSGEND;
1fc16cfd 293 }
1fc16cfd
LOK
294}
295
7bb4ed43 296bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
a171d2fd 297{
16459df9 298 bool bReturn(true);
a75e3a5a 299 bool bChanged(false);
089f0e9d 300
a75e3a5a 301 /* only send the command if the timeout changed */
089f0e9d 302 {
a75e3a5a
LOK
303 CLockObject lock(m_mutex);
304 bChanged = (m_iLineTimeout != iTimeout);
305 m_iLineTimeout = iTimeout;
089f0e9d
LOK
306 }
307
a75e3a5a
LOK
308 if (bChanged)
309 bReturn = m_commands->SetLineTimeout(iTimeout);
a171d2fd 310
a75e3a5a 311 return bReturn;
f9e01dac
LOK
312}
313
a75e3a5a 314bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
5dcf9f25 315{
a75e3a5a 316 CLockObject adapterLock(m_mutex);
0b8c7eab 317 if (!IsOpen())
a75e3a5a 318 {
004b8382 319 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());
a75e3a5a
LOK
320 message->state = ADAPTER_MESSAGE_STATE_ERROR;
321 return false;
322 }
5dcf9f25 323
a75e3a5a
LOK
324 /* write the message */
325 if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
326 {
004b8382 327 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());
a75e3a5a 328 message->state = ADAPTER_MESSAGE_STATE_ERROR;
a8559e01 329 Close();
cb4ee028 330 return false;
a75e3a5a 331 }
cb4ee028 332
004b8382 333 LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
a75e3a5a
LOK
334 message->state = ADAPTER_MESSAGE_STATE_SENT;
335 return true;
c214d197 336}
b057edad 337
a75e3a5a 338bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
12a36be9 339{
a75e3a5a
LOK
340 ssize_t iBytesRead(0);
341 uint8_t buff[256];
342 if (iSize > 256)
343 iSize = 256;
12a36be9 344
a75e3a5a 345 /* read from the serial port */
12a36be9 346 {
a75e3a5a 347 CLockObject lock(m_mutex);
0b8c7eab 348 if (!IsOpen())
a75e3a5a 349 return false;
a8559e01 350
a75e3a5a 351 iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
a8559e01
LOK
352
353 if (m_port->GetErrorNumber())
354 {
004b8382 355 LIB_CEC->AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
a8559e01
LOK
356 m_port->Close();
357 return false;
358 }
12a36be9
LOK
359 }
360
a75e3a5a 361 if (iBytesRead < 0 || iBytesRead > 256)
a75e3a5a 362 return false;
a75e3a5a 363 else if (iBytesRead > 0)
12a36be9 364 {
a75e3a5a
LOK
365 /* add the data to the current frame */
366 m_adapterMessageQueue->AddData(buff, iBytesRead);
12a36be9
LOK
367 }
368
a75e3a5a 369 return true;
b057edad
BL
370}
371
a75e3a5a 372CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage &params, bool bIsRetry /* = false */)
c214d197 373{
0b8c7eab 374 if (!m_port->IsOpen() || !m_adapterMessageQueue)
a75e3a5a 375 return NULL;
c214d197 376
a75e3a5a
LOK
377 /* create the adapter message for this command */
378 CCECAdapterMessage *output = new CCECAdapterMessage;
379 output->PushBack(MSGSTART);
380 output->PushEscaped((uint8_t)msgCode);
381 output->Append(params);
382 output->PushBack(MSGEND);
12a36be9 383
a75e3a5a
LOK
384 /* write the command */
385 if (!m_adapterMessageQueue->Write(output))
12a36be9 386 {
0b714871 387 if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
2fbffb25
LOK
388 {
389 libcec_parameter param;
390 param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
391 LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
392
0b714871 393 Close();
2fbffb25 394 }
a75e3a5a 395 return output;
12a36be9 396 }
a75e3a5a 397 else
12a36be9 398 {
ee090252
LOK
399 if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED &&
400 msgCode != MSGCODE_GET_BUILDDATE /* same messagecode value had a different meaning in older fw builds */)
a75e3a5a
LOK
401 {
402 /* if the controller reported that the command was rejected, and we didn't send the command
403 to set controlled mode, then the controller probably switched to auto mode. set controlled
404 mode and retry */
004b8382 405 LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
a75e3a5a
LOK
406 delete output;
407 if (SetControlledMode(true))
408 return SendCommand(msgCode, params, true);
409 }
12a36be9 410 }
12a36be9 411
a75e3a5a 412 return output;
c214d197
LOK
413}
414
b32ffd87 415bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
12a36be9 416{
a75e3a5a
LOK
417 bool bReturn(false);
418 CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
12a36be9 419
a75e3a5a
LOK
420 /* try to ping the adapter */
421 bool bPinged(false);
422 unsigned iPingTry(0);
423 while (timeout.TimeLeft() > 0 && (bPinged = PingAdapter()) == false)
12a36be9 424 {
004b8382 425 LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
a75e3a5a 426 CEvent::Sleep(500);
12a36be9 427 }
c214d197 428
a75e3a5a
LOK
429 /* try to read the firmware version */
430 if (bPinged && timeout.TimeLeft() > 0 && m_commands->RequestFirmwareVersion() >= 2)
12a36be9 431 {
a75e3a5a
LOK
432 /* try to set controlled mode for v2+ firmwares */
433 unsigned iControlledTry(0);
434 bool bControlled(false);
435 while (timeout.TimeLeft() > 0 && (bControlled = SetControlledMode(true)) == false)
436 {
004b8382 437 LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
a75e3a5a
LOK
438 CEvent::Sleep(500);
439 }
440 bReturn = bControlled;
12a36be9 441 }
a75e3a5a
LOK
442 else
443 bReturn = true;
c214d197 444
baabc020
LOK
445 /* try to read the build date */
446 m_commands->RequestBuildDate();
447
a75e3a5a
LOK
448 SetInitialised(bReturn);
449 return bReturn;
c214d197
LOK
450}
451
a75e3a5a 452bool CUSBCECAdapterCommunication::IsOpen(void)
12a36be9 453{
a75e3a5a
LOK
454 /* thread is not being stopped, the port is open and the thread is running */
455 return !IsStopped() && m_port->IsOpen() && IsRunning();
12a36be9
LOK
456}
457
a75e3a5a 458CStdString CUSBCECAdapterCommunication::GetError(void) const
c214d197 459{
a75e3a5a 460 return m_port->GetError();
c214d197
LOK
461}
462
a75e3a5a 463void CUSBCECAdapterCommunication::SetInitialised(bool bSetTo /* = true */)
12a36be9
LOK
464{
465 CLockObject lock(m_mutex);
a75e3a5a 466 m_bInitialised = bSetTo;
12a36be9
LOK
467}
468
a75e3a5a 469bool CUSBCECAdapterCommunication::IsInitialised(void)
c214d197
LOK
470{
471 CLockObject lock(m_mutex);
a75e3a5a 472 return m_bInitialised;
c214d197
LOK
473}
474
a75e3a5a 475bool CUSBCECAdapterCommunication::StartBootloader(void)
12a36be9 476{
55c75e6e
LOK
477 if (m_port->IsOpen() && m_commands->StartBootloader())
478 {
479 Close();
480 return true;
481 }
482 return false;
12a36be9
LOK
483}
484
a75e3a5a 485bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
13fd6a66 486{
004b8382
LOK
487 if (m_iAckMask == iMask)
488 return true;
489
0b8c7eab 490 if (IsOpen() && m_commands->SetAckMask(iMask))
004b8382
LOK
491 {
492 m_iAckMask = iMask;
493 return true;
494 }
495
0b8c7eab 496 LIB_CEC->AddLog(CEC_LOG_ERROR, "couldn't change the ackmask: the connection is closed");
004b8382
LOK
497 return false;
498}
499
500uint16_t CUSBCECAdapterCommunication::GetAckMask(void)
501{
502 return m_iAckMask;
13fd6a66 503}
ef7696f5 504
a75e3a5a 505bool CUSBCECAdapterCommunication::PingAdapter(void)
6729ac71 506{
0b8c7eab 507 return IsOpen() ? m_commands->PingAdapter() : false;
6729ac71
LOK
508}
509
a75e3a5a 510uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
ef7696f5 511{
0b8c7eab 512 return IsOpen() ? m_commands->GetFirmwareVersion() : CEC_FW_VERSION_UNKNOWN;
ef7696f5
LOK
513}
514
b2f56d35
LOK
515uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
516{
0b8c7eab 517 return IsOpen() ? m_commands->RequestBuildDate() : 0;
b2f56d35
LOK
518}
519
5daed059
LOK
520bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
521{
522 return GetFirmwareVersion() >= CEC_LATEST_ADAPTER_FW_VERSION &&
523 GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE;
524}
525
c0152c09 526bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration &configuration)
ef7696f5 527{
0b8c7eab 528 return IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
ef7696f5
LOK
529}
530
c0152c09 531bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration &configuration)
ef7696f5 532{
0b8c7eab 533 return IsOpen() ? m_commands->GetConfiguration(configuration) : false;
ef7696f5
LOK
534}
535
cba904a6
LOK
536CStdString CUSBCECAdapterCommunication::GetPortName(void)
537{
a75e3a5a 538 return m_port->GetName();
c9c282a4 539}
d4db0c6f 540
a75e3a5a 541bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
d4db0c6f 542{
0b8c7eab 543 return IsOpen() ? m_commands->SetControlledMode(controlled) : false;
d4db0c6f 544}
56e53c14
LOK
545
546void *CAdapterPingThread::Process(void)
547{
548 while (!IsStopped())
549 {
550 if (m_timeout.TimeLeft() == 0)
551 {
a75e3a5a 552 /* reinit the timeout */
56e53c14 553 m_timeout.Init(CEC_ADAPTER_PING_TIMEOUT);
a75e3a5a
LOK
554
555 /* send a ping to the adapter */
556 bool bPinged(false);
557 int iFailedCounter(0);
558 while (!bPinged && iFailedCounter < 3)
559 {
560 if (!m_com->PingAdapter())
561 {
b32ffd87
LOK
562 /* sleep and retry */
563 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
a75e3a5a
LOK
564 ++iFailedCounter;
565 }
566 else
567 {
568 bPinged = true;
569 }
570 }
571
572 if (iFailedCounter == 3)
573 {
574 /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
004b8382 575 m_com->LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
a75e3a5a
LOK
576 m_com->StopThread(false);
577 break;
578 }
56e53c14
LOK
579 }
580
581 Sleep(500);
582 }
583 return NULL;
584}