win32: sync project files and fixed compilation warnings.
[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
004b8382 407CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
ed21be2a 408{
6bbfc3f7 409 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
410 bool bRequestUpdate(false);
411 {
f00ff009 412 CLockObject lock(m_mutex);
ddb6ac5b 413 bRequestUpdate = bIsPresent &&
97fc4ffb 414 (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
ddb6ac5b 415 m_type != CEC_DEVICE_TYPE_TV;
97fc4ffb
LOK
416 }
417
418 if (bRequestUpdate)
ebb6ddb3 419 {
004b8382
LOK
420 CheckVendorIdRequested(initiator);
421 RequestOSDName(initiator);
ebb6ddb3 422 }
5e5637c6 423
f00ff009 424 CLockObject lock(m_mutex);
ed21be2a
LOK
425 return m_strDeviceName;
426}
427
004b8382
LOK
428void CCECBusDevice::SetOSDName(CStdString strName)
429{
430 CLockObject lock(m_mutex);
431 if (m_strDeviceName != strName)
432 {
433 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
434 m_strDeviceName = strName;
435 }
436}
437
438bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
ed21be2a
LOK
439{
440 bool bReturn(false);
b64db02e 441
004b8382 442 if (!IsHandledByLibCEC() &&
4d738fe3 443 !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
ed21be2a 444 {
1344fd1a 445 MarkBusy();
004b8382
LOK
446 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
447 bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 448 MarkReady();
ed21be2a
LOK
449 }
450 return bReturn;
451}
452
004b8382
LOK
453bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
454{
455 CStdString strDeviceName;
456 {
457 CLockObject lock(m_mutex);
458 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
459 strDeviceName = m_strDeviceName;
460 }
461
462 MarkBusy();
463 bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
464 MarkReady();
465 return bReturn;
466}
467
468bool CCECBusDevice::HasValidPhysicalAddress(void)
469{
470 CLockObject lock(m_mutex);
471 return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
472}
473
474uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
475{
476 CLockObject lock(m_mutex);
477 return m_iPhysicalAddress;
478}
479
480uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
16b1e052 481{
0680dab3 482 if (!bSuppressUpdate)
16b1e052 483 {
0680dab3
LOK
484 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
485 bool bRequestUpdate(false);
486 {
487 CLockObject lock(m_mutex);
b32ffd87 488 bRequestUpdate = bIsPresent && m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS;
0680dab3 489 }
16b1e052 490
0680dab3
LOK
491 if (bRequestUpdate)
492 {
004b8382
LOK
493 CheckVendorIdRequested(initiator);
494 if (!RequestPhysicalAddress(initiator))
495 LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
0680dab3 496 }
ebb6ddb3 497 }
97fc4ffb 498
f00ff009 499 CLockObject lock(m_mutex);
16b1e052
LOK
500 return m_iPhysicalAddress;
501}
502
004b8382
LOK
503bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
504{
505 CLockObject lock(m_mutex);
506 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
507 {
508 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
509 m_iPhysicalAddress = iNewAddress;
510 }
511 return true;
512}
513
514bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
16b1e052
LOK
515{
516 bool bReturn(false);
b64db02e 517
004b8382 518 if (!IsHandledByLibCEC())
16b1e052 519 {
1344fd1a 520 MarkBusy();
004b8382
LOK
521 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
522 bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 523 MarkReady();
16b1e052
LOK
524 }
525 return bReturn;
526}
527
004b8382
LOK
528bool CCECBusDevice::TransmitPhysicalAddress(void)
529{
530 uint16_t iPhysicalAddress;
531 cec_device_type type;
532 {
533 CLockObject lock(m_mutex);
534 if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
535 return false;
536
537 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
538 iPhysicalAddress = m_iPhysicalAddress;
539 type = m_type;
540 }
541
542 MarkBusy();
543 bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
544 MarkReady();
545 return bReturn;
546}
547
548cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
549{
550 CLockObject lock(m_mutex);
551 return m_powerStatus;
552}
553
554cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
e9de9629 555{
6bbfc3f7 556 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
557 bool bRequestUpdate(false);
558 {
f00ff009 559 CLockObject lock(m_mutex);
ddb6ac5b 560 bRequestUpdate = (bIsPresent &&
c8f0eef0 561 (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
2efa39b7
LOK
562 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON ||
563 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY ||
564 GetTimeMs() - m_iLastPowerStateUpdate >= CEC_POWER_STATE_REFRESH_TIME));
97fc4ffb
LOK
565 }
566
567 if (bRequestUpdate)
ebb6ddb3 568 {
004b8382
LOK
569 CheckVendorIdRequested(initiator);
570 RequestPowerStatus(initiator);
ebb6ddb3 571 }
5e5637c6 572
f00ff009 573 CLockObject lock(m_mutex);
f294b22f
LOK
574 return m_powerStatus;
575}
576
004b8382
LOK
577void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
578{
579 CLockObject lock(m_mutex);
580 if (m_powerStatus != powerStatus)
581 {
582 m_iLastPowerStateUpdate = GetTimeMs();
583 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
584 m_powerStatus = powerStatus;
585 }
586}
587
588bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
589{
590 bool bReturn(false);
b64db02e 591
004b8382 592 if (!IsHandledByLibCEC() &&
4d738fe3 593 !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
93729720 594 {
1344fd1a 595 MarkBusy();
004b8382
LOK
596 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
597 bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 598 MarkReady();
93729720 599 }
f294b22f
LOK
600 return bReturn;
601}
93729720 602
004b8382 603bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
f294b22f 604{
004b8382 605 cec_power_status state;
97fc4ffb 606 {
f00ff009 607 CLockObject lock(m_mutex);
004b8382
LOK
608 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
609 state = m_powerStatus;
97fc4ffb
LOK
610 }
611
004b8382
LOK
612 MarkBusy();
613 bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
614 MarkReady();
615 return bReturn;
616}
617
618cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
619{
620 CLockObject lock(m_mutex);
f294b22f 621 return m_vendor;
e9de9629
LOK
622}
623
004b8382
LOK
624cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
625{
626 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
627 bool bRequestUpdate(false);
628 {
629 CLockObject lock(m_mutex);
630 bRequestUpdate = (bIsPresent &&
631 (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
632 }
633
634 if (bRequestUpdate)
635 RequestVendorId(initiator);
636
637 CLockObject lock(m_mutex);
638 return m_vendor;
639}
640
641const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
642{
643 return ToString(GetVendorId(initiator, bUpdate));
644}
645
646bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
647{
648 bool bVendorChanged(false);
649
650 {
651 CLockObject lock(m_mutex);
652 bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
653 m_vendor = (cec_vendor_id)iVendorId;
654 }
655
656 if (bVendorChanged)
657 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
658
659 return bVendorChanged;
660}
661
662bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
a3269a0a 663{
f294b22f 664 bool bReturn(false);
b64db02e 665
004b8382 666 if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
a3269a0a 667 {
1344fd1a 668 MarkBusy();
004b8382
LOK
669 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
670 bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
1344fd1a 671 MarkReady();
3e61b350 672
a75e3a5a
LOK
673 if (bWaitForResponse)
674 ReplaceHandler(true);
a3269a0a 675 }
f294b22f 676 return bReturn;
93729720
LOK
677}
678
004b8382 679bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
93729720 680{
004b8382
LOK
681 bool bReturn(false);
682 uint64_t iVendorId;
683 {
684 CLockObject lock(m_mutex);
685 iVendorId = (uint64_t)m_vendor;
686 }
a3269a0a 687
004b8382
LOK
688 MarkBusy();
689 if (iVendorId == CEC_VENDOR_UNKNOWN)
9fd73dd4 690 {
004b8382 691 if (bSendAbort)
c6d7f0e1 692 {
004b8382
LOK
693 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
694 m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
695 bReturn = true;
c6d7f0e1 696 }
9fd73dd4 697 }
004b8382
LOK
698 else
699 {
700 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);
701 bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
702 }
703 MarkReady();
704 return bReturn;
9fd73dd4
LOK
705}
706
a75e3a5a 707cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
f8ae3295 708{
ba427965
LOK
709 cec_bus_device_status status(CEC_DEVICE_STATUS_UNKNOWN);
710 bool bNeedsPoll(false);
711
712 {
713 CLockObject lock(m_mutex);
714 status = m_deviceStatus;
a75e3a5a
LOK
715 bNeedsPoll = !bSuppressPoll &&
716 (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN);
ba427965
LOK
717 }
718
719 if (bNeedsPoll)
f8ae3295 720 {
9fd73dd4 721 bool bPollAcked(false);
7b62b76e 722 if (bNeedsPoll && NeedsPoll())
9fd73dd4 723 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
95a73fa7 724
ba427965
LOK
725 status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
726 SetDeviceStatus(status);
f8ae3295
LOK
727 }
728
ba427965 729 return status;
f8ae3295
LOK
730}
731
93fff5c1
LOK
732void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
733{
93fff5c1 734 {
ee17ad58
LOK
735 CLockObject lock(m_mutex);
736 switch (newStatus)
737 {
738 case CEC_DEVICE_STATUS_UNKNOWN:
739 if (m_deviceStatus != newStatus)
004b8382 740 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
a20d808d
LOK
741 ResetDeviceStatus();
742 m_deviceStatus = newStatus;
ee17ad58
LOK
743 break;
744 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
745 if (m_deviceStatus != newStatus)
004b8382 746 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
a20d808d
LOK
747 SetPowerStatus (CEC_POWER_STATUS_ON);
748 SetVendorId (CEC_VENDOR_UNKNOWN);
749 SetMenuState (CEC_MENU_STATE_ACTIVATED);
750 SetCecVersion (CEC_VERSION_1_3A);
b32ffd87 751 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
004b8382 752 MarkAsInactiveSource();
a20d808d
LOK
753 m_iLastActive = 0;
754 m_deviceStatus = newStatus;
ee17ad58
LOK
755 break;
756 case CEC_DEVICE_STATUS_PRESENT:
757 if (m_deviceStatus != newStatus)
004b8382 758 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
ee17ad58
LOK
759 m_deviceStatus = newStatus;
760 break;
761 case CEC_DEVICE_STATUS_NOT_PRESENT:
762 if (m_deviceStatus != newStatus)
a20d808d 763 {
004b8382 764 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
a20d808d
LOK
765 ResetDeviceStatus();
766 m_deviceStatus = newStatus;
767 }
ee17ad58
LOK
768 break;
769 }
93fff5c1
LOK
770 }
771}
772
004b8382 773void CCECBusDevice::ResetDeviceStatus(void)
93729720 774{
f00ff009 775 CLockObject lock(m_mutex);
004b8382
LOK
776 SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
777 SetVendorId (CEC_VENDOR_UNKNOWN);
778 SetMenuState (CEC_MENU_STATE_ACTIVATED);
779 SetCecVersion (CEC_VERSION_UNKNOWN);
780 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
781 SetOSDName (ToString(m_iLogicalAddress));
782 MarkAsInactiveSource();
783 m_iLastActive = 0;
784 m_bVendorIdRequested = false;
785 m_unsupportedFeatures.clear();
93729720
LOK
786}
787
004b8382 788bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
9dc04b07 789{
004b8382
LOK
790 bool bReturn(false);
791 cec_logical_address destination(dest);
792 if (destination == CECDEVICE_UNKNOWN)
793 destination = m_iLogicalAddress;
96274140 794
004b8382
LOK
795 CCECBusDevice *destDevice = m_processor->GetDevice(destination);
796 if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
797 return bReturn;
798
799 MarkBusy();
800 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
801 bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
802 LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
803
804 CLockObject lock(m_mutex);
805 if (bReturn)
5f2068fe 806 {
004b8382
LOK
807 m_iLastActive = GetTimeMs();
808 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
5f2068fe
LOK
809 }
810 else
004b8382
LOK
811 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
812
813 MarkReady();
814 return bReturn;
815}
816
817void CCECBusDevice::HandlePoll(const cec_logical_address destination)
818{
819 if (destination >= 0 && destination < CECDEVICE_BROADCAST)
5f2068fe 820 {
004b8382 821 CCECBusDevice *device = m_processor->GetDevice(destination);
0cb55c43 822 if (device)
004b8382 823 device->HandlePollFrom(m_iLogicalAddress);
9dc04b07
LOK
824 }
825}
826
004b8382 827void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
e55f3f70 828{
004b8382
LOK
829 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
830 m_bAwaitingReceiveFailed = true;
e55f3f70
LOK
831}
832
004b8382 833bool CCECBusDevice::HandleReceiveFailed(void)
1344fd1a 834{
004b8382
LOK
835 bool bReturn = m_bAwaitingReceiveFailed;
836 m_bAwaitingReceiveFailed = false;
837 return bReturn;
1344fd1a
LOK
838}
839
004b8382 840cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
1344fd1a 841{
004b8382
LOK
842 CLockObject lock(m_mutex);
843 return m_menuState;
1344fd1a
LOK
844}
845
004b8382 846void CCECBusDevice::SetMenuState(const cec_menu_state state)
e9de9629 847{
004b8382
LOK
848 CLockObject lock(m_mutex);
849 if (m_menuState != state)
94e9a2af 850 {
004b8382
LOK
851 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
852 m_menuState = state;
853 }
854}
d211708b 855
004b8382
LOK
856bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
857{
858 cec_menu_state menuState;
859 {
860 CLockObject lock(m_mutex);
861 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
862 menuState = m_menuState;
863 }
104125dc 864
004b8382
LOK
865 MarkBusy();
866 bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
867 MarkReady();
868 return bReturn;
869}
94e9a2af 870
004b8382
LOK
871bool CCECBusDevice::ActivateSource(void)
872{
873 MarkAsActiveSource();
874 LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
875 MarkBusy();
876 bool bReturn = m_handler->ActivateSource();
877 MarkReady();
878 return bReturn;
879}
94e9a2af 880
004b8382
LOK
881bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
882{
883 bool bReturn(false);
e9de9629 884
004b8382 885 if (IsHandledByLibCEC())
104125dc 886 {
004b8382
LOK
887 MarkBusy();
888 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
104125dc 889
004b8382
LOK
890 bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
891 MarkReady();
104125dc 892 }
004b8382
LOK
893 return bReturn;
894}
104125dc 895
004b8382
LOK
896void CCECBusDevice::MarkAsActiveSource(void)
897{
898 CLockObject lock(m_mutex);
899 if (!m_bActiveSource)
900 LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
901 else
902 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
104125dc 903
004b8382
LOK
904 CECDEVICEVEC devices;
905 m_processor->GetDevices()->Get(devices);
906 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
907 if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
908 (*it)->MarkAsInactiveSource();
909
910 m_bActiveSource = true;
911 SetPowerStatus(CEC_POWER_STATUS_ON);
b64db02e
LOK
912}
913
004b8382 914void CCECBusDevice::MarkAsInactiveSource(void)
b64db02e 915{
b64db02e 916 {
f00ff009 917 CLockObject lock(m_mutex);
004b8382
LOK
918 if (m_bActiveSource)
919 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
920 m_bActiveSource = false;
b64db02e 921 }
e9de9629
LOK
922}
923
93729720 924bool CCECBusDevice::TransmitActiveSource(void)
0f23c85c 925{
8fa35473 926 bool bSendActiveSource(false);
0f23c85c 927
8747dd4f 928 {
f00ff009 929 CLockObject lock(m_mutex);
49c8f2e4 930 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
004b8382 931 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
8fa35473
LOK
932 else if (m_bActiveSource)
933 {
004b8382 934 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
8fa35473
LOK
935 bSendActiveSource = true;
936 }
937 else
004b8382 938 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
8747dd4f
LOK
939 }
940
b64db02e
LOK
941 if (bSendActiveSource)
942 {
1344fd1a 943 MarkBusy();
468a1414 944 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
1344fd1a 945 MarkReady();
b64db02e
LOK
946 return true;
947 }
948
949 return false;
0f23c85c
LOK
950}
951
49c8f2e4
LOK
952bool CCECBusDevice::TransmitImageViewOn(void)
953{
49c8f2e4 954 {
9a2f12df
LOK
955 CLockObject lock(m_mutex);
956 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
957 {
004b8382 958 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
9a2f12df
LOK
959 return false;
960 }
49c8f2e4 961 }
9a2f12df
LOK
962
963 MarkBusy();
964 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
965 MarkReady();
966 return true;
49c8f2e4
LOK
967}
968
ab27363d 969bool CCECBusDevice::TransmitInactiveSource(void)
93729720 970{
8fa35473
LOK
971 uint16_t iPhysicalAddress;
972 {
f00ff009 973 CLockObject lock(m_mutex);
004b8382 974 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
8fa35473
LOK
975 iPhysicalAddress = m_iPhysicalAddress;
976 }
93729720 977
1344fd1a
LOK
978 MarkBusy();
979 bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
980 MarkReady();
981 return bReturn;
93729720
LOK
982}
983
004b8382 984bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
0f23c85c 985{
1344fd1a 986 MarkBusy();
004b8382 987 bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
1344fd1a
LOK
988 MarkReady();
989 return bReturn;
0f23c85c
LOK
990}
991
004b8382 992void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
0f23c85c 993{
004b8382
LOK
994 CLockObject lock(m_mutex);
995 if (iNewAddress != m_iStreamPath)
8fa35473 996 {
004b8382
LOK
997 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
998 m_iStreamPath = iNewAddress;
8fa35473 999 }
0f23c85c 1000
99aeafb9
LOK
1001 if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
1002 return;
1003
004b8382
LOK
1004 CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
1005 if (device)
4d738fe3 1006 {
004b8382
LOK
1007 // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
1008 device->MarkAsActiveSource();
4d738fe3 1009 }
004b8382 1010 else
8fa35473 1011 {
004b8382
LOK
1012 // try to find the device with the old address, and mark it as inactive when found
1013 device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
1014 if (device)
1015 device->MarkAsInactiveSource();
8fa35473 1016 }
0f23c85c
LOK
1017}
1018
004b8382 1019bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
fbdea54c
MK
1020{
1021 bool bReturn(false);
004b8382 1022 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
fbdea54c
MK
1023
1024 MarkBusy();
004b8382
LOK
1025 cec_power_status currentStatus = GetPowerStatus(initiator, false);
1026 if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
1027 currentStatus != CEC_POWER_STATUS_ON)
fbdea54c 1028 {
004b8382
LOK
1029 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
1030 if (m_handler->PowerOn(initiator, m_iLogicalAddress))
1031 {
1032 SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
fbdea54c 1033 bReturn = true;
004b8382 1034 }
fbdea54c
MK
1035 }
1036 else
1037 {
004b8382 1038 LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
fbdea54c 1039 }
004b8382 1040
fbdea54c
MK
1041 MarkReady();
1042 return bReturn;
1043}
1044
004b8382 1045bool CCECBusDevice::Standby(const cec_logical_address initiator)
57f45e6c 1046{
004b8382 1047 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
b750a5c3 1048
004b8382 1049 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
1344fd1a 1050 MarkBusy();
004b8382 1051 bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
1344fd1a 1052 MarkReady();
57f45e6c
LOK
1053 return bReturn;
1054}
93729720 1055
004b8382 1056bool CCECBusDevice::NeedsPoll(void)
93729720 1057{
004b8382
LOK
1058 bool bSendPoll(false);
1059 cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
1060 switch (m_iLogicalAddress)
8fa35473 1061 {
004b8382
LOK
1062 case CECDEVICE_PLAYBACKDEVICE3:
1063 pollAddress = CECDEVICE_PLAYBACKDEVICE2;
1064 break;
1065 case CECDEVICE_PLAYBACKDEVICE2:
1066 pollAddress = CECDEVICE_PLAYBACKDEVICE1;
1067 break;
1068 case CECDEVICE_RECORDINGDEVICE3:
1069 pollAddress = CECDEVICE_RECORDINGDEVICE2;
1070 break;
1071 case CECDEVICE_RECORDINGDEVICE2:
1072 pollAddress = CECDEVICE_RECORDINGDEVICE1;
1073 break;
1074 case CECDEVICE_TUNER4:
1075 pollAddress = CECDEVICE_TUNER3;
1076 break;
1077 case CECDEVICE_TUNER3:
1078 pollAddress = CECDEVICE_TUNER2;
1079 break;
1080 case CECDEVICE_TUNER2:
1081 pollAddress = CECDEVICE_TUNER1;
1082 break;
1083 case CECDEVICE_AUDIOSYSTEM:
1084 case CECDEVICE_PLAYBACKDEVICE1:
1085 case CECDEVICE_RECORDINGDEVICE1:
1086 case CECDEVICE_TUNER1:
1087 case CECDEVICE_TV:
1088 bSendPoll = true;
1089 break;
1090 default:
1091 break;
8fa35473 1092 }
93729720 1093
004b8382
LOK
1094 if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
1095 {
1096 CCECBusDevice *device = m_processor->GetDevice(pollAddress);
1097 if (device)
1098 {
1099 cec_bus_device_status status = device->GetStatus();
1100 bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1101 }
1102 else
1103 {
1104 bSendPoll = true;
1105 }
1106 }
1107
1108 return bSendPoll;
93729720
LOK
1109}
1110
004b8382 1111void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
93729720 1112{
004b8382 1113 bool bRequestVendorId(false);
8fa35473 1114 {
f00ff009 1115 CLockObject lock(m_mutex);
004b8382
LOK
1116 bRequestVendorId = !m_bVendorIdRequested;
1117 m_bVendorIdRequested = true;
8fa35473
LOK
1118 }
1119
004b8382 1120 if (bRequestVendorId)
c4098482 1121 {
004b8382
LOK
1122 ReplaceHandler(false);
1123 GetVendorId(initiator);
c4098482 1124 }
93729720 1125}
004b8382 1126//@}
a33794d8 1127
004b8382 1128CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
a33794d8 1129{
004b8382 1130 return AsAudioSystem(this);
a33794d8
LOK
1131}
1132
004b8382 1133CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
a33794d8 1134{
004b8382 1135 return AsPlaybackDevice(this);
a33794d8 1136}
4d738fe3 1137
004b8382 1138CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
4d738fe3 1139{
004b8382 1140 return AsRecordingDevice(this);
4d738fe3
LOK
1141}
1142
004b8382 1143CCECTuner *CCECBusDevice::AsTuner(void)
4d738fe3 1144{
004b8382
LOK
1145 return AsTuner(this);
1146}
ad7e0696 1147
004b8382
LOK
1148CCECTV *CCECBusDevice::AsTV(void)
1149{
1150 return AsTV(this);
1151}
b499cf16 1152
004b8382
LOK
1153CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
1154{
1155 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
1156 return static_cast<CCECAudioSystem *>(device);
1157 return NULL;
4d738fe3 1158}
b64db02e 1159
004b8382 1160CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
b64db02e 1161{
004b8382
LOK
1162 if (device &&
1163 (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
1164 device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
1165 return static_cast<CCECPlaybackDevice *>(device);
1166 return NULL;
b64db02e
LOK
1167}
1168
004b8382 1169CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
a75e3a5a 1170{
004b8382
LOK
1171 if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
1172 return static_cast<CCECRecordingDevice *>(device);
1173 return NULL;
a75e3a5a
LOK
1174}
1175
004b8382 1176CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
0cfdeb5a 1177{
004b8382
LOK
1178 if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
1179 return static_cast<CCECTuner *>(device);
1180 return NULL;
0cfdeb5a
LOK
1181}
1182
004b8382 1183CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
0cfdeb5a 1184{
004b8382
LOK
1185 if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
1186 return static_cast<CCECTV *>(device);
1187 return NULL;
0cfdeb5a
LOK
1188}
1189
004b8382 1190void CCECBusDevice::MarkBusy(void)
ebb6ddb3 1191{
004b8382
LOK
1192 CLockObject handlerLock(m_handlerMutex);
1193 ++m_iHandlerUseCount;
1194}
ebb6ddb3 1195
004b8382
LOK
1196void CCECBusDevice::MarkReady(void)
1197{
1198 CLockObject handlerLock(m_handlerMutex);
1199 if (m_iHandlerUseCount > 0)
1200 --m_iHandlerUseCount;
1201}
1202
1203bool CCECBusDevice::TryLogicalAddress(void)
1204{
1205 LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
1206
1207 if (!TransmitPoll(m_iLogicalAddress))
ebb6ddb3 1208 {
004b8382
LOK
1209 LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
1210 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1211
1212 return true;
ebb6ddb3 1213 }
004b8382
LOK
1214
1215 LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
1216 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
1217 return false;
ebb6ddb3
LOK
1218}
1219
004b8382 1220CCECClient *CCECBusDevice::GetClient(void)
b78b4e33 1221{
004b8382 1222 return m_processor->GetClient(m_iLogicalAddress);
b78b4e33 1223}