c06a8b8e777c057eac616cdadfc3fe79cb9b2fe4
[deb_libcec.git] / src / lib / devices / CECBusDevice.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
33 #include "CECBusDevice.h"
34 #include "../CECProcessor.h"
35 #include "../implementations/ANCommandHandler.h"
36 #include "../implementations/CECCommandHandler.h"
37 #include "../implementations/SLCommandHandler.h"
38 #include "../implementations/VLCommandHandler.h"
39 #include "../platform/timeutils.h"
40
41 using namespace CEC;
42
43 #define ToString(p) m_processor->ToString(p)
44
45 CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress) :
46 m_type(CEC_DEVICE_TYPE_RESERVED),
47 m_iPhysicalAddress(iPhysicalAddress),
48 m_iStreamPath(0),
49 m_iLogicalAddress(iLogicalAddress),
50 m_powerStatus(CEC_POWER_STATUS_UNKNOWN),
51 m_processor(processor),
52 m_vendor(CEC_VENDOR_UNKNOWN),
53 m_menuState(CEC_MENU_STATE_ACTIVATED),
54 m_bActiveSource(false),
55 m_iLastCommandSent(0),
56 m_iLastActive(0),
57 m_cecVersion(CEC_VERSION_UNKNOWN),
58 m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN)
59 {
60 m_handler = new CCECCommandHandler(this);
61
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;
66
67 m_strDeviceName = ToString(m_iLogicalAddress);
68 }
69
70 CCECBusDevice::~CCECBusDevice(void)
71 {
72 m_condition.Broadcast();
73 delete m_handler;
74 }
75
76 void CCECBusDevice::AddLog(cec_log_level level, const CStdString &strMessage)
77 {
78 m_processor->AddLog(level, strMessage);
79 }
80
81 bool CCECBusDevice::HandleCommand(const cec_command &command)
82 {
83 CLockObject lock(&m_transmitMutex);
84 m_iLastActive = GetTimeMs();
85 m_handler->HandleCommand(command);
86 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
87 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
88 m_condition.Signal();
89 return true;
90 }
91
92 bool CCECBusDevice::PowerOn(void)
93 {
94 CStdString strLog;
95 strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
96 AddLog(CEC_LOG_DEBUG, strLog.c_str());
97
98 cec_command command;
99 cec_command::Format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_IMAGE_VIEW_ON);
100 if (m_processor->Transmit(command))
101 {
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 }
112 return true;
113 }
114
115 return false;
116 }
117
118 bool CCECBusDevice::Standby(void)
119 {
120 CStdString strLog;
121 strLog.Format("<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
122 AddLog(CEC_LOG_DEBUG, strLog.c_str());
123
124 cec_command command;
125 cec_command::Format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_STANDBY);
126
127 return m_processor->Transmit(command);
128 }
129
130 /** @name Getters */
131 //@{
132 cec_version CCECBusDevice::GetCecVersion(void)
133 {
134 CLockObject lock(&m_mutex);
135 if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
136 m_cecVersion == CEC_VERSION_UNKNOWN)
137 RequestCecVersion();
138
139 return m_cecVersion;
140 }
141
142 bool CCECBusDevice::RequestCecVersion(void)
143 {
144 bool bReturn(false);
145 if (!MyLogicalAddressContains(m_iLogicalAddress))
146 {
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))
154 bReturn = m_condition.Wait(&m_transmitMutex, 1000);
155 }
156 return bReturn;
157 }
158
159 uint64_t CCECBusDevice::GetLastCommandSent(void) const
160 {
161 return GetTimeMs() - m_iLastCommandSent;
162 }
163
164 const char* CCECBusDevice::GetLogicalAddressName(void) const
165 {
166 return ToString(m_iLogicalAddress);
167 }
168
169 cec_menu_language &CCECBusDevice::GetMenuLanguage(void)
170 {
171 CLockObject lock(&m_mutex);
172 if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
173 !strcmp(m_menuLanguage.language, "???"))
174 RequestMenuLanguage();
175
176 return m_menuLanguage;
177 }
178
179 bool CCECBusDevice::RequestMenuLanguage(void)
180 {
181 bool bReturn(false);
182 if (!MyLogicalAddressContains(m_iLogicalAddress))
183 {
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))
191 bReturn = m_condition.Wait(&m_transmitMutex, 1000);
192 }
193 return bReturn;
194 }
195
196 cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
197 {
198 return m_processor->GetLogicalAddress();
199 }
200
201 uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
202 {
203 return m_processor->GetPhysicalAddress();
204 }
205
206 CStdString CCECBusDevice::GetOSDName(void)
207 {
208 CLockObject lock(&m_mutex);
209 if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
210 m_strDeviceName.Equals(ToString(m_iLogicalAddress)))
211 RequestOSDName();
212
213 return m_strDeviceName;
214 }
215
216 bool 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
233 uint16_t CCECBusDevice::GetPhysicalAddress(bool bRefresh /* = true */)
234 {
235 CLockObject lock(&m_mutex);
236 if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
237 (m_iPhysicalAddress == 0xFFFF || bRefresh))
238 {
239 if (!RequestPhysicalAddress())
240 AddLog(CEC_LOG_ERROR, "failed to request the physical address");
241 }
242
243 return m_iPhysicalAddress;
244 }
245
246 bool 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
263 cec_power_status CCECBusDevice::GetPowerStatus(void)
264 {
265 CLockObject lock(&m_mutex);
266 if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
267 m_powerStatus == CEC_POWER_STATUS_UNKNOWN)
268 RequestPowerStatus();
269
270 return m_powerStatus;
271 }
272
273 bool CCECBusDevice::RequestPowerStatus(void)
274 {
275 bool bReturn(false);
276 if (!MyLogicalAddressContains(m_iLogicalAddress))
277 {
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))
285 bReturn = m_condition.Wait(&m_transmitMutex, 1000);
286 }
287 return bReturn;
288 }
289
290 cec_vendor_id CCECBusDevice::GetVendorId(void)
291 {
292 CLockObject lock(&m_mutex);
293 if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
294 m_vendor == CEC_VENDOR_UNKNOWN)
295 RequestVendorId();
296
297 return m_vendor;
298 }
299
300 bool CCECBusDevice::RequestVendorId(void)
301 {
302 bool bReturn(false);
303 if (!MyLogicalAddressContains(m_iLogicalAddress))
304 {
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);
310
311 CLockObject lock(&m_transmitMutex);
312 if (m_processor->Transmit(command))
313 bReturn = m_condition.Wait(&m_transmitMutex, 1000);
314 }
315 return bReturn;
316 }
317
318 const char *CCECBusDevice::GetVendorName(void)
319 {
320 return ToString(GetVendorId());
321 }
322
323 bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
324 {
325 return m_processor->HasLogicalAddress(address);
326 }
327
328 bool 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
375 cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */)
376 {
377 CLockObject lock(&m_writeMutex);
378 if (m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN || bForcePoll)
379 {
380 lock.Leave();
381 bool bPollAcked(false);
382 if (bForcePoll || NeedsPoll())
383 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
384
385 lock.Lock();
386 m_deviceStatus = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
387 }
388
389 return m_deviceStatus;
390 }
391
392 //@}
393
394 /** @name Setters */
395 //@{
396 void CCECBusDevice::SetCecVersion(const cec_version newVersion)
397 {
398 m_cecVersion = newVersion;
399
400 CStdString strLog;
401 strLog.Format("%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
402 AddLog(CEC_LOG_DEBUG, strLog);
403 }
404
405 void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
406 {
407 CLockObject lock(&m_writeMutex);
408 if (language.device == m_iLogicalAddress)
409 {
410 CStdString strLog;
411 strLog.Format(">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, language.language);
412 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
413 m_menuLanguage = language;
414 }
415 }
416
417 void CCECBusDevice::SetOSDName(CStdString strName)
418 {
419 CLockObject lock(&m_writeMutex);
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
429 void CCECBusDevice::SetMenuState(const cec_menu_state state)
430 {
431 CLockObject lock(&m_writeMutex);
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
441 void CCECBusDevice::SetInactiveDevice(void)
442 {
443 CLockObject lock(&m_writeMutex);
444 m_bActiveSource = false;
445 }
446
447 void CCECBusDevice::SetActiveDevice(void)
448 {
449 CLockObject lock(&m_writeMutex);
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
459 bool 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
481 void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
482 {
483 CLockObject lock(&m_writeMutex);
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
515 void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
516 {
517 CLockObject lock(&m_writeMutex);
518 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
519 {
520 CStdString strLog;
521 strLog.Format(">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
522 AddLog(CEC_LOG_DEBUG, strLog.c_str());
523
524 m_iPhysicalAddress = iNewAddress;
525 }
526 }
527
528 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = 0 */)
529 {
530 CLockObject lock(&m_writeMutex);
531 if (iNewAddress > 0)
532 {
533 CStdString strLog;
534 strLog.Format(">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
535 AddLog(CEC_LOG_DEBUG, strLog.c_str());
536
537 m_iStreamPath = iNewAddress;
538
539 if (iNewAddress > 0)
540 {
541 lock.Leave();
542 SetPowerStatus(CEC_POWER_STATUS_ON);
543 }
544 }
545 }
546
547 void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
548 {
549 CLockObject lock(&m_writeMutex);
550 if (m_powerStatus != powerStatus)
551 {
552 CStdString strLog;
553 strLog.Format(">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
554 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
555 m_powerStatus = powerStatus;
556 }
557 }
558
559 void CCECBusDevice::SetVendorId(uint64_t iVendorId)
560 {
561 {
562 CLockObject lock(&m_writeMutex);
563 m_vendor = (cec_vendor_id)iVendorId;
564
565 switch (iVendorId)
566 {
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;
595 }
596 }
597
598 CStdString strLog;
599 strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
600 m_processor->AddLog(CEC_LOG_DEBUG, strLog.c_str());
601 }
602 //@}
603
604 /** @name Transmit methods */
605 //@{
606 bool CCECBusDevice::TransmitActiveSource(void)
607 {
608 CLockObject lock(&m_writeMutex);
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)
616 {
617 CStdString strLog;
618 strLog.Format("<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
619 AddLog(CEC_LOG_NOTICE, strLog);
620
621 cec_command command;
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));
625
626 lock.Leave();
627 return m_processor->Transmit(command);
628 }
629 else
630 {
631 CStdString strLog;
632 strLog.Format("<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
633 AddLog(CEC_LOG_DEBUG, strLog);
634 }
635
636 return false;
637 }
638
639 bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
640 {
641 CLockObject lock(&m_writeMutex);
642 CStdString strLog;
643 strLog.Format("<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
644 AddLog(CEC_LOG_NOTICE, strLog);
645
646 cec_command command;
647 cec_command::Format(command, m_iLogicalAddress, dest, CEC_OPCODE_CEC_VERSION);
648 command.parameters.PushBack((uint8_t)m_cecVersion);
649
650 lock.Leave();
651 return m_processor->Transmit(command);
652 }
653
654 bool CCECBusDevice::TransmitInactiveSource(void)
655 {
656 CStdString strLog;
657 strLog.Format("<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
658 AddLog(CEC_LOG_NOTICE, strLog);
659
660 cec_command command;
661 cec_command::Format(command, m_iLogicalAddress, CECDEVICE_TV, CEC_OPCODE_INACTIVE_SOURCE);
662 command.parameters.PushBack((m_iPhysicalAddress >> 8) & 0xFF);
663 command.parameters.PushBack(m_iPhysicalAddress & 0xFF);
664
665 return m_processor->Transmit(command);
666 }
667
668 bool CCECBusDevice::TransmitMenuState(cec_logical_address dest)
669 {
670 CStdString strLog;
671 strLog.Format("<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
672 AddLog(CEC_LOG_NOTICE, strLog);
673
674 cec_command command;
675 cec_command::Format(command, m_iLogicalAddress, dest, CEC_OPCODE_MENU_STATUS);
676 command.parameters.PushBack((uint8_t)m_menuState);
677
678 return m_processor->Transmit(command);
679 }
680
681 bool CCECBusDevice::TransmitOSDName(cec_logical_address dest)
682 {
683 CLockObject lock(&m_writeMutex);
684 CStdString strLog;
685 strLog.Format("<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
686 AddLog(CEC_LOG_NOTICE, strLog.c_str());
687
688 cec_command command;
689 cec_command::Format(command, m_iLogicalAddress, dest, CEC_OPCODE_SET_OSD_NAME);
690 for (unsigned int iPtr = 0; iPtr < m_strDeviceName.length(); iPtr++)
691 command.parameters.PushBack(m_strDeviceName.at(iPtr));
692
693 lock.Leave();
694 return m_processor->Transmit(command);
695 }
696
697 bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage)
698 {
699 CLockObject lock(&m_writeMutex);
700 CStdString strLog;
701 strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
702 AddLog(CEC_LOG_NOTICE, strLog.c_str());
703
704 cec_command command;
705 cec_command::Format(command, m_iLogicalAddress, dest, CEC_OPCODE_SET_OSD_STRING);
706 command.parameters.PushBack((uint8_t)duration);
707
708 unsigned int iLen = strlen(strMessage);
709 if (iLen > 13) iLen = 13;
710
711 for (unsigned int iPtr = 0; iPtr < iLen; iPtr++)
712 command.parameters.PushBack(strMessage[iPtr]);
713
714 lock.Leave();
715 return m_processor->Transmit(command);
716 }
717
718 bool CCECBusDevice::TransmitPhysicalAddress(void)
719 {
720 CLockObject lock(&m_writeMutex);
721 CStdString strLog;
722 strLog.Format("<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
723 AddLog(CEC_LOG_NOTICE, strLog.c_str());
724
725 cec_command command;
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));
730
731 lock.Leave();
732 return m_processor->Transmit(command);
733 }
734
735 bool CCECBusDevice::TransmitPoll(cec_logical_address dest)
736 {
737 bool bReturn(false);
738 if (dest == CECDEVICE_UNKNOWN)
739 dest = m_iLogicalAddress;
740
741 CStdString strLog;
742 strLog.Format("<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
743 AddLog(CEC_LOG_NOTICE, strLog.c_str());
744
745 cec_command command;
746 cec_command::Format(command, m_iLogicalAddress, dest, CEC_OPCODE_NONE);
747 command.retries = 0;
748
749 {
750 CLockObject lock(&m_transmitMutex);
751 bReturn = m_processor->Transmit(command);
752 }
753
754 AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
755
756 if (bReturn)
757 {
758 CLockObject lock(&m_writeMutex);
759 m_iLastActive = GetTimeMs();
760 }
761
762 return bReturn;
763 }
764
765 bool CCECBusDevice::TransmitPowerState(cec_logical_address dest)
766 {
767 CLockObject lock(&m_writeMutex);
768 CStdString strLog;
769 strLog.Format("<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
770 AddLog(CEC_LOG_NOTICE, strLog.c_str());
771
772 cec_command command;
773 cec_command::Format(command, m_iLogicalAddress, dest, CEC_OPCODE_REPORT_POWER_STATUS);
774 command.parameters.PushBack((uint8_t) m_powerStatus);
775
776 lock.Leave();
777 return m_processor->Transmit(command);
778 }
779
780 bool CCECBusDevice::TransmitVendorID(cec_logical_address dest)
781 {
782 CLockObject lock(&m_writeMutex);
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);
788
789 lock.Leave();
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;
800 cec_command::Format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID);
801
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));
805
806 lock.Leave();
807 return m_processor->Transmit(command);
808 }
809 }
810
811 bool CCECBusDevice::SendKeypress(cec_user_control_code key, bool bWait /* = false */)
812 {
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);
817
818 if (bWait)
819 {
820 if (m_processor->Transmit(command))
821 return m_condition.Wait(&m_transmitMutex, 1000);
822 return false;
823 }
824
825 return m_processor->Transmit(command);
826 }
827
828 bool CCECBusDevice::SendKeyRelease(bool bWait /* = false */)
829 {
830 CLockObject lock(&m_transmitMutex);
831 cec_command command;
832 cec_command::Format(command, m_processor->GetLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_USER_CONTROL_RELEASE);
833
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);
843 }
844 }
845 //@}