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