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