cec: use the correct source when transmitting an abort message as a reposonse to...
[deb_libcec.git] / src / lib / devices / CECBusDevice.cpp
CommitLineData
e9de9629
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
b492c10e 4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
e9de9629
LOK
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
33#include "CECBusDevice.h"
eafa9d46
LOK
34#include "../CECProcessor.h"
35#include "../implementations/ANCommandHandler.h"
36#include "../implementations/CECCommandHandler.h"
37#include "../implementations/SLCommandHandler.h"
11621576 38#include "../implementations/VLCommandHandler.h"
5477a250 39#include "../LibCEC.h"
ba65909d 40#include "../platform/util/timeutils.h"
e9de9629 41
004b8382
LOK
42#include "CECAudioSystem.h"
43#include "CECPlaybackDevice.h"
44#include "CECRecordingDevice.h"
45#include "CECTuner.h"
46#include "CECTV.h"
47
48using namespace std;
e9de9629 49using namespace CEC;
f00ff009 50using namespace PLATFORM;
e9de9629 51
004b8382
LOK
52#define LIB_CEC m_processor->GetLib()
53#define ToString(p) LIB_CEC->ToString(p)
c4098482 54
d2d1660c 55CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
ecc676ca
LOK
56 m_type (CEC_DEVICE_TYPE_RESERVED),
57 m_iPhysicalAddress (iPhysicalAddress),
b32ffd87 58 m_iStreamPath (CEC_INVALID_PHYSICAL_ADDRESS),
ecc676ca
LOK
59 m_iLogicalAddress (iLogicalAddress),
60 m_powerStatus (CEC_POWER_STATUS_UNKNOWN),
61 m_processor (processor),
62 m_vendor (CEC_VENDOR_UNKNOWN),
63 m_bReplaceHandler (false),
64 m_menuState (CEC_MENU_STATE_ACTIVATED),
65 m_bActiveSource (false),
66 m_iLastActive (0),
67 m_iLastPowerStateUpdate (0),
68 m_cecVersion (CEC_VERSION_UNKNOWN),
69 m_deviceStatus (CEC_DEVICE_STATUS_UNKNOWN),
70 m_iHandlerUseCount (0),
ebb6ddb3 71 m_bAwaitingReceiveFailed(false),
ecc676ca 72 m_bVendorIdRequested (false)
e9de9629
LOK
73{
74 m_handler = new CCECCommandHandler(this);
51b2a094 75
a3269a0a
LOK
76 for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
77 m_menuLanguage.language[iPtr] = '?';
78 m_menuLanguage.language[3] = 0;
79 m_menuLanguage.device = iLogicalAddress;
1fcf5a3f 80
c4098482 81 m_strDeviceName = ToString(m_iLogicalAddress);
e9de9629
LOK
82}
83
84CCECBusDevice::~CCECBusDevice(void)
85{
86 delete m_handler;
87}
88
004b8382
LOK
89bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
90{
91 bool bInitHandler(false);
92 {
93 CTryLockObject lock(m_mutex);
94 if (!lock.IsLocked())
95 return false;
96
97 CLockObject handlerLock(m_handlerMutex);
98 if (m_iHandlerUseCount > 0)
99 return false;
100
101 MarkBusy();
102
103 if (m_vendor != m_handler->GetVendorId())
104 {
105 if (CCECCommandHandler::HasSpecificHandler(m_vendor))
106 {
107 LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
108 delete m_handler;
109
110 switch (m_vendor)
111 {
112 case CEC_VENDOR_SAMSUNG:
113 m_handler = new CANCommandHandler(this);
114 break;
115 case CEC_VENDOR_LG:
116 m_handler = new CSLCommandHandler(this);
117 break;
118 case CEC_VENDOR_PANASONIC:
119 m_handler = new CVLCommandHandler(this);
120 break;
121 default:
122 m_handler = new CCECCommandHandler(this);
123 break;
124 }
125
126 m_handler->SetVendorId(m_vendor);
127 bInitHandler = true;
128 }
129 }
130 }
131
132 if (bInitHandler)
133 {
134 m_handler->InitHandler();
135
136 if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
137 m_handler->ActivateSource();
138 }
139
140 MarkReady();
141
142 return true;
143}
144
93729720 145bool CCECBusDevice::HandleCommand(const cec_command &command)
f8513317 146{
7f919115
LOK
147 bool bHandled(false);
148
149 /* update "last active" */
8fa35473 150 {
f00ff009 151 CLockObject lock(m_mutex);
8fa35473 152 m_iLastActive = GetTimeMs();
f4b7b1dc 153
ba427965 154 /* don't call GetStatus() here, just read the value with the mutex locked */
d297cbd4 155 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC && command.opcode_set == 1)
f4b7b1dc 156 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
1344fd1a
LOK
157
158 MarkBusy();
8fa35473
LOK
159 }
160
7f919115
LOK
161 /* handle the command */
162 bHandled = m_handler->HandleCommand(command);
8fa35473 163
7f919115 164 /* change status to present */
004b8382 165 if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST)
8d915412 166 {
f00ff009 167 CLockObject lock(m_mutex);
8fa35473 168 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
8d915412 169 {
8fa35473 170 if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
004b8382 171 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
8fa35473 172 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
8d915412 173 }
8d915412 174 }
7f919115 175
1344fd1a 176 MarkReady();
7f919115 177 return bHandled;
93729720
LOK
178}
179
004b8382 180const char* CCECBusDevice::GetLogicalAddressName(void) const
93729720 181{
004b8382
LOK
182 return ToString(m_iLogicalAddress);
183}
184
185bool CCECBusDevice::IsPresent(void)
186{
187 CLockObject lock(m_mutex);
188 return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
189}
190
191bool CCECBusDevice::IsHandledByLibCEC(void)
192{
193 CLockObject lock(m_mutex);
194 return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
195}
196
197void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
198{
199 // some commands should never be marked as unsupported
200 if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
201 opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
202 opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
203 opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
204 opcode == CEC_OPCODE_ABORT ||
205 opcode == CEC_OPCODE_FEATURE_ABORT ||
206 opcode == CEC_OPCODE_NONE)
207 return;
c6d7f0e1 208
5e5637c6 209 {
004b8382
LOK
210 CLockObject lock(m_mutex);
211 if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
8670c970 212 {
004b8382
LOK
213 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
214 m_unsupportedFeatures.insert(opcode);
8670c970
LOK
215 }
216 }
f437e4be 217
004b8382
LOK
218 // signal threads that are waiting for a reponse
219 MarkBusy();
220 m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
221 MarkReady();
222}
223
224bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
225{
226 CLockObject lock(m_mutex);
227 bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
228 if (bUnsupported)
229 LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
230 return bUnsupported;
231}
232
233bool CCECBusDevice::TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait /* = true */)
234{
235 MarkBusy();
236 bool bReturn = m_handler->TransmitKeypress(initiator, m_iLogicalAddress, key, bWait);
1344fd1a
LOK
237 MarkReady();
238 return bReturn;
93729720
LOK
239}
240
004b8382 241bool CCECBusDevice::TransmitKeyRelease(const cec_logical_address initiator, bool bWait /* = true */)
93729720 242{
1344fd1a 243 MarkBusy();
004b8382 244 bool bReturn = m_handler->TransmitKeyRelease(initiator, m_iLogicalAddress, bWait);
1344fd1a
LOK
245 MarkReady();
246 return bReturn;
93729720
LOK
247}
248
004b8382 249cec_version CCECBusDevice::GetCecVersion(const cec_logical_address initiator, bool bUpdate /* = false */)
93729720 250{
6bbfc3f7 251 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
252 bool bRequestUpdate(false);
253 {
f00ff009 254 CLockObject lock(m_mutex);
ddb6ac5b 255 bRequestUpdate = bIsPresent &&
6bbfc3f7 256 (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN);
97fc4ffb
LOK
257 }
258
259 if (bRequestUpdate)
ebb6ddb3 260 {
004b8382
LOK
261 CheckVendorIdRequested(initiator);
262 RequestCecVersion(initiator);
ebb6ddb3 263 }
f294b22f 264
f00ff009 265 CLockObject lock(m_mutex);
f294b22f
LOK
266 return m_cecVersion;
267}
268
004b8382 269void CCECBusDevice::SetCecVersion(const cec_version newVersion)
5734016c 270{
004b8382
LOK
271 CLockObject lock(m_mutex);
272 if (m_cecVersion != newVersion)
273 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
274 m_cecVersion = newVersion;
5734016c
LOK
275}
276
004b8382 277bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
278{
279 bool bReturn(false);
b64db02e 280
004b8382 281 if (!IsHandledByLibCEC() &&
66c3ef5a 282 !IsUnsupportedFeature(CEC_OPCODE_GET_CEC_VERSION))
93729720 283 {
1344fd1a 284 MarkBusy();
004b8382
LOK
285 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
286 bReturn = m_handler->TransmitRequestCecVersion(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 287 MarkReady();
93729720 288 }
f294b22f 289 return bReturn;
93729720
LOK
290}
291
004b8382 292bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination)
62f5527d 293{
004b8382
LOK
294 cec_version version;
295 {
296 CLockObject lock(m_mutex);
297 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_cecVersion));
298 version = m_cecVersion;
299 }
300
301 MarkBusy();
302 bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version);
303 MarkReady();
304 return bReturn;
62f5527d
LOK
305}
306
004b8382 307cec_menu_language &CCECBusDevice::GetMenuLanguage(const cec_logical_address initiator, bool bUpdate /* = false */)
93729720 308{
6bbfc3f7 309 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
310 bool bRequestUpdate(false);
311 {
f00ff009 312 CLockObject lock(m_mutex);
ddb6ac5b 313 bRequestUpdate = (bIsPresent &&
97fc4ffb
LOK
314 (bUpdate || !strcmp(m_menuLanguage.language, "???")));
315 }
316
317 if (bRequestUpdate)
ebb6ddb3 318 {
004b8382
LOK
319 CheckVendorIdRequested(initiator);
320 RequestMenuLanguage(initiator);
ebb6ddb3 321 }
5e5637c6 322
f00ff009 323 CLockObject lock(m_mutex);
f294b22f
LOK
324 return m_menuLanguage;
325}
326
004b8382
LOK
327void CCECBusDevice::SetMenuLanguage(const char *strLanguage)
328{
329 if (!strLanguage)
330 return;
331
332 CLockObject lock(m_mutex);
333 if (strcmp(strLanguage, m_menuLanguage.language))
334 {
335 memcpy(m_menuLanguage.language, strLanguage, 3);
336 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, m_menuLanguage.language);
337 }
338}
339
340void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
341{
342 if (language.device == m_iLogicalAddress)
343 SetMenuLanguage(language.language);
344}
345
346bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
347{
348 bool bReturn(false);
b64db02e 349
004b8382 350 if (!IsHandledByLibCEC() &&
4d738fe3 351 !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
93729720 352 {
1344fd1a 353 MarkBusy();
004b8382
LOK
354 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
355 bReturn = m_handler->TransmitRequestMenuLanguage(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 356 MarkReady();
93729720 357 }
f294b22f 358 return bReturn;
93729720
LOK
359}
360
004b8382 361bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination)
3e61b350 362{
004b8382
LOK
363 bool bReturn(false);
364 cec_menu_language language;
365 {
366 CLockObject lock(m_mutex);
367 language = m_menuLanguage;
368 }
3e61b350 369
004b8382
LOK
370 char lang[3];
371 {
372 CLockObject lock(m_mutex);
373 lang[0] = language.language[0];
374 lang[1] = language.language[1];
375 lang[2] = language.language[2];
376 }
377
378 MarkBusy();
379 if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
380 {
381 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): Menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
382 m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
383 bReturn = true;
384 }
385 else
386 {
387 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
388 bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
389 }
390 MarkReady();
391 return bReturn;
f8513317
LOK
392}
393
004b8382 394bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage)
e9de9629 395{
004b8382
LOK
396 bool bReturn(false);
397 if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
398 {
399 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage);
400 MarkBusy();
401 bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage);
402 MarkReady();
403 }
404 return bReturn;
e9de9629
LOK
405}
406
c0152c09
LOK
407CStdString CCECBusDevice::GetCurrentOSDName(void)
408{
409 CLockObject lock(m_mutex);
410 return m_strDeviceName;
411}
412
004b8382 413CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
ed21be2a 414{
6bbfc3f7 415 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
416 bool bRequestUpdate(false);
417 {
f00ff009 418 CLockObject lock(m_mutex);
ddb6ac5b 419 bRequestUpdate = bIsPresent &&
97fc4ffb 420 (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
ddb6ac5b 421 m_type != CEC_DEVICE_TYPE_TV;
97fc4ffb
LOK
422 }
423
424 if (bRequestUpdate)
ebb6ddb3 425 {
004b8382
LOK
426 CheckVendorIdRequested(initiator);
427 RequestOSDName(initiator);
ebb6ddb3 428 }
5e5637c6 429
f00ff009 430 CLockObject lock(m_mutex);
ed21be2a
LOK
431 return m_strDeviceName;
432}
433
004b8382
LOK
434void CCECBusDevice::SetOSDName(CStdString strName)
435{
436 CLockObject lock(m_mutex);
437 if (m_strDeviceName != strName)
438 {
439 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
440 m_strDeviceName = strName;
441 }
442}
443
444bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
ed21be2a
LOK
445{
446 bool bReturn(false);
b64db02e 447
004b8382 448 if (!IsHandledByLibCEC() &&
4d738fe3 449 !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
ed21be2a 450 {
1344fd1a 451 MarkBusy();
004b8382
LOK
452 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
453 bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 454 MarkReady();
ed21be2a
LOK
455 }
456 return bReturn;
457}
458
004b8382
LOK
459bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
460{
461 CStdString strDeviceName;
462 {
463 CLockObject lock(m_mutex);
464 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
465 strDeviceName = m_strDeviceName;
466 }
467
468 MarkBusy();
469 bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
470 MarkReady();
471 return bReturn;
472}
473
474bool CCECBusDevice::HasValidPhysicalAddress(void)
475{
476 CLockObject lock(m_mutex);
477 return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
478}
479
480uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
481{
482 CLockObject lock(m_mutex);
483 return m_iPhysicalAddress;
484}
485
486uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
16b1e052 487{
0680dab3 488 if (!bSuppressUpdate)
16b1e052 489 {
0680dab3
LOK
490 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
491 bool bRequestUpdate(false);
492 {
493 CLockObject lock(m_mutex);
b32ffd87 494 bRequestUpdate = bIsPresent && m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS;
0680dab3 495 }
16b1e052 496
0680dab3
LOK
497 if (bRequestUpdate)
498 {
004b8382
LOK
499 CheckVendorIdRequested(initiator);
500 if (!RequestPhysicalAddress(initiator))
501 LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
0680dab3 502 }
ebb6ddb3 503 }
97fc4ffb 504
f00ff009 505 CLockObject lock(m_mutex);
16b1e052
LOK
506 return m_iPhysicalAddress;
507}
508
004b8382
LOK
509bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
510{
511 CLockObject lock(m_mutex);
512 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
513 {
514 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
515 m_iPhysicalAddress = iNewAddress;
516 }
517 return true;
518}
519
520bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
16b1e052
LOK
521{
522 bool bReturn(false);
b64db02e 523
004b8382 524 if (!IsHandledByLibCEC())
16b1e052 525 {
1344fd1a 526 MarkBusy();
004b8382
LOK
527 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
528 bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 529 MarkReady();
16b1e052
LOK
530 }
531 return bReturn;
532}
533
004b8382
LOK
534bool CCECBusDevice::TransmitPhysicalAddress(void)
535{
536 uint16_t iPhysicalAddress;
537 cec_device_type type;
538 {
539 CLockObject lock(m_mutex);
540 if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
541 return false;
542
543 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
544 iPhysicalAddress = m_iPhysicalAddress;
545 type = m_type;
546 }
547
548 MarkBusy();
549 bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
550 MarkReady();
551 return bReturn;
552}
553
554cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
555{
556 CLockObject lock(m_mutex);
557 return m_powerStatus;
558}
559
560cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
e9de9629 561{
6bbfc3f7 562 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
563 bool bRequestUpdate(false);
564 {
f00ff009 565 CLockObject lock(m_mutex);
ddb6ac5b 566 bRequestUpdate = (bIsPresent &&
c8f0eef0 567 (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
2efa39b7
LOK
568 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON ||
569 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY ||
570 GetTimeMs() - m_iLastPowerStateUpdate >= CEC_POWER_STATE_REFRESH_TIME));
97fc4ffb
LOK
571 }
572
573 if (bRequestUpdate)
ebb6ddb3 574 {
004b8382
LOK
575 CheckVendorIdRequested(initiator);
576 RequestPowerStatus(initiator);
ebb6ddb3 577 }
5e5637c6 578
f00ff009 579 CLockObject lock(m_mutex);
f294b22f
LOK
580 return m_powerStatus;
581}
582
004b8382
LOK
583void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
584{
585 CLockObject lock(m_mutex);
586 if (m_powerStatus != powerStatus)
587 {
588 m_iLastPowerStateUpdate = GetTimeMs();
589 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
590 m_powerStatus = powerStatus;
591 }
592}
593
594bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
595{
596 bool bReturn(false);
b64db02e 597
004b8382 598 if (!IsHandledByLibCEC() &&
4d738fe3 599 !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
93729720 600 {
1344fd1a 601 MarkBusy();
004b8382
LOK
602 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
603 bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 604 MarkReady();
93729720 605 }
f294b22f
LOK
606 return bReturn;
607}
93729720 608
004b8382 609bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
f294b22f 610{
004b8382 611 cec_power_status state;
97fc4ffb 612 {
f00ff009 613 CLockObject lock(m_mutex);
004b8382
LOK
614 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
615 state = m_powerStatus;
97fc4ffb
LOK
616 }
617
004b8382
LOK
618 MarkBusy();
619 bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
620 MarkReady();
621 return bReturn;
622}
623
624cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
625{
626 CLockObject lock(m_mutex);
f294b22f 627 return m_vendor;
e9de9629
LOK
628}
629
004b8382
LOK
630cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
631{
632 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
633 bool bRequestUpdate(false);
634 {
635 CLockObject lock(m_mutex);
636 bRequestUpdate = (bIsPresent &&
637 (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
638 }
639
640 if (bRequestUpdate)
641 RequestVendorId(initiator);
642
643 CLockObject lock(m_mutex);
644 return m_vendor;
645}
646
647const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
648{
649 return ToString(GetVendorId(initiator, bUpdate));
650}
651
652bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
653{
654 bool bVendorChanged(false);
655
656 {
657 CLockObject lock(m_mutex);
658 bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
659 m_vendor = (cec_vendor_id)iVendorId;
660 }
661
662 if (bVendorChanged)
663 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
664
665 return bVendorChanged;
666}
667
668bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
a3269a0a 669{
f294b22f 670 bool bReturn(false);
b64db02e 671
004b8382 672 if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
a3269a0a 673 {
1344fd1a 674 MarkBusy();
004b8382
LOK
675 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
676 bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 677 MarkReady();
3e61b350 678
a75e3a5a
LOK
679 if (bWaitForResponse)
680 ReplaceHandler(true);
a3269a0a 681 }
f294b22f 682 return bReturn;
93729720
LOK
683}
684
004b8382 685bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
93729720 686{
004b8382
LOK
687 bool bReturn(false);
688 uint64_t iVendorId;
689 {
690 CLockObject lock(m_mutex);
691 iVendorId = (uint64_t)m_vendor;
692 }
a3269a0a 693
004b8382
LOK
694 MarkBusy();
695 if (iVendorId == CEC_VENDOR_UNKNOWN)
9fd73dd4 696 {
004b8382 697 if (bSendAbort)
c6d7f0e1 698 {
004b8382
LOK
699 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
700 m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
701 bReturn = true;
c6d7f0e1 702 }
9fd73dd4 703 }
004b8382
LOK
704 else
705 {
706 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
707 bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
708 }
709 MarkReady();
710 return bReturn;
9fd73dd4
LOK
711}
712
a75e3a5a 713cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
f8ae3295 714{
ba427965
LOK
715 cec_bus_device_status status(CEC_DEVICE_STATUS_UNKNOWN);
716 bool bNeedsPoll(false);
717
718 {
719 CLockObject lock(m_mutex);
720 status = m_deviceStatus;
a75e3a5a
LOK
721 bNeedsPoll = !bSuppressPoll &&
722 (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN);
ba427965
LOK
723 }
724
725 if (bNeedsPoll)
f8ae3295 726 {
9fd73dd4 727 bool bPollAcked(false);
7b62b76e 728 if (bNeedsPoll && NeedsPoll())
9fd73dd4 729 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
95a73fa7 730
ba427965
LOK
731 status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
732 SetDeviceStatus(status);
f8ae3295
LOK
733 }
734
ba427965 735 return status;
f8ae3295
LOK
736}
737
93fff5c1
LOK
738void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
739{
93fff5c1 740 {
ee17ad58
LOK
741 CLockObject lock(m_mutex);
742 switch (newStatus)
743 {
744 case CEC_DEVICE_STATUS_UNKNOWN:
745 if (m_deviceStatus != newStatus)
004b8382 746 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
a20d808d
LOK
747 ResetDeviceStatus();
748 m_deviceStatus = newStatus;
ee17ad58
LOK
749 break;
750 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
751 if (m_deviceStatus != newStatus)
004b8382 752 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
a20d808d
LOK
753 SetPowerStatus (CEC_POWER_STATUS_ON);
754 SetVendorId (CEC_VENDOR_UNKNOWN);
755 SetMenuState (CEC_MENU_STATE_ACTIVATED);
756 SetCecVersion (CEC_VERSION_1_3A);
b32ffd87 757 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
004b8382 758 MarkAsInactiveSource();
a20d808d
LOK
759 m_iLastActive = 0;
760 m_deviceStatus = newStatus;
ee17ad58
LOK
761 break;
762 case CEC_DEVICE_STATUS_PRESENT:
763 if (m_deviceStatus != newStatus)
004b8382 764 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
ee17ad58
LOK
765 m_deviceStatus = newStatus;
766 break;
767 case CEC_DEVICE_STATUS_NOT_PRESENT:
768 if (m_deviceStatus != newStatus)
a20d808d 769 {
004b8382 770 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
a20d808d
LOK
771 ResetDeviceStatus();
772 m_deviceStatus = newStatus;
773 }
ee17ad58
LOK
774 break;
775 }
93fff5c1
LOK
776 }
777}
778
004b8382 779void CCECBusDevice::ResetDeviceStatus(void)
93729720 780{
f00ff009 781 CLockObject lock(m_mutex);
004b8382
LOK
782 SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
783 SetVendorId (CEC_VENDOR_UNKNOWN);
784 SetMenuState (CEC_MENU_STATE_ACTIVATED);
785 SetCecVersion (CEC_VERSION_UNKNOWN);
786 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
787 SetOSDName (ToString(m_iLogicalAddress));
788 MarkAsInactiveSource();
789 m_iLastActive = 0;
790 m_bVendorIdRequested = false;
791 m_unsupportedFeatures.clear();
93729720
LOK
792}
793
004b8382 794bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
9dc04b07 795{
004b8382
LOK
796 bool bReturn(false);
797 cec_logical_address destination(dest);
798 if (destination == CECDEVICE_UNKNOWN)
799 destination = m_iLogicalAddress;
96274140 800
004b8382
LOK
801 CCECBusDevice *destDevice = m_processor->GetDevice(destination);
802 if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
803 return bReturn;
804
805 MarkBusy();
806 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
807 bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
808 LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
809
810 CLockObject lock(m_mutex);
811 if (bReturn)
5f2068fe 812 {
004b8382
LOK
813 m_iLastActive = GetTimeMs();
814 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
5f2068fe
LOK
815 }
816 else
004b8382
LOK
817 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
818
819 MarkReady();
820 return bReturn;
821}
822
823void CCECBusDevice::HandlePoll(const cec_logical_address destination)
824{
825 if (destination >= 0 && destination < CECDEVICE_BROADCAST)
5f2068fe 826 {
004b8382 827 CCECBusDevice *device = m_processor->GetDevice(destination);
0cb55c43 828 if (device)
004b8382 829 device->HandlePollFrom(m_iLogicalAddress);
9dc04b07
LOK
830 }
831}
832
004b8382 833void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
e55f3f70 834{
004b8382
LOK
835 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
836 m_bAwaitingReceiveFailed = true;
e55f3f70
LOK
837}
838
004b8382 839bool CCECBusDevice::HandleReceiveFailed(void)
1344fd1a 840{
004b8382
LOK
841 bool bReturn = m_bAwaitingReceiveFailed;
842 m_bAwaitingReceiveFailed = false;
843 return bReturn;
1344fd1a
LOK
844}
845
004b8382 846cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
1344fd1a 847{
004b8382
LOK
848 CLockObject lock(m_mutex);
849 return m_menuState;
1344fd1a
LOK
850}
851
004b8382 852void CCECBusDevice::SetMenuState(const cec_menu_state state)
e9de9629 853{
004b8382
LOK
854 CLockObject lock(m_mutex);
855 if (m_menuState != state)
94e9a2af 856 {
004b8382
LOK
857 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
858 m_menuState = state;
859 }
860}
d211708b 861
004b8382
LOK
862bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
863{
864 cec_menu_state menuState;
865 {
866 CLockObject lock(m_mutex);
867 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
868 menuState = m_menuState;
869 }
104125dc 870
004b8382
LOK
871 MarkBusy();
872 bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
873 MarkReady();
874 return bReturn;
875}
94e9a2af 876
004b8382
LOK
877bool CCECBusDevice::ActivateSource(void)
878{
879 MarkAsActiveSource();
880 LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
881 MarkBusy();
882 bool bReturn = m_handler->ActivateSource();
883 MarkReady();
884 return bReturn;
885}
94e9a2af 886
004b8382
LOK
887bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
888{
889 bool bReturn(false);
e9de9629 890
004b8382 891 if (IsHandledByLibCEC())
104125dc 892 {
004b8382
LOK
893 MarkBusy();
894 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
104125dc 895
004b8382
LOK
896 bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
897 MarkReady();
104125dc 898 }
004b8382
LOK
899 return bReturn;
900}
104125dc 901
004b8382
LOK
902void CCECBusDevice::MarkAsActiveSource(void)
903{
904 CLockObject lock(m_mutex);
905 if (!m_bActiveSource)
906 LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
907 else
908 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
104125dc 909
004b8382
LOK
910 CECDEVICEVEC devices;
911 m_processor->GetDevices()->Get(devices);
912 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
913 if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
914 (*it)->MarkAsInactiveSource();
915
916 m_bActiveSource = true;
917 SetPowerStatus(CEC_POWER_STATUS_ON);
b64db02e
LOK
918}
919
004b8382 920void CCECBusDevice::MarkAsInactiveSource(void)
b64db02e 921{
b64db02e 922 {
f00ff009 923 CLockObject lock(m_mutex);
004b8382
LOK
924 if (m_bActiveSource)
925 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
926 m_bActiveSource = false;
b64db02e 927 }
e9de9629
LOK
928}
929
93729720 930bool CCECBusDevice::TransmitActiveSource(void)
0f23c85c 931{
8fa35473 932 bool bSendActiveSource(false);
0f23c85c 933
8747dd4f 934 {
f00ff009 935 CLockObject lock(m_mutex);
49c8f2e4 936 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
004b8382 937 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
8fa35473
LOK
938 else if (m_bActiveSource)
939 {
004b8382 940 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
8fa35473
LOK
941 bSendActiveSource = true;
942 }
943 else
004b8382 944 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
8747dd4f
LOK
945 }
946
b64db02e
LOK
947 if (bSendActiveSource)
948 {
1344fd1a 949 MarkBusy();
468a1414 950 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
1344fd1a 951 MarkReady();
b64db02e
LOK
952 return true;
953 }
954
955 return false;
0f23c85c
LOK
956}
957
49c8f2e4
LOK
958bool CCECBusDevice::TransmitImageViewOn(void)
959{
49c8f2e4 960 {
9a2f12df
LOK
961 CLockObject lock(m_mutex);
962 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
963 {
004b8382 964 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
9a2f12df
LOK
965 return false;
966 }
49c8f2e4 967 }
9a2f12df
LOK
968
969 MarkBusy();
970 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
971 MarkReady();
972 return true;
49c8f2e4
LOK
973}
974
ab27363d 975bool CCECBusDevice::TransmitInactiveSource(void)
93729720 976{
8fa35473
LOK
977 uint16_t iPhysicalAddress;
978 {
f00ff009 979 CLockObject lock(m_mutex);
004b8382 980 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
8fa35473
LOK
981 iPhysicalAddress = m_iPhysicalAddress;
982 }
93729720 983
1344fd1a
LOK
984 MarkBusy();
985 bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
986 MarkReady();
987 return bReturn;
93729720
LOK
988}
989
004b8382 990bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
0f23c85c 991{
1344fd1a 992 MarkBusy();
004b8382 993 bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
1344fd1a
LOK
994 MarkReady();
995 return bReturn;
0f23c85c
LOK
996}
997
004b8382 998void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
0f23c85c 999{
004b8382
LOK
1000 CLockObject lock(m_mutex);
1001 if (iNewAddress != m_iStreamPath)
8fa35473 1002 {
004b8382
LOK
1003 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
1004 m_iStreamPath = iNewAddress;
8fa35473 1005 }
0f23c85c 1006
99aeafb9
LOK
1007 if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
1008 return;
1009
004b8382
LOK
1010 CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
1011 if (device)
4d738fe3 1012 {
004b8382
LOK
1013 // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
1014 device->MarkAsActiveSource();
4d738fe3 1015 }
004b8382 1016 else
8fa35473 1017 {
004b8382
LOK
1018 // try to find the device with the old address, and mark it as inactive when found
1019 device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
1020 if (device)
1021 device->MarkAsInactiveSource();
8fa35473 1022 }
0f23c85c
LOK
1023}
1024
004b8382 1025bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
fbdea54c
MK
1026{
1027 bool bReturn(false);
004b8382 1028 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
fbdea54c
MK
1029
1030 MarkBusy();
004b8382
LOK
1031 cec_power_status currentStatus = GetPowerStatus(initiator, false);
1032 if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
1033 currentStatus != CEC_POWER_STATUS_ON)
fbdea54c 1034 {
004b8382
LOK
1035 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
1036 if (m_handler->PowerOn(initiator, m_iLogicalAddress))
1037 {
1038 SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
fbdea54c 1039 bReturn = true;
004b8382 1040 }
fbdea54c
MK
1041 }
1042 else
1043 {
004b8382 1044 LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
fbdea54c 1045 }
004b8382 1046
fbdea54c
MK
1047 MarkReady();
1048 return bReturn;
1049}
1050
004b8382 1051bool CCECBusDevice::Standby(const cec_logical_address initiator)
57f45e6c 1052{
004b8382 1053 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
b750a5c3 1054
004b8382 1055 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
1344fd1a 1056 MarkBusy();
004b8382 1057 bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
1344fd1a 1058 MarkReady();
57f45e6c
LOK
1059 return bReturn;
1060}
93729720 1061
004b8382 1062bool CCECBusDevice::NeedsPoll(void)
93729720 1063{
004b8382
LOK
1064 bool bSendPoll(false);
1065 cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
1066 switch (m_iLogicalAddress)
8fa35473 1067 {
004b8382
LOK
1068 case CECDEVICE_PLAYBACKDEVICE3:
1069 pollAddress = CECDEVICE_PLAYBACKDEVICE2;
1070 break;
1071 case CECDEVICE_PLAYBACKDEVICE2:
1072 pollAddress = CECDEVICE_PLAYBACKDEVICE1;
1073 break;
1074 case CECDEVICE_RECORDINGDEVICE3:
1075 pollAddress = CECDEVICE_RECORDINGDEVICE2;
1076 break;
1077 case CECDEVICE_RECORDINGDEVICE2:
1078 pollAddress = CECDEVICE_RECORDINGDEVICE1;
1079 break;
1080 case CECDEVICE_TUNER4:
1081 pollAddress = CECDEVICE_TUNER3;
1082 break;
1083 case CECDEVICE_TUNER3:
1084 pollAddress = CECDEVICE_TUNER2;
1085 break;
1086 case CECDEVICE_TUNER2:
1087 pollAddress = CECDEVICE_TUNER1;
1088 break;
1089 case CECDEVICE_AUDIOSYSTEM:
1090 case CECDEVICE_PLAYBACKDEVICE1:
1091 case CECDEVICE_RECORDINGDEVICE1:
1092 case CECDEVICE_TUNER1:
1093 case CECDEVICE_TV:
1094 bSendPoll = true;
1095 break;
1096 default:
1097 break;
8fa35473 1098 }
93729720 1099
004b8382
LOK
1100 if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
1101 {
1102 CCECBusDevice *device = m_processor->GetDevice(pollAddress);
1103 if (device)
1104 {
1105 cec_bus_device_status status = device->GetStatus();
1106 bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1107 }
1108 else
1109 {
1110 bSendPoll = true;
1111 }
1112 }
1113
1114 return bSendPoll;
93729720
LOK
1115}
1116
004b8382 1117void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
93729720 1118{
004b8382 1119 bool bRequestVendorId(false);
8fa35473 1120 {
f00ff009 1121 CLockObject lock(m_mutex);
004b8382
LOK
1122 bRequestVendorId = !m_bVendorIdRequested;
1123 m_bVendorIdRequested = true;
8fa35473
LOK
1124 }
1125
004b8382 1126 if (bRequestVendorId)
c4098482 1127 {
004b8382
LOK
1128 ReplaceHandler(false);
1129 GetVendorId(initiator);
c4098482 1130 }
93729720 1131}
004b8382 1132//@}
a33794d8 1133
004b8382 1134CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
a33794d8 1135{
004b8382 1136 return AsAudioSystem(this);
a33794d8
LOK
1137}
1138
004b8382 1139CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
a33794d8 1140{
004b8382 1141 return AsPlaybackDevice(this);
a33794d8 1142}
4d738fe3 1143
004b8382 1144CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
4d738fe3 1145{
004b8382 1146 return AsRecordingDevice(this);
4d738fe3
LOK
1147}
1148
004b8382 1149CCECTuner *CCECBusDevice::AsTuner(void)
4d738fe3 1150{
004b8382
LOK
1151 return AsTuner(this);
1152}
ad7e0696 1153
004b8382
LOK
1154CCECTV *CCECBusDevice::AsTV(void)
1155{
1156 return AsTV(this);
1157}
b499cf16 1158
004b8382
LOK
1159CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
1160{
1161 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
1162 return static_cast<CCECAudioSystem *>(device);
1163 return NULL;
4d738fe3 1164}
b64db02e 1165
004b8382 1166CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
b64db02e 1167{
004b8382
LOK
1168 if (device &&
1169 (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
1170 device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
1171 return static_cast<CCECPlaybackDevice *>(device);
1172 return NULL;
b64db02e
LOK
1173}
1174
004b8382 1175CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
a75e3a5a 1176{
004b8382
LOK
1177 if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
1178 return static_cast<CCECRecordingDevice *>(device);
1179 return NULL;
a75e3a5a
LOK
1180}
1181
004b8382 1182CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
0cfdeb5a 1183{
004b8382
LOK
1184 if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
1185 return static_cast<CCECTuner *>(device);
1186 return NULL;
0cfdeb5a
LOK
1187}
1188
004b8382 1189CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
0cfdeb5a 1190{
004b8382
LOK
1191 if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
1192 return static_cast<CCECTV *>(device);
1193 return NULL;
0cfdeb5a
LOK
1194}
1195
004b8382 1196void CCECBusDevice::MarkBusy(void)
ebb6ddb3 1197{
004b8382
LOK
1198 CLockObject handlerLock(m_handlerMutex);
1199 ++m_iHandlerUseCount;
1200}
ebb6ddb3 1201
004b8382
LOK
1202void CCECBusDevice::MarkReady(void)
1203{
1204 CLockObject handlerLock(m_handlerMutex);
1205 if (m_iHandlerUseCount > 0)
1206 --m_iHandlerUseCount;
1207}
1208
1209bool CCECBusDevice::TryLogicalAddress(void)
1210{
1211 LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
1212
1213 if (!TransmitPoll(m_iLogicalAddress))
ebb6ddb3 1214 {
004b8382
LOK
1215 LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
1216 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1217
1218 return true;
ebb6ddb3 1219 }
004b8382
LOK
1220
1221 LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
1222 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
1223 return false;
ebb6ddb3
LOK
1224}
1225
004b8382 1226CCECClient *CCECBusDevice::GetClient(void)
b78b4e33 1227{
004b8382 1228 return m_processor->GetClient(m_iLogicalAddress);
b78b4e33 1229}