cec: removed deprecated CECCreate() method
[deb_libcec.git] / src / lib / CECProcessor.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 "CECProcessor.h"
34
35 #include "adapter/USBCECAdapterCommunication.h"
36 #include "devices/CECBusDevice.h"
37 #include "devices/CECAudioSystem.h"
38 #include "devices/CECPlaybackDevice.h"
39 #include "devices/CECRecordingDevice.h"
40 #include "devices/CECTuner.h"
41 #include "devices/CECTV.h"
42 #include "implementations/CECCommandHandler.h"
43 #include "LibCEC.h"
44 #include "platform/util/timeutils.h"
45
46 using namespace CEC;
47 using namespace std;
48 using namespace PLATFORM;
49
50 CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) :
51 m_bInitialised(false),
52 m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
53 m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
54 m_strDeviceName(strDeviceName),
55 m_types(types),
56 m_communication(NULL),
57 m_controller(controller),
58 m_bMonitor(false),
59 m_iStandardLineTimeout(3),
60 m_iRetryLineTimeout(3),
61 m_iLastTransmission(0)
62 {
63 m_logicalAddresses.Clear();
64 for (int iPtr = 0; iPtr < 16; iPtr++)
65 {
66 switch(iPtr)
67 {
68 case CECDEVICE_AUDIOSYSTEM:
69 m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr, 0xFFFF);
70 break;
71 case CECDEVICE_PLAYBACKDEVICE1:
72 case CECDEVICE_PLAYBACKDEVICE2:
73 case CECDEVICE_PLAYBACKDEVICE3:
74 m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr, 0xFFFF);
75 break;
76 case CECDEVICE_RECORDINGDEVICE1:
77 case CECDEVICE_RECORDINGDEVICE2:
78 case CECDEVICE_RECORDINGDEVICE3:
79 m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr, 0xFFFF);
80 break;
81 case CECDEVICE_TUNER1:
82 case CECDEVICE_TUNER2:
83 case CECDEVICE_TUNER3:
84 case CECDEVICE_TUNER4:
85 m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr, 0xFFFF);
86 break;
87 case CECDEVICE_TV:
88 m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr, 0);
89 break;
90 default:
91 m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0xFFFF);
92 break;
93 }
94 }
95 }
96
97 CCECProcessor::~CCECProcessor(void)
98 {
99 Close();
100
101 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
102 delete m_busDevices[iPtr];
103 }
104
105 void CCECProcessor::Close(void)
106 {
107 StopThread();
108
109 CLockObject lock(m_mutex);
110 if (m_communication)
111 {
112 m_communication->Close();
113 delete m_communication;
114 m_communication = NULL;
115 }
116 }
117
118 bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs)
119 {
120 bool bReturn(false);
121 CLockObject lock(m_mutex);
122 if (m_communication)
123 {
124 CLibCEC::AddLog(CEC_LOG_WARNING, "existing connection handler found, deleting it");
125 m_communication->Close();
126 delete m_communication;
127 }
128
129 m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
130
131 /* check for an already opened connection */
132 if (m_communication->IsOpen())
133 {
134 CLibCEC::AddLog(CEC_LOG_ERROR, "connection already opened");
135 return bReturn;
136 }
137
138 uint64_t iNow = GetTimeMs();
139 uint64_t iTarget = iTimeoutMs > 0 ? iNow + iTimeoutMs : iNow + CEC_DEFAULT_TRANSMIT_WAIT;
140
141 /* open a new connection */
142 unsigned iConnectTry(0);
143 while (iNow < iTarget && (bReturn = m_communication->Open(this, iTimeoutMs)) == false)
144 {
145 CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
146 Sleep(500);
147 iNow = GetTimeMs();
148 }
149
150 if (bReturn)
151 CLibCEC::AddLog(CEC_LOG_NOTICE, "connected to the CEC adapter. firmware version = %d", m_communication->GetFirmwareVersion());
152
153 return bReturn;
154 }
155
156 bool CCECProcessor::IsInitialised(void)
157 {
158 CLockObject lock(m_mutex);
159 return m_bInitialised;
160 }
161
162 void CCECProcessor::SetInitialised(bool bSetTo /* = true */)
163 {
164 CLockObject lock(m_mutex);
165 m_bInitialised = bSetTo;
166 }
167
168 bool CCECProcessor::Initialise(void)
169 {
170 bool bReturn(false);
171 {
172 CLockObject lock(m_mutex);
173 if (!m_logicalAddresses.IsEmpty())
174 m_logicalAddresses.Clear();
175
176 if (!FindLogicalAddresses())
177 {
178 CLibCEC::AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
179 return bReturn;
180 }
181
182 /* only set our OSD name for the primary device */
183 m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName;
184 }
185
186 /* get the vendor id from the TV, so we are using the correct handler */
187 m_busDevices[CECDEVICE_TV]->RequestVendorId();
188 ReplaceHandlers();
189
190 if ((bReturn = SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true)) == false)
191 CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set HDMI port %d on %s (%x)", m_iHDMIPort, ToString(m_iBaseDevice), (uint8_t)m_iBaseDevice);
192
193 SetInitialised(bReturn);
194
195 return bReturn;
196 }
197
198 bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */)
199 {
200 bool bReturn(false);
201
202 {
203 CLockObject lock(m_mutex);
204 if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
205 return bReturn;
206
207 /* create the processor thread */
208 if (!CreateThread())
209 {
210 CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
211 return bReturn;
212 }
213 }
214
215 if ((bReturn = Initialise()) == false)
216 {
217 CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
218 StopThread(true);
219 }
220 else
221 {
222 CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
223 }
224
225 return bReturn;
226 }
227
228 bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
229 {
230 if (m_busDevices[address]->TryLogicalAddress())
231 {
232 m_logicalAddresses.Set(address);
233 return true;
234 }
235
236 return false;
237 }
238
239 bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
240 {
241 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
242 return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1) ||
243 TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2) ||
244 TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3);
245 }
246
247 bool CCECProcessor::FindLogicalAddressTuner(void)
248 {
249 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
250 return TryLogicalAddress(CECDEVICE_TUNER1) ||
251 TryLogicalAddress(CECDEVICE_TUNER2) ||
252 TryLogicalAddress(CECDEVICE_TUNER3) ||
253 TryLogicalAddress(CECDEVICE_TUNER4);
254 }
255
256 bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
257 {
258 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
259 return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1) ||
260 TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2) ||
261 TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3);
262 }
263
264 bool CCECProcessor::FindLogicalAddressAudioSystem(void)
265 {
266 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
267 return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
268 }
269
270 bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
271 {
272 bool bChanged(false);
273
274 CLibCEC::AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
275
276 CLockObject lock(m_mutex);
277 CCECBusDevice *previousDevice = GetDeviceByType(from);
278 m_logicalAddresses.primary = CECDEVICE_UNKNOWN;
279
280 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
281 {
282 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
283 continue;
284
285 if (m_types.types[iPtr] == from)
286 {
287 bChanged = true;
288 m_types.types[iPtr] = to;
289 }
290 else if (m_types.types[iPtr] == to && bChanged)
291 {
292 m_types.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
293 }
294 }
295
296 if (bChanged)
297 {
298 FindLogicalAddresses();
299
300 CCECBusDevice *newDevice = GetDeviceByType(to);
301 if (previousDevice && newDevice)
302 {
303 newDevice->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
304 previousDevice->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
305
306 newDevice->SetCecVersion(previousDevice->GetCecVersion(false));
307 previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN);
308
309 newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false));
310 cec_menu_language lang;
311 lang.device = previousDevice->GetLogicalAddress();
312 for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
313 lang.language[iPtr] = '?';
314 lang.language[3] = 0;
315 previousDevice->SetMenuLanguage(lang);
316
317 newDevice->SetMenuState(previousDevice->GetMenuState());
318 previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
319
320 newDevice->SetOSDName(previousDevice->GetOSDName(false));
321 previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress()));
322
323 newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress(false));
324 previousDevice->SetPhysicalAddress(0xFFFF);
325
326 newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false));
327 previousDevice->SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
328
329 newDevice->SetVendorId(previousDevice->GetVendorId(false));
330 previousDevice->SetVendorId(CEC_VENDOR_UNKNOWN);
331
332 if ((from == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || from == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
333 (to == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || to == CEC_DEVICE_TYPE_RECORDING_DEVICE))
334 {
335 ((CCECPlaybackDevice *) newDevice)->SetDeckControlMode(((CCECPlaybackDevice *) previousDevice)->GetDeckControlMode());
336 ((CCECPlaybackDevice *) previousDevice)->SetDeckControlMode(CEC_DECK_CONTROL_MODE_STOP);
337
338 ((CCECPlaybackDevice *) newDevice)->SetDeckStatus(((CCECPlaybackDevice *) previousDevice)->GetDeckStatus());
339 ((CCECPlaybackDevice *) previousDevice)->SetDeckStatus(CEC_DECK_INFO_STOP);
340 }
341 }
342 }
343
344 return true;
345 }
346
347 bool CCECProcessor::FindLogicalAddresses(void)
348 {
349 bool bReturn(true);
350 m_logicalAddresses.Clear();
351
352 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
353 {
354 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
355 continue;
356
357 CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - device %d: type %d", __FUNCTION__, iPtr, m_types.types[iPtr]);
358
359 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
360 bReturn &= FindLogicalAddressRecordingDevice();
361 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
362 bReturn &= FindLogicalAddressTuner();
363 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
364 bReturn &= FindLogicalAddressPlaybackDevice();
365 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
366 bReturn &= FindLogicalAddressAudioSystem();
367 }
368
369 if (bReturn)
370 SetAckMask(m_logicalAddresses.AckMask());
371
372 return bReturn;
373 }
374
375 void CCECProcessor::ReplaceHandlers(void)
376 {
377 CLockObject lock(m_mutex);
378 if (!IsInitialised())
379 return;
380 for (uint8_t iPtr = 0; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
381 m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
382 }
383
384 bool CCECProcessor::OnCommandReceived(const cec_command &command)
385 {
386 m_commandBuffer.Push(command);
387 return true;
388 }
389
390 void *CCECProcessor::Process(void)
391 {
392 cec_command command;
393 CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
394
395 while (!IsStopped() && m_communication->IsOpen())
396 {
397 ReplaceHandlers();
398 if (m_commandBuffer.Pop(command))
399 ParseCommand(command);
400
401 m_controller->CheckKeypressTimeout();
402 Sleep(5);
403 }
404
405 return NULL;
406 }
407
408 bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
409 {
410 bool bReturn(false);
411
412 if (!IsRunning())
413 return bReturn;
414
415 cec_logical_address addr = m_logicalAddresses.primary;
416
417 if (type != CEC_DEVICE_TYPE_RESERVED)
418 {
419 for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
420 {
421 if (m_logicalAddresses[iPtr] && m_busDevices[iPtr]->m_type == type)
422 {
423 addr = (cec_logical_address) iPtr;
424 break;
425 }
426 }
427 }
428
429 m_busDevices[addr]->SetActiveSource();
430 if (m_busDevices[addr]->GetPhysicalAddress(false) != 0xFFFF)
431 {
432 bReturn = m_busDevices[addr]->TransmitActiveSource();
433
434 if (bReturn)
435 {
436 m_busDevices[addr]->SetMenuState(CEC_MENU_STATE_ACTIVATED);
437 m_busDevices[addr]->TransmitMenuState(CECDEVICE_TV);
438 }
439
440 if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
441 m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
442 m_busDevices[addr]->GetHandler()->SendDeckStatusUpdateOnActiveSource())
443 {
444 bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV);
445 }
446 }
447
448 return bReturn;
449 }
450
451 bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
452 {
453 bool bReturn(false);
454
455 CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
456 if (device)
457 {
458 device->SetActiveSource();
459 bReturn = true;
460 }
461
462 return bReturn;
463 }
464
465 void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
466 {
467 CLockObject lock(m_mutex);
468 m_iStandardLineTimeout = iTimeout;
469 }
470
471 void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
472 {
473 CLockObject lock(m_mutex);
474 m_iRetryLineTimeout = iTimeout;
475 }
476
477 bool CCECProcessor::SetActiveView(void)
478 {
479 return SetActiveSource(m_types.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_types[0]);
480 }
481
482 bool CCECProcessor::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
483 {
484 bool bReturn(false);
485
486 CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
487 if (device)
488 {
489 ((CCECPlaybackDevice *) device)->SetDeckControlMode(mode);
490 if (bSendUpdate)
491 ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
492 bReturn = true;
493 }
494
495 return bReturn;
496 }
497
498 bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
499 {
500 bool bReturn(false);
501
502 CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
503 if (device)
504 {
505 ((CCECPlaybackDevice *) device)->SetDeckStatus(info);
506 if (bSendUpdate)
507 ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
508 bReturn = true;
509 }
510
511 return bReturn;
512 }
513
514 bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
515 {
516 bool bReturn(false);
517 CLockObject lock(m_mutex);
518
519 m_iBaseDevice = iBaseDevice;
520 m_iHDMIPort = iPort;
521 if (!IsRunning() && !bForce)
522 return true;
523
524 CLibCEC::AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
525
526 uint16_t iPhysicalAddress(0);
527 if (iBaseDevice > CECDEVICE_TV)
528 {
529 lock.Unlock();
530 iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
531 lock.Lock();
532 }
533
534 if (iPhysicalAddress < 0xffff)
535 {
536 if (iPhysicalAddress == 0)
537 iPhysicalAddress += 0x1000 * iPort;
538 else if (iPhysicalAddress % 0x1000 == 0)
539 iPhysicalAddress += 0x100 * iPort;
540 else if (iPhysicalAddress % 0x100 == 0)
541 iPhysicalAddress += 0x10 * iPort;
542 else if (iPhysicalAddress % 0x10 == 0)
543 iPhysicalAddress += iPort;
544
545 bReturn = true;
546 }
547
548 if (!bReturn)
549 CLibCEC::AddLog(CEC_LOG_ERROR, "failed to set the physical address");
550 else
551 {
552 lock.Unlock();
553 SetPhysicalAddress(iPhysicalAddress);
554 }
555
556 return bReturn;
557 }
558
559 bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
560 {
561 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
562 {
563 if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress)
564 return true;
565 }
566 return false;
567 }
568
569 bool CCECProcessor::TransmitInactiveSource(void)
570 {
571 if (!IsRunning())
572 return false;
573
574 if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
575 return m_busDevices[m_logicalAddresses.primary]->TransmitInactiveSource();
576 return false;
577 }
578
579 void CCECProcessor::LogOutput(const cec_command &data)
580 {
581 CStdString strTx;
582 strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
583 if (data.opcode_set)
584 strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
585
586 for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
587 strTx.AppendFormat(":%02x", data.parameters[iPtr]);
588 CLibCEC::AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
589 }
590
591 bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
592 {
593 CLockObject lock(m_mutex);
594 if (m_logicalAddresses.primary != iLogicalAddress)
595 {
596 CLibCEC::AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
597 m_logicalAddresses.primary = iLogicalAddress;
598 m_logicalAddresses.Set(iLogicalAddress);
599 return SetAckMask(m_logicalAddresses.AckMask());
600 }
601
602 return true;
603 }
604
605 bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
606 {
607 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
608 {
609 if (m_logicalAddresses[iPtr])
610 m_busDevices[iPtr]->SetMenuState(state);
611 }
612
613 if (bSendUpdate)
614 m_busDevices[m_logicalAddresses.primary]->TransmitMenuState(CECDEVICE_TV);
615
616 return true;
617 }
618
619 bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate /* = true */)
620 {
621 bool bSendActiveView(false);
622 bool bReturn(false);
623 cec_logical_addresses sendUpdatesTo;
624 sendUpdatesTo.Clear();
625
626 {
627 CLockObject lock(m_mutex);
628 if (!m_logicalAddresses.IsEmpty())
629 {
630 bool bWasActiveSource(false);
631 for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
632 if (m_logicalAddresses[iPtr])
633 {
634 bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource();
635 m_busDevices[iPtr]->SetInactiveSource();
636 m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
637 if (bSendUpdate)
638 sendUpdatesTo.Set((cec_logical_address)iPtr);
639 }
640
641 bSendActiveView = bWasActiveSource && bSendUpdate;
642 bReturn = true;
643 }
644 }
645
646 for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
647 if (sendUpdatesTo[iPtr])
648 m_busDevices[iPtr]->TransmitPhysicalAddress();
649
650 if (bSendActiveView)
651 SetActiveView();
652
653 return bReturn;
654 }
655
656 bool CCECProcessor::SwitchMonitoring(bool bEnable)
657 {
658 CLibCEC::AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
659
660 {
661 CLockObject lock(m_mutex);
662 m_bMonitor = bEnable;
663 }
664
665 if (bEnable)
666 return SetAckMask(0);
667 else
668 return SetAckMask(m_logicalAddresses.AckMask());
669 }
670
671 bool CCECProcessor::PollDevice(cec_logical_address iAddress)
672 {
673 if (iAddress != CECDEVICE_UNKNOWN && m_busDevices[iAddress])
674 {
675 return m_logicalAddresses.primary == CECDEVICE_UNKNOWN ?
676 m_busDevices[iAddress]->TransmitPoll(iAddress) :
677 m_busDevices[m_logicalAddresses.primary]->TransmitPoll(iAddress);
678 }
679 return false;
680 }
681
682 uint8_t CCECProcessor::VolumeUp(bool bSendRelease /* = true */)
683 {
684 uint8_t status = 0;
685 if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
686 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bSendRelease);
687
688 return status;
689 }
690
691 uint8_t CCECProcessor::VolumeDown(bool bSendRelease /* = true */)
692 {
693 uint8_t status = 0;
694 if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
695 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bSendRelease);
696
697 return status;
698 }
699
700 uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
701 {
702 uint8_t status = 0;
703 if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
704 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bSendRelease);
705
706 return status;
707 }
708
709 CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const
710 {
711 if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
712 return m_busDevices[m_logicalAddresses.primary];
713
714 CCECBusDevice *device = NULL;
715 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
716 {
717 if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress)
718 {
719 device = m_busDevices[iPtr];
720 break;
721 }
722 }
723
724 return device;
725 }
726
727 CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const
728 {
729 CCECBusDevice *device = NULL;
730
731 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
732 {
733 if (m_busDevices[iPtr]->m_type == type && m_logicalAddresses[iPtr])
734 {
735 device = m_busDevices[iPtr];
736 break;
737 }
738 }
739
740 return device;
741 }
742
743 CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const
744 {
745 CCECBusDevice *device(NULL);
746 cec_logical_address primary = m_logicalAddresses.primary;
747 if (primary != CECDEVICE_UNKNOWN)
748 device = m_busDevices[primary];
749 return device;
750 }
751
752 cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
753 {
754 return m_busDevices[iAddress]->GetCecVersion();
755 }
756
757 cec_osd_name CCECProcessor::GetDeviceOSDName(cec_logical_address iAddress)
758 {
759 CStdString strOSDName = m_busDevices[iAddress]->GetOSDName();
760 cec_osd_name retVal;
761
762 snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
763 retVal.device = iAddress;
764
765 return retVal;
766 }
767
768 bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
769 {
770 if (m_busDevices[iAddress])
771 {
772 *language = m_busDevices[iAddress]->GetMenuLanguage();
773 return (strcmp(language->language, "???") != 0);
774 }
775 return false;
776 }
777
778 uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
779 {
780 if (m_busDevices[iAddress])
781 return m_busDevices[iAddress]->GetVendorId();
782 return false;
783 }
784
785 uint16_t CCECProcessor::GetDevicePhysicalAddress(cec_logical_address iAddress)
786 {
787 if (m_busDevices[iAddress])
788 return m_busDevices[iAddress]->GetPhysicalAddress(false);
789 return false;
790 }
791
792 cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddress)
793 {
794 if (m_busDevices[iAddress])
795 return m_busDevices[iAddress]->GetPowerStatus();
796 return CEC_POWER_STATUS_UNKNOWN;
797 }
798
799 cec_logical_address CCECProcessor::GetActiveSource(void)
800 {
801 for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
802 {
803 if (m_busDevices[iPtr]->IsActiveSource())
804 return (cec_logical_address)iPtr;
805 }
806
807 return CECDEVICE_UNKNOWN;
808 }
809
810 bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
811 {
812 return m_busDevices[iAddress]->IsActiveSource();
813 }
814
815 bool CCECProcessor::Transmit(const cec_command &data)
816 {
817 cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
818 {
819 CLockObject lock(m_mutex);
820 LogOutput(data);
821 m_iLastTransmission = GetTimeMs();
822 if (!m_communication)
823 return false;
824 uint8_t iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
825 retVal = m_communication->Write(data, iMaxTries, m_iLineTimeout, m_iRetryLineTimeout);
826 }
827
828 /* set to "not present" on failed ack */
829 if (retVal == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED &&
830 data.destination != CECDEVICE_BROADCAST)
831 m_busDevices[data.destination]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
832
833 return retVal == ADAPTER_MESSAGE_STATE_SENT_ACKED;
834 }
835
836 void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
837 {
838 CLibCEC::AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
839
840 cec_command command;
841 // TODO
842 cec_command::Format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
843 command.parameters.PushBack((uint8_t)opcode);
844 command.parameters.PushBack((uint8_t)reason);
845
846 Transmit(command);
847 }
848
849 void CCECProcessor::ParseCommand(const cec_command &command)
850 {
851 CStdString dataStr;
852 dataStr.Format(">> %1x%1x:%02x", command.initiator, command.destination, command.opcode);
853 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
854 dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]);
855 CLibCEC::AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
856
857 if (!m_bMonitor && command.initiator >= CECDEVICE_TV && command.initiator <= CECDEVICE_BROADCAST)
858 m_busDevices[(uint8_t)command.initiator]->HandleCommand(command);
859 }
860
861 cec_logical_addresses CCECProcessor::GetActiveDevices(void)
862 {
863 cec_logical_addresses addresses;
864 addresses.Clear();
865 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
866 {
867 if (m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
868 addresses.Set((cec_logical_address) iPtr);
869 }
870 return addresses;
871 }
872
873 bool CCECProcessor::IsPresentDevice(cec_logical_address address)
874 {
875 return m_busDevices[address]->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
876 }
877
878 bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
879 {
880 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
881 {
882 if (m_busDevices[iPtr]->GetType() == type && m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
883 return true;
884 }
885
886 return false;
887 }
888
889 uint16_t CCECProcessor::GetPhysicalAddress(void) const
890 {
891 if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
892 return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false);
893 return false;
894 }
895
896 bool CCECProcessor::SetAckMask(uint16_t iMask)
897 {
898 return m_communication->SetAckMask(iMask);
899 }
900
901 bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
902 {
903 return m_busDevices[iDestination]->TransmitKeypress(key, bWait);
904 }
905
906 bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
907 {
908 return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
909 }
910
911 const char *CCECProcessor::ToString(const cec_device_type type)
912 {
913 switch (type)
914 {
915 case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
916 return "audio system";
917 case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
918 return "playback device";
919 case CEC_DEVICE_TYPE_RECORDING_DEVICE:
920 return "recording device";
921 case CEC_DEVICE_TYPE_RESERVED:
922 return "reserved";
923 case CEC_DEVICE_TYPE_TUNER:
924 return "tuner";
925 case CEC_DEVICE_TYPE_TV:
926 return "TV";
927 default:
928 return "unknown";
929 }
930 }
931
932 const char *CCECProcessor::ToString(const cec_menu_state state)
933 {
934 switch (state)
935 {
936 case CEC_MENU_STATE_ACTIVATED:
937 return "activated";
938 case CEC_MENU_STATE_DEACTIVATED:
939 return "deactivated";
940 default:
941 return "unknown";
942 }
943 }
944
945 const char *CCECProcessor::ToString(const cec_version version)
946 {
947 switch (version)
948 {
949 case CEC_VERSION_1_2:
950 return "1.2";
951 case CEC_VERSION_1_2A:
952 return "1.2a";
953 case CEC_VERSION_1_3:
954 return "1.3";
955 case CEC_VERSION_1_3A:
956 return "1.3a";
957 case CEC_VERSION_1_4:
958 return "1.4";
959 default:
960 return "unknown";
961 }
962 }
963
964 const char *CCECProcessor::ToString(const cec_power_status status)
965 {
966 switch (status)
967 {
968 case CEC_POWER_STATUS_ON:
969 return "on";
970 case CEC_POWER_STATUS_STANDBY:
971 return "standby";
972 case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
973 return "in transition from on to standby";
974 case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
975 return "in transition from standby to on";
976 default:
977 return "unknown";
978 }
979 }
980
981 const char *CCECProcessor::ToString(const cec_logical_address address)
982 {
983 switch(address)
984 {
985 case CECDEVICE_AUDIOSYSTEM:
986 return "Audio";
987 case CECDEVICE_BROADCAST:
988 return "Broadcast";
989 case CECDEVICE_FREEUSE:
990 return "Free use";
991 case CECDEVICE_PLAYBACKDEVICE1:
992 return "Playback 1";
993 case CECDEVICE_PLAYBACKDEVICE2:
994 return "Playback 2";
995 case CECDEVICE_PLAYBACKDEVICE3:
996 return "Playback 3";
997 case CECDEVICE_RECORDINGDEVICE1:
998 return "Recorder 1";
999 case CECDEVICE_RECORDINGDEVICE2:
1000 return "Recorder 2";
1001 case CECDEVICE_RECORDINGDEVICE3:
1002 return "Recorder 3";
1003 case CECDEVICE_RESERVED1:
1004 return "Reserved 1";
1005 case CECDEVICE_RESERVED2:
1006 return "Reserved 2";
1007 case CECDEVICE_TUNER1:
1008 return "Tuner 1";
1009 case CECDEVICE_TUNER2:
1010 return "Tuner 2";
1011 case CECDEVICE_TUNER3:
1012 return "Tuner 3";
1013 case CECDEVICE_TUNER4:
1014 return "Tuner 4";
1015 case CECDEVICE_TV:
1016 return "TV";
1017 default:
1018 return "unknown";
1019 }
1020 }
1021
1022 const char *CCECProcessor::ToString(const cec_deck_control_mode mode)
1023 {
1024 switch (mode)
1025 {
1026 case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
1027 return "skip forward wind";
1028 case CEC_DECK_CONTROL_MODE_EJECT:
1029 return "eject";
1030 case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
1031 return "reverse rewind";
1032 case CEC_DECK_CONTROL_MODE_STOP:
1033 return "stop";
1034 default:
1035 return "unknown";
1036 }
1037 }
1038
1039 const char *CCECProcessor::ToString(const cec_deck_info status)
1040 {
1041 switch (status)
1042 {
1043 case CEC_DECK_INFO_PLAY:
1044 return "play";
1045 case CEC_DECK_INFO_RECORD:
1046 return "record";
1047 case CEC_DECK_INFO_PLAY_REVERSE:
1048 return "play reverse";
1049 case CEC_DECK_INFO_STILL:
1050 return "still";
1051 case CEC_DECK_INFO_SLOW:
1052 return "slow";
1053 case CEC_DECK_INFO_SLOW_REVERSE:
1054 return "slow reverse";
1055 case CEC_DECK_INFO_FAST_FORWARD:
1056 return "fast forward";
1057 case CEC_DECK_INFO_FAST_REVERSE:
1058 return "fast reverse";
1059 case CEC_DECK_INFO_NO_MEDIA:
1060 return "no media";
1061 case CEC_DECK_INFO_STOP:
1062 return "stop";
1063 case CEC_DECK_INFO_SKIP_FORWARD_WIND:
1064 return "info skip forward wind";
1065 case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
1066 return "info skip reverse rewind";
1067 case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
1068 return "info index search forward";
1069 case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
1070 return "info index search reverse";
1071 case CEC_DECK_INFO_OTHER_STATUS:
1072 return "other";
1073 default:
1074 return "unknown";
1075 }
1076 }
1077
1078 const char *CCECProcessor::ToString(const cec_opcode opcode)
1079 {
1080 switch (opcode)
1081 {
1082 case CEC_OPCODE_ACTIVE_SOURCE:
1083 return "active source";
1084 case CEC_OPCODE_IMAGE_VIEW_ON:
1085 return "image view on";
1086 case CEC_OPCODE_TEXT_VIEW_ON:
1087 return "text view on";
1088 case CEC_OPCODE_INACTIVE_SOURCE:
1089 return "inactive source";
1090 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
1091 return "request active source";
1092 case CEC_OPCODE_ROUTING_CHANGE:
1093 return "routing change";
1094 case CEC_OPCODE_ROUTING_INFORMATION:
1095 return "routing information";
1096 case CEC_OPCODE_SET_STREAM_PATH:
1097 return "set stream path";
1098 case CEC_OPCODE_STANDBY:
1099 return "standby";
1100 case CEC_OPCODE_RECORD_OFF:
1101 return "record off";
1102 case CEC_OPCODE_RECORD_ON:
1103 return "record on";
1104 case CEC_OPCODE_RECORD_STATUS:
1105 return "record status";
1106 case CEC_OPCODE_RECORD_TV_SCREEN:
1107 return "record tv screen";
1108 case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
1109 return "clear analogue timer";
1110 case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
1111 return "clear digital timer";
1112 case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
1113 return "clear external timer";
1114 case CEC_OPCODE_SET_ANALOGUE_TIMER:
1115 return "set analogue timer";
1116 case CEC_OPCODE_SET_DIGITAL_TIMER:
1117 return "set digital timer";
1118 case CEC_OPCODE_SET_EXTERNAL_TIMER:
1119 return "set external timer";
1120 case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
1121 return "set timer program title";
1122 case CEC_OPCODE_TIMER_CLEARED_STATUS:
1123 return "timer cleared status";
1124 case CEC_OPCODE_TIMER_STATUS:
1125 return "timer status";
1126 case CEC_OPCODE_CEC_VERSION:
1127 return "cec version";
1128 case CEC_OPCODE_GET_CEC_VERSION:
1129 return "get cec version";
1130 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
1131 return "give physical address";
1132 case CEC_OPCODE_GET_MENU_LANGUAGE:
1133 return "get menu language";
1134 case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
1135 return "report physical address";
1136 case CEC_OPCODE_SET_MENU_LANGUAGE:
1137 return "set menu language";
1138 case CEC_OPCODE_DECK_CONTROL:
1139 return "deck control";
1140 case CEC_OPCODE_DECK_STATUS:
1141 return "deck status";
1142 case CEC_OPCODE_GIVE_DECK_STATUS:
1143 return "give deck status";
1144 case CEC_OPCODE_PLAY:
1145 return "play";
1146 case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
1147 return "give tuner status";
1148 case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
1149 return "select analogue service";
1150 case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
1151 return "set digital service";
1152 case CEC_OPCODE_TUNER_DEVICE_STATUS:
1153 return "tuner device status";
1154 case CEC_OPCODE_TUNER_STEP_DECREMENT:
1155 return "tuner step decrement";
1156 case CEC_OPCODE_TUNER_STEP_INCREMENT:
1157 return "tuner step increment";
1158 case CEC_OPCODE_DEVICE_VENDOR_ID:
1159 return "device vendor id";
1160 case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
1161 return "give device vendor id";
1162 case CEC_OPCODE_VENDOR_COMMAND:
1163 return "vendor command";
1164 case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
1165 return "vendor command with id";
1166 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
1167 return "vendor remote button down";
1168 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
1169 return "vendor remote button up";
1170 case CEC_OPCODE_SET_OSD_STRING:
1171 return "set osd string";
1172 case CEC_OPCODE_GIVE_OSD_NAME:
1173 return "give osd name";
1174 case CEC_OPCODE_SET_OSD_NAME:
1175 return "set osd name";
1176 case CEC_OPCODE_MENU_REQUEST:
1177 return "menu request";
1178 case CEC_OPCODE_MENU_STATUS:
1179 return "menu status";
1180 case CEC_OPCODE_USER_CONTROL_PRESSED:
1181 return "user control pressed";
1182 case CEC_OPCODE_USER_CONTROL_RELEASE:
1183 return "user control release";
1184 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
1185 return "give device power status";
1186 case CEC_OPCODE_REPORT_POWER_STATUS:
1187 return "report power status";
1188 case CEC_OPCODE_FEATURE_ABORT:
1189 return "feature abort";
1190 case CEC_OPCODE_ABORT:
1191 return "abort";
1192 case CEC_OPCODE_GIVE_AUDIO_STATUS:
1193 return "give audio status";
1194 case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
1195 return "give audio mode status";
1196 case CEC_OPCODE_REPORT_AUDIO_STATUS:
1197 return "report audio status";
1198 case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
1199 return "set system audio mode";
1200 case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
1201 return "system audio mode request";
1202 case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
1203 return "system audio mode status";
1204 case CEC_OPCODE_SET_AUDIO_RATE:
1205 return "set audio rate";
1206 default:
1207 return "UNKNOWN";
1208 }
1209 }
1210
1211 const char *CCECProcessor::ToString(const cec_system_audio_status mode)
1212 {
1213 switch(mode)
1214 {
1215 case CEC_SYSTEM_AUDIO_STATUS_ON:
1216 return "on";
1217 case CEC_SYSTEM_AUDIO_STATUS_OFF:
1218 return "off";
1219 default:
1220 return "unknown";
1221 }
1222 }
1223
1224 const char *CCECProcessor::ToString(const cec_audio_status UNUSED(status))
1225 {
1226 // TODO this is a mask
1227 return "TODO";
1228 }
1229
1230 const char *CCECProcessor::ToString(const cec_vendor_id vendor)
1231 {
1232 switch (vendor)
1233 {
1234 case CEC_VENDOR_SAMSUNG:
1235 return "Samsung";
1236 case CEC_VENDOR_LG:
1237 return "LG";
1238 case CEC_VENDOR_PANASONIC:
1239 return "Panasonic";
1240 case CEC_VENDOR_PIONEER:
1241 return "Pioneer";
1242 case CEC_VENDOR_ONKYO:
1243 return "Onkyo";
1244 case CEC_VENDOR_YAMAHA:
1245 return "Yamaha";
1246 case CEC_VENDOR_PHILIPS:
1247 return "Philips";
1248 case CEC_VENDOR_SONY:
1249 return "Sony";
1250 default:
1251 return "Unknown";
1252 }
1253 }
1254
1255 void *CCECBusScan::Process(void)
1256 {
1257 CCECBusDevice *device(NULL);
1258 uint8_t iCounter(0);
1259
1260 while (!IsStopped())
1261 {
1262 if (++iCounter < 10)
1263 {
1264 Sleep(1000);
1265 continue;
1266 }
1267 for (unsigned int iPtr = 0; iPtr <= 11 && !IsStopped(); iPtr++)
1268 {
1269 device = m_processor->m_busDevices[iPtr];
1270 WaitUntilIdle();
1271 if (device && device->GetStatus(true) == CEC_DEVICE_STATUS_PRESENT)
1272 {
1273 WaitUntilIdle();
1274 if (!IsStopped())
1275 device->GetVendorId();
1276
1277 WaitUntilIdle();
1278 if (!IsStopped())
1279 device->GetPowerStatus(true);
1280 }
1281 }
1282 }
1283
1284 return NULL;
1285 }
1286
1287 void CCECBusScan::WaitUntilIdle(void)
1288 {
1289 if (IsStopped())
1290 return;
1291
1292 int32_t iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
1293 while (iWaitTime > 0)
1294 {
1295 Sleep(iWaitTime);
1296 iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
1297 }
1298 }
1299
1300 bool CCECProcessor::StartBootloader(void)
1301 {
1302 return m_communication->StartBootloader();
1303 }
1304
1305 bool CCECProcessor::PingAdapter(void)
1306 {
1307 return m_communication->PingAdapter();
1308 }
1309
1310 void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
1311 {
1312 m_busDevices[initiator]->HandlePoll(destination);
1313 }
1314
1315 bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
1316 {
1317 return !m_busDevices[initiator]->HandleReceiveFailed();
1318 }
1319
1320 bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
1321 {
1322 // stream path changes are sent by the TV
1323 return m_busDevices[CECDEVICE_TV]->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
1324 }