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