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