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