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