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