fixed typo in CUSBCECAdapterCommunication
[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 int64_t iNow = GetTimeMs();
264 if (m_iScheduleEepromWrite > 0 &&
265 m_iScheduleEepromWrite >= iNow)
266 {
267 m_iScheduleEepromWrite = 0;
268 m_iLastEepromWrite = iNow;
269 bWriteEeprom = true;
270 }
271 }
272
273 if (bWriteEeprom)
274 {
275 LIB_CEC->AddLog(CEC_LOG_DEBUG, "updating the eeprom (scheduled)");
276 bWriteEeprom = false;
277 if (!m_commands->WriteEEPROM())
278 {
279 // failed, retry later
280 CLockObject lock(m_mutex);
281 m_iScheduleEepromWrite = GetTimeMs() + CEC_ADAPTER_EEPROM_WRITE_RETRY;
282 }
283 }
284
285 /* TODO sleep 5 ms so other threads can get a lock */
286 Sleep(5);
287 }
288
289 m_adapterMessageQueue->Clear();
290 LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread ended");
291 return NULL;
292 }
293
294 bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage &msg)
295 {
296 bool bIsError(msg.IsError());
297 cec_adapter_messagecode messageCode(msg.Message());
298 CLockObject lock(m_mutex);
299
300 if (messageCode == MSGCODE_FRAME_START && msg.IsACK())
301 {
302 m_lastPollDestination = msg.Destination();
303 if (msg.Destination() < CECDEVICE_BROADCAST)
304 {
305 if (!m_bWaitingForAck[msg.Destination()] && !msg.IsEOM())
306 {
307 if (m_callback)
308 m_callback->HandlePoll(msg.Initiator(), msg.Destination());
309 }
310 else
311 m_bWaitingForAck[msg.Destination()] = false;
312 }
313 }
314 else if (messageCode == MSGCODE_RECEIVE_FAILED)
315 {
316 /* hack to suppress warnings when an LG is polling */
317 if (m_lastPollDestination != CECDEVICE_UNKNOWN)
318 bIsError = m_callback->HandleReceiveFailed(m_lastPollDestination);
319 }
320
321 return bIsError;
322 }
323
324 void CUSBCECAdapterCommunication::MarkAsWaiting(const cec_logical_address dest)
325 {
326 /* mark as waiting for an ack from the destination */
327 if (dest < CECDEVICE_BROADCAST)
328 {
329 CLockObject lock(m_mutex);
330 m_bWaitingForAck[dest] = true;
331 }
332 }
333
334 void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout /* = CEC_CLEAR_INPUT_DEFAULT_WAIT */)
335 {
336 CTimeout timeout(iTimeout);
337 uint8_t buff[1024];
338 ssize_t iBytesRead(0);
339 bool bGotMsgEnd(true);
340
341 while (timeout.TimeLeft() > 0 && ((iBytesRead = m_port->Read(buff, 1024, 5)) > 0 || !bGotMsgEnd))
342 {
343 bGotMsgEnd = false;
344 /* if something was received, wait for MSGEND */
345 for (ssize_t iPtr = 0; iPtr < iBytesRead; iPtr++)
346 bGotMsgEnd = buff[iPtr] == MSGEND;
347 }
348 }
349
350 bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
351 {
352 bool bReturn(true);
353 bool bChanged(false);
354
355 /* only send the command if the timeout changed */
356 {
357 CLockObject lock(m_mutex);
358 bChanged = (m_iLineTimeout != iTimeout);
359 m_iLineTimeout = iTimeout;
360 }
361
362 if (bChanged)
363 bReturn = m_commands->SetLineTimeout(iTimeout);
364
365 return bReturn;
366 }
367
368 bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
369 {
370 CLockObject adapterLock(m_mutex);
371 if (!IsOpen())
372 {
373 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());
374 message->state = ADAPTER_MESSAGE_STATE_ERROR;
375 return false;
376 }
377
378 /* write the message */
379 if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
380 {
381 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());
382 message->state = ADAPTER_MESSAGE_STATE_ERROR;
383 // this will trigger an alert in the reader thread
384 m_port->Close();
385 return false;
386 }
387
388 LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
389 message->state = ADAPTER_MESSAGE_STATE_SENT;
390 return true;
391 }
392
393 bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
394 {
395 ssize_t iBytesRead(0);
396 uint8_t buff[256];
397 if (iSize > 256)
398 iSize = 256;
399
400 /* read from the serial port */
401 {
402 CLockObject lock(m_mutex);
403 if (!IsOpen())
404 return false;
405
406 iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
407
408 if (m_port->GetErrorNumber())
409 {
410 LIB_CEC->AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
411 m_port->Close();
412 return false;
413 }
414 }
415
416 if (iBytesRead < 0 || iBytesRead > 256)
417 return false;
418 else if (iBytesRead > 0)
419 {
420 /* add the data to the current frame */
421 m_adapterMessageQueue->AddData(buff, iBytesRead);
422 }
423
424 return true;
425 }
426
427 CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage &params, bool bIsRetry /* = false */)
428 {
429 if (!IsOpen() || !m_adapterMessageQueue)
430 return NULL;
431
432 /* create the adapter message for this command */
433 CCECAdapterMessage *output = new CCECAdapterMessage;
434 output->PushBack(MSGSTART);
435 output->PushEscaped((uint8_t)msgCode);
436 output->Append(params);
437 output->PushBack(MSGEND);
438
439 /* write the command */
440 if (!m_adapterMessageQueue->Write(output))
441 {
442 // this will trigger an alert in the reader thread
443 if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
444 m_port->Close();
445 return output;
446 }
447 else
448 {
449 if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED &&
450 msgCode != MSGCODE_GET_BUILDDATE /* same messagecode value had a different meaning in older fw builds */)
451 {
452 /* if the controller reported that the command was rejected, and we didn't send the command
453 to set controlled mode, then the controller probably switched to auto mode. set controlled
454 mode and retry */
455 LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
456 delete output;
457 if (SetControlledMode(true))
458 return SendCommand(msgCode, params, true);
459 }
460 }
461
462 return output;
463 }
464
465 bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
466 {
467 bool bReturn(false);
468 CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
469
470 /* try to ping the adapter */
471 bool bPinged(false);
472 unsigned iPingTry(0);
473 while (timeout.TimeLeft() > 0 && (bPinged = PingAdapter()) == false)
474 {
475 LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
476 CEvent::Sleep(500);
477 }
478
479 /* try to read the firmware version */
480 if (bPinged && timeout.TimeLeft() > 0 && m_commands->RequestFirmwareVersion() >= 2)
481 {
482 /* try to set controlled mode for v2+ firmwares */
483 unsigned iControlledTry(0);
484 bool bControlled(false);
485 while (timeout.TimeLeft() > 0 && (bControlled = SetControlledMode(true)) == false)
486 {
487 LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
488 CEvent::Sleep(500);
489 }
490 bReturn = bControlled;
491 }
492 else
493 bReturn = true;
494
495 /* try to read the build date */
496 m_commands->RequestBuildDate();
497
498 SetInitialised(bReturn);
499 return bReturn;
500 }
501
502 bool CUSBCECAdapterCommunication::IsOpen(void)
503 {
504 /* thread is not being stopped, the port is open and the thread is running */
505 return !IsStopped() && m_port->IsOpen() && IsRunning();
506 }
507
508 std::string CUSBCECAdapterCommunication::GetError(void) const
509 {
510 return m_port->GetError();
511 }
512
513 void CUSBCECAdapterCommunication::SetInitialised(bool bSetTo /* = true */)
514 {
515 CLockObject lock(m_mutex);
516 m_bInitialised = bSetTo;
517 }
518
519 bool CUSBCECAdapterCommunication::IsInitialised(void)
520 {
521 CLockObject lock(m_mutex);
522 return m_bInitialised;
523 }
524
525 bool CUSBCECAdapterCommunication::StartBootloader(void)
526 {
527 if (m_port->IsOpen() && m_commands->StartBootloader())
528 {
529 m_port->Close();
530 return true;
531 }
532 return false;
533 }
534
535 bool CUSBCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
536 {
537 {
538 CLockObject lock(m_mutex);
539 if (m_logicalAddresses == addresses)
540 return true;
541 }
542
543 if (IsOpen() && m_commands->SetAckMask(addresses.AckMask()))
544 {
545 CLockObject lock(m_mutex);
546 m_logicalAddresses = addresses;
547 return true;
548 }
549
550 LIB_CEC->AddLog(CEC_LOG_DEBUG, "couldn't change the ackmask: the connection is closed");
551 return false;
552 }
553
554 cec_logical_addresses CUSBCECAdapterCommunication::GetLogicalAddresses(void)
555 {
556 cec_logical_addresses addresses;
557 CLockObject lock(m_mutex);
558 addresses = m_logicalAddresses;
559 return addresses;
560 }
561
562 bool CUSBCECAdapterCommunication::PingAdapter(void)
563 {
564 return IsOpen() ? m_commands->PingAdapter() : false;
565 }
566
567 uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
568 {
569 return m_commands ? m_commands->GetFirmwareVersion() : CEC_FW_VERSION_UNKNOWN;
570 }
571
572 uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
573 {
574 return IsOpen() ? m_commands->RequestBuildDate() : m_commands ? m_commands->GetPersistedBuildDate() : 0;
575 }
576
577 bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
578 {
579 return GetFirmwareVersion() >= CEC_LATEST_ADAPTER_FW_VERSION &&
580 GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE;
581 }
582
583 bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration &configuration)
584 {
585 if (IsOpen())
586 {
587 // returns true when something changed
588 if (m_commands->PersistConfiguration(configuration))
589 {
590 {
591 CLockObject lock(m_mutex);
592 uint64_t iNow = GetTimeMs();
593 if (iNow - m_iLastEepromWrite < CEC_ADAPTER_EEPROM_WRITE_INTERVAL)
594 {
595 // if there was more than 1 write within the last 30 seconds, schedule another one
596 if (m_iScheduleEepromWrite == 0)
597 m_iScheduleEepromWrite = m_iLastEepromWrite + CEC_ADAPTER_EEPROM_WRITE_INTERVAL;
598 return true;
599 }
600 else
601 {
602 m_iLastEepromWrite = iNow;
603 }
604 }
605
606 if (!m_commands->WriteEEPROM())
607 {
608 // write failed, retry later
609 CLockObject lock(m_mutex);
610 m_iScheduleEepromWrite = GetTimeMs() + CEC_ADAPTER_EEPROM_WRITE_RETRY;
611 }
612 }
613 }
614 return IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
615 }
616
617 bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration &configuration)
618 {
619 return IsOpen() ? m_commands->GetConfiguration(configuration) : false;
620 }
621
622 std::string CUSBCECAdapterCommunication::GetPortName(void)
623 {
624 return m_port->GetName();
625 }
626
627 bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
628 {
629 return IsOpen() ? m_commands->SetControlledMode(controlled) : false;
630 }
631
632 uint16_t CUSBCECAdapterCommunication::GetPhysicalAddress(void)
633 {
634 uint16_t iPA(0);
635
636 // try to get the PA from ADL
637 #if defined(HAS_ADL_EDID_PARSER)
638 {
639 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via ADL", __FUNCTION__);
640 CADLEdidParser adl;
641 iPA = adl.GetPhysicalAddress();
642 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - ADL returned physical address %04x", __FUNCTION__, iPA);
643 }
644 #endif
645
646 // try to get the PA from the nvidia driver
647 #if defined(HAS_NVIDIA_EDID_PARSER)
648 if (iPA == 0)
649 {
650 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via nvidia driver", __FUNCTION__);
651 CNVEdidParser nv;
652 iPA = nv.GetPhysicalAddress();
653 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - nvidia driver returned physical address %04x", __FUNCTION__, iPA);
654 }
655 #endif
656
657 // try to get the PA from the OS
658 if (iPA == 0)
659 {
660 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address from the OS", __FUNCTION__);
661 iPA = CEDIDParser::GetPhysicalAddress();
662 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - OS returned physical address %04x", __FUNCTION__, iPA);
663 }
664
665 return iPA;
666 }
667
668 void *CAdapterPingThread::Process(void)
669 {
670 while (!IsStopped())
671 {
672 if (m_timeout.TimeLeft() == 0)
673 {
674 /* reinit the timeout */
675 m_timeout.Init(CEC_ADAPTER_PING_TIMEOUT);
676
677 /* send a ping to the adapter */
678 bool bPinged(false);
679 int iFailedCounter(0);
680 while (!bPinged && iFailedCounter < 3)
681 {
682 if (!m_com->PingAdapter())
683 {
684 /* sleep and retry */
685 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
686 ++iFailedCounter;
687 }
688 else
689 {
690 bPinged = true;
691 }
692 }
693
694 if (iFailedCounter == 3)
695 {
696 /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
697 m_com->LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
698 m_com->StopThread(false);
699 break;
700 }
701 }
702
703 Sleep(500);
704 }
705 return NULL;
706 }