cec: don't hold a lock while waiting for a response. fixes failed libCEC inits and...
[deb_libcec.git] / src / lib / devices / CECBusDevice.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011 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 "CECBusDevice.h"
34 #include "../CECProcessor.h"
35 #include "../implementations/ANCommandHandler.h"
36 #include "../implementations/CECCommandHandler.h"
37 #include "../implementations/SLCommandHandler.h"
38 #include "../implementations/VLCommandHandler.h"
39 #include "../platform/timeutils.h"
40
41 using namespace CEC;
42
43 #define ToString(p) m_processor->ToString(p)
44
45 CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress) :
46 m_type(CEC_DEVICE_TYPE_RESERVED),
47 m_iPhysicalAddress(iPhysicalAddress),
48 m_iStreamPath(0),
49 m_iLogicalAddress(iLogicalAddress),
50 m_powerStatus(CEC_POWER_STATUS_UNKNOWN),
51 m_processor(processor),
52 m_vendor(CEC_VENDOR_UNKNOWN),
53 m_bReplaceHandler(false),
54 m_menuState(CEC_MENU_STATE_ACTIVATED),
55 m_bActiveSource(false),
56 m_iLastActive(0),
57 m_cecVersion(CEC_VERSION_UNKNOWN),
58 m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN),
59 m_handlerMutex(false)
60 {
61 m_handler = new CCECCommandHandler(this);
62
63 for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
64 m_menuLanguage.language[iPtr] = '?';
65 m_menuLanguage.language[3] = 0;
66 m_menuLanguage.device = iLogicalAddress;
67
68 m_strDeviceName = ToString(m_iLogicalAddress);
69 }
70
71 CCECBusDevice::~CCECBusDevice(void)
72 {
73 delete m_handler;
74 }
75
76 void CCECBusDevice::AddLog(cec_log_level level, const CStdString &strMessage)
77 {
78 m_processor->AddLog(level, strMessage);
79 }
80
81 bool CCECBusDevice::HandleCommand(const cec_command &command)
82 {
83 bool bHandled(false);
84
85 /* update "last active" */
86 {
87 CLockObject lock(&m_mutex);
88 m_iLastActive = GetTimeMs();
89
90 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
91 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
92 }
93
94 /* handle the command */
95 bHandled = m_handler->HandleCommand(command);
96
97 /* change status to present */
98 if (bHandled)
99 {
100 CLockObject lock(&m_mutex);
101 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
102 {
103 if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
104 {
105 CStdString strLog;
106 strLog.Format("device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
107 AddLog(CEC_LOG_DEBUG, strLog);
108 }
109 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
110 }
111 }
112
113 return bHandled;
114 }
115
116 bool CCECBusDevice::PowerOn(void)
117 {
118 CStdString strLog;
119 strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
120 AddLog(CEC_LOG_DEBUG, strLog.c_str());
121
122 if (m_handler->TransmitImageViewOn(GetMyLogicalAddress(), m_iLogicalAddress))
123 {
124 {
125 CLockObject lock(&m_mutex);
126 // m_powerStatus = CEC_POWER_STATUS_UNKNOWN;
127 m_powerStatus = CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON;
128 }
129 // cec_power_status status = GetPowerStatus();
130 // if (status == CEC_POWER_STATUS_STANDBY || status == CEC_POWER_STATUS_UNKNOWN)
131 // {
132 // /* sending the normal power on command appears to have failed */
133 // CStdString strLog;
134 // strLog.Format("<< sending power on keypress to '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
135 // AddLog(CEC_LOG_DEBUG, strLog.c_str());
136 //
137 // TransmitKeypress(CEC_USER_CONTROL_CODE_POWER);
138 // return TransmitKeyRelease();
139 // }
140 return true;
141 }
142
143 return false;
144 }
145
146 bool CCECBusDevice::Standby(void)
147 {
148 CStdString strLog;
149 strLog.Format("<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
150 AddLog(CEC_LOG_DEBUG, strLog.c_str());
151
152 return m_handler->TransmitStandby(GetMyLogicalAddress(), m_iLogicalAddress);
153 }
154
155 /** @name Getters */
156 //@{
157 cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
158 {
159 bool bRequestUpdate(false);
160 {
161 CLockObject lock(&m_mutex);
162 bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
163 (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN));
164 }
165
166 if (bRequestUpdate)
167 RequestCecVersion();
168
169 CLockObject lock(&m_mutex);
170 return m_cecVersion;
171 }
172
173 bool CCECBusDevice::RequestCecVersion(void)
174 {
175 bool bReturn(false);
176
177 if (!MyLogicalAddressContains(m_iLogicalAddress))
178 {
179 CStdString strLog;
180 strLog.Format("<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
181 AddLog(CEC_LOG_NOTICE, strLog);
182
183 bReturn = m_handler->TransmitRequestCecVersion(GetMyLogicalAddress(), m_iLogicalAddress);
184 }
185 return bReturn;
186 }
187
188 const char* CCECBusDevice::GetLogicalAddressName(void) const
189 {
190 return ToString(m_iLogicalAddress);
191 }
192
193 cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
194 {
195 bool bRequestUpdate(false);
196 {
197 CLockObject lock(&m_mutex);
198 bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
199 (bUpdate || !strcmp(m_menuLanguage.language, "???")));
200 }
201
202 if (bRequestUpdate)
203 RequestMenuLanguage();
204
205 CLockObject lock(&m_mutex);
206 return m_menuLanguage;
207 }
208
209 bool CCECBusDevice::RequestMenuLanguage(void)
210 {
211 bool bReturn(false);
212
213 if (!MyLogicalAddressContains(m_iLogicalAddress) &&
214 !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
215 {
216 CStdString strLog;
217 strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
218 AddLog(CEC_LOG_NOTICE, strLog);
219 bReturn = m_handler->TransmitRequestMenuLanguage(GetMyLogicalAddress(), m_iLogicalAddress);
220 }
221 return bReturn;
222 }
223
224 cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
225 {
226 return m_processor->GetLogicalAddress();
227 }
228
229 uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
230 {
231 return m_processor->GetPhysicalAddress();
232 }
233
234 CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
235 {
236 bool bRequestUpdate(false);
237 {
238 CLockObject lock(&m_mutex);
239 bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
240 (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
241 m_type != CEC_DEVICE_TYPE_TV);
242 }
243
244 if (bRequestUpdate)
245 RequestOSDName();
246
247 CLockObject lock(&m_mutex);
248 return m_strDeviceName;
249 }
250
251 bool CCECBusDevice::RequestOSDName(void)
252 {
253 bool bReturn(false);
254
255 if (!MyLogicalAddressContains(m_iLogicalAddress) &&
256 !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
257 {
258 CStdString strLog;
259 strLog.Format("<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
260 AddLog(CEC_LOG_NOTICE, strLog);
261 bReturn = m_handler->TransmitRequestOSDName(GetMyLogicalAddress(), m_iLogicalAddress);
262 }
263 return bReturn;
264 }
265
266 uint16_t CCECBusDevice::GetPhysicalAddress(bool bUpdate /* = false */)
267 {
268 bool bRequestUpdate(false);
269 {
270 CLockObject lock(&m_mutex);
271 bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
272 (m_iPhysicalAddress == 0xFFFF || bUpdate));
273 }
274
275 if (bRequestUpdate && !RequestPhysicalAddress())
276 AddLog(CEC_LOG_ERROR, "failed to request the physical address (1)");
277
278 CLockObject lock(&m_mutex);
279 return m_iPhysicalAddress;
280 }
281
282 bool CCECBusDevice::RequestPhysicalAddress(void)
283 {
284 bool bReturn(false);
285
286 if (!MyLogicalAddressContains(m_iLogicalAddress))
287 {
288 CStdString strLog;
289 strLog.Format("<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
290 AddLog(CEC_LOG_NOTICE, strLog);
291 bReturn = m_handler->TransmitRequestPhysicalAddress(GetMyLogicalAddress(), m_iLogicalAddress);
292 }
293 return bReturn;
294 }
295
296 cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
297 {
298 bool bRequestUpdate(false);
299 {
300 CLockObject lock(&m_mutex);
301 bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
302 (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN));
303 }
304
305 if (bRequestUpdate)
306 RequestPowerStatus();
307
308 CLockObject lock(&m_mutex);
309 return m_powerStatus;
310 }
311
312 bool CCECBusDevice::RequestPowerStatus(void)
313 {
314 bool bReturn(false);
315
316 if (!MyLogicalAddressContains(m_iLogicalAddress) &&
317 !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
318 {
319 CStdString strLog;
320 strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
321 AddLog(CEC_LOG_NOTICE, strLog);
322 bReturn = m_handler->TransmitRequestPowerStatus(GetMyLogicalAddress(), m_iLogicalAddress);
323 }
324 return bReturn;
325 }
326
327 cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */)
328 {
329 bool bRequestUpdate(false);
330 {
331 CLockObject lock(&m_mutex);
332 bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
333 (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
334 }
335
336 if (bRequestUpdate)
337 RequestVendorId();
338
339 CLockObject lock(&m_mutex);
340 return m_vendor;
341 }
342
343 bool CCECBusDevice::RequestVendorId(void)
344 {
345 bool bReturn(false);
346
347 if (!MyLogicalAddressContains(m_iLogicalAddress))
348 {
349 CStdString strLog;
350 strLog.Format("<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
351 AddLog(CEC_LOG_NOTICE, strLog);
352 bReturn = m_handler->TransmitRequestVendorId(GetMyLogicalAddress(), m_iLogicalAddress);
353 }
354 return bReturn;
355 }
356
357 const char *CCECBusDevice::GetVendorName(bool bUpdate /* = false */)
358 {
359 return ToString(GetVendorId(bUpdate));
360 }
361
362 bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
363 {
364 return m_processor->HasLogicalAddress(address);
365 }
366
367 bool CCECBusDevice::NeedsPoll(void)
368 {
369 bool bSendPoll(false);
370 switch (m_iLogicalAddress)
371 {
372 case CECDEVICE_PLAYBACKDEVICE3:
373 if (m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE2]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
374 bSendPoll = true;
375 break;
376 case CECDEVICE_PLAYBACKDEVICE2:
377 if (m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE1]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
378 bSendPoll = true;
379 break;
380 case CECDEVICE_RECORDINGDEVICE3:
381 if (m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE2]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
382 bSendPoll = true;
383 break;
384 case CECDEVICE_RECORDINGDEVICE2:
385 if (m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE1]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
386 bSendPoll = true;
387 break;
388 case CECDEVICE_TUNER4:
389 if (m_processor->m_busDevices[CECDEVICE_TUNER3]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
390 bSendPoll = true;
391 break;
392 case CECDEVICE_TUNER3:
393 if (m_processor->m_busDevices[CECDEVICE_TUNER2]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
394 bSendPoll = true;
395 break;
396 case CECDEVICE_TUNER2:
397 if (m_processor->m_busDevices[CECDEVICE_TUNER1]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
398 bSendPoll = true;
399 break;
400 case CECDEVICE_AUDIOSYSTEM:
401 case CECDEVICE_PLAYBACKDEVICE1:
402 case CECDEVICE_RECORDINGDEVICE1:
403 case CECDEVICE_TUNER1:
404 case CECDEVICE_TV:
405 bSendPoll = true;
406 break;
407 default:
408 break;
409 }
410
411 return bSendPoll;
412 }
413
414 cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */)
415 {
416 CLockObject lock(&m_mutex);
417 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC &&
418 (m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN || bForcePoll))
419 {
420 lock.Leave();
421 bool bPollAcked(false);
422 if (bForcePoll || NeedsPoll())
423 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
424
425 lock.Lock();
426 m_deviceStatus = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
427 }
428
429 return m_deviceStatus;
430 }
431
432 //@}
433
434 /** @name Setters */
435 //@{
436 void CCECBusDevice::SetCecVersion(const cec_version newVersion)
437 {
438 m_cecVersion = newVersion;
439
440 CStdString strLog;
441 strLog.Format("%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
442 AddLog(CEC_LOG_DEBUG, strLog);
443 }
444
445 void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
446 {
447 CLockObject lock(&m_mutex);
448 if (language.device == m_iLogicalAddress)
449 {
450 CStdString strLog;
451 strLog.Format(">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, language.language);
452 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
453 m_menuLanguage = language;
454 }
455 }
456
457 void CCECBusDevice::SetOSDName(CStdString strName)
458 {
459 CLockObject lock(&m_mutex);
460 if (m_strDeviceName != strName)
461 {
462 CStdString strLog;
463 strLog.Format(">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName);
464 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
465 m_strDeviceName = strName;
466 }
467 }
468
469 void CCECBusDevice::SetMenuState(const cec_menu_state state)
470 {
471 CLockObject lock(&m_mutex);
472 if (m_menuState != state)
473 {
474 CStdString strLog;
475 strLog.Format(">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
476 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
477 m_menuState = state;
478 }
479 }
480
481 void CCECBusDevice::SetInactiveSource(void)
482 {
483 {
484 CLockObject lock(&m_mutex);
485 m_bActiveSource = false;
486 }
487
488 if (MyLogicalAddressContains(m_iLogicalAddress))
489 SetPowerStatus(CEC_POWER_STATUS_STANDBY);
490 }
491
492 void CCECBusDevice::SetActiveSource(void)
493 {
494 CLockObject lock(&m_mutex);
495
496 for (int iPtr = 0; iPtr < 16; iPtr++)
497 if (iPtr != m_iLogicalAddress)
498 m_processor->m_busDevices[iPtr]->SetInactiveSource();
499
500 m_bActiveSource = true;
501 m_powerStatus = CEC_POWER_STATUS_ON;
502 }
503
504 bool CCECBusDevice::TryLogicalAddress(void)
505 {
506 CStdString strLog;
507 strLog.Format("trying logical address '%s'", GetLogicalAddressName());
508 AddLog(CEC_LOG_DEBUG, strLog);
509
510 m_processor->SetAckMask(0x1 << m_iLogicalAddress);
511 if (!TransmitPoll(m_iLogicalAddress))
512 {
513 strLog.Format("using logical address '%s'", GetLogicalAddressName());
514 AddLog(CEC_LOG_NOTICE, strLog);
515 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
516
517 return true;
518 }
519
520 strLog.Format("logical address '%s' already taken", GetLogicalAddressName());
521 AddLog(CEC_LOG_DEBUG, strLog);
522 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
523 return false;
524 }
525
526 void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
527 {
528 CLockObject lock(&m_mutex);
529 switch (newStatus)
530 {
531 case CEC_DEVICE_STATUS_UNKNOWN:
532 m_iStreamPath = 0;
533 m_powerStatus = CEC_POWER_STATUS_UNKNOWN;
534 m_vendor = CEC_VENDOR_UNKNOWN;
535 m_menuState = CEC_MENU_STATE_ACTIVATED;
536 m_bActiveSource = false;
537 m_iLastActive = 0;
538 m_cecVersion = CEC_VERSION_UNKNOWN;
539 m_deviceStatus = newStatus;
540 break;
541 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
542 m_iStreamPath = 0;
543 m_powerStatus = CEC_POWER_STATUS_ON;
544 m_vendor = CEC_VENDOR_UNKNOWN;
545 m_menuState = CEC_MENU_STATE_ACTIVATED;
546 m_bActiveSource = false;
547 m_iLastActive = 0;
548 m_cecVersion = CEC_VERSION_1_3A;
549 m_deviceStatus = newStatus;
550 break;
551 case CEC_DEVICE_STATUS_PRESENT:
552 case CEC_DEVICE_STATUS_NOT_PRESENT:
553 m_deviceStatus = newStatus;
554 break;
555 }
556 }
557
558 void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
559 {
560 CLockObject lock(&m_mutex);
561 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
562 {
563 CStdString strLog;
564 strLog.Format(">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
565 AddLog(CEC_LOG_DEBUG, strLog.c_str());
566
567 m_iPhysicalAddress = iNewAddress;
568 }
569 }
570
571 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = 0 */)
572 {
573 CLockObject lock(&m_mutex);
574 if (iNewAddress > 0)
575 {
576 CStdString strLog;
577 strLog.Format(">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
578 AddLog(CEC_LOG_DEBUG, strLog.c_str());
579
580 m_iStreamPath = iNewAddress;
581
582 if (iNewAddress > 0)
583 {
584 lock.Leave();
585 SetPowerStatus(CEC_POWER_STATUS_ON);
586 }
587 }
588 }
589
590 void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
591 {
592 CLockObject lock(&m_mutex);
593 if (m_powerStatus != powerStatus)
594 {
595 CStdString strLog;
596 strLog.Format(">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
597 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
598 m_powerStatus = powerStatus;
599 }
600 }
601
602 bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */)
603 {
604 CLockObject lock(&m_mutex);
605 CLockObject handlerLock(&m_handlerMutex);
606
607 if (m_vendor != m_handler->GetVendorId())
608 {
609 if (m_handler->InUse())
610 return false;
611
612 delete m_handler;
613
614 switch (m_vendor)
615 {
616 case CEC_VENDOR_SAMSUNG:
617 m_handler = new CANCommandHandler(this);
618 break;
619 case CEC_VENDOR_LG:
620 m_handler = new CSLCommandHandler(this);
621 break;
622 case CEC_VENDOR_PANASONIC:
623 m_handler = new CVLCommandHandler(this);
624 break;
625 default:
626 m_handler = new CCECCommandHandler(this);
627 break;
628 }
629
630 if (bInitHandler && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised())
631 m_handler->InitHandler();
632 }
633
634 return true;
635 }
636
637 bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */)
638 {
639 bool bVendorChanged(false);
640
641 {
642 CLockObject lock(&m_mutex);
643 bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
644 m_vendor = (cec_vendor_id)iVendorId;
645 ReplaceHandler(bInitHandler);
646 }
647
648 CStdString strLog;
649 strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
650 m_processor->AddLog(CEC_LOG_DEBUG, strLog.c_str());
651
652 return bVendorChanged;
653 }
654 //@}
655
656 /** @name Transmit methods */
657 //@{
658 bool CCECBusDevice::TransmitActiveSource(void)
659 {
660 bool bSendActiveSource(false);
661
662 {
663 CLockObject lock(&m_mutex);
664 if (m_powerStatus != CEC_POWER_STATUS_ON)
665 {
666 CStdString strLog;
667 strLog.Format("<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
668 AddLog(CEC_LOG_DEBUG, strLog);
669 }
670 else if (m_bActiveSource)
671 {
672 CStdString strLog;
673 strLog.Format("<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
674 AddLog(CEC_LOG_NOTICE, strLog);
675 bSendActiveSource = true;
676 }
677 else
678 {
679 CStdString strLog;
680 strLog.Format("<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
681 AddLog(CEC_LOG_DEBUG, strLog);
682 }
683 }
684
685 if (bSendActiveSource)
686 {
687 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
688 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
689 return true;
690 }
691
692 return false;
693 }
694
695 bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
696 {
697 cec_version version;
698 {
699 CLockObject lock(&m_mutex);
700 CStdString strLog;
701 strLog.Format("<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
702 AddLog(CEC_LOG_NOTICE, strLog);
703 version = m_cecVersion;
704 }
705
706 return m_handler->TransmitCECVersion(m_iLogicalAddress, dest, version);
707 }
708
709 bool CCECBusDevice::TransmitInactiveSource(void)
710 {
711 uint16_t iPhysicalAddress;
712 {
713 CLockObject lock(&m_mutex);
714 CStdString strLog;
715 strLog.Format("<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
716 AddLog(CEC_LOG_NOTICE, strLog);
717 iPhysicalAddress = m_iPhysicalAddress;
718 }
719
720 return m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
721 }
722
723 bool CCECBusDevice::TransmitMenuState(cec_logical_address dest)
724 {
725 cec_menu_state menuState;
726 {
727 CLockObject lock(&m_mutex);
728 CStdString strLog;
729 strLog.Format("<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
730 AddLog(CEC_LOG_NOTICE, strLog);
731 menuState = m_menuState;
732 }
733
734 return m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
735 }
736
737 bool CCECBusDevice::TransmitOSDName(cec_logical_address dest)
738 {
739 CStdString strDeviceName;
740 {
741 CLockObject lock(&m_mutex);
742 CStdString strLog;
743 strLog.Format("<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
744 AddLog(CEC_LOG_NOTICE, strLog.c_str());
745 strDeviceName = m_strDeviceName;
746 }
747
748 return m_handler->TransmitOSDName(m_iLogicalAddress, dest, strDeviceName);
749 }
750
751 bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage)
752 {
753 if (!IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
754 {
755 CStdString strLog;
756 strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
757 AddLog(CEC_LOG_NOTICE, strLog.c_str());
758
759 return m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage);
760 }
761 return false;
762 }
763
764 bool CCECBusDevice::TransmitPhysicalAddress(void)
765 {
766 uint16_t iPhysicalAddress;
767 cec_device_type type;
768 {
769 CLockObject lock(&m_mutex);
770 if (m_iPhysicalAddress == 0xffff)
771 return false;
772
773 CStdString strLog;
774 strLog.Format("<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
775 AddLog(CEC_LOG_NOTICE, strLog.c_str());
776
777 iPhysicalAddress = m_iPhysicalAddress;
778 type = m_type;
779 }
780
781 return m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
782 }
783
784 bool CCECBusDevice::TransmitPoll(cec_logical_address dest)
785 {
786 bool bReturn(false);
787 if (dest == CECDEVICE_UNKNOWN)
788 dest = m_iLogicalAddress;
789
790 CCECBusDevice *destDevice = m_processor->m_busDevices[dest];
791 if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
792 return bReturn;
793
794 CStdString strLog;
795 strLog.Format("<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
796 AddLog(CEC_LOG_NOTICE, strLog.c_str());
797 bReturn = m_handler->TransmitPoll(m_iLogicalAddress, dest);
798 AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
799
800 CLockObject lock(&m_mutex);
801 if (bReturn)
802 {
803 m_iLastActive = GetTimeMs();
804 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
805 }
806 else
807 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
808
809 return bReturn;
810 }
811
812 bool CCECBusDevice::TransmitPowerState(cec_logical_address dest)
813 {
814 cec_power_status state;
815 {
816 CLockObject lock(&m_mutex);
817 CStdString strLog;
818 strLog.Format("<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
819 AddLog(CEC_LOG_NOTICE, strLog.c_str());
820 state = m_powerStatus;
821 }
822
823 return m_handler->TransmitPowerState(m_iLogicalAddress, dest, state);
824 }
825
826 bool CCECBusDevice::TransmitVendorID(cec_logical_address dest, bool bSendAbort /* = true */)
827 {
828 uint64_t iVendorId;
829 {
830 CLockObject lock(&m_mutex);
831 iVendorId = (uint64_t)m_vendor;
832 }
833
834 if (iVendorId == CEC_VENDOR_UNKNOWN)
835 {
836 if (bSendAbort)
837 {
838 CStdString strLog;
839 strLog.Format("<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
840 AddLog(CEC_LOG_NOTICE, strLog);
841
842 m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
843 }
844 return false;
845 }
846 else
847 {
848 CStdString strLog;
849 strLog.Format("<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString((cec_vendor_id)iVendorId), iVendorId);
850 AddLog(CEC_LOG_NOTICE, strLog);
851
852 return m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
853 }
854 }
855
856 bool CCECBusDevice::TransmitKeypress(cec_user_control_code key, bool bWait /* = true */)
857 {
858 return m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key, bWait);
859 }
860
861 bool CCECBusDevice::TransmitKeyRelease(bool bWait /* = true */)
862 {
863 return m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress, bWait);
864 }
865
866 bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode) const
867 {
868 return m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end();
869 }
870
871 void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
872 {
873 m_unsupportedFeatures.insert(opcode);
874 }
875
876 bool CCECBusDevice::InitHandler(void)
877 {
878 CLockObject lock(&m_mutex);
879 return m_handler->InitHandler();
880 }
881
882 //@}