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